1 /*-------------------------------------------------------------------------
4 * 2D geometric operations
6 * Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * src/backend/utils/adt/geo_ops.c
13 *-------------------------------------------------------------------------
22 #include "libpq/pqformat.h"
23 #include "miscadmin.h"
24 #include "utils/builtins.h"
25 #include "utils/geo_decls.h"
28 #define M_PI 3.14159265358979323846
38 PATH_NONE, PATH_OPEN, PATH_CLOSED
41 static int point_inside(Point *p, int npts, Point *plist);
42 static int lseg_crossing(double x, double y, double px, double py);
43 static BOX *box_construct(double x1, double x2, double y1, double y2);
44 static BOX *box_copy(BOX *box);
45 static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2);
46 static bool box_ov(BOX *box1, BOX *box2);
47 static double box_ht(BOX *box);
48 static double box_wd(BOX *box);
49 static double circle_ar(CIRCLE *circle);
50 static CIRCLE *circle_copy(CIRCLE *circle);
51 static LINE *line_construct_pm(Point *pt, double m);
52 static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
53 static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
54 static double lseg_dt(LSEG *l1, LSEG *l2);
55 static bool on_ps_internal(Point *pt, LSEG *lseg);
56 static void make_bound_box(POLYGON *poly);
57 static bool plist_same(int npts, Point *p1, Point *p2);
58 static Point *point_construct(double x, double y);
59 static Point *point_copy(Point *pt);
60 static double single_decode(char *num, char **endptr_p,
61 const char *type_name, const char *orig_string);
62 static void single_encode(float8 x, StringInfo str);
63 static void pair_decode(char *str, double *x, double *y, char **endptr_p,
64 const char *type_name, const char *orig_string);
65 static void pair_encode(float8 x, float8 y, StringInfo str);
66 static int pair_count(char *s, char delim);
67 static void path_decode(char *str, bool opentype, int npts, Point *p,
68 bool *isopen, char **endptr_p,
69 const char *type_name, const char *orig_string);
70 static char *path_encode(enum path_delim path_delim, int npts, Point *pt);
71 static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
72 static double box_ar(BOX *box);
73 static void box_cn(Point *center, BOX *box);
74 static Point *interpt_sl(LSEG *lseg, LINE *line);
75 static bool has_interpt_sl(LSEG *lseg, LINE *line);
76 static double dist_pl_internal(Point *pt, LINE *line);
77 static double dist_ps_internal(Point *pt, LSEG *lseg);
78 static Point *line_interpt_internal(LINE *l1, LINE *l2);
79 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
80 static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
81 static double dist_ppoly_internal(Point *pt, POLYGON *poly);
85 * Delimiters for input and output strings.
86 * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
87 * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
100 * Geometric data types are composed of points.
101 * This code tries to support a common format throughout the data types,
102 * to allow for more predictable usage and data type conversion.
103 * The fundamental unit is the point. Other units are line segments,
104 * open paths, boxes, closed paths, and polygons (which should be considered
105 * non-intersecting closed paths).
107 * Data representation is as follows:
109 * line segment: [(x1,y1),(x2,y2)]
110 * box: (x1,y1),(x2,y2)
111 * open path: [(x1,y1),...,(xn,yn)]
112 * closed path: ((x1,y1),...,(xn,yn))
113 * polygon: ((x1,y1),...,(xn,yn))
115 * For boxes, the points are opposite corners with the first point at the top right.
116 * For closed paths and polygons, the points should be reordered to allow
117 * fast and correct equality comparisons.
119 * XXX perhaps points in complex shapes should be reordered internally
120 * to allow faster internal operations, but should keep track of input order
121 * and restore that order for text output - tgl 97/01/16
125 single_decode(char *num, char **endptr_p,
126 const char *type_name, const char *orig_string)
128 return float8in_internal(num, endptr_p, type_name, orig_string);
129 } /* single_decode() */
132 single_encode(float8 x, StringInfo str)
134 char *xstr = float8out_internal(x);
136 appendStringInfoString(str, xstr);
138 } /* single_encode() */
141 pair_decode(char *str, double *x, double *y, char **endptr_p,
142 const char *type_name, const char *orig_string)
146 while (isspace((unsigned char) *str))
148 if ((has_delim = (*str == LDELIM)))
151 *x = float8in_internal(str, &str, type_name, orig_string);
155 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
156 errmsg("invalid input syntax for type %s: \"%s\"",
157 type_name, orig_string)));
159 *y = float8in_internal(str, &str, type_name, orig_string);
163 if (*str++ != RDELIM)
165 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
166 errmsg("invalid input syntax for type %s: \"%s\"",
167 type_name, orig_string)));
168 while (isspace((unsigned char) *str))
172 /* report stopping point if wanted, else complain if not end of string */
175 else if (*str != '\0')
177 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
178 errmsg("invalid input syntax for type %s: \"%s\"",
179 type_name, orig_string)));
183 pair_encode(float8 x, float8 y, StringInfo str)
185 char *xstr = float8out_internal(x);
186 char *ystr = float8out_internal(y);
188 appendStringInfo(str, "%s,%s", xstr, ystr);
194 path_decode(char *str, bool opentype, int npts, Point *p,
195 bool *isopen, char **endptr_p,
196 const char *type_name, const char *orig_string)
202 while (isspace((unsigned char) *str))
204 if ((*isopen = (*str == LDELIM_EP)))
206 /* no open delimiter allowed? */
209 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
210 errmsg("invalid input syntax for type %s: \"%s\"",
211 type_name, orig_string)));
215 else if (*str == LDELIM)
218 while (isspace((unsigned char) *cp))
225 else if (strrchr(str, LDELIM) == str)
232 for (i = 0; i < npts; i++)
234 pair_decode(str, &(p->x), &(p->y), &str, type_name, orig_string);
240 while (isspace((unsigned char) *str))
245 || ((*str == RDELIM_EP) && (*isopen) && (depth == 1)))
249 while (isspace((unsigned char) *str))
254 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
255 errmsg("invalid input syntax for type %s: \"%s\"",
256 type_name, orig_string)));
259 /* report stopping point if wanted, else complain if not end of string */
262 else if (*str != '\0')
264 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
265 errmsg("invalid input syntax for type %s: \"%s\"",
266 type_name, orig_string)));
267 } /* path_decode() */
270 path_encode(enum path_delim path_delim, int npts, Point *pt)
275 initStringInfo(&str);
280 appendStringInfoChar(&str, LDELIM);
283 appendStringInfoChar(&str, LDELIM_EP);
289 for (i = 0; i < npts; i++)
292 appendStringInfoChar(&str, DELIM);
293 appendStringInfoChar(&str, LDELIM);
294 pair_encode(pt->x, pt->y, &str);
295 appendStringInfoChar(&str, RDELIM);
302 appendStringInfoChar(&str, RDELIM);
305 appendStringInfoChar(&str, RDELIM_EP);
312 } /* path_encode() */
314 /*-------------------------------------------------------------
315 * pair_count - count the number of points
316 * allow the following notation:
319 * require an odd number of delim characters in the string
320 *-------------------------------------------------------------*/
322 pair_count(char *s, char delim)
326 while ((s = strchr(s, delim)) != NULL)
331 return (ndelim % 2) ? ((ndelim + 1) / 2) : -1;
335 /***********************************************************************
337 ** Routines for two-dimensional boxes.
339 ***********************************************************************/
341 /*----------------------------------------------------------
342 * Formatting and conversion routines.
343 *---------------------------------------------------------*/
345 /* box_in - convert a string to internal form.
347 * External format: (two corners of box)
348 * "(f8, f8), (f8, f8)"
349 * also supports the older style "(f8, f8, f8, f8)"
352 box_in(PG_FUNCTION_ARGS)
354 char *str = PG_GETARG_CSTRING(0);
355 BOX *box = (BOX *) palloc(sizeof(BOX));
360 path_decode(str, false, 2, &(box->high), &isopen, NULL, "box", str);
362 /* reorder corners if necessary... */
363 if (box->high.x < box->low.x)
366 box->high.x = box->low.x;
369 if (box->high.y < box->low.y)
372 box->high.y = box->low.y;
376 PG_RETURN_BOX_P(box);
379 /* box_out - convert a box to external form.
382 box_out(PG_FUNCTION_ARGS)
384 BOX *box = PG_GETARG_BOX_P(0);
386 PG_RETURN_CSTRING(path_encode(PATH_NONE, 2, &(box->high)));
390 * box_recv - converts external binary format to box
393 box_recv(PG_FUNCTION_ARGS)
395 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
400 box = (BOX *) palloc(sizeof(BOX));
402 box->high.x = pq_getmsgfloat8(buf);
403 box->high.y = pq_getmsgfloat8(buf);
404 box->low.x = pq_getmsgfloat8(buf);
405 box->low.y = pq_getmsgfloat8(buf);
407 /* reorder corners if necessary... */
408 if (box->high.x < box->low.x)
411 box->high.x = box->low.x;
414 if (box->high.y < box->low.y)
417 box->high.y = box->low.y;
421 PG_RETURN_BOX_P(box);
425 * box_send - converts box to binary format
428 box_send(PG_FUNCTION_ARGS)
430 BOX *box = PG_GETARG_BOX_P(0);
433 pq_begintypsend(&buf);
434 pq_sendfloat8(&buf, box->high.x);
435 pq_sendfloat8(&buf, box->high.y);
436 pq_sendfloat8(&buf, box->low.x);
437 pq_sendfloat8(&buf, box->low.y);
438 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
442 /* box_construct - fill in a new box.
445 box_construct(double x1, double x2, double y1, double y2)
447 BOX *result = (BOX *) palloc(sizeof(BOX));
449 return box_fill(result, x1, x2, y1, y2);
453 /* box_fill - fill in a given box struct
456 box_fill(BOX *result, double x1, double x2, double y1, double y2)
483 /* box_copy - copy a box
488 BOX *result = (BOX *) palloc(sizeof(BOX));
490 memcpy((char *) result, (char *) box, sizeof(BOX));
496 /*----------------------------------------------------------
497 * Relational operators for BOXes.
498 * <, >, <=, >=, and == are based on box area.
499 *---------------------------------------------------------*/
501 /* box_same - are two boxes identical?
504 box_same(PG_FUNCTION_ARGS)
506 BOX *box1 = PG_GETARG_BOX_P(0);
507 BOX *box2 = PG_GETARG_BOX_P(1);
509 PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
510 FPeq(box1->low.x, box2->low.x) &&
511 FPeq(box1->high.y, box2->high.y) &&
512 FPeq(box1->low.y, box2->low.y));
515 /* box_overlap - does box1 overlap box2?
518 box_overlap(PG_FUNCTION_ARGS)
520 BOX *box1 = PG_GETARG_BOX_P(0);
521 BOX *box2 = PG_GETARG_BOX_P(1);
523 PG_RETURN_BOOL(box_ov(box1, box2));
527 box_ov(BOX *box1, BOX *box2)
529 return (FPle(box1->low.x, box2->high.x) &&
530 FPle(box2->low.x, box1->high.x) &&
531 FPle(box1->low.y, box2->high.y) &&
532 FPle(box2->low.y, box1->high.y));
535 /* box_left - is box1 strictly left of box2?
538 box_left(PG_FUNCTION_ARGS)
540 BOX *box1 = PG_GETARG_BOX_P(0);
541 BOX *box2 = PG_GETARG_BOX_P(1);
543 PG_RETURN_BOOL(FPlt(box1->high.x, box2->low.x));
546 /* box_overleft - is the right edge of box1 at or left of
547 * the right edge of box2?
549 * This is "less than or equal" for the end of a time range,
550 * when time ranges are stored as rectangles.
553 box_overleft(PG_FUNCTION_ARGS)
555 BOX *box1 = PG_GETARG_BOX_P(0);
556 BOX *box2 = PG_GETARG_BOX_P(1);
558 PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x));
561 /* box_right - is box1 strictly right of box2?
564 box_right(PG_FUNCTION_ARGS)
566 BOX *box1 = PG_GETARG_BOX_P(0);
567 BOX *box2 = PG_GETARG_BOX_P(1);
569 PG_RETURN_BOOL(FPgt(box1->low.x, box2->high.x));
572 /* box_overright - is the left edge of box1 at or right of
573 * the left edge of box2?
575 * This is "greater than or equal" for time ranges, when time ranges
576 * are stored as rectangles.
579 box_overright(PG_FUNCTION_ARGS)
581 BOX *box1 = PG_GETARG_BOX_P(0);
582 BOX *box2 = PG_GETARG_BOX_P(1);
584 PG_RETURN_BOOL(FPge(box1->low.x, box2->low.x));
587 /* box_below - is box1 strictly below box2?
590 box_below(PG_FUNCTION_ARGS)
592 BOX *box1 = PG_GETARG_BOX_P(0);
593 BOX *box2 = PG_GETARG_BOX_P(1);
595 PG_RETURN_BOOL(FPlt(box1->high.y, box2->low.y));
598 /* box_overbelow - is the upper edge of box1 at or below
599 * the upper edge of box2?
602 box_overbelow(PG_FUNCTION_ARGS)
604 BOX *box1 = PG_GETARG_BOX_P(0);
605 BOX *box2 = PG_GETARG_BOX_P(1);
607 PG_RETURN_BOOL(FPle(box1->high.y, box2->high.y));
610 /* box_above - is box1 strictly above box2?
613 box_above(PG_FUNCTION_ARGS)
615 BOX *box1 = PG_GETARG_BOX_P(0);
616 BOX *box2 = PG_GETARG_BOX_P(1);
618 PG_RETURN_BOOL(FPgt(box1->low.y, box2->high.y));
621 /* box_overabove - is the lower edge of box1 at or above
622 * the lower edge of box2?
625 box_overabove(PG_FUNCTION_ARGS)
627 BOX *box1 = PG_GETARG_BOX_P(0);
628 BOX *box2 = PG_GETARG_BOX_P(1);
630 PG_RETURN_BOOL(FPge(box1->low.y, box2->low.y));
633 /* box_contained - is box1 contained by box2?
636 box_contained(PG_FUNCTION_ARGS)
638 BOX *box1 = PG_GETARG_BOX_P(0);
639 BOX *box2 = PG_GETARG_BOX_P(1);
641 PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
642 FPge(box1->low.x, box2->low.x) &&
643 FPle(box1->high.y, box2->high.y) &&
644 FPge(box1->low.y, box2->low.y));
647 /* box_contain - does box1 contain box2?
650 box_contain(PG_FUNCTION_ARGS)
652 BOX *box1 = PG_GETARG_BOX_P(0);
653 BOX *box2 = PG_GETARG_BOX_P(1);
655 PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
656 FPle(box1->low.x, box2->low.x) &&
657 FPge(box1->high.y, box2->high.y) &&
658 FPle(box1->low.y, box2->low.y));
663 * is box1 entirely {above,below} box2?
665 * box_below_eq and box_above_eq are obsolete versions that (probably
666 * erroneously) accept the equal-boundaries case. Since these are not
667 * in sync with the box_left and box_right code, they are deprecated and
668 * not supported in the PG 8.1 rtree operator class extension.
671 box_below_eq(PG_FUNCTION_ARGS)
673 BOX *box1 = PG_GETARG_BOX_P(0);
674 BOX *box2 = PG_GETARG_BOX_P(1);
676 PG_RETURN_BOOL(FPle(box1->high.y, box2->low.y));
680 box_above_eq(PG_FUNCTION_ARGS)
682 BOX *box1 = PG_GETARG_BOX_P(0);
683 BOX *box2 = PG_GETARG_BOX_P(1);
685 PG_RETURN_BOOL(FPge(box1->low.y, box2->high.y));
689 /* box_relop - is area(box1) relop area(box2), within
690 * our accuracy constraint?
693 box_lt(PG_FUNCTION_ARGS)
695 BOX *box1 = PG_GETARG_BOX_P(0);
696 BOX *box2 = PG_GETARG_BOX_P(1);
698 PG_RETURN_BOOL(FPlt(box_ar(box1), box_ar(box2)));
702 box_gt(PG_FUNCTION_ARGS)
704 BOX *box1 = PG_GETARG_BOX_P(0);
705 BOX *box2 = PG_GETARG_BOX_P(1);
707 PG_RETURN_BOOL(FPgt(box_ar(box1), box_ar(box2)));
711 box_eq(PG_FUNCTION_ARGS)
713 BOX *box1 = PG_GETARG_BOX_P(0);
714 BOX *box2 = PG_GETARG_BOX_P(1);
716 PG_RETURN_BOOL(FPeq(box_ar(box1), box_ar(box2)));
720 box_le(PG_FUNCTION_ARGS)
722 BOX *box1 = PG_GETARG_BOX_P(0);
723 BOX *box2 = PG_GETARG_BOX_P(1);
725 PG_RETURN_BOOL(FPle(box_ar(box1), box_ar(box2)));
729 box_ge(PG_FUNCTION_ARGS)
731 BOX *box1 = PG_GETARG_BOX_P(0);
732 BOX *box2 = PG_GETARG_BOX_P(1);
734 PG_RETURN_BOOL(FPge(box_ar(box1), box_ar(box2)));
738 /*----------------------------------------------------------
739 * "Arithmetic" operators on boxes.
740 *---------------------------------------------------------*/
742 /* box_area - returns the area of the box.
745 box_area(PG_FUNCTION_ARGS)
747 BOX *box = PG_GETARG_BOX_P(0);
749 PG_RETURN_FLOAT8(box_ar(box));
753 /* box_width - returns the width of the box
754 * (horizontal magnitude).
757 box_width(PG_FUNCTION_ARGS)
759 BOX *box = PG_GETARG_BOX_P(0);
761 PG_RETURN_FLOAT8(box->high.x - box->low.x);
765 /* box_height - returns the height of the box
766 * (vertical magnitude).
769 box_height(PG_FUNCTION_ARGS)
771 BOX *box = PG_GETARG_BOX_P(0);
773 PG_RETURN_FLOAT8(box->high.y - box->low.y);
777 /* box_distance - returns the distance between the
778 * center points of two boxes.
781 box_distance(PG_FUNCTION_ARGS)
783 BOX *box1 = PG_GETARG_BOX_P(0);
784 BOX *box2 = PG_GETARG_BOX_P(1);
791 PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
795 /* box_center - returns the center point of the box.
798 box_center(PG_FUNCTION_ARGS)
800 BOX *box = PG_GETARG_BOX_P(0);
801 Point *result = (Point *) palloc(sizeof(Point));
805 PG_RETURN_POINT_P(result);
809 /* box_ar - returns the area of the box.
814 return box_wd(box) * box_ht(box);
818 /* box_cn - stores the centerpoint of the box into *center.
821 box_cn(Point *center, BOX *box)
823 center->x = (box->high.x + box->low.x) / 2.0;
824 center->y = (box->high.y + box->low.y) / 2.0;
828 /* box_wd - returns the width (length) of the box
829 * (horizontal magnitude).
834 return box->high.x - box->low.x;
838 /* box_ht - returns the height of the box
839 * (vertical magnitude).
844 return box->high.y - box->low.y;
848 /*----------------------------------------------------------
850 *---------------------------------------------------------*/
853 * returns the overlapping portion of two boxes,
854 * or NULL if they do not intersect.
857 box_intersect(PG_FUNCTION_ARGS)
859 BOX *box1 = PG_GETARG_BOX_P(0);
860 BOX *box2 = PG_GETARG_BOX_P(1);
863 if (!box_ov(box1, box2))
866 result = (BOX *) palloc(sizeof(BOX));
868 result->high.x = Min(box1->high.x, box2->high.x);
869 result->low.x = Max(box1->low.x, box2->low.x);
870 result->high.y = Min(box1->high.y, box2->high.y);
871 result->low.y = Max(box1->low.y, box2->low.y);
873 PG_RETURN_BOX_P(result);
878 * returns a line segment which happens to be the
879 * positive-slope diagonal of "box".
882 box_diagonal(PG_FUNCTION_ARGS)
884 BOX *box = PG_GETARG_BOX_P(0);
885 LSEG *result = (LSEG *) palloc(sizeof(LSEG));
887 statlseg_construct(result, &box->high, &box->low);
889 PG_RETURN_LSEG_P(result);
892 /***********************************************************************
894 ** Routines for 2D lines.
896 ***********************************************************************/
899 line_decode(char *s, const char *str, LINE *line)
901 /* s was already advanced over leading '{' */
902 line->A = single_decode(s, &s, "line", str);
905 line->B = single_decode(s, &s, "line", str);
908 line->C = single_decode(s, &s, "line", str);
911 while (isspace((unsigned char) *s))
919 line_in(PG_FUNCTION_ARGS)
921 char *str = PG_GETARG_CSTRING(0);
922 LINE *line = (LINE *) palloc(sizeof(LINE));
928 while (isspace((unsigned char) *s))
932 if (!line_decode(s + 1, str, line))
934 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
935 errmsg("invalid input syntax for type %s: \"%s\"",
937 if (FPzero(line->A) && FPzero(line->B))
939 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
940 errmsg("invalid line specification: A and B cannot both be zero")));
944 path_decode(s, true, 2, &(lseg.p[0]), &isopen, NULL, "line", str);
945 if (FPeq(lseg.p[0].x, lseg.p[1].x) && FPeq(lseg.p[0].y, lseg.p[1].y))
947 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
948 errmsg("invalid line specification: must be two distinct points")));
949 line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
952 PG_RETURN_LINE_P(line);
957 line_out(PG_FUNCTION_ARGS)
959 LINE *line = PG_GETARG_LINE_P(0);
960 char *astr = float8out_internal(line->A);
961 char *bstr = float8out_internal(line->B);
962 char *cstr = float8out_internal(line->C);
964 PG_RETURN_CSTRING(psprintf("{%s,%s,%s}", astr, bstr, cstr));
968 * line_recv - converts external binary format to line
971 line_recv(PG_FUNCTION_ARGS)
973 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
976 line = (LINE *) palloc(sizeof(LINE));
978 line->A = pq_getmsgfloat8(buf);
979 line->B = pq_getmsgfloat8(buf);
980 line->C = pq_getmsgfloat8(buf);
982 PG_RETURN_LINE_P(line);
986 * line_send - converts line to binary format
989 line_send(PG_FUNCTION_ARGS)
991 LINE *line = PG_GETARG_LINE_P(0);
994 pq_begintypsend(&buf);
995 pq_sendfloat8(&buf, line->A);
996 pq_sendfloat8(&buf, line->B);
997 pq_sendfloat8(&buf, line->C);
998 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1002 /*----------------------------------------------------------
1003 * Conversion routines from one line formula to internal.
1004 * Internal form: Ax+By+C=0
1005 *---------------------------------------------------------*/
1007 /* line_construct_pm()
1011 line_construct_pm(Point *pt, double m)
1013 LINE *result = (LINE *) palloc(sizeof(LINE));
1017 /* vertical - use "x = C" */
1024 /* use "mx - y + yinter = 0" */
1027 result->C = pt->y - m * pt->x;
1034 * Fill already-allocated LINE struct from two points on the line
1037 line_construct_pts(LINE *line, Point *pt1, Point *pt2)
1039 if (FPeq(pt1->x, pt2->x))
1046 printf("line_construct_pts- line is vertical\n");
1049 else if (FPeq(pt1->y, pt2->y))
1056 printf("line_construct_pts- line is horizontal\n");
1061 /* use "mx - y + yinter = 0" */
1062 line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
1064 line->C = pt1->y - line->A * pt1->x;
1065 /* on some platforms, the preceding expression tends to produce -0 */
1069 printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
1070 DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
1075 /* line_construct_pp()
1079 line_construct_pp(PG_FUNCTION_ARGS)
1081 Point *pt1 = PG_GETARG_POINT_P(0);
1082 Point *pt2 = PG_GETARG_POINT_P(1);
1083 LINE *result = (LINE *) palloc(sizeof(LINE));
1085 line_construct_pts(result, pt1, pt2);
1086 PG_RETURN_LINE_P(result);
1090 /*----------------------------------------------------------
1091 * Relative position routines.
1092 *---------------------------------------------------------*/
1095 line_intersect(PG_FUNCTION_ARGS)
1097 LINE *l1 = PG_GETARG_LINE_P(0);
1098 LINE *l2 = PG_GETARG_LINE_P(1);
1100 PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
1102 LinePGetDatum(l2))));
1106 line_parallel(PG_FUNCTION_ARGS)
1108 LINE *l1 = PG_GETARG_LINE_P(0);
1109 LINE *l2 = PG_GETARG_LINE_P(1);
1112 PG_RETURN_BOOL(FPzero(l2->B));
1114 PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
1118 line_perp(PG_FUNCTION_ARGS)
1120 LINE *l1 = PG_GETARG_LINE_P(0);
1121 LINE *l2 = PG_GETARG_LINE_P(1);
1124 PG_RETURN_BOOL(FPzero(l2->B));
1125 else if (FPzero(l1->B))
1126 PG_RETURN_BOOL(FPzero(l2->A));
1128 PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
1132 line_vertical(PG_FUNCTION_ARGS)
1134 LINE *line = PG_GETARG_LINE_P(0);
1136 PG_RETURN_BOOL(FPzero(line->B));
1140 line_horizontal(PG_FUNCTION_ARGS)
1142 LINE *line = PG_GETARG_LINE_P(0);
1144 PG_RETURN_BOOL(FPzero(line->A));
1148 line_eq(PG_FUNCTION_ARGS)
1150 LINE *l1 = PG_GETARG_LINE_P(0);
1151 LINE *l2 = PG_GETARG_LINE_P(1);
1156 else if (!FPzero(l2->B))
1158 else if (!FPzero(l2->C))
1163 PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
1164 FPeq(l1->B, k * l2->B) &&
1165 FPeq(l1->C, k * l2->C));
1169 /*----------------------------------------------------------
1170 * Line arithmetic routines.
1171 *---------------------------------------------------------*/
1174 * Distance between two lines.
1177 line_distance(PG_FUNCTION_ARGS)
1179 LINE *l1 = PG_GETARG_LINE_P(0);
1180 LINE *l2 = PG_GETARG_LINE_P(1);
1184 if (!DatumGetBool(DirectFunctionCall2(line_parallel,
1186 LinePGetDatum(l2))))
1187 PG_RETURN_FLOAT8(0.0);
1188 if (FPzero(l1->B)) /* vertical? */
1189 PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
1190 tmp = point_construct(0.0, l1->C);
1191 result = dist_pl_internal(tmp, l2);
1192 PG_RETURN_FLOAT8(result);
1196 * Point where two lines l1, l2 intersect (if any)
1199 line_interpt(PG_FUNCTION_ARGS)
1201 LINE *l1 = PG_GETARG_LINE_P(0);
1202 LINE *l2 = PG_GETARG_LINE_P(1);
1205 result = line_interpt_internal(l1, l2);
1209 PG_RETURN_POINT_P(result);
1213 * Internal version of line_interpt
1215 * returns a NULL pointer if no intersection point
1218 line_interpt_internal(LINE *l1, LINE *l2)
1225 * NOTE: if the lines are identical then we will find they are parallel
1226 * and report "no intersection". This is a little weird, but since
1227 * there's no *unique* intersection, maybe it's appropriate behavior.
1229 if (DatumGetBool(DirectFunctionCall2(line_parallel,
1231 LinePGetDatum(l2))))
1234 if (FPzero(l1->B)) /* l1 vertical? */
1237 y = (l2->A * x + l2->C);
1239 else if (FPzero(l2->B)) /* l2 vertical? */
1242 y = (l1->A * x + l1->C);
1246 x = (l1->C - l2->C) / (l2->A - l1->A);
1247 y = (l1->A * x + l1->C);
1249 result = point_construct(x, y);
1252 printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
1253 DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
1254 printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
1261 /***********************************************************************
1263 ** Routines for 2D paths (sequences of line segments, also
1264 ** called `polylines').
1266 ** This is not a general package for geometric paths,
1267 ** which of course include polygons; the emphasis here
1268 ** is on (for example) usefulness in wire layout.
1270 ***********************************************************************/
1272 /*----------------------------------------------------------
1273 * String to path / path to string conversion.
1275 * "((xcoord, ycoord),... )"
1276 * "[(xcoord, ycoord),... ]"
1277 * "(xcoord, ycoord),... "
1278 * "[xcoord, ycoord,... ]"
1279 * Also support older format:
1280 * "(closed, npts, xcoord, ycoord,... )"
1281 *---------------------------------------------------------*/
1284 path_area(PG_FUNCTION_ARGS)
1286 PATH *path = PG_GETARG_PATH_P(0);
1294 for (i = 0; i < path->npts; i++)
1296 j = (i + 1) % path->npts;
1297 area += path->p[i].x * path->p[j].y;
1298 area -= path->p[i].y * path->p[j].x;
1302 PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
1307 path_in(PG_FUNCTION_ARGS)
1309 char *str = PG_GETARG_CSTRING(0);
1318 if ((npts = pair_count(str, ',')) <= 0)
1320 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1321 errmsg("invalid input syntax for type %s: \"%s\"",
1325 while (isspace((unsigned char) *s))
1328 /* skip single leading paren */
1329 if ((*s == LDELIM) && (strrchr(s, LDELIM) == s))
1335 base_size = sizeof(path->p[0]) * npts;
1336 size = offsetof(PATH, p) +base_size;
1338 /* Check for integer overflow */
1339 if (base_size / npts != sizeof(path->p[0]) || size <= base_size)
1341 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1342 errmsg("too many points requested")));
1344 path = (PATH *) palloc(size);
1346 SET_VARSIZE(path, size);
1349 path_decode(s, true, npts, &(path->p[0]), &isopen, &s, "path", str);
1355 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1356 errmsg("invalid input syntax for type %s: \"%s\"",
1358 while (isspace((unsigned char) *s))
1363 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
1364 errmsg("invalid input syntax for type %s: \"%s\"",
1367 path->closed = (!isopen);
1368 /* prevent instability in unused pad bytes */
1371 PG_RETURN_PATH_P(path);
1376 path_out(PG_FUNCTION_ARGS)
1378 PATH *path = PG_GETARG_PATH_P(0);
1380 PG_RETURN_CSTRING(path_encode(path->closed ? PATH_CLOSED : PATH_OPEN, path->npts, path->p));
1384 * path_recv - converts external binary format to path
1386 * External representation is closed flag (a boolean byte), int32 number
1387 * of points, and the points.
1390 path_recv(PG_FUNCTION_ARGS)
1392 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1399 closed = pq_getmsgbyte(buf);
1400 npts = pq_getmsgint(buf, sizeof(int32));
1401 if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(PATH, p)) / sizeof(Point)))
1403 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1404 errmsg("invalid number of points in external \"path\" value")));
1406 size = offsetof(PATH, p) +sizeof(path->p[0]) * npts;
1407 path = (PATH *) palloc(size);
1409 SET_VARSIZE(path, size);
1411 path->closed = (closed ? 1 : 0);
1412 /* prevent instability in unused pad bytes */
1415 for (i = 0; i < npts; i++)
1417 path->p[i].x = pq_getmsgfloat8(buf);
1418 path->p[i].y = pq_getmsgfloat8(buf);
1421 PG_RETURN_PATH_P(path);
1425 * path_send - converts path to binary format
1428 path_send(PG_FUNCTION_ARGS)
1430 PATH *path = PG_GETARG_PATH_P(0);
1434 pq_begintypsend(&buf);
1435 pq_sendbyte(&buf, path->closed ? 1 : 0);
1436 pq_sendint(&buf, path->npts, sizeof(int32));
1437 for (i = 0; i < path->npts; i++)
1439 pq_sendfloat8(&buf, path->p[i].x);
1440 pq_sendfloat8(&buf, path->p[i].y);
1442 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1446 /*----------------------------------------------------------
1447 * Relational operators.
1448 * These are based on the path cardinality,
1449 * as stupid as that sounds.
1451 * Better relops and access methods coming soon.
1452 *---------------------------------------------------------*/
1455 path_n_lt(PG_FUNCTION_ARGS)
1457 PATH *p1 = PG_GETARG_PATH_P(0);
1458 PATH *p2 = PG_GETARG_PATH_P(1);
1460 PG_RETURN_BOOL(p1->npts < p2->npts);
1464 path_n_gt(PG_FUNCTION_ARGS)
1466 PATH *p1 = PG_GETARG_PATH_P(0);
1467 PATH *p2 = PG_GETARG_PATH_P(1);
1469 PG_RETURN_BOOL(p1->npts > p2->npts);
1473 path_n_eq(PG_FUNCTION_ARGS)
1475 PATH *p1 = PG_GETARG_PATH_P(0);
1476 PATH *p2 = PG_GETARG_PATH_P(1);
1478 PG_RETURN_BOOL(p1->npts == p2->npts);
1482 path_n_le(PG_FUNCTION_ARGS)
1484 PATH *p1 = PG_GETARG_PATH_P(0);
1485 PATH *p2 = PG_GETARG_PATH_P(1);
1487 PG_RETURN_BOOL(p1->npts <= p2->npts);
1491 path_n_ge(PG_FUNCTION_ARGS)
1493 PATH *p1 = PG_GETARG_PATH_P(0);
1494 PATH *p2 = PG_GETARG_PATH_P(1);
1496 PG_RETURN_BOOL(p1->npts >= p2->npts);
1499 /*----------------------------------------------------------
1500 * Conversion operators.
1501 *---------------------------------------------------------*/
1504 path_isclosed(PG_FUNCTION_ARGS)
1506 PATH *path = PG_GETARG_PATH_P(0);
1508 PG_RETURN_BOOL(path->closed);
1512 path_isopen(PG_FUNCTION_ARGS)
1514 PATH *path = PG_GETARG_PATH_P(0);
1516 PG_RETURN_BOOL(!path->closed);
1520 path_npoints(PG_FUNCTION_ARGS)
1522 PATH *path = PG_GETARG_PATH_P(0);
1524 PG_RETURN_INT32(path->npts);
1529 path_close(PG_FUNCTION_ARGS)
1531 PATH *path = PG_GETARG_PATH_P_COPY(0);
1533 path->closed = TRUE;
1535 PG_RETURN_PATH_P(path);
1539 path_open(PG_FUNCTION_ARGS)
1541 PATH *path = PG_GETARG_PATH_P_COPY(0);
1543 path->closed = FALSE;
1545 PG_RETURN_PATH_P(path);
1550 * Does p1 intersect p2 at any point?
1551 * Use bounding boxes for a quick (O(n)) check, then do a
1552 * O(n^2) iterative edge check.
1555 path_inter(PG_FUNCTION_ARGS)
1557 PATH *p1 = PG_GETARG_PATH_P(0);
1558 PATH *p2 = PG_GETARG_PATH_P(1);
1566 if (p1->npts <= 0 || p2->npts <= 0)
1567 PG_RETURN_BOOL(false);
1569 b1.high.x = b1.low.x = p1->p[0].x;
1570 b1.high.y = b1.low.y = p1->p[0].y;
1571 for (i = 1; i < p1->npts; i++)
1573 b1.high.x = Max(p1->p[i].x, b1.high.x);
1574 b1.high.y = Max(p1->p[i].y, b1.high.y);
1575 b1.low.x = Min(p1->p[i].x, b1.low.x);
1576 b1.low.y = Min(p1->p[i].y, b1.low.y);
1578 b2.high.x = b2.low.x = p2->p[0].x;
1579 b2.high.y = b2.low.y = p2->p[0].y;
1580 for (i = 1; i < p2->npts; i++)
1582 b2.high.x = Max(p2->p[i].x, b2.high.x);
1583 b2.high.y = Max(p2->p[i].y, b2.high.y);
1584 b2.low.x = Min(p2->p[i].x, b2.low.x);
1585 b2.low.y = Min(p2->p[i].y, b2.low.y);
1587 if (!box_ov(&b1, &b2))
1588 PG_RETURN_BOOL(false);
1590 /* pairwise check lseg intersections */
1591 for (i = 0; i < p1->npts; i++)
1601 iprev = p1->npts - 1; /* include the closure segment */
1604 for (j = 0; j < p2->npts; j++)
1614 jprev = p2->npts - 1; /* include the closure segment */
1617 statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
1618 statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
1619 if (lseg_intersect_internal(&seg1, &seg2))
1620 PG_RETURN_BOOL(true);
1624 /* if we dropped through, no two segs intersected */
1625 PG_RETURN_BOOL(false);
1629 * This essentially does a cartesian product of the lsegs in the
1630 * two paths, and finds the min distance between any two lsegs
1633 path_distance(PG_FUNCTION_ARGS)
1635 PATH *p1 = PG_GETARG_PATH_P(0);
1636 PATH *p2 = PG_GETARG_PATH_P(1);
1637 float8 min = 0.0; /* initialize to keep compiler quiet */
1638 bool have_min = false;
1645 for (i = 0; i < p1->npts; i++)
1655 iprev = p1->npts - 1; /* include the closure segment */
1658 for (j = 0; j < p2->npts; j++)
1668 jprev = p2->npts - 1; /* include the closure segment */
1671 statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
1672 statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
1674 tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
1675 LsegPGetDatum(&seg1),
1676 LsegPGetDatum(&seg2)));
1677 if (!have_min || tmp < min)
1688 PG_RETURN_FLOAT8(min);
1692 /*----------------------------------------------------------
1693 * "Arithmetic" operations.
1694 *---------------------------------------------------------*/
1697 path_length(PG_FUNCTION_ARGS)
1699 PATH *path = PG_GETARG_PATH_P(0);
1700 float8 result = 0.0;
1703 for (i = 0; i < path->npts; i++)
1713 iprev = path->npts - 1; /* include the closure segment */
1716 result += point_dt(&path->p[iprev], &path->p[i]);
1719 PG_RETURN_FLOAT8(result);
1722 /***********************************************************************
1724 ** Routines for 2D points.
1726 ***********************************************************************/
1728 /*----------------------------------------------------------
1729 * String to point, point to string conversion.
1733 *---------------------------------------------------------*/
1736 point_in(PG_FUNCTION_ARGS)
1738 char *str = PG_GETARG_CSTRING(0);
1739 Point *point = (Point *) palloc(sizeof(Point));
1741 pair_decode(str, &point->x, &point->y, NULL, "point", str);
1742 PG_RETURN_POINT_P(point);
1746 point_out(PG_FUNCTION_ARGS)
1748 Point *pt = PG_GETARG_POINT_P(0);
1750 PG_RETURN_CSTRING(path_encode(PATH_NONE, 1, pt));
1754 * point_recv - converts external binary format to point
1757 point_recv(PG_FUNCTION_ARGS)
1759 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1762 point = (Point *) palloc(sizeof(Point));
1763 point->x = pq_getmsgfloat8(buf);
1764 point->y = pq_getmsgfloat8(buf);
1765 PG_RETURN_POINT_P(point);
1769 * point_send - converts point to binary format
1772 point_send(PG_FUNCTION_ARGS)
1774 Point *pt = PG_GETARG_POINT_P(0);
1777 pq_begintypsend(&buf);
1778 pq_sendfloat8(&buf, pt->x);
1779 pq_sendfloat8(&buf, pt->y);
1780 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1785 point_construct(double x, double y)
1787 Point *result = (Point *) palloc(sizeof(Point));
1796 point_copy(Point *pt)
1800 if (!PointerIsValid(pt))
1803 result = (Point *) palloc(sizeof(Point));
1811 /*----------------------------------------------------------
1812 * Relational operators for Points.
1813 * Since we do have a sense of coordinates being
1814 * "equal" to a given accuracy (point_vert, point_horiz),
1815 * the other ops must preserve that sense. This means
1816 * that results may, strictly speaking, be a lie (unless
1818 *---------------------------------------------------------*/
1821 point_left(PG_FUNCTION_ARGS)
1823 Point *pt1 = PG_GETARG_POINT_P(0);
1824 Point *pt2 = PG_GETARG_POINT_P(1);
1826 PG_RETURN_BOOL(FPlt(pt1->x, pt2->x));
1830 point_right(PG_FUNCTION_ARGS)
1832 Point *pt1 = PG_GETARG_POINT_P(0);
1833 Point *pt2 = PG_GETARG_POINT_P(1);
1835 PG_RETURN_BOOL(FPgt(pt1->x, pt2->x));
1839 point_above(PG_FUNCTION_ARGS)
1841 Point *pt1 = PG_GETARG_POINT_P(0);
1842 Point *pt2 = PG_GETARG_POINT_P(1);
1844 PG_RETURN_BOOL(FPgt(pt1->y, pt2->y));
1848 point_below(PG_FUNCTION_ARGS)
1850 Point *pt1 = PG_GETARG_POINT_P(0);
1851 Point *pt2 = PG_GETARG_POINT_P(1);
1853 PG_RETURN_BOOL(FPlt(pt1->y, pt2->y));
1857 point_vert(PG_FUNCTION_ARGS)
1859 Point *pt1 = PG_GETARG_POINT_P(0);
1860 Point *pt2 = PG_GETARG_POINT_P(1);
1862 PG_RETURN_BOOL(FPeq(pt1->x, pt2->x));
1866 point_horiz(PG_FUNCTION_ARGS)
1868 Point *pt1 = PG_GETARG_POINT_P(0);
1869 Point *pt2 = PG_GETARG_POINT_P(1);
1871 PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
1875 point_eq(PG_FUNCTION_ARGS)
1877 Point *pt1 = PG_GETARG_POINT_P(0);
1878 Point *pt2 = PG_GETARG_POINT_P(1);
1880 PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
1884 point_ne(PG_FUNCTION_ARGS)
1886 Point *pt1 = PG_GETARG_POINT_P(0);
1887 Point *pt2 = PG_GETARG_POINT_P(1);
1889 PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
1892 /*----------------------------------------------------------
1893 * "Arithmetic" operators on points.
1894 *---------------------------------------------------------*/
1897 point_distance(PG_FUNCTION_ARGS)
1899 Point *pt1 = PG_GETARG_POINT_P(0);
1900 Point *pt2 = PG_GETARG_POINT_P(1);
1902 PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
1906 point_dt(Point *pt1, Point *pt2)
1909 printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
1910 pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
1912 return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
1916 point_slope(PG_FUNCTION_ARGS)
1918 Point *pt1 = PG_GETARG_POINT_P(0);
1919 Point *pt2 = PG_GETARG_POINT_P(1);
1921 PG_RETURN_FLOAT8(point_sl(pt1, pt2));
1926 point_sl(Point *pt1, Point *pt2)
1928 return (FPeq(pt1->x, pt2->x)
1930 : (pt1->y - pt2->y) / (pt1->x - pt2->x));
1934 /***********************************************************************
1936 ** Routines for 2D line segments.
1938 ***********************************************************************/
1940 /*----------------------------------------------------------
1941 * String to lseg, lseg to string conversion.
1942 * External forms: "[(x1, y1), (x2, y2)]"
1943 * "(x1, y1), (x2, y2)"
1945 * closed form ok "((x1, y1), (x2, y2))"
1946 * (old form) "(x1, y1, x2, y2)"
1947 *---------------------------------------------------------*/
1950 lseg_in(PG_FUNCTION_ARGS)
1952 char *str = PG_GETARG_CSTRING(0);
1953 LSEG *lseg = (LSEG *) palloc(sizeof(LSEG));
1956 path_decode(str, true, 2, &(lseg->p[0]), &isopen, NULL, "lseg", str);
1957 PG_RETURN_LSEG_P(lseg);
1962 lseg_out(PG_FUNCTION_ARGS)
1964 LSEG *ls = PG_GETARG_LSEG_P(0);
1966 PG_RETURN_CSTRING(path_encode(PATH_OPEN, 2, (Point *) &(ls->p[0])));
1970 * lseg_recv - converts external binary format to lseg
1973 lseg_recv(PG_FUNCTION_ARGS)
1975 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1978 lseg = (LSEG *) palloc(sizeof(LSEG));
1980 lseg->p[0].x = pq_getmsgfloat8(buf);
1981 lseg->p[0].y = pq_getmsgfloat8(buf);
1982 lseg->p[1].x = pq_getmsgfloat8(buf);
1983 lseg->p[1].y = pq_getmsgfloat8(buf);
1985 PG_RETURN_LSEG_P(lseg);
1989 * lseg_send - converts lseg to binary format
1992 lseg_send(PG_FUNCTION_ARGS)
1994 LSEG *ls = PG_GETARG_LSEG_P(0);
1997 pq_begintypsend(&buf);
1998 pq_sendfloat8(&buf, ls->p[0].x);
1999 pq_sendfloat8(&buf, ls->p[0].y);
2000 pq_sendfloat8(&buf, ls->p[1].x);
2001 pq_sendfloat8(&buf, ls->p[1].y);
2002 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
2007 * form a LSEG from two Points.
2010 lseg_construct(PG_FUNCTION_ARGS)
2012 Point *pt1 = PG_GETARG_POINT_P(0);
2013 Point *pt2 = PG_GETARG_POINT_P(1);
2014 LSEG *result = (LSEG *) palloc(sizeof(LSEG));
2016 result->p[0].x = pt1->x;
2017 result->p[0].y = pt1->y;
2018 result->p[1].x = pt2->x;
2019 result->p[1].y = pt2->y;
2021 PG_RETURN_LSEG_P(result);
2024 /* like lseg_construct, but assume space already allocated */
2026 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
2028 lseg->p[0].x = pt1->x;
2029 lseg->p[0].y = pt1->y;
2030 lseg->p[1].x = pt2->x;
2031 lseg->p[1].y = pt2->y;
2035 lseg_length(PG_FUNCTION_ARGS)
2037 LSEG *lseg = PG_GETARG_LSEG_P(0);
2039 PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1]));
2042 /*----------------------------------------------------------
2043 * Relative position routines.
2044 *---------------------------------------------------------*/
2047 ** find intersection of the two lines, and see if it falls on
2051 lseg_intersect(PG_FUNCTION_ARGS)
2053 LSEG *l1 = PG_GETARG_LSEG_P(0);
2054 LSEG *l2 = PG_GETARG_LSEG_P(1);
2056 PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
2060 lseg_intersect_internal(LSEG *l1, LSEG *l2)
2066 line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
2067 interpt = interpt_sl(l1, &ln);
2069 if (interpt != NULL && on_ps_internal(interpt, l2))
2070 retval = true; /* interpt on l1 and l2 */
2077 lseg_parallel(PG_FUNCTION_ARGS)
2079 LSEG *l1 = PG_GETARG_LSEG_P(0);
2080 LSEG *l2 = PG_GETARG_LSEG_P(1);
2082 PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
2083 point_sl(&l2->p[0], &l2->p[1])));
2087 * Determine if two line segments are perpendicular.
2089 * This code did not get the correct answer for
2090 * '((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
2091 * So, modified it to check explicitly for slope of vertical line
2092 * returned by point_sl() and the results seem better.
2093 * - thomas 1998-01-31
2096 lseg_perp(PG_FUNCTION_ARGS)
2098 LSEG *l1 = PG_GETARG_LSEG_P(0);
2099 LSEG *l2 = PG_GETARG_LSEG_P(1);
2103 m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
2104 m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
2107 printf("lseg_perp- slopes are %g and %g\n", m1, m2);
2110 PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
2111 else if (FPzero(m2))
2112 PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
2114 PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
2118 lseg_vertical(PG_FUNCTION_ARGS)
2120 LSEG *lseg = PG_GETARG_LSEG_P(0);
2122 PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
2126 lseg_horizontal(PG_FUNCTION_ARGS)
2128 LSEG *lseg = PG_GETARG_LSEG_P(0);
2130 PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
2135 lseg_eq(PG_FUNCTION_ARGS)
2137 LSEG *l1 = PG_GETARG_LSEG_P(0);
2138 LSEG *l2 = PG_GETARG_LSEG_P(1);
2140 PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
2141 FPeq(l1->p[0].y, l2->p[0].y) &&
2142 FPeq(l1->p[1].x, l2->p[1].x) &&
2143 FPeq(l1->p[1].y, l2->p[1].y));
2147 lseg_ne(PG_FUNCTION_ARGS)
2149 LSEG *l1 = PG_GETARG_LSEG_P(0);
2150 LSEG *l2 = PG_GETARG_LSEG_P(1);
2152 PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
2153 !FPeq(l1->p[0].y, l2->p[0].y) ||
2154 !FPeq(l1->p[1].x, l2->p[1].x) ||
2155 !FPeq(l1->p[1].y, l2->p[1].y));
2159 lseg_lt(PG_FUNCTION_ARGS)
2161 LSEG *l1 = PG_GETARG_LSEG_P(0);
2162 LSEG *l2 = PG_GETARG_LSEG_P(1);
2164 PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
2165 point_dt(&l2->p[0], &l2->p[1])));
2169 lseg_le(PG_FUNCTION_ARGS)
2171 LSEG *l1 = PG_GETARG_LSEG_P(0);
2172 LSEG *l2 = PG_GETARG_LSEG_P(1);
2174 PG_RETURN_BOOL(FPle(point_dt(&l1->p[0], &l1->p[1]),
2175 point_dt(&l2->p[0], &l2->p[1])));
2179 lseg_gt(PG_FUNCTION_ARGS)
2181 LSEG *l1 = PG_GETARG_LSEG_P(0);
2182 LSEG *l2 = PG_GETARG_LSEG_P(1);
2184 PG_RETURN_BOOL(FPgt(point_dt(&l1->p[0], &l1->p[1]),
2185 point_dt(&l2->p[0], &l2->p[1])));
2189 lseg_ge(PG_FUNCTION_ARGS)
2191 LSEG *l1 = PG_GETARG_LSEG_P(0);
2192 LSEG *l2 = PG_GETARG_LSEG_P(1);
2194 PG_RETURN_BOOL(FPge(point_dt(&l1->p[0], &l1->p[1]),
2195 point_dt(&l2->p[0], &l2->p[1])));
2199 /*----------------------------------------------------------
2200 * Line arithmetic routines.
2201 *---------------------------------------------------------*/
2204 * If two segments don't intersect, then the closest
2205 * point will be from one of the endpoints to the other
2209 lseg_distance(PG_FUNCTION_ARGS)
2211 LSEG *l1 = PG_GETARG_LSEG_P(0);
2212 LSEG *l2 = PG_GETARG_LSEG_P(1);
2214 PG_RETURN_FLOAT8(lseg_dt(l1, l2));
2218 * Distance between two line segments.
2219 * Must check both sets of endpoints to ensure minimum distance is found.
2220 * - thomas 1998-02-01
2223 lseg_dt(LSEG *l1, LSEG *l2)
2228 if (lseg_intersect_internal(l1, l2))
2231 d = dist_ps_internal(&l1->p[0], l2);
2233 d = dist_ps_internal(&l1->p[1], l2);
2234 result = Min(result, d);
2235 d = dist_ps_internal(&l2->p[0], l1);
2236 result = Min(result, d);
2237 d = dist_ps_internal(&l2->p[1], l1);
2238 result = Min(result, d);
2245 lseg_center(PG_FUNCTION_ARGS)
2247 LSEG *lseg = PG_GETARG_LSEG_P(0);
2250 result = (Point *) palloc(sizeof(Point));
2252 result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
2253 result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
2255 PG_RETURN_POINT_P(result);
2259 lseg_interpt_internal(LSEG *l1, LSEG *l2)
2266 * Find the intersection of the appropriate lines, if any.
2268 line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
2269 line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
2270 result = line_interpt_internal(&tmp1, &tmp2);
2271 if (!PointerIsValid(result))
2275 * If the line intersection point isn't within l1 (or equivalently l2),
2276 * there is no valid segment intersection point at all.
2278 if (!on_ps_internal(result, l1) ||
2279 !on_ps_internal(result, l2))
2286 * If there is an intersection, then check explicitly for matching
2287 * endpoints since there may be rounding effects with annoying lsb
2288 * residue. - tgl 1997-07-09
2290 if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
2291 (FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
2293 result->x = l1->p[0].x;
2294 result->y = l1->p[0].y;
2296 else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
2297 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
2299 result->x = l1->p[1].x;
2300 result->y = l1->p[1].y;
2307 * Find the intersection point of two segments (if any).
2310 lseg_interpt(PG_FUNCTION_ARGS)
2312 LSEG *l1 = PG_GETARG_LSEG_P(0);
2313 LSEG *l2 = PG_GETARG_LSEG_P(1);
2316 result = lseg_interpt_internal(l1, l2);
2317 if (!PointerIsValid(result))
2320 PG_RETURN_POINT_P(result);
2323 /***********************************************************************
2325 ** Routines for position comparisons of differently-typed
2328 ***********************************************************************/
2330 /*---------------------------------------------------------------------
2332 * Minimum distance from one object to another.
2333 *-------------------------------------------------------------------*/
2336 * Distance from a point to a line
2339 dist_pl(PG_FUNCTION_ARGS)
2341 Point *pt = PG_GETARG_POINT_P(0);
2342 LINE *line = PG_GETARG_LINE_P(1);
2344 PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
2348 dist_pl_internal(Point *pt, LINE *line)
2350 return fabs((line->A * pt->x + line->B * pt->y + line->C) /
2351 HYPOT(line->A, line->B));
2355 * Distance from a point to a lseg
2358 dist_ps(PG_FUNCTION_ARGS)
2360 Point *pt = PG_GETARG_POINT_P(0);
2361 LSEG *lseg = PG_GETARG_LSEG_P(1);
2363 PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
2367 dist_ps_internal(Point *pt, LSEG *lseg)
2369 double m; /* slope of perp. */
2376 * Construct a line perpendicular to the input segment and through the
2379 if (lseg->p[1].x == lseg->p[0].x)
2381 else if (lseg->p[1].y == lseg->p[0].y)
2382 m = (double) DBL_MAX; /* slope is infinite */
2384 m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
2385 ln = line_construct_pm(pt, m);
2388 printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
2389 ln->A, ln->B, ln->C, pt->x, pt->y, m);
2393 * Calculate distance to the line segment or to the nearest endpoint of
2397 /* intersection is on the line segment? */
2398 if ((ip = interpt_sl(lseg, ln)) != NULL)
2400 /* yes, so use distance to the intersection point */
2401 result = point_dt(pt, ip);
2403 printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
2404 result, ip->x, ip->y);
2409 /* no, so use distance to the nearer endpoint */
2410 result = point_dt(pt, &lseg->p[0]);
2411 tmpdist = point_dt(pt, &lseg->p[1]);
2412 if (tmpdist < result)
2420 * Distance from a point to a path
2423 dist_ppath(PG_FUNCTION_ARGS)
2425 Point *pt = PG_GETARG_POINT_P(0);
2426 PATH *path = PG_GETARG_PATH_P(1);
2427 float8 result = 0.0; /* keep compiler quiet */
2428 bool have_min = false;
2436 /* no points in path? then result is undefined... */
2439 /* one point in path? then get distance between two points... */
2440 result = point_dt(pt, &path->p[0]);
2443 /* make sure the path makes sense... */
2444 Assert(path->npts > 1);
2447 * the distance from a point to a path is the smallest distance
2448 * from the point to any of its constituent segments.
2450 for (i = 0; i < path->npts; i++)
2460 iprev = path->npts - 1; /* include the closure segment */
2463 statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
2464 tmp = dist_ps_internal(pt, &lseg);
2465 if (!have_min || tmp < result)
2473 PG_RETURN_FLOAT8(result);
2477 * Distance from a point to a box
2480 dist_pb(PG_FUNCTION_ARGS)
2482 Point *pt = PG_GETARG_POINT_P(0);
2483 BOX *box = PG_GETARG_BOX_P(1);
2487 near = DatumGetPointP(DirectFunctionCall2(close_pb,
2489 BoxPGetDatum(box)));
2490 result = point_dt(near, pt);
2492 PG_RETURN_FLOAT8(result);
2496 * Distance from a lseg to a line
2499 dist_sl(PG_FUNCTION_ARGS)
2501 LSEG *lseg = PG_GETARG_LSEG_P(0);
2502 LINE *line = PG_GETARG_LINE_P(1);
2506 if (has_interpt_sl(lseg, line))
2510 result = dist_pl_internal(&lseg->p[0], line);
2511 d2 = dist_pl_internal(&lseg->p[1], line);
2512 /* XXX shouldn't we take the min not max? */
2517 PG_RETURN_FLOAT8(result);
2521 * Distance from a lseg to a box
2524 dist_sb(PG_FUNCTION_ARGS)
2526 LSEG *lseg = PG_GETARG_LSEG_P(0);
2527 BOX *box = PG_GETARG_BOX_P(1);
2531 tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
2532 LsegPGetDatum(lseg),
2533 BoxPGetDatum(box)));
2534 result = DirectFunctionCall2(dist_pb,
2535 PointPGetDatum(tmp),
2538 PG_RETURN_DATUM(result);
2542 * Distance from a line to a box
2545 dist_lb(PG_FUNCTION_ARGS)
2548 LINE *line = PG_GETARG_LINE_P(0);
2549 BOX *box = PG_GETARG_BOX_P(1);
2552 /* need to think about this one for a while */
2554 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2555 errmsg("function \"dist_lb\" not implemented")));
2561 * Distance from a circle to a polygon
2564 dist_cpoly(PG_FUNCTION_ARGS)
2566 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
2567 POLYGON *poly = PG_GETARG_POLYGON_P(1);
2570 /* calculate distance to center, and subtract radius */
2571 result = dist_ppoly_internal(&circle->center, poly);
2573 result -= circle->radius;
2577 PG_RETURN_FLOAT8(result);
2581 * Distance from a point to a polygon
2584 dist_ppoly(PG_FUNCTION_ARGS)
2586 Point *point = PG_GETARG_POINT_P(0);
2587 POLYGON *poly = PG_GETARG_POLYGON_P(1);
2590 result = dist_ppoly_internal(point, poly);
2592 PG_RETURN_FLOAT8(result);
2596 dist_polyp(PG_FUNCTION_ARGS)
2598 POLYGON *poly = PG_GETARG_POLYGON_P(0);
2599 Point *point = PG_GETARG_POINT_P(1);
2602 result = dist_ppoly_internal(point, poly);
2604 PG_RETURN_FLOAT8(result);
2608 dist_ppoly_internal(Point *pt, POLYGON *poly)
2615 if (point_inside(pt, poly->npts, poly->p) != 0)
2618 printf("dist_ppoly_internal- point inside of polygon\n");
2623 /* initialize distance with segment between first and last points */
2624 seg.p[0].x = poly->p[0].x;
2625 seg.p[0].y = poly->p[0].y;
2626 seg.p[1].x = poly->p[poly->npts - 1].x;
2627 seg.p[1].y = poly->p[poly->npts - 1].y;
2628 result = dist_ps_internal(pt, &seg);
2630 printf("dist_ppoly_internal- segment 0/n distance is %f\n", result);
2633 /* check distances for other segments */
2634 for (i = 0; (i < poly->npts - 1); i++)
2636 seg.p[0].x = poly->p[i].x;
2637 seg.p[0].y = poly->p[i].y;
2638 seg.p[1].x = poly->p[i + 1].x;
2639 seg.p[1].y = poly->p[i + 1].y;
2640 d = dist_ps_internal(pt, &seg);
2642 printf("dist_ppoly_internal- segment %d distance is %f\n", (i + 1), d);
2652 /*---------------------------------------------------------------------
2654 * Intersection point of objects.
2655 * We choose to ignore the "point" of intersection between
2656 * lines and boxes, since there are typically two.
2657 *-------------------------------------------------------------------*/
2659 /* Get intersection point of lseg and line; returns NULL if no intersection */
2661 interpt_sl(LSEG *lseg, LINE *line)
2666 line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
2667 p = line_interpt_internal(&tmp, line);
2669 printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
2670 DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
2671 printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
2672 DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
2674 if (PointerIsValid(p))
2677 printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
2679 if (on_ps_internal(p, lseg))
2682 printf("interpt_sl- intersection point is on segment\n");
2692 /* variant: just indicate if intersection point exists */
2694 has_interpt_sl(LSEG *lseg, LINE *line)
2698 tmp = interpt_sl(lseg, line);
2704 /*---------------------------------------------------------------------
2706 * Point of closest proximity between objects.
2707 *-------------------------------------------------------------------*/
2710 * The intersection point of a perpendicular of the line
2711 * through the point.
2714 close_pl(PG_FUNCTION_ARGS)
2716 Point *pt = PG_GETARG_POINT_P(0);
2717 LINE *line = PG_GETARG_LINE_P(1);
2722 result = (Point *) palloc(sizeof(Point));
2724 if (FPzero(line->B)) /* vertical? */
2726 result->x = line->C;
2728 PG_RETURN_POINT_P(result);
2730 if (FPzero(line->A)) /* horizontal? */
2733 result->y = line->C;
2734 PG_RETURN_POINT_P(result);
2736 /* drop a perpendicular and find the intersection point */
2738 /* invert and flip the sign on the slope to get a perpendicular */
2739 invm = line->B / line->A;
2740 tmp = line_construct_pm(pt, invm);
2741 result = line_interpt_internal(tmp, line);
2742 Assert(result != NULL);
2743 PG_RETURN_POINT_P(result);
2748 * Closest point on line segment to specified point.
2749 * Take the closest endpoint if the point is left, right,
2750 * above, or below the segment, otherwise find the intersection
2751 * point of the segment and its perpendicular through the point.
2753 * Some tricky code here, relying on boolean expressions
2754 * evaluating to only zero or one to use as an array index.
2755 * bug fixes by gthaker@atl.lmco.com; May 1, 1998
2758 close_ps(PG_FUNCTION_ARGS)
2760 Point *pt = PG_GETARG_POINT_P(0);
2761 LSEG *lseg = PG_GETARG_LSEG_P(1);
2762 Point *result = NULL;
2769 printf("close_sp:pt->x %f pt->y %f\nlseg(0).x %f lseg(0).y %f lseg(1).x %f lseg(1).y %f\n",
2770 pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
2771 lseg->p[1].x, lseg->p[1].y);
2774 /* xh (or yh) is the index of upper x( or y) end point of lseg */
2775 /* !xh (or !yh) is the index of lower x( or y) end point of lseg */
2776 xh = lseg->p[0].x < lseg->p[1].x;
2777 yh = lseg->p[0].y < lseg->p[1].y;
2779 if (FPeq(lseg->p[0].x, lseg->p[1].x)) /* vertical? */
2782 printf("close_ps- segment is vertical\n");
2784 /* first check if point is below or above the entire lseg. */
2785 if (pt->y < lseg->p[!yh].y)
2786 result = point_copy(&lseg->p[!yh]); /* below the lseg */
2787 else if (pt->y > lseg->p[yh].y)
2788 result = point_copy(&lseg->p[yh]); /* above the lseg */
2790 PG_RETURN_POINT_P(result);
2792 /* point lines along (to left or right) of the vertical lseg. */
2794 result = (Point *) palloc(sizeof(Point));
2795 result->x = lseg->p[0].x;
2797 PG_RETURN_POINT_P(result);
2799 else if (FPeq(lseg->p[0].y, lseg->p[1].y)) /* horizontal? */
2802 printf("close_ps- segment is horizontal\n");
2804 /* first check if point is left or right of the entire lseg. */
2805 if (pt->x < lseg->p[!xh].x)
2806 result = point_copy(&lseg->p[!xh]); /* left of the lseg */
2807 else if (pt->x > lseg->p[xh].x)
2808 result = point_copy(&lseg->p[xh]); /* right of the lseg */
2810 PG_RETURN_POINT_P(result);
2812 /* point lines along (at top or below) the horiz. lseg. */
2813 result = (Point *) palloc(sizeof(Point));
2815 result->y = lseg->p[0].y;
2816 PG_RETURN_POINT_P(result);
2820 * vert. and horiz. cases are down, now check if the closest point is one
2821 * of the end points or someplace on the lseg.
2824 invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
2825 tmp = line_construct_pm(&lseg->p[!yh], invm); /* lower edge of the
2827 if (pt->y < (tmp->A * pt->x + tmp->C))
2828 { /* we are below the lower edge */
2829 result = point_copy(&lseg->p[!yh]); /* below the lseg, take lower
2832 printf("close_ps below: tmp A %f B %f C %f\n",
2833 tmp->A, tmp->B, tmp->C);
2835 PG_RETURN_POINT_P(result);
2837 tmp = line_construct_pm(&lseg->p[yh], invm); /* upper edge of the
2839 if (pt->y > (tmp->A * pt->x + tmp->C))
2840 { /* we are below the lower edge */
2841 result = point_copy(&lseg->p[yh]); /* above the lseg, take higher
2844 printf("close_ps above: tmp A %f B %f C %f\n",
2845 tmp->A, tmp->B, tmp->C);
2847 PG_RETURN_POINT_P(result);
2851 * at this point the "normal" from point will hit lseg. The closest point
2852 * will be somewhere on the lseg
2854 tmp = line_construct_pm(pt, invm);
2856 printf("close_ps- tmp A %f B %f C %f\n",
2857 tmp->A, tmp->B, tmp->C);
2859 result = interpt_sl(lseg, tmp);
2862 * ordinarily we should always find an intersection point, but that could
2863 * fail in the presence of NaN coordinates, and perhaps even from simple
2864 * roundoff issues. Return a SQL NULL if so.
2870 printf("close_ps- result.x %f result.y %f\n", result->x, result->y);
2872 PG_RETURN_POINT_P(result);
2877 * Closest point to l1 on l2.
2880 close_lseg(PG_FUNCTION_ARGS)
2882 LSEG *l1 = PG_GETARG_LSEG_P(0);
2883 LSEG *l2 = PG_GETARG_LSEG_P(1);
2884 Point *result = NULL;
2889 d = dist_ps_internal(&l1->p[0], l2);
2891 memcpy(&point, &l1->p[0], sizeof(Point));
2893 if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
2896 memcpy(&point, &l1->p[1], sizeof(Point));
2899 if (dist_ps_internal(&l2->p[0], l1) < dist)
2901 result = DatumGetPointP(DirectFunctionCall2(close_ps,
2902 PointPGetDatum(&l2->p[0]),
2903 LsegPGetDatum(l1)));
2904 memcpy(&point, result, sizeof(Point));
2905 result = DatumGetPointP(DirectFunctionCall2(close_ps,
2906 PointPGetDatum(&point),
2907 LsegPGetDatum(l2)));
2910 if (dist_ps_internal(&l2->p[1], l1) < dist)
2912 result = DatumGetPointP(DirectFunctionCall2(close_ps,
2913 PointPGetDatum(&l2->p[1]),
2914 LsegPGetDatum(l1)));
2915 memcpy(&point, result, sizeof(Point));
2916 result = DatumGetPointP(DirectFunctionCall2(close_ps,
2917 PointPGetDatum(&point),
2918 LsegPGetDatum(l2)));
2922 result = point_copy(&point);
2924 PG_RETURN_POINT_P(result);
2928 * Closest point on or in box to specified point.
2931 close_pb(PG_FUNCTION_ARGS)
2933 Point *pt = PG_GETARG_POINT_P(0);
2934 BOX *box = PG_GETARG_BOX_P(1);
2941 if (DatumGetBool(DirectFunctionCall2(on_pb,
2943 BoxPGetDatum(box))))
2944 PG_RETURN_POINT_P(pt);
2946 /* pairwise check lseg distances */
2947 point.x = box->low.x;
2948 point.y = box->high.y;
2949 statlseg_construct(&lseg, &box->low, &point);
2950 dist = dist_ps_internal(pt, &lseg);
2952 statlseg_construct(&seg, &box->high, &point);
2953 if ((d = dist_ps_internal(pt, &seg)) < dist)
2956 memcpy(&lseg, &seg, sizeof(lseg));
2959 point.x = box->high.x;
2960 point.y = box->low.y;
2961 statlseg_construct(&seg, &box->low, &point);
2962 if ((d = dist_ps_internal(pt, &seg)) < dist)
2965 memcpy(&lseg, &seg, sizeof(lseg));
2968 statlseg_construct(&seg, &box->high, &point);
2969 if ((d = dist_ps_internal(pt, &seg)) < dist)
2972 memcpy(&lseg, &seg, sizeof(lseg));
2975 PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
2977 LsegPGetDatum(&lseg)));
2981 * Closest point on line to line segment.
2983 * XXX THIS CODE IS WRONG
2984 * The code is actually calculating the point on the line segment
2985 * which is backwards from the routine naming convention.
2986 * Copied code to new routine close_ls() but haven't fixed this one yet.
2987 * - thomas 1998-01-31
2990 close_sl(PG_FUNCTION_ARGS)
2993 LSEG *lseg = PG_GETARG_LSEG_P(0);
2994 LINE *line = PG_GETARG_LINE_P(1);
2999 result = interpt_sl(lseg, line);
3001 PG_RETURN_POINT_P(result);
3003 d1 = dist_pl_internal(&lseg->p[0], line);
3004 d2 = dist_pl_internal(&lseg->p[1], line);
3006 result = point_copy(&lseg->p[0]);
3008 result = point_copy(&lseg->p[1]);
3010 PG_RETURN_POINT_P(result);
3014 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3015 errmsg("function \"close_sl\" not implemented")));
3021 * Closest point on line segment to line.
3024 close_ls(PG_FUNCTION_ARGS)
3026 LINE *line = PG_GETARG_LINE_P(0);
3027 LSEG *lseg = PG_GETARG_LSEG_P(1);
3032 result = interpt_sl(lseg, line);
3034 PG_RETURN_POINT_P(result);
3036 d1 = dist_pl_internal(&lseg->p[0], line);
3037 d2 = dist_pl_internal(&lseg->p[1], line);
3039 result = point_copy(&lseg->p[0]);
3041 result = point_copy(&lseg->p[1]);
3043 PG_RETURN_POINT_P(result);
3047 * Closest point on or in box to line segment.
3050 close_sb(PG_FUNCTION_ARGS)
3052 LSEG *lseg = PG_GETARG_LSEG_P(0);
3053 BOX *box = PG_GETARG_BOX_P(1);
3060 /* segment intersects box? then just return closest point to center */
3061 if (DatumGetBool(DirectFunctionCall2(inter_sb,
3062 LsegPGetDatum(lseg),
3063 BoxPGetDatum(box))))
3065 box_cn(&point, box);
3066 PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
3067 PointPGetDatum(&point),
3068 LsegPGetDatum(lseg)));
3071 /* pairwise check lseg distances */
3072 point.x = box->low.x;
3073 point.y = box->high.y;
3074 statlseg_construct(&bseg, &box->low, &point);
3075 dist = lseg_dt(lseg, &bseg);
3077 statlseg_construct(&seg, &box->high, &point);
3078 if ((d = lseg_dt(lseg, &seg)) < dist)
3081 memcpy(&bseg, &seg, sizeof(bseg));
3084 point.x = box->high.x;
3085 point.y = box->low.y;
3086 statlseg_construct(&seg, &box->low, &point);
3087 if ((d = lseg_dt(lseg, &seg)) < dist)
3090 memcpy(&bseg, &seg, sizeof(bseg));
3093 statlseg_construct(&seg, &box->high, &point);
3094 if ((d = lseg_dt(lseg, &seg)) < dist)
3097 memcpy(&bseg, &seg, sizeof(bseg));
3100 /* OK, we now have the closest line segment on the box boundary */
3101 PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
3102 LsegPGetDatum(lseg),
3103 LsegPGetDatum(&bseg)));
3107 close_lb(PG_FUNCTION_ARGS)
3110 LINE *line = PG_GETARG_LINE_P(0);
3111 BOX *box = PG_GETARG_BOX_P(1);
3114 /* think about this one for a while */
3116 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3117 errmsg("function \"close_lb\" not implemented")));
3122 /*---------------------------------------------------------------------
3124 * Whether one object lies completely within another.
3125 *-------------------------------------------------------------------*/
3128 * Does the point satisfy the equation?
3131 on_pl(PG_FUNCTION_ARGS)
3133 Point *pt = PG_GETARG_POINT_P(0);
3134 LINE *line = PG_GETARG_LINE_P(1);
3136 PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
3141 * Determine colinearity by detecting a triangle inequality.
3142 * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
3145 on_ps(PG_FUNCTION_ARGS)
3147 Point *pt = PG_GETARG_POINT_P(0);
3148 LSEG *lseg = PG_GETARG_LSEG_P(1);
3150 PG_RETURN_BOOL(on_ps_internal(pt, lseg));
3154 on_ps_internal(Point *pt, LSEG *lseg)
3156 return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
3157 point_dt(&lseg->p[0], &lseg->p[1]));
3161 on_pb(PG_FUNCTION_ARGS)
3163 Point *pt = PG_GETARG_POINT_P(0);
3164 BOX *box = PG_GETARG_BOX_P(1);
3166 PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x &&
3167 pt->y <= box->high.y && pt->y >= box->low.y);
3171 box_contain_pt(PG_FUNCTION_ARGS)
3173 BOX *box = PG_GETARG_BOX_P(0);
3174 Point *pt = PG_GETARG_POINT_P(1);
3176 PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x &&
3177 pt->y <= box->high.y && pt->y >= box->low.y);
3181 * Whether a point lies within (on) a polyline.
3182 * If open, we have to (groan) check each segment.
3183 * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
3184 * If closed, we use the old O(n) ray method for point-in-polygon.
3185 * The ray is horizontal, from pt out to the right.
3186 * Each segment that crosses the ray counts as an
3187 * intersection; note that an endpoint or edge may touch
3189 * (we can do p-in-p in lg(n), but it takes preprocessing)
3192 on_ppath(PG_FUNCTION_ARGS)
3194 Point *pt = PG_GETARG_POINT_P(0);
3195 PATH *path = PG_GETARG_PATH_P(1);
3205 a = point_dt(pt, &path->p[0]);
3206 for (i = 0; i < n; i++)
3208 b = point_dt(pt, &path->p[i + 1]);
3210 point_dt(&path->p[i], &path->p[i + 1])))
3211 PG_RETURN_BOOL(true);
3214 PG_RETURN_BOOL(false);
3218 PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
3222 on_sl(PG_FUNCTION_ARGS)
3224 LSEG *lseg = PG_GETARG_LSEG_P(0);
3225 LINE *line = PG_GETARG_LINE_P(1);
3227 PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
3228 PointPGetDatum(&lseg->p[0]),
3229 LinePGetDatum(line))) &&
3230 DatumGetBool(DirectFunctionCall2(on_pl,
3231 PointPGetDatum(&lseg->p[1]),
3232 LinePGetDatum(line))));
3236 on_sb(PG_FUNCTION_ARGS)
3238 LSEG *lseg = PG_GETARG_LSEG_P(0);
3239 BOX *box = PG_GETARG_BOX_P(1);
3241 PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
3242 PointPGetDatum(&lseg->p[0]),
3243 BoxPGetDatum(box))) &&
3244 DatumGetBool(DirectFunctionCall2(on_pb,
3245 PointPGetDatum(&lseg->p[1]),
3246 BoxPGetDatum(box))));
3249 /*---------------------------------------------------------------------
3251 * Whether one object intersects another.
3252 *-------------------------------------------------------------------*/
3255 inter_sl(PG_FUNCTION_ARGS)
3257 LSEG *lseg = PG_GETARG_LSEG_P(0);
3258 LINE *line = PG_GETARG_LINE_P(1);
3260 PG_RETURN_BOOL(has_interpt_sl(lseg, line));
3264 * Do line segment and box intersect?
3266 * Segment completely inside box counts as intersection.
3267 * If you want only segments crossing box boundaries,
3268 * try converting box to path first.
3270 * Optimize for non-intersection by checking for box intersection first.
3271 * - thomas 1998-01-30
3274 inter_sb(PG_FUNCTION_ARGS)
3276 LSEG *lseg = PG_GETARG_LSEG_P(0);
3277 BOX *box = PG_GETARG_BOX_P(1);
3282 lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
3283 lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
3284 lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
3285 lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
3287 /* nothing close to overlap? then not going to intersect */
3288 if (!box_ov(&lbox, box))
3289 PG_RETURN_BOOL(false);
3291 /* an endpoint of segment is inside box? then clearly intersects */
3292 if (DatumGetBool(DirectFunctionCall2(on_pb,
3293 PointPGetDatum(&lseg->p[0]),
3294 BoxPGetDatum(box))) ||
3295 DatumGetBool(DirectFunctionCall2(on_pb,
3296 PointPGetDatum(&lseg->p[1]),
3297 BoxPGetDatum(box))))
3298 PG_RETURN_BOOL(true);
3300 /* pairwise check lseg intersections */
3301 point.x = box->low.x;
3302 point.y = box->high.y;
3303 statlseg_construct(&bseg, &box->low, &point);
3304 if (lseg_intersect_internal(&bseg, lseg))
3305 PG_RETURN_BOOL(true);
3307 statlseg_construct(&bseg, &box->high, &point);
3308 if (lseg_intersect_internal(&bseg, lseg))
3309 PG_RETURN_BOOL(true);
3311 point.x = box->high.x;
3312 point.y = box->low.y;
3313 statlseg_construct(&bseg, &box->low, &point);
3314 if (lseg_intersect_internal(&bseg, lseg))
3315 PG_RETURN_BOOL(true);
3317 statlseg_construct(&bseg, &box->high, &point);
3318 if (lseg_intersect_internal(&bseg, lseg))
3319 PG_RETURN_BOOL(true);
3321 /* if we dropped through, no two segs intersected */
3322 PG_RETURN_BOOL(false);
3326 * Do line and box intersect?
3329 inter_lb(PG_FUNCTION_ARGS)
3331 LINE *line = PG_GETARG_LINE_P(0);
3332 BOX *box = PG_GETARG_BOX_P(1);
3337 /* pairwise check lseg intersections */
3342 statlseg_construct(&bseg, &p1, &p2);
3343 if (has_interpt_sl(&bseg, line))
3344 PG_RETURN_BOOL(true);
3347 statlseg_construct(&bseg, &p1, &p2);
3348 if (has_interpt_sl(&bseg, line))
3349 PG_RETURN_BOOL(true);
3352 statlseg_construct(&bseg, &p1, &p2);
3353 if (has_interpt_sl(&bseg, line))
3354 PG_RETURN_BOOL(true);
3357 statlseg_construct(&bseg, &p1, &p2);
3358 if (has_interpt_sl(&bseg, line))
3359 PG_RETURN_BOOL(true);
3361 /* if we dropped through, no intersection */
3362 PG_RETURN_BOOL(false);
3365 /*------------------------------------------------------------------
3366 * The following routines define a data type and operator class for
3367 * POLYGONS .... Part of which (the polygon's bounding box) is built on
3368 * top of the BOX data type.
3370 * make_bound_box - create the bounding box for the input polygon
3371 *------------------------------------------------------------------*/
3373 /*---------------------------------------------------------------------
3374 * Make the smallest bounding box for the given polygon.
3375 *---------------------------------------------------------------------*/
3377 make_bound_box(POLYGON *poly)
3387 x2 = x1 = poly->p[0].x;
3388 y2 = y1 = poly->p[0].y;
3389 for (i = 1; i < poly->npts; i++)
3391 if (poly->p[i].x < x1)
3393 if (poly->p[i].x > x2)
3395 if (poly->p[i].y < y1)
3397 if (poly->p[i].y > y2)
3401 box_fill(&(poly->boundbox), x1, x2, y1, y2);
3405 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3406 errmsg("cannot create bounding box for empty polygon")));
3409 /*------------------------------------------------------------------
3410 * poly_in - read in the polygon from a string specification
3413 * "((x0,y0),...,(xn,yn))"
3415 * also supports the older style "(x1,...,xn,y1,...yn)"
3416 *------------------------------------------------------------------*/
3418 poly_in(PG_FUNCTION_ARGS)
3420 char *str = PG_GETARG_CSTRING(0);
3427 if ((npts = pair_count(str, ',')) <= 0)
3429 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
3430 errmsg("invalid input syntax for type %s: \"%s\"",
3433 base_size = sizeof(poly->p[0]) * npts;
3434 size = offsetof(POLYGON, p) +base_size;
3436 /* Check for integer overflow */
3437 if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
3439 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
3440 errmsg("too many points requested")));
3442 poly = (POLYGON *) palloc0(size); /* zero any holes */
3444 SET_VARSIZE(poly, size);
3447 path_decode(str, false, npts, &(poly->p[0]), &isopen, NULL, "polygon", str);
3449 make_bound_box(poly);
3451 PG_RETURN_POLYGON_P(poly);
3454 /*---------------------------------------------------------------
3455 * poly_out - convert internal POLYGON representation to the
3456 * character string format "((f8,f8),...,(f8,f8))"
3457 *---------------------------------------------------------------*/
3459 poly_out(PG_FUNCTION_ARGS)
3461 POLYGON *poly = PG_GETARG_POLYGON_P(0);
3463 PG_RETURN_CSTRING(path_encode(PATH_CLOSED, poly->npts, poly->p));
3467 * poly_recv - converts external binary format to polygon
3469 * External representation is int32 number of points, and the points.
3470 * We recompute the bounding box on read, instead of trusting it to
3471 * be valid. (Checking it would take just as long, so may as well
3472 * omit it from external representation.)
3475 poly_recv(PG_FUNCTION_ARGS)
3477 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
3483 npts = pq_getmsgint(buf, sizeof(int32));
3484 if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(POLYGON, p)) / sizeof(Point)))
3486 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
3487 errmsg("invalid number of points in external \"polygon\" value")));
3489 size = offsetof(POLYGON, p) +sizeof(poly->p[0]) * npts;
3490 poly = (POLYGON *) palloc0(size); /* zero any holes */
3492 SET_VARSIZE(poly, size);
3495 for (i = 0; i < npts; i++)
3497 poly->p[i].x = pq_getmsgfloat8(buf);
3498 poly->p[i].y = pq_getmsgfloat8(buf);
3501 make_bound_box(poly);
3503 PG_RETURN_POLYGON_P(poly);
3507 * poly_send - converts polygon to binary format
3510 poly_send(PG_FUNCTION_ARGS)
3512 POLYGON *poly = PG_GETARG_POLYGON_P(0);
3516 pq_begintypsend(&buf);
3517 pq_sendint(&buf, poly->npts, sizeof(int32));
3518 for (i = 0; i < poly->npts; i++)
3520 pq_sendfloat8(&buf, poly->p[i].x);
3521 pq_sendfloat8(&buf, poly->p[i].y);
3523 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
3527 /*-------------------------------------------------------
3528 * Is polygon A strictly left of polygon B? i.e. is
3529 * the right most point of A left of the left most point
3531 *-------------------------------------------------------*/
3533 poly_left(PG_FUNCTION_ARGS)
3535 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3536 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3539 result = polya->boundbox.high.x < polyb->boundbox.low.x;
3542 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3544 PG_FREE_IF_COPY(polya, 0);
3545 PG_FREE_IF_COPY(polyb, 1);
3547 PG_RETURN_BOOL(result);
3550 /*-------------------------------------------------------
3551 * Is polygon A overlapping or left of polygon B? i.e. is
3552 * the right most point of A at or left of the right most point
3554 *-------------------------------------------------------*/
3556 poly_overleft(PG_FUNCTION_ARGS)
3558 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3559 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3562 result = polya->boundbox.high.x <= polyb->boundbox.high.x;
3565 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3567 PG_FREE_IF_COPY(polya, 0);
3568 PG_FREE_IF_COPY(polyb, 1);
3570 PG_RETURN_BOOL(result);
3573 /*-------------------------------------------------------
3574 * Is polygon A strictly right of polygon B? i.e. is
3575 * the left most point of A right of the right most point
3577 *-------------------------------------------------------*/
3579 poly_right(PG_FUNCTION_ARGS)
3581 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3582 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3585 result = polya->boundbox.low.x > polyb->boundbox.high.x;
3588 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3590 PG_FREE_IF_COPY(polya, 0);
3591 PG_FREE_IF_COPY(polyb, 1);
3593 PG_RETURN_BOOL(result);
3596 /*-------------------------------------------------------
3597 * Is polygon A overlapping or right of polygon B? i.e. is
3598 * the left most point of A at or right of the left most point
3600 *-------------------------------------------------------*/
3602 poly_overright(PG_FUNCTION_ARGS)
3604 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3605 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3608 result = polya->boundbox.low.x >= polyb->boundbox.low.x;
3611 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3613 PG_FREE_IF_COPY(polya, 0);
3614 PG_FREE_IF_COPY(polyb, 1);
3616 PG_RETURN_BOOL(result);
3619 /*-------------------------------------------------------
3620 * Is polygon A strictly below polygon B? i.e. is
3621 * the upper most point of A below the lower most point
3623 *-------------------------------------------------------*/
3625 poly_below(PG_FUNCTION_ARGS)
3627 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3628 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3631 result = polya->boundbox.high.y < polyb->boundbox.low.y;
3634 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3636 PG_FREE_IF_COPY(polya, 0);
3637 PG_FREE_IF_COPY(polyb, 1);
3639 PG_RETURN_BOOL(result);
3642 /*-------------------------------------------------------
3643 * Is polygon A overlapping or below polygon B? i.e. is
3644 * the upper most point of A at or below the upper most point
3646 *-------------------------------------------------------*/
3648 poly_overbelow(PG_FUNCTION_ARGS)
3650 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3651 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3654 result = polya->boundbox.high.y <= polyb->boundbox.high.y;
3657 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3659 PG_FREE_IF_COPY(polya, 0);
3660 PG_FREE_IF_COPY(polyb, 1);
3662 PG_RETURN_BOOL(result);
3665 /*-------------------------------------------------------
3666 * Is polygon A strictly above polygon B? i.e. is
3667 * the lower most point of A above the upper most point
3669 *-------------------------------------------------------*/
3671 poly_above(PG_FUNCTION_ARGS)
3673 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3674 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3677 result = polya->boundbox.low.y > polyb->boundbox.high.y;
3680 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3682 PG_FREE_IF_COPY(polya, 0);
3683 PG_FREE_IF_COPY(polyb, 1);
3685 PG_RETURN_BOOL(result);
3688 /*-------------------------------------------------------
3689 * Is polygon A overlapping or above polygon B? i.e. is
3690 * the lower most point of A at or above the lower most point
3692 *-------------------------------------------------------*/
3694 poly_overabove(PG_FUNCTION_ARGS)
3696 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3697 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3700 result = polya->boundbox.low.y >= polyb->boundbox.low.y;
3703 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3705 PG_FREE_IF_COPY(polya, 0);
3706 PG_FREE_IF_COPY(polyb, 1);
3708 PG_RETURN_BOOL(result);
3712 /*-------------------------------------------------------
3713 * Is polygon A the same as polygon B? i.e. are all the
3715 * Check all points for matches in both forward and reverse
3716 * direction since polygons are non-directional and are
3718 *-------------------------------------------------------*/
3720 poly_same(PG_FUNCTION_ARGS)
3722 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3723 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3726 if (polya->npts != polyb->npts)
3729 result = plist_same(polya->npts, polya->p, polyb->p);
3732 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3734 PG_FREE_IF_COPY(polya, 0);
3735 PG_FREE_IF_COPY(polyb, 1);
3737 PG_RETURN_BOOL(result);
3740 /*-----------------------------------------------------------------
3741 * Determine if polygon A overlaps polygon B
3742 *-----------------------------------------------------------------*/
3744 poly_overlap(PG_FUNCTION_ARGS)
3746 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3747 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3750 /* Quick check by bounding box */
3751 result = (polya->npts > 0 && polyb->npts > 0 &&
3752 box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
3755 * Brute-force algorithm - try to find intersected edges, if so then
3756 * polygons are overlapped else check is one polygon inside other or not
3757 * by testing single point of them.
3766 /* Init first of polya's edge with last point */
3767 sa.p[0] = polya->p[polya->npts - 1];
3770 for (ia = 0; ia < polya->npts && result == false; ia++)
3772 /* Second point of polya's edge is a current one */
3773 sa.p[1] = polya->p[ia];
3775 /* Init first of polyb's edge with last point */
3776 sb.p[0] = polyb->p[polyb->npts - 1];
3778 for (ib = 0; ib < polyb->npts && result == false; ib++)
3780 sb.p[1] = polyb->p[ib];
3781 result = lseg_intersect_internal(&sa, &sb);
3786 * move current endpoint to the first point of next edge
3791 if (result == false)
3793 result = (point_inside(polya->p, polyb->npts, polyb->p)
3795 point_inside(polyb->p, polya->npts, polya->p));
3800 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3802 PG_FREE_IF_COPY(polya, 0);
3803 PG_FREE_IF_COPY(polyb, 1);
3805 PG_RETURN_BOOL(result);
3809 * Tests special kind of segment for in/out of polygon.
3810 * Special kind means:
3811 * - point a should be on segment s
3812 * - segment (a,b) should not be contained by s
3814 * - segment (a,b) is collinear to s and (a,b) is in polygon
3815 * - segment (a,b) s not collinear to s. Note: that doesn't
3816 * mean that segment is in polygon!
3820 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
3822 /* point a is on s, b is not */
3828 #define POINTEQ(pt1, pt2) (FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
3829 if (POINTEQ(a, s->p))
3831 if (on_ps_internal(s->p + 1, &t))
3832 return lseg_inside_poly(b, s->p + 1, poly, start);
3834 else if (POINTEQ(a, s->p + 1))
3836 if (on_ps_internal(s->p, &t))
3837 return lseg_inside_poly(b, s->p, poly, start);
3839 else if (on_ps_internal(s->p, &t))
3841 return lseg_inside_poly(b, s->p, poly, start);
3843 else if (on_ps_internal(s->p + 1, &t))
3845 return lseg_inside_poly(b, s->p + 1, poly, start);
3848 return true; /* may be not true, but that will check later */
3852 * Returns true if segment (a,b) is in polygon, option
3853 * start is used for optimization - function checks
3854 * polygon's edges started from start
3857 lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
3863 intersection = false;
3867 s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
3869 for (i = start; i < poly->npts && res; i++)
3873 CHECK_FOR_INTERRUPTS();
3875 s.p[1] = poly->p[i];
3877 if (on_ps_internal(t.p, &s))
3879 if (on_ps_internal(t.p + 1, &s))
3880 return true; /* t is contained by s */
3883 res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
3885 else if (on_ps_internal(t.p + 1, &s))
3888 res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
3890 else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
3893 * segments are X-crossing, go to check each subsegment
3896 intersection = true;
3897 res = lseg_inside_poly(t.p, interpt, poly, i + 1);
3899 res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
3906 if (res && !intersection)
3911 * if X-intersection wasn't found then check central point of tested
3912 * segment. In opposite case we already check all subsegments
3914 p.x = (t.p[0].x + t.p[1].x) / 2.0;
3915 p.y = (t.p[0].y + t.p[1].y) / 2.0;
3917 res = point_inside(&p, poly->npts, poly->p);
3923 /*-----------------------------------------------------------------
3924 * Determine if polygon A contains polygon B.
3925 *-----------------------------------------------------------------*/
3927 poly_contain(PG_FUNCTION_ARGS)
3929 POLYGON *polya = PG_GETARG_POLYGON_P(0);
3930 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
3934 * Quick check to see if bounding box is contained.
3936 if (polya->npts > 0 && polyb->npts > 0 &&
3937 DatumGetBool(DirectFunctionCall2(box_contain,
3938 BoxPGetDatum(&polya->boundbox),
3939 BoxPGetDatum(&polyb->boundbox))))
3944 s.p[0] = polyb->p[polyb->npts - 1];
3947 for (i = 0; i < polyb->npts && result; i++)
3949 s.p[1] = polyb->p[i];
3950 result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
3960 * Avoid leaking memory for toasted inputs ... needed for rtree indexes
3962 PG_FREE_IF_COPY(polya, 0);
3963 PG_FREE_IF_COPY(polyb, 1);
3965 PG_RETURN_BOOL(result);
3969 /*-----------------------------------------------------------------
3970 * Determine if polygon A is contained by polygon B
3971 *-----------------------------------------------------------------*/
3973 poly_contained(PG_FUNCTION_ARGS)
3975 Datum polya = PG_GETARG_DATUM(0);
3976 Datum polyb = PG_GETARG_DATUM(1);
3978 /* Just switch the arguments and pass it off to poly_contain */
3979 PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
3984 poly_contain_pt(PG_FUNCTION_ARGS)
3986 POLYGON *poly = PG_GETARG_POLYGON_P(0);
3987 Point *p = PG_GETARG_POINT_P(1);
3989 PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
3993 pt_contained_poly(PG_FUNCTION_ARGS)
3995 Point *p = PG_GETARG_POINT_P(0);
3996 POLYGON *poly = PG_GETARG_POLYGON_P(1);
3998 PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
4003 poly_distance(PG_FUNCTION_ARGS)
4006 POLYGON *polya = PG_GETARG_POLYGON_P(0);
4007 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
4011 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4012 errmsg("function \"poly_distance\" not implemented")));
4018 /***********************************************************************
4020 ** Routines for 2D points.
4022 ***********************************************************************/
4025 construct_point(PG_FUNCTION_ARGS)
4027 float8 x = PG_GETARG_FLOAT8(0);
4028 float8 y = PG_GETARG_FLOAT8(1);
4030 PG_RETURN_POINT_P(point_construct(x, y));
4034 point_add(PG_FUNCTION_ARGS)
4036 Point *p1 = PG_GETARG_POINT_P(0);
4037 Point *p2 = PG_GETARG_POINT_P(1);
4040 result = (Point *) palloc(sizeof(Point));
4042 result->x = (p1->x + p2->x);
4043 result->y = (p1->y + p2->y);
4045 PG_RETURN_POINT_P(result);
4049 point_sub(PG_FUNCTION_ARGS)
4051 Point *p1 = PG_GETARG_POINT_P(0);
4052 Point *p2 = PG_GETARG_POINT_P(1);
4055 result = (Point *) palloc(sizeof(Point));
4057 result->x = (p1->x - p2->x);
4058 result->y = (p1->y - p2->y);
4060 PG_RETURN_POINT_P(result);
4064 point_mul(PG_FUNCTION_ARGS)
4066 Point *p1 = PG_GETARG_POINT_P(0);
4067 Point *p2 = PG_GETARG_POINT_P(1);
4070 result = (Point *) palloc(sizeof(Point));
4072 result->x = (p1->x * p2->x) - (p1->y * p2->y);
4073 result->y = (p1->x * p2->y) + (p1->y * p2->x);
4075 PG_RETURN_POINT_P(result);
4079 point_div(PG_FUNCTION_ARGS)
4081 Point *p1 = PG_GETARG_POINT_P(0);
4082 Point *p2 = PG_GETARG_POINT_P(1);
4086 result = (Point *) palloc(sizeof(Point));
4088 div = (p2->x * p2->x) + (p2->y * p2->y);
4092 (errcode(ERRCODE_DIVISION_BY_ZERO),
4093 errmsg("division by zero")));
4095 result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
4096 result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
4098 PG_RETURN_POINT_P(result);
4102 /***********************************************************************
4104 ** Routines for 2D boxes.
4106 ***********************************************************************/
4109 points_box(PG_FUNCTION_ARGS)
4111 Point *p1 = PG_GETARG_POINT_P(0);
4112 Point *p2 = PG_GETARG_POINT_P(1);
4114 PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
4118 box_add(PG_FUNCTION_ARGS)
4120 BOX *box = PG_GETARG_BOX_P(0);
4121 Point *p = PG_GETARG_POINT_P(1);
4123 PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
4124 (box->low.x + p->x),
4125 (box->high.y + p->y),
4126 (box->low.y + p->y)));
4130 box_sub(PG_FUNCTION_ARGS)
4132 BOX *box = PG_GETARG_BOX_P(0);
4133 Point *p = PG_GETARG_POINT_P(1);
4135 PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
4136 (box->low.x - p->x),
4137 (box->high.y - p->y),
4138 (box->low.y - p->y)));
4142 box_mul(PG_FUNCTION_ARGS)
4144 BOX *box = PG_GETARG_BOX_P(0);
4145 Point *p = PG_GETARG_POINT_P(1);
4150 high = DatumGetPointP(DirectFunctionCall2(point_mul,
4151 PointPGetDatum(&box->high),
4152 PointPGetDatum(p)));
4153 low = DatumGetPointP(DirectFunctionCall2(point_mul,
4154 PointPGetDatum(&box->low),
4155 PointPGetDatum(p)));
4157 result = box_construct(high->x, low->x, high->y, low->y);
4159 PG_RETURN_BOX_P(result);
4163 box_div(PG_FUNCTION_ARGS)
4165 BOX *box = PG_GETARG_BOX_P(0);
4166 Point *p = PG_GETARG_POINT_P(1);
4171 high = DatumGetPointP(DirectFunctionCall2(point_div,
4172 PointPGetDatum(&box->high),
4173 PointPGetDatum(p)));
4174 low = DatumGetPointP(DirectFunctionCall2(point_div,
4175 PointPGetDatum(&box->low),
4176 PointPGetDatum(p)));
4178 result = box_construct(high->x, low->x, high->y, low->y);
4180 PG_RETURN_BOX_P(result);
4184 * Convert point to empty box
4187 point_box(PG_FUNCTION_ARGS)
4189 Point *pt = PG_GETARG_POINT_P(0);
4192 box = (BOX *) palloc(sizeof(BOX));
4194 box->high.x = pt->x;
4196 box->high.y = pt->y;
4199 PG_RETURN_BOX_P(box);
4203 * Smallest bounding box that includes both of the given boxes
4206 boxes_bound_box(PG_FUNCTION_ARGS)
4208 BOX *box1 = PG_GETARG_BOX_P(0),
4209 *box2 = PG_GETARG_BOX_P(1),
4212 container = (BOX *) palloc(sizeof(BOX));
4214 container->high.x = Max(box1->high.x, box2->high.x);
4215 container->low.x = Min(box1->low.x, box2->low.x);
4216 container->high.y = Max(box1->high.y, box2->high.y);
4217 container->low.y = Min(box1->low.y, box2->low.y);
4219 PG_RETURN_BOX_P(container);
4223 /***********************************************************************
4225 ** Routines for 2D paths.
4227 ***********************************************************************/
4230 * Concatenate two paths (only if they are both open).
4233 path_add(PG_FUNCTION_ARGS)
4235 PATH *p1 = PG_GETARG_PATH_P(0);
4236 PATH *p2 = PG_GETARG_PATH_P(1);
4242 if (p1->closed || p2->closed)
4245 base_size = sizeof(p1->p[0]) * (p1->npts + p2->npts);
4246 size = offsetof(PATH, p) +base_size;
4248 /* Check for integer overflow */
4249 if (base_size / sizeof(p1->p[0]) != (p1->npts + p2->npts) ||
4252 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
4253 errmsg("too many points requested")));
4255 result = (PATH *) palloc(size);
4257 SET_VARSIZE(result, size);
4258 result->npts = (p1->npts + p2->npts);
4259 result->closed = p1->closed;
4260 /* prevent instability in unused pad bytes */
4263 for (i = 0; i < p1->npts; i++)
4265 result->p[i].x = p1->p[i].x;
4266 result->p[i].y = p1->p[i].y;
4268 for (i = 0; i < p2->npts; i++)
4270 result->p[i + p1->npts].x = p2->p[i].x;
4271 result->p[i + p1->npts].y = p2->p[i].y;
4274 PG_RETURN_PATH_P(result);
4278 * Translation operators.
4281 path_add_pt(PG_FUNCTION_ARGS)
4283 PATH *path = PG_GETARG_PATH_P_COPY(0);
4284 Point *point = PG_GETARG_POINT_P(1);
4287 for (i = 0; i < path->npts; i++)
4289 path->p[i].x += point->x;
4290 path->p[i].y += point->y;
4293 PG_RETURN_PATH_P(path);
4297 path_sub_pt(PG_FUNCTION_ARGS)
4299 PATH *path = PG_GETARG_PATH_P_COPY(0);
4300 Point *point = PG_GETARG_POINT_P(1);
4303 for (i = 0; i < path->npts; i++)
4305 path->p[i].x -= point->x;
4306 path->p[i].y -= point->y;
4309 PG_RETURN_PATH_P(path);
4313 * Rotation and scaling operators.
4316 path_mul_pt(PG_FUNCTION_ARGS)
4318 PATH *path = PG_GETARG_PATH_P_COPY(0);
4319 Point *point = PG_GETARG_POINT_P(1);
4323 for (i = 0; i < path->npts; i++)
4325 p = DatumGetPointP(DirectFunctionCall2(point_mul,
4326 PointPGetDatum(&path->p[i]),
4327 PointPGetDatum(point)));
4328 path->p[i].x = p->x;
4329 path->p[i].y = p->y;
4332 PG_RETURN_PATH_P(path);
4336 path_div_pt(PG_FUNCTION_ARGS)
4338 PATH *path = PG_GETARG_PATH_P_COPY(0);
4339 Point *point = PG_GETARG_POINT_P(1);
4343 for (i = 0; i < path->npts; i++)
4345 p = DatumGetPointP(DirectFunctionCall2(point_div,
4346 PointPGetDatum(&path->p[i]),
4347 PointPGetDatum(point)));
4348 path->p[i].x = p->x;
4349 path->p[i].y = p->y;
4352 PG_RETURN_PATH_P(path);
4357 path_center(PG_FUNCTION_ARGS)
4360 PATH *path = PG_GETARG_PATH_P(0);
4364 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4365 errmsg("function \"path_center\" not implemented")));
4371 path_poly(PG_FUNCTION_ARGS)
4373 PATH *path = PG_GETARG_PATH_P(0);
4378 /* This is not very consistent --- other similar cases return NULL ... */
4381 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4382 errmsg("open path cannot be converted to polygon")));
4385 * Never overflows: the old size fit in MaxAllocSize, and the new size is
4386 * just a small constant larger.
4388 size = offsetof(POLYGON, p) +sizeof(poly->p[0]) * path->npts;
4389 poly = (POLYGON *) palloc(size);
4391 SET_VARSIZE(poly, size);
4392 poly->npts = path->npts;
4394 for (i = 0; i < path->npts; i++)
4396 poly->p[i].x = path->p[i].x;
4397 poly->p[i].y = path->p[i].y;
4400 make_bound_box(poly);
4402 PG_RETURN_POLYGON_P(poly);
4406 /***********************************************************************
4408 ** Routines for 2D polygons.
4410 ***********************************************************************/
4413 poly_npoints(PG_FUNCTION_ARGS)
4415 POLYGON *poly = PG_GETARG_POLYGON_P(0);
4417 PG_RETURN_INT32(poly->npts);
4422 poly_center(PG_FUNCTION_ARGS)
4424 POLYGON *poly = PG_GETARG_POLYGON_P(0);
4428 circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
4429 PolygonPGetDatum(poly)));
4430 result = DirectFunctionCall1(circle_center,
4431 CirclePGetDatum(circle));
4433 PG_RETURN_DATUM(result);
4438 poly_box(PG_FUNCTION_ARGS)
4440 POLYGON *poly = PG_GETARG_POLYGON_P(0);
4446 box = box_copy(&poly->boundbox);
4448 PG_RETURN_BOX_P(box);
4453 * Convert a box to a polygon.
4456 box_poly(PG_FUNCTION_ARGS)
4458 BOX *box = PG_GETARG_BOX_P(0);
4462 /* map four corners of the box to a polygon */
4463 size = offsetof(POLYGON, p) +sizeof(poly->p[0]) * 4;
4464 poly = (POLYGON *) palloc(size);
4466 SET_VARSIZE(poly, size);
4469 poly->p[0].x = box->low.x;
4470 poly->p[0].y = box->low.y;
4471 poly->p[1].x = box->low.x;
4472 poly->p[1].y = box->high.y;
4473 poly->p[2].x = box->high.x;
4474 poly->p[2].y = box->high.y;
4475 poly->p[3].x = box->high.x;
4476 poly->p[3].y = box->low.y;
4478 box_fill(&poly->boundbox, box->high.x, box->low.x,
4479 box->high.y, box->low.y);
4481 PG_RETURN_POLYGON_P(poly);
4486 poly_path(PG_FUNCTION_ARGS)
4488 POLYGON *poly = PG_GETARG_POLYGON_P(0);
4494 * Never overflows: the old size fit in MaxAllocSize, and the new size is
4495 * smaller by a small constant.
4497 size = offsetof(PATH, p) +sizeof(path->p[0]) * poly->npts;
4498 path = (PATH *) palloc(size);
4500 SET_VARSIZE(path, size);
4501 path->npts = poly->npts;
4502 path->closed = TRUE;
4503 /* prevent instability in unused pad bytes */
4506 for (i = 0; i < poly->npts; i++)
4508 path->p[i].x = poly->p[i].x;
4509 path->p[i].y = poly->p[i].y;
4512 PG_RETURN_PATH_P(path);
4516 /***********************************************************************
4518 ** Routines for circles.
4520 ***********************************************************************/
4522 /*----------------------------------------------------------
4523 * Formatting and conversion routines.
4524 *---------------------------------------------------------*/
4526 /* circle_in - convert a string to internal form.
4528 * External format: (center and radius of circle)
4530 * also supports quick entry style "(f8,f8,f8)"
4533 circle_in(PG_FUNCTION_ARGS)
4535 char *str = PG_GETARG_CSTRING(0);
4536 CIRCLE *circle = (CIRCLE *) palloc(sizeof(CIRCLE));
4542 while (isspace((unsigned char) *s))
4544 if ((*s == LDELIM_C) || (*s == LDELIM))
4548 while (isspace((unsigned char) *cp))
4554 pair_decode(s, &circle->center.x, &circle->center.y, &s, "circle", str);
4559 circle->radius = single_decode(s, &s, "circle", str);
4560 if (circle->radius < 0)
4562 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
4563 errmsg("invalid input syntax for type %s: \"%s\"",
4569 || ((*s == RDELIM_C) && (depth == 1)))
4573 while (isspace((unsigned char) *s))
4578 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
4579 errmsg("invalid input syntax for type %s: \"%s\"",
4585 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
4586 errmsg("invalid input syntax for type %s: \"%s\"",
4589 PG_RETURN_CIRCLE_P(circle);
4592 /* circle_out - convert a circle to external form.
4595 circle_out(PG_FUNCTION_ARGS)
4597 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
4600 initStringInfo(&str);
4602 appendStringInfoChar(&str, LDELIM_C);
4603 appendStringInfoChar(&str, LDELIM);
4604 pair_encode(circle->center.x, circle->center.y, &str);
4605 appendStringInfoChar(&str, RDELIM);
4606 appendStringInfoChar(&str, DELIM);
4607 single_encode(circle->radius, &str);
4608 appendStringInfoChar(&str, RDELIM_C);
4610 PG_RETURN_CSTRING(str.data);
4614 * circle_recv - converts external binary format to circle
4617 circle_recv(PG_FUNCTION_ARGS)
4619 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
4622 circle = (CIRCLE *) palloc(sizeof(CIRCLE));
4624 circle->center.x = pq_getmsgfloat8(buf);
4625 circle->center.y = pq_getmsgfloat8(buf);
4626 circle->radius = pq_getmsgfloat8(buf);
4628 if (circle->radius < 0)
4630 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
4631 errmsg("invalid radius in external \"circle\" value")));
4633 PG_RETURN_CIRCLE_P(circle);
4637 * circle_send - converts circle to binary format
4640 circle_send(PG_FUNCTION_ARGS)
4642 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
4645 pq_begintypsend(&buf);
4646 pq_sendfloat8(&buf, circle->center.x);
4647 pq_sendfloat8(&buf, circle->center.y);
4648 pq_sendfloat8(&buf, circle->radius);
4649 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
4653 /*----------------------------------------------------------
4654 * Relational operators for CIRCLEs.
4655 * <, >, <=, >=, and == are based on circle area.
4656 *---------------------------------------------------------*/
4658 /* circles identical?
4661 circle_same(PG_FUNCTION_ARGS)
4663 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4664 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4666 PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
4667 FPeq(circle1->center.x, circle2->center.x) &&
4668 FPeq(circle1->center.y, circle2->center.y));
4671 /* circle_overlap - does circle1 overlap circle2?
4674 circle_overlap(PG_FUNCTION_ARGS)
4676 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4677 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4679 PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
4680 circle1->radius + circle2->radius));
4683 /* circle_overleft - is the right edge of circle1 at or left of
4684 * the right edge of circle2?
4687 circle_overleft(PG_FUNCTION_ARGS)
4689 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4690 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4692 PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
4693 (circle2->center.x + circle2->radius)));
4696 /* circle_left - is circle1 strictly left of circle2?
4699 circle_left(PG_FUNCTION_ARGS)
4701 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4702 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4704 PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
4705 (circle2->center.x - circle2->radius)));
4708 /* circle_right - is circle1 strictly right of circle2?
4711 circle_right(PG_FUNCTION_ARGS)
4713 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4714 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4716 PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
4717 (circle2->center.x + circle2->radius)));
4720 /* circle_overright - is the left edge of circle1 at or right of
4721 * the left edge of circle2?
4724 circle_overright(PG_FUNCTION_ARGS)
4726 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4727 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4729 PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
4730 (circle2->center.x - circle2->radius)));
4733 /* circle_contained - is circle1 contained by circle2?
4736 circle_contained(PG_FUNCTION_ARGS)
4738 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4739 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4741 PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
4744 /* circle_contain - does circle1 contain circle2?
4747 circle_contain(PG_FUNCTION_ARGS)
4749 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4750 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4752 PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
4756 /* circle_below - is circle1 strictly below circle2?
4759 circle_below(PG_FUNCTION_ARGS)
4761 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4762 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4764 PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
4765 (circle2->center.y - circle2->radius)));
4768 /* circle_above - is circle1 strictly above circle2?
4771 circle_above(PG_FUNCTION_ARGS)
4773 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4774 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4776 PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
4777 (circle2->center.y + circle2->radius)));
4780 /* circle_overbelow - is the upper edge of circle1 at or below
4781 * the upper edge of circle2?
4784 circle_overbelow(PG_FUNCTION_ARGS)
4786 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4787 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4789 PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
4790 (circle2->center.y + circle2->radius)));
4793 /* circle_overabove - is the lower edge of circle1 at or above
4794 * the lower edge of circle2?
4797 circle_overabove(PG_FUNCTION_ARGS)
4799 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4800 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4802 PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
4803 (circle2->center.y - circle2->radius)));
4807 /* circle_relop - is area(circle1) relop area(circle2), within
4808 * our accuracy constraint?
4811 circle_eq(PG_FUNCTION_ARGS)
4813 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4814 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4816 PG_RETURN_BOOL(FPeq(circle_ar(circle1), circle_ar(circle2)));
4820 circle_ne(PG_FUNCTION_ARGS)
4822 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4823 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4825 PG_RETURN_BOOL(FPne(circle_ar(circle1), circle_ar(circle2)));
4829 circle_lt(PG_FUNCTION_ARGS)
4831 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4832 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4834 PG_RETURN_BOOL(FPlt(circle_ar(circle1), circle_ar(circle2)));
4838 circle_gt(PG_FUNCTION_ARGS)
4840 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4841 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4843 PG_RETURN_BOOL(FPgt(circle_ar(circle1), circle_ar(circle2)));
4847 circle_le(PG_FUNCTION_ARGS)
4849 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4850 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4852 PG_RETURN_BOOL(FPle(circle_ar(circle1), circle_ar(circle2)));
4856 circle_ge(PG_FUNCTION_ARGS)
4858 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
4859 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
4861 PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
4865 /*----------------------------------------------------------
4866 * "Arithmetic" operators on circles.
4867 *---------------------------------------------------------*/
4870 circle_copy(CIRCLE *circle)
4874 if (!PointerIsValid(circle))
4877 result = (CIRCLE *) palloc(sizeof(CIRCLE));
4878 memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
4884 * Translation operator.
4887 circle_add_pt(PG_FUNCTION_ARGS)
4889 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
4890 Point *point = PG_GETARG_POINT_P(1);
4893 result = circle_copy(circle);
4895 result->center.x += point->x;
4896 result->center.y += point->y;
4898 PG_RETURN_CIRCLE_P(result);
4902 circle_sub_pt(PG_FUNCTION_ARGS)
4904 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
4905 Point *point = PG_GETARG_POINT_P(1);
4908 result = circle_copy(circle);
4910 result->center.x -= point->x;
4911 result->center.y -= point->y;
4913 PG_RETURN_CIRCLE_P(result);
4918 * Rotation and scaling operators.
4921 circle_mul_pt(PG_FUNCTION_ARGS)
4923 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
4924 Point *point = PG_GETARG_POINT_P(1);
4928 result = circle_copy(circle);
4930 p = DatumGetPointP(DirectFunctionCall2(point_mul,
4931 PointPGetDatum(&circle->center),
4932 PointPGetDatum(point)));
4933 result->center.x = p->x;
4934 result->center.y = p->y;
4935 result->radius *= HYPOT(point->x, point->y);
4937 PG_RETURN_CIRCLE_P(result);
4941 circle_div_pt(PG_FUNCTION_ARGS)
4943 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
4944 Point *point = PG_GETARG_POINT_P(1);
4948 result = circle_copy(circle);
4950 p = DatumGetPointP(DirectFunctionCall2(point_div,
4951 PointPGetDatum(&circle->center),
4952 PointPGetDatum(point)));
4953 result->center.x = p->x;
4954 result->center.y = p->y;
4955 result->radius /= HYPOT(point->x, point->y);
4957 PG_RETURN_CIRCLE_P(result);
4961 /* circle_area - returns the area of the circle.
4964 circle_area(PG_FUNCTION_ARGS)
4966 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
4968 PG_RETURN_FLOAT8(circle_ar(circle));
4972 /* circle_diameter - returns the diameter of the circle.
4975 circle_diameter(PG_FUNCTION_ARGS)
4977 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
4979 PG_RETURN_FLOAT8(2 * circle->radius);
4983 /* circle_radius - returns the radius of the circle.
4986 circle_radius(PG_FUNCTION_ARGS)
4988 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
4990 PG_RETURN_FLOAT8(circle->radius);
4994 /* circle_distance - returns the distance between
4998 circle_distance(PG_FUNCTION_ARGS)
5000 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
5001 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
5004 result = point_dt(&circle1->center, &circle2->center)
5005 - (circle1->radius + circle2->radius);
5008 PG_RETURN_FLOAT8(result);
5013 circle_contain_pt(PG_FUNCTION_ARGS)
5015 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
5016 Point *point = PG_GETARG_POINT_P(1);
5019 d = point_dt(&circle->center, point);
5020 PG_RETURN_BOOL(d <= circle->radius);
5025 pt_contained_circle(PG_FUNCTION_ARGS)
5027 Point *point = PG_GETARG_POINT_P(0);
5028 CIRCLE *circle = PG_GETARG_CIRCLE_P(1);
5031 d = point_dt(&circle->center, point);
5032 PG_RETURN_BOOL(d <= circle->radius);
5036 /* dist_pc - returns the distance between
5037 * a point and a circle.
5040 dist_pc(PG_FUNCTION_ARGS)
5042 Point *point = PG_GETARG_POINT_P(0);
5043 CIRCLE *circle = PG_GETARG_CIRCLE_P(1);
5046 result = point_dt(point, &circle->center) - circle->radius;
5049 PG_RETURN_FLOAT8(result);
5053 * Distance from a circle to a point
5056 dist_cpoint(PG_FUNCTION_ARGS)
5058 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
5059 Point *point = PG_GETARG_POINT_P(1);
5062 result = point_dt(point, &circle->center) - circle->radius;
5065 PG_RETURN_FLOAT8(result);
5068 /* circle_center - returns the center point of the circle.
5071 circle_center(PG_FUNCTION_ARGS)
5073 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
5076 result = (Point *) palloc(sizeof(Point));
5077 result->x = circle->center.x;
5078 result->y = circle->center.y;
5080 PG_RETURN_POINT_P(result);
5084 /* circle_ar - returns the area of the circle.
5087 circle_ar(CIRCLE *circle)
5089 return M_PI * (circle->radius * circle->radius);
5093 /*----------------------------------------------------------
5094 * Conversion operators.
5095 *---------------------------------------------------------*/
5098 cr_circle(PG_FUNCTION_ARGS)
5100 Point *center = PG_GETARG_POINT_P(0);
5101 float8 radius = PG_GETARG_FLOAT8(1);
5104 result = (CIRCLE *) palloc(sizeof(CIRCLE));
5106 result->center.x = center->x;
5107 result->center.y = center->y;
5108 result->radius = radius;
5110 PG_RETURN_CIRCLE_P(result);
5114 circle_box(PG_FUNCTION_ARGS)
5116 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
5120 box = (BOX *) palloc(sizeof(BOX));
5122 delta = circle->radius / sqrt(2.0);
5124 box->high.x = circle->center.x + delta;
5125 box->low.x = circle->center.x - delta;
5126 box->high.y = circle->center.y + delta;
5127 box->low.y = circle->center.y - delta;
5129 PG_RETURN_BOX_P(box);
5133 * Convert a box to a circle.
5136 box_circle(PG_FUNCTION_ARGS)
5138 BOX *box = PG_GETARG_BOX_P(0);
5141 circle = (CIRCLE *) palloc(sizeof(CIRCLE));
5143 circle->center.x = (box->high.x + box->low.x) / 2;
5144 circle->center.y = (box->high.y + box->low.y) / 2;
5146 circle->radius = point_dt(&circle->center, &box->high);
5148 PG_RETURN_CIRCLE_P(circle);
5153 circle_poly(PG_FUNCTION_ARGS)
5155 int32 npts = PG_GETARG_INT32(0);
5156 CIRCLE *circle = PG_GETARG_CIRCLE_P(1);
5164 if (FPzero(circle->radius))
5166 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
5167 errmsg("cannot convert circle with radius zero to polygon")));
5171 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5172 errmsg("must request at least 2 points")));
5174 base_size = sizeof(poly->p[0]) * npts;
5175 size = offsetof(POLYGON, p) +base_size;
5177 /* Check for integer overflow */
5178 if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
5180 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
5181 errmsg("too many points requested")));
5183 poly = (POLYGON *) palloc0(size); /* zero any holes */
5184 SET_VARSIZE(poly, size);
5187 anglestep = (2.0 * M_PI) / npts;
5189 for (i = 0; i < npts; i++)
5191 angle = i * anglestep;
5192 poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
5193 poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
5196 make_bound_box(poly);
5198 PG_RETURN_POLYGON_P(poly);
5201 /* poly_circle - convert polygon to circle
5203 * XXX This algorithm should use weighted means of line segments
5204 * rather than straight average values of points - tgl 97/01/21.
5207 poly_circle(PG_FUNCTION_ARGS)
5209 POLYGON *poly = PG_GETARG_POLYGON_P(0);
5215 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
5216 errmsg("cannot convert empty polygon to circle")));
5218 circle = (CIRCLE *) palloc(sizeof(CIRCLE));
5220 circle->center.x = 0;
5221 circle->center.y = 0;
5224 for (i = 0; i < poly->npts; i++)
5226 circle->center.x += poly->p[i].x;
5227 circle->center.y += poly->p[i].y;
5229 circle->center.x /= poly->npts;
5230 circle->center.y /= poly->npts;
5232 for (i = 0; i < poly->npts; i++)
5233 circle->radius += point_dt(&poly->p[i], &circle->center);
5234 circle->radius /= poly->npts;
5236 PG_RETURN_CIRCLE_P(circle);
5240 /***********************************************************************
5242 ** Private routines for multiple types.
5244 ***********************************************************************/
5247 * Test to see if the point is inside the polygon, returns 1/0, or 2 if
5248 * the point is on the polygon.
5249 * Code adapted but not copied from integer-based routines in WN: A
5250 * Server for the HTTP
5251 * version 1.15.1, file wn/image.c
5252 * http://hopf.math.northwestern.edu/index.html
5253 * Description of algorithm: http://www.linuxjournal.com/article/2197
5254 * http://www.linuxjournal.com/article/2029
5257 #define POINT_ON_POLYGON INT_MAX
5260 point_inside(Point *p, int npts, Point *plist)
5275 /* compute first polygon point relative to single point */
5276 x0 = plist[0].x - p->x;
5277 y0 = plist[0].y - p->y;
5281 /* loop over polygon points and aggregate total_cross */
5282 for (i = 1; i < npts; i++)
5284 /* compute next polygon point relative to single point */
5285 x = plist[i].x - p->x;
5286 y = plist[i].y - p->y;
5288 /* compute previous to current point crossing */
5289 if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
5291 total_cross += cross;
5297 /* now do the first point */
5298 if ((cross = lseg_crossing(x0, y0, prev_x, prev_y)) == POINT_ON_POLYGON)
5300 total_cross += cross;
5302 if (total_cross != 0)
5309 * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
5310 * Returns +/-1 if one point is on the positive X-axis.
5311 * Returns 0 if both points are on the positive X-axis, or there is no crossing.
5312 * Returns POINT_ON_POLYGON if the segment contains (0,0).
5313 * Wow, that is one confusing API, but it is used above, and when summed,
5314 * can tell is if a point is in a polygon.
5318 lseg_crossing(double x, double y, double prev_x, double prev_y)
5324 { /* y == 0, on X axis */
5325 if (FPzero(x)) /* (x,y) is (0,0)? */
5326 return POINT_ON_POLYGON;
5327 else if (FPgt(x, 0))
5329 if (FPzero(prev_y)) /* y and prev_y are zero */
5331 return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
5332 return FPlt(prev_y, 0) ? 1 : -1;
5335 { /* x < 0, x not on positive X axis */
5338 return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
5344 /* compute y crossing direction from previous point */
5345 y_sign = FPgt(y, 0) ? 1 : -1;
5348 /* previous point was on X axis, so new point is either off or on */
5349 return FPlt(prev_x, 0) ? 0 : y_sign;
5350 else if (FPgt(y_sign * prev_y, 0))
5351 /* both above or below X axis */
5352 return 0; /* same sign */
5354 { /* y and prev_y cross X-axis */
5355 if (FPge(x, 0) && FPgt(prev_x, 0))
5356 /* both non-negative so cross positive X-axis */
5358 if (FPlt(x, 0) && FPle(prev_x, 0))
5359 /* both non-positive so do not cross positive X-axis */
5362 /* x and y cross axises, see URL above point_inside() */
5363 z = (x - prev_x) * y - (y - prev_y) * x;
5365 return POINT_ON_POLYGON;
5366 return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
5373 plist_same(int npts, Point *p1, Point *p2)
5379 /* find match for first point */
5380 for (i = 0; i < npts; i++)
5382 if ((FPeq(p2[i].x, p1[0].x))
5383 && (FPeq(p2[i].y, p1[0].y)))
5386 /* match found? then look forward through remaining points */
5387 for (ii = 1, j = i + 1; ii < npts; ii++, j++)
5391 if ((!FPeq(p2[j].x, p1[ii].x))
5392 || (!FPeq(p2[j].y, p1[ii].y)))
5395 printf("plist_same- %d failed forward match with %d\n", j, ii);
5401 printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
5406 /* match not found forwards? then look backwards */
5407 for (ii = 1, j = i - 1; ii < npts; ii++, j--)
5411 if ((!FPeq(p2[j].x, p1[ii].x))
5412 || (!FPeq(p2[j].y, p1[ii].y)))
5415 printf("plist_same- %d failed reverse match with %d\n", j, ii);
5421 printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
5432 /*-------------------------------------------------------------------------
5433 * Determine the hypotenuse.
5435 * If required, x and y are swapped to make x the larger number. The
5436 * traditional formula of x^2+y^2 is rearranged to factor x outside the
5437 * sqrt. This allows computation of the hypotenuse for significantly
5438 * larger values, and with a higher precision than when using the naive
5439 * formula. In particular, this cannot overflow unless the final result
5440 * would be out-of-range.
5442 * sqrt( x^2 + y^2 ) = sqrt( x^2( 1 + y^2/x^2) )
5443 * = x * sqrt( 1 + y^2/x^2 )
5444 * = x * sqrt( 1 + y/x * y/x )
5446 * It is expected that this routine will eventually be replaced with the
5447 * C99 hypot() function.
5449 * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
5450 * case of hypot(inf,nan) results in INF, and not NAN.
5451 *-----------------------------------------------------------------------
5454 pg_hypot(double x, double y)
5458 /* Handle INF and NaN properly */
5459 if (isinf(x) || isinf(y))
5460 return get_float8_infinity();
5462 if (isnan(x) || isnan(y))
5463 return get_float8_nan();
5465 /* Else, drop any minus signs */
5469 /* Swap x and y if needed to make x the larger one */
5479 * If y is zero, the hypotenuse is x. This test saves a few cycles in
5480 * such cases, but more importantly it also protects against
5481 * divide-by-zero errors, since now x >= y.
5486 /* Determine the hypotenuse */
5488 return x * sqrt(1.0 + (yx * yx));