9090 WHILE (lng >= 180 ) LOOP
9191 lng := lng - 360 ;
9292 END LOOP;
93- return lng;
93+ RETURN lng;
94+ END;
95+ $BODY$;
96+
97+
98+ -- pluscode_latitudeToInteger ####
99+ -- Convert latitude to an integer representation.
100+ -- PARAMETERS
101+ -- latitude numeric // latitude in degrees
102+ -- EXAMPLE
103+ -- select pluscode_latitudeToInteger(149.18);
104+ CREATE OR REPLACE FUNCTION public .pluscode_latitudeToInteger(
105+ latitude numeric )
106+ RETURNS numeric
107+ LANGUAGE ' plpgsql'
108+ COST 100
109+ IMMUTABLE
110+ AS $BODY$
111+ DECLARE
112+ CODE_ALPHABET_ text := ' 23456789CFGHJMPQRVWX' ;
113+ ENCODING_BASE_ int := char_length(CODE_ALPHABET_);
114+ LATITUDE_MAX_ int := 90 ;
115+ MAX_DIGIT_COUNT_ int := 15 ;
116+ PAIR_CODE_LENGTH_ int := 10 ;
117+ PAIR_PRECISION_ decimal := power(ENCODING_BASE_, 3 );
118+ GRID_ROWS_ int := 5 ;
119+ FINAL_LAT_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_ROWS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
120+ latVal decimal := 0 ;
121+ BEGIN
122+ latVal := round(latitude * FINAL_LAT_PRECISION_);
123+ latVal := latVal + LATITUDE_MAX_ * FINAL_LAT_PRECISION_;
124+ IF (latVal < 0 ) THEN
125+ latVal := 0 ;
126+ ELSIF (latVal > 2 * LATITUDE_MAX_ * FINAL_LAT_PRECISION_) THEN
127+ latVal := 2 * LATITUDE_MAX_ * FINAL_LAT_PRECISION_ - 1 ;
128+ END IF;
129+ RETURN latVal;
130+ END;
131+ $BODY$;
132+
133+
134+ -- pluscode_longitudeToInteger ####
135+ -- Convert longitude to an integer representation.
136+ -- PARAMETERS
137+ -- longitude numeric // longitude in degrees
138+ -- EXAMPLE
139+ -- select pluscode_longitudeToInteger(149.18);
140+ CREATE OR REPLACE FUNCTION public .pluscode_longitudeToInteger(
141+ longitude numeric )
142+ RETURNS numeric
143+ LANGUAGE ' plpgsql'
144+ COST 100
145+ IMMUTABLE
146+ AS $BODY$
147+ DECLARE
148+ CODE_ALPHABET_ text := ' 23456789CFGHJMPQRVWX' ;
149+ ENCODING_BASE_ int := char_length(CODE_ALPHABET_);
150+ LONGITUDE_MAX_ int := 180 ;
151+ MAX_DIGIT_COUNT_ int := 15 ;
152+ PAIR_CODE_LENGTH_ int := 10 ;
153+ PAIR_PRECISION_ decimal := power(ENCODING_BASE_, 3 );
154+ GRID_COLUMNS_ int := 4 ;
155+ FINAL_LNG_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_COLUMNS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
156+ lngVal decimal := 0 ;
157+ BEGIN
158+ lngVal := round(longitude * FINAL_LNG_PRECISION_);
159+ lngVal := lngVal + LONGITUDE_MAX_ * FINAL_LNG_PRECISION_;
160+ IF (lngVal < 0 ) THEN
161+ lngVal := lngVal % (2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_) + 2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_;
162+ ELSIF (lngVal > 2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_) THEN
163+ lngVal := lngVal % (2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_);
164+ END IF;
165+ RETURN lngVal;
94166END;
95167$BODY$;
96168
@@ -302,17 +374,16 @@ END;
302374$BODY$;
303375
304376
305- -- pluscode_encode ####
306- -- Encode lat lng to get pluscode
377+ -- pluscode_encodeIntegers ####
378+ -- Encode lat lng in their integer representation to get an Open Location Code.
379+ -- This function is for testing purposes only.
307380-- PARAMETERS
308381-- latitude numeric // latitude ref
309382-- longitude numeric // longitude ref
310383-- codeLength int// How long must be the pluscode
311- -- EXAMPLE
312- -- select pluscode_encode(49.05,-0.108,12);
313- CREATE OR REPLACE FUNCTION public .pluscode_encode(
314- latitude numeric ,
315- longitude numeric ,
384+ CREATE OR REPLACE FUNCTION public .pluscode_encodeIntegers(
385+ latVal numeric ,
386+ lngVal numeric ,
316387 codeLength int DEFAULT 10 )
317388RETURNS text
318389 LANGUAGE ' plpgsql'
@@ -325,51 +396,17 @@ DECLARE
325396 PADDING_CHARACTER_ text := ' 0' ;
326397 CODE_ALPHABET_ text := ' 23456789CFGHJMPQRVWX' ;
327398 ENCODING_BASE_ int := char_length(CODE_ALPHABET_);
328- LATITUDE_MAX_ int := 90 ;
329- LONGITUDE_MAX_ int := 180 ;
330- MIN_DIGIT_COUNT_ int := 2 ;
331399 MAX_DIGIT_COUNT_ int := 15 ;
332400 PAIR_CODE_LENGTH_ int := 10 ;
333- PAIR_PRECISION_ decimal := power(ENCODING_BASE_, 3 );
334401 GRID_CODE_LENGTH_ int := MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_;
335402 GRID_COLUMNS_ int := 4 ;
336403 GRID_ROWS_ int := 5 ;
337- FINAL_LAT_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_ROWS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
338- FINAL_LNG_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_COLUMNS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
339404 code text := ' ' ;
340- latVal decimal := 0 ;
341- lngVal decimal := 0 ;
342405 latDigit smallint ;
343406 lngDigit smallint ;
344407 ndx smallint ;
345408 i_ smallint ;
346409BEGIN
347- IF ((codeLength < MIN_DIGIT_COUNT_) OR ((codeLength < PAIR_CODE_LENGTH_) AND (codeLength % 2 = 1 ))) THEN
348- RAISE EXCEPTION ' Invalid Open Location Code length - %' , codeLength
349- USING HINT = ' The Open Location Code length must be 2, 4, 6, 8, 10, 11, 12, 13, 14, or 15.' ;
350- END IF;
351-
352- codeLength := LEAST(codeLength, MAX_DIGIT_COUNT_);
353-
354- latVal := floor(round((latitude + LATITUDE_MAX_) * FINAL_LAT_PRECISION_, 6 ));
355- lngVal := floor(round((longitude + LONGITUDE_MAX_) * FINAL_LNG_PRECISION_, 6 ));
356-
357- latVal := round(latitude * FINAL_LAT_PRECISION_);
358- latVal := latVal + LATITUDE_MAX_ * FINAL_LAT_PRECISION_;
359- IF (latVal < 0 ) THEN
360- latVal := 0 ;
361- ELSIF (latVal > 2 * LATITUDE_MAX_ * FINAL_LAT_PRECISION_) THEN
362- latVal := 2 * LATITUDE_MAX_ * FINAL_LAT_PRECISION_ - 1 ;
363- END IF;
364-
365- lngVal := round(longitude * FINAL_LNG_PRECISION_);
366- lngVal := lngVal + LONGITUDE_MAX_ * FINAL_LNG_PRECISION_;
367- IF (lngVal < 0 ) THEN
368- lngVal := lngVal % (2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_) + 2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_;
369- ELSIF (lngVal > 2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_) THEN
370- lngVal := lngVal % (2 * LONGITUDE_MAX_ * FINAL_LNG_PRECISION_);
371- END IF;
372-
373410 IF (codeLength > PAIR_CODE_LENGTH_) THEN
374411 i_ := 0 ;
375412 WHILE (i_ < (MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_)) LOOP
@@ -406,6 +443,63 @@ END;
406443$BODY$;
407444
408445
446+ -- pluscode_encode ####
447+ -- Encode lat lng to get pluscode
448+ -- PARAMETERS
449+ -- latitude numeric // latitude ref
450+ -- longitude numeric // longitude ref
451+ -- codeLength int// How long must be the pluscode
452+ -- EXAMPLE
453+ -- select pluscode_encode(49.05,-0.108,12);
454+ CREATE OR REPLACE FUNCTION public .pluscode_encode(
455+ latitude numeric ,
456+ longitude numeric ,
457+ codeLength int DEFAULT 10 )
458+ RETURNS text
459+ LANGUAGE ' plpgsql'
460+ COST 100
461+ IMMUTABLE
462+ AS $BODY$
463+ DECLARE
464+ SEPARATOR_ text := ' +' ;
465+ SEPARATOR_POSITION_ int := 8 ;
466+ PADDING_CHARACTER_ text := ' 0' ;
467+ CODE_ALPHABET_ text := ' 23456789CFGHJMPQRVWX' ;
468+ ENCODING_BASE_ int := char_length(CODE_ALPHABET_);
469+ LATITUDE_MAX_ int := 90 ;
470+ LONGITUDE_MAX_ int := 180 ;
471+ MIN_DIGIT_COUNT_ int := 2 ;
472+ MAX_DIGIT_COUNT_ int := 15 ;
473+ PAIR_CODE_LENGTH_ int := 10 ;
474+ PAIR_PRECISION_ decimal := power(ENCODING_BASE_, 3 );
475+ GRID_CODE_LENGTH_ int := MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_;
476+ GRID_COLUMNS_ int := 4 ;
477+ GRID_ROWS_ int := 5 ;
478+ FINAL_LAT_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_ROWS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
479+ FINAL_LNG_PRECISION_ decimal := PAIR_PRECISION_ * power(GRID_COLUMNS_, MAX_DIGIT_COUNT_ - PAIR_CODE_LENGTH_);
480+ code text := ' ' ;
481+ latVal decimal := 0 ;
482+ lngVal decimal := 0 ;
483+ latDigit smallint ;
484+ lngDigit smallint ;
485+ ndx smallint ;
486+ i_ smallint ;
487+ BEGIN
488+ IF ((codeLength < MIN_DIGIT_COUNT_) OR ((codeLength < PAIR_CODE_LENGTH_) AND (codeLength % 2 = 1 ))) THEN
489+ RAISE EXCEPTION ' Invalid Open Location Code length - %' , codeLength
490+ USING HINT = ' The Open Location Code length must be 2, 4, 6, 8, 10, 11, 12, 13, 14, or 15.' ;
491+ END IF;
492+
493+ codeLength := LEAST(codeLength, MAX_DIGIT_COUNT_);
494+
495+ latVal := pluscode_latitudeToInteger(latitude);
496+ lngVal := pluscode_longitudeToInteger(longitude);
497+
498+ RETURN pluscode_encodeIntegers(latVal, lngVal, codeLength);
499+ END;
500+ $BODY$;
501+
502+
409503-- pluscode_decode ####
410504-- Decode a pluscode to get the corresponding bounding box and the center
411505-- PARAMETERS
0 commit comments