LCOV - differential code coverage report
Current view: top level - src/backend/utils/adt - geo_ops.c (source / functions) Coverage Total Hit UNC LBC UIC UBC GBC GIC GNC CBC EUB ECB DCB
Current: Differential Code Coverage HEAD vs 15 Lines: 92.4 % 2024 1871 5 41 90 17 48 1093 62 668 88 1132 30
Current Date: 2023-04-08 17:13:01 Functions: 95.1 % 267 254 13 252 2 13 254
Baseline: 15 Line coverage date bins:
Baseline Date: 2023-04-08 15:09:40 (60,120] days: 92.4 % 66 61 4 1 61
Legend: Lines: hit not hit (180,240] days: 100.0 % 2 2 2 2
(240..) days: 92.4 % 1956 1808 1 41 89 17 48 1091 1 668 86 1113
Function coverage date bins:
(60,120] days: 100.0 % 2 2 2
(240..) days: 47.4 % 532 252 13 252 13 254

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

Generated by: LCOV version v1.16-55-g56c0a2a