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);
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);
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);
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/*
417 * box_in - convert a string to internal form.
418 *
419 * External format: (two corners of box)
420 * "(f8, f8), (f8, f8)"
421 * also supports the older style "(f8, f8, f8, f8)"
422 */
423Datum
425{
426 char *str = PG_GETARG_CSTRING(0);
427 Node *escontext = fcinfo->context;
429 bool isopen;
430 float8 x,
431 y;
432
433 if (!path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str,
434 escontext))
436
437 /* reorder corners if necessary... */
438 if (float8_lt(box->high.x, box->low.x))
439 {
440 x = box->high.x;
441 box->high.x = box->low.x;
442 box->low.x = x;
443 }
444 if (float8_lt(box->high.y, box->low.y))
445 {
446 y = box->high.y;
447 box->high.y = box->low.y;
448 box->low.y = y;
449 }
450
452}
453
454/*
455 * box_out - convert a box to external form.
456 */
457Datum
464
465/*
466 * box_recv - converts external binary format to box
467 */
468Datum
470{
472 BOX *box;
473 float8 x,
474 y;
475
477
478 box->high.x = pq_getmsgfloat8(buf);
479 box->high.y = pq_getmsgfloat8(buf);
480 box->low.x = pq_getmsgfloat8(buf);
481 box->low.y = pq_getmsgfloat8(buf);
482
483 /* reorder corners if necessary... */
484 if (float8_lt(box->high.x, box->low.x))
485 {
486 x = box->high.x;
487 box->high.x = box->low.x;
488 box->low.x = x;
489 }
490 if (float8_lt(box->high.y, box->low.y))
491 {
492 y = box->high.y;
493 box->high.y = box->low.y;
494 box->low.y = y;
495 }
496
498}
499
500/*
501 * box_send - converts box to binary format
502 */
503Datum
505{
506 BOX *box = PG_GETARG_BOX_P(0);
508
510 pq_sendfloat8(&buf, box->high.x);
511 pq_sendfloat8(&buf, box->high.y);
512 pq_sendfloat8(&buf, box->low.x);
513 pq_sendfloat8(&buf, box->low.y);
515}
516
517
518/*
519 * box_construct - fill in a new box.
520 */
521static inline void
523{
524 if (float8_gt(pt1->x, pt2->x))
525 {
526 result->high.x = pt1->x;
527 result->low.x = pt2->x;
528 }
529 else
530 {
531 result->high.x = pt2->x;
532 result->low.x = pt1->x;
533 }
534 if (float8_gt(pt1->y, pt2->y))
535 {
536 result->high.y = pt1->y;
537 result->low.y = pt2->y;
538 }
539 else
540 {
541 result->high.y = pt2->y;
542 result->low.y = pt1->y;
543 }
544}
545
546
547/*----------------------------------------------------------
548 * Relational operators for BOXes.
549 * <, >, <=, >=, and == are based on box area.
550 *---------------------------------------------------------*/
551
552/*
553 * box_same - are two boxes identical?
554 */
555Datum
557{
560
561 PG_RETURN_BOOL(point_eq_point(&box1->high, &box2->high) &&
562 point_eq_point(&box1->low, &box2->low));
563}
564
565/*
566 * box_overlap - does box1 overlap box2?
567 */
568Datum
576
577static bool
579{
580 return (FPle(box1->low.x, box2->high.x) &&
581 FPle(box2->low.x, box1->high.x) &&
582 FPle(box1->low.y, box2->high.y) &&
583 FPle(box2->low.y, box1->high.y));
584}
585
586/*
587 * box_left - is box1 strictly left of box2?
588 */
589Datum
591{
594
595 PG_RETURN_BOOL(FPlt(box1->high.x, box2->low.x));
596}
597
598/*
599 * box_overleft - is the right edge of box1 at or left of
600 * the right edge of box2?
601 *
602 * This is "less than or equal" for the end of a time range,
603 * when time ranges are stored as rectangles.
604 */
605Datum
607{
610
611 PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x));
612}
613
614/*
615 * box_right - is box1 strictly right of box2?
616 */
617Datum
619{
622
623 PG_RETURN_BOOL(FPgt(box1->low.x, box2->high.x));
624}
625
626/*
627 * box_overright - is the left edge of box1 at or right of
628 * the left edge of box2?
629 *
630 * This is "greater than or equal" for time ranges, when time ranges
631 * are stored as rectangles.
632 */
633Datum
635{
638
639 PG_RETURN_BOOL(FPge(box1->low.x, box2->low.x));
640}
641
642/*
643 * box_below - is box1 strictly below box2?
644 */
645Datum
647{
650
651 PG_RETURN_BOOL(FPlt(box1->high.y, box2->low.y));
652}
653
654/*
655 * box_overbelow - is the upper edge of box1 at or below
656 * the upper edge of box2?
657 */
658Datum
660{
663
664 PG_RETURN_BOOL(FPle(box1->high.y, box2->high.y));
665}
666
667/*
668 * box_above - is box1 strictly above box2?
669 */
670Datum
672{
675
676 PG_RETURN_BOOL(FPgt(box1->low.y, box2->high.y));
677}
678
679/*
680 * box_overabove - is the lower edge of box1 at or above
681 * the lower edge of box2?
682 */
683Datum
685{
688
689 PG_RETURN_BOOL(FPge(box1->low.y, box2->low.y));
690}
691
692/*
693 * box_contained - is box1 contained by box2?
694 */
695Datum
703
704/*
705 * box_contain - does box1 contain box2?
706 */
707Datum
715
716/*
717 * Check whether the second box is in the first box or on its border
718 */
719static bool
721{
722 return FPge(contains_box->high.x, contained_box->high.x) &&
723 FPle(contains_box->low.x, contained_box->low.x) &&
724 FPge(contains_box->high.y, contained_box->high.y) &&
725 FPle(contains_box->low.y, contained_box->low.y);
726}
727
728
729/*
730 * box_positionop -
731 * is box1 entirely {above,below} box2?
732 *
733 * box_below_eq and box_above_eq are obsolete versions that (probably
734 * erroneously) accept the equal-boundaries case. Since these are not
735 * in sync with the box_left and box_right code, they are deprecated and
736 * not supported in the PG 8.1 rtree operator class extension.
737 */
738Datum
740{
743
744 PG_RETURN_BOOL(FPle(box1->high.y, box2->low.y));
745}
746
747Datum
749{
752
753 PG_RETURN_BOOL(FPge(box1->low.y, box2->high.y));
754}
755
756
757/*
758 * box_relop - is area(box1) relop area(box2), within
759 * our accuracy constraint?
760 */
761Datum
769
770Datum
778
779Datum
787
788Datum
796
797Datum
805
806
807/*----------------------------------------------------------
808 * "Arithmetic" operators on boxes.
809 *---------------------------------------------------------*/
810
811/*
812 * box_area - returns the area of the box.
813 */
814Datum
821
822
823/*
824 * box_width - returns the width of the box
825 * (horizontal magnitude).
826 */
827Datum
834
835
836/*
837 * box_height - returns the height of the box
838 * (vertical magnitude).
839 */
840Datum
847
848
849/*
850 * box_distance - returns the distance between the
851 * center points of two boxes.
852 */
853Datum
855{
858 Point a,
859 b;
860
861 box_cn(&a, box1, NULL);
862 box_cn(&b, box2, NULL);
863
865}
866
867
868/*
869 * box_center - returns the center point of the box.
870 */
871Datum
873{
874 BOX *box = PG_GETARG_BOX_P(0);
876
877 box_cn(result, box, fcinfo->context);
878 if (SOFT_ERROR_OCCURRED(fcinfo->context))
880
882}
883
884
885/*
886 * box_ar - returns the area of the box.
887 */
888static float8
890{
891 return float8_mul(box_wd(box), box_ht(box));
892}
893
894
895/*
896 * box_cn - stores the centerpoint of the box into *center.
897 */
898static void
899box_cn(Point *center, BOX *box, Node *escontext)
900{
901 float8 x;
902 float8 y;
903
904 x = float8_pl_safe(box->high.x, box->low.x, escontext);
905 if (SOFT_ERROR_OCCURRED(escontext))
906 return;
907
908 center->x = float8_div_safe(x, 2.0, escontext);
909 if (SOFT_ERROR_OCCURRED(escontext))
910 return;
911
912 y = float8_pl_safe(box->high.y, box->low.y, escontext);
913 if (SOFT_ERROR_OCCURRED(escontext))
914 return;
915
916 center->y = float8_div_safe(y, 2.0, escontext);
917 if (SOFT_ERROR_OCCURRED(escontext))
918 return;
919}
920
921/*
922 * box_wd - returns the width (length) of the box
923 * (horizontal magnitude).
924 */
925static float8
927{
928 return float8_mi(box->high.x, box->low.x);
929}
930
931
932/*
933 * box_ht - returns the height of the box
934 * (vertical magnitude).
935 */
936static float8
938{
939 return float8_mi(box->high.y, box->low.y);
940}
941
942
943/*----------------------------------------------------------
944 * Funky operations.
945 *---------------------------------------------------------*/
946
947/*
948 * box_intersect -
949 * returns the overlapping portion of two boxes,
950 * or NULL if they do not intersect.
951 */
952Datum
954{
957 BOX *result;
958
959 if (!box_ov(box1, box2))
961
963
964 result->high.x = float8_min(box1->high.x, box2->high.x);
965 result->low.x = float8_max(box1->low.x, box2->low.x);
966 result->high.y = float8_min(box1->high.y, box2->high.y);
967 result->low.y = float8_max(box1->low.y, box2->low.y);
968
970}
971
972
973/*
974 * box_diagonal -
975 * returns a line segment which happens to be the
976 * positive-slope diagonal of "box".
977 */
978Datum
988
989/***********************************************************************
990 **
991 ** Routines for 2D lines.
992 **
993 ***********************************************************************/
994
995static bool
996line_decode(char *s, const char *str, LINE *line, Node *escontext)
997{
998 /* s was already advanced over leading '{' */
999 if (!single_decode(s, &line->A, &s, "line", str, escontext))
1000 return false;
1001 if (*s++ != DELIM)
1002 goto fail;
1003 if (!single_decode(s, &line->B, &s, "line", str, escontext))
1004 return false;
1005 if (*s++ != DELIM)
1006 goto fail;
1007 if (!single_decode(s, &line->C, &s, "line", str, escontext))
1008 return false;
1009 if (*s++ != RDELIM_L)
1010 goto fail;
1011 while (isspace((unsigned char) *s))
1012 s++;
1013 if (*s != '\0')
1014 goto fail;
1015 return true;
1016
1017fail:
1018 ereturn(escontext, false,
1020 errmsg("invalid input syntax for type %s: \"%s\"",
1021 "line", str)));
1022}
1023
1024Datum
1026{
1027 char *str = PG_GETARG_CSTRING(0);
1028 Node *escontext = fcinfo->context;
1029 LINE *line = palloc_object(LINE);
1030 LSEG lseg;
1031 bool isopen;
1032 char *s;
1033
1034 s = str;
1035 while (isspace((unsigned char) *s))
1036 s++;
1037 if (*s == LDELIM_L)
1038 {
1039 if (!line_decode(s + 1, str, line, escontext))
1041 if (FPzero(line->A) && FPzero(line->B))
1042 ereturn(escontext, (Datum) 0,
1044 errmsg("invalid line specification: A and B cannot both be zero")));
1045 }
1046 else
1047 {
1048 if (!path_decode(s, true, 2, &lseg.p[0], &isopen, NULL, "line", str,
1049 escontext))
1051 if (point_eq_point(&lseg.p[0], &lseg.p[1]))
1052 ereturn(escontext, (Datum) 0,
1054 errmsg("invalid line specification: must be two distinct points")));
1055
1056 /*
1057 * XXX lseg_sl() and line_construct() can throw overflow/underflow
1058 * errors. Eventually we should allow those to be soft, but the
1059 * notational pain seems to outweigh the value for now.
1060 */
1061 line_construct(line, &lseg.p[0], lseg_sl(&lseg));
1062 }
1063
1064 PG_RETURN_LINE_P(line);
1065}
1066
1067
1068Datum
1070{
1071 LINE *line = PG_GETARG_LINE_P(0);
1072 char *astr = float8out_internal(line->A);
1073 char *bstr = float8out_internal(line->B);
1074 char *cstr = float8out_internal(line->C);
1075
1076 PG_RETURN_CSTRING(psprintf("%c%s%c%s%c%s%c", LDELIM_L, astr, DELIM, bstr,
1077 DELIM, cstr, RDELIM_L));
1078}
1079
1080/*
1081 * line_recv - converts external binary format to line
1082 */
1083Datum
1085{
1087 LINE *line;
1088
1089 line = palloc_object(LINE);
1090
1091 line->A = pq_getmsgfloat8(buf);
1092 line->B = pq_getmsgfloat8(buf);
1093 line->C = pq_getmsgfloat8(buf);
1094
1095 if (FPzero(line->A) && FPzero(line->B))
1096 ereport(ERROR,
1098 errmsg("invalid line specification: A and B cannot both be zero")));
1099
1100 PG_RETURN_LINE_P(line);
1101}
1102
1103/*
1104 * line_send - converts line to binary format
1105 */
1106Datum
1108{
1109 LINE *line = PG_GETARG_LINE_P(0);
1111
1113 pq_sendfloat8(&buf, line->A);
1114 pq_sendfloat8(&buf, line->B);
1115 pq_sendfloat8(&buf, line->C);
1117}
1118
1119
1120/*----------------------------------------------------------
1121 * Conversion routines from one line formula to internal.
1122 * Internal form: Ax+By+C=0
1123 *---------------------------------------------------------*/
1124
1125/*
1126 * Fill already-allocated LINE struct from the point and the slope
1127 */
1128static inline void
1130{
1131 if (isinf(m))
1132 {
1133 /* vertical - use "x = C" */
1134 result->A = -1.0;
1135 result->B = 0.0;
1136 result->C = pt->x;
1137 }
1138 else if (m == 0)
1139 {
1140 /* horizontal - use "y = C" */
1141 result->A = 0.0;
1142 result->B = -1.0;
1143 result->C = pt->y;
1144 }
1145 else
1146 {
1147 /* use "mx - y + yinter = 0" */
1148 result->A = m;
1149 result->B = -1.0;
1150 result->C = float8_mi(pt->y, float8_mul(m, pt->x));
1151 /* on some platforms, the preceding expression tends to produce -0 */
1152 if (result->C == 0.0)
1153 result->C = 0.0;
1154 }
1155}
1156
1157/*
1158 * line_construct_pp()
1159 * two points
1160 */
1161Datum
1163{
1167
1168 if (point_eq_point(pt1, pt2))
1169 ereport(ERROR,
1171 errmsg("invalid line specification: must be two distinct points")));
1172
1174
1176}
1177
1178
1179/*----------------------------------------------------------
1180 * Relative position routines.
1181 *---------------------------------------------------------*/
1182
1183Datum
1191
1192Datum
1194{
1195 LINE *l1 = PG_GETARG_LINE_P(0);
1196 LINE *l2 = PG_GETARG_LINE_P(1);
1197
1199}
1200
1201Datum
1203{
1204 LINE *l1 = PG_GETARG_LINE_P(0);
1205 LINE *l2 = PG_GETARG_LINE_P(1);
1206
1207 if (FPzero(l1->A))
1208 PG_RETURN_BOOL(FPzero(l2->B));
1209 if (FPzero(l2->A))
1210 PG_RETURN_BOOL(FPzero(l1->B));
1211 if (FPzero(l1->B))
1212 PG_RETURN_BOOL(FPzero(l2->A));
1213 if (FPzero(l2->B))
1214 PG_RETURN_BOOL(FPzero(l1->A));
1215
1217 float8_mul(l1->B, l2->B)), -1.0));
1218}
1219
1220Datum
1222{
1223 LINE *line = PG_GETARG_LINE_P(0);
1224
1225 PG_RETURN_BOOL(FPzero(line->B));
1226}
1227
1228Datum
1230{
1231 LINE *line = PG_GETARG_LINE_P(0);
1232
1233 PG_RETURN_BOOL(FPzero(line->A));
1234}
1235
1236
1237/*
1238 * Check whether the two lines are the same
1239 */
1240Datum
1242{
1243 LINE *l1 = PG_GETARG_LINE_P(0);
1244 LINE *l2 = PG_GETARG_LINE_P(1);
1245 float8 ratio;
1246
1247 /* If any NaNs are involved, insist on exact equality */
1248 if (unlikely(isnan(l1->A) || isnan(l1->B) || isnan(l1->C) ||
1249 isnan(l2->A) || isnan(l2->B) || isnan(l2->C)))
1250 {
1251 PG_RETURN_BOOL(float8_eq(l1->A, l2->A) &&
1252 float8_eq(l1->B, l2->B) &&
1253 float8_eq(l1->C, l2->C));
1254 }
1255
1256 /* Otherwise, lines whose parameters are proportional are the same */
1257 if (!FPzero(l2->A))
1258 ratio = float8_div(l1->A, l2->A);
1259 else if (!FPzero(l2->B))
1260 ratio = float8_div(l1->B, l2->B);
1261 else if (!FPzero(l2->C))
1262 ratio = float8_div(l1->C, l2->C);
1263 else
1264 ratio = 1.0;
1265
1266 PG_RETURN_BOOL(FPeq(l1->A, float8_mul(ratio, l2->A)) &&
1267 FPeq(l1->B, float8_mul(ratio, l2->B)) &&
1268 FPeq(l1->C, float8_mul(ratio, l2->C)));
1269}
1270
1271
1272/*----------------------------------------------------------
1273 * Line arithmetic routines.
1274 *---------------------------------------------------------*/
1275
1276/*
1277 * Return slope of the line
1278 */
1279static inline float8
1281{
1282 if (FPzero(line->A))
1283 return 0.0;
1284 if (FPzero(line->B))
1285 return get_float8_infinity();
1286 return float8_div(line->A, -line->B);
1287}
1288
1289
1290/*
1291 * Return inverse slope of the line
1292 */
1293static inline float8
1295{
1296 if (FPzero(line->A))
1297 return get_float8_infinity();
1298 if (FPzero(line->B))
1299 return 0.0;
1300 return float8_div(line->B, line->A);
1301}
1302
1303
1304/*
1305 * line_distance()
1306 * Distance between two lines.
1307 */
1308Datum
1310{
1311 LINE *l1 = PG_GETARG_LINE_P(0);
1312 LINE *l2 = PG_GETARG_LINE_P(1);
1313 float8 ratio;
1314
1315 if (line_interpt_line(NULL, l1, l2)) /* intersecting? */
1316 PG_RETURN_FLOAT8(0.0);
1317
1318 if (!FPzero(l1->A) && !isnan(l1->A) && !FPzero(l2->A) && !isnan(l2->A))
1319 ratio = float8_div(l1->A, l2->A);
1320 else if (!FPzero(l1->B) && !isnan(l1->B) && !FPzero(l2->B) && !isnan(l2->B))
1321 ratio = float8_div(l1->B, l2->B);
1322 else
1323 ratio = 1.0;
1324
1326 float8_mul(ratio, l2->C))),
1327 hypot(l1->A, l1->B)));
1328}
1329
1330/*
1331 * line_interpt()
1332 * Point where two lines l1, l2 intersect (if any)
1333 */
1334Datum
1336{
1337 LINE *l1 = PG_GETARG_LINE_P(0);
1338 LINE *l2 = PG_GETARG_LINE_P(1);
1339 Point *result;
1340
1342
1343 if (!line_interpt_line(result, l1, l2))
1346}
1347
1348/*
1349 * Internal version of line_interpt
1350 *
1351 * Return whether two lines intersect. If *result is not NULL, it is set to
1352 * the intersection point.
1353 *
1354 * NOTE: If the lines are identical then we will find they are parallel
1355 * and report "no intersection". This is a little weird, but since
1356 * there's no *unique* intersection, maybe it's appropriate behavior.
1357 *
1358 * If the lines have NaN constants, we will return true, and the intersection
1359 * point would have NaN coordinates. We shouldn't return false in this case
1360 * because that would mean the lines are parallel.
1361 */
1362static bool
1364{
1365 float8 x,
1366 y;
1367
1368 if (!FPzero(l1->B))
1369 {
1370 if (FPeq(l2->A, float8_mul(l1->A, float8_div(l2->B, l1->B))))
1371 return false;
1372
1373 x = float8_div(float8_mi(float8_mul(l1->B, l2->C),
1374 float8_mul(l2->B, l1->C)),
1375 float8_mi(float8_mul(l1->A, l2->B),
1376 float8_mul(l2->A, l1->B)));
1377 y = float8_div(-float8_pl(float8_mul(l1->A, x), l1->C), l1->B);
1378 }
1379 else if (!FPzero(l2->B))
1380 {
1381 if (FPeq(l1->A, float8_mul(l2->A, float8_div(l1->B, l2->B))))
1382 return false;
1383
1384 x = float8_div(float8_mi(float8_mul(l2->B, l1->C),
1385 float8_mul(l1->B, l2->C)),
1386 float8_mi(float8_mul(l2->A, l1->B),
1387 float8_mul(l1->A, l2->B)));
1388 y = float8_div(-float8_pl(float8_mul(l2->A, x), l2->C), l2->B);
1389 }
1390 else
1391 return false;
1392
1393 /* On some platforms, the preceding expressions tend to produce -0. */
1394 if (x == 0.0)
1395 x = 0.0;
1396 if (y == 0.0)
1397 y = 0.0;
1398
1399 if (result != NULL)
1401
1402 return true;
1403}
1404
1405
1406/***********************************************************************
1407 **
1408 ** Routines for 2D paths (sequences of line segments, also
1409 ** called `polylines').
1410 **
1411 ** This is not a general package for geometric paths,
1412 ** which of course include polygons; the emphasis here
1413 ** is on (for example) usefulness in wire layout.
1414 **
1415 ***********************************************************************/
1416
1417/*----------------------------------------------------------
1418 * String to path / path to string conversion.
1419 * External format:
1420 * "((xcoord, ycoord),... )"
1421 * "[(xcoord, ycoord),... ]"
1422 * "(xcoord, ycoord),... "
1423 * "[xcoord, ycoord,... ]"
1424 * Also support older format:
1425 * "(closed, npts, xcoord, ycoord,... )"
1426 *---------------------------------------------------------*/
1427
1428Datum
1430{
1431 PATH *path = PG_GETARG_PATH_P(0);
1432 float8 area = 0.0;
1433 int i,
1434 j;
1435
1436 if (!path->closed)
1438
1439 for (i = 0; i < path->npts; i++)
1440 {
1441 j = (i + 1) % path->npts;
1442 area = float8_pl(area, float8_mul(path->p[i].x, path->p[j].y));
1443 area = float8_mi(area, float8_mul(path->p[i].y, path->p[j].x));
1444 }
1445
1446 PG_RETURN_FLOAT8(float8_div(fabs(area), 2.0));
1447}
1448
1449
1450Datum
1452{
1453 char *str = PG_GETARG_CSTRING(0);
1454 Node *escontext = fcinfo->context;
1455 PATH *path;
1456 bool isopen;
1457 char *s;
1458 int npts;
1459 int size;
1460 int base_size;
1461 int depth = 0;
1462
1463 if ((npts = pair_count(str, ',')) <= 0)
1464 ereturn(escontext, (Datum) 0,
1466 errmsg("invalid input syntax for type %s: \"%s\"",
1467 "path", str)));
1468
1469 s = str;
1470 while (isspace((unsigned char) *s))
1471 s++;
1472
1473 /* skip single leading paren */
1474 if ((*s == LDELIM) && (strrchr(s, LDELIM) == s))
1475 {
1476 s++;
1477 depth++;
1478 }
1479
1480 base_size = sizeof(path->p[0]) * npts;
1481 size = offsetof(PATH, p) + base_size;
1482
1483 /* Check for integer overflow */
1484 if (base_size / npts != sizeof(path->p[0]) || size <= base_size)
1485 ereturn(escontext, (Datum) 0,
1487 errmsg("too many points requested")));
1488
1489 path = (PATH *) palloc(size);
1490
1491 SET_VARSIZE(path, size);
1492 path->npts = npts;
1493
1494 if (!path_decode(s, true, npts, &(path->p[0]), &isopen, &s, "path", str,
1495 escontext))
1497
1498 if (depth >= 1)
1499 {
1500 if (*s++ != RDELIM)
1501 ereturn(escontext, (Datum) 0,
1503 errmsg("invalid input syntax for type %s: \"%s\"",
1504 "path", str)));
1505 while (isspace((unsigned char) *s))
1506 s++;
1507 }
1508 if (*s != '\0')
1509 ereturn(escontext, (Datum) 0,
1511 errmsg("invalid input syntax for type %s: \"%s\"",
1512 "path", str)));
1513
1514 path->closed = (!isopen);
1515 /* prevent instability in unused pad bytes */
1516 path->dummy = 0;
1517
1518 PG_RETURN_PATH_P(path);
1519}
1520
1521
1522Datum
1524{
1525 PATH *path = PG_GETARG_PATH_P(0);
1526
1528}
1529
1530/*
1531 * path_recv - converts external binary format to path
1532 *
1533 * External representation is closed flag (a boolean byte), int32 number
1534 * of points, and the points.
1535 */
1536Datum
1538{
1540 PATH *path;
1541 int closed;
1542 int32 npts;
1543 int32 i;
1544 int size;
1545
1546 closed = pq_getmsgbyte(buf);
1547 npts = pq_getmsgint(buf, sizeof(int32));
1548 if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(PATH, p)) / sizeof(Point)))
1549 ereport(ERROR,
1551 errmsg("invalid number of points in external \"path\" value")));
1552
1553 size = offsetof(PATH, p) + sizeof(path->p[0]) * npts;
1554 path = (PATH *) palloc(size);
1555
1556 SET_VARSIZE(path, size);
1557 path->npts = npts;
1558 path->closed = (closed ? 1 : 0);
1559 /* prevent instability in unused pad bytes */
1560 path->dummy = 0;
1561
1562 for (i = 0; i < npts; i++)
1563 {
1564 path->p[i].x = pq_getmsgfloat8(buf);
1565 path->p[i].y = pq_getmsgfloat8(buf);
1566 }
1567
1568 PG_RETURN_PATH_P(path);
1569}
1570
1571/*
1572 * path_send - converts path to binary format
1573 */
1574Datum
1576{
1577 PATH *path = PG_GETARG_PATH_P(0);
1579 int32 i;
1580
1582 pq_sendbyte(&buf, path->closed ? 1 : 0);
1583 pq_sendint32(&buf, path->npts);
1584 for (i = 0; i < path->npts; i++)
1585 {
1586 pq_sendfloat8(&buf, path->p[i].x);
1587 pq_sendfloat8(&buf, path->p[i].y);
1588 }
1590}
1591
1592
1593/*----------------------------------------------------------
1594 * Relational operators.
1595 * These are based on the path cardinality,
1596 * as stupid as that sounds.
1597 *
1598 * Better relops and access methods coming soon.
1599 *---------------------------------------------------------*/
1600
1601Datum
1603{
1604 PATH *p1 = PG_GETARG_PATH_P(0);
1605 PATH *p2 = PG_GETARG_PATH_P(1);
1606
1607 PG_RETURN_BOOL(p1->npts < p2->npts);
1608}
1609
1610Datum
1612{
1613 PATH *p1 = PG_GETARG_PATH_P(0);
1614 PATH *p2 = PG_GETARG_PATH_P(1);
1615
1616 PG_RETURN_BOOL(p1->npts > p2->npts);
1617}
1618
1619Datum
1621{
1622 PATH *p1 = PG_GETARG_PATH_P(0);
1623 PATH *p2 = PG_GETARG_PATH_P(1);
1624
1625 PG_RETURN_BOOL(p1->npts == p2->npts);
1626}
1627
1628Datum
1630{
1631 PATH *p1 = PG_GETARG_PATH_P(0);
1632 PATH *p2 = PG_GETARG_PATH_P(1);
1633
1634 PG_RETURN_BOOL(p1->npts <= p2->npts);
1635}
1636
1637Datum
1639{
1640 PATH *p1 = PG_GETARG_PATH_P(0);
1641 PATH *p2 = PG_GETARG_PATH_P(1);
1642
1643 PG_RETURN_BOOL(p1->npts >= p2->npts);
1644}
1645
1646/*----------------------------------------------------------
1647 * Conversion operators.
1648 *---------------------------------------------------------*/
1649
1650Datum
1652{
1653 PATH *path = PG_GETARG_PATH_P(0);
1654
1655 PG_RETURN_BOOL(path->closed);
1656}
1657
1658Datum
1660{
1661 PATH *path = PG_GETARG_PATH_P(0);
1662
1663 PG_RETURN_BOOL(!path->closed);
1664}
1665
1666Datum
1668{
1669 PATH *path = PG_GETARG_PATH_P(0);
1670
1671 PG_RETURN_INT32(path->npts);
1672}
1673
1674
1675Datum
1677{
1678 PATH *path = PG_GETARG_PATH_P_COPY(0);
1679
1680 path->closed = true;
1681
1682 PG_RETURN_PATH_P(path);
1683}
1684
1685Datum
1687{
1688 PATH *path = PG_GETARG_PATH_P_COPY(0);
1689
1690 path->closed = false;
1691
1692 PG_RETURN_PATH_P(path);
1693}
1694
1695
1696/*
1697 * path_inter -
1698 * Does p1 intersect p2 at any point?
1699 * Use bounding boxes for a quick (O(n)) check, then do a
1700 * O(n^2) iterative edge check.
1701 */
1702Datum
1704{
1705 PATH *p1 = PG_GETARG_PATH_P(0);
1706 PATH *p2 = PG_GETARG_PATH_P(1);
1707 BOX b1,
1708 b2;
1709 int i,
1710 j;
1711 LSEG seg1,
1712 seg2;
1713
1714 Assert(p1->npts > 0 && p2->npts > 0);
1715
1716 b1.high.x = b1.low.x = p1->p[0].x;
1717 b1.high.y = b1.low.y = p1->p[0].y;
1718 for (i = 1; i < p1->npts; i++)
1719 {
1720 b1.high.x = float8_max(p1->p[i].x, b1.high.x);
1721 b1.high.y = float8_max(p1->p[i].y, b1.high.y);
1722 b1.low.x = float8_min(p1->p[i].x, b1.low.x);
1723 b1.low.y = float8_min(p1->p[i].y, b1.low.y);
1724 }
1725 b2.high.x = b2.low.x = p2->p[0].x;
1726 b2.high.y = b2.low.y = p2->p[0].y;
1727 for (i = 1; i < p2->npts; i++)
1728 {
1729 b2.high.x = float8_max(p2->p[i].x, b2.high.x);
1730 b2.high.y = float8_max(p2->p[i].y, b2.high.y);
1731 b2.low.x = float8_min(p2->p[i].x, b2.low.x);
1732 b2.low.y = float8_min(p2->p[i].y, b2.low.y);
1733 }
1734 if (!box_ov(&b1, &b2))
1735 PG_RETURN_BOOL(false);
1736
1737 /* pairwise check lseg intersections */
1738 for (i = 0; i < p1->npts; i++)
1739 {
1740 int iprev;
1741
1742 if (i > 0)
1743 iprev = i - 1;
1744 else
1745 {
1746 if (!p1->closed)
1747 continue;
1748 iprev = p1->npts - 1; /* include the closure segment */
1749 }
1750
1751 for (j = 0; j < p2->npts; j++)
1752 {
1753 int jprev;
1754
1755 if (j > 0)
1756 jprev = j - 1;
1757 else
1758 {
1759 if (!p2->closed)
1760 continue;
1761 jprev = p2->npts - 1; /* include the closure segment */
1762 }
1763
1764 statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
1765 statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
1767 PG_RETURN_BOOL(true);
1768 }
1769 }
1770
1771 /* if we dropped through, no two segs intersected */
1772 PG_RETURN_BOOL(false);
1773}
1774
1775/*
1776 * path_distance()
1777 * This essentially does a cartesian product of the lsegs in the
1778 * two paths, and finds the min distance between any two lsegs
1779 */
1780Datum
1782{
1783 PATH *p1 = PG_GETARG_PATH_P(0);
1784 PATH *p2 = PG_GETARG_PATH_P(1);
1785 float8 min = 0.0; /* initialize to keep compiler quiet */
1786 bool have_min = false;
1787 float8 tmp;
1788 int i,
1789 j;
1790 LSEG seg1,
1791 seg2;
1792
1793 for (i = 0; i < p1->npts; i++)
1794 {
1795 int iprev;
1796
1797 if (i > 0)
1798 iprev = i - 1;
1799 else
1800 {
1801 if (!p1->closed)
1802 continue;
1803 iprev = p1->npts - 1; /* include the closure segment */
1804 }
1805
1806 for (j = 0; j < p2->npts; j++)
1807 {
1808 int jprev;
1809
1810 if (j > 0)
1811 jprev = j - 1;
1812 else
1813 {
1814 if (!p2->closed)
1815 continue;
1816 jprev = p2->npts - 1; /* include the closure segment */
1817 }
1818
1819 statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
1820 statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
1821
1822 tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
1823 if (!have_min || float8_lt(tmp, min))
1824 {
1825 min = tmp;
1826 have_min = true;
1827 }
1828 }
1829 }
1830
1831 if (!have_min)
1833
1834 PG_RETURN_FLOAT8(min);
1835}
1836
1837
1838/*----------------------------------------------------------
1839 * "Arithmetic" operations.
1840 *---------------------------------------------------------*/
1841
1842Datum
1844{
1845 PATH *path = PG_GETARG_PATH_P(0);
1846 float8 result = 0.0;
1847 int i;
1848
1849 for (i = 0; i < path->npts; i++)
1850 {
1851 int iprev;
1852
1853 if (i > 0)
1854 iprev = i - 1;
1855 else
1856 {
1857 if (!path->closed)
1858 continue;
1859 iprev = path->npts - 1; /* include the closure segment */
1860 }
1861
1862 result = float8_pl(result, point_dt(&path->p[iprev], &path->p[i], NULL));
1863 }
1864
1866}
1867
1868/***********************************************************************
1869 **
1870 ** Routines for 2D points.
1871 **
1872 ***********************************************************************/
1873
1874/*----------------------------------------------------------
1875 * String to point, point to string conversion.
1876 * External format:
1877 * "(x,y)"
1878 * "x,y"
1879 *---------------------------------------------------------*/
1880
1881Datum
1883{
1884 char *str = PG_GETARG_CSTRING(0);
1886
1887 /* Ignore failure from pair_decode, since our return value won't matter */
1888 pair_decode(str, &point->x, &point->y, NULL, "point", str, fcinfo->context);
1890}
1891
1892Datum
1899
1900/*
1901 * point_recv - converts external binary format to point
1902 */
1903Datum
1914
1915/*
1916 * point_send - converts point to binary format
1917 */
1918Datum
1929
1930
1931/*
1932 * Initialize a point
1933 */
1934static inline void
1936{
1937 result->x = x;
1938 result->y = y;
1939}
1940
1941
1942/*----------------------------------------------------------
1943 * Relational operators for Points.
1944 * Since we do have a sense of coordinates being
1945 * "equal" to a given accuracy (point_vert, point_horiz),
1946 * the other ops must preserve that sense. This means
1947 * that results may, strictly speaking, be a lie (unless
1948 * EPSILON = 0.0).
1949 *---------------------------------------------------------*/
1950
1951Datum
1959
1960Datum
1968
1969Datum
1977
1978Datum
1986
1987Datum
1995
1996Datum
2004
2005Datum
2013
2014Datum
2022
2023
2024/*
2025 * Check whether the two points are the same
2026 */
2027static inline bool
2029{
2030 /* If any NaNs are involved, insist on exact equality */
2031 if (unlikely(isnan(pt1->x) || isnan(pt1->y) ||
2032 isnan(pt2->x) || isnan(pt2->y)))
2033 return (float8_eq(pt1->x, pt2->x) && float8_eq(pt1->y, pt2->y));
2034
2035 return (FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
2036}
2037
2038
2039/*----------------------------------------------------------
2040 * "Arithmetic" operators on points.
2041 *---------------------------------------------------------*/
2042
2043Datum
2051
2052static inline float8
2054{
2055 float8 x;
2056 float8 y;
2057
2058 x = float8_mi_safe(pt1->x, pt2->x, escontext);
2059 if (unlikely(SOFT_ERROR_OCCURRED(escontext)))
2060 return 0.0;
2061
2062 y = float8_mi_safe(pt1->y, pt2->y, escontext);
2063 if (unlikely(SOFT_ERROR_OCCURRED(escontext)))
2064 return 0.0;
2065
2066 return hypot(x, y);
2067}
2068
2069Datum
2077
2078
2079/*
2080 * Return slope of two points
2081 *
2082 * Note that this function returns Inf when the points are the same.
2083 */
2084static inline float8
2086{
2087 if (FPeq(pt1->x, pt2->x))
2088 return get_float8_infinity();
2089 if (FPeq(pt1->y, pt2->y))
2090 return 0.0;
2091 return float8_div(float8_mi(pt1->y, pt2->y), float8_mi(pt1->x, pt2->x));
2092}
2093
2094
2095/*
2096 * Return inverse slope of two points
2097 *
2098 * Note that this function returns 0.0 when the points are the same.
2099 */
2100static inline float8
2102{
2103 if (FPeq(pt1->x, pt2->x))
2104 return 0.0;
2105 if (FPeq(pt1->y, pt2->y))
2106 return get_float8_infinity();
2107 return float8_div(float8_mi(pt1->x, pt2->x), float8_mi(pt2->y, pt1->y));
2108}
2109
2110
2111/***********************************************************************
2112 **
2113 ** Routines for 2D line segments.
2114 **
2115 ***********************************************************************/
2116
2117/*----------------------------------------------------------
2118 * String to lseg, lseg to string conversion.
2119 * External forms: "[(x1, y1), (x2, y2)]"
2120 * "(x1, y1), (x2, y2)"
2121 * "x1, y1, x2, y2"
2122 * closed form ok "((x1, y1), (x2, y2))"
2123 * (old form) "(x1, y1, x2, y2)"
2124 *---------------------------------------------------------*/
2125
2126Datum
2128{
2129 char *str = PG_GETARG_CSTRING(0);
2130 Node *escontext = fcinfo->context;
2132 bool isopen;
2133
2134 if (!path_decode(str, true, 2, &lseg->p[0], &isopen, NULL, "lseg", str,
2135 escontext))
2137
2139}
2140
2141
2142Datum
2149
2150/*
2151 * lseg_recv - converts external binary format to lseg
2152 */
2153Datum
2155{
2157 LSEG *lseg;
2158
2160
2161 lseg->p[0].x = pq_getmsgfloat8(buf);
2162 lseg->p[0].y = pq_getmsgfloat8(buf);
2163 lseg->p[1].x = pq_getmsgfloat8(buf);
2164 lseg->p[1].y = pq_getmsgfloat8(buf);
2165
2167}
2168
2169/*
2170 * lseg_send - converts lseg to binary format
2171 */
2172Datum
2174{
2175 LSEG *ls = PG_GETARG_LSEG_P(0);
2177
2179 pq_sendfloat8(&buf, ls->p[0].x);
2180 pq_sendfloat8(&buf, ls->p[0].y);
2181 pq_sendfloat8(&buf, ls->p[1].x);
2182 pq_sendfloat8(&buf, ls->p[1].y);
2184}
2185
2186
2187/*
2188 * lseg_construct -
2189 * form a LSEG from two Points.
2190 */
2191Datum
2202
2203/* like lseg_construct, but assume space already allocated */
2204static inline void
2206{
2207 lseg->p[0].x = pt1->x;
2208 lseg->p[0].y = pt1->y;
2209 lseg->p[1].x = pt2->x;
2210 lseg->p[1].y = pt2->y;
2211}
2212
2213
2214/*
2215 * Return slope of the line segment
2216 */
2217static inline float8
2219{
2220 return point_sl(&lseg->p[0], &lseg->p[1]);
2221}
2222
2223
2224/*
2225 * Return inverse slope of the line segment
2226 */
2227static inline float8
2229{
2230 return point_invsl(&lseg->p[0], &lseg->p[1]);
2231}
2232
2233
2234Datum
2236{
2238
2239 PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1], NULL));
2240}
2241
2242/*----------------------------------------------------------
2243 * Relative position routines.
2244 *---------------------------------------------------------*/
2245
2246/*
2247 * find intersection of the two lines, and see if it falls on
2248 * both segments.
2249 */
2250Datum
2258
2259
2260Datum
2262{
2263 LSEG *l1 = PG_GETARG_LSEG_P(0);
2264 LSEG *l2 = PG_GETARG_LSEG_P(1);
2265
2267}
2268
2269/*
2270 * Determine if two line segments are perpendicular.
2271 */
2272Datum
2274{
2275 LSEG *l1 = PG_GETARG_LSEG_P(0);
2276 LSEG *l2 = PG_GETARG_LSEG_P(1);
2277
2279}
2280
2281Datum
2283{
2285
2286 PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
2287}
2288
2289Datum
2291{
2293
2294 PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
2295}
2296
2297
2298Datum
2300{
2301 LSEG *l1 = PG_GETARG_LSEG_P(0);
2302 LSEG *l2 = PG_GETARG_LSEG_P(1);
2303
2304 PG_RETURN_BOOL(point_eq_point(&l1->p[0], &l2->p[0]) &&
2305 point_eq_point(&l1->p[1], &l2->p[1]));
2306}
2307
2308Datum
2310{
2311 LSEG *l1 = PG_GETARG_LSEG_P(0);
2312 LSEG *l2 = PG_GETARG_LSEG_P(1);
2313
2314 PG_RETURN_BOOL(!point_eq_point(&l1->p[0], &l2->p[0]) ||
2315 !point_eq_point(&l1->p[1], &l2->p[1]));
2316}
2317
2318Datum
2320{
2321 LSEG *l1 = PG_GETARG_LSEG_P(0);
2322 LSEG *l2 = PG_GETARG_LSEG_P(1);
2323
2324 PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1], NULL),
2325 point_dt(&l2->p[0], &l2->p[1], NULL)));
2326}
2327
2328Datum
2330{
2331 LSEG *l1 = PG_GETARG_LSEG_P(0);
2332 LSEG *l2 = PG_GETARG_LSEG_P(1);
2333
2334 PG_RETURN_BOOL(FPle(point_dt(&l1->p[0], &l1->p[1], NULL),
2335 point_dt(&l2->p[0], &l2->p[1], NULL)));
2336}
2337
2338Datum
2340{
2341 LSEG *l1 = PG_GETARG_LSEG_P(0);
2342 LSEG *l2 = PG_GETARG_LSEG_P(1);
2343
2344 PG_RETURN_BOOL(FPgt(point_dt(&l1->p[0], &l1->p[1], NULL),
2345 point_dt(&l2->p[0], &l2->p[1], NULL)));
2346}
2347
2348Datum
2350{
2351 LSEG *l1 = PG_GETARG_LSEG_P(0);
2352 LSEG *l2 = PG_GETARG_LSEG_P(1);
2353
2354 PG_RETURN_BOOL(FPge(point_dt(&l1->p[0], &l1->p[1], NULL),
2355 point_dt(&l2->p[0], &l2->p[1], NULL)));
2356}
2357
2358
2359/*----------------------------------------------------------
2360 * Line arithmetic routines.
2361 *---------------------------------------------------------*/
2362
2363/*
2364 * lseg_distance -
2365 * If two segments don't intersect, then the closest
2366 * point will be from one of the endpoints to the other
2367 * segment.
2368 */
2369Datum
2377
2378
2379Datum
2381{
2383 Point *result;
2384 float8 x;
2385 float8 y;
2386
2388
2389 x = float8_pl_safe(lseg->p[0].x, lseg->p[1].x, fcinfo->context);
2390 if (SOFT_ERROR_OCCURRED(fcinfo->context))
2391 goto fail;
2392
2393 result->x = float8_div_safe(x, 2.0, fcinfo->context);
2394 if (SOFT_ERROR_OCCURRED(fcinfo->context))
2395 goto fail;
2396
2397 y = float8_pl_safe(lseg->p[0].y, lseg->p[1].y, fcinfo->context);
2398 if (SOFT_ERROR_OCCURRED(fcinfo->context))
2399 goto fail;
2400
2401 result->y = float8_div_safe(y, 2.0, fcinfo->context);
2402 if (SOFT_ERROR_OCCURRED(fcinfo->context))
2403 goto fail;
2404
2406
2407fail:
2409}
2410
2411
2412/*
2413 * Return whether the two segments intersect. If *result is not NULL,
2414 * it is set to the intersection point.
2415 *
2416 * This function is almost perfectly symmetric, even though it doesn't look
2417 * like it. See lseg_interpt_line() for the other half of it.
2418 */
2419static bool
2421{
2422 Point interpt;
2423 LINE tmp;
2424
2425 line_construct(&tmp, &l2->p[0], lseg_sl(l2));
2426 if (!lseg_interpt_line(&interpt, l1, &tmp))
2427 return false;
2428
2429 /*
2430 * If the line intersection point isn't within l2, there is no valid
2431 * segment intersection point at all.
2432 */
2433 if (!lseg_contain_point(l2, &interpt))
2434 return false;
2435
2436 if (result != NULL)
2437 *result = interpt;
2438
2439 return true;
2440}
2441
2442Datum
2444{
2445 LSEG *l1 = PG_GETARG_LSEG_P(0);
2446 LSEG *l2 = PG_GETARG_LSEG_P(1);
2447 Point *result;
2448
2450
2451 if (!lseg_interpt_lseg(result, l1, l2))
2454}
2455
2456/***********************************************************************
2457 **
2458 ** Routines for position comparisons of differently-typed
2459 ** 2D objects.
2460 **
2461 ***********************************************************************/
2462
2463/*---------------------------------------------------------------------
2464 * dist_
2465 * Minimum distance from one object to another.
2466 *-------------------------------------------------------------------*/
2467
2468/*
2469 * Distance from a point to a line
2470 */
2471Datum
2479
2480/*
2481 * Distance from a line to a point
2482 */
2483Datum
2491
2492/*
2493 * Distance from a point to a lseg
2494 */
2495Datum
2503
2504/*
2505 * Distance from a lseg to a point
2506 */
2507Datum
2515
2516static float8
2518{
2519 float8 result = 0.0; /* keep compiler quiet */
2520 bool have_min = false;
2521 float8 tmp;
2522 int i;
2523 LSEG lseg;
2524
2525 Assert(path->npts > 0);
2526
2527 /*
2528 * The distance from a point to a path is the smallest distance from the
2529 * point to any of its constituent segments.
2530 */
2531 for (i = 0; i < path->npts; i++)
2532 {
2533 int iprev;
2534
2535 if (i > 0)
2536 iprev = i - 1;
2537 else
2538 {
2539 if (!path->closed)
2540 continue;
2541 iprev = path->npts - 1; /* Include the closure segment */
2542 }
2543
2544 statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
2545 tmp = lseg_closept_point(NULL, &lseg, pt);
2546 if (!have_min || float8_lt(tmp, result))
2547 {
2548 result = tmp;
2549 have_min = true;
2550 }
2551 }
2552
2553 return result;
2554}
2555
2556/*
2557 * Distance from a point to a path
2558 */
2559Datum
2567
2568/*
2569 * Distance from a path to a point
2570 */
2571Datum
2579
2580/*
2581 * Distance from a point to a box
2582 */
2583Datum
2591
2592/*
2593 * Distance from a box to a point
2594 */
2595Datum
2603
2604/*
2605 * Distance from a lseg to a line
2606 */
2607Datum
2615
2616/*
2617 * Distance from a line to a lseg
2618 */
2619Datum
2627
2628/*
2629 * Distance from a lseg to a box
2630 */
2631Datum
2639
2640/*
2641 * Distance from a box to a lseg
2642 */
2643Datum
2651
2652static float8
2654{
2655 float8 result;
2656
2657 /* calculate distance to center, and subtract radius */
2659 circle->radius);
2660 if (result < 0.0)
2661 result = 0.0;
2662
2663 return result;
2664}
2665
2666/*
2667 * Distance from a circle to a polygon
2668 */
2669Datum
2677
2678/*
2679 * Distance from a polygon to a circle
2680 */
2681Datum
2689
2690/*
2691 * Distance from a point to a polygon
2692 */
2693Datum
2701
2702Datum
2710
2711static float8
2713{
2714 float8 result;
2715 float8 d;
2716 int i;
2717 LSEG seg;
2718
2719 if (point_inside(pt, poly->npts, poly->p) != 0)
2720 return 0.0;
2721
2722 /* initialize distance with segment between first and last points */
2723 seg.p[0].x = poly->p[0].x;
2724 seg.p[0].y = poly->p[0].y;
2725 seg.p[1].x = poly->p[poly->npts - 1].x;
2726 seg.p[1].y = poly->p[poly->npts - 1].y;
2727 result = lseg_closept_point(NULL, &seg, pt);
2728
2729 /* check distances for other segments */
2730 for (i = 0; i < poly->npts - 1; i++)
2731 {
2732 seg.p[0].x = poly->p[i].x;
2733 seg.p[0].y = poly->p[i].y;
2734 seg.p[1].x = poly->p[i + 1].x;
2735 seg.p[1].y = poly->p[i + 1].y;
2736 d = lseg_closept_point(NULL, &seg, pt);
2737 if (float8_lt(d, result))
2738 result = d;
2739 }
2740
2741 return result;
2742}
2743
2744
2745/*---------------------------------------------------------------------
2746 * interpt_
2747 * Intersection point of objects.
2748 * We choose to ignore the "point" of intersection between
2749 * lines and boxes, since there are typically two.
2750 *-------------------------------------------------------------------*/
2751
2752/*
2753 * Return whether the line segment intersect with the line. If *result is not
2754 * NULL, it is set to the intersection point.
2755 */
2756static bool
2758{
2759 Point interpt;
2760 LINE tmp;
2761
2762 /*
2763 * First, we promote the line segment to a line, because we know how to
2764 * find the intersection point of two lines. If they don't have an
2765 * intersection point, we are done.
2766 */
2767 line_construct(&tmp, &lseg->p[0], lseg_sl(lseg));
2768 if (!line_interpt_line(&interpt, &tmp, line))
2769 return false;
2770
2771 /*
2772 * Then, we check whether the intersection point is actually on the line
2773 * segment.
2774 */
2776 return false;
2777 if (result != NULL)
2778 {
2779 /*
2780 * If there is an intersection, then check explicitly for matching
2781 * endpoints since there may be rounding effects with annoying LSB
2782 * residue.
2783 */
2784 if (point_eq_point(&lseg->p[0], &interpt))
2785 *result = lseg->p[0];
2786 else if (point_eq_point(&lseg->p[1], &interpt))
2787 *result = lseg->p[1];
2788 else
2789 *result = interpt;
2790 }
2791
2792 return true;
2793}
2794
2795/*---------------------------------------------------------------------
2796 * close_
2797 * Point of closest proximity between objects.
2798 *-------------------------------------------------------------------*/
2799
2800/*
2801 * If *result is not NULL, it is set to the intersection point of a
2802 * perpendicular of the line through the point. Returns the distance
2803 * of those two points.
2804 */
2805static float8
2807{
2808 Point closept;
2809 LINE tmp;
2810
2811 /*
2812 * We drop a perpendicular to find the intersection point. Ordinarily we
2813 * should always find it, but that can fail in the presence of NaN
2814 * coordinates, and perhaps even from simple roundoff issues.
2815 */
2816 line_construct(&tmp, point, line_invsl(line));
2817 if (!line_interpt_line(&closept, &tmp, line))
2818 {
2819 if (result != NULL)
2820 *result = *point;
2821
2822 return get_float8_nan();
2823 }
2824
2825 if (result != NULL)
2826 *result = closept;
2827
2828 return point_dt(&closept, point, NULL);
2829}
2830
2831Datum
2833{
2835 LINE *line = PG_GETARG_LINE_P(1);
2836 Point *result;
2837
2839
2840 if (isnan(line_closept_point(result, line, pt)))
2842
2844}
2845
2846
2847/*
2848 * Closest point on line segment to specified point.
2849 *
2850 * If *result is not NULL, set it to the closest point on the line segment
2851 * to the point. Returns the distance of the two points.
2852 */
2853static float8
2855{
2856 Point closept;
2857 LINE tmp;
2858
2859 /*
2860 * To find the closest point, we draw a perpendicular line from the point
2861 * to the line segment.
2862 */
2863 line_construct(&tmp, pt, point_invsl(&lseg->p[0], &lseg->p[1]));
2865
2866 if (result != NULL)
2867 *result = closept;
2868
2869 return point_dt(&closept, pt, NULL);
2870}
2871
2872Datum
2886
2887
2888/*
2889 * Closest point on line segment to line segment
2890 */
2891static float8
2893{
2894 Point point;
2895 float8 dist,
2896 d;
2897
2898 /* First, we handle the case when the line segments are intersecting. */
2900 return 0.0;
2901
2902 /*
2903 * Then, we find the closest points from the endpoints of the second line
2904 * segment, and keep the closest one.
2905 */
2907 d = lseg_closept_point(&point, on_lseg, &to_lseg->p[1]);
2908 if (float8_lt(d, dist))
2909 {
2910 dist = d;
2911 if (result != NULL)
2912 *result = point;
2913 }
2914
2915 /* The closest point can still be one of the endpoints, so we test them. */
2916 d = lseg_closept_point(NULL, to_lseg, &on_lseg->p[0]);
2917 if (float8_lt(d, dist))
2918 {
2919 dist = d;
2920 if (result != NULL)
2921 *result = on_lseg->p[0];
2922 }
2923 d = lseg_closept_point(NULL, to_lseg, &on_lseg->p[1]);
2924 if (float8_lt(d, dist))
2925 {
2926 dist = d;
2927 if (result != NULL)
2928 *result = on_lseg->p[1];
2929 }
2930
2931 return dist;
2932}
2933
2934Datum
2936{
2937 LSEG *l1 = PG_GETARG_LSEG_P(0);
2938 LSEG *l2 = PG_GETARG_LSEG_P(1);
2939 Point *result;
2940
2941 if (lseg_sl(l1) == lseg_sl(l2))
2943
2945
2946 if (isnan(lseg_closept_lseg(result, l2, l1)))
2948
2950}
2951
2952
2953/*
2954 * Closest point on or in box to specified point.
2955 *
2956 * If *result is not NULL, set it to the closest point on the box to the
2957 * given point, and return the distance of the two points.
2958 */
2959static float8
2961{
2962 float8 dist,
2963 d;
2964 Point point,
2965 closept;
2966 LSEG lseg;
2967
2968 if (box_contain_point(box, pt))
2969 {
2970 if (result != NULL)
2971 *result = *pt;
2972
2973 return 0.0;
2974 }
2975
2976 /* pairwise check lseg distances */
2977 point.x = box->low.x;
2978 point.y = box->high.y;
2979 statlseg_construct(&lseg, &box->low, &point);
2981
2982 statlseg_construct(&lseg, &box->high, &point);
2984 if (float8_lt(d, dist))
2985 {
2986 dist = d;
2987 if (result != NULL)
2988 *result = closept;
2989 }
2990
2991 point.x = box->high.x;
2992 point.y = box->low.y;
2993 statlseg_construct(&lseg, &box->low, &point);
2995 if (float8_lt(d, dist))
2996 {
2997 dist = d;
2998 if (result != NULL)
2999 *result = closept;
3000 }
3001
3002 statlseg_construct(&lseg, &box->high, &point);
3004 if (float8_lt(d, dist))
3005 {
3006 dist = d;
3007 if (result != NULL)
3008 *result = closept;
3009 }
3010
3011 return dist;
3012}
3013
3014Datum
3028
3029/*
3030 * Closest point on line segment to line.
3031 *
3032 * Return the distance between the line and the closest point of the line
3033 * segment to the line. If *result is not NULL, set it to that point.
3034 *
3035 * NOTE: When the lines are parallel, endpoints of one of the line segment
3036 * are FPeq(), in presence of NaN or Infinite coordinates, or perhaps =
3037 * even because of simple roundoff issues, there may not be a single closest
3038 * point. We are likely to set the result to the second endpoint in these
3039 * cases.
3040 */
3041static float8
3043{
3044 float8 dist1,
3045 dist2;
3046
3047 if (lseg_interpt_line(result, lseg, line))
3048 return 0.0;
3049
3050 dist1 = line_closept_point(NULL, line, &lseg->p[0]);
3051 dist2 = line_closept_point(NULL, line, &lseg->p[1]);
3052
3053 if (dist1 < dist2)
3054 {
3055 if (result != NULL)
3056 *result = lseg->p[0];
3057
3058 return dist1;
3059 }
3060 else
3061 {
3062 if (result != NULL)
3063 *result = lseg->p[1];
3064
3065 return dist2;
3066 }
3067}
3068
3069Datum
3071{
3072 LINE *line = PG_GETARG_LINE_P(0);
3074 Point *result;
3075
3076 if (lseg_sl(lseg) == line_sl(line))
3078
3080
3081 if (isnan(lseg_closept_line(result, lseg, line)))
3083
3085}
3086
3087
3088/*
3089 * Closest point on or in box to line segment.
3090 *
3091 * Returns the distance between the closest point on or in the box to
3092 * the line segment. If *result is not NULL, it is set to that point.
3093 */
3094static float8
3096{
3097 float8 dist,
3098 d;
3099 Point point,
3100 closept;
3101 LSEG bseg;
3102
3104 return 0.0;
3105
3106 /* pairwise check lseg distances */
3107 point.x = box->low.x;
3108 point.y = box->high.y;
3109 statlseg_construct(&bseg, &box->low, &point);
3111
3112 statlseg_construct(&bseg, &box->high, &point);
3114 if (float8_lt(d, dist))
3115 {
3116 dist = d;
3117 if (result != NULL)
3118 *result = closept;
3119 }
3120
3121 point.x = box->high.x;
3122 point.y = box->low.y;
3123 statlseg_construct(&bseg, &box->low, &point);
3125 if (float8_lt(d, dist))
3126 {
3127 dist = d;
3128 if (result != NULL)
3129 *result = closept;
3130 }
3131
3132 statlseg_construct(&bseg, &box->high, &point);
3134 if (float8_lt(d, dist))
3135 {
3136 dist = d;
3137 if (result != NULL)
3138 *result = closept;
3139 }
3140
3141 return dist;
3142}
3143
3144Datum
3158
3159
3160/*---------------------------------------------------------------------
3161 * on_
3162 * Whether one object lies completely within another.
3163 *-------------------------------------------------------------------*/
3164
3165/*
3166 * Does the point satisfy the equation?
3167 */
3168static bool
3170{
3171 return FPzero(float8_pl(float8_pl(float8_mul(line->A, point->x),
3172 float8_mul(line->B, point->y)),
3173 line->C));
3174}
3175
3176Datum
3178{
3180 LINE *line = PG_GETARG_LINE_P(1);
3181
3183}
3184
3185
3186/*
3187 * Determine colinearity by detecting a triangle inequality.
3188 * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
3189 */
3190static bool
3192{
3193 return FPeq(point_dt(pt, &lseg->p[0], NULL) +
3194 point_dt(pt, &lseg->p[1], NULL),
3195 point_dt(&lseg->p[0], &lseg->p[1], NULL));
3196}
3197
3198Datum
3206
3207
3208/*
3209 * Check whether the point is in the box or on its border
3210 */
3211static bool
3213{
3214 return box->high.x >= point->x && box->low.x <= point->x &&
3215 box->high.y >= point->y && box->low.y <= point->y;
3216}
3217
3218Datum
3226
3227Datum
3235
3236/*
3237 * on_ppath -
3238 * Whether a point lies within (on) a polyline.
3239 * If open, we have to (groan) check each segment.
3240 * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
3241 * If closed, we use the old O(n) ray method for point-in-polygon.
3242 * The ray is horizontal, from pt out to the right.
3243 * Each segment that crosses the ray counts as an
3244 * intersection; note that an endpoint or edge may touch
3245 * but not cross.
3246 * (we can do p-in-p in lg(n), but it takes preprocessing)
3247 */
3248Datum
3250{
3252 PATH *path = PG_GETARG_PATH_P(1);
3253 int i,
3254 n;
3255 float8 a,
3256 b;
3257
3258 /*-- OPEN --*/
3259 if (!path->closed)
3260 {
3261 n = path->npts - 1;
3262 a = point_dt(pt, &path->p[0], NULL);
3263 for (i = 0; i < n; i++)
3264 {
3265 b = point_dt(pt, &path->p[i + 1], NULL);
3266 if (FPeq(float8_pl(a, b), point_dt(&path->p[i], &path->p[i + 1], NULL)))
3267 PG_RETURN_BOOL(true);
3268 a = b;
3269 }
3270 PG_RETURN_BOOL(false);
3271 }
3272
3273 /*-- CLOSED --*/
3274 PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
3275}
3276
3277
3278/*
3279 * Check whether the line segment is on the line or close enough
3280 *
3281 * It is, if both of its points are on the line or close enough.
3282 */
3283Datum
3285{
3287 LINE *line = PG_GETARG_LINE_P(1);
3288
3289 PG_RETURN_BOOL(line_contain_point(line, &lseg->p[0]) &&
3290 line_contain_point(line, &lseg->p[1]));
3291}
3292
3293
3294/*
3295 * Check whether the line segment is in the box or on its border
3296 *
3297 * It is, if both of its points are in the box or on its border.
3298 */
3299static bool
3301{
3302 return box_contain_point(box, &lseg->p[0]) &&
3303 box_contain_point(box, &lseg->p[1]);
3304}
3305
3306Datum
3314
3315/*---------------------------------------------------------------------
3316 * inter_
3317 * Whether one object intersects another.
3318 *-------------------------------------------------------------------*/
3319
3320Datum
3328
3329
3330/*
3331 * Do line segment and box intersect?
3332 *
3333 * Segment completely inside box counts as intersection.
3334 * If you want only segments crossing box boundaries,
3335 * try converting box to path first.
3336 *
3337 * This function also sets the *result to the closest point on the line
3338 * segment to the center of the box when they overlap and the result is
3339 * not NULL. It is somewhat arbitrary, but maybe the best we can do as
3340 * there are typically two points they intersect.
3341 *
3342 * Optimize for non-intersection by checking for box intersection first.
3343 * - thomas 1998-01-30
3344 */
3345static bool
3347{
3348 BOX lbox;
3349 LSEG bseg;
3350 Point point;
3351
3352 lbox.low.x = float8_min(lseg->p[0].x, lseg->p[1].x);
3353 lbox.low.y = float8_min(lseg->p[0].y, lseg->p[1].y);
3354 lbox.high.x = float8_max(lseg->p[0].x, lseg->p[1].x);
3355 lbox.high.y = float8_max(lseg->p[0].y, lseg->p[1].y);
3356
3357 /* nothing close to overlap? then not going to intersect */
3358 if (!box_ov(&lbox, box))
3359 return false;
3360
3361 if (result != NULL)
3362 {
3363 box_cn(&point, box, NULL);
3365 }
3366
3367 /* an endpoint of segment is inside box? then clearly intersects */
3368 if (box_contain_point(box, &lseg->p[0]) ||
3369 box_contain_point(box, &lseg->p[1]))
3370 return true;
3371
3372 /* pairwise check lseg intersections */
3373 point.x = box->low.x;
3374 point.y = box->high.y;
3375 statlseg_construct(&bseg, &box->low, &point);
3377 return true;
3378
3379 statlseg_construct(&bseg, &box->high, &point);
3381 return true;
3382
3383 point.x = box->high.x;
3384 point.y = box->low.y;
3385 statlseg_construct(&bseg, &box->low, &point);
3387 return true;
3388
3389 statlseg_construct(&bseg, &box->high, &point);
3391 return true;
3392
3393 /* if we dropped through, no two segs intersected */
3394 return false;
3395}
3396
3397Datum
3405
3406
3407/*
3408 * inter_lb()
3409 * Do line and box intersect?
3410 */
3411Datum
3413{
3414 LINE *line = PG_GETARG_LINE_P(0);
3415 BOX *box = PG_GETARG_BOX_P(1);
3416 LSEG bseg;
3417 Point p1,
3418 p2;
3419
3420 /* pairwise check lseg intersections */
3421 p1.x = box->low.x;
3422 p1.y = box->low.y;
3423 p2.x = box->low.x;
3424 p2.y = box->high.y;
3426 if (lseg_interpt_line(NULL, &bseg, line))
3427 PG_RETURN_BOOL(true);
3428 p1.x = box->high.x;
3429 p1.y = box->high.y;
3431 if (lseg_interpt_line(NULL, &bseg, line))
3432 PG_RETURN_BOOL(true);
3433 p2.x = box->high.x;
3434 p2.y = box->low.y;
3436 if (lseg_interpt_line(NULL, &bseg, line))
3437 PG_RETURN_BOOL(true);
3438 p1.x = box->low.x;
3439 p1.y = box->low.y;
3441 if (lseg_interpt_line(NULL, &bseg, line))
3442 PG_RETURN_BOOL(true);
3443
3444 /* if we dropped through, no intersection */
3445 PG_RETURN_BOOL(false);
3446}
3447
3448/*------------------------------------------------------------------
3449 * The following routines define a data type and operator class for
3450 * POLYGONS .... Part of which (the polygon's bounding box) is built on
3451 * top of the BOX data type.
3452 *
3453 * make_bound_box - create the bounding box for the input polygon
3454 *------------------------------------------------------------------*/
3455
3456/*---------------------------------------------------------------------
3457 * Make the smallest bounding box for the given polygon.
3458 *---------------------------------------------------------------------*/
3459static void
3461{
3462 int i;
3463 float8 x1,
3464 y1,
3465 x2,
3466 y2;
3467
3468 Assert(poly->npts > 0);
3469
3470 x1 = x2 = poly->p[0].x;
3471 y2 = y1 = poly->p[0].y;
3472 for (i = 1; i < poly->npts; i++)
3473 {
3474 if (float8_lt(poly->p[i].x, x1))
3475 x1 = poly->p[i].x;
3476 if (float8_gt(poly->p[i].x, x2))
3477 x2 = poly->p[i].x;
3478 if (float8_lt(poly->p[i].y, y1))
3479 y1 = poly->p[i].y;
3480 if (float8_gt(poly->p[i].y, y2))
3481 y2 = poly->p[i].y;
3482 }
3483
3484 poly->boundbox.low.x = x1;
3485 poly->boundbox.high.x = x2;
3486 poly->boundbox.low.y = y1;
3487 poly->boundbox.high.y = y2;
3488}
3489
3490/*------------------------------------------------------------------
3491 * poly_in - read in the polygon from a string specification
3492 *
3493 * External format:
3494 * "((x0,y0),...,(xn,yn))"
3495 * "x0,y0,...,xn,yn"
3496 * also supports the older style "(x1,...,xn,y1,...yn)"
3497 *------------------------------------------------------------------*/
3498Datum
3500{
3501 char *str = PG_GETARG_CSTRING(0);
3502 Node *escontext = fcinfo->context;
3503 POLYGON *poly;
3504 int npts;
3505 int size;
3506 int base_size;
3507 bool isopen;
3508
3509 if ((npts = pair_count(str, ',')) <= 0)
3510 ereturn(escontext, (Datum) 0,
3512 errmsg("invalid input syntax for type %s: \"%s\"",
3513 "polygon", str)));
3514
3515 base_size = sizeof(poly->p[0]) * npts;
3516 size = offsetof(POLYGON, p) + base_size;
3517
3518 /* Check for integer overflow */
3519 if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
3520 ereturn(escontext, (Datum) 0,
3522 errmsg("too many points requested")));
3523
3524 poly = (POLYGON *) palloc0(size); /* zero any holes */
3525
3526 SET_VARSIZE(poly, size);
3527 poly->npts = npts;
3528
3529 if (!path_decode(str, false, npts, &(poly->p[0]), &isopen, NULL, "polygon",
3530 str, escontext))
3532
3534
3536}
3537
3538/*---------------------------------------------------------------
3539 * poly_out - convert internal POLYGON representation to the
3540 * character string format "((f8,f8),...,(f8,f8))"
3541 *---------------------------------------------------------------*/
3542Datum
3549
3550/*
3551 * poly_recv - converts external binary format to polygon
3552 *
3553 * External representation is int32 number of points, and the points.
3554 * We recompute the bounding box on read, instead of trusting it to
3555 * be valid. (Checking it would take just as long, so may as well
3556 * omit it from external representation.)
3557 */
3558Datum
3560{
3562 POLYGON *poly;
3563 int32 npts;
3564 int32 i;
3565 int size;
3566
3567 npts = pq_getmsgint(buf, sizeof(int32));
3568 if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(POLYGON, p)) / sizeof(Point)))
3569 ereport(ERROR,
3571 errmsg("invalid number of points in external \"polygon\" value")));
3572
3573 size = offsetof(POLYGON, p) + sizeof(poly->p[0]) * npts;
3574 poly = (POLYGON *) palloc0(size); /* zero any holes */
3575
3576 SET_VARSIZE(poly, size);
3577 poly->npts = npts;
3578
3579 for (i = 0; i < npts; i++)
3580 {
3581 poly->p[i].x = pq_getmsgfloat8(buf);
3582 poly->p[i].y = pq_getmsgfloat8(buf);
3583 }
3584
3586
3588}
3589
3590/*
3591 * poly_send - converts polygon to binary format
3592 */
3593Datum
3595{
3598 int32 i;
3599
3601 pq_sendint32(&buf, poly->npts);
3602 for (i = 0; i < poly->npts; i++)
3603 {
3604 pq_sendfloat8(&buf, poly->p[i].x);
3605 pq_sendfloat8(&buf, poly->p[i].y);
3606 }
3608}
3609
3610
3611/*-------------------------------------------------------
3612 * Is polygon A strictly left of polygon B? i.e. is
3613 * the right most point of A left of the left most point
3614 * of B?
3615 *-------------------------------------------------------*/
3616Datum
3618{
3621 bool result;
3622
3623 result = polya->boundbox.high.x < polyb->boundbox.low.x;
3624
3625 /*
3626 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3627 */
3630
3632}
3633
3634/*-------------------------------------------------------
3635 * Is polygon A overlapping or left of polygon B? i.e. is
3636 * the right most point of A at or left of the right most point
3637 * of B?
3638 *-------------------------------------------------------*/
3639Datum
3641{
3644 bool result;
3645
3646 result = polya->boundbox.high.x <= polyb->boundbox.high.x;
3647
3648 /*
3649 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3650 */
3653
3655}
3656
3657/*-------------------------------------------------------
3658 * Is polygon A strictly right of polygon B? i.e. is
3659 * the left most point of A right of the right most point
3660 * of B?
3661 *-------------------------------------------------------*/
3662Datum
3664{
3667 bool result;
3668
3669 result = polya->boundbox.low.x > polyb->boundbox.high.x;
3670
3671 /*
3672 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3673 */
3676
3678}
3679
3680/*-------------------------------------------------------
3681 * Is polygon A overlapping or right of polygon B? i.e. is
3682 * the left most point of A at or right of the left most point
3683 * of B?
3684 *-------------------------------------------------------*/
3685Datum
3687{
3690 bool result;
3691
3692 result = polya->boundbox.low.x >= polyb->boundbox.low.x;
3693
3694 /*
3695 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3696 */
3699
3701}
3702
3703/*-------------------------------------------------------
3704 * Is polygon A strictly below polygon B? i.e. is
3705 * the upper most point of A below the lower most point
3706 * of B?
3707 *-------------------------------------------------------*/
3708Datum
3710{
3713 bool result;
3714
3715 result = polya->boundbox.high.y < polyb->boundbox.low.y;
3716
3717 /*
3718 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3719 */
3722
3724}
3725
3726/*-------------------------------------------------------
3727 * Is polygon A overlapping or below polygon B? i.e. is
3728 * the upper most point of A at or below the upper most point
3729 * of B?
3730 *-------------------------------------------------------*/
3731Datum
3733{
3736 bool result;
3737
3738 result = polya->boundbox.high.y <= polyb->boundbox.high.y;
3739
3740 /*
3741 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3742 */
3745
3747}
3748
3749/*-------------------------------------------------------
3750 * Is polygon A strictly above polygon B? i.e. is
3751 * the lower most point of A above the upper most point
3752 * of B?
3753 *-------------------------------------------------------*/
3754Datum
3756{
3759 bool result;
3760
3761 result = polya->boundbox.low.y > polyb->boundbox.high.y;
3762
3763 /*
3764 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3765 */
3768
3770}
3771
3772/*-------------------------------------------------------
3773 * Is polygon A overlapping or above polygon B? i.e. is
3774 * the lower most point of A at or above the lower most point
3775 * of B?
3776 *-------------------------------------------------------*/
3777Datum
3779{
3782 bool result;
3783
3784 result = polya->boundbox.low.y >= polyb->boundbox.low.y;
3785
3786 /*
3787 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3788 */
3791
3793}
3794
3795
3796/*-------------------------------------------------------
3797 * Is polygon A the same as polygon B? i.e. are all the
3798 * points the same?
3799 * Check all points for matches in both forward and reverse
3800 * direction since polygons are non-directional and are
3801 * closed shapes.
3802 *-------------------------------------------------------*/
3803Datum
3805{
3808 bool result;
3809
3810 if (polya->npts != polyb->npts)
3811 result = false;
3812 else
3813 result = plist_same(polya->npts, polya->p, polyb->p);
3814
3815 /*
3816 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3817 */
3820
3822}
3823
3824/*-----------------------------------------------------------------
3825 * Determine if polygon A overlaps polygon B
3826 *-----------------------------------------------------------------*/
3827static bool
3829{
3830 bool result;
3831
3832 Assert(polya->npts > 0 && polyb->npts > 0);
3833
3834 /* Quick check by bounding box */
3835 result = box_ov(&polya->boundbox, &polyb->boundbox);
3836
3837 /*
3838 * Brute-force algorithm - try to find intersected edges, if so then
3839 * polygons are overlapped else check is one polygon inside other or not
3840 * by testing single point of them.
3841 */
3842 if (result)
3843 {
3844 int ia,
3845 ib;
3846 LSEG sa,
3847 sb;
3848
3849 /* Init first of polya's edge with last point */
3850 sa.p[0] = polya->p[polya->npts - 1];
3851 result = false;
3852
3853 for (ia = 0; ia < polya->npts && !result; ia++)
3854 {
3855 /* Second point of polya's edge is a current one */
3856 sa.p[1] = polya->p[ia];
3857
3858 /* Init first of polyb's edge with last point */
3859 sb.p[0] = polyb->p[polyb->npts - 1];
3860
3861 for (ib = 0; ib < polyb->npts && !result; ib++)
3862 {
3863 sb.p[1] = polyb->p[ib];
3865 sb.p[0] = sb.p[1];
3866 }
3867
3868 /*
3869 * move current endpoint to the first point of next edge
3870 */
3871 sa.p[0] = sa.p[1];
3872 }
3873
3874 if (!result)
3875 {
3876 result = (point_inside(polya->p, polyb->npts, polyb->p) ||
3877 point_inside(polyb->p, polya->npts, polya->p));
3878 }
3879 }
3880
3881 return result;
3882}
3883
3884Datum
3886{
3889 bool result;
3890
3892
3893 /*
3894 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3895 */
3898
3900}
3901
3902/*
3903 * Tests special kind of segment for in/out of polygon.
3904 * Special kind means:
3905 * - point a should be on segment s
3906 * - segment (a,b) should not be contained by s
3907 * Returns true if:
3908 * - segment (a,b) is collinear to s and (a,b) is in polygon
3909 * - segment (a,b) s not collinear to s. Note: that doesn't
3910 * mean that segment is in polygon!
3911 */
3912
3913static bool
3915{
3916 /* point a is on s, b is not */
3917 LSEG t;
3918
3919 t.p[0] = *a;
3920 t.p[1] = *b;
3921
3922 if (point_eq_point(a, s->p))
3923 {
3924 if (lseg_contain_point(&t, s->p + 1))
3925 return lseg_inside_poly(b, s->p + 1, poly, start);
3926 }
3927 else if (point_eq_point(a, s->p + 1))
3928 {
3929 if (lseg_contain_point(&t, s->p))
3930 return lseg_inside_poly(b, s->p, poly, start);
3931 }
3932 else if (lseg_contain_point(&t, s->p))
3933 {
3934 return lseg_inside_poly(b, s->p, poly, start);
3935 }
3936 else if (lseg_contain_point(&t, s->p + 1))
3937 {
3938 return lseg_inside_poly(b, s->p + 1, poly, start);
3939 }
3940
3941 return true; /* may be not true, but that will check later */
3942}
3943
3944/*
3945 * Returns true if segment (a,b) is in polygon, option
3946 * start is used for optimization - function checks
3947 * polygon's edges starting from start
3948 */
3949static bool
3951{
3952 LSEG s,
3953 t;
3954 int i;
3955 bool res = true,
3956 intersection = false;
3957
3958 /* since this function recurses, it could be driven to stack overflow */
3960
3961 t.p[0] = *a;
3962 t.p[1] = *b;
3963 s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
3964
3965 for (i = start; i < poly->npts && res; i++)
3966 {
3967 Point interpt;
3968
3970
3971 s.p[1] = poly->p[i];
3972
3973 if (lseg_contain_point(&s, t.p))
3974 {
3975 if (lseg_contain_point(&s, t.p + 1))
3976 return true; /* t is contained by s */
3977
3978 /* Y-cross */
3979 res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
3980 }
3981 else if (lseg_contain_point(&s, t.p + 1))
3982 {
3983 /* Y-cross */
3984 res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
3985 }
3986 else if (lseg_interpt_lseg(&interpt, &t, &s))
3987 {
3988 /*
3989 * segments are X-crossing, go to check each subsegment
3990 */
3991
3992 intersection = true;
3993 res = lseg_inside_poly(t.p, &interpt, poly, i + 1);
3994 if (res)
3995 res = lseg_inside_poly(t.p + 1, &interpt, poly, i + 1);
3996 }
3997
3998 s.p[0] = s.p[1];
3999 }
4000
4001 if (res && !intersection)
4002 {
4003 Point p;
4004
4005 /*
4006 * if X-intersection wasn't found, then check central point of tested
4007 * segment. In opposite case we already check all subsegments
4008 */
4009 p.x = float8_div(float8_pl(t.p[0].x, t.p[1].x), 2.0);
4010 p.y = float8_div(float8_pl(t.p[0].y, t.p[1].y), 2.0);
4011
4012 res = point_inside(&p, poly->npts, poly->p);
4013 }
4014
4015 return res;
4016}
4017
4018/*
4019 * Check whether the first polygon contains the second
4020 */
4021static bool
4023{
4024 int i;
4025 LSEG s;
4026
4027 Assert(contains_poly->npts > 0 && contained_poly->npts > 0);
4028
4029 /*
4030 * Quick check to see if contained's bounding box is contained in
4031 * contains' bb.
4032 */
4033 if (!box_contain_box(&contains_poly->boundbox, &contained_poly->boundbox))
4034 return false;
4035
4036 s.p[0] = contained_poly->p[contained_poly->npts - 1];
4037
4038 for (i = 0; i < contained_poly->npts; i++)
4039 {
4040 s.p[1] = contained_poly->p[i];
4041 if (!lseg_inside_poly(s.p, s.p + 1, contains_poly, 0))
4042 return false;
4043 s.p[0] = s.p[1];
4044 }
4045
4046 return true;
4047}
4048
4049Datum
4051{
4054 bool result;
4055
4057
4058 /*
4059 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
4060 */
4063
4065}
4066
4067
4068/*-----------------------------------------------------------------
4069 * Determine if polygon A is contained by polygon B
4070 *-----------------------------------------------------------------*/
4071Datum
4073{
4076 bool result;
4077
4078 /* Just switch the arguments and pass it off to poly_contain */
4080
4081 /*
4082 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
4083 */
4086
4088}
4089
4090
4091Datum
4099
4100Datum
4108
4109
4110Datum
4112{
4115 float8 min = 0.0; /* initialize to keep compiler quiet */
4116 bool have_min = false;
4117 float8 tmp;
4118 int i,
4119 j;
4120 LSEG seg1,
4121 seg2;
4122
4123 /*
4124 * Distance is zero if polygons overlap. We must check this because the
4125 * path distance will not give the right answer if one poly is entirely
4126 * within the other.
4127 */
4129 PG_RETURN_FLOAT8(0.0);
4130
4131 /*
4132 * When they don't overlap, the distance calculation is identical to that
4133 * for closed paths (i.e., we needn't care about the fact that polygons
4134 * include their contained areas). See path_distance().
4135 */
4136 for (i = 0; i < polya->npts; i++)
4137 {
4138 int iprev;
4139
4140 if (i > 0)
4141 iprev = i - 1;
4142 else
4143 iprev = polya->npts - 1;
4144
4145 for (j = 0; j < polyb->npts; j++)
4146 {
4147 int jprev;
4148
4149 if (j > 0)
4150 jprev = j - 1;
4151 else
4152 jprev = polyb->npts - 1;
4153
4154 statlseg_construct(&seg1, &polya->p[iprev], &polya->p[i]);
4155 statlseg_construct(&seg2, &polyb->p[jprev], &polyb->p[j]);
4156
4157 tmp = lseg_closept_lseg(NULL, &seg1, &seg2);
4158 if (!have_min || float8_lt(tmp, min))
4159 {
4160 min = tmp;
4161 have_min = true;
4162 }
4163 }
4164 }
4165
4166 if (!have_min)
4168
4169 PG_RETURN_FLOAT8(min);
4170}
4171
4172
4173/***********************************************************************
4174 **
4175 ** Routines for 2D points.
4176 **
4177 ***********************************************************************/
4178
4179Datum
4192
4193
4194static inline void
4196{
4197 float8 x;
4198 float8 y;
4199
4200 x = float8_pl_safe(pt1->x, pt2->x, escontext);
4201 if (SOFT_ERROR_OCCURRED(escontext))
4202 return;
4203
4204 y = float8_pl_safe(pt1->y, pt2->y, escontext);
4205 if (SOFT_ERROR_OCCURRED(escontext))
4206 return;
4207
4209}
4210
4211Datum
4224
4225
4226static inline void
4228{
4230 float8_mi(pt1->x, pt2->x),
4231 float8_mi(pt1->y, pt2->y));
4232}
4233
4234Datum
4247
4248
4249static inline void
4251{
4253 float8_mi(float8_mul(pt1->x, pt2->x),
4254 float8_mul(pt1->y, pt2->y)),
4255 float8_pl(float8_mul(pt1->x, pt2->y),
4256 float8_mul(pt1->y, pt2->x)));
4257}
4258
4259Datum
4272
4273
4274static inline void
4276{
4277 float8 div;
4278
4279 div = float8_pl(float8_mul(pt2->x, pt2->x), float8_mul(pt2->y, pt2->y));
4280
4283 float8_mul(pt1->y, pt2->y)), div),
4285 float8_mul(pt1->x, pt2->y)), div));
4286}
4287
4288Datum
4301
4302
4303/***********************************************************************
4304 **
4305 ** Routines for 2D boxes.
4306 **
4307 ***********************************************************************/
4308
4309Datum
4311{
4314 BOX *result;
4315
4317
4319
4321}
4322
4323Datum
4325{
4326 BOX *box = PG_GETARG_BOX_P(0);
4327 Point *p = PG_GETARG_POINT_P(1);
4328 BOX *result;
4329
4331
4332 point_add_point(&result->high, &box->high, p, NULL);
4333 point_add_point(&result->low, &box->low, p, NULL);
4334
4336}
4337
4338Datum
4340{
4341 BOX *box = PG_GETARG_BOX_P(0);
4342 Point *p = PG_GETARG_POINT_P(1);
4343 BOX *result;
4344
4346
4347 point_sub_point(&result->high, &box->high, p);
4348 point_sub_point(&result->low, &box->low, p);
4349
4351}
4352
4353Datum
4355{
4356 BOX *box = PG_GETARG_BOX_P(0);
4357 Point *p = PG_GETARG_POINT_P(1);
4358 BOX *result;
4359 Point high,
4360 low;
4361
4363
4364 point_mul_point(&high, &box->high, p);
4365 point_mul_point(&low, &box->low, p);
4366
4367 box_construct(result, &high, &low);
4368
4370}
4371
4372Datum
4374{
4375 BOX *box = PG_GETARG_BOX_P(0);
4376 Point *p = PG_GETARG_POINT_P(1);
4377 BOX *result;
4378 Point high,
4379 low;
4380
4382
4383 point_div_point(&high, &box->high, p);
4384 point_div_point(&low, &box->low, p);
4385
4386 box_construct(result, &high, &low);
4387
4389}
4390
4391/*
4392 * Convert point to empty box
4393 */
4394Datum
4396{
4398 BOX *box;
4399
4401
4402 box->high.x = pt->x;
4403 box->low.x = pt->x;
4404 box->high.y = pt->y;
4405 box->low.y = pt->y;
4406
4408}
4409
4410/*
4411 * Smallest bounding box that includes both of the given boxes
4412 */
4413Datum
4415{
4416 BOX *box1 = PG_GETARG_BOX_P(0),
4417 *box2 = PG_GETARG_BOX_P(1),
4418 *container;
4419
4420 container = palloc_object(BOX);
4421
4422 container->high.x = float8_max(box1->high.x, box2->high.x);
4423 container->low.x = float8_min(box1->low.x, box2->low.x);
4424 container->high.y = float8_max(box1->high.y, box2->high.y);
4425 container->low.y = float8_min(box1->low.y, box2->low.y);
4426
4427 PG_RETURN_BOX_P(container);
4428}
4429
4430
4431/***********************************************************************
4432 **
4433 ** Routines for 2D paths.
4434 **
4435 ***********************************************************************/
4436
4437/*
4438 * path_add()
4439 * Concatenate two paths (only if they are both open).
4440 */
4441Datum
4443{
4444 PATH *p1 = PG_GETARG_PATH_P(0);
4445 PATH *p2 = PG_GETARG_PATH_P(1);
4446 PATH *result;
4447 int size,
4448 base_size;
4449 int i;
4450
4451 if (p1->closed || p2->closed)
4453
4454 base_size = sizeof(p1->p[0]) * (p1->npts + p2->npts);
4455 size = offsetof(PATH, p) + base_size;
4456
4457 /* Check for integer overflow */
4458 if (base_size / sizeof(p1->p[0]) != (p1->npts + p2->npts) ||
4459 size <= base_size)
4460 ereport(ERROR,
4462 errmsg("too many points requested")));
4463
4464 result = (PATH *) palloc(size);
4465
4466 SET_VARSIZE(result, size);
4467 result->npts = (p1->npts + p2->npts);
4468 result->closed = p1->closed;
4469 /* prevent instability in unused pad bytes */
4470 result->dummy = 0;
4471
4472 for (i = 0; i < p1->npts; i++)
4473 {
4474 result->p[i].x = p1->p[i].x;
4475 result->p[i].y = p1->p[i].y;
4476 }
4477 for (i = 0; i < p2->npts; i++)
4478 {
4479 result->p[i + p1->npts].x = p2->p[i].x;
4480 result->p[i + p1->npts].y = p2->p[i].y;
4481 }
4482
4484}
4485
4486/*
4487 * path_add_pt()
4488 * Translation operators.
4489 */
4490Datum
4492{
4493 PATH *path = PG_GETARG_PATH_P_COPY(0);
4495 int i;
4496
4497 for (i = 0; i < path->npts; i++)
4498 point_add_point(&path->p[i], &path->p[i], point, NULL);
4499
4500 PG_RETURN_PATH_P(path);
4501}
4502
4503Datum
4505{
4506 PATH *path = PG_GETARG_PATH_P_COPY(0);
4508 int i;
4509
4510 for (i = 0; i < path->npts; i++)
4511 point_sub_point(&path->p[i], &path->p[i], point);
4512
4513 PG_RETURN_PATH_P(path);
4514}
4515
4516/*
4517 * path_mul_pt()
4518 * Rotation and scaling operators.
4519 */
4520Datum
4522{
4523 PATH *path = PG_GETARG_PATH_P_COPY(0);
4525 int i;
4526
4527 for (i = 0; i < path->npts; i++)
4528 point_mul_point(&path->p[i], &path->p[i], point);
4529
4530 PG_RETURN_PATH_P(path);
4531}
4532
4533Datum
4535{
4536 PATH *path = PG_GETARG_PATH_P_COPY(0);
4538 int i;
4539
4540 for (i = 0; i < path->npts; i++)
4541 point_div_point(&path->p[i], &path->p[i], point);
4542
4543 PG_RETURN_PATH_P(path);
4544}
4545
4546
4547Datum
4549{
4550 PATH *path = PG_GETARG_PATH_P(0);
4551 POLYGON *poly;
4552 int size;
4553 int i;
4554
4555 /* This is not very consistent --- other similar cases return NULL ... */
4556 if (!path->closed)
4557 ereturn(fcinfo->context, (Datum) 0,
4559 errmsg("open path cannot be converted to polygon")));
4560
4561 /*
4562 * Never overflows: the old size fit in MaxAllocSize, and the new size is
4563 * just a small constant larger.
4564 */
4565 size = offsetof(POLYGON, p) + sizeof(poly->p[0]) * path->npts;
4566 poly = (POLYGON *) palloc(size);
4567
4568 SET_VARSIZE(poly, size);
4569 poly->npts = path->npts;
4570
4571 for (i = 0; i < path->npts; i++)
4572 {
4573 poly->p[i].x = path->p[i].x;
4574 poly->p[i].y = path->p[i].y;
4575 }
4576
4578
4580}
4581
4582
4583/***********************************************************************
4584 **
4585 ** Routines for 2D polygons.
4586 **
4587 ***********************************************************************/
4588
4589Datum
4596
4597
4598Datum
4600{
4602 Point *result;
4603 CIRCLE circle;
4604
4606
4607 poly_to_circle(&circle, poly, fcinfo->context);
4608 if (SOFT_ERROR_OCCURRED(fcinfo->context))
4610
4611 *result = circle.center;
4612
4614}
4615
4616
4617Datum
4619{
4621 BOX *box;
4622
4624 *box = poly->boundbox;
4625
4627}
4628
4629
4630/*
4631 * box_poly()
4632 * Convert a box to a polygon.
4633 */
4634Datum
4636{
4637 BOX *box = PG_GETARG_BOX_P(0);
4638 POLYGON *poly;
4639 int size;
4640
4641 /* map four corners of the box to a polygon */
4642 size = offsetof(POLYGON, p) + sizeof(poly->p[0]) * 4;
4643 poly = (POLYGON *) palloc(size);
4644
4645 SET_VARSIZE(poly, size);
4646 poly->npts = 4;
4647
4648 poly->p[0].x = box->low.x;
4649 poly->p[0].y = box->low.y;
4650 poly->p[1].x = box->low.x;
4651 poly->p[1].y = box->high.y;
4652 poly->p[2].x = box->high.x;
4653 poly->p[2].y = box->high.y;
4654 poly->p[3].x = box->high.x;
4655 poly->p[3].y = box->low.y;
4656
4657 box_construct(&poly->boundbox, &box->high, &box->low);
4658
4660}
4661
4662
4663Datum
4665{
4667 PATH *path;
4668 int size;
4669 int i;
4670
4671 /*
4672 * Never overflows: the old size fit in MaxAllocSize, and the new size is
4673 * smaller by a small constant.
4674 */
4675 size = offsetof(PATH, p) + sizeof(path->p[0]) * poly->npts;
4676 path = (PATH *) palloc(size);
4677
4678 SET_VARSIZE(path, size);
4679 path->npts = poly->npts;
4680 path->closed = true;
4681 /* prevent instability in unused pad bytes */
4682 path->dummy = 0;
4683
4684 for (i = 0; i < poly->npts; i++)
4685 {
4686 path->p[i].x = poly->p[i].x;
4687 path->p[i].y = poly->p[i].y;
4688 }
4689
4690 PG_RETURN_PATH_P(path);
4691}
4692
4693
4694/***********************************************************************
4695 **
4696 ** Routines for circles.
4697 **
4698 ***********************************************************************/
4699
4700/*----------------------------------------------------------
4701 * Formatting and conversion routines.
4702 *---------------------------------------------------------*/
4703
4704/*
4705 * circle_in - convert a string to internal form.
4706 *
4707 * External format: (center and radius of circle)
4708 * "<(f8,f8),f8>"
4709 * also supports quick entry style "f8,f8,f8"
4710 */
4711Datum
4713{
4714 char *str = PG_GETARG_CSTRING(0);
4715 Node *escontext = fcinfo->context;
4717 char *s,
4718 *cp;
4719 int depth = 0;
4720
4721 s = str;
4722 while (isspace((unsigned char) *s))
4723 s++;
4724 if (*s == LDELIM_C)
4725 depth++, s++;
4726 else if (*s == LDELIM)
4727 {
4728 /* If there are two left parens, consume the first one */
4729 cp = (s + 1);
4730 while (isspace((unsigned char) *cp))
4731 cp++;
4732 if (*cp == LDELIM)
4733 depth++, s = cp;
4734 }
4735
4736 /* pair_decode will consume parens around the pair, if any */
4737 if (!pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str,
4738 escontext))
4740
4741 if (*s == DELIM)
4742 s++;
4743
4744 if (!single_decode(s, &circle->radius, &s, "circle", str, escontext))
4746
4747 /* We have to accept NaN. */
4748 if (circle->radius < 0.0)
4749 ereturn(escontext, (Datum) 0,
4751 errmsg("invalid input syntax for type %s: \"%s\"",
4752 "circle", str)));
4753
4754 while (depth > 0)
4755 {
4756 if ((*s == RDELIM) || ((*s == RDELIM_C) && (depth == 1)))
4757 {
4758 depth--;
4759 s++;
4760 while (isspace((unsigned char) *s))
4761 s++;
4762 }
4763 else
4764 ereturn(escontext, (Datum) 0,
4766 errmsg("invalid input syntax for type %s: \"%s\"",
4767 "circle", str)));
4768 }
4769
4770 if (*s != '\0')
4771 ereturn(escontext, (Datum) 0,
4773 errmsg("invalid input syntax for type %s: \"%s\"",
4774 "circle", str)));
4775
4777}
4778
4779/*
4780 * circle_out - convert a circle to external form.
4781 */
4782Datum
4800
4801/*
4802 * circle_recv - converts external binary format to circle
4803 */
4804Datum
4806{
4808 CIRCLE *circle;
4809
4811
4812 circle->center.x = pq_getmsgfloat8(buf);
4813 circle->center.y = pq_getmsgfloat8(buf);
4814 circle->radius = pq_getmsgfloat8(buf);
4815
4816 /* We have to accept NaN. */
4817 if (circle->radius < 0.0)
4818 ereport(ERROR,
4820 errmsg("invalid radius in external \"circle\" value")));
4821
4823}
4824
4825/*
4826 * circle_send - converts circle to binary format
4827 */
4828Datum
4840
4841
4842/*----------------------------------------------------------
4843 * Relational operators for CIRCLEs.
4844 * <, >, <=, >=, and == are based on circle area.
4845 *---------------------------------------------------------*/
4846
4847/*
4848 * circles identical?
4849 *
4850 * We consider NaNs values to be equal to each other to let those circles
4851 * to be found.
4852 */
4853Datum
4855{
4858
4859 PG_RETURN_BOOL(((isnan(circle1->radius) && isnan(circle2->radius)) ||
4860 FPeq(circle1->radius, circle2->radius)) &&
4861 point_eq_point(&circle1->center, &circle2->center));
4862}
4863
4864/*
4865 * circle_overlap - does circle1 overlap circle2?
4866 */
4867Datum
4869{
4872
4873 PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center, NULL),
4874 float8_pl(circle1->radius, circle2->radius)));
4875}
4876
4877/*
4878 * circle_overleft - is the right edge of circle1 at or left of
4879 * the right edge of circle2?
4880 */
4881Datum
4883{
4886
4887 PG_RETURN_BOOL(FPle(float8_pl(circle1->center.x, circle1->radius),
4888 float8_pl(circle2->center.x, circle2->radius)));
4889}
4890
4891/*
4892 * circle_left - is circle1 strictly left of circle2?
4893 */
4894Datum
4896{
4899
4900 PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.x, circle1->radius),
4901 float8_mi(circle2->center.x, circle2->radius)));
4902}
4903
4904/*
4905 * circle_right - is circle1 strictly right of circle2?
4906 */
4907Datum
4909{
4912
4913 PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.x, circle1->radius),
4914 float8_pl(circle2->center.x, circle2->radius)));
4915}
4916
4917/*
4918 * circle_overright - is the left edge of circle1 at or right of
4919 * the left edge of circle2?
4920 */
4921Datum
4923{
4926
4927 PG_RETURN_BOOL(FPge(float8_mi(circle1->center.x, circle1->radius),
4928 float8_mi(circle2->center.x, circle2->radius)));
4929}
4930
4931/*
4932 * circle_contained - is circle1 contained by circle2?
4933 */
4934Datum
4936{
4939
4940 PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center, NULL),
4941 float8_mi(circle2->radius, circle1->radius)));
4942}
4943
4944/*
4945 * circle_contain - does circle1 contain circle2?
4946 */
4947Datum
4949{
4952
4953 PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center, NULL),
4954 float8_mi(circle1->radius, circle2->radius)));
4955}
4956
4957
4958/*
4959 * circle_below - is circle1 strictly below circle2?
4960 */
4961Datum
4963{
4966
4967 PG_RETURN_BOOL(FPlt(float8_pl(circle1->center.y, circle1->radius),
4968 float8_mi(circle2->center.y, circle2->radius)));
4969}
4970
4971/*
4972 * circle_above - is circle1 strictly above circle2?
4973 */
4974Datum
4976{
4979
4980 PG_RETURN_BOOL(FPgt(float8_mi(circle1->center.y, circle1->radius),
4981 float8_pl(circle2->center.y, circle2->radius)));
4982}
4983
4984/*
4985 * circle_overbelow - is the upper edge of circle1 at or below
4986 * the upper edge of circle2?
4987 */
4988Datum
4990{
4993
4994 PG_RETURN_BOOL(FPle(float8_pl(circle1->center.y, circle1->radius),
4995 float8_pl(circle2->center.y, circle2->radius)));
4996}
4997
4998/*
4999 * circle_overabove - is the lower edge of circle1 at or above
5000 * the lower edge of circle2?
5001 */
5002Datum
5004{
5007
5008 PG_RETURN_BOOL(FPge(float8_mi(circle1->center.y, circle1->radius),
5009 float8_mi(circle2->center.y, circle2->radius)));
5010}
5011
5012
5013/*
5014 * circle_relop - is area(circle1) relop area(circle2), within
5015 * our accuracy constraint?
5016 */
5017Datum
5025
5026Datum
5034
5035Datum
5043
5044Datum
5052
5053Datum
5061
5062Datum
5070
5071
5072/*----------------------------------------------------------
5073 * "Arithmetic" operators on circles.
5074 *---------------------------------------------------------*/
5075
5076/*
5077 * circle_add_pt()
5078 * Translation operator.
5079 */
5080Datum
5082{
5085 CIRCLE *result;
5086
5088
5089 point_add_point(&result->center, &circle->center, point, NULL);
5090 result->radius = circle->radius;
5091
5093}
5094
5095Datum
5097{
5100 CIRCLE *result;
5101
5103
5104 point_sub_point(&result->center, &circle->center, point);
5105 result->radius = circle->radius;
5106
5108}
5109
5110
5111/*
5112 * circle_mul_pt()
5113 * Rotation and scaling operators.
5114 */
5115Datum
5117{
5120 CIRCLE *result;
5121
5123
5124 point_mul_point(&result->center, &circle->center, point);
5125 result->radius = float8_mul(circle->radius, hypot(point->x, point->y));
5126
5128}
5129
5130Datum
5132{
5135 CIRCLE *result;
5136
5138
5139 point_div_point(&result->center, &circle->center, point);
5140 result->radius = float8_div(circle->radius, hypot(point->x, point->y));
5141
5143}
5144
5145
5146/*
5147 * circle_area - returns the area of the circle.
5148 */
5149Datum
5156
5157
5158/*
5159 * circle_diameter - returns the diameter of the circle.
5160 */
5161Datum
5168
5169
5170/*
5171 * circle_radius - returns the radius of the circle.
5172 */
5173Datum
5180
5181
5182/*
5183 * circle_distance - returns the distance between
5184 * two circles.
5185 */
5186Datum
5188{
5191 float8 result;
5192
5193 result = float8_mi(point_dt(&circle1->center, &circle2->center, NULL),
5194 float8_pl(circle1->radius, circle2->radius));
5195 if (result < 0.0)
5196 result = 0.0;
5197
5199}
5200
5201
5202Datum
5212
5213
5214Datum
5224
5225
5226/*
5227 * dist_pc - returns the distance between
5228 * a point and a circle.
5229 */
5230Datum
5232{
5235 float8 result;
5236
5237 result = float8_mi(point_dt(point, &circle->center, NULL),
5238 circle->radius);
5239 if (result < 0.0)
5240 result = 0.0;
5241
5243}
5244
5245/*
5246 * Distance from a circle to a point
5247 */
5248Datum
5250{
5253 float8 result;
5254
5255 result = float8_mi(point_dt(point, &circle->center, NULL), circle->radius);
5256 if (result < 0.0)
5257 result = 0.0;
5258
5260}
5261
5262/*
5263 * circle_center - returns the center point of the circle.
5264 */
5265Datum
5267{
5269 Point *result;
5270
5272 result->x = circle->center.x;
5273 result->y = circle->center.y;
5274
5276}
5277
5278
5279/*
5280 * circle_ar - returns the area of the circle.
5281 */
5282static float8
5284{
5285 return float8_mul(float8_mul(circle->radius, circle->radius), M_PI);
5286}
5287
5288
5289/*----------------------------------------------------------
5290 * Conversion operators.
5291 *---------------------------------------------------------*/
5292
5293Datum
5295{
5296 Point *center = PG_GETARG_POINT_P(0);
5297 float8 radius = PG_GETARG_FLOAT8(1);
5298 CIRCLE *result;
5299
5301
5302 result->center.x = center->x;
5303 result->center.y = center->y;
5304 result->radius = radius;
5305
5307}
5308
5309Datum
5311{
5313 BOX *box;
5314 float8 delta;
5315
5317
5318 delta = float8_div_safe(circle->radius, sqrt(2.0), fcinfo->context);
5319 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5320 goto fail;
5321
5322 box->high.x = float8_pl_safe(circle->center.x, delta, fcinfo->context);
5323 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5324 goto fail;
5325
5326 box->low.x = float8_mi_safe(circle->center.x, delta, fcinfo->context);
5327 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5328 goto fail;
5329
5330 box->high.y = float8_pl_safe(circle->center.y, delta, fcinfo->context);
5331 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5332 goto fail;
5333
5334 box->low.y = float8_mi_safe(circle->center.y, delta, fcinfo->context);
5335 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5336 goto fail;
5337
5339
5340fail:
5342}
5343
5344/*
5345 * box_circle()
5346 * Convert a box to a circle.
5347 */
5348Datum
5350{
5351 BOX *box = PG_GETARG_BOX_P(0);
5352 CIRCLE *circle;
5353 float8 x;
5354 float8 y;
5355
5357
5358 x = float8_pl_safe(box->high.x, box->low.x, fcinfo->context);
5359 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5360 goto fail;
5361
5362 circle->center.x = float8_div_safe(x, 2.0, fcinfo->context);
5363 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5364 goto fail;
5365
5366 y = float8_pl_safe(box->high.y, box->low.y, fcinfo->context);
5367 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5368 goto fail;
5369
5370 circle->center.y = float8_div_safe(y, 2.0, fcinfo->context);
5371 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5372 goto fail;
5373
5374 circle->radius = point_dt(&circle->center, &box->high,
5375 fcinfo->context);
5376
5377 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5378 goto fail;
5379
5381
5382fail:
5384}
5385
5386
5387static POLYGON *
5389{
5390 POLYGON *poly;
5391 int base_size,
5392 size;
5393 int i;
5394 float8 angle;
5396
5397 if (FPzero(circle->radius))
5398 ereturn(fcinfo->context, NULL,
5400 errmsg("cannot convert circle with radius zero to polygon")));
5401
5402 if (npts < 2)
5403 ereturn(fcinfo->context, NULL,
5405 errmsg("must request at least 2 points")));
5406
5407 base_size = sizeof(poly->p[0]) * npts;
5408 size = offsetof(POLYGON, p) + base_size;
5409
5410 /* Check for integer overflow */
5411 if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
5412 ereturn(fcinfo->context, NULL,
5414 errmsg("too many points requested")));
5415
5416 poly = (POLYGON *) palloc0(size); /* zero any holes */
5417 SET_VARSIZE(poly, size);
5418 poly->npts = npts;
5419
5420 anglestep = float8_div(2.0 * M_PI, npts);
5421
5422 for (i = 0; i < npts; i++)
5423 {
5424 float8 temp;
5425
5427 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5428 return NULL;
5429
5430 temp = float8_mul_safe(circle->radius, cos(angle), fcinfo->context);
5431 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5432 return NULL;
5433
5434 poly->p[i].x = float8_mi_safe(circle->center.x, temp, fcinfo->context);
5435 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5436 return NULL;
5437
5438 temp = float8_mul_safe(circle->radius, sin(angle), fcinfo->context);
5439 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5440 return NULL;
5441
5442 poly->p[i].y = float8_pl_safe(circle->center.y, temp, fcinfo->context);
5443 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5444 return NULL;
5445 }
5446
5448
5449 return poly;
5450}
5451
5452Datum
5460
5461/* convert circle to 12-vertex polygon */
5462Datum
5464{
5465 int32 npts = 12;
5467
5469}
5470
5471/*
5472 * Convert polygon to circle
5473 *
5474 * The result must be preallocated.
5475 *
5476 * XXX This algorithm should use weighted means of line segments
5477 * rather than straight average values of points - tgl 97/01/21.
5478 */
5479static void
5481{
5482 int i;
5483 float8 x;
5484
5485 Assert(poly->npts > 0);
5486
5487 result->center.x = 0;
5488 result->center.y = 0;
5489 result->radius = 0;
5490
5491 for (i = 0; i < poly->npts; i++)
5492 {
5493 point_add_point(&result->center, &result->center, &poly->p[i], escontext);
5494 if (SOFT_ERROR_OCCURRED(escontext))
5495 return;
5496 }
5497
5498 result->center.x = float8_div_safe(result->center.x, poly->npts, escontext);
5499 if (SOFT_ERROR_OCCURRED(escontext))
5500 return;
5501
5502 result->center.y = float8_div_safe(result->center.y, poly->npts, escontext);
5503 if (SOFT_ERROR_OCCURRED(escontext))
5504 return;
5505
5506 for (i = 0; i < poly->npts; i++)
5507 {
5508 x = point_dt(&poly->p[i], &result->center, escontext);
5509 if (SOFT_ERROR_OCCURRED(escontext))
5510 return;
5511
5512 result->radius = float8_pl_safe(result->radius, x, escontext);
5513 if (SOFT_ERROR_OCCURRED(escontext))
5514 return;
5515 }
5516
5517 result->radius = float8_div_safe(result->radius, poly->npts, escontext);
5518 if (SOFT_ERROR_OCCURRED(escontext))
5519 return;
5520}
5521
5522Datum
5524{
5526 CIRCLE *result;
5527
5529
5530 poly_to_circle(result, poly, fcinfo->context);
5531 if (SOFT_ERROR_OCCURRED(fcinfo->context))
5533
5535}
5536
5537
5538/***********************************************************************
5539 **
5540 ** Private routines for multiple types.
5541 **
5542 ***********************************************************************/
5543
5544/*
5545 * Test to see if the point is inside the polygon, returns 1/0, or 2 if
5546 * the point is on the polygon.
5547 * Code adapted but not copied from integer-based routines in WN: A
5548 * Server for the HTTP
5549 * version 1.15.1, file wn/image.c
5550 * http://hopf.math.northwestern.edu/index.html
5551 * Description of algorithm: http://www.linuxjournal.com/article/2197
5552 * http://www.linuxjournal.com/article/2029
5553 */
5554
5555#define POINT_ON_POLYGON INT_MAX
5556
5557static int
5559{
5560 float8 x0,
5561 y0;
5562 float8 prev_x,
5563 prev_y;
5564 int i = 0;
5565 float8 x,
5566 y;
5567 int cross,
5568 total_cross = 0;
5569
5570 Assert(npts > 0);
5571
5572 /* compute first polygon point relative to single point */
5573 x0 = float8_mi(plist[0].x, p->x);
5574 y0 = float8_mi(plist[0].y, p->y);
5575
5576 prev_x = x0;
5577 prev_y = y0;
5578 /* loop over polygon points and aggregate total_cross */
5579 for (i = 1; i < npts; i++)
5580 {
5581 /* compute next polygon point relative to single point */
5582 x = float8_mi(plist[i].x, p->x);
5583 y = float8_mi(plist[i].y, p->y);
5584
5585 /* compute previous to current point crossing */
5587 return 2;
5588 total_cross += cross;
5589
5590 prev_x = x;
5591 prev_y = y;
5592 }
5593
5594 /* now do the first point */
5596 return 2;
5597 total_cross += cross;
5598
5599 if (total_cross != 0)
5600 return 1;
5601 return 0;
5602}
5603
5604
5605/*
5606 * lseg_crossing()
5607 * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
5608 * Returns +/-1 if one point is on the positive X-axis.
5609 * Returns 0 if both points are on the positive X-axis, or there is no crossing.
5610 * Returns POINT_ON_POLYGON if the segment contains (0,0).
5611 * Wow, that is one confusing API, but it is used above, and when summed,
5612 * can tell is if a point is in a polygon.
5613 */
5614
5615static int
5617{
5618 float8 z;
5619 int y_sign;
5620
5621 if (FPzero(y))
5622 { /* y == 0, on X axis */
5623 if (FPzero(x)) /* (x,y) is (0,0)? */
5624 return POINT_ON_POLYGON;
5625 else if (FPgt(x, 0))
5626 { /* x > 0 */
5627 if (FPzero(prev_y)) /* y and prev_y are zero */
5628 /* prev_x > 0? */
5629 return FPgt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
5630 return FPlt(prev_y, 0.0) ? 1 : -1;
5631 }
5632 else
5633 { /* x < 0, x not on positive X axis */
5634 if (FPzero(prev_y))
5635 /* prev_x < 0? */
5636 return FPlt(prev_x, 0.0) ? 0 : POINT_ON_POLYGON;
5637 return 0;
5638 }
5639 }
5640 else
5641 { /* y != 0 */
5642 /* compute y crossing direction from previous point */
5643 y_sign = FPgt(y, 0.0) ? 1 : -1;
5644
5645 if (FPzero(prev_y))
5646 /* previous point was on X axis, so new point is either off or on */
5647 return FPlt(prev_x, 0.0) ? 0 : y_sign;
5648 else if ((y_sign < 0 && FPlt(prev_y, 0.0)) ||
5649 (y_sign > 0 && FPgt(prev_y, 0.0)))
5650 /* both above or below X axis */
5651 return 0; /* same sign */
5652 else
5653 { /* y and prev_y cross X-axis */
5654 if (FPge(x, 0.0) && FPgt(prev_x, 0.0))
5655 /* both non-negative so cross positive X-axis */
5656 return 2 * y_sign;
5657 if (FPlt(x, 0.0) && FPle(prev_x, 0.0))
5658 /* both non-positive so do not cross positive X-axis */
5659 return 0;
5660
5661 /* x and y cross axes, see URL above point_inside() */
5664 if (FPzero(z))
5665 return POINT_ON_POLYGON;
5666 if ((y_sign < 0 && FPlt(z, 0.0)) ||
5667 (y_sign > 0 && FPgt(z, 0.0)))
5668 return 0;
5669 return 2 * y_sign;
5670 }
5671 }
5672}
5673
5674
5675static bool
5677{
5678 int i,
5679 ii,
5680 j;
5681
5682 /* find match for first point */
5683 for (i = 0; i < npts; i++)
5684 {
5685 if (point_eq_point(&p2[i], &p1[0]))
5686 {
5687
5688 /* match found? then look forward through remaining points */
5689 for (ii = 1, j = i + 1; ii < npts; ii++, j++)
5690 {
5691 if (j >= npts)
5692 j = 0;
5693 if (!point_eq_point(&p2[j], &p1[ii]))
5694 break;
5695 }
5696 if (ii == npts)
5697 return true;
5698
5699 /* match not found forwards? then look backwards */
5700 for (ii = 1, j = i - 1; ii < npts; ii++, j--)
5701 {
5702 if (j < 0)
5703 j = (npts - 1);
5704 if (!point_eq_point(&p2[j], &p1[ii]))
5705 break;
5706 }
5707 if (ii == npts)
5708 return true;
5709 }
5710 }
5711
5712 return false;
5713}
#define Assert(condition)
Definition c.h:943
double float8
Definition c.h:714
int32_t int32
Definition c.h:620
#define unlikely(x)
Definition c.h:438
uint32 result
#define M_PI
int errcode(int sqlerrcode)
Definition elog.c:875
#define ereturn(context, dummy_value,...)
Definition elog.h:280
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
#define palloc_object(type)
Definition fe_memutils.h:89
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:5131
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:4935
Datum close_ls(PG_FUNCTION_ARGS)
Definition geo_ops.c:3070
static bool box_ov(BOX *box1, BOX *box2)
Definition geo_ops.c:578
static float8 box_closept_point(Point *result, BOX *box, Point *pt)
Definition geo_ops.c:2960
Datum box_width(PG_FUNCTION_ARGS)
Definition geo_ops.c:828
Datum path_n_le(PG_FUNCTION_ARGS)
Definition geo_ops.c:1629
Datum lseg_center(PG_FUNCTION_ARGS)
Definition geo_ops.c:2380
Datum path_close(PG_FUNCTION_ARGS)
Definition geo_ops.c:1676
Datum circle_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:4712
Datum point_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:2044
static int lseg_crossing(float8 x, float8 y, float8 prev_x, float8 prev_y)
Definition geo_ops.c:5616
Datum circle_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:5018
Datum path_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:1781
static bool box_interpt_lseg(Point *result, BOX *box, LSEG *lseg)
Definition geo_ops.c:3346
static void point_add_point(Point *result, Point *pt1, Point *pt2, Node *escontext)
Definition geo_ops.c:4195
static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
Definition geo_ops.c:3950
static bool lseg_contain_point(LSEG *lseg, Point *pt)
Definition geo_ops.c:3191
#define DELIM
Definition geo_ops.c:160
Datum lseg_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:2173
Datum box_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:590
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:2015
Datum path_n_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:1620
Datum point_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:1893
Datum circle_overright(PG_FUNCTION_ARGS)
Definition geo_ops.c:4922
Datum circle_radius(PG_FUNCTION_ARGS)
Definition geo_ops.c:5174
Datum cr_circle(PG_FUNCTION_ARGS)
Definition geo_ops.c:5294
static char * path_encode(enum path_delim path_delim, int npts, Point *pt)
Datum point_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:1919
Datum circle_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:5187
#define POINT_ON_POLYGON
Definition geo_ops.c:5555
Datum circle_center(PG_FUNCTION_ARGS)
Definition geo_ops.c:5266
Datum box_gt(PG_FUNCTION_ARGS)
Definition geo_ops.c:771
Datum circle_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:4908
Datum circle_overleft(PG_FUNCTION_ARGS)
Definition geo_ops.c:4882
Datum path_mul_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4521
Datum box_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:618
static float8 box_ht(BOX *box)
Definition geo_ops.c:937
Datum dist_pathp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2572
Datum circle_diameter(PG_FUNCTION_ARGS)
Definition geo_ops.c:5162
static bool poly_contain_poly(POLYGON *contains_poly, POLYGON *contained_poly)
Definition geo_ops.c:4022
Datum lseg_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:2143
Datum path_n_ge(PG_FUNCTION_ARGS)
Definition geo_ops.c:1638
Datum box_ge(PG_FUNCTION_ARGS)
Definition geo_ops.c:798
Datum poly_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:3499
Datum dist_pc(PG_FUNCTION_ARGS)
Definition geo_ops.c:5231
Datum point_sub(PG_FUNCTION_ARGS)
Definition geo_ops.c:4235
Datum poly_npoints(PG_FUNCTION_ARGS)
Definition geo_ops.c:4590
Datum dist_ps(PG_FUNCTION_ARGS)
Definition geo_ops.c:2496
Datum poly_overabove(PG_FUNCTION_ARGS)
Definition geo_ops.c:3778
static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
Definition geo_ops.c:2205
Datum on_pl(PG_FUNCTION_ARGS)
Definition geo_ops.c:3177
Datum path_isopen(PG_FUNCTION_ARGS)
Definition geo_ops.c:1659
Datum path_sub_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4504
Datum circle_same(PG_FUNCTION_ARGS)
Definition geo_ops.c:4854
static void poly_to_circle(CIRCLE *result, POLYGON *poly, Node *escontext)
Definition geo_ops.c:5480
Datum point_div(PG_FUNCTION_ARGS)
Definition geo_ops.c:4289
Datum line_vertical(PG_FUNCTION_ARGS)
Definition geo_ops.c:1221
Datum box_same(PG_FUNCTION_ARGS)
Definition geo_ops.c:556
Datum line_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:1025
Datum circle_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:5310
static void point_construct(Point *result, float8 x, float8 y)
Definition geo_ops.c:1935
Datum circle_ge(PG_FUNCTION_ARGS)
Definition geo_ops.c:5063
Datum poly_contain_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4092
Datum dist_ppoly(PG_FUNCTION_ARGS)
Definition geo_ops.c:2694
Datum poly_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:3543
Datum poly_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:4111
Datum line_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:1309
Datum circle_mul_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5116
Datum point_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:2006
static bool box_contain_box(BOX *contains_box, BOX *contained_box)
Definition geo_ops.c:720
Datum dist_ppath(PG_FUNCTION_ARGS)
Definition geo_ops.c:2560
Datum point_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:4395
static void line_construct(LINE *result, Point *pt, float8 m)
Definition geo_ops.c:1129
#define LDELIM_L
Definition geo_ops.c:165
Datum box_sub(PG_FUNCTION_ARGS)
Definition geo_ops.c:4339
Datum circle_overabove(PG_FUNCTION_ARGS)
Definition geo_ops.c:5003
Datum poly_overright(PG_FUNCTION_ARGS)
Definition geo_ops.c:3686
Datum point_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:1970
Datum dist_cpoly(PG_FUNCTION_ARGS)
Definition geo_ops.c:2670
Datum line_perp(PG_FUNCTION_ARGS)
Definition geo_ops.c:1202
Datum path_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:1451
Datum dist_pl(PG_FUNCTION_ARGS)
Definition geo_ops.c:2472
Datum lseg_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:2299
Datum poly_contained(PG_FUNCTION_ARGS)
Definition geo_ops.c:4072
Datum poly_circle(PG_FUNCTION_ARGS)
Definition geo_ops.c:5523
Datum box_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:854
Datum close_lseg(PG_FUNCTION_ARGS)
Definition geo_ops.c:2935
Datum path_area(PG_FUNCTION_ARGS)
Definition geo_ops.c:1429
Datum points_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:4310
Datum box_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:646
static void make_bound_box(POLYGON *poly)
Definition geo_ops.c:3460
Datum poly_overleft(PG_FUNCTION_ARGS)
Definition geo_ops.c:3640
static bool line_decode(char *s, const char *str, LINE *line, Node *escontext)
Definition geo_ops.c:996
Datum poly_path(PG_FUNCTION_ARGS)
Definition geo_ops.c:4664
static float8 box_closept_lseg(Point *result, BOX *box, LSEG *lseg)
Definition geo_ops.c:3095
static void point_mul_point(Point *result, Point *pt1, Point *pt2)
Definition geo_ops.c:4250
Datum circle_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:4975
Datum dist_sp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2508
Datum poly_overlap(PG_FUNCTION_ARGS)
Definition geo_ops.c:3885
Datum circle_to_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:5463
Datum lseg_ge(PG_FUNCTION_ARGS)
Definition geo_ops.c:2349
Datum poly_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:3617
Datum line_construct_pp(PG_FUNCTION_ARGS)
Definition geo_ops.c:1162
static bool poly_overlap_internal(POLYGON *polya, POLYGON *polyb)
Definition geo_ops.c:3828
static float8 circle_ar(CIRCLE *circle)
Definition geo_ops.c:5283
Datum path_open(PG_FUNCTION_ARGS)
Definition geo_ops.c:1686
Datum box_add(PG_FUNCTION_ARGS)
Definition geo_ops.c:4324
Datum box_diagonal(PG_FUNCTION_ARGS)
Definition geo_ops.c:979
Datum line_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:1241
Datum box_below_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:739
Datum path_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:1575
Datum poly_contain(PG_FUNCTION_ARGS)
Definition geo_ops.c:4050
Datum circle_add_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5081
static void point_div_point(Point *result, Point *pt1, Point *pt2)
Definition geo_ops.c:4275
static float8 box_ar(BOX *box)
Definition geo_ops.c:889
Datum poly_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:3559
Datum inter_lb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3412
Datum box_area(PG_FUNCTION_ARGS)
Definition geo_ops.c:815
Datum path_length(PG_FUNCTION_ARGS)
Definition geo_ops.c:1843
Datum boxes_bound_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:4414
Datum box_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:458
Datum circle_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:4962
#define LDELIM_C
Definition geo_ops.c:163
Datum lseg_gt(PG_FUNCTION_ARGS)
Definition geo_ops.c:2339
#define LDELIM_EP
Definition geo_ops.c:161
static float8 lseg_closept_point(Point *result, LSEG *lseg, Point *pt)
Definition geo_ops.c:2854
Datum path_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:1523
Datum box_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:424
Datum box_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:469
static float8 lseg_closept_line(Point *result, LSEG *lseg, LINE *line)
Definition geo_ops.c:3042
Datum on_ppath(PG_FUNCTION_ARGS)
Definition geo_ops.c:3249
Datum pt_contained_circle(PG_FUNCTION_ARGS)
Definition geo_ops.c:5215
Datum lseg_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:2154
Datum line_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:1107
Datum lseg_horizontal(PG_FUNCTION_ARGS)
Definition geo_ops.c:2290
Datum close_pl(PG_FUNCTION_ARGS)
Definition geo_ops.c:2832
static float8 line_closept_point(Point *result, LINE *line, Point *point)
Definition geo_ops.c:2806
Datum box_above_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:748
Datum on_ps(PG_FUNCTION_ARGS)
Definition geo_ops.c:3199
#define RDELIM
Definition geo_ops.c:159
Datum box_contain_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:3228
Datum dist_sl(PG_FUNCTION_ARGS)
Definition geo_ops.c:2608
Datum path_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:4548
Datum point_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:1979
Datum box_le(PG_FUNCTION_ARGS)
Definition geo_ops.c:789
Datum line_parallel(PG_FUNCTION_ARGS)
Definition geo_ops.c:1193
Datum lseg_length(PG_FUNCTION_ARGS)
Definition geo_ops.c:2235
Datum line_out(PG_FUNCTION_ARGS)
Definition geo_ops.c:1069
Datum line_interpt(PG_FUNCTION_ARGS)
Definition geo_ops.c:1335
static float8 point_dt(Point *pt1, Point *pt2, Node *escontext)
Definition geo_ops.c:2053
Datum close_sb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3145
static POLYGON * circle_poly_internal(int32 npts, const CIRCLE *circle, FunctionCallInfo fcinfo)
Definition geo_ops.c:5388
Datum lseg_le(PG_FUNCTION_ARGS)
Definition geo_ops.c:2329
Datum on_pb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3219
static int point_inside(Point *p, int npts, Point *plist)
Definition geo_ops.c:5558
Datum lseg_ne(PG_FUNCTION_ARGS)
Definition geo_ops.c:2309
Datum path_inter(PG_FUNCTION_ARGS)
Definition geo_ops.c:1703
Datum dist_lp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2484
Datum box_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:4635
Datum inter_sb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3398
Datum poly_below(PG_FUNCTION_ARGS)
Definition geo_ops.c:3709
Datum poly_overbelow(PG_FUNCTION_ARGS)
Definition geo_ops.c:3732
Datum pt_contained_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:4101
Datum circle_contain(PG_FUNCTION_ARGS)
Definition geo_ops.c:4948
static bool line_interpt_line(Point *result, LINE *l1, LINE *l2)
Definition geo_ops.c:1363
static void box_construct(BOX *result, Point *pt1, Point *pt2)
Definition geo_ops.c:522
Datum lseg_lt(PG_FUNCTION_ARGS)
Definition geo_ops.c:2319
Datum circle_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:4829
static bool box_contain_lseg(BOX *box, LSEG *lseg)
Definition geo_ops.c:3300
Datum circle_lt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5036
Datum lseg_vertical(PG_FUNCTION_ARGS)
Definition geo_ops.c:2282
Datum lseg_construct(PG_FUNCTION_ARGS)
Definition geo_ops.c:2192
Datum lseg_intersect(PG_FUNCTION_ARGS)
Definition geo_ops.c:2251
Datum dist_bp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2596
Datum box_div(PG_FUNCTION_ARGS)
Definition geo_ops.c:4373
Datum path_n_lt(PG_FUNCTION_ARGS)
Definition geo_ops.c:1602
Datum box_overright(PG_FUNCTION_ARGS)
Definition geo_ops.c:634
Datum path_npoints(PG_FUNCTION_ARGS)
Definition geo_ops.c:1667
Datum on_sl(PG_FUNCTION_ARGS)
Definition geo_ops.c:3284
Datum point_horiz(PG_FUNCTION_ARGS)
Definition geo_ops.c:1997
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:4783
Datum inter_sl(PG_FUNCTION_ARGS)
Definition geo_ops.c:3321
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:2261
static bool plist_same(int npts, Point *p1, Point *p2)
Definition geo_ops.c:5676
static bool touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
Definition geo_ops.c:3914
Datum box_overabove(PG_FUNCTION_ARGS)
Definition geo_ops.c:684
Datum poly_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:3755
Datum line_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:1084
Datum lseg_interpt(PG_FUNCTION_ARGS)
Definition geo_ops.c:2443
Datum point_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:1904
Datum box_circle(PG_FUNCTION_ARGS)
Definition geo_ops.c:5349
Datum path_isclosed(PG_FUNCTION_ARGS)
Definition geo_ops.c:1651
Datum circle_sub_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5096
Datum line_horizontal(PG_FUNCTION_ARGS)
Definition geo_ops.c:1229
Datum box_mul(PG_FUNCTION_ARGS)
Definition geo_ops.c:4354
Datum box_overlap(PG_FUNCTION_ARGS)
Definition geo_ops.c:569
Datum box_center(PG_FUNCTION_ARGS)
Definition geo_ops.c:872
Datum circle_overbelow(PG_FUNCTION_ARGS)
Definition geo_ops.c:4989
static float8 dist_ppoly_internal(Point *pt, POLYGON *poly)
Definition geo_ops.c:2712
#define RDELIM_L
Definition geo_ops.c:166
Datum box_contain(PG_FUNCTION_ARGS)
Definition geo_ops.c:708
Datum box_height(PG_FUNCTION_ARGS)
Definition geo_ops.c:841
Datum circle_contain_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5203
Datum dist_bs(PG_FUNCTION_ARGS)
Definition geo_ops.c:2644
Datum path_add_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4491
static float8 box_wd(BOX *box)
Definition geo_ops.c:926
static bool box_contain_point(BOX *box, Point *point)
Definition geo_ops.c:3212
Datum circle_ne(PG_FUNCTION_ARGS)
Definition geo_ops.c:5027
Datum circle_le(PG_FUNCTION_ARGS)
Definition geo_ops.c:5054
Datum box_intersect(PG_FUNCTION_ARGS)
Definition geo_ops.c:953
Datum close_pb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3015
Datum circle_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:4895
static float8 point_sl(Point *pt1, Point *pt2)
Definition geo_ops.c:2085
static float8 lseg_invsl(LSEG *lseg)
Definition geo_ops.c:2228
Datum point_left(PG_FUNCTION_ARGS)
Definition geo_ops.c:1952
Datum path_add(PG_FUNCTION_ARGS)
Definition geo_ops.c:4442
static bool line_contain_point(LINE *line, Point *point)
Definition geo_ops.c:3169
Datum circle_overlap(PG_FUNCTION_ARGS)
Definition geo_ops.c:4868
Datum lseg_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:2127
Datum circle_area(PG_FUNCTION_ARGS)
Definition geo_ops.c:5150
#define RDELIM_C
Definition geo_ops.c:164
Datum on_sb(PG_FUNCTION_ARGS)
Definition geo_ops.c:3307
Datum dist_pb(PG_FUNCTION_ARGS)
Definition geo_ops.c:2584
Datum point_add(PG_FUNCTION_ARGS)
Definition geo_ops.c:4212
static float8 lseg_sl(LSEG *lseg)
Definition geo_ops.c:2218
Datum circle_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:4805
Datum poly_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:3663
Datum box_lt(PG_FUNCTION_ARGS)
Definition geo_ops.c:762
Datum path_recv(PG_FUNCTION_ARGS)
Definition geo_ops.c:1537
static float8 dist_cpoly_internal(CIRCLE *circle, POLYGON *poly)
Definition geo_ops.c:2653
static void box_cn(Point *center, BOX *box, Node *escontext)
Definition geo_ops.c:899
static float8 line_sl(LINE *line)
Definition geo_ops.c:1280
#define RDELIM_EP
Definition geo_ops.c:162
Datum line_intersect(PG_FUNCTION_ARGS)
Definition geo_ops.c:1184
Datum box_eq(PG_FUNCTION_ARGS)
Definition geo_ops.c:780
Datum path_n_gt(PG_FUNCTION_ARGS)
Definition geo_ops.c:1611
Datum poly_box(PG_FUNCTION_ARGS)
Definition geo_ops.c:4618
Datum point_slope(PG_FUNCTION_ARGS)
Definition geo_ops.c:2070
Datum circle_poly(PG_FUNCTION_ARGS)
Definition geo_ops.c:5453
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:2420
Datum point_right(PG_FUNCTION_ARGS)
Definition geo_ops.c:1961
Datum box_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:504
static float8 point_invsl(Point *pt1, Point *pt2)
Definition geo_ops.c:2101
Datum point_mul(PG_FUNCTION_ARGS)
Definition geo_ops.c:4260
static float8 dist_ppath_internal(Point *pt, PATH *path)
Definition geo_ops.c:2517
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:2682
Datum dist_sb(PG_FUNCTION_ARGS)
Definition geo_ops.c:2632
static float8 line_invsl(LINE *line)
Definition geo_ops.c:1294
static void point_sub_point(Point *result, Point *pt1, Point *pt2)
Definition geo_ops.c:4227
Datum circle_gt(PG_FUNCTION_ARGS)
Definition geo_ops.c:5045
Datum box_overbelow(PG_FUNCTION_ARGS)
Definition geo_ops.c:659
static float8 lseg_closept_lseg(Point *result, LSEG *on_lseg, LSEG *to_lseg)
Definition geo_ops.c:2892
Datum dist_cpoint(PG_FUNCTION_ARGS)
Definition geo_ops.c:5249
Datum lseg_distance(PG_FUNCTION_ARGS)
Definition geo_ops.c:2370
Datum dist_ls(PG_FUNCTION_ARGS)
Definition geo_ops.c:2620
Datum construct_point(PG_FUNCTION_ARGS)
Definition geo_ops.c:4180
Datum poly_center(PG_FUNCTION_ARGS)
Definition geo_ops.c:4599
Datum lseg_perp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2273
Datum box_contained(PG_FUNCTION_ARGS)
Definition geo_ops.c:696
Datum path_div_pt(PG_FUNCTION_ARGS)
Definition geo_ops.c:4534
static bool lseg_interpt_line(Point *result, LSEG *lseg, LINE *line)
Definition geo_ops.c:2757
Datum point_in(PG_FUNCTION_ARGS)
Definition geo_ops.c:1882
Datum box_overleft(PG_FUNCTION_ARGS)
Definition geo_ops.c:606
static bool point_eq_point(Point *pt1, Point *pt2)
Definition geo_ops.c:2028
#define LDELIM
Definition geo_ops.c:158
Datum close_ps(PG_FUNCTION_ARGS)
Definition geo_ops.c:2873
Datum dist_polyp(PG_FUNCTION_ARGS)
Definition geo_ops.c:2703
Datum box_above(PG_FUNCTION_ARGS)
Definition geo_ops.c:671
Datum poly_same(PG_FUNCTION_ARGS)
Definition geo_ops.c:3804
static void single_encode(float8 x, StringInfo str)
Definition geo_ops.c:204
Datum point_vert(PG_FUNCTION_ARGS)
Definition geo_ops.c:1988
Datum poly_send(PG_FUNCTION_ARGS)
Definition geo_ops.c:3594
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:1619
void * palloc0(Size size)
Definition mcxt.c:1420
void * palloc(Size size)
Definition mcxt.c:1390
#define CHECK_FOR_INTERRUPTS()
Definition miscadmin.h:125
#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
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