00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include <math.h>
00018 #include <limits.h>
00019 #include <float.h>
00020 #include <ctype.h>
00021
00022 #include "libpq/pqformat.h"
00023 #include "utils/builtins.h"
00024 #include "utils/geo_decls.h"
00025
00026 #ifndef M_PI
00027 #define M_PI 3.14159265358979323846
00028 #endif
00029
00030
00031
00032
00033
00034
00035 static int point_inside(Point *p, int npts, Point *plist);
00036 static int lseg_crossing(double x, double y, double px, double py);
00037 static BOX *box_construct(double x1, double x2, double y1, double y2);
00038 static BOX *box_copy(BOX *box);
00039 static BOX *box_fill(BOX *result, double x1, double x2, double y1, double y2);
00040 static bool box_ov(BOX *box1, BOX *box2);
00041 static double box_ht(BOX *box);
00042 static double box_wd(BOX *box);
00043 static double circle_ar(CIRCLE *circle);
00044 static CIRCLE *circle_copy(CIRCLE *circle);
00045 static LINE *line_construct_pm(Point *pt, double m);
00046 static void line_construct_pts(LINE *line, Point *pt1, Point *pt2);
00047 static bool lseg_intersect_internal(LSEG *l1, LSEG *l2);
00048 static double lseg_dt(LSEG *l1, LSEG *l2);
00049 static bool on_ps_internal(Point *pt, LSEG *lseg);
00050 static void make_bound_box(POLYGON *poly);
00051 static bool plist_same(int npts, Point *p1, Point *p2);
00052 static Point *point_construct(double x, double y);
00053 static Point *point_copy(Point *pt);
00054 static int single_decode(char *str, float8 *x, char **ss);
00055 static int single_encode(float8 x, char *str);
00056 static int pair_decode(char *str, float8 *x, float8 *y, char **s);
00057 static int pair_encode(float8 x, float8 y, char *str);
00058 static int pair_count(char *s, char delim);
00059 static int path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p);
00060 static char *path_encode(bool closed, int npts, Point *pt);
00061 static void statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2);
00062 static double box_ar(BOX *box);
00063 static void box_cn(Point *center, BOX *box);
00064 static Point *interpt_sl(LSEG *lseg, LINE *line);
00065 static bool has_interpt_sl(LSEG *lseg, LINE *line);
00066 static double dist_pl_internal(Point *pt, LINE *line);
00067 static double dist_ps_internal(Point *pt, LSEG *lseg);
00068 static Point *line_interpt_internal(LINE *l1, LINE *l2);
00069 static bool lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start);
00070 static Point *lseg_interpt_internal(LSEG *l1, LSEG *l2);
00071
00072
00073
00074
00075
00076
00077
00078
00079 #define LDELIM '('
00080 #define RDELIM ')'
00081 #define DELIM ','
00082 #define LDELIM_EP '['
00083 #define RDELIM_EP ']'
00084 #define LDELIM_C '<'
00085 #define RDELIM_C '>'
00086
00087
00088
00089 #define P_MAXLEN (2*(DBL_DIG+3+7)+1)
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117 static int
00118 single_decode(char *str, float8 *x, char **s)
00119 {
00120 char *cp;
00121
00122 if (!PointerIsValid(str))
00123 return FALSE;
00124
00125 while (isspace((unsigned char) *str))
00126 str++;
00127 *x = strtod(str, &cp);
00128 #ifdef GEODEBUG
00129 printf("single_decode- (%x) try decoding %s to %g\n", (cp - str), str, *x);
00130 #endif
00131 if (cp <= str)
00132 return FALSE;
00133 while (isspace((unsigned char) *cp))
00134 cp++;
00135
00136 if (s != NULL)
00137 *s = cp;
00138
00139 return TRUE;
00140 }
00141
00142 static int
00143 single_encode(float8 x, char *str)
00144 {
00145 int ndig = DBL_DIG + extra_float_digits;
00146
00147 if (ndig < 1)
00148 ndig = 1;
00149
00150 sprintf(str, "%.*g", ndig, x);
00151 return TRUE;
00152 }
00153
00154 static int
00155 pair_decode(char *str, float8 *x, float8 *y, char **s)
00156 {
00157 int has_delim;
00158 char *cp;
00159
00160 if (!PointerIsValid(str))
00161 return FALSE;
00162
00163 while (isspace((unsigned char) *str))
00164 str++;
00165 if ((has_delim = (*str == LDELIM)))
00166 str++;
00167
00168 while (isspace((unsigned char) *str))
00169 str++;
00170 *x = strtod(str, &cp);
00171 if (cp <= str)
00172 return FALSE;
00173 while (isspace((unsigned char) *cp))
00174 cp++;
00175 if (*cp++ != DELIM)
00176 return FALSE;
00177 while (isspace((unsigned char) *cp))
00178 cp++;
00179 *y = strtod(cp, &str);
00180 if (str <= cp)
00181 return FALSE;
00182 while (isspace((unsigned char) *str))
00183 str++;
00184 if (has_delim)
00185 {
00186 if (*str != RDELIM)
00187 return FALSE;
00188 str++;
00189 while (isspace((unsigned char) *str))
00190 str++;
00191 }
00192 if (s != NULL)
00193 *s = str;
00194
00195 return TRUE;
00196 }
00197
00198 static int
00199 pair_encode(float8 x, float8 y, char *str)
00200 {
00201 int ndig = DBL_DIG + extra_float_digits;
00202
00203 if (ndig < 1)
00204 ndig = 1;
00205
00206 sprintf(str, "%.*g,%.*g", ndig, x, ndig, y);
00207 return TRUE;
00208 }
00209
00210 static int
00211 path_decode(int opentype, int npts, char *str, int *isopen, char **ss, Point *p)
00212 {
00213 int depth = 0;
00214 char *s,
00215 *cp;
00216 int i;
00217
00218 s = str;
00219 while (isspace((unsigned char) *s))
00220 s++;
00221 if ((*isopen = (*s == LDELIM_EP)))
00222 {
00223
00224 if (!opentype)
00225 return FALSE;
00226 depth++;
00227 s++;
00228 while (isspace((unsigned char) *s))
00229 s++;
00230
00231 }
00232 else if (*s == LDELIM)
00233 {
00234 cp = (s + 1);
00235 while (isspace((unsigned char) *cp))
00236 cp++;
00237 if (*cp == LDELIM)
00238 {
00239 #ifdef NOT_USED
00240
00241 if (npts <= 1)
00242 return FALSE;
00243 #endif
00244 depth++;
00245 s = cp;
00246 }
00247 else if (strrchr(s, LDELIM) == s)
00248 {
00249 depth++;
00250 s = cp;
00251 }
00252 }
00253
00254 for (i = 0; i < npts; i++)
00255 {
00256 if (!pair_decode(s, &(p->x), &(p->y), &s))
00257 return FALSE;
00258
00259 if (*s == DELIM)
00260 s++;
00261 p++;
00262 }
00263
00264 while (depth > 0)
00265 {
00266 if ((*s == RDELIM)
00267 || ((*s == RDELIM_EP) && (*isopen) && (depth == 1)))
00268 {
00269 depth--;
00270 s++;
00271 while (isspace((unsigned char) *s))
00272 s++;
00273 }
00274 else
00275 return FALSE;
00276 }
00277 *ss = s;
00278
00279 return TRUE;
00280 }
00281
00282 static char *
00283 path_encode(bool closed, int npts, Point *pt)
00284 {
00285 int size = npts * (P_MAXLEN + 3) + 2;
00286 char *result;
00287 char *cp;
00288 int i;
00289
00290
00291 if ((size - 2) / npts != (P_MAXLEN + 3))
00292 ereport(ERROR,
00293 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
00294 errmsg("too many points requested")));
00295
00296 result = palloc(size);
00297
00298 cp = result;
00299 switch (closed)
00300 {
00301 case TRUE:
00302 *cp++ = LDELIM;
00303 break;
00304 case FALSE:
00305 *cp++ = LDELIM_EP;
00306 break;
00307 default:
00308 break;
00309 }
00310
00311 for (i = 0; i < npts; i++)
00312 {
00313 *cp++ = LDELIM;
00314 if (!pair_encode(pt->x, pt->y, cp))
00315 ereport(ERROR,
00316 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
00317 errmsg("could not format \"path\" value")));
00318
00319 cp += strlen(cp);
00320 *cp++ = RDELIM;
00321 *cp++ = DELIM;
00322 pt++;
00323 }
00324 cp--;
00325 switch (closed)
00326 {
00327 case TRUE:
00328 *cp++ = RDELIM;
00329 break;
00330 case FALSE:
00331 *cp++ = RDELIM_EP;
00332 break;
00333 default:
00334 break;
00335 }
00336 *cp = '\0';
00337
00338 return result;
00339 }
00340
00341
00342
00343
00344
00345
00346
00347
00348 static int
00349 pair_count(char *s, char delim)
00350 {
00351 int ndelim = 0;
00352
00353 while ((s = strchr(s, delim)) != NULL)
00354 {
00355 ndelim++;
00356 s++;
00357 }
00358 return (ndelim % 2) ? ((ndelim + 1) / 2) : -1;
00359 }
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378 Datum
00379 box_in(PG_FUNCTION_ARGS)
00380 {
00381 char *str = PG_GETARG_CSTRING(0);
00382 BOX *box = (BOX *) palloc(sizeof(BOX));
00383 int isopen;
00384 char *s;
00385 double x,
00386 y;
00387
00388 if ((!path_decode(FALSE, 2, str, &isopen, &s, &(box->high)))
00389 || (*s != '\0'))
00390 ereport(ERROR,
00391 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00392 errmsg("invalid input syntax for type box: \"%s\"", str)));
00393
00394
00395 if (box->high.x < box->low.x)
00396 {
00397 x = box->high.x;
00398 box->high.x = box->low.x;
00399 box->low.x = x;
00400 }
00401 if (box->high.y < box->low.y)
00402 {
00403 y = box->high.y;
00404 box->high.y = box->low.y;
00405 box->low.y = y;
00406 }
00407
00408 PG_RETURN_BOX_P(box);
00409 }
00410
00411
00412
00413 Datum
00414 box_out(PG_FUNCTION_ARGS)
00415 {
00416 BOX *box = PG_GETARG_BOX_P(0);
00417
00418 PG_RETURN_CSTRING(path_encode(-1, 2, &(box->high)));
00419 }
00420
00421
00422
00423
00424 Datum
00425 box_recv(PG_FUNCTION_ARGS)
00426 {
00427 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
00428 BOX *box;
00429 double x,
00430 y;
00431
00432 box = (BOX *) palloc(sizeof(BOX));
00433
00434 box->high.x = pq_getmsgfloat8(buf);
00435 box->high.y = pq_getmsgfloat8(buf);
00436 box->low.x = pq_getmsgfloat8(buf);
00437 box->low.y = pq_getmsgfloat8(buf);
00438
00439
00440 if (box->high.x < box->low.x)
00441 {
00442 x = box->high.x;
00443 box->high.x = box->low.x;
00444 box->low.x = x;
00445 }
00446 if (box->high.y < box->low.y)
00447 {
00448 y = box->high.y;
00449 box->high.y = box->low.y;
00450 box->low.y = y;
00451 }
00452
00453 PG_RETURN_BOX_P(box);
00454 }
00455
00456
00457
00458
00459 Datum
00460 box_send(PG_FUNCTION_ARGS)
00461 {
00462 BOX *box = PG_GETARG_BOX_P(0);
00463 StringInfoData buf;
00464
00465 pq_begintypsend(&buf);
00466 pq_sendfloat8(&buf, box->high.x);
00467 pq_sendfloat8(&buf, box->high.y);
00468 pq_sendfloat8(&buf, box->low.x);
00469 pq_sendfloat8(&buf, box->low.y);
00470 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
00471 }
00472
00473
00474
00475
00476 static BOX *
00477 box_construct(double x1, double x2, double y1, double y2)
00478 {
00479 BOX *result = (BOX *) palloc(sizeof(BOX));
00480
00481 return box_fill(result, x1, x2, y1, y2);
00482 }
00483
00484
00485
00486
00487 static BOX *
00488 box_fill(BOX *result, double x1, double x2, double y1, double y2)
00489 {
00490 if (x1 > x2)
00491 {
00492 result->high.x = x1;
00493 result->low.x = x2;
00494 }
00495 else
00496 {
00497 result->high.x = x2;
00498 result->low.x = x1;
00499 }
00500 if (y1 > y2)
00501 {
00502 result->high.y = y1;
00503 result->low.y = y2;
00504 }
00505 else
00506 {
00507 result->high.y = y2;
00508 result->low.y = y1;
00509 }
00510
00511 return result;
00512 }
00513
00514
00515
00516
00517 static BOX *
00518 box_copy(BOX *box)
00519 {
00520 BOX *result = (BOX *) palloc(sizeof(BOX));
00521
00522 memcpy((char *) result, (char *) box, sizeof(BOX));
00523
00524 return result;
00525 }
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535 Datum
00536 box_same(PG_FUNCTION_ARGS)
00537 {
00538 BOX *box1 = PG_GETARG_BOX_P(0);
00539 BOX *box2 = PG_GETARG_BOX_P(1);
00540
00541 PG_RETURN_BOOL(FPeq(box1->high.x, box2->high.x) &&
00542 FPeq(box1->low.x, box2->low.x) &&
00543 FPeq(box1->high.y, box2->high.y) &&
00544 FPeq(box1->low.y, box2->low.y));
00545 }
00546
00547
00548
00549 Datum
00550 box_overlap(PG_FUNCTION_ARGS)
00551 {
00552 BOX *box1 = PG_GETARG_BOX_P(0);
00553 BOX *box2 = PG_GETARG_BOX_P(1);
00554
00555 PG_RETURN_BOOL(box_ov(box1, box2));
00556 }
00557
00558 static bool
00559 box_ov(BOX *box1, BOX *box2)
00560 {
00561 return (FPle(box1->low.x, box2->high.x) &&
00562 FPle(box2->low.x, box1->high.x) &&
00563 FPle(box1->low.y, box2->high.y) &&
00564 FPle(box2->low.y, box1->high.y));
00565 }
00566
00567
00568
00569 Datum
00570 box_left(PG_FUNCTION_ARGS)
00571 {
00572 BOX *box1 = PG_GETARG_BOX_P(0);
00573 BOX *box2 = PG_GETARG_BOX_P(1);
00574
00575 PG_RETURN_BOOL(FPlt(box1->high.x, box2->low.x));
00576 }
00577
00578
00579
00580
00581
00582
00583
00584 Datum
00585 box_overleft(PG_FUNCTION_ARGS)
00586 {
00587 BOX *box1 = PG_GETARG_BOX_P(0);
00588 BOX *box2 = PG_GETARG_BOX_P(1);
00589
00590 PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x));
00591 }
00592
00593
00594
00595 Datum
00596 box_right(PG_FUNCTION_ARGS)
00597 {
00598 BOX *box1 = PG_GETARG_BOX_P(0);
00599 BOX *box2 = PG_GETARG_BOX_P(1);
00600
00601 PG_RETURN_BOOL(FPgt(box1->low.x, box2->high.x));
00602 }
00603
00604
00605
00606
00607
00608
00609
00610 Datum
00611 box_overright(PG_FUNCTION_ARGS)
00612 {
00613 BOX *box1 = PG_GETARG_BOX_P(0);
00614 BOX *box2 = PG_GETARG_BOX_P(1);
00615
00616 PG_RETURN_BOOL(FPge(box1->low.x, box2->low.x));
00617 }
00618
00619
00620
00621 Datum
00622 box_below(PG_FUNCTION_ARGS)
00623 {
00624 BOX *box1 = PG_GETARG_BOX_P(0);
00625 BOX *box2 = PG_GETARG_BOX_P(1);
00626
00627 PG_RETURN_BOOL(FPlt(box1->high.y, box2->low.y));
00628 }
00629
00630
00631
00632
00633 Datum
00634 box_overbelow(PG_FUNCTION_ARGS)
00635 {
00636 BOX *box1 = PG_GETARG_BOX_P(0);
00637 BOX *box2 = PG_GETARG_BOX_P(1);
00638
00639 PG_RETURN_BOOL(FPle(box1->high.y, box2->high.y));
00640 }
00641
00642
00643
00644 Datum
00645 box_above(PG_FUNCTION_ARGS)
00646 {
00647 BOX *box1 = PG_GETARG_BOX_P(0);
00648 BOX *box2 = PG_GETARG_BOX_P(1);
00649
00650 PG_RETURN_BOOL(FPgt(box1->low.y, box2->high.y));
00651 }
00652
00653
00654
00655
00656 Datum
00657 box_overabove(PG_FUNCTION_ARGS)
00658 {
00659 BOX *box1 = PG_GETARG_BOX_P(0);
00660 BOX *box2 = PG_GETARG_BOX_P(1);
00661
00662 PG_RETURN_BOOL(FPge(box1->low.y, box2->low.y));
00663 }
00664
00665
00666
00667 Datum
00668 box_contained(PG_FUNCTION_ARGS)
00669 {
00670 BOX *box1 = PG_GETARG_BOX_P(0);
00671 BOX *box2 = PG_GETARG_BOX_P(1);
00672
00673 PG_RETURN_BOOL(FPle(box1->high.x, box2->high.x) &&
00674 FPge(box1->low.x, box2->low.x) &&
00675 FPle(box1->high.y, box2->high.y) &&
00676 FPge(box1->low.y, box2->low.y));
00677 }
00678
00679
00680
00681 Datum
00682 box_contain(PG_FUNCTION_ARGS)
00683 {
00684 BOX *box1 = PG_GETARG_BOX_P(0);
00685 BOX *box2 = PG_GETARG_BOX_P(1);
00686
00687 PG_RETURN_BOOL(FPge(box1->high.x, box2->high.x) &&
00688 FPle(box1->low.x, box2->low.x) &&
00689 FPge(box1->high.y, box2->high.y) &&
00690 FPle(box1->low.y, box2->low.y));
00691 }
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702 Datum
00703 box_below_eq(PG_FUNCTION_ARGS)
00704 {
00705 BOX *box1 = PG_GETARG_BOX_P(0);
00706 BOX *box2 = PG_GETARG_BOX_P(1);
00707
00708 PG_RETURN_BOOL(FPle(box1->high.y, box2->low.y));
00709 }
00710
00711 Datum
00712 box_above_eq(PG_FUNCTION_ARGS)
00713 {
00714 BOX *box1 = PG_GETARG_BOX_P(0);
00715 BOX *box2 = PG_GETARG_BOX_P(1);
00716
00717 PG_RETURN_BOOL(FPge(box1->low.y, box2->high.y));
00718 }
00719
00720
00721
00722
00723
00724 Datum
00725 box_lt(PG_FUNCTION_ARGS)
00726 {
00727 BOX *box1 = PG_GETARG_BOX_P(0);
00728 BOX *box2 = PG_GETARG_BOX_P(1);
00729
00730 PG_RETURN_BOOL(FPlt(box_ar(box1), box_ar(box2)));
00731 }
00732
00733 Datum
00734 box_gt(PG_FUNCTION_ARGS)
00735 {
00736 BOX *box1 = PG_GETARG_BOX_P(0);
00737 BOX *box2 = PG_GETARG_BOX_P(1);
00738
00739 PG_RETURN_BOOL(FPgt(box_ar(box1), box_ar(box2)));
00740 }
00741
00742 Datum
00743 box_eq(PG_FUNCTION_ARGS)
00744 {
00745 BOX *box1 = PG_GETARG_BOX_P(0);
00746 BOX *box2 = PG_GETARG_BOX_P(1);
00747
00748 PG_RETURN_BOOL(FPeq(box_ar(box1), box_ar(box2)));
00749 }
00750
00751 Datum
00752 box_le(PG_FUNCTION_ARGS)
00753 {
00754 BOX *box1 = PG_GETARG_BOX_P(0);
00755 BOX *box2 = PG_GETARG_BOX_P(1);
00756
00757 PG_RETURN_BOOL(FPle(box_ar(box1), box_ar(box2)));
00758 }
00759
00760 Datum
00761 box_ge(PG_FUNCTION_ARGS)
00762 {
00763 BOX *box1 = PG_GETARG_BOX_P(0);
00764 BOX *box2 = PG_GETARG_BOX_P(1);
00765
00766 PG_RETURN_BOOL(FPge(box_ar(box1), box_ar(box2)));
00767 }
00768
00769
00770
00771
00772
00773
00774
00775
00776 Datum
00777 box_area(PG_FUNCTION_ARGS)
00778 {
00779 BOX *box = PG_GETARG_BOX_P(0);
00780
00781 PG_RETURN_FLOAT8(box_ar(box));
00782 }
00783
00784
00785
00786
00787
00788 Datum
00789 box_width(PG_FUNCTION_ARGS)
00790 {
00791 BOX *box = PG_GETARG_BOX_P(0);
00792
00793 PG_RETURN_FLOAT8(box->high.x - box->low.x);
00794 }
00795
00796
00797
00798
00799
00800 Datum
00801 box_height(PG_FUNCTION_ARGS)
00802 {
00803 BOX *box = PG_GETARG_BOX_P(0);
00804
00805 PG_RETURN_FLOAT8(box->high.y - box->low.y);
00806 }
00807
00808
00809
00810
00811
00812 Datum
00813 box_distance(PG_FUNCTION_ARGS)
00814 {
00815 BOX *box1 = PG_GETARG_BOX_P(0);
00816 BOX *box2 = PG_GETARG_BOX_P(1);
00817 Point a,
00818 b;
00819
00820 box_cn(&a, box1);
00821 box_cn(&b, box2);
00822
00823 PG_RETURN_FLOAT8(HYPOT(a.x - b.x, a.y - b.y));
00824 }
00825
00826
00827
00828
00829 Datum
00830 box_center(PG_FUNCTION_ARGS)
00831 {
00832 BOX *box = PG_GETARG_BOX_P(0);
00833 Point *result = (Point *) palloc(sizeof(Point));
00834
00835 box_cn(result, box);
00836
00837 PG_RETURN_POINT_P(result);
00838 }
00839
00840
00841
00842
00843 static double
00844 box_ar(BOX *box)
00845 {
00846 return box_wd(box) * box_ht(box);
00847 }
00848
00849
00850
00851
00852 static void
00853 box_cn(Point *center, BOX *box)
00854 {
00855 center->x = (box->high.x + box->low.x) / 2.0;
00856 center->y = (box->high.y + box->low.y) / 2.0;
00857 }
00858
00859
00860
00861
00862
00863 static double
00864 box_wd(BOX *box)
00865 {
00866 return box->high.x - box->low.x;
00867 }
00868
00869
00870
00871
00872
00873 static double
00874 box_ht(BOX *box)
00875 {
00876 return box->high.y - box->low.y;
00877 }
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888 Datum
00889 box_intersect(PG_FUNCTION_ARGS)
00890 {
00891 BOX *box1 = PG_GETARG_BOX_P(0);
00892 BOX *box2 = PG_GETARG_BOX_P(1);
00893 BOX *result;
00894
00895 if (!box_ov(box1, box2))
00896 PG_RETURN_NULL();
00897
00898 result = (BOX *) palloc(sizeof(BOX));
00899
00900 result->high.x = Min(box1->high.x, box2->high.x);
00901 result->low.x = Max(box1->low.x, box2->low.x);
00902 result->high.y = Min(box1->high.y, box2->high.y);
00903 result->low.y = Max(box1->low.y, box2->low.y);
00904
00905 PG_RETURN_BOX_P(result);
00906 }
00907
00908
00909
00910
00911
00912
00913 Datum
00914 box_diagonal(PG_FUNCTION_ARGS)
00915 {
00916 BOX *box = PG_GETARG_BOX_P(0);
00917 LSEG *result = (LSEG *) palloc(sizeof(LSEG));
00918
00919 statlseg_construct(result, &box->high, &box->low);
00920
00921 PG_RETURN_LSEG_P(result);
00922 }
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933 Datum
00934 line_in(PG_FUNCTION_ARGS)
00935 {
00936 #ifdef ENABLE_LINE_TYPE
00937 char *str = PG_GETARG_CSTRING(0);
00938 #endif
00939 LINE *line;
00940
00941 #ifdef ENABLE_LINE_TYPE
00942
00943 LSEG lseg;
00944 int isopen;
00945 char *s;
00946
00947 if ((!path_decode(TRUE, 2, str, &isopen, &s, &(lseg.p[0])))
00948 || (*s != '\0'))
00949 ereport(ERROR,
00950 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
00951 errmsg("invalid input syntax for type line: \"%s\"", str)));
00952
00953 line = (LINE *) palloc(sizeof(LINE));
00954 line_construct_pts(line, &lseg.p[0], &lseg.p[1]);
00955 #else
00956 ereport(ERROR,
00957 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
00958 errmsg("type \"line\" not yet implemented")));
00959
00960 line = NULL;
00961 #endif
00962
00963 PG_RETURN_LINE_P(line);
00964 }
00965
00966
00967 Datum
00968 line_out(PG_FUNCTION_ARGS)
00969 {
00970 #ifdef ENABLE_LINE_TYPE
00971 LINE *line = PG_GETARG_LINE_P(0);
00972 #endif
00973 char *result;
00974
00975 #ifdef ENABLE_LINE_TYPE
00976
00977 LSEG lseg;
00978
00979 if (FPzero(line->B))
00980 {
00981
00982 result->A = -1;
00983 result->B = 0;
00984 result->C = pt1->x;
00985 #ifdef GEODEBUG
00986 printf("line_out- line is vertical\n");
00987 #endif
00988 #ifdef NOT_USED
00989 result->m = DBL_MAX;
00990 #endif
00991
00992 }
00993 else if (FPzero(line->A))
00994 {
00995
00996 result->A = 0;
00997 result->B = -1;
00998 result->C = pt1->y;
00999 #ifdef GEODEBUG
01000 printf("line_out- line is horizontal\n");
01001 #endif
01002 #ifdef NOT_USED
01003 result->m = 0.0;
01004 #endif
01005
01006 }
01007 else
01008 {
01009 }
01010
01011 if (FPzero(line->A))
01012 {
01013 }
01014 else if (FPzero(line->B))
01015 {
01016 }
01017 else
01018 {
01019 }
01020
01021 return path_encode(TRUE, 2, (Point *) &(ls->p[0]));
01022 #else
01023 ereport(ERROR,
01024 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01025 errmsg("type \"line\" not yet implemented")));
01026 result = NULL;
01027 #endif
01028
01029 PG_RETURN_CSTRING(result);
01030 }
01031
01032
01033
01034
01035 Datum
01036 line_recv(PG_FUNCTION_ARGS)
01037 {
01038 ereport(ERROR,
01039 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01040 errmsg("type \"line\" not yet implemented")));
01041 return 0;
01042 }
01043
01044
01045
01046
01047 Datum
01048 line_send(PG_FUNCTION_ARGS)
01049 {
01050 ereport(ERROR,
01051 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01052 errmsg("type \"line\" not yet implemented")));
01053 return 0;
01054 }
01055
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065 static LINE *
01066 line_construct_pm(Point *pt, double m)
01067 {
01068 LINE *result = (LINE *) palloc(sizeof(LINE));
01069
01070 if (m == DBL_MAX)
01071 {
01072
01073 result->A = -1;
01074 result->B = 0;
01075 result->C = pt->x;
01076 }
01077 else
01078 {
01079
01080 result->A = m;
01081 result->B = -1.0;
01082 result->C = pt->y - m * pt->x;
01083 }
01084
01085 #ifdef NOT_USED
01086 result->m = m;
01087 #endif
01088
01089 return result;
01090 }
01091
01092
01093
01094
01095 static void
01096 line_construct_pts(LINE *line, Point *pt1, Point *pt2)
01097 {
01098 if (FPeq(pt1->x, pt2->x))
01099 {
01100
01101 line->A = -1;
01102 line->B = 0;
01103 line->C = pt1->x;
01104 #ifdef NOT_USED
01105 line->m = DBL_MAX;
01106 #endif
01107 #ifdef GEODEBUG
01108 printf("line_construct_pts- line is vertical\n");
01109 #endif
01110 }
01111 else if (FPeq(pt1->y, pt2->y))
01112 {
01113
01114 line->A = 0;
01115 line->B = -1;
01116 line->C = pt1->y;
01117 #ifdef NOT_USED
01118 line->m = 0.0;
01119 #endif
01120 #ifdef GEODEBUG
01121 printf("line_construct_pts- line is horizontal\n");
01122 #endif
01123 }
01124 else
01125 {
01126
01127 line->A = (pt2->y - pt1->y) / (pt2->x - pt1->x);
01128 line->B = -1.0;
01129 line->C = pt1->y - line->A * pt1->x;
01130 #ifdef NOT_USED
01131 line->m = line->A;
01132 #endif
01133 #ifdef GEODEBUG
01134 printf("line_construct_pts- line is neither vertical nor horizontal (diffs x=%.*g, y=%.*g\n",
01135 DBL_DIG, (pt2->x - pt1->x), DBL_DIG, (pt2->y - pt1->y));
01136 #endif
01137 }
01138 }
01139
01140
01141
01142
01143 Datum
01144 line_construct_pp(PG_FUNCTION_ARGS)
01145 {
01146 Point *pt1 = PG_GETARG_POINT_P(0);
01147 Point *pt2 = PG_GETARG_POINT_P(1);
01148 LINE *result = (LINE *) palloc(sizeof(LINE));
01149
01150 line_construct_pts(result, pt1, pt2);
01151 PG_RETURN_LINE_P(result);
01152 }
01153
01154
01155
01156
01157
01158
01159 Datum
01160 line_intersect(PG_FUNCTION_ARGS)
01161 {
01162 LINE *l1 = PG_GETARG_LINE_P(0);
01163 LINE *l2 = PG_GETARG_LINE_P(1);
01164
01165 PG_RETURN_BOOL(!DatumGetBool(DirectFunctionCall2(line_parallel,
01166 LinePGetDatum(l1),
01167 LinePGetDatum(l2))));
01168 }
01169
01170 Datum
01171 line_parallel(PG_FUNCTION_ARGS)
01172 {
01173 LINE *l1 = PG_GETARG_LINE_P(0);
01174 LINE *l2 = PG_GETARG_LINE_P(1);
01175
01176 #ifdef NOT_USED
01177 PG_RETURN_BOOL(FPeq(l1->m, l2->m));
01178 #endif
01179 if (FPzero(l1->B))
01180 PG_RETURN_BOOL(FPzero(l2->B));
01181
01182 PG_RETURN_BOOL(FPeq(l2->A, l1->A * (l2->B / l1->B)));
01183 }
01184
01185 Datum
01186 line_perp(PG_FUNCTION_ARGS)
01187 {
01188 LINE *l1 = PG_GETARG_LINE_P(0);
01189 LINE *l2 = PG_GETARG_LINE_P(1);
01190
01191 #ifdef NOT_USED
01192 if (l1->m)
01193 PG_RETURN_BOOL(FPeq(l2->m / l1->m, -1.0));
01194 else if (l2->m)
01195 PG_RETURN_BOOL(FPeq(l1->m / l2->m, -1.0));
01196 #endif
01197 if (FPzero(l1->A))
01198 PG_RETURN_BOOL(FPzero(l2->B));
01199 else if (FPzero(l1->B))
01200 PG_RETURN_BOOL(FPzero(l2->A));
01201
01202 PG_RETURN_BOOL(FPeq(((l1->A * l2->B) / (l1->B * l2->A)), -1.0));
01203 }
01204
01205 Datum
01206 line_vertical(PG_FUNCTION_ARGS)
01207 {
01208 LINE *line = PG_GETARG_LINE_P(0);
01209
01210 PG_RETURN_BOOL(FPzero(line->B));
01211 }
01212
01213 Datum
01214 line_horizontal(PG_FUNCTION_ARGS)
01215 {
01216 LINE *line = PG_GETARG_LINE_P(0);
01217
01218 PG_RETURN_BOOL(FPzero(line->A));
01219 }
01220
01221 Datum
01222 line_eq(PG_FUNCTION_ARGS)
01223 {
01224 LINE *l1 = PG_GETARG_LINE_P(0);
01225 LINE *l2 = PG_GETARG_LINE_P(1);
01226 double k;
01227
01228 if (!FPzero(l2->A))
01229 k = l1->A / l2->A;
01230 else if (!FPzero(l2->B))
01231 k = l1->B / l2->B;
01232 else if (!FPzero(l2->C))
01233 k = l1->C / l2->C;
01234 else
01235 k = 1.0;
01236
01237 PG_RETURN_BOOL(FPeq(l1->A, k * l2->A) &&
01238 FPeq(l1->B, k * l2->B) &&
01239 FPeq(l1->C, k * l2->C));
01240 }
01241
01242
01243
01244
01245
01246
01247
01248
01249
01250 Datum
01251 line_distance(PG_FUNCTION_ARGS)
01252 {
01253 LINE *l1 = PG_GETARG_LINE_P(0);
01254 LINE *l2 = PG_GETARG_LINE_P(1);
01255 float8 result;
01256 Point *tmp;
01257
01258 if (!DatumGetBool(DirectFunctionCall2(line_parallel,
01259 LinePGetDatum(l1),
01260 LinePGetDatum(l2))))
01261 PG_RETURN_FLOAT8(0.0);
01262 if (FPzero(l1->B))
01263 PG_RETURN_FLOAT8(fabs(l1->C - l2->C));
01264 tmp = point_construct(0.0, l1->C);
01265 result = dist_pl_internal(tmp, l2);
01266 PG_RETURN_FLOAT8(result);
01267 }
01268
01269
01270
01271
01272 Datum
01273 line_interpt(PG_FUNCTION_ARGS)
01274 {
01275 LINE *l1 = PG_GETARG_LINE_P(0);
01276 LINE *l2 = PG_GETARG_LINE_P(1);
01277 Point *result;
01278
01279 result = line_interpt_internal(l1, l2);
01280
01281 if (result == NULL)
01282 PG_RETURN_NULL();
01283 PG_RETURN_POINT_P(result);
01284 }
01285
01286
01287
01288
01289
01290
01291 static Point *
01292 line_interpt_internal(LINE *l1, LINE *l2)
01293 {
01294 Point *result;
01295 double x,
01296 y;
01297
01298
01299
01300
01301
01302
01303 if (DatumGetBool(DirectFunctionCall2(line_parallel,
01304 LinePGetDatum(l1),
01305 LinePGetDatum(l2))))
01306 return NULL;
01307
01308 #ifdef NOT_USED
01309 if (FPzero(l1->B))
01310 result = point_construct(l2->m * l1->C + l2->C, l1->C);
01311 else if (FPzero(l2->B))
01312 result = point_construct(l1->m * l2->C + l1->C, l2->C);
01313 else
01314 {
01315 x = (l1->C - l2->C) / (l2->A - l1->A);
01316 result = point_construct(x, l1->m * x + l1->C);
01317 }
01318 #endif
01319
01320 if (FPzero(l1->B))
01321 {
01322 x = l1->C;
01323 y = (l2->A * x + l2->C);
01324 }
01325 else if (FPzero(l2->B))
01326 {
01327 x = l2->C;
01328 y = (l1->A * x + l1->C);
01329 }
01330 else
01331 {
01332 x = (l1->C - l2->C) / (l2->A - l1->A);
01333 y = (l1->A * x + l1->C);
01334 }
01335 result = point_construct(x, y);
01336
01337 #ifdef GEODEBUG
01338 printf("line_interpt- lines are A=%.*g, B=%.*g, C=%.*g, A=%.*g, B=%.*g, C=%.*g\n",
01339 DBL_DIG, l1->A, DBL_DIG, l1->B, DBL_DIG, l1->C, DBL_DIG, l2->A, DBL_DIG, l2->B, DBL_DIG, l2->C);
01340 printf("line_interpt- lines intersect at (%.*g,%.*g)\n", DBL_DIG, x, DBL_DIG, y);
01341 #endif
01342
01343 return result;
01344 }
01345
01346
01347
01348
01349
01350
01351
01352
01353
01354
01355
01356
01357
01358
01359
01360
01361
01362
01363
01364
01365
01366
01367
01368
01369 Datum
01370 path_area(PG_FUNCTION_ARGS)
01371 {
01372 PATH *path = PG_GETARG_PATH_P(0);
01373 double area = 0.0;
01374 int i,
01375 j;
01376
01377 if (!path->closed)
01378 PG_RETURN_NULL();
01379
01380 for (i = 0; i < path->npts; i++)
01381 {
01382 j = (i + 1) % path->npts;
01383 area += path->p[i].x * path->p[j].y;
01384 area -= path->p[i].y * path->p[j].x;
01385 }
01386
01387 area *= 0.5;
01388 PG_RETURN_FLOAT8(area < 0.0 ? -area : area);
01389 }
01390
01391
01392 Datum
01393 path_in(PG_FUNCTION_ARGS)
01394 {
01395 char *str = PG_GETARG_CSTRING(0);
01396 PATH *path;
01397 int isopen;
01398 char *s;
01399 int npts;
01400 int size;
01401 int depth = 0;
01402
01403 if ((npts = pair_count(str, ',')) <= 0)
01404 ereport(ERROR,
01405 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01406 errmsg("invalid input syntax for type path: \"%s\"", str)));
01407
01408 s = str;
01409 while (isspace((unsigned char) *s))
01410 s++;
01411
01412
01413 if ((*s == LDELIM) && (strrchr(s, LDELIM) == s))
01414 {
01415 s++;
01416 depth++;
01417 }
01418
01419 size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * npts;
01420 path = (PATH *) palloc(size);
01421
01422 SET_VARSIZE(path, size);
01423 path->npts = npts;
01424
01425 if ((!path_decode(TRUE, npts, s, &isopen, &s, &(path->p[0])))
01426 && (!((depth == 0) && (*s == '\0'))) && !((depth >= 1) && (*s == RDELIM)))
01427 ereport(ERROR,
01428 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01429 errmsg("invalid input syntax for type path: \"%s\"", str)));
01430
01431 path->closed = (!isopen);
01432
01433 path->dummy = 0;
01434
01435 PG_RETURN_PATH_P(path);
01436 }
01437
01438
01439 Datum
01440 path_out(PG_FUNCTION_ARGS)
01441 {
01442 PATH *path = PG_GETARG_PATH_P(0);
01443
01444 PG_RETURN_CSTRING(path_encode(path->closed, path->npts, path->p));
01445 }
01446
01447
01448
01449
01450
01451
01452
01453 Datum
01454 path_recv(PG_FUNCTION_ARGS)
01455 {
01456 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
01457 PATH *path;
01458 int closed;
01459 int32 npts;
01460 int32 i;
01461 int size;
01462
01463 closed = pq_getmsgbyte(buf);
01464 npts = pq_getmsgint(buf, sizeof(int32));
01465 if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(PATH, p[0])) / sizeof(Point)))
01466 ereport(ERROR,
01467 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
01468 errmsg("invalid number of points in external \"path\" value")));
01469
01470 size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * npts;
01471 path = (PATH *) palloc(size);
01472
01473 SET_VARSIZE(path, size);
01474 path->npts = npts;
01475 path->closed = (closed ? 1 : 0);
01476
01477 path->dummy = 0;
01478
01479 for (i = 0; i < npts; i++)
01480 {
01481 path->p[i].x = pq_getmsgfloat8(buf);
01482 path->p[i].y = pq_getmsgfloat8(buf);
01483 }
01484
01485 PG_RETURN_PATH_P(path);
01486 }
01487
01488
01489
01490
01491 Datum
01492 path_send(PG_FUNCTION_ARGS)
01493 {
01494 PATH *path = PG_GETARG_PATH_P(0);
01495 StringInfoData buf;
01496 int32 i;
01497
01498 pq_begintypsend(&buf);
01499 pq_sendbyte(&buf, path->closed ? 1 : 0);
01500 pq_sendint(&buf, path->npts, sizeof(int32));
01501 for (i = 0; i < path->npts; i++)
01502 {
01503 pq_sendfloat8(&buf, path->p[i].x);
01504 pq_sendfloat8(&buf, path->p[i].y);
01505 }
01506 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
01507 }
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518 Datum
01519 path_n_lt(PG_FUNCTION_ARGS)
01520 {
01521 PATH *p1 = PG_GETARG_PATH_P(0);
01522 PATH *p2 = PG_GETARG_PATH_P(1);
01523
01524 PG_RETURN_BOOL(p1->npts < p2->npts);
01525 }
01526
01527 Datum
01528 path_n_gt(PG_FUNCTION_ARGS)
01529 {
01530 PATH *p1 = PG_GETARG_PATH_P(0);
01531 PATH *p2 = PG_GETARG_PATH_P(1);
01532
01533 PG_RETURN_BOOL(p1->npts > p2->npts);
01534 }
01535
01536 Datum
01537 path_n_eq(PG_FUNCTION_ARGS)
01538 {
01539 PATH *p1 = PG_GETARG_PATH_P(0);
01540 PATH *p2 = PG_GETARG_PATH_P(1);
01541
01542 PG_RETURN_BOOL(p1->npts == p2->npts);
01543 }
01544
01545 Datum
01546 path_n_le(PG_FUNCTION_ARGS)
01547 {
01548 PATH *p1 = PG_GETARG_PATH_P(0);
01549 PATH *p2 = PG_GETARG_PATH_P(1);
01550
01551 PG_RETURN_BOOL(p1->npts <= p2->npts);
01552 }
01553
01554 Datum
01555 path_n_ge(PG_FUNCTION_ARGS)
01556 {
01557 PATH *p1 = PG_GETARG_PATH_P(0);
01558 PATH *p2 = PG_GETARG_PATH_P(1);
01559
01560 PG_RETURN_BOOL(p1->npts >= p2->npts);
01561 }
01562
01563
01564
01565
01566
01567 Datum
01568 path_isclosed(PG_FUNCTION_ARGS)
01569 {
01570 PATH *path = PG_GETARG_PATH_P(0);
01571
01572 PG_RETURN_BOOL(path->closed);
01573 }
01574
01575 Datum
01576 path_isopen(PG_FUNCTION_ARGS)
01577 {
01578 PATH *path = PG_GETARG_PATH_P(0);
01579
01580 PG_RETURN_BOOL(!path->closed);
01581 }
01582
01583 Datum
01584 path_npoints(PG_FUNCTION_ARGS)
01585 {
01586 PATH *path = PG_GETARG_PATH_P(0);
01587
01588 PG_RETURN_INT32(path->npts);
01589 }
01590
01591
01592 Datum
01593 path_close(PG_FUNCTION_ARGS)
01594 {
01595 PATH *path = PG_GETARG_PATH_P_COPY(0);
01596
01597 path->closed = TRUE;
01598
01599 PG_RETURN_PATH_P(path);
01600 }
01601
01602 Datum
01603 path_open(PG_FUNCTION_ARGS)
01604 {
01605 PATH *path = PG_GETARG_PATH_P_COPY(0);
01606
01607 path->closed = FALSE;
01608
01609 PG_RETURN_PATH_P(path);
01610 }
01611
01612
01613
01614
01615
01616
01617
01618 Datum
01619 path_inter(PG_FUNCTION_ARGS)
01620 {
01621 PATH *p1 = PG_GETARG_PATH_P(0);
01622 PATH *p2 = PG_GETARG_PATH_P(1);
01623 BOX b1,
01624 b2;
01625 int i,
01626 j;
01627 LSEG seg1,
01628 seg2;
01629
01630 if (p1->npts <= 0 || p2->npts <= 0)
01631 PG_RETURN_BOOL(false);
01632
01633 b1.high.x = b1.low.x = p1->p[0].x;
01634 b1.high.y = b1.low.y = p1->p[0].y;
01635 for (i = 1; i < p1->npts; i++)
01636 {
01637 b1.high.x = Max(p1->p[i].x, b1.high.x);
01638 b1.high.y = Max(p1->p[i].y, b1.high.y);
01639 b1.low.x = Min(p1->p[i].x, b1.low.x);
01640 b1.low.y = Min(p1->p[i].y, b1.low.y);
01641 }
01642 b2.high.x = b2.low.x = p2->p[0].x;
01643 b2.high.y = b2.low.y = p2->p[0].y;
01644 for (i = 1; i < p2->npts; i++)
01645 {
01646 b2.high.x = Max(p2->p[i].x, b2.high.x);
01647 b2.high.y = Max(p2->p[i].y, b2.high.y);
01648 b2.low.x = Min(p2->p[i].x, b2.low.x);
01649 b2.low.y = Min(p2->p[i].y, b2.low.y);
01650 }
01651 if (!box_ov(&b1, &b2))
01652 PG_RETURN_BOOL(false);
01653
01654
01655 for (i = 0; i < p1->npts; i++)
01656 {
01657 int iprev;
01658
01659 if (i > 0)
01660 iprev = i - 1;
01661 else
01662 {
01663 if (!p1->closed)
01664 continue;
01665 iprev = p1->npts - 1;
01666 }
01667
01668 for (j = 0; j < p2->npts; j++)
01669 {
01670 int jprev;
01671
01672 if (j > 0)
01673 jprev = j - 1;
01674 else
01675 {
01676 if (!p2->closed)
01677 continue;
01678 jprev = p2->npts - 1;
01679 }
01680
01681 statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
01682 statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
01683 if (lseg_intersect_internal(&seg1, &seg2))
01684 PG_RETURN_BOOL(true);
01685 }
01686 }
01687
01688
01689 PG_RETURN_BOOL(false);
01690 }
01691
01692
01693
01694
01695
01696 Datum
01697 path_distance(PG_FUNCTION_ARGS)
01698 {
01699 PATH *p1 = PG_GETARG_PATH_P(0);
01700 PATH *p2 = PG_GETARG_PATH_P(1);
01701 float8 min = 0.0;
01702 bool have_min = false;
01703 float8 tmp;
01704 int i,
01705 j;
01706 LSEG seg1,
01707 seg2;
01708
01709 for (i = 0; i < p1->npts; i++)
01710 {
01711 int iprev;
01712
01713 if (i > 0)
01714 iprev = i - 1;
01715 else
01716 {
01717 if (!p1->closed)
01718 continue;
01719 iprev = p1->npts - 1;
01720 }
01721
01722 for (j = 0; j < p2->npts; j++)
01723 {
01724 int jprev;
01725
01726 if (j > 0)
01727 jprev = j - 1;
01728 else
01729 {
01730 if (!p2->closed)
01731 continue;
01732 jprev = p2->npts - 1;
01733 }
01734
01735 statlseg_construct(&seg1, &p1->p[iprev], &p1->p[i]);
01736 statlseg_construct(&seg2, &p2->p[jprev], &p2->p[j]);
01737
01738 tmp = DatumGetFloat8(DirectFunctionCall2(lseg_distance,
01739 LsegPGetDatum(&seg1),
01740 LsegPGetDatum(&seg2)));
01741 if (!have_min || tmp < min)
01742 {
01743 min = tmp;
01744 have_min = true;
01745 }
01746 }
01747 }
01748
01749 if (!have_min)
01750 PG_RETURN_NULL();
01751
01752 PG_RETURN_FLOAT8(min);
01753 }
01754
01755
01756
01757
01758
01759
01760 Datum
01761 path_length(PG_FUNCTION_ARGS)
01762 {
01763 PATH *path = PG_GETARG_PATH_P(0);
01764 float8 result = 0.0;
01765 int i;
01766
01767 for (i = 0; i < path->npts; i++)
01768 {
01769 int iprev;
01770
01771 if (i > 0)
01772 iprev = i - 1;
01773 else
01774 {
01775 if (!path->closed)
01776 continue;
01777 iprev = path->npts - 1;
01778 }
01779
01780 result += point_dt(&path->p[iprev], &path->p[i]);
01781 }
01782
01783 PG_RETURN_FLOAT8(result);
01784 }
01785
01786
01787
01788
01789
01790
01791
01792
01793
01794
01795
01796
01797
01798
01799 Datum
01800 point_in(PG_FUNCTION_ARGS)
01801 {
01802 char *str = PG_GETARG_CSTRING(0);
01803 Point *point;
01804 double x,
01805 y;
01806 char *s;
01807
01808 if (!pair_decode(str, &x, &y, &s) || (*s != '\0'))
01809 ereport(ERROR,
01810 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01811 errmsg("invalid input syntax for type point: \"%s\"", str)));
01812
01813 point = (Point *) palloc(sizeof(Point));
01814
01815 point->x = x;
01816 point->y = y;
01817
01818 PG_RETURN_POINT_P(point);
01819 }
01820
01821 Datum
01822 point_out(PG_FUNCTION_ARGS)
01823 {
01824 Point *pt = PG_GETARG_POINT_P(0);
01825
01826 PG_RETURN_CSTRING(path_encode(-1, 1, pt));
01827 }
01828
01829
01830
01831
01832 Datum
01833 point_recv(PG_FUNCTION_ARGS)
01834 {
01835 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
01836 Point *point;
01837
01838 point = (Point *) palloc(sizeof(Point));
01839 point->x = pq_getmsgfloat8(buf);
01840 point->y = pq_getmsgfloat8(buf);
01841 PG_RETURN_POINT_P(point);
01842 }
01843
01844
01845
01846
01847 Datum
01848 point_send(PG_FUNCTION_ARGS)
01849 {
01850 Point *pt = PG_GETARG_POINT_P(0);
01851 StringInfoData buf;
01852
01853 pq_begintypsend(&buf);
01854 pq_sendfloat8(&buf, pt->x);
01855 pq_sendfloat8(&buf, pt->y);
01856 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
01857 }
01858
01859
01860 static Point *
01861 point_construct(double x, double y)
01862 {
01863 Point *result = (Point *) palloc(sizeof(Point));
01864
01865 result->x = x;
01866 result->y = y;
01867 return result;
01868 }
01869
01870
01871 static Point *
01872 point_copy(Point *pt)
01873 {
01874 Point *result;
01875
01876 if (!PointerIsValid(pt))
01877 return NULL;
01878
01879 result = (Point *) palloc(sizeof(Point));
01880
01881 result->x = pt->x;
01882 result->y = pt->y;
01883 return result;
01884 }
01885
01886
01887
01888
01889
01890
01891
01892
01893
01894
01895
01896 Datum
01897 point_left(PG_FUNCTION_ARGS)
01898 {
01899 Point *pt1 = PG_GETARG_POINT_P(0);
01900 Point *pt2 = PG_GETARG_POINT_P(1);
01901
01902 PG_RETURN_BOOL(FPlt(pt1->x, pt2->x));
01903 }
01904
01905 Datum
01906 point_right(PG_FUNCTION_ARGS)
01907 {
01908 Point *pt1 = PG_GETARG_POINT_P(0);
01909 Point *pt2 = PG_GETARG_POINT_P(1);
01910
01911 PG_RETURN_BOOL(FPgt(pt1->x, pt2->x));
01912 }
01913
01914 Datum
01915 point_above(PG_FUNCTION_ARGS)
01916 {
01917 Point *pt1 = PG_GETARG_POINT_P(0);
01918 Point *pt2 = PG_GETARG_POINT_P(1);
01919
01920 PG_RETURN_BOOL(FPgt(pt1->y, pt2->y));
01921 }
01922
01923 Datum
01924 point_below(PG_FUNCTION_ARGS)
01925 {
01926 Point *pt1 = PG_GETARG_POINT_P(0);
01927 Point *pt2 = PG_GETARG_POINT_P(1);
01928
01929 PG_RETURN_BOOL(FPlt(pt1->y, pt2->y));
01930 }
01931
01932 Datum
01933 point_vert(PG_FUNCTION_ARGS)
01934 {
01935 Point *pt1 = PG_GETARG_POINT_P(0);
01936 Point *pt2 = PG_GETARG_POINT_P(1);
01937
01938 PG_RETURN_BOOL(FPeq(pt1->x, pt2->x));
01939 }
01940
01941 Datum
01942 point_horiz(PG_FUNCTION_ARGS)
01943 {
01944 Point *pt1 = PG_GETARG_POINT_P(0);
01945 Point *pt2 = PG_GETARG_POINT_P(1);
01946
01947 PG_RETURN_BOOL(FPeq(pt1->y, pt2->y));
01948 }
01949
01950 Datum
01951 point_eq(PG_FUNCTION_ARGS)
01952 {
01953 Point *pt1 = PG_GETARG_POINT_P(0);
01954 Point *pt2 = PG_GETARG_POINT_P(1);
01955
01956 PG_RETURN_BOOL(FPeq(pt1->x, pt2->x) && FPeq(pt1->y, pt2->y));
01957 }
01958
01959 Datum
01960 point_ne(PG_FUNCTION_ARGS)
01961 {
01962 Point *pt1 = PG_GETARG_POINT_P(0);
01963 Point *pt2 = PG_GETARG_POINT_P(1);
01964
01965 PG_RETURN_BOOL(FPne(pt1->x, pt2->x) || FPne(pt1->y, pt2->y));
01966 }
01967
01968
01969
01970
01971
01972 Datum
01973 point_distance(PG_FUNCTION_ARGS)
01974 {
01975 Point *pt1 = PG_GETARG_POINT_P(0);
01976 Point *pt2 = PG_GETARG_POINT_P(1);
01977
01978 PG_RETURN_FLOAT8(HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
01979 }
01980
01981 double
01982 point_dt(Point *pt1, Point *pt2)
01983 {
01984 #ifdef GEODEBUG
01985 printf("point_dt- segment (%f,%f),(%f,%f) length is %f\n",
01986 pt1->x, pt1->y, pt2->x, pt2->y, HYPOT(pt1->x - pt2->x, pt1->y - pt2->y));
01987 #endif
01988 return HYPOT(pt1->x - pt2->x, pt1->y - pt2->y);
01989 }
01990
01991 Datum
01992 point_slope(PG_FUNCTION_ARGS)
01993 {
01994 Point *pt1 = PG_GETARG_POINT_P(0);
01995 Point *pt2 = PG_GETARG_POINT_P(1);
01996
01997 PG_RETURN_FLOAT8(point_sl(pt1, pt2));
01998 }
01999
02000
02001 double
02002 point_sl(Point *pt1, Point *pt2)
02003 {
02004 return (FPeq(pt1->x, pt2->x)
02005 ? (double) DBL_MAX
02006 : (pt1->y - pt2->y) / (pt1->x - pt2->x));
02007 }
02008
02009
02010
02011
02012
02013
02014
02015
02016
02017
02018
02019
02020
02021
02022
02023
02024
02025 Datum
02026 lseg_in(PG_FUNCTION_ARGS)
02027 {
02028 char *str = PG_GETARG_CSTRING(0);
02029 LSEG *lseg;
02030 int isopen;
02031 char *s;
02032
02033 lseg = (LSEG *) palloc(sizeof(LSEG));
02034
02035 if ((!path_decode(TRUE, 2, str, &isopen, &s, &(lseg->p[0])))
02036 || (*s != '\0'))
02037 ereport(ERROR,
02038 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
02039 errmsg("invalid input syntax for type lseg: \"%s\"", str)));
02040
02041 #ifdef NOT_USED
02042 lseg->m = point_sl(&lseg->p[0], &lseg->p[1]);
02043 #endif
02044
02045 PG_RETURN_LSEG_P(lseg);
02046 }
02047
02048
02049 Datum
02050 lseg_out(PG_FUNCTION_ARGS)
02051 {
02052 LSEG *ls = PG_GETARG_LSEG_P(0);
02053
02054 PG_RETURN_CSTRING(path_encode(FALSE, 2, (Point *) &(ls->p[0])));
02055 }
02056
02057
02058
02059
02060 Datum
02061 lseg_recv(PG_FUNCTION_ARGS)
02062 {
02063 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
02064 LSEG *lseg;
02065
02066 lseg = (LSEG *) palloc(sizeof(LSEG));
02067
02068 lseg->p[0].x = pq_getmsgfloat8(buf);
02069 lseg->p[0].y = pq_getmsgfloat8(buf);
02070 lseg->p[1].x = pq_getmsgfloat8(buf);
02071 lseg->p[1].y = pq_getmsgfloat8(buf);
02072
02073 #ifdef NOT_USED
02074 lseg->m = point_sl(&lseg->p[0], &lseg->p[1]);
02075 #endif
02076
02077 PG_RETURN_LSEG_P(lseg);
02078 }
02079
02080
02081
02082
02083 Datum
02084 lseg_send(PG_FUNCTION_ARGS)
02085 {
02086 LSEG *ls = PG_GETARG_LSEG_P(0);
02087 StringInfoData buf;
02088
02089 pq_begintypsend(&buf);
02090 pq_sendfloat8(&buf, ls->p[0].x);
02091 pq_sendfloat8(&buf, ls->p[0].y);
02092 pq_sendfloat8(&buf, ls->p[1].x);
02093 pq_sendfloat8(&buf, ls->p[1].y);
02094 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
02095 }
02096
02097
02098
02099
02100
02101 Datum
02102 lseg_construct(PG_FUNCTION_ARGS)
02103 {
02104 Point *pt1 = PG_GETARG_POINT_P(0);
02105 Point *pt2 = PG_GETARG_POINT_P(1);
02106 LSEG *result = (LSEG *) palloc(sizeof(LSEG));
02107
02108 result->p[0].x = pt1->x;
02109 result->p[0].y = pt1->y;
02110 result->p[1].x = pt2->x;
02111 result->p[1].y = pt2->y;
02112
02113 #ifdef NOT_USED
02114 result->m = point_sl(pt1, pt2);
02115 #endif
02116
02117 PG_RETURN_LSEG_P(result);
02118 }
02119
02120
02121 static void
02122 statlseg_construct(LSEG *lseg, Point *pt1, Point *pt2)
02123 {
02124 lseg->p[0].x = pt1->x;
02125 lseg->p[0].y = pt1->y;
02126 lseg->p[1].x = pt2->x;
02127 lseg->p[1].y = pt2->y;
02128
02129 #ifdef NOT_USED
02130 lseg->m = point_sl(pt1, pt2);
02131 #endif
02132 }
02133
02134 Datum
02135 lseg_length(PG_FUNCTION_ARGS)
02136 {
02137 LSEG *lseg = PG_GETARG_LSEG_P(0);
02138
02139 PG_RETURN_FLOAT8(point_dt(&lseg->p[0], &lseg->p[1]));
02140 }
02141
02142
02143
02144
02145
02146
02147
02148
02149
02150 Datum
02151 lseg_intersect(PG_FUNCTION_ARGS)
02152 {
02153 LSEG *l1 = PG_GETARG_LSEG_P(0);
02154 LSEG *l2 = PG_GETARG_LSEG_P(1);
02155
02156 PG_RETURN_BOOL(lseg_intersect_internal(l1, l2));
02157 }
02158
02159 static bool
02160 lseg_intersect_internal(LSEG *l1, LSEG *l2)
02161 {
02162 LINE ln;
02163 Point *interpt;
02164 bool retval;
02165
02166 line_construct_pts(&ln, &l2->p[0], &l2->p[1]);
02167 interpt = interpt_sl(l1, &ln);
02168
02169 if (interpt != NULL && on_ps_internal(interpt, l2))
02170 retval = true;
02171 else
02172 retval = false;
02173 return retval;
02174 }
02175
02176 Datum
02177 lseg_parallel(PG_FUNCTION_ARGS)
02178 {
02179 LSEG *l1 = PG_GETARG_LSEG_P(0);
02180 LSEG *l2 = PG_GETARG_LSEG_P(1);
02181
02182 #ifdef NOT_USED
02183 PG_RETURN_BOOL(FPeq(l1->m, l2->m));
02184 #endif
02185 PG_RETURN_BOOL(FPeq(point_sl(&l1->p[0], &l1->p[1]),
02186 point_sl(&l2->p[0], &l2->p[1])));
02187 }
02188
02189
02190
02191
02192
02193
02194
02195
02196
02197
02198 Datum
02199 lseg_perp(PG_FUNCTION_ARGS)
02200 {
02201 LSEG *l1 = PG_GETARG_LSEG_P(0);
02202 LSEG *l2 = PG_GETARG_LSEG_P(1);
02203 double m1,
02204 m2;
02205
02206 m1 = point_sl(&(l1->p[0]), &(l1->p[1]));
02207 m2 = point_sl(&(l2->p[0]), &(l2->p[1]));
02208
02209 #ifdef GEODEBUG
02210 printf("lseg_perp- slopes are %g and %g\n", m1, m2);
02211 #endif
02212 if (FPzero(m1))
02213 PG_RETURN_BOOL(FPeq(m2, DBL_MAX));
02214 else if (FPzero(m2))
02215 PG_RETURN_BOOL(FPeq(m1, DBL_MAX));
02216
02217 PG_RETURN_BOOL(FPeq(m1 / m2, -1.0));
02218 }
02219
02220 Datum
02221 lseg_vertical(PG_FUNCTION_ARGS)
02222 {
02223 LSEG *lseg = PG_GETARG_LSEG_P(0);
02224
02225 PG_RETURN_BOOL(FPeq(lseg->p[0].x, lseg->p[1].x));
02226 }
02227
02228 Datum
02229 lseg_horizontal(PG_FUNCTION_ARGS)
02230 {
02231 LSEG *lseg = PG_GETARG_LSEG_P(0);
02232
02233 PG_RETURN_BOOL(FPeq(lseg->p[0].y, lseg->p[1].y));
02234 }
02235
02236
02237 Datum
02238 lseg_eq(PG_FUNCTION_ARGS)
02239 {
02240 LSEG *l1 = PG_GETARG_LSEG_P(0);
02241 LSEG *l2 = PG_GETARG_LSEG_P(1);
02242
02243 PG_RETURN_BOOL(FPeq(l1->p[0].x, l2->p[0].x) &&
02244 FPeq(l1->p[0].y, l2->p[0].y) &&
02245 FPeq(l1->p[1].x, l2->p[1].x) &&
02246 FPeq(l1->p[1].y, l2->p[1].y));
02247 }
02248
02249 Datum
02250 lseg_ne(PG_FUNCTION_ARGS)
02251 {
02252 LSEG *l1 = PG_GETARG_LSEG_P(0);
02253 LSEG *l2 = PG_GETARG_LSEG_P(1);
02254
02255 PG_RETURN_BOOL(!FPeq(l1->p[0].x, l2->p[0].x) ||
02256 !FPeq(l1->p[0].y, l2->p[0].y) ||
02257 !FPeq(l1->p[1].x, l2->p[1].x) ||
02258 !FPeq(l1->p[1].y, l2->p[1].y));
02259 }
02260
02261 Datum
02262 lseg_lt(PG_FUNCTION_ARGS)
02263 {
02264 LSEG *l1 = PG_GETARG_LSEG_P(0);
02265 LSEG *l2 = PG_GETARG_LSEG_P(1);
02266
02267 PG_RETURN_BOOL(FPlt(point_dt(&l1->p[0], &l1->p[1]),
02268 point_dt(&l2->p[0], &l2->p[1])));
02269 }
02270
02271 Datum
02272 lseg_le(PG_FUNCTION_ARGS)
02273 {
02274 LSEG *l1 = PG_GETARG_LSEG_P(0);
02275 LSEG *l2 = PG_GETARG_LSEG_P(1);
02276
02277 PG_RETURN_BOOL(FPle(point_dt(&l1->p[0], &l1->p[1]),
02278 point_dt(&l2->p[0], &l2->p[1])));
02279 }
02280
02281 Datum
02282 lseg_gt(PG_FUNCTION_ARGS)
02283 {
02284 LSEG *l1 = PG_GETARG_LSEG_P(0);
02285 LSEG *l2 = PG_GETARG_LSEG_P(1);
02286
02287 PG_RETURN_BOOL(FPgt(point_dt(&l1->p[0], &l1->p[1]),
02288 point_dt(&l2->p[0], &l2->p[1])));
02289 }
02290
02291 Datum
02292 lseg_ge(PG_FUNCTION_ARGS)
02293 {
02294 LSEG *l1 = PG_GETARG_LSEG_P(0);
02295 LSEG *l2 = PG_GETARG_LSEG_P(1);
02296
02297 PG_RETURN_BOOL(FPge(point_dt(&l1->p[0], &l1->p[1]),
02298 point_dt(&l2->p[0], &l2->p[1])));
02299 }
02300
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311 Datum
02312 lseg_distance(PG_FUNCTION_ARGS)
02313 {
02314 LSEG *l1 = PG_GETARG_LSEG_P(0);
02315 LSEG *l2 = PG_GETARG_LSEG_P(1);
02316
02317 PG_RETURN_FLOAT8(lseg_dt(l1, l2));
02318 }
02319
02320
02321
02322
02323
02324
02325 static double
02326 lseg_dt(LSEG *l1, LSEG *l2)
02327 {
02328 double result,
02329 d;
02330
02331 if (lseg_intersect_internal(l1, l2))
02332 return 0.0;
02333
02334 d = dist_ps_internal(&l1->p[0], l2);
02335 result = d;
02336 d = dist_ps_internal(&l1->p[1], l2);
02337 result = Min(result, d);
02338 d = dist_ps_internal(&l2->p[0], l1);
02339 result = Min(result, d);
02340 d = dist_ps_internal(&l2->p[1], l1);
02341 result = Min(result, d);
02342
02343 return result;
02344 }
02345
02346
02347 Datum
02348 lseg_center(PG_FUNCTION_ARGS)
02349 {
02350 LSEG *lseg = PG_GETARG_LSEG_P(0);
02351 Point *result;
02352
02353 result = (Point *) palloc(sizeof(Point));
02354
02355 result->x = (lseg->p[0].x + lseg->p[1].x) / 2.0;
02356 result->y = (lseg->p[0].y + lseg->p[1].y) / 2.0;
02357
02358 PG_RETURN_POINT_P(result);
02359 }
02360
02361 static Point *
02362 lseg_interpt_internal(LSEG *l1, LSEG *l2)
02363 {
02364 Point *result;
02365 LINE tmp1,
02366 tmp2;
02367
02368
02369
02370
02371 line_construct_pts(&tmp1, &l1->p[0], &l1->p[1]);
02372 line_construct_pts(&tmp2, &l2->p[0], &l2->p[1]);
02373 result = line_interpt_internal(&tmp1, &tmp2);
02374 if (!PointerIsValid(result))
02375 return NULL;
02376
02377
02378
02379
02380
02381 if (!on_ps_internal(result, l1) ||
02382 !on_ps_internal(result, l2))
02383 {
02384 pfree(result);
02385 return NULL;
02386 }
02387
02388
02389
02390
02391
02392
02393 if ((FPeq(l1->p[0].x, l2->p[0].x) && FPeq(l1->p[0].y, l2->p[0].y)) ||
02394 (FPeq(l1->p[0].x, l2->p[1].x) && FPeq(l1->p[0].y, l2->p[1].y)))
02395 {
02396 result->x = l1->p[0].x;
02397 result->y = l1->p[0].y;
02398 }
02399 else if ((FPeq(l1->p[1].x, l2->p[0].x) && FPeq(l1->p[1].y, l2->p[0].y)) ||
02400 (FPeq(l1->p[1].x, l2->p[1].x) && FPeq(l1->p[1].y, l2->p[1].y)))
02401 {
02402 result->x = l1->p[1].x;
02403 result->y = l1->p[1].y;
02404 }
02405
02406 return result;
02407 }
02408
02409
02410
02411
02412 Datum
02413 lseg_interpt(PG_FUNCTION_ARGS)
02414 {
02415 LSEG *l1 = PG_GETARG_LSEG_P(0);
02416 LSEG *l2 = PG_GETARG_LSEG_P(1);
02417 Point *result;
02418
02419 result = lseg_interpt_internal(l1, l2);
02420 if (!PointerIsValid(result))
02421 PG_RETURN_NULL();
02422
02423 PG_RETURN_POINT_P(result);
02424 }
02425
02426
02427
02428
02429
02430
02431
02432
02433
02434
02435
02436
02437
02438 Datum
02439 dist_pl(PG_FUNCTION_ARGS)
02440 {
02441 Point *pt = PG_GETARG_POINT_P(0);
02442 LINE *line = PG_GETARG_LINE_P(1);
02443
02444 PG_RETURN_FLOAT8(dist_pl_internal(pt, line));
02445 }
02446
02447 static double
02448 dist_pl_internal(Point *pt, LINE *line)
02449 {
02450 return (line->A * pt->x + line->B * pt->y + line->C) /
02451 HYPOT(line->A, line->B);
02452 }
02453
02454 Datum
02455 dist_ps(PG_FUNCTION_ARGS)
02456 {
02457 Point *pt = PG_GETARG_POINT_P(0);
02458 LSEG *lseg = PG_GETARG_LSEG_P(1);
02459
02460 PG_RETURN_FLOAT8(dist_ps_internal(pt, lseg));
02461 }
02462
02463 static double
02464 dist_ps_internal(Point *pt, LSEG *lseg)
02465 {
02466 double m;
02467 LINE *ln;
02468 double result,
02469 tmpdist;
02470 Point *ip;
02471
02472
02473
02474
02475
02476 if (lseg->p[1].x == lseg->p[0].x)
02477 m = 0;
02478 else if (lseg->p[1].y == lseg->p[0].y)
02479 m = (double) DBL_MAX;
02480 else
02481 m = (lseg->p[0].x - lseg->p[1].x) / (lseg->p[1].y - lseg->p[0].y);
02482 ln = line_construct_pm(pt, m);
02483
02484 #ifdef GEODEBUG
02485 printf("dist_ps- line is A=%g B=%g C=%g from (point) slope (%f,%f) %g\n",
02486 ln->A, ln->B, ln->C, pt->x, pt->y, m);
02487 #endif
02488
02489
02490
02491
02492
02493
02494
02495 if ((ip = interpt_sl(lseg, ln)) != NULL)
02496 {
02497
02498 result = point_dt(pt, ip);
02499 #ifdef GEODEBUG
02500 printf("dist_ps- distance is %f to intersection point is (%f,%f)\n",
02501 result, ip->x, ip->y);
02502 #endif
02503 }
02504 else
02505 {
02506
02507 result = point_dt(pt, &lseg->p[0]);
02508 tmpdist = point_dt(pt, &lseg->p[1]);
02509 if (tmpdist < result)
02510 result = tmpdist;
02511 }
02512
02513 return result;
02514 }
02515
02516
02517
02518
02519 Datum
02520 dist_ppath(PG_FUNCTION_ARGS)
02521 {
02522 Point *pt = PG_GETARG_POINT_P(0);
02523 PATH *path = PG_GETARG_PATH_P(1);
02524 float8 result = 0.0;
02525 bool have_min = false;
02526 float8 tmp;
02527 int i;
02528 LSEG lseg;
02529
02530 switch (path->npts)
02531 {
02532 case 0:
02533
02534 PG_RETURN_NULL();
02535 case 1:
02536
02537 result = point_dt(pt, &path->p[0]);
02538 break;
02539 default:
02540
02541 Assert(path->npts > 1);
02542
02543
02544
02545
02546
02547 for (i = 0; i < path->npts; i++)
02548 {
02549 int iprev;
02550
02551 if (i > 0)
02552 iprev = i - 1;
02553 else
02554 {
02555 if (!path->closed)
02556 continue;
02557 iprev = path->npts - 1;
02558 }
02559
02560 statlseg_construct(&lseg, &path->p[iprev], &path->p[i]);
02561 tmp = dist_ps_internal(pt, &lseg);
02562 if (!have_min || tmp < result)
02563 {
02564 result = tmp;
02565 have_min = true;
02566 }
02567 }
02568 break;
02569 }
02570 PG_RETURN_FLOAT8(result);
02571 }
02572
02573 Datum
02574 dist_pb(PG_FUNCTION_ARGS)
02575 {
02576 Point *pt = PG_GETARG_POINT_P(0);
02577 BOX *box = PG_GETARG_BOX_P(1);
02578 float8 result;
02579 Point *near;
02580
02581 near = DatumGetPointP(DirectFunctionCall2(close_pb,
02582 PointPGetDatum(pt),
02583 BoxPGetDatum(box)));
02584 result = point_dt(near, pt);
02585
02586 PG_RETURN_FLOAT8(result);
02587 }
02588
02589
02590 Datum
02591 dist_sl(PG_FUNCTION_ARGS)
02592 {
02593 LSEG *lseg = PG_GETARG_LSEG_P(0);
02594 LINE *line = PG_GETARG_LINE_P(1);
02595 float8 result,
02596 d2;
02597
02598 if (has_interpt_sl(lseg, line))
02599 result = 0.0;
02600 else
02601 {
02602 result = dist_pl_internal(&lseg->p[0], line);
02603 d2 = dist_pl_internal(&lseg->p[1], line);
02604
02605 if (d2 > result)
02606 result = d2;
02607 }
02608
02609 PG_RETURN_FLOAT8(result);
02610 }
02611
02612
02613 Datum
02614 dist_sb(PG_FUNCTION_ARGS)
02615 {
02616 LSEG *lseg = PG_GETARG_LSEG_P(0);
02617 BOX *box = PG_GETARG_BOX_P(1);
02618 Point *tmp;
02619 Datum result;
02620
02621 tmp = DatumGetPointP(DirectFunctionCall2(close_sb,
02622 LsegPGetDatum(lseg),
02623 BoxPGetDatum(box)));
02624 result = DirectFunctionCall2(dist_pb,
02625 PointPGetDatum(tmp),
02626 BoxPGetDatum(box));
02627
02628 PG_RETURN_DATUM(result);
02629 }
02630
02631
02632 Datum
02633 dist_lb(PG_FUNCTION_ARGS)
02634 {
02635 #ifdef NOT_USED
02636 LINE *line = PG_GETARG_LINE_P(0);
02637 BOX *box = PG_GETARG_BOX_P(1);
02638 #endif
02639
02640
02641 ereport(ERROR,
02642 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02643 errmsg("function \"dist_lb\" not implemented")));
02644
02645 PG_RETURN_NULL();
02646 }
02647
02648
02649 Datum
02650 dist_cpoly(PG_FUNCTION_ARGS)
02651 {
02652 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
02653 POLYGON *poly = PG_GETARG_POLYGON_P(1);
02654 float8 result;
02655 float8 d;
02656 int i;
02657 LSEG seg;
02658
02659 if (point_inside(&(circle->center), poly->npts, poly->p) != 0)
02660 {
02661 #ifdef GEODEBUG
02662 printf("dist_cpoly- center inside of polygon\n");
02663 #endif
02664 PG_RETURN_FLOAT8(0.0);
02665 }
02666
02667
02668 seg.p[0].x = poly->p[0].x;
02669 seg.p[0].y = poly->p[0].y;
02670 seg.p[1].x = poly->p[poly->npts - 1].x;
02671 seg.p[1].y = poly->p[poly->npts - 1].y;
02672 result = dist_ps_internal(&circle->center, &seg);
02673 #ifdef GEODEBUG
02674 printf("dist_cpoly- segment 0/n distance is %f\n", result);
02675 #endif
02676
02677
02678 for (i = 0; (i < poly->npts - 1); i++)
02679 {
02680 seg.p[0].x = poly->p[i].x;
02681 seg.p[0].y = poly->p[i].y;
02682 seg.p[1].x = poly->p[i + 1].x;
02683 seg.p[1].y = poly->p[i + 1].y;
02684 d = dist_ps_internal(&circle->center, &seg);
02685 #ifdef GEODEBUG
02686 printf("dist_cpoly- segment %d distance is %f\n", (i + 1), d);
02687 #endif
02688 if (d < result)
02689 result = d;
02690 }
02691
02692 result -= circle->radius;
02693 if (result < 0)
02694 result = 0;
02695
02696 PG_RETURN_FLOAT8(result);
02697 }
02698
02699
02700
02701
02702
02703
02704
02705
02706
02707
02708 static Point *
02709 interpt_sl(LSEG *lseg, LINE *line)
02710 {
02711 LINE tmp;
02712 Point *p;
02713
02714 line_construct_pts(&tmp, &lseg->p[0], &lseg->p[1]);
02715 p = line_interpt_internal(&tmp, line);
02716 #ifdef GEODEBUG
02717 printf("interpt_sl- segment is (%.*g %.*g) (%.*g %.*g)\n",
02718 DBL_DIG, lseg->p[0].x, DBL_DIG, lseg->p[0].y, DBL_DIG, lseg->p[1].x, DBL_DIG, lseg->p[1].y);
02719 printf("interpt_sl- segment becomes line A=%.*g B=%.*g C=%.*g\n",
02720 DBL_DIG, tmp.A, DBL_DIG, tmp.B, DBL_DIG, tmp.C);
02721 #endif
02722 if (PointerIsValid(p))
02723 {
02724 #ifdef GEODEBUG
02725 printf("interpt_sl- intersection point is (%.*g %.*g)\n", DBL_DIG, p->x, DBL_DIG, p->y);
02726 #endif
02727 if (on_ps_internal(p, lseg))
02728 {
02729 #ifdef GEODEBUG
02730 printf("interpt_sl- intersection point is on segment\n");
02731 #endif
02732 }
02733 else
02734 p = NULL;
02735 }
02736
02737 return p;
02738 }
02739
02740
02741 static bool
02742 has_interpt_sl(LSEG *lseg, LINE *line)
02743 {
02744 Point *tmp;
02745
02746 tmp = interpt_sl(lseg, line);
02747 if (tmp)
02748 return true;
02749 return false;
02750 }
02751
02752
02753
02754
02755
02756
02757
02758
02759
02760
02761 Datum
02762 close_pl(PG_FUNCTION_ARGS)
02763 {
02764 Point *pt = PG_GETARG_POINT_P(0);
02765 LINE *line = PG_GETARG_LINE_P(1);
02766 Point *result;
02767 LINE *tmp;
02768 double invm;
02769
02770 result = (Point *) palloc(sizeof(Point));
02771
02772 #ifdef NOT_USED
02773 if (FPeq(line->A, -1.0) && FPzero(line->B))
02774 {
02775 }
02776 #endif
02777 if (FPzero(line->B))
02778 {
02779 result->x = line->C;
02780 result->y = pt->y;
02781 PG_RETURN_POINT_P(result);
02782 }
02783 if (FPzero(line->A))
02784 {
02785 result->x = pt->x;
02786 result->y = line->C;
02787 PG_RETURN_POINT_P(result);
02788 }
02789
02790 #ifdef NOT_USED
02791 invm = -1.0 / line->m;
02792 #endif
02793
02794 invm = line->B / line->A;
02795 tmp = line_construct_pm(pt, invm);
02796 result = line_interpt_internal(tmp, line);
02797 Assert(result != NULL);
02798 PG_RETURN_POINT_P(result);
02799 }
02800
02801
02802
02803
02804
02805
02806
02807
02808
02809
02810
02811
02812 Datum
02813 close_ps(PG_FUNCTION_ARGS)
02814 {
02815 Point *pt = PG_GETARG_POINT_P(0);
02816 LSEG *lseg = PG_GETARG_LSEG_P(1);
02817 Point *result = NULL;
02818 LINE *tmp;
02819 double invm;
02820 int xh,
02821 yh;
02822
02823 #ifdef GEODEBUG
02824 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",
02825 pt->x, pt->y, lseg->p[0].x, lseg->p[0].y,
02826 lseg->p[1].x, lseg->p[1].y);
02827 #endif
02828
02829
02830
02831 xh = lseg->p[0].x < lseg->p[1].x;
02832 yh = lseg->p[0].y < lseg->p[1].y;
02833
02834 if (FPeq(lseg->p[0].x, lseg->p[1].x))
02835 {
02836 #ifdef GEODEBUG
02837 printf("close_ps- segment is vertical\n");
02838 #endif
02839
02840 if (pt->y < lseg->p[!yh].y)
02841 result = point_copy(&lseg->p[!yh]);
02842 else if (pt->y > lseg->p[yh].y)
02843 result = point_copy(&lseg->p[yh]);
02844 if (result != NULL)
02845 PG_RETURN_POINT_P(result);
02846
02847
02848
02849 result = (Point *) palloc(sizeof(Point));
02850 result->x = lseg->p[0].x;
02851 result->y = pt->y;
02852 PG_RETURN_POINT_P(result);
02853 }
02854 else if (FPeq(lseg->p[0].y, lseg->p[1].y))
02855 {
02856 #ifdef GEODEBUG
02857 printf("close_ps- segment is horizontal\n");
02858 #endif
02859
02860 if (pt->x < lseg->p[!xh].x)
02861 result = point_copy(&lseg->p[!xh]);
02862 else if (pt->x > lseg->p[xh].x)
02863 result = point_copy(&lseg->p[xh]);
02864 if (result != NULL)
02865 PG_RETURN_POINT_P(result);
02866
02867
02868 result = (Point *) palloc(sizeof(Point));
02869 result->x = pt->x;
02870 result->y = lseg->p[0].y;
02871 PG_RETURN_POINT_P(result);
02872 }
02873
02874
02875
02876
02877
02878
02879 invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
02880 tmp = line_construct_pm(&lseg->p[!yh], invm);
02881
02882 if (pt->y < (tmp->A * pt->x + tmp->C))
02883 {
02884 result = point_copy(&lseg->p[!yh]);
02885
02886 #ifdef GEODEBUG
02887 printf("close_ps below: tmp A %f B %f C %f m %f\n",
02888 tmp->A, tmp->B, tmp->C, tmp->m);
02889 #endif
02890 PG_RETURN_POINT_P(result);
02891 }
02892 tmp = line_construct_pm(&lseg->p[yh], invm);
02893
02894 if (pt->y > (tmp->A * pt->x + tmp->C))
02895 {
02896 result = point_copy(&lseg->p[yh]);
02897
02898 #ifdef GEODEBUG
02899 printf("close_ps above: tmp A %f B %f C %f m %f\n",
02900 tmp->A, tmp->B, tmp->C, tmp->m);
02901 #endif
02902 PG_RETURN_POINT_P(result);
02903 }
02904
02905
02906
02907
02908
02909 tmp = line_construct_pm(pt, invm);
02910 #ifdef GEODEBUG
02911 printf("close_ps- tmp A %f B %f C %f m %f\n",
02912 tmp->A, tmp->B, tmp->C, tmp->m);
02913 #endif
02914 result = interpt_sl(lseg, tmp);
02915 Assert(result != NULL);
02916 #ifdef GEODEBUG
02917 printf("close_ps- result.x %f result.y %f\n", result->x, result->y);
02918 #endif
02919 PG_RETURN_POINT_P(result);
02920 }
02921
02922
02923
02924
02925
02926 Datum
02927 close_lseg(PG_FUNCTION_ARGS)
02928 {
02929 LSEG *l1 = PG_GETARG_LSEG_P(0);
02930 LSEG *l2 = PG_GETARG_LSEG_P(1);
02931 Point *result = NULL;
02932 Point point;
02933 double dist;
02934 double d;
02935
02936 d = dist_ps_internal(&l1->p[0], l2);
02937 dist = d;
02938 memcpy(&point, &l1->p[0], sizeof(Point));
02939
02940 if ((d = dist_ps_internal(&l1->p[1], l2)) < dist)
02941 {
02942 dist = d;
02943 memcpy(&point, &l1->p[1], sizeof(Point));
02944 }
02945
02946 if (dist_ps_internal(&l2->p[0], l1) < dist)
02947 {
02948 result = DatumGetPointP(DirectFunctionCall2(close_ps,
02949 PointPGetDatum(&l2->p[0]),
02950 LsegPGetDatum(l1)));
02951 memcpy(&point, result, sizeof(Point));
02952 result = DatumGetPointP(DirectFunctionCall2(close_ps,
02953 PointPGetDatum(&point),
02954 LsegPGetDatum(l2)));
02955 }
02956
02957 if (dist_ps_internal(&l2->p[1], l1) < dist)
02958 {
02959 result = DatumGetPointP(DirectFunctionCall2(close_ps,
02960 PointPGetDatum(&l2->p[1]),
02961 LsegPGetDatum(l1)));
02962 memcpy(&point, result, sizeof(Point));
02963 result = DatumGetPointP(DirectFunctionCall2(close_ps,
02964 PointPGetDatum(&point),
02965 LsegPGetDatum(l2)));
02966 }
02967
02968 if (result == NULL)
02969 result = point_copy(&point);
02970
02971 PG_RETURN_POINT_P(result);
02972 }
02973
02974
02975
02976
02977 Datum
02978 close_pb(PG_FUNCTION_ARGS)
02979 {
02980 Point *pt = PG_GETARG_POINT_P(0);
02981 BOX *box = PG_GETARG_BOX_P(1);
02982 LSEG lseg,
02983 seg;
02984 Point point;
02985 double dist,
02986 d;
02987
02988 if (DatumGetBool(DirectFunctionCall2(on_pb,
02989 PointPGetDatum(pt),
02990 BoxPGetDatum(box))))
02991 PG_RETURN_POINT_P(pt);
02992
02993
02994 point.x = box->low.x;
02995 point.y = box->high.y;
02996 statlseg_construct(&lseg, &box->low, &point);
02997 dist = dist_ps_internal(pt, &lseg);
02998
02999 statlseg_construct(&seg, &box->high, &point);
03000 if ((d = dist_ps_internal(pt, &seg)) < dist)
03001 {
03002 dist = d;
03003 memcpy(&lseg, &seg, sizeof(lseg));
03004 }
03005
03006 point.x = box->high.x;
03007 point.y = box->low.y;
03008 statlseg_construct(&seg, &box->low, &point);
03009 if ((d = dist_ps_internal(pt, &seg)) < dist)
03010 {
03011 dist = d;
03012 memcpy(&lseg, &seg, sizeof(lseg));
03013 }
03014
03015 statlseg_construct(&seg, &box->high, &point);
03016 if ((d = dist_ps_internal(pt, &seg)) < dist)
03017 {
03018 dist = d;
03019 memcpy(&lseg, &seg, sizeof(lseg));
03020 }
03021
03022 PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
03023 PointPGetDatum(pt),
03024 LsegPGetDatum(&lseg)));
03025 }
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036 Datum
03037 close_sl(PG_FUNCTION_ARGS)
03038 {
03039 LSEG *lseg = PG_GETARG_LSEG_P(0);
03040 LINE *line = PG_GETARG_LINE_P(1);
03041 Point *result;
03042 float8 d1,
03043 d2;
03044
03045 result = interpt_sl(lseg, line);
03046 if (result)
03047 PG_RETURN_POINT_P(result);
03048
03049 d1 = dist_pl_internal(&lseg->p[0], line);
03050 d2 = dist_pl_internal(&lseg->p[1], line);
03051 if (d1 < d2)
03052 result = point_copy(&lseg->p[0]);
03053 else
03054 result = point_copy(&lseg->p[1]);
03055
03056 PG_RETURN_POINT_P(result);
03057 }
03058
03059
03060
03061
03062 Datum
03063 close_ls(PG_FUNCTION_ARGS)
03064 {
03065 LINE *line = PG_GETARG_LINE_P(0);
03066 LSEG *lseg = PG_GETARG_LSEG_P(1);
03067 Point *result;
03068 float8 d1,
03069 d2;
03070
03071 result = interpt_sl(lseg, line);
03072 if (result)
03073 PG_RETURN_POINT_P(result);
03074
03075 d1 = dist_pl_internal(&lseg->p[0], line);
03076 d2 = dist_pl_internal(&lseg->p[1], line);
03077 if (d1 < d2)
03078 result = point_copy(&lseg->p[0]);
03079 else
03080 result = point_copy(&lseg->p[1]);
03081
03082 PG_RETURN_POINT_P(result);
03083 }
03084
03085
03086
03087
03088 Datum
03089 close_sb(PG_FUNCTION_ARGS)
03090 {
03091 LSEG *lseg = PG_GETARG_LSEG_P(0);
03092 BOX *box = PG_GETARG_BOX_P(1);
03093 Point point;
03094 LSEG bseg,
03095 seg;
03096 double dist,
03097 d;
03098
03099
03100 if (DatumGetBool(DirectFunctionCall2(inter_sb,
03101 LsegPGetDatum(lseg),
03102 BoxPGetDatum(box))))
03103 {
03104 box_cn(&point, box);
03105 PG_RETURN_DATUM(DirectFunctionCall2(close_ps,
03106 PointPGetDatum(&point),
03107 LsegPGetDatum(lseg)));
03108 }
03109
03110
03111 point.x = box->low.x;
03112 point.y = box->high.y;
03113 statlseg_construct(&bseg, &box->low, &point);
03114 dist = lseg_dt(lseg, &bseg);
03115
03116 statlseg_construct(&seg, &box->high, &point);
03117 if ((d = lseg_dt(lseg, &seg)) < dist)
03118 {
03119 dist = d;
03120 memcpy(&bseg, &seg, sizeof(bseg));
03121 }
03122
03123 point.x = box->high.x;
03124 point.y = box->low.y;
03125 statlseg_construct(&seg, &box->low, &point);
03126 if ((d = lseg_dt(lseg, &seg)) < dist)
03127 {
03128 dist = d;
03129 memcpy(&bseg, &seg, sizeof(bseg));
03130 }
03131
03132 statlseg_construct(&seg, &box->high, &point);
03133 if ((d = lseg_dt(lseg, &seg)) < dist)
03134 {
03135 dist = d;
03136 memcpy(&bseg, &seg, sizeof(bseg));
03137 }
03138
03139
03140 PG_RETURN_DATUM(DirectFunctionCall2(close_lseg,
03141 LsegPGetDatum(lseg),
03142 LsegPGetDatum(&bseg)));
03143 }
03144
03145 Datum
03146 close_lb(PG_FUNCTION_ARGS)
03147 {
03148 #ifdef NOT_USED
03149 LINE *line = PG_GETARG_LINE_P(0);
03150 BOX *box = PG_GETARG_BOX_P(1);
03151 #endif
03152
03153
03154 ereport(ERROR,
03155 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
03156 errmsg("function \"close_lb\" not implemented")));
03157
03158 PG_RETURN_NULL();
03159 }
03160
03161
03162
03163
03164
03165
03166
03167
03168
03169 Datum
03170 on_pl(PG_FUNCTION_ARGS)
03171 {
03172 Point *pt = PG_GETARG_POINT_P(0);
03173 LINE *line = PG_GETARG_LINE_P(1);
03174
03175 PG_RETURN_BOOL(FPzero(line->A * pt->x + line->B * pt->y + line->C));
03176 }
03177
03178
03179
03180
03181
03182
03183 Datum
03184 on_ps(PG_FUNCTION_ARGS)
03185 {
03186 Point *pt = PG_GETARG_POINT_P(0);
03187 LSEG *lseg = PG_GETARG_LSEG_P(1);
03188
03189 PG_RETURN_BOOL(on_ps_internal(pt, lseg));
03190 }
03191
03192 static bool
03193 on_ps_internal(Point *pt, LSEG *lseg)
03194 {
03195 return FPeq(point_dt(pt, &lseg->p[0]) + point_dt(pt, &lseg->p[1]),
03196 point_dt(&lseg->p[0], &lseg->p[1]));
03197 }
03198
03199 Datum
03200 on_pb(PG_FUNCTION_ARGS)
03201 {
03202 Point *pt = PG_GETARG_POINT_P(0);
03203 BOX *box = PG_GETARG_BOX_P(1);
03204
03205 PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x &&
03206 pt->y <= box->high.y && pt->y >= box->low.y);
03207 }
03208
03209 Datum
03210 box_contain_pt(PG_FUNCTION_ARGS)
03211 {
03212 BOX *box = PG_GETARG_BOX_P(0);
03213 Point *pt = PG_GETARG_POINT_P(1);
03214
03215 PG_RETURN_BOOL(pt->x <= box->high.x && pt->x >= box->low.x &&
03216 pt->y <= box->high.y && pt->y >= box->low.y);
03217 }
03218
03219
03220
03221
03222
03223
03224
03225
03226
03227
03228
03229
03230 Datum
03231 on_ppath(PG_FUNCTION_ARGS)
03232 {
03233 Point *pt = PG_GETARG_POINT_P(0);
03234 PATH *path = PG_GETARG_PATH_P(1);
03235 int i,
03236 n;
03237 double a,
03238 b;
03239
03240
03241 if (!path->closed)
03242 {
03243 n = path->npts - 1;
03244 a = point_dt(pt, &path->p[0]);
03245 for (i = 0; i < n; i++)
03246 {
03247 b = point_dt(pt, &path->p[i + 1]);
03248 if (FPeq(a + b,
03249 point_dt(&path->p[i], &path->p[i + 1])))
03250 PG_RETURN_BOOL(true);
03251 a = b;
03252 }
03253 PG_RETURN_BOOL(false);
03254 }
03255
03256
03257 PG_RETURN_BOOL(point_inside(pt, path->npts, path->p) != 0);
03258 }
03259
03260 Datum
03261 on_sl(PG_FUNCTION_ARGS)
03262 {
03263 LSEG *lseg = PG_GETARG_LSEG_P(0);
03264 LINE *line = PG_GETARG_LINE_P(1);
03265
03266 PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pl,
03267 PointPGetDatum(&lseg->p[0]),
03268 LinePGetDatum(line))) &&
03269 DatumGetBool(DirectFunctionCall2(on_pl,
03270 PointPGetDatum(&lseg->p[1]),
03271 LinePGetDatum(line))));
03272 }
03273
03274 Datum
03275 on_sb(PG_FUNCTION_ARGS)
03276 {
03277 LSEG *lseg = PG_GETARG_LSEG_P(0);
03278 BOX *box = PG_GETARG_BOX_P(1);
03279
03280 PG_RETURN_BOOL(DatumGetBool(DirectFunctionCall2(on_pb,
03281 PointPGetDatum(&lseg->p[0]),
03282 BoxPGetDatum(box))) &&
03283 DatumGetBool(DirectFunctionCall2(on_pb,
03284 PointPGetDatum(&lseg->p[1]),
03285 BoxPGetDatum(box))));
03286 }
03287
03288
03289
03290
03291
03292
03293 Datum
03294 inter_sl(PG_FUNCTION_ARGS)
03295 {
03296 LSEG *lseg = PG_GETARG_LSEG_P(0);
03297 LINE *line = PG_GETARG_LINE_P(1);
03298
03299 PG_RETURN_BOOL(has_interpt_sl(lseg, line));
03300 }
03301
03302
03303
03304
03305
03306
03307
03308
03309
03310
03311
03312 Datum
03313 inter_sb(PG_FUNCTION_ARGS)
03314 {
03315 LSEG *lseg = PG_GETARG_LSEG_P(0);
03316 BOX *box = PG_GETARG_BOX_P(1);
03317 BOX lbox;
03318 LSEG bseg;
03319 Point point;
03320
03321 lbox.low.x = Min(lseg->p[0].x, lseg->p[1].x);
03322 lbox.low.y = Min(lseg->p[0].y, lseg->p[1].y);
03323 lbox.high.x = Max(lseg->p[0].x, lseg->p[1].x);
03324 lbox.high.y = Max(lseg->p[0].y, lseg->p[1].y);
03325
03326
03327 if (!box_ov(&lbox, box))
03328 PG_RETURN_BOOL(false);
03329
03330
03331 if (DatumGetBool(DirectFunctionCall2(on_pb,
03332 PointPGetDatum(&lseg->p[0]),
03333 BoxPGetDatum(box))) ||
03334 DatumGetBool(DirectFunctionCall2(on_pb,
03335 PointPGetDatum(&lseg->p[1]),
03336 BoxPGetDatum(box))))
03337 PG_RETURN_BOOL(true);
03338
03339
03340 point.x = box->low.x;
03341 point.y = box->high.y;
03342 statlseg_construct(&bseg, &box->low, &point);
03343 if (lseg_intersect_internal(&bseg, lseg))
03344 PG_RETURN_BOOL(true);
03345
03346 statlseg_construct(&bseg, &box->high, &point);
03347 if (lseg_intersect_internal(&bseg, lseg))
03348 PG_RETURN_BOOL(true);
03349
03350 point.x = box->high.x;
03351 point.y = box->low.y;
03352 statlseg_construct(&bseg, &box->low, &point);
03353 if (lseg_intersect_internal(&bseg, lseg))
03354 PG_RETURN_BOOL(true);
03355
03356 statlseg_construct(&bseg, &box->high, &point);
03357 if (lseg_intersect_internal(&bseg, lseg))
03358 PG_RETURN_BOOL(true);
03359
03360
03361 PG_RETURN_BOOL(false);
03362 }
03363
03364
03365
03366
03367 Datum
03368 inter_lb(PG_FUNCTION_ARGS)
03369 {
03370 LINE *line = PG_GETARG_LINE_P(0);
03371 BOX *box = PG_GETARG_BOX_P(1);
03372 LSEG bseg;
03373 Point p1,
03374 p2;
03375
03376
03377 p1.x = box->low.x;
03378 p1.y = box->low.y;
03379 p2.x = box->low.x;
03380 p2.y = box->high.y;
03381 statlseg_construct(&bseg, &p1, &p2);
03382 if (has_interpt_sl(&bseg, line))
03383 PG_RETURN_BOOL(true);
03384 p1.x = box->high.x;
03385 p1.y = box->high.y;
03386 statlseg_construct(&bseg, &p1, &p2);
03387 if (has_interpt_sl(&bseg, line))
03388 PG_RETURN_BOOL(true);
03389 p2.x = box->high.x;
03390 p2.y = box->low.y;
03391 statlseg_construct(&bseg, &p1, &p2);
03392 if (has_interpt_sl(&bseg, line))
03393 PG_RETURN_BOOL(true);
03394 p1.x = box->low.x;
03395 p1.y = box->low.y;
03396 statlseg_construct(&bseg, &p1, &p2);
03397 if (has_interpt_sl(&bseg, line))
03398 PG_RETURN_BOOL(true);
03399
03400
03401 PG_RETURN_BOOL(false);
03402 }
03403
03404
03405
03406
03407
03408
03409
03410
03411
03412
03413
03414
03415 static void
03416 make_bound_box(POLYGON *poly)
03417 {
03418 int i;
03419 double x1,
03420 y1,
03421 x2,
03422 y2;
03423
03424 if (poly->npts > 0)
03425 {
03426 x2 = x1 = poly->p[0].x;
03427 y2 = y1 = poly->p[0].y;
03428 for (i = 1; i < poly->npts; i++)
03429 {
03430 if (poly->p[i].x < x1)
03431 x1 = poly->p[i].x;
03432 if (poly->p[i].x > x2)
03433 x2 = poly->p[i].x;
03434 if (poly->p[i].y < y1)
03435 y1 = poly->p[i].y;
03436 if (poly->p[i].y > y2)
03437 y2 = poly->p[i].y;
03438 }
03439
03440 box_fill(&(poly->boundbox), x1, x2, y1, y2);
03441 }
03442 else
03443 ereport(ERROR,
03444 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
03445 errmsg("cannot create bounding box for empty polygon")));
03446 }
03447
03448
03449
03450
03451
03452
03453
03454
03455
03456 Datum
03457 poly_in(PG_FUNCTION_ARGS)
03458 {
03459 char *str = PG_GETARG_CSTRING(0);
03460 POLYGON *poly;
03461 int npts;
03462 int size;
03463 int isopen;
03464 char *s;
03465
03466 if ((npts = pair_count(str, ',')) <= 0)
03467 ereport(ERROR,
03468 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
03469 errmsg("invalid input syntax for type polygon: \"%s\"", str)));
03470
03471 size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * npts;
03472 poly = (POLYGON *) palloc0(size);
03473
03474 SET_VARSIZE(poly, size);
03475 poly->npts = npts;
03476
03477 if ((!path_decode(FALSE, npts, str, &isopen, &s, &(poly->p[0])))
03478 || (*s != '\0'))
03479 ereport(ERROR,
03480 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
03481 errmsg("invalid input syntax for type polygon: \"%s\"", str)));
03482
03483 make_bound_box(poly);
03484
03485 PG_RETURN_POLYGON_P(poly);
03486 }
03487
03488
03489
03490
03491
03492 Datum
03493 poly_out(PG_FUNCTION_ARGS)
03494 {
03495 POLYGON *poly = PG_GETARG_POLYGON_P(0);
03496
03497 PG_RETURN_CSTRING(path_encode(TRUE, poly->npts, poly->p));
03498 }
03499
03500
03501
03502
03503
03504
03505
03506
03507
03508 Datum
03509 poly_recv(PG_FUNCTION_ARGS)
03510 {
03511 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
03512 POLYGON *poly;
03513 int32 npts;
03514 int32 i;
03515 int size;
03516
03517 npts = pq_getmsgint(buf, sizeof(int32));
03518 if (npts <= 0 || npts >= (int32) ((INT_MAX - offsetof(POLYGON, p[0])) / sizeof(Point)))
03519 ereport(ERROR,
03520 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
03521 errmsg("invalid number of points in external \"polygon\" value")));
03522
03523 size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * npts;
03524 poly = (POLYGON *) palloc0(size);
03525
03526 SET_VARSIZE(poly, size);
03527 poly->npts = npts;
03528
03529 for (i = 0; i < npts; i++)
03530 {
03531 poly->p[i].x = pq_getmsgfloat8(buf);
03532 poly->p[i].y = pq_getmsgfloat8(buf);
03533 }
03534
03535 make_bound_box(poly);
03536
03537 PG_RETURN_POLYGON_P(poly);
03538 }
03539
03540
03541
03542
03543 Datum
03544 poly_send(PG_FUNCTION_ARGS)
03545 {
03546 POLYGON *poly = PG_GETARG_POLYGON_P(0);
03547 StringInfoData buf;
03548 int32 i;
03549
03550 pq_begintypsend(&buf);
03551 pq_sendint(&buf, poly->npts, sizeof(int32));
03552 for (i = 0; i < poly->npts; i++)
03553 {
03554 pq_sendfloat8(&buf, poly->p[i].x);
03555 pq_sendfloat8(&buf, poly->p[i].y);
03556 }
03557 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
03558 }
03559
03560
03561
03562
03563
03564
03565
03566 Datum
03567 poly_left(PG_FUNCTION_ARGS)
03568 {
03569 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03570 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03571 bool result;
03572
03573 result = polya->boundbox.high.x < polyb->boundbox.low.x;
03574
03575
03576
03577
03578 PG_FREE_IF_COPY(polya, 0);
03579 PG_FREE_IF_COPY(polyb, 1);
03580
03581 PG_RETURN_BOOL(result);
03582 }
03583
03584
03585
03586
03587
03588
03589 Datum
03590 poly_overleft(PG_FUNCTION_ARGS)
03591 {
03592 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03593 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03594 bool result;
03595
03596 result = polya->boundbox.high.x <= polyb->boundbox.high.x;
03597
03598
03599
03600
03601 PG_FREE_IF_COPY(polya, 0);
03602 PG_FREE_IF_COPY(polyb, 1);
03603
03604 PG_RETURN_BOOL(result);
03605 }
03606
03607
03608
03609
03610
03611
03612 Datum
03613 poly_right(PG_FUNCTION_ARGS)
03614 {
03615 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03616 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03617 bool result;
03618
03619 result = polya->boundbox.low.x > polyb->boundbox.high.x;
03620
03621
03622
03623
03624 PG_FREE_IF_COPY(polya, 0);
03625 PG_FREE_IF_COPY(polyb, 1);
03626
03627 PG_RETURN_BOOL(result);
03628 }
03629
03630
03631
03632
03633
03634
03635 Datum
03636 poly_overright(PG_FUNCTION_ARGS)
03637 {
03638 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03639 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03640 bool result;
03641
03642 result = polya->boundbox.low.x >= polyb->boundbox.low.x;
03643
03644
03645
03646
03647 PG_FREE_IF_COPY(polya, 0);
03648 PG_FREE_IF_COPY(polyb, 1);
03649
03650 PG_RETURN_BOOL(result);
03651 }
03652
03653
03654
03655
03656
03657
03658 Datum
03659 poly_below(PG_FUNCTION_ARGS)
03660 {
03661 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03662 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03663 bool result;
03664
03665 result = polya->boundbox.high.y < polyb->boundbox.low.y;
03666
03667
03668
03669
03670 PG_FREE_IF_COPY(polya, 0);
03671 PG_FREE_IF_COPY(polyb, 1);
03672
03673 PG_RETURN_BOOL(result);
03674 }
03675
03676
03677
03678
03679
03680
03681 Datum
03682 poly_overbelow(PG_FUNCTION_ARGS)
03683 {
03684 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03685 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03686 bool result;
03687
03688 result = polya->boundbox.high.y <= polyb->boundbox.high.y;
03689
03690
03691
03692
03693 PG_FREE_IF_COPY(polya, 0);
03694 PG_FREE_IF_COPY(polyb, 1);
03695
03696 PG_RETURN_BOOL(result);
03697 }
03698
03699
03700
03701
03702
03703
03704 Datum
03705 poly_above(PG_FUNCTION_ARGS)
03706 {
03707 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03708 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03709 bool result;
03710
03711 result = polya->boundbox.low.y > polyb->boundbox.high.y;
03712
03713
03714
03715
03716 PG_FREE_IF_COPY(polya, 0);
03717 PG_FREE_IF_COPY(polyb, 1);
03718
03719 PG_RETURN_BOOL(result);
03720 }
03721
03722
03723
03724
03725
03726
03727 Datum
03728 poly_overabove(PG_FUNCTION_ARGS)
03729 {
03730 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03731 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03732 bool result;
03733
03734 result = polya->boundbox.low.y >= polyb->boundbox.low.y;
03735
03736
03737
03738
03739 PG_FREE_IF_COPY(polya, 0);
03740 PG_FREE_IF_COPY(polyb, 1);
03741
03742 PG_RETURN_BOOL(result);
03743 }
03744
03745
03746
03747
03748
03749
03750
03751
03752
03753 Datum
03754 poly_same(PG_FUNCTION_ARGS)
03755 {
03756 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03757 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03758 bool result;
03759
03760 if (polya->npts != polyb->npts)
03761 result = false;
03762 else
03763 result = plist_same(polya->npts, polya->p, polyb->p);
03764
03765
03766
03767
03768 PG_FREE_IF_COPY(polya, 0);
03769 PG_FREE_IF_COPY(polyb, 1);
03770
03771 PG_RETURN_BOOL(result);
03772 }
03773
03774
03775
03776
03777 Datum
03778 poly_overlap(PG_FUNCTION_ARGS)
03779 {
03780 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03781 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03782 bool result;
03783
03784
03785 result = (polya->npts > 0 && polyb->npts > 0 &&
03786 box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
03787
03788
03789
03790
03791
03792
03793 if (result)
03794 {
03795 int ia,
03796 ib;
03797 LSEG sa,
03798 sb;
03799
03800
03801 sa.p[0] = polya->p[polya->npts - 1];
03802 result = false;
03803
03804 for (ia = 0; ia < polya->npts && result == false; ia++)
03805 {
03806
03807 sa.p[1] = polya->p[ia];
03808
03809
03810 sb.p[0] = polyb->p[polyb->npts - 1];
03811
03812 for (ib = 0; ib < polyb->npts && result == false; ib++)
03813 {
03814 sb.p[1] = polyb->p[ib];
03815 result = lseg_intersect_internal(&sa, &sb);
03816 sb.p[0] = sb.p[1];
03817 }
03818
03819
03820
03821
03822 sa.p[0] = sa.p[1];
03823 }
03824
03825 if (result == false)
03826 {
03827 result = (point_inside(polya->p, polyb->npts, polyb->p)
03828 ||
03829 point_inside(polyb->p, polya->npts, polya->p));
03830 }
03831 }
03832
03833
03834
03835
03836 PG_FREE_IF_COPY(polya, 0);
03837 PG_FREE_IF_COPY(polyb, 1);
03838
03839 PG_RETURN_BOOL(result);
03840 }
03841
03842
03843
03844
03845
03846
03847
03848
03849
03850
03851
03852
03853 static bool
03854 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
03855 {
03856
03857 LSEG t;
03858
03859 t.p[0] = *a;
03860 t.p[1] = *b;
03861
03862 #define POINTEQ(pt1, pt2) (FPeq((pt1)->x, (pt2)->x) && FPeq((pt1)->y, (pt2)->y))
03863 if (POINTEQ(a, s->p))
03864 {
03865 if (on_ps_internal(s->p + 1, &t))
03866 return lseg_inside_poly(b, s->p + 1, poly, start);
03867 }
03868 else if (POINTEQ(a, s->p + 1))
03869 {
03870 if (on_ps_internal(s->p, &t))
03871 return lseg_inside_poly(b, s->p, poly, start);
03872 }
03873 else if (on_ps_internal(s->p, &t))
03874 {
03875 return lseg_inside_poly(b, s->p, poly, start);
03876 }
03877 else if (on_ps_internal(s->p + 1, &t))
03878 {
03879 return lseg_inside_poly(b, s->p + 1, poly, start);
03880 }
03881
03882 return true;
03883 }
03884
03885
03886
03887
03888
03889
03890 static bool
03891 lseg_inside_poly(Point *a, Point *b, POLYGON *poly, int start)
03892 {
03893 LSEG s,
03894 t;
03895 int i;
03896 bool res = true,
03897 intersection = false;
03898
03899 t.p[0] = *a;
03900 t.p[1] = *b;
03901 s.p[0] = poly->p[(start == 0) ? (poly->npts - 1) : (start - 1)];
03902
03903 for (i = start; i < poly->npts && res; i++)
03904 {
03905 Point *interpt;
03906
03907 s.p[1] = poly->p[i];
03908
03909 if (on_ps_internal(t.p, &s))
03910 {
03911 if (on_ps_internal(t.p + 1, &s))
03912 return true;
03913
03914
03915 res = touched_lseg_inside_poly(t.p, t.p + 1, &s, poly, i + 1);
03916 }
03917 else if (on_ps_internal(t.p + 1, &s))
03918 {
03919
03920 res = touched_lseg_inside_poly(t.p + 1, t.p, &s, poly, i + 1);
03921 }
03922 else if ((interpt = lseg_interpt_internal(&t, &s)) != NULL)
03923 {
03924
03925
03926
03927
03928 intersection = true;
03929 res = lseg_inside_poly(t.p, interpt, poly, i + 1);
03930 if (res)
03931 res = lseg_inside_poly(t.p + 1, interpt, poly, i + 1);
03932 pfree(interpt);
03933 }
03934
03935 s.p[0] = s.p[1];
03936 }
03937
03938 if (res && !intersection)
03939 {
03940 Point p;
03941
03942
03943
03944
03945
03946 p.x = (t.p[0].x + t.p[1].x) / 2.0;
03947 p.y = (t.p[0].y + t.p[1].y) / 2.0;
03948
03949 res = point_inside(&p, poly->npts, poly->p);
03950 }
03951
03952 return res;
03953 }
03954
03955
03956
03957
03958 Datum
03959 poly_contain(PG_FUNCTION_ARGS)
03960 {
03961 POLYGON *polya = PG_GETARG_POLYGON_P(0);
03962 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
03963 bool result;
03964
03965
03966
03967
03968 if (polya->npts > 0 && polyb->npts > 0 &&
03969 DatumGetBool(DirectFunctionCall2(box_contain,
03970 BoxPGetDatum(&polya->boundbox),
03971 BoxPGetDatum(&polyb->boundbox))))
03972 {
03973 int i;
03974 LSEG s;
03975
03976 s.p[0] = polyb->p[polyb->npts - 1];
03977 result = true;
03978
03979 for (i = 0; i < polyb->npts && result; i++)
03980 {
03981 s.p[1] = polyb->p[i];
03982 result = lseg_inside_poly(s.p, s.p + 1, polya, 0);
03983 s.p[0] = s.p[1];
03984 }
03985 }
03986 else
03987 {
03988 result = false;
03989 }
03990
03991
03992
03993
03994 PG_FREE_IF_COPY(polya, 0);
03995 PG_FREE_IF_COPY(polyb, 1);
03996
03997 PG_RETURN_BOOL(result);
03998 }
03999
04000
04001
04002
04003
04004 Datum
04005 poly_contained(PG_FUNCTION_ARGS)
04006 {
04007 Datum polya = PG_GETARG_DATUM(0);
04008 Datum polyb = PG_GETARG_DATUM(1);
04009
04010
04011 PG_RETURN_DATUM(DirectFunctionCall2(poly_contain, polyb, polya));
04012 }
04013
04014
04015 Datum
04016 poly_contain_pt(PG_FUNCTION_ARGS)
04017 {
04018 POLYGON *poly = PG_GETARG_POLYGON_P(0);
04019 Point *p = PG_GETARG_POINT_P(1);
04020
04021 PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
04022 }
04023
04024 Datum
04025 pt_contained_poly(PG_FUNCTION_ARGS)
04026 {
04027 Point *p = PG_GETARG_POINT_P(0);
04028 POLYGON *poly = PG_GETARG_POLYGON_P(1);
04029
04030 PG_RETURN_BOOL(point_inside(p, poly->npts, poly->p) != 0);
04031 }
04032
04033
04034 Datum
04035 poly_distance(PG_FUNCTION_ARGS)
04036 {
04037 #ifdef NOT_USED
04038 POLYGON *polya = PG_GETARG_POLYGON_P(0);
04039 POLYGON *polyb = PG_GETARG_POLYGON_P(1);
04040 #endif
04041
04042 ereport(ERROR,
04043 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04044 errmsg("function \"poly_distance\" not implemented")));
04045
04046 PG_RETURN_NULL();
04047 }
04048
04049
04050
04051
04052
04053
04054
04055
04056 Datum
04057 construct_point(PG_FUNCTION_ARGS)
04058 {
04059 float8 x = PG_GETARG_FLOAT8(0);
04060 float8 y = PG_GETARG_FLOAT8(1);
04061
04062 PG_RETURN_POINT_P(point_construct(x, y));
04063 }
04064
04065 Datum
04066 point_add(PG_FUNCTION_ARGS)
04067 {
04068 Point *p1 = PG_GETARG_POINT_P(0);
04069 Point *p2 = PG_GETARG_POINT_P(1);
04070 Point *result;
04071
04072 result = (Point *) palloc(sizeof(Point));
04073
04074 result->x = (p1->x + p2->x);
04075 result->y = (p1->y + p2->y);
04076
04077 PG_RETURN_POINT_P(result);
04078 }
04079
04080 Datum
04081 point_sub(PG_FUNCTION_ARGS)
04082 {
04083 Point *p1 = PG_GETARG_POINT_P(0);
04084 Point *p2 = PG_GETARG_POINT_P(1);
04085 Point *result;
04086
04087 result = (Point *) palloc(sizeof(Point));
04088
04089 result->x = (p1->x - p2->x);
04090 result->y = (p1->y - p2->y);
04091
04092 PG_RETURN_POINT_P(result);
04093 }
04094
04095 Datum
04096 point_mul(PG_FUNCTION_ARGS)
04097 {
04098 Point *p1 = PG_GETARG_POINT_P(0);
04099 Point *p2 = PG_GETARG_POINT_P(1);
04100 Point *result;
04101
04102 result = (Point *) palloc(sizeof(Point));
04103
04104 result->x = (p1->x * p2->x) - (p1->y * p2->y);
04105 result->y = (p1->x * p2->y) + (p1->y * p2->x);
04106
04107 PG_RETURN_POINT_P(result);
04108 }
04109
04110 Datum
04111 point_div(PG_FUNCTION_ARGS)
04112 {
04113 Point *p1 = PG_GETARG_POINT_P(0);
04114 Point *p2 = PG_GETARG_POINT_P(1);
04115 Point *result;
04116 double div;
04117
04118 result = (Point *) palloc(sizeof(Point));
04119
04120 div = (p2->x * p2->x) + (p2->y * p2->y);
04121
04122 if (div == 0.0)
04123 ereport(ERROR,
04124 (errcode(ERRCODE_DIVISION_BY_ZERO),
04125 errmsg("division by zero")));
04126
04127 result->x = ((p1->x * p2->x) + (p1->y * p2->y)) / div;
04128 result->y = ((p2->x * p1->y) - (p2->y * p1->x)) / div;
04129
04130 PG_RETURN_POINT_P(result);
04131 }
04132
04133
04134
04135
04136
04137
04138
04139
04140 Datum
04141 points_box(PG_FUNCTION_ARGS)
04142 {
04143 Point *p1 = PG_GETARG_POINT_P(0);
04144 Point *p2 = PG_GETARG_POINT_P(1);
04145
04146 PG_RETURN_BOX_P(box_construct(p1->x, p2->x, p1->y, p2->y));
04147 }
04148
04149 Datum
04150 box_add(PG_FUNCTION_ARGS)
04151 {
04152 BOX *box = PG_GETARG_BOX_P(0);
04153 Point *p = PG_GETARG_POINT_P(1);
04154
04155 PG_RETURN_BOX_P(box_construct((box->high.x + p->x),
04156 (box->low.x + p->x),
04157 (box->high.y + p->y),
04158 (box->low.y + p->y)));
04159 }
04160
04161 Datum
04162 box_sub(PG_FUNCTION_ARGS)
04163 {
04164 BOX *box = PG_GETARG_BOX_P(0);
04165 Point *p = PG_GETARG_POINT_P(1);
04166
04167 PG_RETURN_BOX_P(box_construct((box->high.x - p->x),
04168 (box->low.x - p->x),
04169 (box->high.y - p->y),
04170 (box->low.y - p->y)));
04171 }
04172
04173 Datum
04174 box_mul(PG_FUNCTION_ARGS)
04175 {
04176 BOX *box = PG_GETARG_BOX_P(0);
04177 Point *p = PG_GETARG_POINT_P(1);
04178 BOX *result;
04179 Point *high,
04180 *low;
04181
04182 high = DatumGetPointP(DirectFunctionCall2(point_mul,
04183 PointPGetDatum(&box->high),
04184 PointPGetDatum(p)));
04185 low = DatumGetPointP(DirectFunctionCall2(point_mul,
04186 PointPGetDatum(&box->low),
04187 PointPGetDatum(p)));
04188
04189 result = box_construct(high->x, low->x, high->y, low->y);
04190
04191 PG_RETURN_BOX_P(result);
04192 }
04193
04194 Datum
04195 box_div(PG_FUNCTION_ARGS)
04196 {
04197 BOX *box = PG_GETARG_BOX_P(0);
04198 Point *p = PG_GETARG_POINT_P(1);
04199 BOX *result;
04200 Point *high,
04201 *low;
04202
04203 high = DatumGetPointP(DirectFunctionCall2(point_div,
04204 PointPGetDatum(&box->high),
04205 PointPGetDatum(p)));
04206 low = DatumGetPointP(DirectFunctionCall2(point_div,
04207 PointPGetDatum(&box->low),
04208 PointPGetDatum(p)));
04209
04210 result = box_construct(high->x, low->x, high->y, low->y);
04211
04212 PG_RETURN_BOX_P(result);
04213 }
04214
04215
04216
04217
04218
04219
04220
04221
04222
04223
04224
04225 Datum
04226 path_add(PG_FUNCTION_ARGS)
04227 {
04228 PATH *p1 = PG_GETARG_PATH_P(0);
04229 PATH *p2 = PG_GETARG_PATH_P(1);
04230 PATH *result;
04231 int size,
04232 base_size;
04233 int i;
04234
04235 if (p1->closed || p2->closed)
04236 PG_RETURN_NULL();
04237
04238 base_size = sizeof(p1->p[0]) * (p1->npts + p2->npts);
04239 size = offsetof(PATH, p[0]) +base_size;
04240
04241
04242 if (base_size / sizeof(p1->p[0]) != (p1->npts + p2->npts) ||
04243 size <= base_size)
04244 ereport(ERROR,
04245 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
04246 errmsg("too many points requested")));
04247
04248 result = (PATH *) palloc(size);
04249
04250 SET_VARSIZE(result, size);
04251 result->npts = (p1->npts + p2->npts);
04252 result->closed = p1->closed;
04253
04254 result->dummy = 0;
04255
04256 for (i = 0; i < p1->npts; i++)
04257 {
04258 result->p[i].x = p1->p[i].x;
04259 result->p[i].y = p1->p[i].y;
04260 }
04261 for (i = 0; i < p2->npts; i++)
04262 {
04263 result->p[i + p1->npts].x = p2->p[i].x;
04264 result->p[i + p1->npts].y = p2->p[i].y;
04265 }
04266
04267 PG_RETURN_PATH_P(result);
04268 }
04269
04270
04271
04272
04273 Datum
04274 path_add_pt(PG_FUNCTION_ARGS)
04275 {
04276 PATH *path = PG_GETARG_PATH_P_COPY(0);
04277 Point *point = PG_GETARG_POINT_P(1);
04278 int i;
04279
04280 for (i = 0; i < path->npts; i++)
04281 {
04282 path->p[i].x += point->x;
04283 path->p[i].y += point->y;
04284 }
04285
04286 PG_RETURN_PATH_P(path);
04287 }
04288
04289 Datum
04290 path_sub_pt(PG_FUNCTION_ARGS)
04291 {
04292 PATH *path = PG_GETARG_PATH_P_COPY(0);
04293 Point *point = PG_GETARG_POINT_P(1);
04294 int i;
04295
04296 for (i = 0; i < path->npts; i++)
04297 {
04298 path->p[i].x -= point->x;
04299 path->p[i].y -= point->y;
04300 }
04301
04302 PG_RETURN_PATH_P(path);
04303 }
04304
04305
04306
04307
04308 Datum
04309 path_mul_pt(PG_FUNCTION_ARGS)
04310 {
04311 PATH *path = PG_GETARG_PATH_P_COPY(0);
04312 Point *point = PG_GETARG_POINT_P(1);
04313 Point *p;
04314 int i;
04315
04316 for (i = 0; i < path->npts; i++)
04317 {
04318 p = DatumGetPointP(DirectFunctionCall2(point_mul,
04319 PointPGetDatum(&path->p[i]),
04320 PointPGetDatum(point)));
04321 path->p[i].x = p->x;
04322 path->p[i].y = p->y;
04323 }
04324
04325 PG_RETURN_PATH_P(path);
04326 }
04327
04328 Datum
04329 path_div_pt(PG_FUNCTION_ARGS)
04330 {
04331 PATH *path = PG_GETARG_PATH_P_COPY(0);
04332 Point *point = PG_GETARG_POINT_P(1);
04333 Point *p;
04334 int i;
04335
04336 for (i = 0; i < path->npts; i++)
04337 {
04338 p = DatumGetPointP(DirectFunctionCall2(point_div,
04339 PointPGetDatum(&path->p[i]),
04340 PointPGetDatum(point)));
04341 path->p[i].x = p->x;
04342 path->p[i].y = p->y;
04343 }
04344
04345 PG_RETURN_PATH_P(path);
04346 }
04347
04348
04349 Datum
04350 path_center(PG_FUNCTION_ARGS)
04351 {
04352 #ifdef NOT_USED
04353 PATH *path = PG_GETARG_PATH_P(0);
04354 #endif
04355
04356 ereport(ERROR,
04357 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
04358 errmsg("function \"path_center\" not implemented")));
04359
04360 PG_RETURN_NULL();
04361 }
04362
04363 Datum
04364 path_poly(PG_FUNCTION_ARGS)
04365 {
04366 PATH *path = PG_GETARG_PATH_P(0);
04367 POLYGON *poly;
04368 int size;
04369 int i;
04370
04371
04372 if (!path->closed)
04373 ereport(ERROR,
04374 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04375 errmsg("open path cannot be converted to polygon")));
04376
04377 size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * path->npts;
04378 poly = (POLYGON *) palloc(size);
04379
04380 SET_VARSIZE(poly, size);
04381 poly->npts = path->npts;
04382
04383 for (i = 0; i < path->npts; i++)
04384 {
04385 poly->p[i].x = path->p[i].x;
04386 poly->p[i].y = path->p[i].y;
04387 }
04388
04389 make_bound_box(poly);
04390
04391 PG_RETURN_POLYGON_P(poly);
04392 }
04393
04394
04395
04396
04397
04398
04399
04400
04401 Datum
04402 poly_npoints(PG_FUNCTION_ARGS)
04403 {
04404 POLYGON *poly = PG_GETARG_POLYGON_P(0);
04405
04406 PG_RETURN_INT32(poly->npts);
04407 }
04408
04409
04410 Datum
04411 poly_center(PG_FUNCTION_ARGS)
04412 {
04413 POLYGON *poly = PG_GETARG_POLYGON_P(0);
04414 Datum result;
04415 CIRCLE *circle;
04416
04417 circle = DatumGetCircleP(DirectFunctionCall1(poly_circle,
04418 PolygonPGetDatum(poly)));
04419 result = DirectFunctionCall1(circle_center,
04420 CirclePGetDatum(circle));
04421
04422 PG_RETURN_DATUM(result);
04423 }
04424
04425
04426 Datum
04427 poly_box(PG_FUNCTION_ARGS)
04428 {
04429 POLYGON *poly = PG_GETARG_POLYGON_P(0);
04430 BOX *box;
04431
04432 if (poly->npts < 1)
04433 PG_RETURN_NULL();
04434
04435 box = box_copy(&poly->boundbox);
04436
04437 PG_RETURN_BOX_P(box);
04438 }
04439
04440
04441
04442
04443
04444 Datum
04445 box_poly(PG_FUNCTION_ARGS)
04446 {
04447 BOX *box = PG_GETARG_BOX_P(0);
04448 POLYGON *poly;
04449 int size;
04450
04451
04452 size = offsetof(POLYGON, p[0]) +sizeof(poly->p[0]) * 4;
04453 poly = (POLYGON *) palloc(size);
04454
04455 SET_VARSIZE(poly, size);
04456 poly->npts = 4;
04457
04458 poly->p[0].x = box->low.x;
04459 poly->p[0].y = box->low.y;
04460 poly->p[1].x = box->low.x;
04461 poly->p[1].y = box->high.y;
04462 poly->p[2].x = box->high.x;
04463 poly->p[2].y = box->high.y;
04464 poly->p[3].x = box->high.x;
04465 poly->p[3].y = box->low.y;
04466
04467 box_fill(&poly->boundbox, box->high.x, box->low.x,
04468 box->high.y, box->low.y);
04469
04470 PG_RETURN_POLYGON_P(poly);
04471 }
04472
04473
04474 Datum
04475 poly_path(PG_FUNCTION_ARGS)
04476 {
04477 POLYGON *poly = PG_GETARG_POLYGON_P(0);
04478 PATH *path;
04479 int size;
04480 int i;
04481
04482 size = offsetof(PATH, p[0]) +sizeof(path->p[0]) * poly->npts;
04483 path = (PATH *) palloc(size);
04484
04485 SET_VARSIZE(path, size);
04486 path->npts = poly->npts;
04487 path->closed = TRUE;
04488
04489 path->dummy = 0;
04490
04491 for (i = 0; i < poly->npts; i++)
04492 {
04493 path->p[i].x = poly->p[i].x;
04494 path->p[i].y = poly->p[i].y;
04495 }
04496
04497 PG_RETURN_PATH_P(path);
04498 }
04499
04500
04501
04502
04503
04504
04505
04506
04507
04508
04509
04510
04511
04512
04513
04514
04515
04516
04517 Datum
04518 circle_in(PG_FUNCTION_ARGS)
04519 {
04520 char *str = PG_GETARG_CSTRING(0);
04521 CIRCLE *circle;
04522 char *s,
04523 *cp;
04524 int depth = 0;
04525
04526 circle = (CIRCLE *) palloc(sizeof(CIRCLE));
04527
04528 s = str;
04529 while (isspace((unsigned char) *s))
04530 s++;
04531 if ((*s == LDELIM_C) || (*s == LDELIM))
04532 {
04533 depth++;
04534 cp = (s + 1);
04535 while (isspace((unsigned char) *cp))
04536 cp++;
04537 if (*cp == LDELIM)
04538 s = cp;
04539 }
04540
04541 if (!pair_decode(s, &circle->center.x, &circle->center.y, &s))
04542 ereport(ERROR,
04543 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
04544 errmsg("invalid input syntax for type circle: \"%s\"", str)));
04545
04546 if (*s == DELIM)
04547 s++;
04548 while (isspace((unsigned char) *s))
04549 s++;
04550
04551 if ((!single_decode(s, &circle->radius, &s)) || (circle->radius < 0))
04552 ereport(ERROR,
04553 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
04554 errmsg("invalid input syntax for type circle: \"%s\"", str)));
04555
04556 while (depth > 0)
04557 {
04558 if ((*s == RDELIM)
04559 || ((*s == RDELIM_C) && (depth == 1)))
04560 {
04561 depth--;
04562 s++;
04563 while (isspace((unsigned char) *s))
04564 s++;
04565 }
04566 else
04567 ereport(ERROR,
04568 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
04569 errmsg("invalid input syntax for type circle: \"%s\"", str)));
04570 }
04571
04572 if (*s != '\0')
04573 ereport(ERROR,
04574 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
04575 errmsg("invalid input syntax for type circle: \"%s\"", str)));
04576
04577 PG_RETURN_CIRCLE_P(circle);
04578 }
04579
04580
04581
04582 Datum
04583 circle_out(PG_FUNCTION_ARGS)
04584 {
04585 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
04586 char *result;
04587 char *cp;
04588
04589 result = palloc(2 * P_MAXLEN + 6);
04590
04591 cp = result;
04592 *cp++ = LDELIM_C;
04593 *cp++ = LDELIM;
04594 if (!pair_encode(circle->center.x, circle->center.y, cp))
04595 ereport(ERROR,
04596 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04597 errmsg("could not format \"circle\" value")));
04598
04599 cp += strlen(cp);
04600 *cp++ = RDELIM;
04601 *cp++ = DELIM;
04602 if (!single_encode(circle->radius, cp))
04603 ereport(ERROR,
04604 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
04605 errmsg("could not format \"circle\" value")));
04606
04607 cp += strlen(cp);
04608 *cp++ = RDELIM_C;
04609 *cp = '\0';
04610
04611 PG_RETURN_CSTRING(result);
04612 }
04613
04614
04615
04616
04617 Datum
04618 circle_recv(PG_FUNCTION_ARGS)
04619 {
04620 StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
04621 CIRCLE *circle;
04622
04623 circle = (CIRCLE *) palloc(sizeof(CIRCLE));
04624
04625 circle->center.x = pq_getmsgfloat8(buf);
04626 circle->center.y = pq_getmsgfloat8(buf);
04627 circle->radius = pq_getmsgfloat8(buf);
04628
04629 if (circle->radius < 0)
04630 ereport(ERROR,
04631 (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
04632 errmsg("invalid radius in external \"circle\" value")));
04633
04634 PG_RETURN_CIRCLE_P(circle);
04635 }
04636
04637
04638
04639
04640 Datum
04641 circle_send(PG_FUNCTION_ARGS)
04642 {
04643 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
04644 StringInfoData buf;
04645
04646 pq_begintypsend(&buf);
04647 pq_sendfloat8(&buf, circle->center.x);
04648 pq_sendfloat8(&buf, circle->center.y);
04649 pq_sendfloat8(&buf, circle->radius);
04650 PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
04651 }
04652
04653
04654
04655
04656
04657
04658
04659
04660
04661 Datum
04662 circle_same(PG_FUNCTION_ARGS)
04663 {
04664 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04665 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04666
04667 PG_RETURN_BOOL(FPeq(circle1->radius, circle2->radius) &&
04668 FPeq(circle1->center.x, circle2->center.x) &&
04669 FPeq(circle1->center.y, circle2->center.y));
04670 }
04671
04672
04673
04674 Datum
04675 circle_overlap(PG_FUNCTION_ARGS)
04676 {
04677 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04678 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04679
04680 PG_RETURN_BOOL(FPle(point_dt(&circle1->center, &circle2->center),
04681 circle1->radius + circle2->radius));
04682 }
04683
04684
04685
04686
04687 Datum
04688 circle_overleft(PG_FUNCTION_ARGS)
04689 {
04690 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04691 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04692
04693 PG_RETURN_BOOL(FPle((circle1->center.x + circle1->radius),
04694 (circle2->center.x + circle2->radius)));
04695 }
04696
04697
04698
04699 Datum
04700 circle_left(PG_FUNCTION_ARGS)
04701 {
04702 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04703 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04704
04705 PG_RETURN_BOOL(FPlt((circle1->center.x + circle1->radius),
04706 (circle2->center.x - circle2->radius)));
04707 }
04708
04709
04710
04711 Datum
04712 circle_right(PG_FUNCTION_ARGS)
04713 {
04714 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04715 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04716
04717 PG_RETURN_BOOL(FPgt((circle1->center.x - circle1->radius),
04718 (circle2->center.x + circle2->radius)));
04719 }
04720
04721
04722
04723
04724 Datum
04725 circle_overright(PG_FUNCTION_ARGS)
04726 {
04727 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04728 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04729
04730 PG_RETURN_BOOL(FPge((circle1->center.x - circle1->radius),
04731 (circle2->center.x - circle2->radius)));
04732 }
04733
04734
04735
04736 Datum
04737 circle_contained(PG_FUNCTION_ARGS)
04738 {
04739 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04740 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04741
04742 PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle1->radius), circle2->radius));
04743 }
04744
04745
04746
04747 Datum
04748 circle_contain(PG_FUNCTION_ARGS)
04749 {
04750 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04751 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04752
04753 PG_RETURN_BOOL(FPle((point_dt(&circle1->center, &circle2->center) + circle2->radius), circle1->radius));
04754 }
04755
04756
04757
04758
04759 Datum
04760 circle_below(PG_FUNCTION_ARGS)
04761 {
04762 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04763 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04764
04765 PG_RETURN_BOOL(FPlt((circle1->center.y + circle1->radius),
04766 (circle2->center.y - circle2->radius)));
04767 }
04768
04769
04770
04771 Datum
04772 circle_above(PG_FUNCTION_ARGS)
04773 {
04774 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04775 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04776
04777 PG_RETURN_BOOL(FPgt((circle1->center.y - circle1->radius),
04778 (circle2->center.y + circle2->radius)));
04779 }
04780
04781
04782
04783
04784 Datum
04785 circle_overbelow(PG_FUNCTION_ARGS)
04786 {
04787 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04788 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04789
04790 PG_RETURN_BOOL(FPle((circle1->center.y + circle1->radius),
04791 (circle2->center.y + circle2->radius)));
04792 }
04793
04794
04795
04796
04797 Datum
04798 circle_overabove(PG_FUNCTION_ARGS)
04799 {
04800 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04801 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04802
04803 PG_RETURN_BOOL(FPge((circle1->center.y - circle1->radius),
04804 (circle2->center.y - circle2->radius)));
04805 }
04806
04807
04808
04809
04810
04811 Datum
04812 circle_eq(PG_FUNCTION_ARGS)
04813 {
04814 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04815 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04816
04817 PG_RETURN_BOOL(FPeq(circle_ar(circle1), circle_ar(circle2)));
04818 }
04819
04820 Datum
04821 circle_ne(PG_FUNCTION_ARGS)
04822 {
04823 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04824 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04825
04826 PG_RETURN_BOOL(FPne(circle_ar(circle1), circle_ar(circle2)));
04827 }
04828
04829 Datum
04830 circle_lt(PG_FUNCTION_ARGS)
04831 {
04832 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04833 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04834
04835 PG_RETURN_BOOL(FPlt(circle_ar(circle1), circle_ar(circle2)));
04836 }
04837
04838 Datum
04839 circle_gt(PG_FUNCTION_ARGS)
04840 {
04841 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04842 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04843
04844 PG_RETURN_BOOL(FPgt(circle_ar(circle1), circle_ar(circle2)));
04845 }
04846
04847 Datum
04848 circle_le(PG_FUNCTION_ARGS)
04849 {
04850 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04851 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04852
04853 PG_RETURN_BOOL(FPle(circle_ar(circle1), circle_ar(circle2)));
04854 }
04855
04856 Datum
04857 circle_ge(PG_FUNCTION_ARGS)
04858 {
04859 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
04860 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
04861
04862 PG_RETURN_BOOL(FPge(circle_ar(circle1), circle_ar(circle2)));
04863 }
04864
04865
04866
04867
04868
04869
04870 static CIRCLE *
04871 circle_copy(CIRCLE *circle)
04872 {
04873 CIRCLE *result;
04874
04875 if (!PointerIsValid(circle))
04876 return NULL;
04877
04878 result = (CIRCLE *) palloc(sizeof(CIRCLE));
04879 memcpy((char *) result, (char *) circle, sizeof(CIRCLE));
04880 return result;
04881 }
04882
04883
04884
04885
04886
04887 Datum
04888 circle_add_pt(PG_FUNCTION_ARGS)
04889 {
04890 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
04891 Point *point = PG_GETARG_POINT_P(1);
04892 CIRCLE *result;
04893
04894 result = circle_copy(circle);
04895
04896 result->center.x += point->x;
04897 result->center.y += point->y;
04898
04899 PG_RETURN_CIRCLE_P(result);
04900 }
04901
04902 Datum
04903 circle_sub_pt(PG_FUNCTION_ARGS)
04904 {
04905 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
04906 Point *point = PG_GETARG_POINT_P(1);
04907 CIRCLE *result;
04908
04909 result = circle_copy(circle);
04910
04911 result->center.x -= point->x;
04912 result->center.y -= point->y;
04913
04914 PG_RETURN_CIRCLE_P(result);
04915 }
04916
04917
04918
04919
04920
04921 Datum
04922 circle_mul_pt(PG_FUNCTION_ARGS)
04923 {
04924 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
04925 Point *point = PG_GETARG_POINT_P(1);
04926 CIRCLE *result;
04927 Point *p;
04928
04929 result = circle_copy(circle);
04930
04931 p = DatumGetPointP(DirectFunctionCall2(point_mul,
04932 PointPGetDatum(&circle->center),
04933 PointPGetDatum(point)));
04934 result->center.x = p->x;
04935 result->center.y = p->y;
04936 result->radius *= HYPOT(point->x, point->y);
04937
04938 PG_RETURN_CIRCLE_P(result);
04939 }
04940
04941 Datum
04942 circle_div_pt(PG_FUNCTION_ARGS)
04943 {
04944 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
04945 Point *point = PG_GETARG_POINT_P(1);
04946 CIRCLE *result;
04947 Point *p;
04948
04949 result = circle_copy(circle);
04950
04951 p = DatumGetPointP(DirectFunctionCall2(point_div,
04952 PointPGetDatum(&circle->center),
04953 PointPGetDatum(point)));
04954 result->center.x = p->x;
04955 result->center.y = p->y;
04956 result->radius /= HYPOT(point->x, point->y);
04957
04958 PG_RETURN_CIRCLE_P(result);
04959 }
04960
04961
04962
04963
04964 Datum
04965 circle_area(PG_FUNCTION_ARGS)
04966 {
04967 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
04968
04969 PG_RETURN_FLOAT8(circle_ar(circle));
04970 }
04971
04972
04973
04974
04975 Datum
04976 circle_diameter(PG_FUNCTION_ARGS)
04977 {
04978 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
04979
04980 PG_RETURN_FLOAT8(2 * circle->radius);
04981 }
04982
04983
04984
04985
04986 Datum
04987 circle_radius(PG_FUNCTION_ARGS)
04988 {
04989 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
04990
04991 PG_RETURN_FLOAT8(circle->radius);
04992 }
04993
04994
04995
04996
04997
04998 Datum
04999 circle_distance(PG_FUNCTION_ARGS)
05000 {
05001 CIRCLE *circle1 = PG_GETARG_CIRCLE_P(0);
05002 CIRCLE *circle2 = PG_GETARG_CIRCLE_P(1);
05003 float8 result;
05004
05005 result = point_dt(&circle1->center, &circle2->center)
05006 - (circle1->radius + circle2->radius);
05007 if (result < 0)
05008 result = 0;
05009 PG_RETURN_FLOAT8(result);
05010 }
05011
05012
05013 Datum
05014 circle_contain_pt(PG_FUNCTION_ARGS)
05015 {
05016 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
05017 Point *point = PG_GETARG_POINT_P(1);
05018 double d;
05019
05020 d = point_dt(&circle->center, point);
05021 PG_RETURN_BOOL(d <= circle->radius);
05022 }
05023
05024
05025 Datum
05026 pt_contained_circle(PG_FUNCTION_ARGS)
05027 {
05028 Point *point = PG_GETARG_POINT_P(0);
05029 CIRCLE *circle = PG_GETARG_CIRCLE_P(1);
05030 double d;
05031
05032 d = point_dt(&circle->center, point);
05033 PG_RETURN_BOOL(d <= circle->radius);
05034 }
05035
05036
05037
05038
05039
05040 Datum
05041 dist_pc(PG_FUNCTION_ARGS)
05042 {
05043 Point *point = PG_GETARG_POINT_P(0);
05044 CIRCLE *circle = PG_GETARG_CIRCLE_P(1);
05045 float8 result;
05046
05047 result = point_dt(point, &circle->center) - circle->radius;
05048 if (result < 0)
05049 result = 0;
05050 PG_RETURN_FLOAT8(result);
05051 }
05052
05053
05054
05055
05056 Datum
05057 circle_center(PG_FUNCTION_ARGS)
05058 {
05059 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
05060 Point *result;
05061
05062 result = (Point *) palloc(sizeof(Point));
05063 result->x = circle->center.x;
05064 result->y = circle->center.y;
05065
05066 PG_RETURN_POINT_P(result);
05067 }
05068
05069
05070
05071
05072 static double
05073 circle_ar(CIRCLE *circle)
05074 {
05075 return M_PI * (circle->radius * circle->radius);
05076 }
05077
05078
05079
05080
05081
05082
05083 Datum
05084 cr_circle(PG_FUNCTION_ARGS)
05085 {
05086 Point *center = PG_GETARG_POINT_P(0);
05087 float8 radius = PG_GETARG_FLOAT8(1);
05088 CIRCLE *result;
05089
05090 result = (CIRCLE *) palloc(sizeof(CIRCLE));
05091
05092 result->center.x = center->x;
05093 result->center.y = center->y;
05094 result->radius = radius;
05095
05096 PG_RETURN_CIRCLE_P(result);
05097 }
05098
05099 Datum
05100 circle_box(PG_FUNCTION_ARGS)
05101 {
05102 CIRCLE *circle = PG_GETARG_CIRCLE_P(0);
05103 BOX *box;
05104 double delta;
05105
05106 box = (BOX *) palloc(sizeof(BOX));
05107
05108 delta = circle->radius / sqrt(2.0);
05109
05110 box->high.x = circle->center.x + delta;
05111 box->low.x = circle->center.x - delta;
05112 box->high.y = circle->center.y + delta;
05113 box->low.y = circle->center.y - delta;
05114
05115 PG_RETURN_BOX_P(box);
05116 }
05117
05118
05119
05120
05121 Datum
05122 box_circle(PG_FUNCTION_ARGS)
05123 {
05124 BOX *box = PG_GETARG_BOX_P(0);
05125 CIRCLE *circle;
05126
05127 circle = (CIRCLE *) palloc(sizeof(CIRCLE));
05128
05129 circle->center.x = (box->high.x + box->low.x) / 2;
05130 circle->center.y = (box->high.y + box->low.y) / 2;
05131
05132 circle->radius = point_dt(&circle->center, &box->high);
05133
05134 PG_RETURN_CIRCLE_P(circle);
05135 }
05136
05137
05138 Datum
05139 circle_poly(PG_FUNCTION_ARGS)
05140 {
05141 int32 npts = PG_GETARG_INT32(0);
05142 CIRCLE *circle = PG_GETARG_CIRCLE_P(1);
05143 POLYGON *poly;
05144 int base_size,
05145 size;
05146 int i;
05147 double angle;
05148 double anglestep;
05149
05150 if (FPzero(circle->radius))
05151 ereport(ERROR,
05152 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
05153 errmsg("cannot convert circle with radius zero to polygon")));
05154
05155 if (npts < 2)
05156 ereport(ERROR,
05157 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
05158 errmsg("must request at least 2 points")));
05159
05160 base_size = sizeof(poly->p[0]) * npts;
05161 size = offsetof(POLYGON, p[0]) +base_size;
05162
05163
05164 if (base_size / npts != sizeof(poly->p[0]) || size <= base_size)
05165 ereport(ERROR,
05166 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
05167 errmsg("too many points requested")));
05168
05169 poly = (POLYGON *) palloc0(size);
05170 SET_VARSIZE(poly, size);
05171 poly->npts = npts;
05172
05173 anglestep = (2.0 * M_PI) / npts;
05174
05175 for (i = 0; i < npts; i++)
05176 {
05177 angle = i * anglestep;
05178 poly->p[i].x = circle->center.x - (circle->radius * cos(angle));
05179 poly->p[i].y = circle->center.y + (circle->radius * sin(angle));
05180 }
05181
05182 make_bound_box(poly);
05183
05184 PG_RETURN_POLYGON_P(poly);
05185 }
05186
05187
05188
05189
05190
05191
05192 Datum
05193 poly_circle(PG_FUNCTION_ARGS)
05194 {
05195 POLYGON *poly = PG_GETARG_POLYGON_P(0);
05196 CIRCLE *circle;
05197 int i;
05198
05199 if (poly->npts < 2)
05200 ereport(ERROR,
05201 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
05202 errmsg("cannot convert empty polygon to circle")));
05203
05204 circle = (CIRCLE *) palloc(sizeof(CIRCLE));
05205
05206 circle->center.x = 0;
05207 circle->center.y = 0;
05208 circle->radius = 0;
05209
05210 for (i = 0; i < poly->npts; i++)
05211 {
05212 circle->center.x += poly->p[i].x;
05213 circle->center.y += poly->p[i].y;
05214 }
05215 circle->center.x /= poly->npts;
05216 circle->center.y /= poly->npts;
05217
05218 for (i = 0; i < poly->npts; i++)
05219 circle->radius += point_dt(&poly->p[i], &circle->center);
05220 circle->radius /= poly->npts;
05221
05222 if (FPzero(circle->radius))
05223 ereport(ERROR,
05224 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
05225 errmsg("cannot convert empty polygon to circle")));
05226
05227 PG_RETURN_CIRCLE_P(circle);
05228 }
05229
05230
05231
05232
05233
05234
05235
05236
05237
05238
05239
05240
05241
05242
05243
05244
05245
05246
05247
05248 #define POINT_ON_POLYGON INT_MAX
05249
05250 static int
05251 point_inside(Point *p, int npts, Point *plist)
05252 {
05253 double x0,
05254 y0;
05255 double prev_x,
05256 prev_y;
05257 int i = 0;
05258 double x,
05259 y;
05260 int cross,
05261 total_cross = 0;
05262
05263 if (npts <= 0)
05264 return 0;
05265
05266
05267 x0 = plist[0].x - p->x;
05268 y0 = plist[0].y - p->y;
05269
05270 prev_x = x0;
05271 prev_y = y0;
05272
05273 for (i = 1; i < npts; i++)
05274 {
05275
05276 x = plist[i].x - p->x;
05277 y = plist[i].y - p->y;
05278
05279
05280 if ((cross = lseg_crossing(x, y, prev_x, prev_y)) == POINT_ON_POLYGON)
05281 return 2;
05282 total_cross += cross;
05283
05284 prev_x = x;
05285 prev_y = y;
05286 }
05287
05288
05289 if ((cross = lseg_crossing(x0, y0, prev_x, prev_y)) == POINT_ON_POLYGON)
05290 return 2;
05291 total_cross += cross;
05292
05293 if (total_cross != 0)
05294 return 1;
05295 return 0;
05296 }
05297
05298
05299
05300
05301
05302
05303
05304
05305
05306
05307
05308 static int
05309 lseg_crossing(double x, double y, double prev_x, double prev_y)
05310 {
05311 double z;
05312 int y_sign;
05313
05314 if (FPzero(y))
05315 {
05316 if (FPzero(x))
05317 return POINT_ON_POLYGON;
05318 else if (FPgt(x, 0))
05319 {
05320 if (FPzero(prev_y))
05321
05322 return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
05323 return FPlt(prev_y, 0) ? 1 : -1;
05324 }
05325 else
05326 {
05327 if (FPzero(prev_y))
05328
05329 return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
05330 return 0;
05331 }
05332 }
05333 else
05334 {
05335
05336 y_sign = FPgt(y, 0) ? 1 : -1;
05337
05338 if (FPzero(prev_y))
05339
05340 return FPlt(prev_x, 0) ? 0 : y_sign;
05341 else if (FPgt(y_sign * prev_y, 0))
05342
05343 return 0;
05344 else
05345 {
05346 if (FPge(x, 0) && FPgt(prev_x, 0))
05347
05348 return 2 * y_sign;
05349 if (FPlt(x, 0) && FPle(prev_x, 0))
05350
05351 return 0;
05352
05353
05354 z = (x - prev_x) * y - (y - prev_y) * x;
05355 if (FPzero(z))
05356 return POINT_ON_POLYGON;
05357 return FPgt((y_sign * z), 0) ? 0 : 2 * y_sign;
05358 }
05359 }
05360 }
05361
05362
05363 static bool
05364 plist_same(int npts, Point *p1, Point *p2)
05365 {
05366 int i,
05367 ii,
05368 j;
05369
05370
05371 for (i = 0; i < npts; i++)
05372 {
05373 if ((FPeq(p2[i].x, p1[0].x))
05374 && (FPeq(p2[i].y, p1[0].y)))
05375 {
05376
05377
05378 for (ii = 1, j = i + 1; ii < npts; ii++, j++)
05379 {
05380 if (j >= npts)
05381 j = 0;
05382 if ((!FPeq(p2[j].x, p1[ii].x))
05383 || (!FPeq(p2[j].y, p1[ii].y)))
05384 {
05385 #ifdef GEODEBUG
05386 printf("plist_same- %d failed forward match with %d\n", j, ii);
05387 #endif
05388 break;
05389 }
05390 }
05391 #ifdef GEODEBUG
05392 printf("plist_same- ii = %d/%d after forward match\n", ii, npts);
05393 #endif
05394 if (ii == npts)
05395 return TRUE;
05396
05397
05398 for (ii = 1, j = i - 1; ii < npts; ii++, j--)
05399 {
05400 if (j < 0)
05401 j = (npts - 1);
05402 if ((!FPeq(p2[j].x, p1[ii].x))
05403 || (!FPeq(p2[j].y, p1[ii].y)))
05404 {
05405 #ifdef GEODEBUG
05406 printf("plist_same- %d failed reverse match with %d\n", j, ii);
05407 #endif
05408 break;
05409 }
05410 }
05411 #ifdef GEODEBUG
05412 printf("plist_same- ii = %d/%d after reverse match\n", ii, npts);
05413 #endif
05414 if (ii == npts)
05415 return TRUE;
05416 }
05417 }
05418
05419 return FALSE;
05420 }
05421
05422
05423
05424
05425
05426
05427
05428
05429
05430
05431
05432
05433
05434
05435
05436
05437
05438
05439
05440
05441
05442
05443
05444 double
05445 pg_hypot(double x, double y)
05446 {
05447 double yx;
05448
05449
05450 if (isinf(x) || isinf(y))
05451 return get_float8_infinity();
05452
05453 if (isnan(x) || isnan(y))
05454 return get_float8_nan();
05455
05456
05457 x = fabs(x);
05458 y = fabs(y);
05459
05460
05461 if (x < y)
05462 {
05463 double temp = x;
05464
05465 x = y;
05466 y = temp;
05467 }
05468
05469
05470
05471
05472
05473
05474 if (y == 0.0)
05475 return x;
05476
05477
05478 yx = y / x;
05479 return x * sqrt(1.0 + (yx * yx));
05480 }