LCOV - code coverage report
Current view: top level - src/backend/utils/adt - geo_ops.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 90.8 % 2091 1898
Test Date: 2026-04-07 14:16:30 Functions: 95.1 % 268 255
Legend: Lines:     hit not hit

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

Generated by: LCOV version 2.0-1