PostgreSQL Source Code git master
Loading...
Searching...
No Matches
geo_ops.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * geo_ops.c
4 * 2D geometric operations
5 *
6 * This module implements the geometric functions and operators. The
7 * geometric types are (from simple to more complicated):
8 *
9 * - point
10 * - line
11 * - line segment
12 * - box
13 * - circle
14 * - polygon
15 *
16 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
17 * Portions Copyright (c) 1994, Regents of the University of California
18 *
19 *
20 * IDENTIFICATION
21 * src/backend/utils/adt/geo_ops.c
22 *
23 *-------------------------------------------------------------------------
24 */
25#include "postgres.h"
26
27#include <math.h>
28#include <limits.h>
29#include <float.h>
30#include <ctype.h>
31
32#include "libpq/pqformat.h"
33#include "miscadmin.h"
34#include "nodes/miscnodes.h"
35#include "utils/float.h"
36#include "utils/fmgrprotos.h"
37#include "utils/geo_decls.h"
38#include "varatt.h"
39
40/*
41 * * Type constructors have this form:
42 * void type_construct(Type *result, ...);
43 *
44 * * Operators commonly have signatures such as
45 * void type1_operator_type2(Type *result, Type1 *obj1, Type2 *obj2);
46 *
47 * Common operators are:
48 * * Intersection point:
49 * bool type1_interpt_type2(Point *result, Type1 *obj1, Type2 *obj2);
50 * Return whether the two objects intersect. If *result is not NULL,
51 * it is set to the intersection point.
52 *
53 * * Containment:
54 * bool type1_contain_type2(Type1 *obj1, Type2 *obj2);
55 * Return whether obj1 contains obj2.
56 * bool type1_contain_type2(Type1 *contains_obj, Type1 *contained_obj);
57 * Return whether obj1 contains obj2 (used when types are the same)
58 *
59 * * Distance of closest point in or on obj1 to obj2:
60 * float8 type1_closept_type2(Point *result, Type1 *obj1, Type2 *obj2);
61 * Returns the shortest distance between two objects. If *result is not
62 * NULL, it is set to the closest point in or on obj1 to obj2.
63 *
64 * These functions may be used to implement multiple SQL-level operators. For
65 * example, determining whether two lines are parallel is done by checking
66 * whether they don't intersect.
67 */
68
69/*
70 * Internal routines
71 */
72
77
78/* Routines for points */
79static inline void point_construct(Point *result, float8 x, float8 y);
80static inline void point_add_point(Point *result, Point *pt1, Point *pt2, Node *escontext);
81static inline void point_sub_point(Point *result, Point *pt1, Point *pt2);
82static inline void point_mul_point(Point *result, Point *pt1, Point *pt2);
83static inline void point_div_point(Point *result, Point *pt1, Point *pt2);
84static inline bool point_eq_point(Point *pt1, Point *pt2);
85static inline float8 point_dt(Point *pt1, Point *pt2, Node *escontext);
86static inline float8 point_sl(Point *pt1, Point *pt2);
87static int point_inside(Point *p, int npts, Point *plist);
88
89/* Routines for lines */
90static inline void line_construct(LINE *result, Point *pt, float8 m);
91static inline float8 line_sl(LINE *line);
92static inline float8 line_invsl(LINE *line);
93static bool line_interpt_line(Point *result, LINE *l1, LINE *l2);
94static bool line_contain_point(LINE *line, Point *point);
95static float8 line_closept_point(Point *result, LINE *line, Point *point);
96
97/* Routines for line segments */
98static inline void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
99static inline float8 lseg_sl(LSEG *lseg);
100static inline float8 lseg_invsl(LSEG *lseg);
101static bool lseg_interpt_line(Point *result, LSEG *lseg, LINE *line);
102static bool lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2);
104static bool lseg_contain_point(LSEG *lseg, Point *pt);
105static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt);
106static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line);
108
109/* Routines for boxes */
110static inline void box_construct(BOX *result, Point *pt1, Point *pt2);
111static void box_cn(Point *center, BOX *box, Node *escontext);
112static bool box_ov(BOX *box1, BOX *box2);
113static float8 box_ar(BOX *box);
114static float8 box_ht(BOX *box);
115static float8 box_wd(BOX *box);
116static bool box_contain_point(BOX *box, Point *point);
118static bool box_contain_lseg(BOX *box, LSEG *lseg);
119static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg);
120static float8 box_closept_point(Point *result, BOX *box, Point *pt);
121static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg);
122
123/* Routines for circles */
125
126/* Routines for polygons */
127static void make_bound_box(POLYGON *poly);
128static POLYGON *circle_poly_internal(int32 npts, const CIRCLE *circle, FunctionCallInfo fcinfo);
129static void poly_to_circle(CIRCLE *result, POLYGON *poly, Node *escontext);
130static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
132static bool plist_same(int npts, Point *p1, Point *p2);
134
135/* Routines for encoding and decoding */
136static bool single_decode(char *num, float8 *x, char **endptr_p,
137 const char *type_name, const char *orig_string,
138 Node *escontext);
139static void single_encode(float8 x, StringInfo str);
140static bool pair_decode(char *str, float8 *x, float8 *y, char **endptr_p,
141 const char *type_name, const char *orig_string,
142 Node *escontext);
143static void pair_encode(float8 x, float8 y, StringInfo str);
144static int pair_count(char *s, char delim);
145static bool path_decode(char *str, bool opentype, int npts, Point *p,
146 bool *isopen, char **endptr_p,
147 const char *type_name, const char *orig_string,
148 Node *escontext);
149static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
150
151
152/*
153 * Delimiters for input and output strings.
154 * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
155 * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
156 */
157
158#define LDELIM '('
159#define RDELIM ')'
160#define DELIM ','
161#define LDELIM_EP '['
162#define RDELIM_EP ']'
163#define LDELIM_C '<'
164#define RDELIM_C '>'
165#define LDELIM_L '{'
166#define RDELIM_L '}'
167
168
169/*
170 * Geometric data types are composed of points.
171 * This code tries to support a common format throughout the data types,
172 * to allow for more predictable usage and data type conversion.
173 * The fundamental unit is the point. Other units are line segments,
174 * open paths, boxes, closed paths, and polygons (which should be considered
175 * non-intersecting closed paths).
176 *
177 * Data representation is as follows:
178 * point: (x,y)
179 * line segment: [(x1,y1),(x2,y2)]
180 * box: (x1,y1),(x2,y2)
181 * open path: [(x1,y1),...,(xn,yn)]
182 * closed path: ((x1,y1),...,(xn,yn))
183 * polygon: ((x1,y1),...,(xn,yn))
184 *
185 * For boxes, the points are opposite corners with the first point at the top right.
186 * For closed paths and polygons, the points should be reordered to allow
187 * fast and correct equality comparisons.
188 *
189 * XXX perhaps points in complex shapes should be reordered internally
190 * to allow faster internal operations, but should keep track of input order
191 * and restore that order for text output - tgl 97/01/16
192 */
193
194static bool
195single_decode(char *num, float8 *x, char **endptr_p,
196 const char *type_name, const char *orig_string,
197 Node *escontext)
198{
199 *x = float8in_internal(num, endptr_p, type_name, orig_string, escontext);
200 return (!SOFT_ERROR_OCCURRED(escontext));
201} /* single_decode() */
202
203static void
205{
206 char *xstr = float8out_internal(x);
207
209 pfree(xstr);
210} /* single_encode() */
211
212static bool
214 const char *type_name, const char *orig_string,
215 Node *escontext)
216{
217 bool has_delim;
218
219 while (isspace((unsigned char) *str))
220 str++;
221 if ((has_delim = (*str == LDELIM)))
222 str++;
223
224 if (!single_decode(str, x, &str, type_name, orig_string, escontext))
225 return false;
226
227 if (*str++ != DELIM)
228 goto fail;
229
230 if (!single_decode(str, y, &str, type_name, orig_string, escontext))
231 return false;
232
233 if (has_delim)
234 {
235 if (*str++ != RDELIM)
236 goto fail;
237 while (isspace((unsigned char) *str))
238 str++;
239 }
240
241 /* report stopping point if wanted, else complain if not end of string */
242 if (endptr_p)
243 *endptr_p = str;
244 else if (*str != '\0')
245 goto fail;
246 return true;
247
248fail:
249 ereturn(escontext, false,
251 errmsg("invalid input syntax for type %s: \"%s\"",
252 type_name, orig_string)));
253}
254
255static void
257{
258 char *xstr = float8out_internal(x);
259 char *ystr = float8out_internal(y);
260
261 appendStringInfo(str, "%s,%s", xstr, ystr);
262 pfree(xstr);
263 pfree(ystr);
264}
265
266static bool
267path_decode(char *str, bool opentype, int npts, Point *p,
268 bool *isopen, char **endptr_p,
269 const char *type_name, const char *orig_string,
270 Node *escontext)
271{
272 int depth = 0;
273 char *cp;
274 int i;
275
276 while (isspace((unsigned char) *str))
277 str++;
278 if ((*isopen = (*str == LDELIM_EP)))
279 {
280 /* no open delimiter allowed? */
281 if (!opentype)
282 goto fail;
283 depth++;
284 str++;
285 }
286 else if (*str == LDELIM)
287 {
288 cp = (str + 1);
289 while (isspace((unsigned char) *cp))
290 cp++;
291 if (*cp == LDELIM)
292 {
293 depth++;
294 str = cp;
295 }
296 else if (strrchr(str, LDELIM) == str)
297 {
298 depth++;
299 str = cp;
300 }
301 }
302
303 for (i = 0; i < npts; i++)
304 {
305 if (!pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string,
306 escontext))
307 return false;
308 if (*str == DELIM)
309 str++;
310 p++;
311 }
312
313 while (depth > 0)
314 {
315 if (*str == RDELIM || (*str == RDELIM_EP && *isopen && depth == 1))
316 {
317 depth--;
318 str++;
319 while (isspace((unsigned char) *str))
320 str++;
321 }
322 else
323 goto fail;
324 }
325
326 /* report stopping point if wanted, else complain if not end of string */
327 if (endptr_p)
328 *endptr_p = str;
329 else if (*str != '\0')
330 goto fail;
331 return true;
332
333fail:
334 ereturn(escontext, false,
336 errmsg("invalid input syntax for type %s: \"%s\"",
337 type_name, orig_string)));
338} /* path_decode() */
339
340static char *
342{
344 int i;
345
347
348 switch (path_delim)
349 {
350 case PATH_CLOSED:
352 break;
353 case PATH_OPEN:
355 break;
356 case PATH_NONE:
357 break;
358 }
359
360 for (i = 0; i < npts; i++)
361 {
362 if (i > 0)
365 pair_encode(pt->x, pt->y, &str);
367 pt++;
368 }
369
370 switch (path_delim)
371 {
372 case PATH_CLOSED:
374 break;
375 case PATH_OPEN:
377 break;
378 case PATH_NONE:
379 break;
380 }
381
382 return str.data;
383} /* path_encode() */
384
385/*-------------------------------------------------------------
386 * pair_count - count the number of points
387 * allow the following notation:
388 * '((1,2),(3,4))'
389 * '(1,3,2,4)'
390 * require an odd number of delim characters in the string
391 *-------------------------------------------------------------*/
392static int
393pair_count(char *s, char delim)
394{
395 int ndelim = 0;
396
397 while ((s = strchr(s, delim)) != NULL)
398 {
399 ndelim++;
400 s++;
401 }
402 return (ndelim % 2) ? ((ndelim + 1) / 2) : -1;
403}
404
405
406/***********************************************************************
407 **
408 ** Routines for two-dimensional boxes.
409 **
410 ***********************************************************************/
411
412/*----------------------------------------------------------
413 * Formatting and conversion routines.
414 *---------------------------------------------------------*/
415
416/* box_in - convert a string to internal form.
417 *
418 * External format: (two corners of box)
419 * "(f8, f8), (f8, f8)"
420 * also supports the older style "(f8, f8, f8, f8)"
421 */
422Datum
424{
425 char *str = PG_GETARG_CSTRING(0);
426 Node *escontext = fcinfo->context;
428 bool isopen;
429 float8 x,
430 y;
431
432 if (!path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str,
433 escontext))
435
436 /* reorder corners if necessary... */
437 if (float8_lt(box->high.x, box->low.x))
438 {
439 x = box->high.x;
440 box->high.x = box->low.x;
441 box->low.x = x;
442 }
443 if (float8_lt(box->high.y, box->low.y))
444 {
445 y = box->high.y;
446 box->high.y = box->low.y;
447 box->low.y = y;
448 }
449
451}
452
453/* box_out - convert a box to external form.
454 */
455Datum
462
463/*
464 * box_recv - converts external binary format to box
465 */
466Datum
468{
470 BOX *box;
471 float8 x,
472 y;
473
475
476 box->high.x = pq_getmsgfloat8(buf);
477 box->high.y = pq_getmsgfloat8(buf);
478 box->low.x = pq_getmsgfloat8(buf);
479 box->low.y = pq_getmsgfloat8(buf);
480
481 /* reorder corners if necessary... */
482 if (float8_lt(box->high.x, box->low.x))
483 {
484 x = box->high.x;
485 box->high.x = box->low.x;
486 box->low.x = x;
487 }
488 if (float8_lt(box->high.y, box->low.y))
489 {
490 y = box->high.y;
491 box->high.y = box->low.y;
492 box->low.y = y;
493 }
494
496}
497
498/*
499 * box_send - converts box to binary format
500 */
501Datum
503{
504 BOX *box = PG_GETARG_BOX_P(0);
506
508 pq_sendfloat8(&buf, box->high.x);
509 pq_sendfloat8(&buf, box->high.y);
510 pq_sendfloat8(&buf, box->low.x);
511 pq_sendfloat8(&buf, box->low.y);
513}
514
515
516/* box_construct - fill in a new box.
517 */
518static inline void
520{
521 if (float8_gt(pt1->x, pt2->x))
522 {
523 result->high.x = pt1->x;
524 result->low.x = pt2->x;
525 }
526 else
527 {
528 result->high.x = pt2->x;
529 result->low.x = pt1->x;
530 }
531 if (float8_gt(pt1->y, pt2->y))
532 {
533 result->high.y = pt1->y;
534 result->low.y = pt2->y;
535 }
536 else
537 {
538 result->high.y = pt2->y;
539 result->low.y = pt1->y;
540 }
541}
542
543
544/*----------------------------------------------------------
545 * Relational operators for BOXes.
546 * <, >, <=, >=, and == are based on box area.
547 *---------------------------------------------------------*/
548
549/* box_same - are two boxes identical?
550 */
551Datum
553{
556
557 PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
558 point_eq_point(&box1->low, &box2->low));
559}
560
561/* box_overlap - does box1 overlap box2?
562 */
563Datum
571
572static bool
574{
575 return (FPle(box1->low.x, box2->high.x) &&
576 FPle(box2->low.x, box1->high.x) &&
577 FPle(box1->low.y, box2->high.y) &&
578 FPle(box2->low.y, box1->high.y));
579}
580
581/* box_left - is box1 strictly left of box2?
582 */
583Datum
585{
588
589 PG_RETURN_BOOL(FPlt(box1->high.x, box2->low.x));
590}
591
592/* box_overleft - is the right edge of box1 at or left of
593 * the right edge of box2?
594 *
595 * This is "less than or equal" for the end of a time range,
596 * when time ranges are stored as rectangles.
597 */
598Datum
600{
603
604 PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x));
605}
606
607/* box_right - is box1 strictly right of box2?
608 */
609Datum
611{
614
615 PG_RETURN_BOOL(FPgt(box1->low.x, box2->high.x));
616}
617
618/* box_overright - is the left edge of box1 at or right of
619 * the left edge of box2?
620 *
621 * This is "greater than or equal" for time ranges, when time ranges
622 * are stored as rectangles.
623 */
624Datum
626{
629
630 PG_RETURN_BOOL(FPge(box1->low.x, box2->low.x));
631}
632
633/* box_below - is box1 strictly below box2?
634 */
635Datum
637{
640
641 PG_RETURN_BOOL(FPlt(box1->high.y, box2->low.y));
642}
643
644/* box_overbelow - is the upper edge of box1 at or below
645 * the upper edge of box2?
646 */
647Datum
649{
652
653 PG_RETURN_BOOL(FPle(box1->high.y, box2->high.y));
654}
655
656/* box_above - is box1 strictly above box2?
657 */
658Datum
660{
663
664 PG_RETURN_BOOL(FPgt(box1->low.y, box2->high.y));
665}
666
667/* box_overabove - is the lower edge of box1 at or above
668 * the lower edge of box2?
669 */
670Datum
672{
675
676 PG_RETURN_BOOL(FPge(box1->low.y, box2->low.y));
677}
678
679/* box_contained - is box1 contained by box2?
680 */
681Datum
689
690/* box_contain - does box1 contain box2?
691 */
692Datum
700
701/*
702 * Check whether the second box is in the first box or on its border
703 */
704static bool
706{
707 return FPge(contains_box->high.x, contained_box->high.x) &&
708 FPle(contains_box->low.x, contained_box->low.x) &&
709 FPge(contains_box->high.y, contained_box->high.y) &&
710 FPle(contains_box->low.y, contained_box->low.y);
711}
712
713
714/* box_positionop -
715 * is box1 entirely {above,below} box2?
716 *
717 * box_below_eq and box_above_eq are obsolete versions that (probably
718 * erroneously) accept the equal-boundaries case. Since these are not
719 * in sync with the box_left and box_right code, they are deprecated and
720 * not supported in the PG 8.1 rtree operator class extension.
721 */
722Datum
724{
727
728 PG_RETURN_BOOL(FPle(box1->high.y, box2->low.y));
729}
730
731Datum
733{
736
737 PG_RETURN_BOOL(FPge(box1->low.y, box2->high.y));
738}
739
740
741/* box_relop - is area(box1) relop area(box2), within
742 * our accuracy constraint?
743 */
744Datum
752
753Datum
761
762Datum
770
771Datum
779
780Datum
788
789
790/*----------------------------------------------------------
791 * "Arithmetic" operators on boxes.
792 *---------------------------------------------------------*/
793
794/* box_area - returns the area of the box.
795 */
796Datum
803
804
805/* box_width - returns the width of the box
806 * (horizontal magnitude).
807 */
808Datum
815
816
817/* box_height - returns the height of the box
818 * (vertical magnitude).
819 */
820Datum
827
828
829/* box_distance - returns the distance between the
830 * center points of two boxes.
831 */
832Datum
834{
837 Point a,
838 b;
839
840 box_cn(&a, box1, NULL);
841 box_cn(&b, box2, NULL);
842
844}
845
846
847/* box_center - returns the center point of the box.
848 */
849Datum
851{
852 BOX *box = PG_GETARG_BOX_P(0);
853 Point *result = palloc_object(Point);
854
855 box_cn(result, box, fcinfo->context);
856 if (SOFT_ERROR_OCCURRED(fcinfo->context))
858
859 PG_RETURN_POINT_P(result);
860}
861
862
863/* box_ar - returns the area of the box.
864 */
865static float8
867{
868 return float8_mul(box_wd(box), box_ht(box));
869}
870
871
872/* box_cn - stores the centerpoint of the box into *center.
873 */
874static void
875box_cn(Point *center, BOX *box, Node *escontext)
876{
877 float8 x;
878 float8 y;
879
880 x = float8_pl_safe(box->high.x, box->low.x, escontext);
881 if (SOFT_ERROR_OCCURRED(escontext))
882 return;
883
884 center->x = float8_div_safe(x, 2.0, escontext);
885 if (SOFT_ERROR_OCCURRED(escontext))
886 return;
887
888 y = float8_pl_safe(box->high.y, box->low.y, escontext);
889 if (SOFT_ERROR_OCCURRED(escontext))
890 return;
891
892 center->y = float8_div_safe(y, 2.0, escontext);
893 if (SOFT_ERROR_OCCURRED(escontext))
894 return;
895}
896
897/* box_wd - returns the width (length) of the box
898 * (horizontal magnitude).
899 */
900static float8
902{
903 return float8_mi(box->high.x, box->low.x);
904}
905
906
907/* box_ht - returns the height of the box
908 * (vertical magnitude).
909 */
910static float8
912{
913 return float8_mi(box->high.y, box->low.y);
914}
915
916
917/*----------------------------------------------------------
918 * Funky operations.
919 *---------------------------------------------------------*/
920
921/* box_intersect -
922 * returns the overlapping portion of two boxes,
923 * or NULL if they do not intersect.
924 */
925Datum
927{
930 BOX *result;
931
932 if (!box_ov(box1, box2))
934
935 result = palloc_object(BOX);
936
937 result->high.x = float8_min(box1->high.x, box2->high.x);
938 result->low.x = float8_max(box1->low.x, box2->low.x);
939 result->high.y = float8_min(box1->high.y, box2->high.y);
940 result->low.y = float8_max(box1->low.y, box2->low.y);
941
942 PG_RETURN_BOX_P(result);
943}
944
945
946/* box_diagonal -
947 * returns a line segment which happens to be the
948 * positive-slope diagonal of "box".
949 */
950Datum
952{
953 BOX *box = PG_GETARG_BOX_P(0);
954 LSEG *result = palloc_object(LSEG);
955
956 statlseg_construct(result, &box->high, &box->low);
957
958 PG_RETURN_LSEG_P(result);
959}
960
961/***********************************************************************
962 **
963 ** Routines for 2D lines.
964 **
965 ***********************************************************************/
966
967static bool
968line_decode(char *s, const char *str, LINE *line, Node *escontext)
969{
970 /* s was already advanced over leading '{' */
971 if (!single_decode(s, &line->A, &s, "line", str, escontext))
972 return false;
973 if (*s++ != DELIM)
974 goto fail;
975 if (!single_decode(s, &line->B, &s, "line", str, escontext))
976 return false;
977 if (*s++ != DELIM)
978 goto fail;
979 if (!single_decode(s, &line->C, &s, "line", str, escontext))
980 return false;
981 if (*s++ != RDELIM_L)
982 goto fail;
983 while (isspace((unsigned char) *s))
984 s++;
985 if (*s != '\0')
986 goto fail;
987 return true;
988
989fail:
990 ereturn(escontext, false,
992 errmsg("invalid input syntax for type %s: \"%s\"",
993 "line", str)));
994}
995
996Datum
998{
999 char *str = PG_GETARG_CSTRING(0);
1000 Node *escontext = fcinfo->context;
1001 LINE *line = palloc_object(LINE);
1002 LSEG lseg;
1003 bool isopen;
1004 char *s;
1005
1006 s = str;
1007 while (isspace((unsigned char) *s))
1008 s++;
1009 if (*s == LDELIM_L)
1010 {
1011 if (!line_decode(s + 1, str, line, escontext))
1013 if (FPzero(line->A) && FPzero(line->B))
1014 ereturn(escontext, (Datum) 0,
1016 errmsg("invalid line specification: A and B cannot both be zero")));
1017 }
1018 else
1019 {
1020 if (!path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str,
1021 escontext))
1023 if (point_eq_point(&lseg.p[0], &lseg.p[1]))
1024 ereturn(escontext, (Datum) 0,
1026 errmsg("invalid line specification: must be two distinct points")));
1027
1028 /*
1029 * XXX lseg_sl() and line_construct() can throw overflow/underflow
1030 * errors. Eventually we should allow those to be soft, but the
1031 * notational pain seems to outweigh the value for now.
1032 */
1033 line_construct(line, &lseg.p[0], lseg_sl(&lseg));
1034 }
1035
1036 PG_RETURN_LINE_P(line);
1037}
1038
1039
1040Datum
1042{
1043 LINE *line = PG_GETARG_LINE_P(0);
1044 char *astr = float8out_internal(line->A);
1045 char *bstr = float8out_internal(line->B);
1046 char *cstr = float8out_internal(line->C);
1047
1048 PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
1049 DELIM, cstr, RDELIM_L));
1050}
1051
1052/*
1053 * line_recv - converts external binary format to line
1054 */
1055Datum
1057{
1059 LINE *line;
1060
1061 line = palloc_object(LINE);
1062
1063 line->A = pq_getmsgfloat8(buf);
1064 line->B = pq_getmsgfloat8(buf);
1065 line->C = pq_getmsgfloat8(buf);
1066
1067 if (FPzero(line->A) && FPzero(line->B))
1068 ereport(ERROR,
1070 errmsg("invalid line specification: A and B cannot both be zero")));
1071
1072 PG_RETURN_LINE_P(line);
1073}
1074
1075/*
1076 * line_send - converts line to binary format
1077 */
1078Datum
1080{
1081 LINE *line = PG_GETARG_LINE_P(0);
1083
1085 pq_sendfloat8(&buf, line->A);
1086 pq_sendfloat8(&buf, line->B);
1087 pq_sendfloat8(&buf, line->C);
1089}
1090
1091
1092/*----------------------------------------------------------
1093 * Conversion routines from one line formula to internal.
1094 * Internal form: Ax+By+C=0
1095 *---------------------------------------------------------*/
1096
1097/*
1098 * Fill already-allocated LINE struct from the point and the slope
1099 */
1100static inline void
1102{
1103 if (isinf(m))
1104 {
1105 /* vertical - use "x = C" */
1106 result->A = -1.0;
1107 result->B = 0.0;
1108 result->C = pt->x;
1109 }
1110 else if (m == 0)
1111 {
1112 /* horizontal - use "y = C" */
1113 result->A = 0.0;
1114 result->B = -1.0;
1115 result->C = pt->y;
1116 }
1117 else
1118 {
1119 /* use "mx - y + yinter = 0" */
1120 result->A = m;
1121 result->B = -1.0;
1122 result->C = float8_mi(pt->y, float8_mul(m, pt->x));
1123 /* on some platforms, the preceding expression tends to produce -0 */
1124 if (result->C == 0.0)
1125 result->C = 0.0;
1126 }
1127}
1128
1129/* line_construct_pp()
1130 * two points
1131 */
1132Datum
1134{
1137 LINE *result = palloc_object(LINE);
1138
1139 if (point_eq_point(pt1, pt2))
1140 ereport(ERROR,
1142 errmsg("invalid line specification: must be two distinct points")));
1143
1144 line_construct(result, pt1, point_sl(pt1, pt2));
1145
1146 PG_RETURN_LINE_P(result);
1147}
1148
1149
1150/*----------------------------------------------------------
1151 * Relative position routines.
1152 *---------------------------------------------------------*/
1153
1154Datum
1162
1163Datum
1165{
1166 LINE *l1 = PG_GETARG_LINE_P(0);
1167 LINE *l2 = PG_GETARG_LINE_P(1);
1168
1170}
1171
1172Datum
1174{
1175 LINE *l1 = PG_GETARG_LINE_P(0);
1176 LINE *l2 = PG_GETARG_LINE_P(1);
1177
1178 if (FPzero(l1->A))
1179 PG_RETURN_BOOL(FPzero(l2->B));
1180 if (FPzero(l2->A))
1181 PG_RETURN_BOOL(FPzero(l1->B));
1182 if (FPzero(l1->B))
1183 PG_RETURN_BOOL(FPzero(l2->A));
1184 if (FPzero(l2->B))
1185 PG_RETURN_BOOL(FPzero(l1->A));
1186
1188 float8_mul(l1->B, l2->B)), -1.0));
1189}
1190
1191Datum
1193{
1194 LINE *line = PG_GETARG_LINE_P(0);
1195
1196 PG_RETURN_BOOL(FPzero(line->B));
1197}
1198
1199Datum
1201{
1202 LINE *line = PG_GETARG_LINE_P(0);
1203
1204 PG_RETURN_BOOL(FPzero(line->A));
1205}
1206
1207
1208/*
1209 * Check whether the two lines are the same
1210 */
1211Datum
1213{
1214 LINE *l1 = PG_GETARG_LINE_P(0);
1215 LINE *l2 = PG_GETARG_LINE_P(1);
1216 float8 ratio;
1217
1218 /* If any NaNs are involved, insist on exact equality */
1219 if (unlikely(isnan(l1->A) || isnan(l1->B) || isnan(l1->C) ||
1220 isnan(l2->A) || isnan(l2->B) || isnan(l2->C)))
1221 {
1222 PG_RETURN_BOOL(float8_eq(l1->A, l2->A) &&
1223 float8_eq(l1->B, l2->B) &&
1224 float8_eq(l1->C, l2->C));
1225 }
1226
1227 /* Otherwise, lines whose parameters are proportional are the same */
1228 if (!FPzero(l2->A))
1229 ratio = float8_div(l1->A, l2->A);
1230 else if (!FPzero(l2->B))
1231 ratio = float8_div(l1->B, l2->B);
1232 else if (!FPzero(l2->C))
1233 ratio = float8_div(l1->C, l2->C);
1234 else
1235 ratio = 1.0;
1236
1237 PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
1238 FPeq(l1->B, float8_mul(ratio, l2->B)) &&
1239 FPeq(l1->C, float8_mul(ratio, l2->C)));
1240}
1241
1242
1243/*----------------------------------------------------------
1244 * Line arithmetic routines.
1245 *---------------------------------------------------------*/
1246
1247/*
1248 * Return slope of the line
1249 */
1250static inline float8
1252{
1253 if (FPzero(line->A))
1254 return 0.0;
1255 if (FPzero(line->B))
1256 return get_float8_infinity();
1257 return float8_div(line->A, -line->B);
1258}
1259
1260
1261/*
1262 * Return inverse slope of the line
1263 */
1264static inline float8
1266{
1267 if (FPzero(line->A))
1268 return get_float8_infinity();
1269 if (FPzero(line->B))
1270 return 0.0;
1271 return float8_div(line->B, line->A);
1272}
1273
1274
1275/* line_distance()
1276 * Distance between two lines.
1277 */
1278Datum
1280{
1281 LINE *l1 = PG_GETARG_LINE_P(0);
1282 LINE *l2 = PG_GETARG_LINE_P(1);
1283 float8 ratio;
1284
1285 if (line_interpt_line(NULL, l1, l2)) /* intersecting? */
1286 PG_RETURN_FLOAT8(0.0);
1287
1288 if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
1289 ratio = float8_div(l1->A, l2->A);
1290 else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
1291 ratio = float8_div(l1->B, l2->B);
1292 else
1293 ratio = 1.0;
1294
1296 float8_mul(ratio, l2->C))),
1297 hypot(l1->A, l1->B)));
1298}
1299
1300/* line_interpt()
1301 * Point where two lines l1, l2 intersect (if any)
1302 */
1303Datum
1305{
1306 LINE *l1 = PG_GETARG_LINE_P(0);
1307 LINE *l2 = PG_GETARG_LINE_P(1);
1308 Point *result;
1309
1310 result = palloc_object(Point);
1311
1312 if (!line_interpt_line(result, l1, l2))
1314 PG_RETURN_POINT_P(result);
1315}
1316
1317/*
1318 * Internal version of line_interpt
1319 *
1320 * Return whether two lines intersect. If *result is not NULL, it is set to
1321 * the intersection point.
1322 *
1323 * NOTE: If the lines are identical then we will find they are parallel
1324 * and report "no intersection". This is a little weird, but since
1325 * there's no *unique* intersection, maybe it's appropriate behavior.
1326 *
1327 * If the lines have NaN constants, we will return true, and the intersection
1328 * point would have NaN coordinates. We shouldn't return false in this case
1329 * because that would mean the lines are parallel.
1330 */
1331static bool
1333{
1334 float8 x,
1335 y;
1336
1337 if (!FPzero(l1->B))
1338 {
1339 if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
1340 return false;
1341
1342 x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
1343 float8_mul(l2->B, l1->C)),
1344 float8_mi(float8_mul(l1->A, l2->B),
1345 float8_mul(l2->A, l1->B)));
1346 y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
1347 }
1348 else if (!FPzero(l2->B))
1349 {
1350 if (FPeq(l1->A, float8_mul(l2->A, float8_div(l1->B, l2->B))))
1351 return false;
1352
1353 x = float8_div(float8_mi(float8_mul(l2->B, l1->C),
1354 float8_mul(l1->B, l2->C)),
1355 float8_mi(float8_mul(l2->A, l1->B),
1356 float8_mul(l1->A, l2->B)));
1357 y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
1358 }
1359 else
1360 return false;
1361
1362 /* On some platforms, the preceding expressions tend to produce -0. */
1363 if (x == 0.0)
1364 x = 0.0;
1365 if (y == 0.0)
1366 y = 0.0;
1367
1368 if (result != NULL)
1369 point_construct(result, x, y);
1370
1371 return true;
1372}
1373
1374
1375/***********************************************************************
1376 **
1377 ** Routines for 2D paths (sequences of line segments, also
1378 ** called `polylines').
1379 **
1380 ** This is not a general package for geometric paths,
1381 ** which of course include polygons; the emphasis here
1382 ** is on (for example) usefulness in wire layout.
1383 **
1384 ***********************************************************************/
1385
1386/*----------------------------------------------------------
1387 * String to path / path to string conversion.
1388 * External format:
1389 * "((xcoord, ycoord),... )"
1390 * "[(xcoord, ycoord),... ]"
1391 * "(xcoord, ycoord),... "
1392 * "[xcoord, ycoord,... ]"
1393 * Also support older format:
1394 * "(closed, npts, xcoord, ycoord,... )"
1395 *---------------------------------------------------------*/
1396
1397Datum
1399{
1400 PATH *path = PG_GETARG_PATH_P(0);
1401 float8 area = 0.0;
1402 int i,
1403 j;
1404
1405 if (!path->closed)
1407
1408 for (i = 0; i < path->npts; i++)
1409 {
1410 j = (i + 1) % path->npts;
1411 area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
1412 area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
1413 }
1414
1415 PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
1416}
1417
1418
1419Datum
1421{
1422 char *str = PG_GETARG_CSTRING(0);
1423 Node *escontext = fcinfo->context;
1424 PATH *path;
1425 bool isopen;
1426 char *s;
1427 int npts;
1428 int size;
1429 int base_size;
1430 int depth = 0;
1431
1432 if ((npts = pair_count(str, ',')) <= 0)
1433 ereturn(escontext, (Datum) 0,
1435 errmsg("invalid input syntax for type %s: \"%s\"",
1436 "path", str)));
1437
1438 s = str;
1439 while (isspace((unsigned char) *s))
1440 s++;
1441
1442 /* skip single leading paren */
1443 if ((*s == LDELIM) && (strrchr(s, LDELIM) == s))
1444 {
1445 s++;
1446 depth++;
1447 }
1448
1449 base_size = sizeof(path->p[0]) * npts;
1450 size = offsetof(PATH, p) + base_size;
1451
1452 /* Check for integer overflow */
1453 if (base_size / npts != sizeof(path->p[0]) || size <= base_size)
1454 ereturn(escontext, (Datum) 0,
1456 errmsg("too many points requested")));
1457
1458 path = (PATH *) palloc(size);
1459
1460 SET_VARSIZE(path, size);
1461 path->npts = npts;
1462
1463 if (!path_decode(s, true, npts, &(path->p[0]), &isopen, &s, "path", str,
1464 escontext))
1466
1467 if (depth >= 1)
1468 {
1469 if (*s++ != RDELIM)
1470 ereturn(escontext, (Datum) 0,
1472 errmsg("invalid input syntax for type %s: \"%s\"",
1473 "path", str)));
1474 while (isspace((unsigned char) *s))
1475 s++;
1476 }
1477 if (*s != '\0')
1478 ereturn(escontext, (Datum) 0,
1480 errmsg("invalid input syntax for type %s: \"%s\"",
1481 "path", str)));
1482
1483 path->closed = (!isopen);
1484 /* prevent instability in unused pad bytes */
1485 path->dummy = 0;
1486
1487 PG_RETURN_PATH_P(path);
1488}
1489
1490
1491Datum
1493{
1494 PATH *path = PG_GETARG_PATH_P(0);
1495
1497}
1498
1499/*
1500 * path_recv - converts external binary format to path
1501 *
1502 * External representation is closed flag (a boolean byte), int32 number
1503 * of points, and the points.
1504 */
1505Datum
1507{
1509 PATH *path;
1510 int closed;
1511 int32 npts;
1512 int32 i;
1513 int size;
1514
1515 closed = pq_getmsgbyte(buf);
1516 npts = pq_getmsgint(buf, sizeof(int32));
1517 if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(PATH, p)) / sizeof(Point)))
1518 ereport(ERROR,
1520 errmsg("invalid number of points in external \"path\" value")));
1521
1522 size = offsetof(PATH, p) + sizeof(path->p[0]) * npts;
1523 path = (PATH *) palloc(size);
1524
1525 SET_VARSIZE(path, size);
1526 path->npts = npts;
1527 path->closed = (closed ? 1 : 0);
1528 /* prevent instability in unused pad bytes */
1529 path->dummy = 0;
1530
1531 for (i = 0; i < npts; i++)
1532 {
1533 path->p[i].x = pq_getmsgfloat8(buf);
1534 path->p[i].y = pq_getmsgfloat8(buf);
1535 }
1536
1537 PG_RETURN_PATH_P(path);
1538}
1539
1540/*
1541 * path_send - converts path to binary format
1542 */
1543Datum
1545{
1546 PATH *path = PG_GETARG_PATH_P(0);
1548 int32 i;
1549
1551 pq_sendbyte(&buf, path->closed ? 1 : 0);
1552 pq_sendint32(&buf, path->npts);
1553 for (i = 0; i < path->npts; i++)
1554 {
1555 pq_sendfloat8(&buf, path->p[i].x);
1556 pq_sendfloat8(&buf, path->p[i].y);
1557 }
1559}
1560
1561
1562/*----------------------------------------------------------
1563 * Relational operators.
1564 * These are based on the path cardinality,
1565 * as stupid as that sounds.
1566 *
1567 * Better relops and access methods coming soon.
1568 *---------------------------------------------------------*/
1569
1570Datum
1572{
1573 PATH *p1 = PG_GETARG_PATH_P(0);
1574 PATH *p2 = PG_GETARG_PATH_P(1);
1575
1576 PG_RETURN_BOOL(p1->npts < p2->npts);
1577}
1578
1579Datum
1581{
1582 PATH *p1 = PG_GETARG_PATH_P(0);
1583 PATH *p2 = PG_GETARG_PATH_P(1);
1584
1585 PG_RETURN_BOOL(p1->npts > p2->npts);
1586}
1587
1588Datum
1590{
1591 PATH *p1 = PG_GETARG_PATH_P(0);
1592 PATH *p2 = PG_GETARG_PATH_P(1);
1593
1594 PG_RETURN_BOOL(p1->npts == p2->npts);
1595}
1596
1597Datum
1599{
1600 PATH *p1 = PG_GETARG_PATH_P(0);
1601 PATH *p2 = PG_GETARG_PATH_P(1);
1602
1603 PG_RETURN_BOOL(p1->npts <= p2->npts);
1604}
1605
1606Datum
1608{
1609 PATH *p1 = PG_GETARG_PATH_P(0);
1610 PATH *p2 = PG_GETARG_PATH_P(1);
1611
1612 PG_RETURN_BOOL(p1->npts >= p2->npts);
1613}
1614
1615/*----------------------------------------------------------
1616 * Conversion operators.
1617 *---------------------------------------------------------*/
1618
1619Datum
1621{
1622 PATH *path = PG_GETARG_PATH_P(0);
1623
1624 PG_RETURN_BOOL(path->closed);
1625}
1626
1627Datum
1629{
1630 PATH *path = PG_GETARG_PATH_P(0);
1631
1632 PG_RETURN_BOOL(!path->closed);
1633}
1634
1635Datum
1637{
1638 PATH *path = PG_GETARG_PATH_P(0);
1639
1640 PG_RETURN_INT32(path->npts);
1641}
1642
1643
1644Datum
1646{
1647 PATH *path = PG_GETARG_PATH_P_COPY(0);
1648
1649 path->closed = true;
1650
1651 PG_RETURN_PATH_P(path);
1652}
1653
1654Datum
1656{
1657 PATH *path = PG_GETARG_PATH_P_COPY(0);
1658
1659 path->closed = false;
1660
1661 PG_RETURN_PATH_P(path);
1662}
1663
1664
1665/* path_inter -
1666 * Does p1 intersect p2 at any point?
1667 * Use bounding boxes for a quick (O(n)) check, then do a
1668 * O(n^2) iterative edge check.
1669 */
1670Datum
1672{
1673 PATH *p1 = PG_GETARG_PATH_P(0);
1674 PATH *p2 = PG_GETARG_PATH_P(1);
1675 BOX b1,
1676 b2;
1677 int i,
1678 j;
1679 LSEG seg1,
1680 seg2;
1681
1682 Assert(p1->npts > 0 && p2->npts > 0);
1683
1684 b1.high.x = b1.low.x = p1->p[0].x;
1685 b1.high.y = b1.low.y = p1->p[0].y;
1686 for (i = 1; i < p1->npts; i++)
1687 {
1688 b1.high.x = float8_max(p1->p[i].x, b1.high.x);
1689 b1.high.y = float8_max(p1->p[i].y, b1.high.y);
1690 b1.low.x = float8_min(p1->p[i].x, b1.low.x);
1691 b1.low.y = float8_min(p1->p[i].y, b1.low.y);
1692 }
1693 b2.high.x = b2.low.x = p2->p[0].x;
1694 b2.high.y = b2.low.y = p2->p[0].y;
1695 for (i = 1; i < p2->npts; i++)
1696 {
1697 b2.high.x = float8_max(p2->p[i].x, b2.high.x);
1698 b2.high.y = float8_max(p2->p[i].y, b2.high.y);
1699 b2.low.x = float8_min(p2->p[i].x, b2.low.x);
1700 b2.low.y = float8_min(p2->p[i].y, b2.low.y);
1701 }
1702 if (!box_ov(&b1, &b2))
1703 PG_RETURN_BOOL(false);
1704
1705 /* pairwise check lseg intersections */
1706 for (i = 0; i < p1->npts; i++)
1707 {
1708 int iprev;
1709
1710 if (i > 0)
1711 iprev = i - 1;
1712 else
1713 {
1714 if (!p1->closed)
1715 continue;
1716 iprev = p1->npts - 1; /* include the closure segment */
1717 }
1718
1719 for (j = 0; j < p2->npts; j++)
1720 {
1721 int jprev;
1722
1723 if (j > 0)
1724 jprev = j - 1;
1725 else
1726 {
1727 if (!p2->closed)
1728 continue;
1729 jprev = p2->npts - 1; /* include the closure segment */
1730 }
1731
1732 statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
1733 statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
1735 PG_RETURN_BOOL(true);
1736 }
1737 }
1738
1739 /* if we dropped through, no two segs intersected */
1740 PG_RETURN_BOOL(false);
1741}
1742
1743/* path_distance()
1744 * This essentially does a cartesian product of the lsegs in the
1745 * two paths, and finds the min distance between any two lsegs
1746 */
1747Datum
1749{
1750 PATH *p1 = PG_GETARG_PATH_P(0);
1751 PATH *p2 = PG_GETARG_PATH_P(1);
1752 float8 min = 0.0; /* initialize to keep compiler quiet */
1753 bool have_min = false;
1754 float8 tmp;
1755 int i,
1756 j;
1757 LSEG seg1,
1758 seg2;
1759
1760 for (i = 0; i < p1->npts; i++)
1761 {
1762 int iprev;
1763
1764 if (i > 0)
1765 iprev = i - 1;
1766 else
1767 {
1768 if (!p1->closed)
1769 continue;
1770 iprev = p1->npts - 1; /* include the closure segment */
1771 }
1772
1773 for (j = 0; j < p2->npts; j++)
1774 {
1775 int jprev;
1776
1777 if (j > 0)
1778 jprev = j - 1;
1779 else
1780 {
1781 if (!p2->closed)
1782 continue;
1783 jprev = p2->npts - 1; /* include the closure segment */
1784 }
1785
1786 statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
1787 statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
1788
1789 tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
1790 if (!have_min || float8_lt(tmp, min))
1791 {
1792 min = tmp;
1793 have_min = true;
1794 }
1795 }
1796 }
1797
1798 if (!have_min)
1800
1801 PG_RETURN_FLOAT8(min);
1802}
1803
1804
1805/*----------------------------------------------------------
1806 * "Arithmetic" operations.
1807 *---------------------------------------------------------*/
1808
1809Datum
1811{
1812 PATH *path = PG_GETARG_PATH_P(0);
1813 float8 result = 0.0;
1814 int i;
1815
1816 for (i = 0; i < path->npts; i++)
1817 {
1818 int iprev;
1819
1820 if (i > 0)
1821 iprev = i - 1;
1822 else
1823 {
1824 if (!path->closed)
1825 continue;
1826 iprev = path->npts - 1; /* include the closure segment */
1827 }
1828
1829 result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i], NULL));
1830 }
1831
1832 PG_RETURN_FLOAT8(result);
1833}
1834
1835/***********************************************************************
1836 **
1837 ** Routines for 2D points.
1838 **
1839 ***********************************************************************/
1840
1841/*----------------------------------------------------------
1842 * String to point, point to string conversion.
1843 * External format:
1844 * "(x,y)"
1845 * "x,y"
1846 *---------------------------------------------------------*/
1847
1848Datum
1850{
1851 char *str = PG_GETARG_CSTRING(0);
1853
1854 /* Ignore failure from pair_decode, since our return value won't matter */
1855 pair_decode(str, &point->x, &point->y, NULL, "point", str, fcinfo->context);
1857}
1858
1859Datum
1866
1867/*
1868 * point_recv - converts external binary format to point
1869 */
1870Datum
1881
1882/*
1883 * point_send - converts point to binary format
1884 */
1885Datum
1896
1897
1898/*
1899 * Initialize a point
1900 */
1901static inline void
1903{
1904 result->x = x;
1905 result->y = y;
1906}
1907
1908
1909/*----------------------------------------------------------
1910 * Relational operators for Points.
1911 * Since we do have a sense of coordinates being
1912 * "equal" to a given accuracy (point_vert, point_horiz),
1913 * the other ops must preserve that sense. This means
1914 * that results may, strictly speaking, be a lie (unless
1915 * EPSILON = 0.0).
1916 *---------------------------------------------------------*/
1917
1918Datum
1926
1927Datum
1935
1936Datum
1944
1945Datum
1953
1954Datum
1962
1963Datum
1971
1972Datum
1980
1981Datum
1989
1990
1991/*
1992 * Check whether the two points are the same
1993 */
1994static inline bool
1996{
1997 /* If any NaNs are involved, insist on exact equality */
1998 if (unlikely(isnan(pt1->x) || isnan(pt1->y) ||
1999 isnan(pt2->x) || isnan(pt2->y)))
2000 return (float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y));
2001
2002 return (FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
2003}
2004
2005
2006/*----------------------------------------------------------
2007 * "Arithmetic" operators on points.
2008 *---------------------------------------------------------*/
2009
2010Datum
2018
2019static inline float8
2021{
2022 float8 x;
2023 float8 y;
2024
2025 x = float8_mi_safe(pt1->x, pt2->x, escontext);
2026 if (unlikely(SOFT_ERROR_OCCURRED(escontext)))
2027 return 0.0;
2028
2029 y = float8_mi_safe(pt1->y, pt2->y, escontext);
2030 if (unlikely(SOFT_ERROR_OCCURRED(escontext)))
2031 return 0.0;
2032
2033 return hypot(x, y);
2034}
2035
2036Datum
2044
2045
2046/*
2047 * Return slope of two points
2048 *
2049 * Note that this function returns Inf when the points are the same.
2050 */
2051static inline float8
2053{
2054 if (FPeq(pt1->x, pt2->x))
2055 return get_float8_infinity();
2056 if (FPeq(pt1->y, pt2->y))
2057 return 0.0;
2058 return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
2059}
2060
2061
2062/*
2063 * Return inverse slope of two points
2064 *
2065 * Note that this function returns 0.0 when the points are the same.
2066 */
2067static inline float8
2069{
2070 if (FPeq(pt1->x, pt2->x))
2071 return 0.0;
2072 if (FPeq(pt1->y, pt2->y))
2073 return get_float8_infinity();
2074 return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y));
2075}
2076
2077
2078/***********************************************************************
2079 **
2080 ** Routines for 2D line segments.
2081 **
2082 ***********************************************************************/
2083
2084/*----------------------------------------------------------
2085 * String to lseg, lseg to string conversion.
2086 * External forms: "[(x1, y1), (x2, y2)]"
2087 * "(x1, y1), (x2, y2)"
2088 * "x1, y1, x2, y2"
2089 * closed form ok "((x1, y1), (x2, y2))"
2090 * (old form) "(x1, y1, x2, y2)"
2091 *---------------------------------------------------------*/
2092
2093Datum
2095{
2096 char *str = PG_GETARG_CSTRING(0);
2097 Node *escontext = fcinfo->context;
2099 bool isopen;
2100
2101 if (!path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str,
2102 escontext))
2104
2106}
2107
2108
2109Datum
2116
2117/*
2118 * lseg_recv - converts external binary format to lseg
2119 */
2120Datum
2122{
2124 LSEG *lseg;
2125
2127
2128 lseg->p[0].x = pq_getmsgfloat8(buf);
2129 lseg->p[0].y = pq_getmsgfloat8(buf);
2130 lseg->p[1].x = pq_getmsgfloat8(buf);
2131 lseg->p[1].y = pq_getmsgfloat8(buf);
2132
2134}
2135
2136/*
2137 * lseg_send - converts lseg to binary format
2138 */
2139Datum
2141{
2142 LSEG *ls = PG_GETARG_LSEG_P(0);
2144
2146 pq_sendfloat8(&buf, ls->p[0].x);
2147 pq_sendfloat8(&buf, ls->p[0].y);
2148 pq_sendfloat8(&buf, ls->p[1].x);
2149 pq_sendfloat8(&buf, ls->p[1].y);
2151}
2152
2153
2154/* lseg_construct -
2155 * form a LSEG from two Points.
2156 */
2157Datum
2159{
2162 LSEG *result = palloc_object(LSEG);
2163
2164 statlseg_construct(result, pt1, pt2);
2165
2166 PG_RETURN_LSEG_P(result);
2167}
2168
2169/* like lseg_construct, but assume space already allocated */
2170static inline void
2172{
2173 lseg->p[0].x = pt1->x;
2174 lseg->p[0].y = pt1->y;
2175 lseg->p[1].x = pt2->x;
2176 lseg->p[1].y = pt2->y;
2177}
2178
2179
2180/*
2181 * Return slope of the line segment
2182 */
2183static inline float8
2185{
2186 return point_sl(&lseg->p[0], &lseg->p[1]);
2187}
2188
2189
2190/*
2191 * Return inverse slope of the line segment
2192 */
2193static inline float8
2195{
2196 return point_invsl(&lseg->p[0], &lseg->p[1]);
2197}
2198
2199
2200Datum
2202{
2204
2205 PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1], NULL));
2206}
2207
2208/*----------------------------------------------------------
2209 * Relative position routines.
2210 *---------------------------------------------------------*/
2211
2212/*
2213 ** find intersection of the two lines, and see if it falls on
2214 ** both segments.
2215 */
2216Datum
2224
2225
2226Datum
2228{
2229 LSEG *l1 = PG_GETARG_LSEG_P(0);
2230 LSEG *l2 = PG_GETARG_LSEG_P(1);
2231
2233}
2234
2235/*
2236 * Determine if two line segments are perpendicular.
2237 */
2238Datum
2240{
2241 LSEG *l1 = PG_GETARG_LSEG_P(0);
2242 LSEG *l2 = PG_GETARG_LSEG_P(1);
2243
2245}
2246
2247Datum
2249{
2251
2252 PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
2253}
2254
2255Datum
2257{
2259
2260 PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
2261}
2262
2263
2264Datum
2266{
2267 LSEG *l1 = PG_GETARG_LSEG_P(0);
2268 LSEG *l2 = PG_GETARG_LSEG_P(1);
2269
2270 PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
2271 point_eq_point(&l1->p[1], &l2->p[1]));
2272}
2273
2274Datum
2276{
2277 LSEG *l1 = PG_GETARG_LSEG_P(0);
2278 LSEG *l2 = PG_GETARG_LSEG_P(1);
2279
2280 PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
2281 !point_eq_point(&l1->p[1], &l2->p[1]));
2282}
2283
2284Datum
2286{
2287 LSEG *l1 = PG_GETARG_LSEG_P(0);
2288 LSEG *l2 = PG_GETARG_LSEG_P(1);
2289
2290 PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1], NULL),
2291 point_dt(&l2->p[0], &l2->p[1], NULL)));
2292}
2293
2294Datum
2296{
2297 LSEG *l1 = PG_GETARG_LSEG_P(0);
2298 LSEG *l2 = PG_GETARG_LSEG_P(1);
2299
2300 PG_RETURN_BOOL(FPle(point_dt(&l1->p[0], &l1->p[1], NULL),
2301 point_dt(&l2->p[0], &l2->p[1], NULL)));
2302}
2303
2304Datum
2306{
2307 LSEG *l1 = PG_GETARG_LSEG_P(0);
2308 LSEG *l2 = PG_GETARG_LSEG_P(1);
2309
2310 PG_RETURN_BOOL(FPgt(point_dt(&l1->p[0], &l1->p[1], NULL),
2311 point_dt(&l2->p[0], &l2->p[1], NULL)));
2312}
2313
2314Datum
2316{
2317 LSEG *l1 = PG_GETARG_LSEG_P(0);
2318 LSEG *l2 = PG_GETARG_LSEG_P(1);
2319
2320 PG_RETURN_BOOL(FPge(point_dt(&l1->p[0], &l1->p[1], NULL),
2321 point_dt(&l2->p[0], &l2->p[1], NULL)));
2322}
2323
2324
2325/*----------------------------------------------------------
2326 * Line arithmetic routines.
2327 *---------------------------------------------------------*/
2328
2329/* lseg_distance -
2330 * If two segments don't intersect, then the closest
2331 * point will be from one of the endpoints to the other
2332 * segment.
2333 */
2334Datum
2342
2343
2344Datum
2346{
2348 Point *result;
2349 float8 x;
2350 float8 y;
2351
2352 result = palloc_object(Point);
2353
2354 x = float8_pl_safe(lseg->p[0].x, lseg->p[1].x, fcinfo->context);
2355 if (SOFT_ERROR_OCCURRED(fcinfo->context))
2356 goto fail;
2357
2358 result->x = float8_div_safe(x, 2.0, fcinfo->context);
2359 if (SOFT_ERROR_OCCURRED(fcinfo->context))
2360 goto fail;
2361
2362 y = float8_pl_safe(lseg->p[0].y, lseg->p[1].y, fcinfo->context);
2363 if (SOFT_ERROR_OCCURRED(fcinfo->context))
2364 goto fail;
2365
2366 result->y = float8_div_safe(y, 2.0, fcinfo->context);
2367 if (SOFT_ERROR_OCCURRED(fcinfo->context))
2368 goto fail;
2369
2370 PG_RETURN_POINT_P(result);
2371
2372fail:
2374}
2375
2376
2377/*
2378 * Return whether the two segments intersect. If *result is not NULL,
2379 * it is set to the intersection point.
2380 *
2381 * This function is almost perfectly symmetric, even though it doesn't look
2382 * like it. See lseg_interpt_line() for the other half of it.
2383 */
2384static bool
2386{
2387 Point interpt;
2388 LINE tmp;
2389
2390 line_construct(&tmp, &l2->p[0], lseg_sl(l2));
2391 if (!lseg_interpt_line(&interpt, l1, &tmp))
2392 return false;
2393
2394 /*
2395 * If the line intersection point isn't within l2, there is no valid
2396 * segment intersection point at all.
2397 */
2398 if (!lseg_contain_point(l2, &interpt))
2399 return false;
2400
2401 if (result != NULL)
2402 *result = interpt;
2403
2404 return true;
2405}
2406
2407Datum
2409{
2410 LSEG *l1 = PG_GETARG_LSEG_P(0);
2411 LSEG *l2 = PG_GETARG_LSEG_P(1);
2412 Point *result;
2413
2414 result = palloc_object(Point);
2415
2416 if (!lseg_interpt_lseg(result, l1, l2))
2418 PG_RETURN_POINT_P(result);
2419}
2420
2421/***********************************************************************
2422 **
2423 ** Routines for position comparisons of differently-typed
2424 ** 2D objects.
2425 **
2426 ***********************************************************************/
2427
2428/*---------------------------------------------------------------------
2429 * dist_
2430 * Minimum distance from one object to another.
2431 *-------------------------------------------------------------------*/
2432
2433/*
2434 * Distance from a point to a line
2435 */
2436Datum
2444
2445/*
2446 * Distance from a line to a point
2447 */
2448Datum
2456
2457/*
2458 * Distance from a point to a lseg
2459 */
2460Datum
2468
2469/*
2470 * Distance from a lseg to a point
2471 */
2472Datum
2480
2481static float8
2483{
2484 float8 result = 0.0; /* keep compiler quiet */
2485 bool have_min = false;
2486 float8 tmp;
2487 int i;
2488 LSEG lseg;
2489
2490 Assert(path->npts > 0);
2491
2492 /*
2493 * The distance from a point to a path is the smallest distance from the
2494 * point to any of its constituent segments.
2495 */
2496 for (i = 0; i < path->npts; i++)
2497 {
2498 int iprev;
2499
2500 if (i > 0)
2501 iprev = i - 1;
2502 else
2503 {
2504 if (!path->closed)
2505 continue;
2506 iprev = path->npts - 1; /* Include the closure segment */
2507 }
2508
2509 statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
2510 tmp = lseg_closept_point(NULL, &lseg, pt);
2511 if (!have_min || float8_lt(tmp, result))
2512 {
2513 result = tmp;
2514 have_min = true;
2515 }
2516 }
2517
2518 return result;
2519}
2520
2521/*
2522 * Distance from a point to a path
2523 */
2524Datum
2532
2533/*
2534 * Distance from a path to a point
2535 */
2536Datum
2544
2545/*
2546 * Distance from a point to a box
2547 */
2548Datum
2556
2557/*
2558 * Distance from a box to a point
2559 */
2560Datum
2568
2569/*
2570 * Distance from a lseg to a line
2571 */
2572Datum
2580
2581/*
2582 * Distance from a line to a lseg
2583 */
2584Datum
2592
2593/*
2594 * Distance from a lseg to a box
2595 */
2596Datum
2604
2605/*
2606 * Distance from a box to a lseg
2607 */
2608Datum
2616
2617static float8
2619{
2620 float8 result;
2621
2622 /* calculate distance to center, and subtract radius */
2623 result = float8_mi(dist_ppoly_internal(&circle->center, poly),
2624 circle->radius);
2625 if (result < 0.0)
2626 result = 0.0;
2627
2628 return result;
2629}
2630
2631/*
2632 * Distance from a circle to a polygon
2633 */
2634Datum
2642
2643/*
2644 * Distance from a polygon to a circle
2645 */
2646Datum
2654
2655/*
2656 * Distance from a point to a polygon
2657 */
2658Datum
2666
2667Datum
2675
2676static float8
2678{
2679 float8 result;
2680 float8 d;
2681 int i;
2682 LSEG seg;
2683
2684 if (point_inside(pt, poly->npts, poly->p) != 0)
2685 return 0.0;
2686
2687 /* initialize distance with segment between first and last points */
2688 seg.p[0].x = poly->p[0].x;
2689 seg.p[0].y = poly->p[0].y;
2690 seg.p[1].x = poly->p[poly->npts - 1].x;
2691 seg.p[1].y = poly->p[poly->npts - 1].y;
2692 result = lseg_closept_point(NULL, &seg, pt);
2693
2694 /* check distances for other segments */
2695 for (i = 0; i < poly->npts - 1; i++)
2696 {
2697 seg.p[0].x = poly->p[i].x;
2698 seg.p[0].y = poly->p[i].y;
2699 seg.p[1].x = poly->p[i + 1].x;
2700 seg.p[1].y = poly->p[i + 1].y;
2701 d = lseg_closept_point(NULL, &seg, pt);
2702 if (float8_lt(d, result))
2703 result = d;
2704 }
2705
2706 return result;
2707}
2708
2709
2710/*---------------------------------------------------------------------
2711 * interpt_
2712 * Intersection point of objects.
2713 * We choose to ignore the "point" of intersection between
2714 * lines and boxes, since there are typically two.
2715 *-------------------------------------------------------------------*/
2716
2717/*
2718 * Return whether the line segment intersect with the line. If *result is not
2719 * NULL, it is set to the intersection point.
2720 */
2721static bool
2723{
2724 Point interpt;
2725 LINE tmp;
2726
2727 /*
2728 * First, we promote the line segment to a line, because we know how to
2729 * find the intersection point of two lines. If they don't have an
2730 * intersection point, we are done.
2731 */
2732 line_construct(&tmp, &lseg->p[0], lseg_sl(lseg));
2733 if (!line_interpt_line(&interpt, &tmp, line))
2734 return false;
2735
2736 /*
2737 * Then, we check whether the intersection point is actually on the line
2738 * segment.
2739 */
2741 return false;
2742 if (result != NULL)
2743 {
2744 /*
2745 * If there is an intersection, then check explicitly for matching
2746 * endpoints since there may be rounding effects with annoying LSB
2747 * residue.
2748 */
2749 if (point_eq_point(&lseg->p[0], &interpt))
2750 *result = lseg->p[0];
2751 else if (point_eq_point(&lseg->p[1], &interpt))
2752 *result = lseg->p[1];
2753 else
2754 *result = interpt;
2755 }
2756
2757 return true;
2758}
2759
2760/*---------------------------------------------------------------------
2761 * close_
2762 * Point of closest proximity between objects.
2763 *-------------------------------------------------------------------*/
2764
2765/*
2766 * If *result is not NULL, it is set to the intersection point of a
2767 * perpendicular of the line through the point. Returns the distance
2768 * of those two points.
2769 */
2770static float8
2772{
2773 Point closept;
2774 LINE tmp;
2775
2776 /*
2777 * We drop a perpendicular to find the intersection point. Ordinarily we
2778 * should always find it, but that can fail in the presence of NaN
2779 * coordinates, and perhaps even from simple roundoff issues.
2780 */
2781 line_construct(&tmp, point, line_invsl(line));
2782 if (!line_interpt_line(&closept, &tmp, line))
2783 {
2784 if (result != NULL)
2785 *result = *point;
2786
2787 return get_float8_nan();
2788 }
2789
2790 if (result != NULL)
2791 *result = closept;
2792
2793 return point_dt(&closept, point, NULL);
2794}
2795
2796Datum
2798{
2800 LINE *line = PG_GETARG_LINE_P(1);
2801 Point *result;
2802
2803 result = palloc_object(Point);
2804
2805 if (isnan(line_closept_point(result, line, pt)))
2807
2808 PG_RETURN_POINT_P(result);
2809}
2810
2811
2812/*
2813 * Closest point on line segment to specified point.
2814 *
2815 * If *result is not NULL, set it to the closest point on the line segment
2816 * to the point. Returns the distance of the two points.
2817 */
2818static float8
2820{
2821 Point closept;
2822 LINE tmp;
2823
2824 /*
2825 * To find the closest point, we draw a perpendicular line from the point
2826 * to the line segment.
2827 */
2828 line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]));
2830
2831 if (result != NULL)
2832 *result = closept;
2833
2834 return point_dt(&closept, pt, NULL);
2835}
2836
2837Datum
2839{
2842 Point *result;
2843
2844 result = palloc_object(Point);
2845
2846 if (isnan(lseg_closept_point(result, lseg, pt)))
2848
2849 PG_RETURN_POINT_P(result);
2850}
2851
2852
2853/*
2854 * Closest point on line segment to line segment
2855 */
2856static float8
2858{
2859 Point point;
2860 float8 dist,
2861 d;
2862
2863 /* First, we handle the case when the line segments are intersecting. */
2864 if (lseg_interpt_lseg(result, on_lseg, to_lseg))
2865 return 0.0;
2866
2867 /*
2868 * Then, we find the closest points from the endpoints of the second line
2869 * segment, and keep the closest one.
2870 */
2871 dist = lseg_closept_point(result, on_lseg, &to_lseg->p[0]);
2872 d = lseg_closept_point(&point, on_lseg, &to_lseg->p[1]);
2873 if (float8_lt(d, dist))
2874 {
2875 dist = d;
2876 if (result != NULL)
2877 *result = point;
2878 }
2879
2880 /* The closest point can still be one of the endpoints, so we test them. */
2881 d = lseg_closept_point(NULL, to_lseg, &on_lseg->p[0]);
2882 if (float8_lt(d, dist))
2883 {
2884 dist = d;
2885 if (result != NULL)
2886 *result = on_lseg->p[0];
2887 }
2888 d = lseg_closept_point(NULL, to_lseg, &on_lseg->p[1]);
2889 if (float8_lt(d, dist))
2890 {
2891 dist = d;
2892 if (result != NULL)
2893 *result = on_lseg->p[1];
2894 }
2895
2896 return dist;
2897}
2898
2899Datum
2901{
2902 LSEG *l1 = PG_GETARG_LSEG_P(0);
2903 LSEG *l2 = PG_GETARG_LSEG_P(1);
2904 Point *result;
2905
2906 if (lseg_sl(l1) == lseg_sl(l2))
2908
2909 result = palloc_object(Point);
2910
2911 if (isnan(lseg_closept_lseg(result, l2, l1)))
2913
2914 PG_RETURN_POINT_P(result);
2915}
2916
2917
2918/*
2919 * Closest point on or in box to specified point.
2920 *
2921 * If *result is not NULL, set it to the closest point on the box to the
2922 * given point, and return the distance of the two points.
2923 */
2924static float8
2926{
2927 float8 dist,
2928 d;
2929 Point point,
2930 closept;
2931 LSEG lseg;
2932
2933 if (box_contain_point(box, pt))
2934 {
2935 if (result != NULL)
2936 *result = *pt;
2937
2938 return 0.0;
2939 }
2940
2941 /* pairwise check lseg distances */
2942 point.x = box->low.x;
2943 point.y = box->high.y;
2944 statlseg_construct(&lseg, &box->low, &point);
2945 dist = lseg_closept_point(result, &lseg, pt);
2946
2947 statlseg_construct(&lseg, &box->high, &point);
2949 if (float8_lt(d, dist))
2950 {
2951 dist = d;
2952 if (result != NULL)
2953 *result = closept;
2954 }
2955
2956 point.x = box->high.x;
2957 point.y = box->low.y;
2958 statlseg_construct(&lseg, &box->low, &point);
2960 if (float8_lt(d, dist))
2961 {
2962 dist = d;
2963 if (result != NULL)
2964 *result = closept;
2965 }
2966
2967 statlseg_construct(&lseg, &box->high, &point);
2969 if (float8_lt(d, dist))
2970 {
2971 dist = d;
2972 if (result != NULL)
2973 *result = closept;
2974 }
2975
2976 return dist;
2977}
2978
2979Datum
2981{
2983 BOX *box = PG_GETARG_BOX_P(1);
2984 Point *result;
2985
2986 result = palloc_object(Point);
2987
2988 if (isnan(box_closept_point(result, box, pt)))
2990
2991 PG_RETURN_POINT_P(result);
2992}
2993
2994/*
2995 * Closest point on line segment to line.
2996 *
2997 * Return the distance between the line and the closest point of the line
2998 * segment to the line. If *result is not NULL, set it to that point.
2999 *
3000 * NOTE: When the lines are parallel, endpoints of one of the line segment
3001 * are FPeq(), in presence of NaN or Infinite coordinates, or perhaps =
3002 * even because of simple roundoff issues, there may not be a single closest
3003 * point. We are likely to set the result to the second endpoint in these
3004 * cases.
3005 */
3006static float8
3008{
3009 float8 dist1,
3010 dist2;
3011
3012 if (lseg_interpt_line(result, lseg, line))
3013 return 0.0;
3014
3015 dist1 = line_closept_point(NULL, line, &lseg->p[0]);
3016 dist2 = line_closept_point(NULL, line, &lseg->p[1]);
3017
3018 if (dist1 < dist2)
3019 {
3020 if (result != NULL)
3021 *result = lseg->p[0];
3022
3023 return dist1;
3024 }
3025 else
3026 {
3027 if (result != NULL)
3028 *result = lseg->p[1];
3029
3030 return dist2;
3031 }
3032}
3033
3034Datum
3036{
3037 LINE *line = PG_GETARG_LINE_P(0);
3039 Point *result;
3040
3041 if (lseg_sl(lseg) == line_sl(line))
3043
3044 result = palloc_object(Point);
3045
3046 if (isnan(lseg_closept_line(result, lseg, line)))
3048
3049 PG_RETURN_POINT_P(result);
3050}
3051
3052
3053/*
3054 * Closest point on or in box to line segment.
3055 *
3056 * Returns the distance between the closest point on or in the box to
3057 * the line segment. If *result is not NULL, it is set to that point.
3058 */
3059static float8
3061{
3062 float8 dist,
3063 d;
3064 Point point,
3065 closept;
3066 LSEG bseg;
3067
3068 if (box_interpt_lseg(result, box, lseg))
3069 return 0.0;
3070
3071 /* pairwise check lseg distances */
3072 point.x = box->low.x;
3073 point.y = box->high.y;
3074 statlseg_construct(&bseg, &box->low, &point);
3075 dist = lseg_closept_lseg(result, &bseg, lseg);
3076
3077 statlseg_construct(&bseg, &box->high, &point);
3079 if (float8_lt(d, dist))
3080 {
3081 dist = d;
3082 if (result != NULL)
3083 *result = closept;
3084 }
3085
3086 point.x = box->high.x;
3087 point.y = box->low.y;
3088 statlseg_construct(&bseg, &box->low, &point);
3090 if (float8_lt(d, dist))
3091 {
3092 dist = d;
3093 if (result != NULL)
3094 *result = closept;
3095 }
3096
3097 statlseg_construct(&bseg, &box->high, &point);
3099 if (float8_lt(d, dist))
3100 {
3101 dist = d;
3102 if (result != NULL)
3103 *result = closept;
3104 }
3105
3106 return dist;
3107}
3108
3109Datum
3111{
3113 BOX *box = PG_GETARG_BOX_P(1);
3114 Point *result;
3115
3116 result = palloc_object(Point);
3117
3118 if (isnan(box_closept_lseg(result, box, lseg)))
3120
3121 PG_RETURN_POINT_P(result);
3122}
3123
3124
3125/*---------------------------------------------------------------------
3126 * on_
3127 * Whether one object lies completely within another.
3128 *-------------------------------------------------------------------*/
3129
3130/*
3131 * Does the point satisfy the equation?
3132 */
3133static bool
3135{
3136 return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
3137 float8_mul(line->B, point->y)),
3138 line->C));
3139}
3140
3141Datum
3143{
3145 LINE *line = PG_GETARG_LINE_P(1);
3146
3148}
3149
3150
3151/*
3152 * Determine colinearity by detecting a triangle inequality.
3153 * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
3154 */
3155static bool
3157{
3158 return FPeq(point_dt(pt, &lseg->p[0], NULL) +
3159 point_dt(pt, &lseg->p[1], NULL),
3160 point_dt(&lseg->p[0], &lseg->p[1], NULL));
3161}
3162
3163Datum
3171
3172
3173/*
3174 * Check whether the point is in the box or on its border
3175 */
3176static bool
3178{
3179 return box->high.x >= point->x && box->low.x <= point->x &&
3180 box->high.y >= point->y && box->low.y <= point->y;
3181}
3182
3183Datum
3191
3192Datum
3200
3201/* on_ppath -
3202 * Whether a point lies within (on) a polyline.
3203 * If open, we have to (groan) check each segment.
3204 * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
3205 * If closed, we use the old O(n) ray method for point-in-polygon.
3206 * The ray is horizontal, from pt out to the right.
3207 * Each segment that crosses the ray counts as an
3208 * intersection; note that an endpoint or edge may touch
3209 * but not cross.
3210 * (we can do p-in-p in lg(n), but it takes preprocessing)
3211 */
3212Datum
3214{
3216 PATH *path = PG_GETARG_PATH_P(1);
3217 int i,
3218 n;
3219 float8 a,
3220 b;
3221
3222 /*-- OPEN --*/
3223 if (!path->closed)
3224 {
3225 n = path->npts - 1;
3226 a = point_dt(pt, &path->p[0], NULL);
3227 for (i = 0; i < n; i++)
3228 {
3229 b = point_dt(pt, &path->p[i + 1], NULL);
3230 if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1], NULL)))
3231 PG_RETURN_BOOL(true);
3232 a = b;
3233 }
3234 PG_RETURN_BOOL(false);
3235 }
3236
3237 /*-- CLOSED --*/
3238 PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
3239}
3240
3241
3242/*
3243 * Check whether the line segment is on the line or close enough
3244 *
3245 * It is, if both of its points are on the line or close enough.
3246 */
3247Datum
3249{
3251 LINE *line = PG_GETARG_LINE_P(1);
3252
3253 PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
3254 line_contain_point(line, &lseg->p[1]));
3255}
3256
3257
3258/*
3259 * Check whether the line segment is in the box or on its border
3260 *
3261 * It is, if both of its points are in the box or on its border.
3262 */
3263static bool
3265{
3266 return box_contain_point(box, &lseg->p[0]) &&
3267 box_contain_point(box, &lseg->p[1]);
3268}
3269
3270Datum
3278
3279/*---------------------------------------------------------------------
3280 * inter_
3281 * Whether one object intersects another.
3282 *-------------------------------------------------------------------*/
3283
3284Datum
3292
3293
3294/*
3295 * Do line segment and box intersect?
3296 *
3297 * Segment completely inside box counts as intersection.
3298 * If you want only segments crossing box boundaries,
3299 * try converting box to path first.
3300 *
3301 * This function also sets the *result to the closest point on the line
3302 * segment to the center of the box when they overlap and the result is
3303 * not NULL. It is somewhat arbitrary, but maybe the best we can do as
3304 * there are typically two points they intersect.
3305 *
3306 * Optimize for non-intersection by checking for box intersection first.
3307 * - thomas 1998-01-30
3308 */
3309static bool
3311{
3312 BOX lbox;
3313 LSEG bseg;
3314 Point point;
3315
3316 lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
3317 lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
3318 lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
3319 lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
3320
3321 /* nothing close to overlap? then not going to intersect */
3322 if (!box_ov(&lbox, box))
3323 return false;
3324
3325 if (result != NULL)
3326 {
3327 box_cn(&point, box, NULL);
3328 lseg_closept_point(result, lseg, &point);
3329 }
3330
3331 /* an endpoint of segment is inside box? then clearly intersects */
3332 if (box_contain_point(box, &lseg->p[0]) ||
3333 box_contain_point(box, &lseg->p[1]))
3334 return true;
3335
3336 /* pairwise check lseg intersections */
3337 point.x = box->low.x;
3338 point.y = box->high.y;
3339 statlseg_construct(&bseg, &box->low, &point);
3341 return true;
3342
3343 statlseg_construct(&bseg, &box->high, &point);
3345 return true;
3346
3347 point.x = box->high.x;
3348 point.y = box->low.y;
3349 statlseg_construct(&bseg, &box->low, &point);
3351 return true;
3352
3353 statlseg_construct(&bseg, &box->high, &point);
3355 return true;
3356
3357 /* if we dropped through, no two segs intersected */
3358 return false;
3359}
3360
3361Datum
3369
3370
3371/* inter_lb()
3372 * Do line and box intersect?
3373 */
3374Datum
3376{
3377 LINE *line = PG_GETARG_LINE_P(0);
3378 BOX *box = PG_GETARG_BOX_P(1);
3379 LSEG bseg;
3380 Point p1,
3381 p2;
3382
3383 /* pairwise check lseg intersections */
3384 p1.x = box->low.x;
3385 p1.y = box->low.y;
3386 p2.x = box->low.x;
3387 p2.y = box->high.y;
3389 if (lseg_interpt_line(NULL, &bseg, line))
3390 PG_RETURN_BOOL(true);
3391 p1.x = box->high.x;
3392 p1.y = box->high.y;
3394 if (lseg_interpt_line(NULL, &bseg, line))
3395 PG_RETURN_BOOL(true);
3396 p2.x = box->high.x;
3397 p2.y = box->low.y;
3399 if (lseg_interpt_line(NULL, &bseg, line))
3400 PG_RETURN_BOOL(true);
3401 p1.x = box->low.x;
3402 p1.y = box->low.y;
3404 if (lseg_interpt_line(NULL, &bseg, line))
3405 PG_RETURN_BOOL(true);
3406
3407 /* if we dropped through, no intersection */
3408 PG_RETURN_BOOL(false);
3409}
3410
3411/*------------------------------------------------------------------
3412 * The following routines define a data type and operator class for
3413 * POLYGONS .... Part of which (the polygon's bounding box) is built on
3414 * top of the BOX data type.
3415 *
3416 * make_bound_box - create the bounding box for the input polygon
3417 *------------------------------------------------------------------*/
3418
3419/*---------------------------------------------------------------------
3420 * Make the smallest bounding box for the given polygon.
3421 *---------------------------------------------------------------------*/
3422static void
3424{
3425 int i;
3426 float8 x1,
3427 y1,
3428 x2,
3429 y2;
3430
3431 Assert(poly->npts > 0);
3432
3433 x1 = x2 = poly->p[0].x;
3434 y2 = y1 = poly->p[0].y;
3435 for (i = 1; i < poly->npts; i++)
3436 {
3437 if (float8_lt(poly->p[i].x, x1))
3438 x1 = poly->p[i].x;
3439 if (float8_gt(poly->p[i].x, x2))
3440 x2 = poly->p[i].x;
3441 if (float8_lt(poly->p[i].y, y1))
3442 y1 = poly->p[i].y;
3443 if (float8_gt(poly->p[i].y, y2))
3444 y2 = poly->p[i].y;
3445 }
3446
3447 poly->boundbox.low.x = x1;
3448 poly->boundbox.high.x = x2;
3449 poly->boundbox.low.y = y1;
3450 poly->boundbox.high.y = y2;
3451}
3452
3453/*------------------------------------------------------------------
3454 * poly_in - read in the polygon from a string specification
3455 *
3456 * External format:
3457 * "((x0,y0),...,(xn,yn))"
3458 * "x0,y0,...,xn,yn"
3459 * also supports the older style "(x1,...,xn,y1,...yn)"
3460 *------------------------------------------------------------------*/
3461Datum
3463{
3464 char *str = PG_GETARG_CSTRING(0);
3465 Node *escontext = fcinfo->context;
3466 POLYGON *poly;
3467 int npts;
3468 int size;
3469 int base_size;
3470 bool isopen;
3471
3472 if ((npts = pair_count(str, ',')) <= 0)
3473 ereturn(escontext, (Datum) 0,
3475 errmsg("invalid input syntax for type %s: \"%s\"",
3476 "polygon", str)));
3477
3478 base_size = sizeof(poly->p[0]) * npts;
3479 size = offsetof(POLYGON, p) + base_size;
3480
3481 /* Check for integer overflow */
3482 if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
3483 ereturn(escontext, (Datum) 0,
3485 errmsg("too many points requested")));
3486
3487 poly = (POLYGON *) palloc0(size); /* zero any holes */
3488
3489 SET_VARSIZE(poly, size);
3490 poly->npts = npts;
3491
3492 if (!path_decode(str, false, npts, &(poly->p[0]), &isopen, NULL, "polygon",
3493 str, escontext))
3495
3497
3499}
3500
3501/*---------------------------------------------------------------
3502 * poly_out - convert internal POLYGON representation to the
3503 * character string format "((f8,f8),...,(f8,f8))"
3504 *---------------------------------------------------------------*/
3505Datum
3512
3513/*
3514 * poly_recv - converts external binary format to polygon
3515 *
3516 * External representation is int32 number of points, and the points.
3517 * We recompute the bounding box on read, instead of trusting it to
3518 * be valid. (Checking it would take just as long, so may as well
3519 * omit it from external representation.)
3520 */
3521Datum
3523{
3525 POLYGON *poly;
3526 int32 npts;
3527 int32 i;
3528 int size;
3529
3530 npts = pq_getmsgint(buf, sizeof(int32));
3531 if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(POLYGON, p)) / sizeof(Point)))
3532 ereport(ERROR,
3534 errmsg("invalid number of points in external \"polygon\" value")));
3535
3536 size = offsetof(POLYGON, p) + sizeof(poly->p[0]) * npts;
3537 poly = (POLYGON *) palloc0(size); /* zero any holes */
3538
3539 SET_VARSIZE(poly, size);
3540 poly->npts = npts;
3541
3542 for (i = 0; i < npts; i++)
3543 {
3544 poly->p[i].x = pq_getmsgfloat8(buf);
3545 poly->p[i].y = pq_getmsgfloat8(buf);
3546 }
3547
3549
3551}
3552
3553/*
3554 * poly_send - converts polygon to binary format
3555 */
3556Datum
3558{
3561 int32 i;
3562
3564 pq_sendint32(&buf, poly->npts);
3565 for (i = 0; i < poly->npts; i++)
3566 {
3567 pq_sendfloat8(&buf, poly->p[i].x);
3568 pq_sendfloat8(&buf, poly->p[i].y);
3569 }
3571}
3572
3573
3574/*-------------------------------------------------------
3575 * Is polygon A strictly left of polygon B? i.e. is
3576 * the right most point of A left of the left most point
3577 * of B?
3578 *-------------------------------------------------------*/
3579Datum
3581{
3584 bool result;
3585
3586 result = polya->boundbox.high.x < polyb->boundbox.low.x;
3587
3588 /*
3589 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3590 */
3593
3594 PG_RETURN_BOOL(result);
3595}
3596
3597/*-------------------------------------------------------
3598 * Is polygon A overlapping or left of polygon B? i.e. is
3599 * the right most point of A at or left of the right most point
3600 * of B?
3601 *-------------------------------------------------------*/
3602Datum
3604{
3607 bool result;
3608
3609 result = polya->boundbox.high.x <= polyb->boundbox.high.x;
3610
3611 /*
3612 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3613 */
3616
3617 PG_RETURN_BOOL(result);
3618}
3619
3620/*-------------------------------------------------------
3621 * Is polygon A strictly right of polygon B? i.e. is
3622 * the left most point of A right of the right most point
3623 * of B?
3624 *-------------------------------------------------------*/
3625Datum
3627{
3630 bool result;
3631
3632 result = polya->boundbox.low.x > polyb->boundbox.high.x;
3633
3634 /*
3635 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3636 */
3639
3640 PG_RETURN_BOOL(result);
3641}
3642
3643/*-------------------------------------------------------
3644 * Is polygon A overlapping or right of polygon B? i.e. is
3645 * the left most point of A at or right of the left most point
3646 * of B?
3647 *-------------------------------------------------------*/
3648Datum
3650{
3653 bool result;
3654
3655 result = polya->boundbox.low.x >= polyb->boundbox.low.x;
3656
3657 /*
3658 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3659 */
3662
3663 PG_RETURN_BOOL(result);
3664}
3665
3666/*-------------------------------------------------------
3667 * Is polygon A strictly below polygon B? i.e. is
3668 * the upper most point of A below the lower most point
3669 * of B?
3670 *-------------------------------------------------------*/
3671Datum
3673{
3676 bool result;
3677
3678 result = polya->boundbox.high.y < polyb->boundbox.low.y;
3679
3680 /*
3681 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3682 */
3685
3686 PG_RETURN_BOOL(result);
3687}
3688
3689/*-------------------------------------------------------
3690 * Is polygon A overlapping or below polygon B? i.e. is
3691 * the upper most point of A at or below the upper most point
3692 * of B?
3693 *-------------------------------------------------------*/
3694Datum
3696{
3699 bool result;
3700
3701 result = polya->boundbox.high.y <= polyb->boundbox.high.y;
3702
3703 /*
3704 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3705 */
3708
3709 PG_RETURN_BOOL(result);
3710}
3711
3712/*-------------------------------------------------------
3713 * Is polygon A strictly above polygon B? i.e. is
3714 * the lower most point of A above the upper most point
3715 * of B?
3716 *-------------------------------------------------------*/
3717Datum
3719{
3722 bool result;
3723
3724 result = polya->boundbox.low.y > polyb->boundbox.high.y;
3725
3726 /*
3727 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3728 */
3731
3732 PG_RETURN_BOOL(result);
3733}
3734
3735/*-------------------------------------------------------
3736 * Is polygon A overlapping or above polygon B? i.e. is
3737 * the lower most point of A at or above the lower most point
3738 * of B?
3739 *-------------------------------------------------------*/
3740Datum
3742{
3745 bool result;
3746
3747 result = polya->boundbox.low.y >= polyb->boundbox.low.y;
3748
3749 /*
3750 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3751 */
3754
3755 PG_RETURN_BOOL(result);
3756}
3757
3758
3759/*-------------------------------------------------------
3760 * Is polygon A the same as polygon B? i.e. are all the
3761 * points the same?
3762 * Check all points for matches in both forward and reverse
3763 * direction since polygons are non-directional and are
3764 * closed shapes.
3765 *-------------------------------------------------------*/
3766Datum
3768{
3771 bool result;
3772
3773 if (polya->npts != polyb->npts)
3774 result = false;
3775 else
3776 result = plist_same(polya->npts, polya->p, polyb->p);
3777
3778 /*
3779 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3780 */
3783
3784 PG_RETURN_BOOL(result);
3785}
3786
3787/*-----------------------------------------------------------------
3788 * Determine if polygon A overlaps polygon B
3789 *-----------------------------------------------------------------*/
3790static bool
3792{
3793 bool result;
3794
3795 Assert(polya->npts > 0 && polyb->npts > 0);
3796
3797 /* Quick check by bounding box */
3798 result = box_ov(&polya->boundbox, &polyb->boundbox);
3799
3800 /*
3801 * Brute-force algorithm - try to find intersected edges, if so then
3802 * polygons are overlapped else check is one polygon inside other or not
3803 * by testing single point of them.
3804 */
3805 if (result)
3806 {
3807 int ia,
3808 ib;
3809 LSEG sa,
3810 sb;
3811
3812 /* Init first of polya's edge with last point */
3813 sa.p[0] = polya->p[polya->npts - 1];
3814 result = false;
3815
3816 for (ia = 0; ia < polya->npts && !result; ia++)
3817 {
3818 /* Second point of polya's edge is a current one */
3819 sa.p[1] = polya->p[ia];
3820
3821 /* Init first of polyb's edge with last point */
3822 sb.p[0] = polyb->p[polyb->npts - 1];
3823
3824 for (ib = 0; ib < polyb->npts && !result; ib++)
3825 {
3826 sb.p[1] = polyb->p[ib];
3827 result = lseg_interpt_lseg(NULL, &sa, &sb);
3828 sb.p[0] = sb.p[1];
3829 }
3830
3831 /*
3832 * move current endpoint to the first point of next edge
3833 */
3834 sa.p[0] = sa.p[1];
3835 }
3836
3837 if (!result)
3838 {
3839 result = (point_inside(polya->p, polyb->npts, polyb->p) ||
3840 point_inside(polyb->p, polya->npts, polya->p));
3841 }
3842 }
3843
3844 return result;
3845}
3846
3847Datum
3849{
3852 bool result;
3853
3855
3856 /*
3857 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3858 */
3861
3862 PG_RETURN_BOOL(result);
3863}
3864
3865/*
3866 * Tests special kind of segment for in/out of polygon.
3867 * Special kind means:
3868 * - point a should be on segment s
3869 * - segment (a,b) should not be contained by s
3870 * Returns true if:
3871 * - segment (a,b) is collinear to s and (a,b) is in polygon
3872 * - segment (a,b) s not collinear to s. Note: that doesn't
3873 * mean that segment is in polygon!
3874 */
3875
3876static bool
3878{
3879 /* point a is on s, b is not */
3880 LSEG t;
3881
3882 t.p[0] = *a;
3883 t.p[1] = *b;
3884
3885 if (point_eq_point(a, s->p))
3886 {
3887 if (lseg_contain_point(&t, s->p + 1))
3888 return lseg_inside_poly(b, s->p + 1, poly, start);
3889 }
3890 else if (point_eq_point(a, s->p + 1))
3891 {
3892 if (lseg_contain_point(&t, s->p))
3893 return lseg_inside_poly(b, s->p, poly, start);
3894 }
3895 else if (lseg_contain_point(&t, s->p))
3896 {
3897 return lseg_inside_poly(b, s->p, poly, start);
3898 }
3899 else if (lseg_contain_point(&t, s->p + 1))
3900 {
3901 return lseg_inside_poly(b, s->p + 1, poly, start);
3902 }
3903
3904 return true; /* may be not true, but that will check later */
3905}
3906
3907/*
3908 * Returns true if segment (a,b) is in polygon, option
3909 * start is used for optimization - function checks
3910 * polygon's edges starting from start
3911 */
3912static bool
3914{
3915 LSEG s,
3916 t;
3917 int i;
3918 bool res = true,
3919 intersection = false;
3920
3921 /* since this function recurses, it could be driven to stack overflow */
3923
3924 t.p[0] = *a;
3925 t.p[1] = *b;
3926 s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
3927
3928 for (i = start; i < poly->npts && res; i++)
3929 {
3930 Point interpt;
3931
3933
3934 s.p[1] = poly->p[i];
3935
3936 if (lseg_contain_point(&s, t.p))
3937 {
3938 if (lseg_contain_point(&s, t.p + 1))
3939 return true; /* t is contained by s */
3940
3941 /* Y-cross */
3942 res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
3943 }
3944 else if (lseg_contain_point(&s, t.p + 1))
3945 {
3946 /* Y-cross */
3947 res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
3948 }
3949 else if (lseg_interpt_lseg(&interpt, &t, &s))
3950 {
3951 /*
3952 * segments are X-crossing, go to check each subsegment
3953 */
3954
3955 intersection = true;
3956 res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
3957 if (res)
3958 res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
3959 }
3960
3961 s.p[0] = s.p[1];
3962 }
3963
3964 if (res && !intersection)
3965 {
3966 Point p;
3967
3968 /*
3969 * if X-intersection wasn't found, then check central point of tested
3970 * segment. In opposite case we already check all subsegments
3971 */
3972 p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
3973 p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
3974
3975 res = point_inside(&p, poly->npts, poly->p);
3976 }
3977
3978 return res;
3979}
3980
3981/*
3982 * Check whether the first polygon contains the second
3983 */
3984static bool
3986{
3987 int i;
3988 LSEG s;
3989
3990 Assert(contains_poly->npts > 0 && contained_poly->npts > 0);
3991
3992 /*
3993 * Quick check to see if contained's bounding box is contained in
3994 * contains' bb.
3995 */
3996 if (!box_contain_box(&contains_poly->boundbox, &contained_poly->boundbox))
3997 return false;
3998
3999 s.p[0] = contained_poly->p[contained_poly->npts - 1];
4000
4001 for (i = 0; i < contained_poly->npts; i++)
4002 {
4003 s.p[1] = contained_poly->p[i];
4004 if (!lseg_inside_poly(s.p, s.p + 1, contains_poly, 0))
4005 return false;
4006 s.p[0] = s.p[1];
4007 }
4008
4009 return true;
4010}
4011
4012Datum
4014{
4017 bool result;
4018
4019 result = poly_contain_poly(polya, polyb);
4020
4021 /*
4022 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
4023 */
4026
4027 PG_RETURN_BOOL(result);
4028}
4029
4030
4031/*-----------------------------------------------------------------
4032 * Determine if polygon A is contained by polygon B
4033 *-----------------------------------------------------------------*/
4034Datum
4036{
4039 bool result;
4040
4041 /* Just switch the arguments and pass it off to poly_contain */
4042 result = poly_contain_poly(polyb, polya);
4043
4044 /*
4045 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
4046 */
4049
4050 PG_RETURN_BOOL(result);
4051}
4052
4053
4054Datum
4062
4063Datum
4071
4072
4073Datum
4075{
4078 float8 min = 0.0; /* initialize to keep compiler quiet */
4079 bool have_min = false;
4080 float8 tmp;
4081 int i,
4082 j;
4083 LSEG seg1,
4084 seg2;
4085
4086 /*
4087 * Distance is zero if polygons overlap. We must check this because the
4088 * path distance will not give the right answer if one poly is entirely
4089 * within the other.
4090 */
4092 PG_RETURN_FLOAT8(0.0);
4093
4094 /*
4095 * When they don't overlap, the distance calculation is identical to that
4096 * for closed paths (i.e., we needn't care about the fact that polygons
4097 * include their contained areas). See path_distance().
4098 */
4099 for (i = 0; i < polya->npts; i++)
4100 {
4101 int iprev;
4102
4103 if (i > 0)
4104 iprev = i - 1;
4105 else
4106 iprev = polya->npts - 1;
4107
4108 for (j = 0; j < polyb->npts; j++)
4109 {
4110 int jprev;
4111
4112 if (j > 0)
4113 jprev = j - 1;
4114 else
4115 jprev = polyb->npts - 1;
4116
4117 statlseg_construct(&seg1, &polya->p[iprev], &polya->p[i]);
4118 statlseg_construct(&seg2, &polyb->p[jprev], &polyb->p[j]);
4119
4120 tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
4121 if (!have_min || float8_lt(tmp, min))
4122 {
4123 min = tmp;
4124 have_min = true;
4125 }
4126 }
4127 }
4128
4129 if (!have_min)
4131
4132 PG_RETURN_FLOAT8(min);
4133}
4134
4135
4136/***********************************************************************
4137 **
4138 ** Routines for 2D points.
4139 **
4140 ***********************************************************************/
4141
4142Datum
4144{
4147 Point *result;
4148
4149 result = palloc_object(Point);
4150
4151 point_construct(result, x, y);
4152
4153 PG_RETURN_POINT_P(result);
4154}
4155
4156
4157static inline void
4158point_add_point(Point *result, Point *pt1, Point *pt2, Node *escontext)
4159{
4160 float8 x;
4161 float8 y;
4162
4163 x = float8_pl_safe(pt1->x, pt2->x, escontext);
4164 if (SOFT_ERROR_OCCURRED(escontext))
4165 return;
4166
4167 y = float8_pl_safe(pt1->y, pt2->y, escontext);
4168 if (SOFT_ERROR_OCCURRED(escontext))
4169 return;
4170
4171 point_construct(result, x, y);
4172}
4173
4174Datum
4176{
4179 Point *result;
4180
4181 result = palloc_object(Point);
4182
4183 point_add_point(result, p1, p2, NULL);
4184
4185 PG_RETURN_POINT_P(result);
4186}
4187
4188
4189static inline void
4191{
4192 point_construct(result,
4193 float8_mi(pt1->x, pt2->x),
4194 float8_mi(pt1->y, pt2->y));
4195}
4196
4197Datum
4199{
4202 Point *result;
4203
4204 result = palloc_object(Point);
4205
4206 point_sub_point(result, p1, p2);
4207
4208 PG_RETURN_POINT_P(result);
4209}
4210
4211
4212static inline void
4214{
4215 point_construct(result,
4216 float8_mi(float8_mul(pt1->x, pt2->x),
4217 float8_mul(pt1->y, pt2->y)),
4218 float8_pl(float8_mul(pt1->x, pt2->y),
4219 float8_mul(pt1->y, pt2->x)));
4220}
4221
4222Datum
4224{
4227 Point *result;
4228
4229 result = palloc_object(Point);
4230
4231 point_mul_point(result, p1, p2);
4232
4233 PG_RETURN_POINT_P(result);
4234}
4235
4236
4237static inline void
4239{
4240 float8 div;
4241
4242 div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
4243
4244 point_construct(result,
4246 float8_mul(pt1->y, pt2->y)), div),
4248 float8_mul(pt1->x, pt2->y)), div));
4249}
4250
4251Datum
4253{
4256 Point *result;
4257
4258 result = palloc_object(Point);
4259
4260 point_div_point(result, p1, p2);
4261
4262 PG_RETURN_POINT_P(result);
4263}
4264
4265
4266/***********************************************************************
4267 **
4268 ** Routines for 2D boxes.
4269 **
4270 ***********************************************************************/
4271
4272Datum
4274{
4277 BOX *result;
4278
4279 result = palloc_object(BOX);
4280
4281 box_construct(result, p1, p2);
4282
4283 PG_RETURN_BOX_P(result);
4284}
4285
4286Datum
4288{
4289 BOX *box = PG_GETARG_BOX_P(0);
4290 Point *p = PG_GETARG_POINT_P(1);
4291 BOX *result;
4292
4293 result = palloc_object(BOX);
4294
4295 point_add_point(&result->high, &box->high, p, NULL);
4296 point_add_point(&result->low, &box->low, p, NULL);
4297
4298 PG_RETURN_BOX_P(result);
4299}
4300
4301Datum
4303{
4304 BOX *box = PG_GETARG_BOX_P(0);
4305 Point *p = PG_GETARG_POINT_P(1);
4306 BOX *result;
4307
4308 result = palloc_object(BOX);
4309
4310 point_sub_point(&result->high, &box->high, p);
4311 point_sub_point(&result->low, &box->low, p);
4312
4313 PG_RETURN_BOX_P(result);
4314}
4315
4316Datum
4318{
4319 BOX *box = PG_GETARG_BOX_P(0);
4320 Point *p = PG_GETARG_POINT_P(1);
4321 BOX *result;
4322 Point high,
4323 low;
4324
4325 result = palloc_object(BOX);
4326
4327 point_mul_point(&high, &box->high, p);
4328 point_mul_point(&low, &box->low, p);
4329
4330 box_construct(result, &high, &low);
4331
4332 PG_RETURN_BOX_P(result);
4333}
4334
4335Datum
4337{
4338 BOX *box = PG_GETARG_BOX_P(0);
4339 Point *p = PG_GETARG_POINT_P(1);
4340 BOX *result;
4341 Point high,
4342 low;
4343
4344 result = palloc_object(BOX);
4345
4346 point_div_point(&high, &box->high, p);
4347 point_div_point(&low, &box->low, p);
4348
4349 box_construct(result, &high, &low);
4350
4351 PG_RETURN_BOX_P(result);
4352}
4353
4354/*
4355 * Convert point to empty box
4356 */
4357Datum
4359{
4361 BOX *box;
4362
4364
4365 box->high.x = pt->x;
4366 box->low.x = pt->x;
4367 box->high.y = pt->y;
4368 box->low.y = pt->y;
4369
4371}
4372
4373/*
4374 * Smallest bounding box that includes both of the given boxes
4375 */
4376Datum
4378{
4379 BOX *box1 = PG_GETARG_BOX_P(0),
4380 *box2 = PG_GETARG_BOX_P(1),
4381 *container;
4382
4383 container = palloc_object(BOX);
4384
4385 container->high.x = float8_max(box1->high.x, box2->high.x);
4386 container->low.x = float8_min(box1->low.x, box2->low.x);
4387 container->high.y = float8_max(box1->high.y, box2->high.y);
4388 container->low.y = float8_min(box1->low.y, box2->low.y);
4389
4390 PG_RETURN_BOX_P(container);
4391}
4392
4393
4394/***********************************************************************
4395 **
4396 ** Routines for 2D paths.
4397 **
4398 ***********************************************************************/
4399
4400/* path_add()
4401 * Concatenate two paths (only if they are both open).
4402 */
4403Datum
4405{
4406 PATH *p1 = PG_GETARG_PATH_P(0);
4407 PATH *p2 = PG_GETARG_PATH_P(1);
4408 PATH *result;
4409 int size,
4410 base_size;
4411 int i;
4412
4413 if (p1->closed || p2->closed)
4415
4416 base_size = sizeof(p1->p[0]) * (p1->npts + p2->npts);
4417 size = offsetof(PATH, p) + base_size;
4418
4419 /* Check for integer overflow */
4420 if (base_size / sizeof(p1->p[0]) != (p1->npts + p2->npts) ||
4421 size <= base_size)
4422 ereport(ERROR,
4424 errmsg("too many points requested")));
4425
4426 result = (PATH *) palloc(size);
4427
4428 SET_VARSIZE(result, size);
4429 result->npts = (p1->npts + p2->npts);
4430 result->closed = p1->closed;
4431 /* prevent instability in unused pad bytes */
4432 result->dummy = 0;
4433
4434 for (i = 0; i < p1->npts; i++)
4435 {
4436 result->p[i].x = p1->p[i].x;
4437 result->p[i].y = p1->p[i].y;
4438 }
4439 for (i = 0; i < p2->npts; i++)
4440 {
4441 result->p[i + p1->npts].x = p2->p[i].x;
4442 result->p[i + p1->npts].y = p2->p[i].y;
4443 }
4444
4445 PG_RETURN_PATH_P(result);
4446}
4447
4448/* path_add_pt()
4449 * Translation operators.
4450 */
4451Datum
4453{
4454 PATH *path = PG_GETARG_PATH_P_COPY(0);
4456 int i;
4457
4458 for (i = 0; i < path->npts; i++)
4459 point_add_point(&path->p[i], &path->p[i], point, NULL);
4460
4461 PG_RETURN_PATH_P(path);
4462}
4463
4464Datum
4466{
4467 PATH *path = PG_GETARG_PATH_P_COPY(0);
4469 int i;
4470
4471 for (i = 0; i < path->npts; i++)
4472 point_sub_point(&path->p[i], &path->p[i], point);
4473
4474 PG_RETURN_PATH_P(path);
4475}
4476
4477/* path_mul_pt()
4478 * Rotation and scaling operators.
4479 */
4480Datum
4482{
4483 PATH *path = PG_GETARG_PATH_P_COPY(0);
4485 int i;
4486
4487 for (i = 0; i < path->npts; i++)
4488 point_mul_point(&path->p[i], &path->p[i], point);
4489
4490 PG_RETURN_PATH_P(path);
4491}
4492
4493Datum
4495{
4496 PATH *path = PG_GETARG_PATH_P_COPY(0);
4498 int i;
4499
4500 for (i = 0; i < path->npts; i++)
4501 point_div_point(&path->p[i], &path->p[i], point);
4502
4503 PG_RETURN_PATH_P(path);
4504}
4505
4506
4507Datum
4509{
4510 PATH *path = PG_GETARG_PATH_P(0);
4511 POLYGON *poly;
4512 int size;
4513 int i;
4514
4515 /* This is not very consistent --- other similar cases return NULL ... */
4516 if (!path->closed)
4517 ereturn(fcinfo->context, (Datum) 0,
4519 errmsg("open path cannot be converted to polygon")));
4520
4521 /*
4522 * Never overflows: the old size fit in MaxAllocSize, and the new size is
4523 * just a small constant larger.
4524 */
4525 size = offsetof(POLYGON, p) + sizeof(poly->p[0]) * path->npts;
4526 poly = (POLYGON *) palloc(size);
4527
4528 SET_VARSIZE(poly, size);
4529 poly->npts = path->npts;
4530
4531 for (i = 0; i < path->npts; i++)
4532 {
4533 poly->p[i].x = path->p[i].x;
4534 poly->p[i].y = path->p[i].y;
4535 }
4536
4538
4540}
4541
4542
4543/***********************************************************************
4544 **
4545 ** Routines for 2D polygons.
4546 **
4547 ***********************************************************************/
4548
4549Datum
4556
4557
4558Datum
4560{
4562 Point *result;
4563 CIRCLE circle;
4564
4565 result = palloc_object(Point);
4566
4567 poly_to_circle(&circle, poly, fcinfo->context);
4568 if (SOFT_ERROR_OCCURRED(fcinfo->context))
4570
4571 *result = circle.center;
4572
4573 PG_RETURN_POINT_P(result);
4574}
4575
4576
4577Datum
4579{
4581 BOX *box;
4582
4584 *box = poly->boundbox;
4585
4587}
4588
4589
4590/* box_poly()
4591 * Convert a box to a polygon.
4592 */
4593Datum
4595{
4596 BOX *box = PG_GETARG_BOX_P(0);
4597 POLYGON *poly;
4598 int size;
4599
4600 /* map four corners of the box to a polygon */
4601 size = offsetof(POLYGON, p) + sizeof(poly->p[0]) * 4;
4602 poly = (POLYGON *) palloc(size);
4603
4604 SET_VARSIZE(poly, size);
4605 poly->npts = 4;
4606
4607 poly->p[0].x = box->low.x;
4608 poly->p[0].y = box->low.y;
4609 poly->p[1].x = box->low.x;
4610 poly->p[1].y = box->high.y;
4611 poly->p[2].x = box->high.x;
4612 poly->p[2].y = box->high.y;
4613 poly->p[3].x = box->high.x;
4614 poly->p[3].y = box->low.y;
4615
4616 box_construct(&poly->boundbox, &box->high, &box->low);
4617
4619}
4620
4621
4622Datum
4624{
4626 PATH *path;
4627 int size;
4628 int i;
4629
4630 /*
4631 * Never overflows: the old size fit in MaxAllocSize, and the new size is
4632 * smaller by a small constant.
4633 */
4634 size = offsetof(PATH, p) + sizeof(path->p[0]) * poly->npts;
4635 path = (PATH *) palloc(size);
4636
4637 SET_VARSIZE(path, size);
4638 path->npts = poly->npts;
4639 path->closed = true;
4640 /* prevent instability in unused pad bytes */
4641 path->dummy = 0;
4642
4643 for (i = 0; i < poly->npts; i++)
4644 {
4645 path->p[i].x = poly->p[i].x;
4646 path->p[i].y = poly->p[i].y;
4647 }
4648
4649 PG_RETURN_PATH_P(path);
4650}
4651
4652
4653/***********************************************************************
4654 **
4655 ** Routines for circles.
4656 **
4657 ***********************************************************************/
4658
4659/*----------------------------------------------------------
4660 * Formatting and conversion routines.
4661 *---------------------------------------------------------*/
4662
4663/* circle_in - convert a string to internal form.
4664 *
4665 * External format: (center and radius of circle)
4666 * "<(f8,f8),f8>"
4667 * also supports quick entry style "f8,f8,f8"
4668 */
4669Datum
4671{
4672 char *str = PG_GETARG_CSTRING(0);
4673 Node *escontext = fcinfo->context;
4675 char *s,
4676 *cp;
4677 int depth = 0;
4678
4679 s = str;
4680 while (isspace((unsigned char) *s))
4681 s++;
4682 if (*s == LDELIM_C)
4683 depth++, s++;
4684 else if (*s == LDELIM)
4685 {
4686 /* If there are two left parens, consume the first one */
4687 cp = (s + 1);
4688 while (isspace((unsigned char) *cp))
4689 cp++;
4690 if (*cp == LDELIM)
4691 depth++, s = cp;
4692 }
4693
4694 /* pair_decode will consume parens around the pair, if any */
4695 if (!pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str,
4696 escontext))
4698
4699 if (*s == DELIM)
4700 s++;
4701
4702 if (!single_decode(s, &circle->radius, &s, "circle", str, escontext))
4704
4705 /* We have to accept NaN. */
4706 if (circle->radius < 0.0)
4707 ereturn(escontext, (Datum) 0,
4709 errmsg("invalid input syntax for type %s: \"%s\"",
4710 "circle", str)));
4711
4712 while (depth > 0)
4713 {
4714 if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
4715 {
4716 depth--;
4717 s++;
4718 while (isspace((unsigned char) *s))
4719 s++;
4720 }
4721 else
4722 ereturn(escontext, (Datum) 0,
4724 errmsg("invalid input syntax for type %s: \"%s\"",
4725 "circle", str)));
4726 }
4727
4728 if (*s != '\0')
4729 ereturn(escontext, (Datum) 0,
4731 errmsg("invalid input syntax for type %s: \"%s\"",
4732 "circle", str)));
4733
4735}
4736
4737/* circle_out - convert a circle to external form.
4738 */
4739Datum
4757
4758/*
4759 * circle_recv - converts external binary format to circle
4760 */
4761Datum
4763{
4765 CIRCLE *circle;
4766
4768
4769 circle->center.x = pq_getmsgfloat8(buf);
4770 circle->center.y = pq_getmsgfloat8(buf);
4771 circle->radius = pq_getmsgfloat8(buf);
4772
4773 /* We have to accept NaN. */
4774 if (circle->radius < 0.0)
4775 ereport(ERROR,
4777 errmsg("invalid radius in external \"circle\" value")));
4778
4780}
4781
4782/*
4783 * circle_send - converts circle to binary format
4784 */
4785Datum
4797
4798
4799/*----------------------------------------------------------
4800 * Relational operators for CIRCLEs.
4801 * <, >, <=, >=, and == are based on circle area.
4802 *---------------------------------------------------------*/
4803
4804/* circles identical?
4805 *
4806 * We consider NaNs values to be equal to each other to let those circles
4807 * to be found.
4808 */
4809Datum
4811{
4814
4815 PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle2->radius)) ||
4816 FPeq(circle1->radius, circle2->radius)) &&
4817 point_eq_point(&circle1->center, &circle2->center));
4818}
4819
4820/* circle_overlap - does circle1 overlap circle2?
4821 */
4822Datum
4824{
4827
4828 PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center, NULL),
4829 float8_pl(circle1->radius, circle2->radius)));
4830}
4831
4832/* circle_overleft - is the right edge of circle1 at or left of
4833 * the right edge of circle2?
4834 */
4835Datum
4837{
4840
4841 PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
4842 float8_pl(circle2->center.x, circle2->radius)));
4843}
4844
4845/* circle_left - is circle1 strictly left of circle2?
4846 */
4847Datum
4849{
4852
4853 PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
4854 float8_mi(circle2->center.x, circle2->radius)));
4855}
4856
4857/* circle_right - is circle1 strictly right of circle2?
4858 */
4859Datum
4861{
4864
4865 PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
4866 float8_pl(circle2->center.x, circle2->radius)));
4867}
4868
4869/* circle_overright - is the left edge of circle1 at or right of
4870 * the left edge of circle2?
4871 */
4872Datum
4874{
4877
4878 PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
4879 float8_mi(circle2->center.x, circle2->radius)));
4880}
4881
4882/* circle_contained - is circle1 contained by circle2?
4883 */
4884Datum
4886{
4889
4890 PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center, NULL),
4891 float8_mi(circle2->radius, circle1->radius)));
4892}
4893
4894/* circle_contain - does circle1 contain circle2?
4895 */
4896Datum
4898{
4901
4902 PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center, NULL),
4903 float8_mi(circle1->radius, circle2->radius)));
4904}
4905
4906
4907/* circle_below - is circle1 strictly below circle2?
4908 */
4909Datum
4911{
4914
4915 PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
4916 float8_mi(circle2->center.y, circle2->radius)));
4917}
4918
4919/* circle_above - is circle1 strictly above circle2?
4920 */
4921Datum
4923{
4926
4927 PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
4928 float8_pl(circle2->center.y, circle2->radius)));
4929}
4930
4931/* circle_overbelow - is the upper edge of circle1 at or below
4932 * the upper edge of circle2?
4933 */
4934Datum
4936{
4939
4940 PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
4941 float8_pl(circle2->center.y, circle2->radius)));
4942}
4943
4944/* circle_overabove - is the lower edge of circle1 at or above
4945 * the lower edge of circle2?
4946 */
4947Datum
4949{
4952
4953 PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
4954 float8_mi(circle2->center.y, circle2->radius)));
4955}
4956
4957
4958/* circle_relop - is area(circle1) relop area(circle2), within
4959 * our accuracy constraint?
4960 */
4961Datum
4969
4970Datum
4978
4979Datum
4987
4988Datum
4996
4997Datum
5005
5006Datum
5014
5015
5016/*----------------------------------------------------------
5017 * "Arithmetic" operators on circles.
5018 *---------------------------------------------------------*/
5019
5020/* circle_add_pt()
5021 * Translation operator.
5022 */
5023Datum
5025{
5028 CIRCLE *result;
5029
5030 result = palloc_object(CIRCLE);
5031
5032 point_add_point(&result->center, &circle->center, point, NULL);
5033 result->radius = circle->radius;
5034
5035 PG_RETURN_CIRCLE_P(result);
5036}
5037
5038Datum
5040{
5043 CIRCLE *result;
5044
5045 result = palloc_object(CIRCLE);
5046
5047 point_sub_point(&result->center, &circle->center, point);
5048 result->radius = circle->radius;
5049
5050 PG_RETURN_CIRCLE_P(result);
5051}
5052
5053
5054/* circle_mul_pt()
5055 * Rotation and scaling operators.
5056 */
5057Datum
5059{
5062 CIRCLE *result;
5063
5064 result = palloc_object(CIRCLE);
5065
5066 point_mul_point(&result->center, &circle->center, point);
5067 result->radius = float8_mul(circle->radius, hypot(point->x, point->y));
5068
5069 PG_RETURN_CIRCLE_P(result);
5070}
5071
5072Datum
5074{
5077 CIRCLE *result;
5078
5079 result = palloc_object(CIRCLE);
5080
5081 point_div_point(&result->center, &circle->center, point);
5082 result->radius = float8_div(circle->radius, hypot(point->x, point->y));
5083
5084 PG_RETURN_CIRCLE_P(result);
5085}
5086
5087
5088/* circle_area - returns the area of the circle.
5089 */
5090Datum
5097
5098
5099/* circle_diameter - returns the diameter of the circle.
5100 */
5101Datum
5108
5109
5110/* circle_radius - returns the radius of the circle.
5111 */
5112Datum
5119
5120
5121/* circle_distance - returns the distance between
5122 * two circles.
5123 */
5124Datum
5126{
5129 float8 result;
5130
5131 result = float8_mi(point_dt(&circle1->center, &circle2->center, NULL),
5132 float8_pl(circle1->radius, circle2->radius));
5133 if (result < 0.0)
5134 result = 0.0;
5135
5136 PG_RETURN_FLOAT8(result);
5137}
5138
5139
5140Datum
5150
5151
5152Datum
5162
5163
5164/* dist_pc - returns the distance between
5165 * a point and a circle.
5166 */
5167Datum
5169{
5172 float8 result;
5173
5174 result = float8_mi(point_dt(point, &circle->center, NULL),
5175 circle->radius);
5176 if (result < 0.0)
5177 result = 0.0;
5178
5179 PG_RETURN_FLOAT8(result);
5180}
5181
5182/*
5183 * Distance from a circle to a point
5184 */
5185Datum
5187{
5190 float8 result;
5191
5192 result = float8_mi(point_dt(point, &circle->center, NULL), circle->radius);
5193 if (result < 0.0)
5194 result = 0.0;
5195
5196 PG_RETURN_FLOAT8(result);
5197}
5198
5199/* circle_center - returns the center point of the circle.
5200 */
5201Datum
5203{
5205 Point *result;
5206
5207 result = palloc_object(Point);
5208 result->x = circle->center.x;
5209 result->y = circle->center.y;
5210
5211 PG_RETURN_POINT_P(result);
5212}
5213
5214
5215/* circle_ar - returns the area of the circle.
5216 */
5217static float8
5219{
5220 return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
5221}
5222
5223
5224/*----------------------------------------------------------
5225 * Conversion operators.
5226 *---------------------------------------------------------*/
5227
5228Datum
5230{
5231 Point *center = PG_GETARG_POINT_P(0);
5232 float8 radius = PG_GETARG_FLOAT8(1);
5233 CIRCLE *result;
5234
5235 result = palloc_object(CIRCLE);
5236
5237 result->center.x = center->x;
5238 result->center.y = center->y;
5239 result->radius = radius;
5240
5241 PG_RETURN_CIRCLE_P(result);
5242}
5243
5244Datum
5246{
5248 BOX *box;
5249 float8 delta;
5250
5252
5253 delta = float8_div_safe(circle->radius, sqrt(2.0), fcinfo->context);
5254 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5255 goto fail;
5256
5257 box->high.x = float8_pl_safe(circle->center.x, delta, fcinfo->context);
5258 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5259 goto fail;
5260
5261 box->low.x = float8_mi_safe(circle->center.x, delta, fcinfo->context);
5262 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5263 goto fail;
5264
5265 box->high.y = float8_pl_safe(circle->center.y, delta, fcinfo->context);
5266 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5267 goto fail;
5268
5269 box->low.y = float8_mi_safe(circle->center.y, delta, fcinfo->context);
5270 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5271 goto fail;
5272
5274
5275fail:
5277}
5278
5279/* box_circle()
5280 * Convert a box to a circle.
5281 */
5282Datum
5284{
5285 BOX *box = PG_GETARG_BOX_P(0);
5286 CIRCLE *circle;
5287 float8 x;
5288 float8 y;
5289
5291
5292 x = float8_pl_safe(box->high.x, box->low.x, fcinfo->context);
5293 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5294 goto fail;
5295
5296 circle->center.x = float8_div_safe(x, 2.0, fcinfo->context);
5297 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5298 goto fail;
5299
5300 y = float8_pl_safe(box->high.y, box->low.y, fcinfo->context);
5301 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5302 goto fail;
5303
5304 circle->center.y = float8_div_safe(y, 2.0, fcinfo->context);
5305 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5306 goto fail;
5307
5308 circle->radius = point_dt(&circle->center, &box->high,
5309 fcinfo->context);
5310
5311 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5312 goto fail;
5313
5315
5316fail:
5318}
5319
5320
5321static POLYGON *
5323{
5324 POLYGON *poly;
5325 int base_size,
5326 size;
5327 int i;
5328 float8 angle;
5330
5331 if (FPzero(circle->radius))
5332 ereturn(fcinfo->context, NULL,
5334 errmsg("cannot convert circle with radius zero to polygon")));
5335
5336 if (npts < 2)
5337 ereturn(fcinfo->context, NULL,
5339 errmsg("must request at least 2 points")));
5340
5341 base_size = sizeof(poly->p[0]) * npts;
5342 size = offsetof(POLYGON, p) + base_size;
5343
5344 /* Check for integer overflow */
5345 if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
5346 ereturn(fcinfo->context, NULL,
5348 errmsg("too many points requested")));
5349
5350 poly = (POLYGON *) palloc0(size); /* zero any holes */
5351 SET_VARSIZE(poly, size);
5352 poly->npts = npts;
5353
5354 anglestep = float8_div(2.0 * M_PI, npts);
5355
5356 for (i = 0; i < npts; i++)
5357 {
5358 float8 temp;
5359
5361 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5362 return NULL;
5363
5364 temp = float8_mul_safe(circle->radius, cos(angle), fcinfo->context);
5365 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5366 return NULL;
5367
5368 poly->p[i].x = float8_mi_safe(circle->center.x, temp, fcinfo->context);
5369 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5370 return NULL;
5371
5372 temp = float8_mul_safe(circle->radius, sin(angle), fcinfo->context);
5373 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5374 return NULL;
5375
5376 poly->p[i].y = float8_pl_safe(circle->center.y, temp, fcinfo->context);
5377 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5378 return NULL;
5379 }
5380
5382
5383 return poly;
5384}
5385
5386Datum
5394
5395/* convert circle to 12-vertex polygon */
5396Datum
5398{
5399 int32 npts = 12;
5401
5403}
5404
5405/*
5406 * Convert polygon to circle
5407 *
5408 * The result must be preallocated.
5409 *
5410 * XXX This algorithm should use weighted means of line segments
5411 * rather than straight average values of points - tgl 97/01/21.
5412 */
5413static void
5414poly_to_circle(CIRCLE *result, POLYGON *poly, Node *escontext)
5415{
5416 int i;
5417 float8 x;
5418
5419 Assert(poly->npts > 0);
5420
5421 result->center.x = 0;
5422 result->center.y = 0;
5423 result->radius = 0;
5424
5425 for (i = 0; i < poly->npts; i++)
5426 {
5427 point_add_point(&result->center, &result->center, &poly->p[i], escontext);
5428 if (SOFT_ERROR_OCCURRED(escontext))
5429 return;
5430 }
5431
5432 result->center.x = float8_div_safe(result->center.x, poly->npts, escontext);
5433 if (SOFT_ERROR_OCCURRED(escontext))
5434 return;
5435
5436 result->center.y = float8_div_safe(result->center.y, poly->npts, escontext);
5437 if (SOFT_ERROR_OCCURRED(escontext))
5438 return;
5439
5440 for (i = 0; i < poly->npts; i++)
5441 {
5442 x = point_dt(&poly->p[i], &result->center, escontext);
5443 if (SOFT_ERROR_OCCURRED(escontext))
5444 return;
5445
5446 result->radius = float8_pl_safe(result->radius, x, escontext);
5447 if (SOFT_ERROR_OCCURRED(escontext))
5448 return;
5449 }
5450
5451 result->radius = float8_div_safe(result->radius, poly->npts, escontext);
5452 if (SOFT_ERROR_OCCURRED(escontext))
5453 return;
5454}
5455
5456Datum
5458{
5460 CIRCLE *result;
5461
5462 result = palloc_object(CIRCLE);
5463
5464 poly_to_circle(result, poly, fcinfo->context);
5465 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5467
5468 PG_RETURN_CIRCLE_P(result);
5469}
5470
5471
5472/***********************************************************************
5473 **
5474 ** Private routines for multiple types.
5475 **
5476 ***********************************************************************/
5477
5478/*
5479 * Test to see if the point is inside the polygon, returns 1/0, or 2 if
5480 * the point is on the polygon.
5481 * Code adapted but not copied from integer-based routines in WN: A
5482 * Server for the HTTP
5483 * version 1.15.1, file wn/image.c
5484 * http://hopf.math.northwestern.edu/index.html
5485 * Description of algorithm: http://www.linuxjournal.com/article/2197
5486 * http://www.linuxjournal.com/article/2029
5487 */
5488
5489#define POINT_ON_POLYGON INT_MAX
5490
5491static int
5493{
5494 float8 x0,
5495 y0;
5496 float8 prev_x,
5497 prev_y;
5498 int i = 0;
5499 float8 x,
5500 y;
5501 int cross,
5502 total_cross = 0;
5503
5504 Assert(npts > 0);
5505
5506 /* compute first polygon point relative to single point */
5507 x0 = float8_mi(plist[0].x, p->x);
5508 y0 = float8_mi(plist[0].y, p->y);
5509
5510 prev_x = x0;
5511 prev_y = y0;
5512 /* loop over polygon points and aggregate total_cross */
5513 for (i = 1; i < npts; i++)
5514 {
5515 /* compute next polygon point relative to single point */
5516 x = float8_mi(plist[i].x, p->x);
5517 y = float8_mi(plist[i].y, p->y);
5518
5519 /* compute previous to current point crossing */
5521 return 2;
5522 total_cross += cross;
5523
5524 prev_x = x;
5525 prev_y = y;
5526 }
5527
5528 /* now do the first point */
5530 return 2;
5531 total_cross += cross;
5532
5533 if (total_cross != 0)
5534 return 1;
5535 return 0;
5536}
5537
5538
5539/* lseg_crossing()
5540 * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
5541 * Returns +/-1 if one point is on the positive X-axis.
5542 * Returns 0 if both points are on the positive X-axis, or there is no crossing.
5543 * Returns POINT_ON_POLYGON if the segment contains (0,0).
5544 * Wow, that is one confusing API, but it is used above, and when summed,
5545 * can tell is if a point is in a polygon.
5546 */
5547
5548static int
5550{
5551 float8 z;
5552 int y_sign;
5553
5554 if (FPzero(y))
5555 { /* y == 0, on X axis */
5556 if (FPzero(x)) /* (x,y) is (0,0)? */
5557 return POINT_ON_POLYGON;
5558 else if (FPgt(x, 0))
5559 { /* x > 0 */
5560 if (FPzero(prev_y)) /* y and prev_y are zero */
5561 /* prev_x > 0? */
5562 return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
5563 return FPlt(prev_y, 0.0) ? 1 : -1;
5564 }
5565 else
5566 { /* x < 0, x not on positive X axis */
5567 if (FPzero(prev_y))
5568 /* prev_x < 0? */
5569 return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
5570 return 0;
5571 }
5572 }
5573 else
5574 { /* y != 0 */
5575 /* compute y crossing direction from previous point */
5576 y_sign = FPgt(y, 0.0) ? 1 : -1;
5577
5578 if (FPzero(prev_y))
5579 /* previous point was on X axis, so new point is either off or on */
5580 return FPlt(prev_x, 0.0) ? 0 : y_sign;
5581 else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
5582 (y_sign > 0 && FPgt(prev_y, 0.0)))
5583 /* both above or below X axis */
5584 return 0; /* same sign */
5585 else
5586 { /* y and prev_y cross X-axis */
5587 if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
5588 /* both non-negative so cross positive X-axis */
5589 return 2 * y_sign;
5590 if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
5591 /* both non-positive so do not cross positive X-axis */
5592 return 0;
5593
5594 /* x and y cross axes, see URL above point_inside() */
5597 if (FPzero(z))
5598 return POINT_ON_POLYGON;
5599 if ((y_sign < 0 && FPlt(z, 0.0)) ||
5600 (y_sign > 0 && FPgt(z, 0.0)))
5601 return 0;
5602 return 2 * y_sign;
5603 }
5604 }
5605}
5606
5607
5608static bool
5610{
5611 int i,
5612 ii,
5613 j;
5614
5615 /* find match for first point */
5616 for (i = 0; i < npts; i++)
5617 {
5618 if (point_eq_point(&p2[i], &p1[0]))
5619 {
5620
5621 /* match found? then look forward through remaining points */
5622 for (ii = 1, j = i + 1; ii < npts; ii++, j++)
5623 {
5624 if (j >= npts)
5625 j = 0;
5626 if (!point_eq_point(&p2[j], &p1[ii]))
5627 break;
5628 }
5629 if (ii == npts)
5630 return true;
5631
5632 /* match not found forwards? then look backwards */
5633 for (ii = 1, j = i - 1; ii < npts; ii++, j--)
5634 {
5635 if (j < 0)
5636 j = (npts - 1);
5637 if (!point_eq_point(&p2[j], &p1[ii]))
5638 break;
5639 }
5640 if (ii == npts)
5641 return true;
5642 }
5643 }
5644
5645 return false;
5646}
#define Assert(condition)
Definition c.h:945
double float8
Definition c.h:716
int32_t int32
Definition c.h:614
#define unlikely(x)
Definition c.h:432
#define M_PI
int errcode(int sqlerrcode)
Definition elog.c:874
#define ereturn(context, dummy_value,...)
Definition elog.h:278
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
#define palloc_object(type)
Definition fe_memutils.h:74
float8 float8in_internal(char *num, char **endptr_p, const char *type_name, const char *orig_string, struct Node *escontext)
Definition float.c:436
char * float8out_internal(double num)
Definition float.c:578
static float8 float8_mul_safe(const float8 val1, const float8 val2, struct Node *escontext)
Definition float.h:178
static float8 float8_min(const float8 val1, const float8 val2)
Definition float.h:322
static float8 float8_pl_safe(const float8 val1, const float8 val2, struct Node *escontext)
Definition float.h:116
static float8 float8_mul(const float8 val1, const float8 val2)
Definition float.h:192
static float8 float8_pl(const float8 val1, const float8 val2)
Definition float.h:128
static float8 float8_mi(const float8 val1, const float8 val2)
Definition float.h:158
static float8 get_float8_infinity(void)
Definition float.h:68
static float8 float8_mi_safe(const float8 val1, const float8 val2, struct Node *escontext)
Definition float.h:146
static float8 float8_max(const float8 val1, const float8 val2)
Definition float.h:334
static bool float8_eq(const float8 val1, const float8 val2)
Definition float.h:250
static float8 get_float8_nan(void)
Definition float.h:87
static float8 float8_div(const float8 val1, const float8 val2)
Definition float.h:230
static float8 float8_div_safe(const float8 val1, const float8 val2, struct Node *escontext)
Definition float.h:214
static bool float8_lt(const float8 val1, const float8 val2)
Definition float.h:274
static bool float8_gt(const float8 val1, const float8 val2)
Definition float.h:298
#define PG_FREE_IF_COPY(ptr, n)
Definition fmgr.h:260
#define PG_RETURN_BYTEA_P(x)
Definition fmgr.h:373
#define PG_GETARG_FLOAT8(n)
Definition fmgr.h:283
#define PG_RETURN_FLOAT8(x)
Definition fmgr.h:369
#define PG_GETARG_POINTER(n)
Definition fmgr.h:277
#define PG_RETURN_CSTRING(x)
Definition fmgr.h:364
#define PG_GETARG_CSTRING(n)
Definition fmgr.h:278
#define PG_RETURN_NULL()
Definition fmgr.h:346
#define PG_RETURN_INT32(x)
Definition fmgr.h:355
#define PG_GETARG_INT32(n)
Definition fmgr.h:269
#define PG_FUNCTION_ARGS
Definition fmgr.h:193
#define PG_RETURN_BOOL(x)
Definition fmgr.h:360
static bool FPlt(double A, double B)
Definition geo_decls.h:59
#define FPzero(A)
Definition geo_decls.h:44
#define PG_GETARG_POINT_P(n)
Definition geo_decls.h:184
#define PG_RETURN_CIRCLE_P(x)
Definition geo_decls.h:275
static bool FPge(double A, double B)
Definition geo_decls.h:77
#define PG_RETURN_BOX_P(x)
Definition geo_decls.h:243
#define PG_RETURN_LSEG_P(x)
Definition geo_decls.h:198
#define PG_RETURN_POINT_P(x)
Definition geo_decls.h:185
#define PG_GETARG_LINE_P(n)
Definition geo_decls.h:229
static bool FPne(double A, double B)
Definition geo_decls.h:53
#define PG_RETURN_POLYGON_P(x)
Definition geo_decls.h:262
#define PG_GETARG_BOX_P(n)
Definition geo_decls.h:242
#define PG_GETARG_POLYGON_P(n)
Definition geo_decls.h:260
#define PG_GETARG_PATH_P_COPY(n)
Definition geo_decls.h:216
#define PG_GETARG_CIRCLE_P(n)
Definition geo_decls.h:274
static bool FPgt(double A, double B)
Definition geo_decls.h:71
static bool FPle(double A, double B)
Definition geo_decls.h:65
#define PG_GETARG_LSEG_P(n)
Definition geo_decls.h:197
#define PG_RETURN_LINE_P(x)
Definition geo_decls.h:230
#define PG_GETARG_PATH_P(n)
Definition geo_decls.h:215
static bool FPeq(double A, double B)
Definition geo_decls.h:47
#define PG_RETURN_PATH_P(x)
Definition geo_decls.h:217
Datum circle_div_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5073
static bool pair_decode(char *str, float8 *x, float8 *y, char **endptr_p, const char *type_name, const char *orig_string, Node *escontext)
Definition geo_ops.c:213
Datum circle_contained(PG_FUNCTION_ARGS)
Definition geo_ops.c:4885
Datum close_ls(PG_FUNCTION_ARGS)
Definition geo_ops.c:3035
static bool box_ov(BOX *box1, BOX *box2)
Definition geo_ops.c:573
static float8 box_closept_point(Point *result, BOX *box, Point *pt)
Definition geo_ops.c:2925
Datum box_width(PG_FUNCTION_ARGS)
Definition geo_ops.c:809
Datum path_n_le(PG_FUNCTION_ARGS)
Definition geo_ops.c:1598
Datum lseg_center(PG_FUNCTION_ARGS)
Definition geo_ops.c:2345
Datum path_close(PG_FUNCTION_ARGS)
Definition geo_ops.c:1645
Datum circle_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:4670
Datum point_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:2011
static int lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
Definition geo_ops.c:5549
Datum circle_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:4962
Datum path_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:1748
static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
Definition geo_ops.c:3310
static void point_add_point(Point *result, Point *pt1, Point *pt2, Node *escontext)
Definition geo_ops.c:4158
static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
Definition geo_ops.c:3913
static bool lseg_contain_point(LSEG *lseg, Point *pt)
Definition geo_ops.c:3156
#define DELIM
Definition geo_ops.c:160
Datum lseg_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:2140
Datum box_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:584
static bool single_decode(char *num, float8 *x, char **endptr_p, const char *type_name, const char *orig_string, Node *escontext)
Definition geo_ops.c:195
Datum point_ne(PG_FUNCTION_ARGS)
Definition geo_ops.c:1982
Datum path_n_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:1589
Datum point_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:1860
Datum circle_overright(PG_FUNCTION_ARGS)
Definition geo_ops.c:4873
Datum circle_radius(PG_FUNCTION_ARGS)
Definition geo_ops.c:5113
Datum cr_circle(PG_FUNCTION_ARGS)
Definition geo_ops.c:5229
static char * path_encode(enum path_delim path_delim, int npts, Point *pt)
Datum point_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:1886
Datum circle_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:5125
#define POINT_ON_POLYGON
Definition geo_ops.c:5489
Datum circle_center(PG_FUNCTION_ARGS)
Definition geo_ops.c:5202
Datum box_gt(PG_FUNCTION_ARGS)
Definition geo_ops.c:754
Datum circle_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:4860
Datum circle_overleft(PG_FUNCTION_ARGS)
Definition geo_ops.c:4836
Datum path_mul_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4481
Datum box_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:610
static float8 box_ht(BOX *box)
Definition geo_ops.c:911
Datum dist_pathp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2537
Datum circle_diameter(PG_FUNCTION_ARGS)
Definition geo_ops.c:5102
static bool poly_contain_poly(POLYGON *contains_poly, POLYGON *contained_poly)
Definition geo_ops.c:3985
Datum lseg_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:2110
Datum path_n_ge(PG_FUNCTION_ARGS)
Definition geo_ops.c:1607
Datum box_ge(PG_FUNCTION_ARGS)
Definition geo_ops.c:781
Datum poly_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:3462
Datum dist_pc(PG_FUNCTION_ARGS)
Definition geo_ops.c:5168
Datum point_sub(PG_FUNCTION_ARGS)
Definition geo_ops.c:4198
Datum poly_npoints(PG_FUNCTION_ARGS)
Definition geo_ops.c:4550
Datum dist_ps(PG_FUNCTION_ARGS)
Definition geo_ops.c:2461
Datum poly_overabove(PG_FUNCTION_ARGS)
Definition geo_ops.c:3741
static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
Definition geo_ops.c:2171
Datum on_pl(PG_FUNCTION_ARGS)
Definition geo_ops.c:3142
Datum path_isopen(PG_FUNCTION_ARGS)
Definition geo_ops.c:1628
Datum path_sub_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4465
Datum circle_same(PG_FUNCTION_ARGS)
Definition geo_ops.c:4810
static void poly_to_circle(CIRCLE *result, POLYGON *poly, Node *escontext)
Definition geo_ops.c:5414
Datum point_div(PG_FUNCTION_ARGS)
Definition geo_ops.c:4252
Datum line_vertical(PG_FUNCTION_ARGS)
Definition geo_ops.c:1192
Datum box_same(PG_FUNCTION_ARGS)
Definition geo_ops.c:552
Datum line_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:997
Datum circle_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:5245
static void point_construct(Point *result, float8 x, float8 y)
Definition geo_ops.c:1902
Datum circle_ge(PG_FUNCTION_ARGS)
Definition geo_ops.c:5007
Datum poly_contain_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4055
Datum dist_ppoly(PG_FUNCTION_ARGS)
Definition geo_ops.c:2659
Datum poly_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:3506
Datum poly_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:4074
Datum line_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:1279
Datum circle_mul_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5058
Datum point_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:1973
static bool box_contain_box(BOX *contains_box, BOX *contained_box)
Definition geo_ops.c:705
Datum dist_ppath(PG_FUNCTION_ARGS)
Definition geo_ops.c:2525
Datum point_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:4358
static void line_construct(LINE *result, Point *pt, float8 m)
Definition geo_ops.c:1101
#define LDELIM_L
Definition geo_ops.c:165
Datum box_sub(PG_FUNCTION_ARGS)
Definition geo_ops.c:4302
Datum circle_overabove(PG_FUNCTION_ARGS)
Definition geo_ops.c:4948
Datum poly_overright(PG_FUNCTION_ARGS)
Definition geo_ops.c:3649
Datum point_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:1937
Datum dist_cpoly(PG_FUNCTION_ARGS)
Definition geo_ops.c:2635
Datum line_perp(PG_FUNCTION_ARGS)
Definition geo_ops.c:1173
Datum path_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:1420
Datum dist_pl(PG_FUNCTION_ARGS)
Definition geo_ops.c:2437
Datum lseg_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:2265
Datum poly_contained(PG_FUNCTION_ARGS)
Definition geo_ops.c:4035
Datum poly_circle(PG_FUNCTION_ARGS)
Definition geo_ops.c:5457
Datum box_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:833
Datum close_lseg(PG_FUNCTION_ARGS)
Definition geo_ops.c:2900
Datum path_area(PG_FUNCTION_ARGS)
Definition geo_ops.c:1398
Datum points_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:4273
Datum box_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:636
static void make_bound_box(POLYGON *poly)
Definition geo_ops.c:3423
Datum poly_overleft(PG_FUNCTION_ARGS)
Definition geo_ops.c:3603
static bool line_decode(char *s, const char *str, LINE *line, Node *escontext)
Definition geo_ops.c:968
Datum poly_path(PG_FUNCTION_ARGS)
Definition geo_ops.c:4623
static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
Definition geo_ops.c:3060
static void point_mul_point(Point *result, Point *pt1, Point *pt2)
Definition geo_ops.c:4213
Datum circle_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:4922
Datum dist_sp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2473
Datum poly_overlap(PG_FUNCTION_ARGS)
Definition geo_ops.c:3848
Datum circle_to_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:5397
Datum lseg_ge(PG_FUNCTION_ARGS)
Definition geo_ops.c:2315
Datum poly_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:3580
Datum line_construct_pp(PG_FUNCTION_ARGS)
Definition geo_ops.c:1133
static bool poly_overlap_internal(POLYGON *polya, POLYGON *polyb)
Definition geo_ops.c:3791
static float8 circle_ar(CIRCLE *circle)
Definition geo_ops.c:5218
Datum path_open(PG_FUNCTION_ARGS)
Definition geo_ops.c:1655
Datum box_add(PG_FUNCTION_ARGS)
Definition geo_ops.c:4287
Datum box_diagonal(PG_FUNCTION_ARGS)
Definition geo_ops.c:951
Datum line_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:1212
Datum box_below_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:723
Datum path_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:1544
Datum poly_contain(PG_FUNCTION_ARGS)
Definition geo_ops.c:4013
Datum circle_add_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5024
static void point_div_point(Point *result, Point *pt1, Point *pt2)
Definition geo_ops.c:4238
static float8 box_ar(BOX *box)
Definition geo_ops.c:866
Datum poly_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:3522
Datum inter_lb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3375
Datum box_area(PG_FUNCTION_ARGS)
Definition geo_ops.c:797
Datum path_length(PG_FUNCTION_ARGS)
Definition geo_ops.c:1810
Datum boxes_bound_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:4377
Datum box_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:456
Datum circle_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:4910
#define LDELIM_C
Definition geo_ops.c:163
Datum lseg_gt(PG_FUNCTION_ARGS)
Definition geo_ops.c:2305
#define LDELIM_EP
Definition geo_ops.c:161
static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
Definition geo_ops.c:2819
Datum path_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:1492
Datum box_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:423
Datum box_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:467
static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
Definition geo_ops.c:3007
Datum on_ppath(PG_FUNCTION_ARGS)
Definition geo_ops.c:3213
Datum pt_contained_circle(PG_FUNCTION_ARGS)
Definition geo_ops.c:5153
Datum lseg_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:2121
Datum line_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:1079
Datum lseg_horizontal(PG_FUNCTION_ARGS)
Definition geo_ops.c:2256
Datum close_pl(PG_FUNCTION_ARGS)
Definition geo_ops.c:2797
static float8 line_closept_point(Point *result, LINE *line, Point *point)
Definition geo_ops.c:2771
Datum box_above_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:732
Datum on_ps(PG_FUNCTION_ARGS)
Definition geo_ops.c:3164
#define RDELIM
Definition geo_ops.c:159
Datum box_contain_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:3193
Datum dist_sl(PG_FUNCTION_ARGS)
Definition geo_ops.c:2573
Datum path_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:4508
Datum point_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:1946
Datum box_le(PG_FUNCTION_ARGS)
Definition geo_ops.c:772
Datum line_parallel(PG_FUNCTION_ARGS)
Definition geo_ops.c:1164
Datum lseg_length(PG_FUNCTION_ARGS)
Definition geo_ops.c:2201
Datum line_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:1041
Datum line_interpt(PG_FUNCTION_ARGS)
Definition geo_ops.c:1304
static float8 point_dt(Point *pt1, Point *pt2, Node *escontext)
Definition geo_ops.c:2020
Datum close_sb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3110
static POLYGON * circle_poly_internal(int32 npts, const CIRCLE *circle, FunctionCallInfo fcinfo)
Definition geo_ops.c:5322
Datum lseg_le(PG_FUNCTION_ARGS)
Definition geo_ops.c:2295
Datum on_pb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3184
static int point_inside(Point *p, int npts, Point *plist)
Definition geo_ops.c:5492
Datum lseg_ne(PG_FUNCTION_ARGS)
Definition geo_ops.c:2275
Datum path_inter(PG_FUNCTION_ARGS)
Definition geo_ops.c:1671
Datum dist_lp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2449
Datum box_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:4594
Datum inter_sb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3362
Datum poly_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:3672
Datum poly_overbelow(PG_FUNCTION_ARGS)
Definition geo_ops.c:3695
Datum pt_contained_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:4064
Datum circle_contain(PG_FUNCTION_ARGS)
Definition geo_ops.c:4897
static bool line_interpt_line(Point *result, LINE *l1, LINE *l2)
Definition geo_ops.c:1332
static void box_construct(BOX *result, Point *pt1, Point *pt2)
Definition geo_ops.c:519
Datum lseg_lt(PG_FUNCTION_ARGS)
Definition geo_ops.c:2285
Datum circle_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:4786
static bool box_contain_lseg(BOX *box, LSEG *lseg)
Definition geo_ops.c:3264
Datum circle_lt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4980
Datum lseg_vertical(PG_FUNCTION_ARGS)
Definition geo_ops.c:2248
Datum lseg_construct(PG_FUNCTION_ARGS)
Definition geo_ops.c:2158
Datum lseg_intersect(PG_FUNCTION_ARGS)
Definition geo_ops.c:2217
Datum dist_bp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2561
Datum box_div(PG_FUNCTION_ARGS)
Definition geo_ops.c:4336
Datum path_n_lt(PG_FUNCTION_ARGS)
Definition geo_ops.c:1571
Datum box_overright(PG_FUNCTION_ARGS)
Definition geo_ops.c:625
Datum path_npoints(PG_FUNCTION_ARGS)
Definition geo_ops.c:1636
Datum on_sl(PG_FUNCTION_ARGS)
Definition geo_ops.c:3248
Datum point_horiz(PG_FUNCTION_ARGS)
Definition geo_ops.c:1964
path_delim
Definition geo_ops.c:74
@ PATH_NONE
Definition geo_ops.c:75
@ PATH_CLOSED
Definition geo_ops.c:75
@ PATH_OPEN
Definition geo_ops.c:75
Datum circle_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:4740
Datum inter_sl(PG_FUNCTION_ARGS)
Definition geo_ops.c:3285
static bool path_decode(char *str, bool opentype, int npts, Point *p, bool *isopen, char **endptr_p, const char *type_name, const char *orig_string, Node *escontext)
Definition geo_ops.c:267
Datum lseg_parallel(PG_FUNCTION_ARGS)
Definition geo_ops.c:2227
static bool plist_same(int npts, Point *p1, Point *p2)
Definition geo_ops.c:5609
static bool touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
Definition geo_ops.c:3877
Datum box_overabove(PG_FUNCTION_ARGS)
Definition geo_ops.c:671
Datum poly_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:3718
Datum line_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:1056
Datum lseg_interpt(PG_FUNCTION_ARGS)
Definition geo_ops.c:2408
Datum point_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:1871
Datum box_circle(PG_FUNCTION_ARGS)
Definition geo_ops.c:5283
Datum path_isclosed(PG_FUNCTION_ARGS)
Definition geo_ops.c:1620
Datum circle_sub_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5039
Datum line_horizontal(PG_FUNCTION_ARGS)
Definition geo_ops.c:1200
Datum box_mul(PG_FUNCTION_ARGS)
Definition geo_ops.c:4317
Datum box_overlap(PG_FUNCTION_ARGS)
Definition geo_ops.c:564
Datum box_center(PG_FUNCTION_ARGS)
Definition geo_ops.c:850
Datum circle_overbelow(PG_FUNCTION_ARGS)
Definition geo_ops.c:4935
static float8 dist_ppoly_internal(Point *pt, POLYGON *poly)
Definition geo_ops.c:2677
#define RDELIM_L
Definition geo_ops.c:166
Datum box_contain(PG_FUNCTION_ARGS)
Definition geo_ops.c:693
Datum box_height(PG_FUNCTION_ARGS)
Definition geo_ops.c:821
Datum circle_contain_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5141
Datum dist_bs(PG_FUNCTION_ARGS)
Definition geo_ops.c:2609
Datum path_add_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4452
static float8 box_wd(BOX *box)
Definition geo_ops.c:901
static bool box_contain_point(BOX *box, Point *point)
Definition geo_ops.c:3177
Datum circle_ne(PG_FUNCTION_ARGS)
Definition geo_ops.c:4971
Datum circle_le(PG_FUNCTION_ARGS)
Definition geo_ops.c:4998
Datum box_intersect(PG_FUNCTION_ARGS)
Definition geo_ops.c:926
Datum close_pb(PG_FUNCTION_ARGS)
Definition geo_ops.c:2980
Datum circle_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:4848
static float8 point_sl(Point *pt1, Point *pt2)
Definition geo_ops.c:2052
static float8 lseg_invsl(LSEG *lseg)
Definition geo_ops.c:2194
Datum point_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:1919
Datum path_add(PG_FUNCTION_ARGS)
Definition geo_ops.c:4404
static bool line_contain_point(LINE *line, Point *point)
Definition geo_ops.c:3134
Datum circle_overlap(PG_FUNCTION_ARGS)
Definition geo_ops.c:4823
Datum lseg_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:2094
Datum circle_area(PG_FUNCTION_ARGS)
Definition geo_ops.c:5091
#define RDELIM_C
Definition geo_ops.c:164
Datum on_sb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3271
Datum dist_pb(PG_FUNCTION_ARGS)
Definition geo_ops.c:2549
Datum point_add(PG_FUNCTION_ARGS)
Definition geo_ops.c:4175
static float8 lseg_sl(LSEG *lseg)
Definition geo_ops.c:2184
Datum circle_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:4762
Datum poly_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:3626
Datum box_lt(PG_FUNCTION_ARGS)
Definition geo_ops.c:745
Datum path_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:1506
static float8 dist_cpoly_internal(CIRCLE *circle, POLYGON *poly)
Definition geo_ops.c:2618
static void box_cn(Point *center, BOX *box, Node *escontext)
Definition geo_ops.c:875
static float8 line_sl(LINE *line)
Definition geo_ops.c:1251
#define RDELIM_EP
Definition geo_ops.c:162
Datum line_intersect(PG_FUNCTION_ARGS)
Definition geo_ops.c:1155
Datum box_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:763
Datum path_n_gt(PG_FUNCTION_ARGS)
Definition geo_ops.c:1580
Datum poly_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:4578
Datum point_slope(PG_FUNCTION_ARGS)
Definition geo_ops.c:2037
Datum circle_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:5387
static int pair_count(char *s, char delim)
Definition geo_ops.c:393
static bool lseg_interpt_lseg(Point *result, LSEG *l1, LSEG *l2)
Definition geo_ops.c:2385
Datum point_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:1928
Datum box_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:502
static float8 point_invsl(Point *pt1, Point *pt2)
Definition geo_ops.c:2068
Datum point_mul(PG_FUNCTION_ARGS)
Definition geo_ops.c:4223
static float8 dist_ppath_internal(Point *pt, PATH *path)
Definition geo_ops.c:2482
static void pair_encode(float8 x, float8 y, StringInfo str)
Definition geo_ops.c:256
Datum dist_polyc(PG_FUNCTION_ARGS)
Definition geo_ops.c:2647
Datum dist_sb(PG_FUNCTION_ARGS)
Definition geo_ops.c:2597
static float8 line_invsl(LINE *line)
Definition geo_ops.c:1265
static void point_sub_point(Point *result, Point *pt1, Point *pt2)
Definition geo_ops.c:4190
Datum circle_gt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4989
Datum box_overbelow(PG_FUNCTION_ARGS)
Definition geo_ops.c:648
static float8 lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg)
Definition geo_ops.c:2857
Datum dist_cpoint(PG_FUNCTION_ARGS)
Definition geo_ops.c:5186
Datum lseg_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:2335
Datum dist_ls(PG_FUNCTION_ARGS)
Definition geo_ops.c:2585
Datum construct_point(PG_FUNCTION_ARGS)
Definition geo_ops.c:4143
Datum poly_center(PG_FUNCTION_ARGS)
Definition geo_ops.c:4559
Datum lseg_perp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2239
Datum box_contained(PG_FUNCTION_ARGS)
Definition geo_ops.c:682
Datum path_div_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4494
static bool lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
Definition geo_ops.c:2722
Datum point_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:1849
Datum box_overleft(PG_FUNCTION_ARGS)
Definition geo_ops.c:599
static bool point_eq_point(Point *pt1, Point *pt2)
Definition geo_ops.c:1995
#define LDELIM
Definition geo_ops.c:158
Datum close_ps(PG_FUNCTION_ARGS)
Definition geo_ops.c:2838
Datum dist_polyp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2668
Datum box_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:659
Datum poly_same(PG_FUNCTION_ARGS)
Definition geo_ops.c:3767
static void single_encode(float8 x, StringInfo str)
Definition geo_ops.c:204
Datum point_vert(PG_FUNCTION_ARGS)
Definition geo_ops.c:1955
Datum poly_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:3557
return str start
const char * str
int y
Definition isn.c:76
int b
Definition isn.c:74
int x
Definition isn.c:75
int a
Definition isn.c:73
int j
Definition isn.c:78
int i
Definition isn.c:77
void pfree(void *pointer)
Definition mcxt.c:1616
void * palloc0(Size size)
Definition mcxt.c:1417
void * palloc(Size size)
Definition mcxt.c:1387
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:123
#define SOFT_ERROR_OCCURRED(escontext)
Definition miscnodes.h:53
static char * errmsg
static char buf[DEFAULT_XLOG_SEG_SIZE]
uint64_t Datum
Definition postgres.h:70
unsigned int pq_getmsgint(StringInfo msg, int b)
Definition pqformat.c:414
float8 pq_getmsgfloat8(StringInfo msg)
Definition pqformat.c:487
void pq_begintypsend(StringInfo buf)
Definition pqformat.c:325
int pq_getmsgbyte(StringInfo msg)
Definition pqformat.c:398
bytea * pq_endtypsend(StringInfo buf)
Definition pqformat.c:345
void pq_sendfloat8(StringInfo buf, float8 f)
Definition pqformat.c:276
static void pq_sendint32(StringInfo buf, uint32 i)
Definition pqformat.h:144
static void pq_sendbyte(StringInfo buf, uint8 byt)
Definition pqformat.h:160
static int fb(int x)
char * psprintf(const char *fmt,...)
Definition psprintf.c:43
void check_stack_depth(void)
Definition stack_depth.c:95
struct StringInfoData * StringInfo
Definition string.h:15
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoString(StringInfo str, const char *s)
Definition stringinfo.c:230
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
void initStringInfo(StringInfo str)
Definition stringinfo.c:97
Point low
Definition geo_decls.h:142
Point high
Definition geo_decls.h:141
float8 radius
Definition geo_decls.h:164
Point center
Definition geo_decls.h:163
float8 A
Definition geo_decls.h:129
float8 B
Definition geo_decls.h:130
float8 C
Definition geo_decls.h:131
Point p[2]
Definition geo_decls.h:107
Definition nodes.h:135
Point p[FLEXIBLE_ARRAY_MEMBER]
Definition geo_decls.h:120
int32 npts
Definition geo_decls.h:117
int32 closed
Definition geo_decls.h:118
int32 dummy
Definition geo_decls.h:119
float8 y
Definition geo_decls.h:98
float8 x
Definition geo_decls.h:97
static void SET_VARSIZE(void *PTR, Size len)
Definition varatt.h:432