Header And Logo

PostgreSQL
| The world's most advanced open source database.

geo_ops.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * geo_ops.c
00004  *    2D geometric operations
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/utils/adt/geo_ops.c
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  * Internal routines
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  * Delimiters for input and output strings.
00075  * LDELIM, RDELIM, and DELIM are left, right, and separator delimiters, respectively.
00076  * LDELIM_EP, RDELIM_EP are left and right delimiters for paths with endpoints.
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 /* Maximum number of characters printed by pair_encode() */
00088 /* ...+3+7 : 3 accounts for extra_float_digits max value */
00089 #define P_MAXLEN (2*(DBL_DIG+3+7)+1)
00090 
00091 
00092 /*
00093  * Geometric data types are composed of points.
00094  * This code tries to support a common format throughout the data types,
00095  *  to allow for more predictable usage and data type conversion.
00096  * The fundamental unit is the point. Other units are line segments,
00097  *  open paths, boxes, closed paths, and polygons (which should be considered
00098  *  non-intersecting closed paths).
00099  *
00100  * Data representation is as follows:
00101  *  point:              (x,y)
00102  *  line segment:       [(x1,y1),(x2,y2)]
00103  *  box:                (x1,y1),(x2,y2)
00104  *  open path:          [(x1,y1),...,(xn,yn)]
00105  *  closed path:        ((x1,y1),...,(xn,yn))
00106  *  polygon:            ((x1,y1),...,(xn,yn))
00107  *
00108  * For boxes, the points are opposite corners with the first point at the top right.
00109  * For closed paths and polygons, the points should be reordered to allow
00110  *  fast and correct equality comparisons.
00111  *
00112  * XXX perhaps points in complex shapes should be reordered internally
00113  *  to allow faster internal operations, but should keep track of input order
00114  *  and restore that order for text output - tgl 97/01/16
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 }   /* single_decode() */
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 }   /* single_encode() */
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         /* no open delimiter allowed? */
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             /* nested delimiters with only one point? */
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 }   /* path_decode() */
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     /* Check for integer overflow */
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 }   /* path_encode() */
00340 
00341 /*-------------------------------------------------------------
00342  * pair_count - count the number of points
00343  * allow the following notation:
00344  * '((1,2),(3,4))'
00345  * '(1,3,2,4)'
00346  * require an odd number of delim characters in the string
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  **     Routines for two-dimensional boxes.
00365  **
00366  ***********************************************************************/
00367 
00368 /*----------------------------------------------------------
00369  * Formatting and conversion routines.
00370  *---------------------------------------------------------*/
00371 
00372 /*      box_in  -       convert a string to internal form.
00373  *
00374  *      External format: (two corners of box)
00375  *              "(f8, f8), (f8, f8)"
00376  *              also supports the older style "(f8, f8, f8, f8)"
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     /* reorder corners if necessary... */
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 /*      box_out -       convert a box to external form.
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  *      box_recv            - converts external binary format to box
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     /* reorder corners if necessary... */
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  *      box_send            - converts box to binary format
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 /*      box_construct   -       fill in a new box.
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 /*      box_fill        -       fill in a given box struct
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 /*      box_copy        -       copy a box
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  *  Relational operators for BOXes.
00530  *      <, >, <=, >=, and == are based on box area.
00531  *---------------------------------------------------------*/
00532 
00533 /*      box_same        -       are two boxes identical?
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 /*      box_overlap     -       does box1 overlap box2?
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 /*      box_left        -       is box1 strictly left of box2?
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 /*      box_overleft    -       is the right edge of box1 at or left of
00579  *                              the right edge of box2?
00580  *
00581  *      This is "less than or equal" for the end of a time range,
00582  *      when time ranges are stored as rectangles.
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 /*      box_right       -       is box1 strictly right of box2?
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 /*      box_overright   -       is the left edge of box1 at or right of
00605  *                              the left edge of box2?
00606  *
00607  *      This is "greater than or equal" for time ranges, when time ranges
00608  *      are stored as rectangles.
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 /*      box_below       -       is box1 strictly below box2?
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 /*      box_overbelow   -       is the upper edge of box1 at or below
00631  *                              the upper edge of box2?
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 /*      box_above       -       is box1 strictly above box2?
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 /*      box_overabove   -       is the lower edge of box1 at or above
00654  *                              the lower edge of box2?
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 /*      box_contained   -       is box1 contained by box2?
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 /*      box_contain     -       does box1 contain box2?
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 /*      box_positionop  -
00695  *              is box1 entirely {above,below} box2?
00696  *
00697  * box_below_eq and box_above_eq are obsolete versions that (probably
00698  * erroneously) accept the equal-boundaries case.  Since these are not
00699  * in sync with the box_left and box_right code, they are deprecated and
00700  * not supported in the PG 8.1 rtree operator class extension.
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 /*      box_relop       -       is area(box1) relop area(box2), within
00722  *                              our accuracy constraint?
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  *  "Arithmetic" operators on boxes.
00772  *---------------------------------------------------------*/
00773 
00774 /*      box_area        -       returns the area of the box.
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 /*      box_width       -       returns the width of the box
00786  *                                (horizontal magnitude).
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 /*      box_height      -       returns the height of the box
00798  *                                (vertical magnitude).
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 /*      box_distance    -       returns the distance between the
00810  *                                center points of two boxes.
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 /*      box_center      -       returns the center point of the box.
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 /*      box_ar  -       returns the area of the box.
00842  */
00843 static double
00844 box_ar(BOX *box)
00845 {
00846     return box_wd(box) * box_ht(box);
00847 }
00848 
00849 
00850 /*      box_cn  -       stores the centerpoint of the box into *center.
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 /*      box_wd  -       returns the width (length) of the box
00861  *                                (horizontal magnitude).
00862  */
00863 static double
00864 box_wd(BOX *box)
00865 {
00866     return box->high.x - box->low.x;
00867 }
00868 
00869 
00870 /*      box_ht  -       returns the height of the box
00871  *                                (vertical magnitude).
00872  */
00873 static double
00874 box_ht(BOX *box)
00875 {
00876     return box->high.y - box->low.y;
00877 }
00878 
00879 
00880 /*----------------------------------------------------------
00881  *  Funky operations.
00882  *---------------------------------------------------------*/
00883 
00884 /*      box_intersect   -
00885  *              returns the overlapping portion of two boxes,
00886  *                or NULL if they do not intersect.
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 /*      box_diagonal    -
00910  *              returns a line segment which happens to be the
00911  *                positive-slope diagonal of "box".
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  **     Routines for 2D lines.
00927  **             Lines are not intended to be used as ADTs per se,
00928  **             but their ops are useful tools for other ADT ops.  Thus,
00929  **             there are few relops.
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     /* when fixed, modify "not implemented", catalog/pg_type.h and SGML */
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     /* when fixed, modify "not implemented", catalog/pg_type.h and SGML */
00977     LSEG        lseg;
00978 
00979     if (FPzero(line->B))
00980     {                           /* vertical */
00981         /* use "x = C" */
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     {                           /* horizontal */
00995         /* use "x = C" */
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))        /* horizontal? */
01012     {
01013     }
01014     else if (FPzero(line->B))   /* vertical? */
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  *      line_recv           - converts external binary format to line
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  *      line_send           - converts line to binary format
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  *  Conversion routines from one line formula to internal.
01059  *      Internal form:  Ax+By+C=0
01060  *---------------------------------------------------------*/
01061 
01062 /* line_construct_pm()
01063  * point-slope
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         /* vertical - use "x = C" */
01073         result->A = -1;
01074         result->B = 0;
01075         result->C = pt->x;
01076     }
01077     else
01078     {
01079         /* use "mx - y + yinter = 0" */
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  * Fill already-allocated LINE struct from two points on the line
01094  */
01095 static void
01096 line_construct_pts(LINE *line, Point *pt1, Point *pt2)
01097 {
01098     if (FPeq(pt1->x, pt2->x))
01099     {                           /* vertical */
01100         /* use "x = C" */
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     {                           /* horizontal */
01113         /* use "y = C" */
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         /* use "mx - y + yinter = 0" */
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 /* line_construct_pp()
01141  * two points
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  *  Relative position routines.
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  *  Line arithmetic routines.
01245  *---------------------------------------------------------*/
01246 
01247 /* line_distance()
01248  * Distance between two lines.
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))          /* vertical? */
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 /* line_interpt()
01270  * Point where two lines l1, l2 intersect (if any)
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  * Internal version of line_interpt
01288  *
01289  * returns a NULL pointer if no intersection point
01290  */
01291 static Point *
01292 line_interpt_internal(LINE *l1, LINE *l2)
01293 {
01294     Point      *result;
01295     double      x,
01296                 y;
01297 
01298     /*
01299      * NOTE: if the lines are identical then we will find they are parallel
01300      * and report "no intersection".  This is a little weird, but since
01301      * there's no *unique* intersection, maybe it's appropriate behavior.
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))          /* l1 vertical? */
01310         result = point_construct(l2->m * l1->C + l2->C, l1->C);
01311     else if (FPzero(l2->B))     /* l2 vertical? */
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))          /* l1 vertical? */
01321     {
01322         x = l1->C;
01323         y = (l2->A * x + l2->C);
01324     }
01325     else if (FPzero(l2->B))     /* l2 vertical? */
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  **     Routines for 2D paths (sequences of line segments, also
01350  **             called `polylines').
01351  **
01352  **             This is not a general package for geometric paths,
01353  **             which of course include polygons; the emphasis here
01354  **             is on (for example) usefulness in wire layout.
01355  **
01356  ***********************************************************************/
01357 
01358 /*----------------------------------------------------------
01359  *  String to path / path to string conversion.
01360  *      External format:
01361  *              "((xcoord, ycoord),... )"
01362  *              "[(xcoord, ycoord),... ]"
01363  *              "(xcoord, ycoord),... "
01364  *              "[xcoord, ycoord,... ]"
01365  *      Also support older format:
01366  *              "(closed, npts, xcoord, ycoord,... )"
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     /* skip single leading paren */
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     /* prevent instability in unused pad bytes */
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  *      path_recv           - converts external binary format to path
01449  *
01450  * External representation is closed flag (a boolean byte), int32 number
01451  * of points, and the points.
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     /* prevent instability in unused pad bytes */
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  *      path_send           - converts path to binary format
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  *  Relational operators.
01512  *      These are based on the path cardinality,
01513  *      as stupid as that sounds.
01514  *
01515  *      Better relops and access methods coming soon.
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  * Conversion operators.
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 /* path_inter -
01614  *      Does p1 intersect p2 at any point?
01615  *      Use bounding boxes for a quick (O(n)) check, then do a
01616  *      O(n^2) iterative edge check.
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     /* pairwise check lseg intersections */
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;       /* include the closure segment */
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;   /* include the closure segment */
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     /* if we dropped through, no two segs intersected */
01689     PG_RETURN_BOOL(false);
01690 }
01691 
01692 /* path_distance()
01693  * This essentially does a cartesian product of the lsegs in the
01694  *  two paths, and finds the min distance between any two lsegs
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;      /* initialize to keep compiler quiet */
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;       /* include the closure segment */
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;   /* include the closure segment */
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  *  "Arithmetic" operations.
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;     /* include the closure segment */
01778         }
01779 
01780         result += point_dt(&path->p[iprev], &path->p[i]);
01781     }
01782 
01783     PG_RETURN_FLOAT8(result);
01784 }
01785 
01786 /***********************************************************************
01787  **
01788  **     Routines for 2D points.
01789  **
01790  ***********************************************************************/
01791 
01792 /*----------------------------------------------------------
01793  *  String to point, point to string conversion.
01794  *      External format:
01795  *              "(x,y)"
01796  *              "x,y"
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  *      point_recv          - converts external binary format to point
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  *      point_send          - converts point to binary format
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  *  Relational operators for Points.
01889  *      Since we do have a sense of coordinates being
01890  *      "equal" to a given accuracy (point_vert, point_horiz),
01891  *      the other ops must preserve that sense.  This means
01892  *      that results may, strictly speaking, be a lie (unless
01893  *      EPSILON = 0.0).
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  *  "Arithmetic" operators on points.
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  **     Routines for 2D line segments.
02013  **
02014  ***********************************************************************/
02015 
02016 /*----------------------------------------------------------
02017  *  String to lseg, lseg to string conversion.
02018  *      External forms: "[(x1, y1), (x2, y2)]"
02019  *                      "(x1, y1), (x2, y2)"
02020  *                      "x1, y1, x2, y2"
02021  *      closed form ok  "((x1, y1), (x2, y2))"
02022  *      (old form)      "(x1, y1, x2, y2)"
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  *      lseg_recv           - converts external binary format to lseg
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  *      lseg_send           - converts lseg to binary format
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 /* lseg_construct -
02099  *      form a LSEG from two Points.
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 /* like lseg_construct, but assume space already allocated */
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  *  Relative position routines.
02144  *---------------------------------------------------------*/
02145 
02146 /*
02147  **  find intersection of the two lines, and see if it falls on
02148  **  both segments.
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;          /* interpt on l1 and l2 */
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 /* lseg_perp()
02190  * Determine if two line segments are perpendicular.
02191  *
02192  * This code did not get the correct answer for
02193  *  '((0,0),(0,1))'::lseg ?-| '((0,0),(1,0))'::lseg
02194  * So, modified it to check explicitly for slope of vertical line
02195  *  returned by point_sl() and the results seem better.
02196  * - thomas 1998-01-31
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  *  Line arithmetic routines.
02304  *---------------------------------------------------------*/
02305 
02306 /* lseg_distance -
02307  *      If two segments don't intersect, then the closest
02308  *      point will be from one of the endpoints to the other
02309  *      segment.
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 /* lseg_dt()
02321  * Distance between two line segments.
02322  * Must check both sets of endpoints to ensure minimum distance is found.
02323  * - thomas 1998-02-01
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      * Find the intersection of the appropriate lines, if any.
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      * If the line intersection point isn't within l1 (or equivalently l2),
02379      * there is no valid segment intersection point at all.
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      * If there is an intersection, then check explicitly for matching
02390      * endpoints since there may be rounding effects with annoying lsb
02391      * residue. - tgl 1997-07-09
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 /* lseg_interpt -
02410  *      Find the intersection point of two segments (if any).
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  **     Routines for position comparisons of differently-typed
02429  **             2D objects.
02430  **
02431  ***********************************************************************/
02432 
02433 /*---------------------------------------------------------------------
02434  *      dist_
02435  *              Minimum distance from one object to another.
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;              /* slope of perp. */
02467     LINE       *ln;
02468     double      result,
02469                 tmpdist;
02470     Point      *ip;
02471 
02472     /*
02473      * Construct a line perpendicular to the input segment and through the
02474      * input point
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;   /* slope is infinite */
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      * Calculate distance to the line segment or to the nearest endpoint of
02491      * the segment.
02492      */
02493 
02494     /* intersection is on the line segment? */
02495     if ((ip = interpt_sl(lseg, ln)) != NULL)
02496     {
02497         /* yes, so use distance to the intersection point */
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         /* no, so use distance to the nearer endpoint */
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  ** Distance from a point to a path
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;   /* keep compiler quiet */
02525     bool        have_min = false;
02526     float8      tmp;
02527     int         i;
02528     LSEG        lseg;
02529 
02530     switch (path->npts)
02531     {
02532         case 0:
02533             /* no points in path? then result is undefined... */
02534             PG_RETURN_NULL();
02535         case 1:
02536             /* one point in path? then get distance between two points... */
02537             result = point_dt(pt, &path->p[0]);
02538             break;
02539         default:
02540             /* make sure the path makes sense... */
02541             Assert(path->npts > 1);
02542 
02543             /*
02544              * the distance from a point to a path is the smallest distance
02545              * from the point to any of its constituent segments.
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;     /* include the closure segment */
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         /* XXX shouldn't we take the min not max? */
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     /* need to think about this one for a while */
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     /* initialize distance with segment between first and last points */
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     /* check distances for other segments */
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  *      interpt_
02702  *              Intersection point of objects.
02703  *              We choose to ignore the "point" of intersection between
02704  *                lines and boxes, since there are typically two.
02705  *-------------------------------------------------------------------*/
02706 
02707 /* Get intersection point of lseg and line; returns NULL if no intersection */
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 /* variant: just indicate if intersection point exists */
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  *      close_
02754  *              Point of closest proximity between objects.
02755  *-------------------------------------------------------------------*/
02756 
02757 /* close_pl -
02758  *      The intersection point of a perpendicular of the line
02759  *      through the point.
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     {                           /* vertical */
02775     }
02776 #endif
02777     if (FPzero(line->B))        /* vertical? */
02778     {
02779         result->x = line->C;
02780         result->y = pt->y;
02781         PG_RETURN_POINT_P(result);
02782     }
02783     if (FPzero(line->A))        /* horizontal? */
02784     {
02785         result->x = pt->x;
02786         result->y = line->C;
02787         PG_RETURN_POINT_P(result);
02788     }
02789     /* drop a perpendicular and find the intersection point */
02790 #ifdef NOT_USED
02791     invm = -1.0 / line->m;
02792 #endif
02793     /* invert and flip the sign on the slope to get a perpendicular */
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 /* close_ps()
02803  * Closest point on line segment to specified point.
02804  * Take the closest endpoint if the point is left, right,
02805  *  above, or below the segment, otherwise find the intersection
02806  *  point of the segment and its perpendicular through the point.
02807  *
02808  * Some tricky code here, relying on boolean expressions
02809  *  evaluating to only zero or one to use as an array index.
02810  *      bug fixes by [email protected]; May 1, 1998
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     /* xh (or yh) is the index of upper x( or y) end point of lseg */
02830     /* !xh (or !yh) is the index of lower x( or y) end point of lseg */
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))       /* vertical? */
02835     {
02836 #ifdef GEODEBUG
02837         printf("close_ps- segment is vertical\n");
02838 #endif
02839         /* first check if point is below or above the entire lseg. */
02840         if (pt->y < lseg->p[!yh].y)
02841             result = point_copy(&lseg->p[!yh]); /* below the lseg */
02842         else if (pt->y > lseg->p[yh].y)
02843             result = point_copy(&lseg->p[yh]);  /* above the lseg */
02844         if (result != NULL)
02845             PG_RETURN_POINT_P(result);
02846 
02847         /* point lines along (to left or right) of the vertical lseg. */
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))  /* horizontal? */
02855     {
02856 #ifdef GEODEBUG
02857         printf("close_ps- segment is horizontal\n");
02858 #endif
02859         /* first check if point is left or right of the entire lseg. */
02860         if (pt->x < lseg->p[!xh].x)
02861             result = point_copy(&lseg->p[!xh]); /* left of the lseg */
02862         else if (pt->x > lseg->p[xh].x)
02863             result = point_copy(&lseg->p[xh]);  /* right of the lseg */
02864         if (result != NULL)
02865             PG_RETURN_POINT_P(result);
02866 
02867         /* point lines along (at top or below) the horiz. lseg. */
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      * vert. and horiz. cases are down, now check if the closest point is one
02876      * of the end points or someplace on the lseg.
02877      */
02878 
02879     invm = -1.0 / point_sl(&(lseg->p[0]), &(lseg->p[1]));
02880     tmp = line_construct_pm(&lseg->p[!yh], invm);       /* lower edge of the
02881                                                          * "band" */
02882     if (pt->y < (tmp->A * pt->x + tmp->C))
02883     {                           /* we are below the lower edge */
02884         result = point_copy(&lseg->p[!yh]);     /* below the lseg, take lower
02885                                                  * end pt */
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);        /* upper edge of the
02893                                                          * "band" */
02894     if (pt->y > (tmp->A * pt->x + tmp->C))
02895     {                           /* we are below the lower edge */
02896         result = point_copy(&lseg->p[yh]);      /* above the lseg, take higher
02897                                                  * end pt */
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      * at this point the "normal" from point will hit lseg. The closet point
02907      * will be somewhere on the lseg
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 /* close_lseg()
02924  * Closest point to l1 on l2.
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 /* close_pb()
02975  * Closest point on or in box to specified point.
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     /* pairwise check lseg distances */
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 /* close_sl()
03028  * Closest point on line to line segment.
03029  *
03030  * XXX THIS CODE IS WRONG
03031  * The code is actually calculating the point on the line segment
03032  *  which is backwards from the routine naming convention.
03033  * Copied code to new routine close_ls() but haven't fixed this one yet.
03034  * - thomas 1998-01-31
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 /* close_ls()
03060  * Closest point on line segment to line.
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 /* close_sb()
03086  * Closest point on or in box to line segment.
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     /* segment intersects box? then just return closest point to center */
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     /* pairwise check lseg distances */
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     /* OK, we now have the closest line segment on the box boundary */
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     /* think about this one for a while */
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  *      on_
03163  *              Whether one object lies completely within another.
03164  *-------------------------------------------------------------------*/
03165 
03166 /* on_pl -
03167  *      Does the point satisfy the equation?
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 /* on_ps -
03180  *      Determine colinearity by detecting a triangle inequality.
03181  * This algorithm seems to behave nicely even with lsb residues - tgl 1997-07-09
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 /* on_ppath -
03220  *      Whether a point lies within (on) a polyline.
03221  *      If open, we have to (groan) check each segment.
03222  * (uses same algorithm as for point intersecting segment - tgl 1997-07-09)
03223  *      If closed, we use the old O(n) ray method for point-in-polygon.
03224  *              The ray is horizontal, from pt out to the right.
03225  *              Each segment that crosses the ray counts as an
03226  *              intersection; note that an endpoint or edge may touch
03227  *              but not cross.
03228  *              (we can do p-in-p in lg(n), but it takes preprocessing)
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     /*-- OPEN --*/
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     /*-- CLOSED --*/
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  *      inter_
03290  *              Whether one object intersects another.
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 /* inter_sb()
03303  * Do line segment and box intersect?
03304  *
03305  * Segment completely inside box counts as intersection.
03306  * If you want only segments crossing box boundaries,
03307  *  try converting box to path first.
03308  *
03309  * Optimize for non-intersection by checking for box intersection first.
03310  * - thomas 1998-01-30
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     /* nothing close to overlap? then not going to intersect */
03327     if (!box_ov(&lbox, box))
03328         PG_RETURN_BOOL(false);
03329 
03330     /* an endpoint of segment is inside box? then clearly intersects */
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     /* pairwise check lseg intersections */
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     /* if we dropped through, no two segs intersected */
03361     PG_RETURN_BOOL(false);
03362 }
03363 
03364 /* inter_lb()
03365  * Do line and box intersect?
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     /* pairwise check lseg intersections */
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     /* if we dropped through, no intersection */
03401     PG_RETURN_BOOL(false);
03402 }
03403 
03404 /*------------------------------------------------------------------
03405  * The following routines define a data type and operator class for
03406  * POLYGONS .... Part of which (the polygon's bounding box) is built on
03407  * top of the BOX data type.
03408  *
03409  * make_bound_box - create the bounding box for the input polygon
03410  *------------------------------------------------------------------*/
03411 
03412 /*---------------------------------------------------------------------
03413  * Make the smallest bounding box for the given polygon.
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  * poly_in - read in the polygon from a string specification
03450  *
03451  *      External format:
03452  *              "((x0,y0),...,(xn,yn))"
03453  *              "x0,y0,...,xn,yn"
03454  *              also supports the older style "(x1,...,xn,y1,...yn)"
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);   /* zero any holes */
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  * poly_out - convert internal POLYGON representation to the
03490  *            character string format "((f8,f8),...,(f8,f8))"
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  *      poly_recv           - converts external binary format to polygon
03502  *
03503  * External representation is int32 number of points, and the points.
03504  * We recompute the bounding box on read, instead of trusting it to
03505  * be valid.  (Checking it would take just as long, so may as well
03506  * omit it from external representation.)
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);   /* zero any holes */
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  *      poly_send           - converts polygon to binary format
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  * Is polygon A strictly left of polygon B? i.e. is
03563  * the right most point of A left of the left most point
03564  * of B?
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Is polygon A overlapping or left of polygon B? i.e. is
03586  * the right most point of A at or left of the right most point
03587  * of B?
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Is polygon A strictly right of polygon B? i.e. is
03609  * the left most point of A right of the right most point
03610  * of B?
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Is polygon A overlapping or right of polygon B? i.e. is
03632  * the left most point of A at or right of the left most point
03633  * of B?
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Is polygon A strictly below polygon B? i.e. is
03655  * the upper most point of A below the lower most point
03656  * of B?
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Is polygon A overlapping or below polygon B? i.e. is
03678  * the upper most point of A at or below the upper most point
03679  * of B?
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Is polygon A strictly above polygon B? i.e. is
03701  * the lower most point of A above the upper most point
03702  * of B?
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Is polygon A overlapping or above polygon B? i.e. is
03724  * the lower most point of A at or above the lower most point
03725  * of B?
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Is polygon A the same as polygon B? i.e. are all the
03748  * points the same?
03749  * Check all points for matches in both forward and reverse
03750  *  direction since polygons are non-directional and are
03751  *  closed shapes.
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Determine if polygon A overlaps polygon B
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     /* Quick check by bounding box */
03785     result = (polya->npts > 0 && polyb->npts > 0 &&
03786               box_ov(&polya->boundbox, &polyb->boundbox)) ? true : false;
03787 
03788     /*
03789      * Brute-force algorithm - try to find intersected edges, if so then
03790      * polygons are overlapped else check is one polygon inside other or not
03791      * by testing single point of them.
03792      */
03793     if (result)
03794     {
03795         int         ia,
03796                     ib;
03797         LSEG        sa,
03798                     sb;
03799 
03800         /* Init first of polya's edge with last point */
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             /* Second point of polya's edge is a current one */
03807             sa.p[1] = polya->p[ia];
03808 
03809             /* Init first of polyb's edge with last point */
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              * move current endpoint to the first point of next edge
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Tests special kind of segment for in/out of polygon.
03844  * Special kind means:
03845  *  - point a should be on segment s
03846  *  - segment (a,b) should not be contained by s
03847  * Returns true if:
03848  *  - segment (a,b) is collinear to s and (a,b) is in polygon
03849  *  - segment (a,b) s not collinear to s. Note: that doesn't
03850  *    mean that segment is in polygon!
03851  */
03852 
03853 static bool
03854 touched_lseg_inside_poly(Point *a, Point *b, LSEG *s, POLYGON *poly, int start)
03855 {
03856     /* point a is on s, b is not */
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;                /* may be not true, but that will check later */
03883 }
03884 
03885 /*
03886  * Returns true if segment (a,b) is in polygon, option
03887  * start is used for optimization - function checks
03888  * polygon's edges started from start
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;    /* t is contained by s */
03913 
03914             /* Y-cross */
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             /* Y-cross */
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              * segments are X-crossing, go to check each subsegment
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          * if X-intersection wasn't found  then check central point of tested
03944          * segment. In opposite case we already check all subsegments
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  * Determine if polygon A contains polygon B.
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      * Quick check to see if bounding box is contained.
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      * Avoid leaking memory for toasted inputs ... needed for rtree indexes
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  * Determine if polygon A is contained by polygon B
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     /* Just switch the arguments and pass it off to poly_contain */
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  **     Routines for 2D points.
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  **     Routines for 2D boxes.
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  **     Routines for 2D paths.
04219  **
04220  ***********************************************************************/
04221 
04222 /* path_add()
04223  * Concatenate two paths (only if they are both open).
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     /* Check for integer overflow */
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     /* prevent instability in unused pad bytes */
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 /* path_add_pt()
04271  * Translation operators.
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 /* path_mul_pt()
04306  * Rotation and scaling operators.
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     /* This is not very consistent --- other similar cases return NULL ... */
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  **     Routines for 2D polygons.
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 /* box_poly()
04442  * Convert a box to a polygon.
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     /* map four corners of the box to a polygon */
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     /* prevent instability in unused pad bytes */
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  **     Routines for circles.
04504  **
04505  ***********************************************************************/
04506 
04507 /*----------------------------------------------------------
04508  * Formatting and conversion routines.
04509  *---------------------------------------------------------*/
04510 
04511 /*      circle_in       -       convert a string to internal form.
04512  *
04513  *      External format: (center and radius of circle)
04514  *              "((f8,f8)<f8>)"
04515  *              also supports quick entry style "(f8,f8,f8)"
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 /*      circle_out      -       convert a circle to external form.
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  *      circle_recv         - converts external binary format to circle
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  *      circle_send         - converts circle to binary format
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  *  Relational operators for CIRCLEs.
04656  *      <, >, <=, >=, and == are based on circle area.
04657  *---------------------------------------------------------*/
04658 
04659 /*      circles identical?
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 /*      circle_overlap  -       does circle1 overlap circle2?
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 /*      circle_overleft -       is the right edge of circle1 at or left of
04685  *                              the right edge of circle2?
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 /*      circle_left     -       is circle1 strictly left of circle2?
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 /*      circle_right    -       is circle1 strictly right of circle2?
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 /*      circle_overright    -   is the left edge of circle1 at or right of
04722  *                              the left edge of circle2?
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 /*      circle_contained        -       is circle1 contained by circle2?
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 /*      circle_contain  -       does circle1 contain circle2?
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 /*      circle_below        -       is circle1 strictly below circle2?
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 /*      circle_above    -       is circle1 strictly above circle2?
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 /*      circle_overbelow -      is the upper edge of circle1 at or below
04782  *                              the upper edge of circle2?
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 /*      circle_overabove    -   is the lower edge of circle1 at or above
04795  *                              the lower edge of circle2?
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 /*      circle_relop    -       is area(circle1) relop area(circle2), within
04809  *                              our accuracy constraint?
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  *  "Arithmetic" operators on circles.
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 /* circle_add_pt()
04885  * Translation operator.
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 /* circle_mul_pt()
04919  * Rotation and scaling operators.
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 /*      circle_area     -       returns the area of the circle.
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 /*      circle_diameter -       returns the diameter of the circle.
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 /*      circle_radius   -       returns the radius of the circle.
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 /*      circle_distance -       returns the distance between
04996  *                                two circles.
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 /*      dist_pc -       returns the distance between
05038  *                        a point and a circle.
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 /*      circle_center   -       returns the center point of the circle.
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 /*      circle_ar       -       returns the area of the circle.
05071  */
05072 static double
05073 circle_ar(CIRCLE *circle)
05074 {
05075     return M_PI * (circle->radius * circle->radius);
05076 }
05077 
05078 
05079 /*----------------------------------------------------------
05080  *  Conversion operators.
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 /* box_circle()
05119  * Convert a box to a circle.
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     /* Check for integer overflow */
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);   /* zero any holes */
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 /*      poly_circle     - convert polygon to circle
05188  *
05189  * XXX This algorithm should use weighted means of line segments
05190  *  rather than straight average values of points - tgl 97/01/21.
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  **     Private routines for multiple types.
05234  **
05235  ***********************************************************************/
05236 
05237 /*
05238  *  Test to see if the point is inside the polygon, returns 1/0, or 2 if
05239  *  the point is on the polygon.
05240  *  Code adapted but not copied from integer-based routines in WN: A
05241  *  Server for the HTTP
05242  *  version 1.15.1, file wn/image.c
05243  *  http://hopf.math.northwestern.edu/index.html
05244  *  Description of algorithm:  http://www.linuxjournal.com/article/2197
05245  *                             http://www.linuxjournal.com/article/2029
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     /* compute first polygon point relative to single point */
05267     x0 = plist[0].x - p->x;
05268     y0 = plist[0].y - p->y;
05269 
05270     prev_x = x0;
05271     prev_y = y0;
05272     /* loop over polygon points and aggregate total_cross */
05273     for (i = 1; i < npts; i++)
05274     {
05275         /* compute next polygon point relative to single point */
05276         x = plist[i].x - p->x;
05277         y = plist[i].y - p->y;
05278 
05279         /* compute previous to current point crossing */
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     /* now do the first point */
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 /* lseg_crossing()
05300  * Returns +/-2 if line segment crosses the positive X-axis in a +/- direction.
05301  * Returns +/-1 if one point is on the positive X-axis.
05302  * Returns 0 if both points are on the positive X-axis, or there is no crossing.
05303  * Returns POINT_ON_POLYGON if the segment contains (0,0).
05304  * Wow, that is one confusing API, but it is used above, and when summed,
05305  * can tell is if a point is in a polygon.
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     {                           /* y == 0, on X axis */
05316         if (FPzero(x))          /* (x,y) is (0,0)? */
05317             return POINT_ON_POLYGON;
05318         else if (FPgt(x, 0))
05319         {                       /* x > 0 */
05320             if (FPzero(prev_y)) /* y and prev_y are zero */
05321                 /* prev_x > 0? */
05322                 return FPgt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
05323             return FPlt(prev_y, 0) ? 1 : -1;
05324         }
05325         else
05326         {                       /* x < 0, x not on positive X axis */
05327             if (FPzero(prev_y))
05328                 /* prev_x < 0? */
05329                 return FPlt(prev_x, 0) ? 0 : POINT_ON_POLYGON;
05330             return 0;
05331         }
05332     }
05333     else
05334     {                           /* y != 0 */
05335         /* compute y crossing direction from previous point */
05336         y_sign = FPgt(y, 0) ? 1 : -1;
05337 
05338         if (FPzero(prev_y))
05339             /* previous point was on X axis, so new point is either off or on */
05340             return FPlt(prev_x, 0) ? 0 : y_sign;
05341         else if (FPgt(y_sign * prev_y, 0))
05342             /* both above or below X axis */
05343             return 0;           /* same sign */
05344         else
05345         {                       /* y and prev_y cross X-axis */
05346             if (FPge(x, 0) && FPgt(prev_x, 0))
05347                 /* both non-negative so cross positive X-axis */
05348                 return 2 * y_sign;
05349             if (FPlt(x, 0) && FPle(prev_x, 0))
05350                 /* both non-positive so do not cross positive X-axis */
05351                 return 0;
05352 
05353             /* x and y cross axises, see URL above point_inside() */
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     /* find match for first point */
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             /* match found? then look forward through remaining points */
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             /* match not found forwards? then look backwards */
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  * Determine the hypotenuse.
05425  *
05426  * If required, x and y are swapped to make x the larger number. The
05427  * traditional formula of x^2+y^2 is rearranged to factor x outside the
05428  * sqrt. This allows computation of the hypotenuse for significantly
05429  * larger values, and with a higher precision than when using the naive
05430  * formula.  In particular, this cannot overflow unless the final result
05431  * would be out-of-range.
05432  *
05433  * sqrt( x^2 + y^2 ) = sqrt( x^2( 1 + y^2/x^2) )
05434  *                   = x * sqrt( 1 + y^2/x^2 )
05435  *                   = x * sqrt( 1 + y/x * y/x )
05436  *
05437  * It is expected that this routine will eventually be replaced with the
05438  * C99 hypot() function.
05439  *
05440  * This implementation conforms to IEEE Std 1003.1 and GLIBC, in that the
05441  * case of hypot(inf,nan) results in INF, and not NAN.
05442  *-----------------------------------------------------------------------
05443  */
05444 double
05445 pg_hypot(double x, double y)
05446 {
05447     double      yx;
05448 
05449     /* Handle INF and NaN properly */
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     /* Else, drop any minus signs */
05457     x = fabs(x);
05458     y = fabs(y);
05459 
05460     /* Swap x and y if needed to make x the larger one */
05461     if (x < y)
05462     {
05463         double      temp = x;
05464 
05465         x = y;
05466         y = temp;
05467     }
05468 
05469     /*
05470      * If y is zero, the hypotenuse is x.  This test saves a few cycles in
05471      * such cases, but more importantly it also protects against
05472      * divide-by-zero errors, since now x >= y.
05473      */
05474     if (y == 0.0)
05475         return x;
05476 
05477     /* Determine the hypotenuse */
05478     yx = y / x;
05479     return x * sqrt(1.0 + (yx * yx));
05480 }