Coverage Report

Created: 2026-08-13 07:12

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