1 #include "polygon.h"
2
3 /* Polygon functions */
4
5
6 PG_FUNCTION_INFO_V1(spherepoly_in);
7 PG_FUNCTION_INFO_V1(spherepoly_equal);
8 PG_FUNCTION_INFO_V1(spherepoly_equal_neg);
9 PG_FUNCTION_INFO_V1(spherepoly_circ);
10 PG_FUNCTION_INFO_V1(spherepoly_npts);
11 PG_FUNCTION_INFO_V1(spherepoly_area);
12 PG_FUNCTION_INFO_V1(spherepoly_cont_point);
13 PG_FUNCTION_INFO_V1(spherepoly_cont_point_neg);
14 PG_FUNCTION_INFO_V1(spherepoly_cont_point_com);
15 PG_FUNCTION_INFO_V1(spherepoly_cont_point_com_neg);
16 PG_FUNCTION_INFO_V1(spherepoly_cont_circle);
17 PG_FUNCTION_INFO_V1(spherepoly_cont_circle_neg);
18 PG_FUNCTION_INFO_V1(spherepoly_cont_circle_com);
19 PG_FUNCTION_INFO_V1(spherepoly_cont_circle_com_neg);
20 PG_FUNCTION_INFO_V1(spherecircle_cont_poly);
21 PG_FUNCTION_INFO_V1(spherecircle_cont_poly_neg);
22 PG_FUNCTION_INFO_V1(spherecircle_cont_poly_com);
23 PG_FUNCTION_INFO_V1(spherecircle_cont_poly_com_neg);
24 PG_FUNCTION_INFO_V1(spherepoly_overlap_circle);
25 PG_FUNCTION_INFO_V1(spherepoly_overlap_circle_neg);
26 PG_FUNCTION_INFO_V1(spherepoly_overlap_circle_com);
27 PG_FUNCTION_INFO_V1(spherepoly_overlap_circle_com_neg);
28 PG_FUNCTION_INFO_V1(spherepoly_cont_line);
29 PG_FUNCTION_INFO_V1(spherepoly_cont_line_neg);
30 PG_FUNCTION_INFO_V1(spherepoly_cont_line_com);
31 PG_FUNCTION_INFO_V1(spherepoly_cont_line_com_neg);
32 PG_FUNCTION_INFO_V1(spherepoly_overlap_line);
33 PG_FUNCTION_INFO_V1(spherepoly_overlap_line_neg);
34 PG_FUNCTION_INFO_V1(spherepoly_overlap_line_com);
35 PG_FUNCTION_INFO_V1(spherepoly_overlap_line_com_neg);
36 PG_FUNCTION_INFO_V1(spherepoly_cont_poly);
37 PG_FUNCTION_INFO_V1(spherepoly_cont_poly_neg);
38 PG_FUNCTION_INFO_V1(spherepoly_cont_poly_com);
39 PG_FUNCTION_INFO_V1(spherepoly_cont_poly_com_neg);
40 PG_FUNCTION_INFO_V1(spherepoly_overlap_poly);
41 PG_FUNCTION_INFO_V1(spherepoly_overlap_poly_neg);
42 PG_FUNCTION_INFO_V1(spherepoly_cont_ellipse);
43 PG_FUNCTION_INFO_V1(spherepoly_cont_ellipse_neg);
44 PG_FUNCTION_INFO_V1(spherepoly_cont_ellipse_com);
45 PG_FUNCTION_INFO_V1(spherepoly_cont_ellipse_com_neg);
46 PG_FUNCTION_INFO_V1(sphereellipse_cont_poly);
47 PG_FUNCTION_INFO_V1(sphereellipse_cont_poly_neg);
48 PG_FUNCTION_INFO_V1(sphereellipse_cont_poly_com);
49 PG_FUNCTION_INFO_V1(sphereellipse_cont_poly_com_neg);
50 PG_FUNCTION_INFO_V1(spherepoly_overlap_ellipse);
51 PG_FUNCTION_INFO_V1(spherepoly_overlap_ellipse_neg);
52 PG_FUNCTION_INFO_V1(spherepoly_overlap_ellipse_com);
53 PG_FUNCTION_INFO_V1(spherepoly_overlap_ellipse_com_neg);
54 PG_FUNCTION_INFO_V1(spheretrans_poly);
55 PG_FUNCTION_INFO_V1(spheretrans_poly_inverse);
56 PG_FUNCTION_INFO_V1(spherepoly_add_point);
57 PG_FUNCTION_INFO_V1(spherepoly_add_points_finalize);
58
59
60 /*
61 * Writes "center" of a polygon into 'v'.
62 *
63 * v - pointer to the center of a polygon
64 * poly - pointer to the polygon
65 */
66 static void
spherepoly_center(Vector3D * v,const SPOLY * poly)67 spherepoly_center(Vector3D *v, const SPOLY *poly)
68 {
69 int32 i;
70 Vector3D v1,
71 v2;
72
73 v1.x = 2.0;
74 v1.y = 2.0;
75 v1.z = 2.0;
76 v2.x = -2.0;
77 v2.y = -2.0;
78 v2.z = -2.0;
79
80 for (i = 0; i < poly->npts; i++)
81 {
82 spoint_vector3d(v, &poly->p[i]);
83 v1.x = Min(v->x, v1.x);
84 v1.y = Min(v->y, v1.y);
85 v1.z = Min(v->z, v1.z);
86 v2.x = Max(v->x, v2.x);
87 v2.y = Max(v->y, v2.y);
88 v2.z = Max(v->z, v2.z);
89 }
90
91 v->x = (v1.x + v2.x) / 2.0;
92 v->y = (v1.y + v2.y) / 2.0;
93 v->z = (v1.z + v2.z) / 2.0;
94 }
95
96
97 /*
98 * Checks if line segments cross.
99 */
100 static bool
spherepoly_check(const SPOLY * poly)101 spherepoly_check(const SPOLY *poly)
102 {
103 int32 i,
104 k;
105 SLine sli,
106 slk;
107 Vector3D v;
108 SPoint p;
109 SEuler se;
110 int8 pos;
111
112 spherepoly_center(&v, poly);
113 /* If 0-vector */
114 if (FPzero(v.x) && FPzero(v.y) && FPzero(v.z))
115 {
116 return false;
117 }
118
119 for (i = 0; i < poly->npts; i++)
120 {
121 spoly_segment(&sli, poly, i);
122 for (k = (i + 1); k < poly->npts; k++)
123 {
124 spoly_segment(&slk, poly, k);
125 pos = sline_sline_pos(&sli, &slk);
126 if (!(pos == PGS_LINE_CONNECT || pos == PGS_LINE_AVOID))
127 {
128 return false;
129 }
130 }
131 }
132
133 vector3d_spoint(&p, &v);
134
135 se.phi_a = EULER_AXIS_Z;
136 se.theta_a = EULER_AXIS_X;
137 se.psi_a = EULER_AXIS_Z;
138 se.phi = -PIH - p.lng;
139 se.theta = p.lat - PIH;
140 se.psi = 0.0;
141
142 for (i = 0; i < poly->npts; i++)
143 {
144 euler_spoint_trans(&p, &poly->p[i], &se);
145 /* less _and_ equal are important !! */
146 /* Do not change it! */
147 if (FPle(p.lat, 0.0))
148 {
149 return false;
150 }
151 }
152 return true;
153 }
154
155
156 /*
157 * Converts an array of spherical points to SPOLY.
158 *
159 * arr - pointer to the array of spherical points
160 * nelem - number of the elements
161 *
162 * Returns the pointer to the created spherical polygon.
163 */
164 static SPOLY *
spherepoly_from_array(SPoint * arr,int32 nelem)165 spherepoly_from_array(SPoint *arr, int32 nelem)
166 {
167 SPOLY *poly = NULL;
168
169 if (nelem < 3)
170 {
171 elog(ERROR, "spherepoly_from_array: more than two points needed");
172 return NULL;
173 }
174 else
175 {
176 int32 i;
177 float8 scheck;
178 int32 size;
179
180 for (i = 0; i < nelem; i++)
181 {
182 spoint_check(&arr[i]);
183 }
184
185 /* check duplicate points */
186 i = 0;
187 while (i < (nelem - 1))
188 {
189 if (nelem < 3)
190 break;
191 if (spoint_eq(&arr[i], &arr[i + 1]))
192 {
193 if (i < (nelem - 2))
194 {
195 memmove((void *) &arr[i + 1],
196 (void *) &arr[i + 2],
197 (nelem - i - 2) * sizeof(SPoint));
198 }
199 nelem--;
200 continue;
201 }
202 i++;
203 }
204 if (spoint_eq(&arr[0], &arr[nelem - 1]))
205 {
206 nelem--;
207 }
208 if (nelem < 3)
209 {
210 elog(ERROR, "spherepoly_from_array: more than two points needed");
211 return NULL;
212 }
213
214 size = offsetof(SPOLY, p[0]) +sizeof(SPoint) * nelem;
215 poly = (SPOLY *) palloc(size);
216 SET_VARSIZE(poly, size);
217 poly->npts = nelem;
218 for (i = 0; i < nelem; i++)
219 {
220 if (i == 0)
221 {
222 scheck = spoint_dist(&arr[nelem - 1], &arr[0]);
223 }
224 else
225 {
226 scheck = spoint_dist(&arr[i - 1], &arr[i]);
227 }
228 if (FPeq(scheck, PI))
229 {
230 elog(ERROR, "spherepoly_from_array: a polygon segment length must be not equal 180 degrees.");
231 return NULL;
232 }
233 memcpy((void *) &poly->p[i],
234 (void *) &arr[i],
235 sizeof(SPoint));
236 }
237
238 }
239
240 if (!spherepoly_check(poly))
241 {
242 elog(ERROR, "spherepoly_from_array: a line segment overlaps or polygon too large");
243 pfree(poly);
244 return NULL;
245 }
246
247 return poly;
248
249 }
250
251
252 /*
253 * Performs a transform of a polygon using an Euler transformation.
254 *
255 * se - pointer to the Euler transformation
256 * in - pointer to the polygon
257 * out - pointer to the transformed polygon
258 */
259 static void
euler_spoly_trans(SPOLY * out,const SPOLY * in,const SEuler * se)260 euler_spoly_trans(SPOLY *out, const SPOLY *in, const SEuler *se)
261 {
262 int32 i;
263
264 out->size = in->size;
265 out->npts = in->npts;
266 for (i = 0; i < in->npts; i++)
267 euler_spoint_trans(&out->p[i], &in->p[i], se);
268 }
269
270
271 /*
272 * Returns the relationship between polygon and circle as
273 * PGS_CIRCLE_POLY_REL int8 value.
274 */
275 static int8
poly_circle_pos(const SPOLY * poly,const SCIRCLE * circ)276 poly_circle_pos(const SPOLY *poly, const SCIRCLE *circ)
277 {
278 int8 pos = 0;
279 int32 i;
280 SLine sl;
281 bool pcp;
282 const int8 sc_in = (1 << PGS_CIRCLE_CONT_LINE);
283 const int8 sc_ov = (1 << PGS_CIRCLE_LINE_OVER);
284 const int8 sc_os = (1 << PGS_CIRCLE_LINE_AVOID);
285
286 pcp = spoly_contains_point(poly, &circ->center);
287
288 if (FPzero(circ->radius))
289 {
290 if (pcp)
291 {
292 return PGS_POLY_CONT_CIRCLE;
293 }
294 else
295 {
296 return PGS_CIRCLE_POLY_AVOID;
297 }
298 }
299
300 for (i = 0; i < poly->npts; i++)
301 {
302
303 spoly_segment(&sl, poly, i);
304 pos |= (1 << sphereline_circle_pos(&sl, circ));
305 if (((pos & sc_in) && (pos & sc_os)) || (pos & sc_ov))
306 {
307 return PGS_CIRCLE_POLY_OVER;
308 /* overlaps */
309 }
310
311 }
312
313 if ((pos & sc_in) == pos)
314 {
315 /* all lines inside circle */
316 /* circle contains polygon */
317 return PGS_CIRCLE_CONT_POLY;
318 }
319 else if ((pos & sc_os) == pos)
320 {
321 /* all lines outside circle */
322 if (pcp)
323 {
324 /* polygon contains circle */
325 return PGS_POLY_CONT_CIRCLE;
326 }
327 else
328 {
329 /* circle outside polygon */
330 return PGS_CIRCLE_POLY_AVOID;
331 }
332
333 }
334 /* circle and polygon overlap */
335 return PGS_CIRCLE_POLY_OVER;
336 }
337
338
339 /*
340 * Returns the relationship between a polygon and an ellipse
341 * as PGS_ELLIPSE_POLY_REL int8 value.
342 */
343 static int8
poly_ellipse_pos(const SPOLY * poly,const SELLIPSE * ell)344 poly_ellipse_pos(const SPOLY *poly, const SELLIPSE *ell)
345 {
346 int8 pos = 0;
347 int32 i;
348 SLine sl;
349 bool pcp;
350 SPoint cen;
351 const int8 sc_in = (1 << PGS_ELLIPSE_CONT_LINE);
352 const int8 sc_ov = (1 << PGS_ELLIPSE_LINE_OVER);
353 const int8 sc_os = (1 << PGS_ELLIPSE_LINE_AVOID);
354
355 sellipse_center(&cen, ell);
356 pcp = spoly_contains_point(poly, &cen);
357
358 if (FPzero(ell->rad[0]))
359 {
360 if (pcp)
361 {
362 return PGS_POLY_CONT_ELLIPSE;
363 }
364 else
365 {
366 return PGS_ELLIPSE_POLY_AVOID;
367 }
368 }
369
370 if (FPzero(ell->rad[1]))
371 {
372 SLine l;
373 int8 res;
374
375 sellipse_line(&l, ell);
376 res = poly_line_pos(poly, &l);
377 if (res == PGS_LINE_POLY_AVOID)
378 {
379 return PGS_ELLIPSE_POLY_AVOID;
380 }
381 else if (res == PGS_POLY_CONT_LINE)
382 {
383 return PGS_POLY_CONT_ELLIPSE;
384 }
385 else
386 {
387 return PGS_ELLIPSE_POLY_OVER;
388 }
389 }
390
391 for (i = 0; i < poly->npts; i++)
392 {
393 spoly_segment(&sl, poly, i);
394 pos |= (1 << sellipse_line_pos(ell, &sl));
395 if (((pos & sc_in) && (pos & sc_os)) || (pos & sc_ov))
396 {
397 return PGS_ELLIPSE_POLY_OVER;
398 /* overlaps */
399 }
400 }
401
402 if ((pos & sc_in) == pos)
403 {
404 /* all lines inside ellipse */
405 /* ellipse contains polygon */
406 return PGS_ELLIPSE_CONT_POLY;
407 }
408 else if ((pos & sc_os) == pos)
409 {
410 /* all lines outside ellipse */
411 if (pcp)
412 {
413 /* polygon contains ellipse */
414 return PGS_POLY_CONT_ELLIPSE;
415 }
416 else
417 {
418 /* ellipse outside polygon */
419 return PGS_ELLIPSE_POLY_AVOID;
420 }
421
422 }
423
424 /* ellipse and polygon overlap */
425 return PGS_ELLIPSE_POLY_OVER;
426 }
427
428
429 /*
430 * Returns the relationship between two polygons as
431 * PGS_POLY_REL int8 value.
432 *
433 * p1 - pointer to the first polygon
434 * p2 - pointer to the second polygon
435 *
436 * If 'recheck' is true, swaps 'p1' and 'p2'.
437 */
438 static int8
poly_poly_pos(const SPOLY * p1,const SPOLY * p2,bool recheck)439 poly_poly_pos(const SPOLY *p1, const SPOLY *p2, bool recheck)
440 {
441 int32 i;
442 SLine sl;
443 int8 pos = 0,
444 res = 0;
445 const int8 sp_os = (1 << PGS_LINE_POLY_AVOID);
446 const int8 sp_ct = (1 << PGS_POLY_CONT_LINE);
447 const int8 sp_ov = (1 << PGS_LINE_POLY_OVER);
448
449 for (i = 0; i < p2->npts; i++)
450 {
451
452 spoly_segment(&sl, p2, i);
453 pos = (1 << poly_line_pos(p1, &sl));
454 if (pos == sp_ov)
455 {
456 return PGS_POLY_OVER;
457 /* overlap */
458 }
459 res |= pos;
460 }
461
462 if (res == sp_os)
463 {
464 if (!recheck)
465 {
466 pos = poly_poly_pos(p2, p1, true);
467 }
468 if (pos == PGS_POLY_CONT)
469 {
470 return PGS_POLY_OVER;
471 }
472 else
473 {
474 return PGS_POLY_AVOID;
475 }
476 }
477 if (res == sp_ct)
478 {
479 return PGS_POLY_CONT;
480 }
481 return PGS_POLY_OVER;
482 }
483
484 /*
485 * Checks whether two polygons are equal.
486 *
487 * If 'dir' is true, check with reverse polygon of 'p2'.
488 */
489 bool
spoly_eq(const SPOLY * p1,const SPOLY * p2,bool dir)490 spoly_eq(const SPOLY *p1, const SPOLY *p2, bool dir)
491 {
492 bool ret = false;
493
494 if (p1->npts == p2->npts)
495 {
496
497 int32 i,
498 k,
499 cntr,
500 shift;
501
502 for (shift = 0; shift < p1->npts; shift++)
503 {
504 cntr = 0;
505 for (i = 0; i < p1->npts; i++)
506 {
507 k = (dir) ? (p1->npts - i - 1) : (i);
508 k += shift;
509 k = (k < p1->npts) ? (k) : (k - p1->npts);
510 if (spoint_eq(&p1->p[i], &p2->p[k]))
511 {
512 cntr++;
513 }
514 }
515 if (cntr == p1->npts)
516 {
517 ret = true;
518 break;
519 }
520 }
521
522 /* Try other direction if not equal */
523 if (!dir && !ret)
524 {
525 ret = spoly_eq(p1, p2, true);
526 }
527
528 }
529
530 return ret;
531 }
532
533 /*
534 * Returns the i-th line segment of a polygon.
535 *
536 * sl - pointer to the line segment
537 * poly - pointer to the polygon
538 * i - number of the segment
539 */
540 bool
spoly_segment(SLine * sl,const SPOLY * poly,int32 i)541 spoly_segment(SLine *sl, const SPOLY *poly, int32 i)
542 {
543 if (i >= 0 && i < poly->npts)
544 {
545 if (i == (poly->npts - 1))
546 sline_from_points(sl, &poly->p[i], &poly->p[0]);
547 else
548 sline_from_points(sl, &poly->p[i], &poly->p[i + 1]);
549 return true;
550 }
551 else
552 {
553 return false;
554 }
555 }
556
557 /*
558 * Checks whether a polygon contains a point.
559 *
560 * pg - pointer to the polygon
561 * sp - pointer to the point
562 */
563 bool
spoly_contains_point(const SPOLY * pg,const SPoint * sp)564 spoly_contains_point(const SPOLY *pg, const SPoint *sp)
565 {
566 int32 i;
567 SLine sl;
568 bool res = false;
569 float8 scp;
570 Vector3D vc,
571 vp;
572
573 /* First check if point is outside polygon (behind) */
574 spherepoly_center(&vc, pg);
575 spoint_vector3d(&vp, sp);
576 scp = vector3d_scalar(&vp, &vc);
577 if (FPle(scp, 0.0))
578 {
579 return false;
580 }
581
582 /* Check whether point is edge */
583 for (i = 0; i < pg->npts; i++)
584 {
585 if (spoint_eq(&pg->p[i], sp))
586 {
587 return true;
588 }
589 }
590
591 /* Check whether point is on a line segment */
592 for (i = 0; i < pg->npts; i++)
593 {
594 spoly_segment(&sl, pg, i);
595 if (spoint_at_sline(sp, &sl))
596 {
597 return true;
598 }
599 }
600
601 do
602 {
603 SEuler se,
604 te;
605 SPoint p,
606 lp[2];
607 bool a1,
608 a2,
609 eqa;
610 int32 cntr = 0;
611 SPOLY *tmp = (SPOLY *) palloc(VARSIZE(pg));
612
613 /*
614 * Make a transformation, so the point is (0,0)
615 */
616
617 se.phi_a = EULER_AXIS_Z;
618 se.theta_a = EULER_AXIS_X;
619 se.psi_a = EULER_AXIS_Z;
620 se.phi = PIH - sp->lng;
621 se.theta = -sp->lat;
622 se.psi = -PIH;
623
624 euler_spoly_trans(tmp, pg, &se);
625
626 p.lng = 0.0;
627 p.lat = 0.0;
628
629 /* Check whether an edge is on equator. */
630 /* If yes, rotate randomized around 0,0 */
631
632 cntr = 0;
633 do
634 {
635 eqa = false;
636 for (i = 0; i < pg->npts; i++)
637 {
638 if (FPzero(tmp->p[i].lat))
639 {
640 if (FPeq(cos(tmp->p[i].lng), -1.0))
641 {
642 return false;
643 }
644 else
645 {
646 eqa = true;
647 break;
648 }
649 }
650 }
651 if (eqa)
652 {
653 SPOLY *ttt = (SPOLY *) palloc(VARSIZE(pg));
654
655 srand(cntr);
656 se.phi_a = se.theta_a = se.psi_a = EULER_AXIS_X;
657 se.phi = ((double) rand() / RAND_MAX) * PID;
658 se.theta = 0.0;
659 se.psi = 0.0;
660 euler_spoly_trans(ttt, tmp, &se);
661 memcpy((void *) tmp, (void *) ttt, VARSIZE(pg));
662 pfree(ttt);
663 }
664 if (cntr > 10000)
665 {
666 elog(WARNING, "Bug found in spoly_contains_point");
667 elog(ERROR, "Please report it to pg_sphere team!");
668 return false;
669 }
670 cntr++;
671 } while (eqa);
672
673 /* Count line segment crossing "equator" */
674
675 cntr = 0;
676 for (i = 0; i < pg->npts; i++)
677 {
678
679 /* create a single line from segment */
680 spoly_segment(&sl, tmp, i);
681
682 sline_begin(&lp[0], &sl);
683 sline_end(&lp[1], &sl);
684
685 a1 = (FPgt(lp[0].lat, 0.0) && FPlt(lp[1].lat, 0.0));
686 a2 = (FPlt(lp[0].lat, 0.0) && FPgt(lp[1].lat, 0.0));
687
688 if (a1 || a2)
689 {
690 /* if crossing */
691 sphereline_to_euler_inv(&te, &sl);
692 if (a2)
693 {
694 /* crossing ascending */
695 p.lng = PID - te.phi;
696 }
697 else
698 {
699 p.lng = PI - te.phi;
700 }
701 spoint_check(&p);
702 if (p.lng < PI)
703 {
704 /* crossing between 0 and 180 deg */
705 cntr++;
706 }
707 }
708 }
709
710 pfree(tmp);
711 if (cntr % 2)
712 {
713 res = true;
714 }
715
716 } while (0);
717
718 return res;
719 }
720
721 /*
722 * Returns the relationship between a polygon and a line as
723 * PGS_LINE_POLY_REL int8 value.
724 *
725 * poly - pointer to the polygon
726 * line - pointer to the line
727 */
728 int8
poly_line_pos(const SPOLY * poly,const SLine * line)729 poly_line_pos(const SPOLY *poly, const SLine *line)
730 {
731 int32 i;
732 SLine sl;
733 SPoint slbeg,
734 slend;
735 int8 p1,
736 p2,
737 pos,
738 res;
739 const int8 sl_os = (1 << PGS_LINE_AVOID);
740 const int8 sl_cl = (1 << PGS_LINE_CONT_LINE);
741 const int8 sl_cr = (1 << PGS_LINE_CROSS);
742 const int8 sl_cn = (1 << PGS_LINE_CONNECT);
743 const int8 sl_ov = (1 << PGS_LINE_OVER);
744 const int8 sl_eq = (1 << PGS_LINE_EQUAL);
745
746 pos = 0;
747 res = 0;
748
749 sline_begin(&slbeg, line);
750 sline_end(&slend, line);
751
752 p1 = spoly_contains_point(poly, &slbeg);
753 p2 = spoly_contains_point(poly, &slend);
754
755 for (i = 0; i < poly->npts; i++)
756 {
757 spoly_segment(&sl, poly, i);
758 pos = (1 << sline_sline_pos(&sl, line));
759 if (pos == sl_eq)
760 {
761 pos = sl_cl;
762 /* is contain */
763 }
764 if (pos == sl_ov)
765 {
766 return PGS_LINE_POLY_OVER;
767 /* overlap */
768 }
769 /* Recheck line crossing */
770 if (pos == sl_cr)
771 {
772 bool bal,
773 eal;
774
775 bal = spoint_at_sline(&slbeg, &sl);
776 eal = spoint_at_sline(&slend, &sl);
777 if (!bal && !eal)
778 {
779 return PGS_LINE_POLY_OVER;
780 /* overlap */
781 }
782 if ((bal && p2) || (eal && p1))
783 {
784 pos = sl_cl;
785 /* is contain */
786 }
787 else
788 {
789 return PGS_LINE_POLY_OVER;
790 /* overlap */
791 }
792 }
793 res |= pos;
794 }
795 if ((res & sl_cl) && ((res - sl_cl - sl_os - sl_cn - 1) < 0))
796 {
797 return PGS_POLY_CONT_LINE;
798 }
799 else if (p1 && p2 && ((res - sl_os - sl_cn - 1) < 0))
800 {
801 return PGS_POLY_CONT_LINE;
802 }
803 else if (!p1 && !p2 && ((res - sl_os - 1) < 0))
804 {
805 return PGS_LINE_POLY_AVOID;
806 }
807 return PGS_LINE_POLY_OVER;
808 }
809
810
811 Datum
spherepoly_in(PG_FUNCTION_ARGS)812 spherepoly_in(PG_FUNCTION_ARGS)
813 {
814 SPOLY *poly;
815 char *c = PG_GETARG_CSTRING(0);
816 int32 i,
817 nelem;
818
819 void sphere_yyparse(void);
820
821 init_buffer(c);
822 sphere_yyparse();
823
824 nelem = get_path_count();
825 if (nelem > 2)
826 {
827 // allocate arr
828 SPoint* arr = (SPoint *)malloc(nelem * sizeof(SPoint));
829 if (arr == NULL) {
830 reset_buffer();
831 elog(ERROR, "spherepoly_in: Could not allocate array.");
832 PG_RETURN_NULL();
833 }
834
835 for (i = 0; i < nelem; i++)
836 {
837 get_path_elem(i, &arr[i].lng, &arr[i].lat);
838 }
839 poly = spherepoly_from_array(&arr[0], nelem);
840 // free allocated array
841 free(arr);
842 }
843 else
844 {
845 reset_buffer();
846 elog(ERROR, "spherepoly_in: more than two points needed");
847 PG_RETURN_NULL();
848 }
849 reset_buffer();
850
851 PG_RETURN_POINTER(poly);
852 }
853
854 Datum
spherepoly_equal(PG_FUNCTION_ARGS)855 spherepoly_equal(PG_FUNCTION_ARGS)
856 {
857 SPOLY *p1 = PG_GETARG_SPOLY(0);
858 SPOLY *p2 = PG_GETARG_SPOLY(1);
859
860 PG_RETURN_BOOL(spoly_eq(p1, p2, false));
861 }
862
863 Datum
spherepoly_equal_neg(PG_FUNCTION_ARGS)864 spherepoly_equal_neg(PG_FUNCTION_ARGS)
865 {
866 SPOLY *p1 = PG_GETARG_SPOLY(0);
867 SPOLY *p2 = PG_GETARG_SPOLY(1);
868
869 PG_RETURN_BOOL(!spoly_eq(p1, p2, false));
870 }
871
872 Datum
spherepoly_circ(PG_FUNCTION_ARGS)873 spherepoly_circ(PG_FUNCTION_ARGS)
874 {
875 SPOLY *poly = PG_GETARG_SPOLY(0);
876 int32 i;
877 SLine l;
878 float8 sum = 0.0;
879
880 for (i = 0; i < poly->npts; i++)
881 {
882 spoly_segment(&l, poly, i);
883 sum += l.length;
884 }
885 PG_RETURN_FLOAT8(sum);
886 }
887
888 Datum
spherepoly_npts(PG_FUNCTION_ARGS)889 spherepoly_npts(PG_FUNCTION_ARGS)
890 {
891 SPOLY *poly = PG_GETARG_SPOLY(0);
892
893 PG_RETURN_INT32(poly->npts);
894 }
895
896
897
898 Datum
spherepoly_area(PG_FUNCTION_ARGS)899 spherepoly_area(PG_FUNCTION_ARGS)
900 {
901 SPOLY *poly = PG_GETARG_SPOLY(0);
902 int32 i;
903 SPoint *s = (SPoint*)malloc((poly->npts+2)*sizeof(SPoint));
904 //SPoint s[poly->npts + 2];
905 SPoint stmp[2];
906 SEuler se;
907 float8 sum = 0.0;
908
909 if (s == NULL) {
910 elog(ERROR, "spherepoly_area: Could not allocate array.");
911 PG_RETURN_NULL();
912 }
913
914 memcpy((void *) &s[1],
915 (void *) &poly->p[0],
916 poly->npts * sizeof(SPoint));
917 memcpy((void *) &s[0], (void *) &s[poly->npts], sizeof(SPoint));
918 memcpy((void *) &s[poly->npts + 1], (void *) &s[1], sizeof(SPoint));
919
920 se.psi = 0;
921 se.phi_a = EULER_AXIS_Z;
922 se.theta_a = EULER_AXIS_X;
923 se.psi_a = EULER_AXIS_Z;
924
925 for (i = 1; i <= poly->npts; i++)
926 {
927
928 se.phi = -PIH - s[i].lng;
929 se.theta = s[i].lat - PIH;
930 euler_spoint_trans(&stmp[0], &s[i - 1], &se);
931 euler_spoint_trans(&stmp[1], &s[i + 1], &se);
932
933 stmp[1].lng -= stmp[0].lng;
934 if (FPlt(stmp[1].lng, 0.0))
935 {
936 stmp[1].lng += PID;
937 }
938 sum += stmp[1].lng;
939
940 }
941
942 sum -= (PI * (poly->npts - 2));
943 if (FPge(sum, PID))
944 {
945 sum = 2 * PID - sum;
946 }
947
948 if (FPzero(sum))
949 {
950 sum = 0.0;
951 }
952
953 // free array
954 free(s);
955
956 PG_RETURN_FLOAT8(sum);
957 }
958
959 Datum
spherepoly_cont_point(PG_FUNCTION_ARGS)960 spherepoly_cont_point(PG_FUNCTION_ARGS)
961 {
962 SPOLY *poly = PG_GETARG_SPOLY(0);
963 SPoint *sp = (SPoint *) PG_GETARG_POINTER(1);
964
965 PG_RETURN_BOOL(spoly_contains_point(poly, sp));
966 }
967
968 Datum
spherepoly_cont_point_neg(PG_FUNCTION_ARGS)969 spherepoly_cont_point_neg(PG_FUNCTION_ARGS)
970 {
971 SPOLY *poly = PG_GETARG_SPOLY(0);
972 SPoint *sp = (SPoint *) PG_GETARG_POINTER(1);
973
974 PG_RETURN_BOOL(!spoly_contains_point(poly, sp));
975 }
976
977 Datum
spherepoly_cont_point_com(PG_FUNCTION_ARGS)978 spherepoly_cont_point_com(PG_FUNCTION_ARGS)
979 {
980 SPOLY *poly = PG_GETARG_SPOLY(1);
981 SPoint *sp = (SPoint *) PG_GETARG_POINTER(0);
982
983 PG_RETURN_BOOL(spoly_contains_point(poly, sp));
984 }
985
986 Datum
spherepoly_cont_point_com_neg(PG_FUNCTION_ARGS)987 spherepoly_cont_point_com_neg(PG_FUNCTION_ARGS)
988 {
989 SPOLY *poly = PG_GETARG_SPOLY(1);
990 SPoint *sp = (SPoint *) PG_GETARG_POINTER(0);
991
992 PG_RETURN_BOOL(!spoly_contains_point(poly, sp));
993 }
994
995 Datum
spherepoly_cont_circle(PG_FUNCTION_ARGS)996 spherepoly_cont_circle(PG_FUNCTION_ARGS)
997 {
998 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(1);
999 SPOLY *poly = PG_GETARG_SPOLY(0);
1000
1001 PG_RETURN_BOOL(poly_circle_pos(poly, circ) == PGS_POLY_CONT_CIRCLE);
1002 }
1003
1004 Datum
spherepoly_cont_circle_neg(PG_FUNCTION_ARGS)1005 spherepoly_cont_circle_neg(PG_FUNCTION_ARGS)
1006 {
1007 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(1);
1008 SPOLY *poly = PG_GETARG_SPOLY(0);
1009
1010 PG_RETURN_BOOL(poly_circle_pos(poly, circ) != PGS_POLY_CONT_CIRCLE);
1011 }
1012
1013 Datum
spherepoly_cont_circle_com(PG_FUNCTION_ARGS)1014 spherepoly_cont_circle_com(PG_FUNCTION_ARGS)
1015 {
1016 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(0);
1017 SPOLY *poly = PG_GETARG_SPOLY(1);
1018
1019 PG_RETURN_BOOL(poly_circle_pos(poly, circ) == PGS_POLY_CONT_CIRCLE);
1020 }
1021
1022 Datum
spherepoly_cont_circle_com_neg(PG_FUNCTION_ARGS)1023 spherepoly_cont_circle_com_neg(PG_FUNCTION_ARGS)
1024 {
1025 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(0);
1026 SPOLY *poly = PG_GETARG_SPOLY(1);
1027
1028 PG_RETURN_BOOL(poly_circle_pos(poly, circ) != PGS_POLY_CONT_CIRCLE);
1029 }
1030
1031 Datum
spherecircle_cont_poly(PG_FUNCTION_ARGS)1032 spherecircle_cont_poly(PG_FUNCTION_ARGS)
1033 {
1034 SPOLY *poly = PG_GETARG_SPOLY(1);
1035 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(0);
1036
1037 PG_RETURN_BOOL(poly_circle_pos(poly, circ) == PGS_CIRCLE_CONT_POLY);
1038 }
1039
1040 Datum
spherecircle_cont_poly_neg(PG_FUNCTION_ARGS)1041 spherecircle_cont_poly_neg(PG_FUNCTION_ARGS)
1042 {
1043 SPOLY *poly = PG_GETARG_SPOLY(1);
1044 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(0);
1045
1046 PG_RETURN_BOOL(poly_circle_pos(poly, circ) != PGS_CIRCLE_CONT_POLY);
1047 }
1048
1049 Datum
spherecircle_cont_poly_com(PG_FUNCTION_ARGS)1050 spherecircle_cont_poly_com(PG_FUNCTION_ARGS)
1051 {
1052 SPOLY *poly = PG_GETARG_SPOLY(0);
1053 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(1);
1054
1055 PG_RETURN_BOOL(poly_circle_pos(poly, circ) == PGS_CIRCLE_CONT_POLY);
1056 }
1057
1058 Datum
spherecircle_cont_poly_com_neg(PG_FUNCTION_ARGS)1059 spherecircle_cont_poly_com_neg(PG_FUNCTION_ARGS)
1060 {
1061 SPOLY *poly = PG_GETARG_SPOLY(0);
1062 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(1);
1063
1064 PG_RETURN_BOOL(poly_circle_pos(poly, circ) != PGS_CIRCLE_CONT_POLY);
1065 }
1066
1067 Datum
spherepoly_overlap_circle(PG_FUNCTION_ARGS)1068 spherepoly_overlap_circle(PG_FUNCTION_ARGS)
1069 {
1070 SPOLY *poly = PG_GETARG_SPOLY(0);
1071 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(1);
1072
1073 PG_RETURN_BOOL(poly_circle_pos(poly, circ) > PGS_CIRCLE_POLY_AVOID);
1074 }
1075
1076 Datum
spherepoly_overlap_circle_neg(PG_FUNCTION_ARGS)1077 spherepoly_overlap_circle_neg(PG_FUNCTION_ARGS)
1078 {
1079 SPOLY *poly = PG_GETARG_SPOLY(0);
1080 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(1);
1081
1082 PG_RETURN_BOOL(poly_circle_pos(poly, circ) == PGS_CIRCLE_POLY_AVOID);
1083 }
1084
1085 Datum
spherepoly_overlap_circle_com(PG_FUNCTION_ARGS)1086 spherepoly_overlap_circle_com(PG_FUNCTION_ARGS)
1087 {
1088 SPOLY *poly = PG_GETARG_SPOLY(1);
1089 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(0);
1090
1091 PG_RETURN_BOOL(poly_circle_pos(poly, circ) > PGS_CIRCLE_POLY_AVOID);
1092 }
1093
1094 Datum
spherepoly_overlap_circle_com_neg(PG_FUNCTION_ARGS)1095 spherepoly_overlap_circle_com_neg(PG_FUNCTION_ARGS)
1096 {
1097 SPOLY *poly = PG_GETARG_SPOLY(1);
1098 SCIRCLE *circ = (SCIRCLE *) PG_GETARG_POINTER(0);
1099
1100 PG_RETURN_BOOL(poly_circle_pos(poly, circ) == PGS_CIRCLE_POLY_AVOID);
1101 }
1102
1103 Datum
spherepoly_cont_line(PG_FUNCTION_ARGS)1104 spherepoly_cont_line(PG_FUNCTION_ARGS)
1105 {
1106 SPOLY *poly = PG_GETARG_SPOLY(0);
1107 SLine *line = (SLine *) PG_GETARG_POINTER(1);
1108
1109 PG_RETURN_BOOL(poly_line_pos(poly, line) == PGS_POLY_CONT_LINE);
1110 }
1111
1112 Datum
spherepoly_cont_line_neg(PG_FUNCTION_ARGS)1113 spherepoly_cont_line_neg(PG_FUNCTION_ARGS)
1114 {
1115 SPOLY *poly = PG_GETARG_SPOLY(0);
1116 SLine *line = (SLine *) PG_GETARG_POINTER(1);
1117
1118 PG_RETURN_BOOL(poly_line_pos(poly, line) != PGS_POLY_CONT_LINE);
1119 }
1120
1121 Datum
spherepoly_cont_line_com(PG_FUNCTION_ARGS)1122 spherepoly_cont_line_com(PG_FUNCTION_ARGS)
1123 {
1124 SPOLY *poly = PG_GETARG_SPOLY(1);
1125 SLine *line = (SLine *) PG_GETARG_POINTER(0);
1126
1127 PG_RETURN_BOOL(poly_line_pos(poly, line) == PGS_POLY_CONT_LINE);
1128 }
1129
1130 Datum
spherepoly_cont_line_com_neg(PG_FUNCTION_ARGS)1131 spherepoly_cont_line_com_neg(PG_FUNCTION_ARGS)
1132 {
1133 SPOLY *poly = PG_GETARG_SPOLY(1);
1134 SLine *line = (SLine *) PG_GETARG_POINTER(0);
1135
1136 PG_RETURN_BOOL(poly_line_pos(poly, line) != PGS_POLY_CONT_LINE);
1137 }
1138
1139 Datum
spherepoly_overlap_line(PG_FUNCTION_ARGS)1140 spherepoly_overlap_line(PG_FUNCTION_ARGS)
1141 {
1142 SPOLY *poly = PG_GETARG_SPOLY(0);
1143 SLine *line = (SLine *) PG_GETARG_POINTER(1);
1144
1145 PG_RETURN_BOOL(poly_line_pos(poly, line) > PGS_LINE_POLY_AVOID);
1146 }
1147
1148 Datum
spherepoly_overlap_line_neg(PG_FUNCTION_ARGS)1149 spherepoly_overlap_line_neg(PG_FUNCTION_ARGS)
1150 {
1151 SPOLY *poly = PG_GETARG_SPOLY(0);
1152 SLine *line = (SLine *) PG_GETARG_POINTER(1);
1153
1154 PG_RETURN_BOOL(poly_line_pos(poly, line) == PGS_LINE_POLY_AVOID);
1155 }
1156
1157 Datum
spherepoly_overlap_line_com(PG_FUNCTION_ARGS)1158 spherepoly_overlap_line_com(PG_FUNCTION_ARGS)
1159 {
1160 SPOLY *poly = PG_GETARG_SPOLY(1);
1161 SLine *line = (SLine *) PG_GETARG_POINTER(0);
1162
1163 PG_RETURN_BOOL(poly_line_pos(poly, line) > PGS_LINE_POLY_AVOID);
1164 }
1165
1166 Datum
spherepoly_overlap_line_com_neg(PG_FUNCTION_ARGS)1167 spherepoly_overlap_line_com_neg(PG_FUNCTION_ARGS)
1168 {
1169 SPOLY *poly = PG_GETARG_SPOLY(1);
1170 SLine *line = (SLine *) PG_GETARG_POINTER(0);
1171
1172 PG_RETURN_BOOL(poly_line_pos(poly, line) == PGS_LINE_POLY_AVOID);
1173 }
1174
1175
1176 Datum
spherepoly_cont_poly(PG_FUNCTION_ARGS)1177 spherepoly_cont_poly(PG_FUNCTION_ARGS)
1178 {
1179 SPOLY *poly1 = PG_GETARG_SPOLY(0);
1180 SPOLY *poly2 = PG_GETARG_SPOLY(1);
1181
1182 PG_RETURN_BOOL(poly_poly_pos(poly1, poly2, false) == PGS_POLY_CONT);
1183 }
1184
1185 Datum
spherepoly_cont_poly_neg(PG_FUNCTION_ARGS)1186 spherepoly_cont_poly_neg(PG_FUNCTION_ARGS)
1187 {
1188 SPOLY *poly1 = PG_GETARG_SPOLY(0);
1189 SPOLY *poly2 = PG_GETARG_SPOLY(1);
1190
1191 PG_RETURN_BOOL(poly_poly_pos(poly1, poly2, false) != PGS_POLY_CONT);
1192 }
1193
1194 Datum
spherepoly_cont_poly_com(PG_FUNCTION_ARGS)1195 spherepoly_cont_poly_com(PG_FUNCTION_ARGS)
1196 {
1197 SPOLY *poly1 = PG_GETARG_SPOLY(1);
1198 SPOLY *poly2 = PG_GETARG_SPOLY(0);
1199
1200 PG_RETURN_BOOL(poly_poly_pos(poly1, poly2, false) == PGS_POLY_CONT);
1201 }
1202
1203 Datum
spherepoly_cont_poly_com_neg(PG_FUNCTION_ARGS)1204 spherepoly_cont_poly_com_neg(PG_FUNCTION_ARGS)
1205 {
1206 SPOLY *poly1 = PG_GETARG_SPOLY(1);
1207 SPOLY *poly2 = PG_GETARG_SPOLY(0);
1208
1209 PG_RETURN_BOOL(poly_poly_pos(poly1, poly2, false) != PGS_POLY_CONT);
1210 }
1211
1212 Datum
spherepoly_overlap_poly(PG_FUNCTION_ARGS)1213 spherepoly_overlap_poly(PG_FUNCTION_ARGS)
1214 {
1215 SPOLY *poly1 = PG_GETARG_SPOLY(0);
1216 SPOLY *poly2 = PG_GETARG_SPOLY(1);
1217
1218 PG_RETURN_BOOL(poly_poly_pos(poly1, poly2, false) > PGS_POLY_AVOID);
1219 }
1220
1221 Datum
spherepoly_overlap_poly_neg(PG_FUNCTION_ARGS)1222 spherepoly_overlap_poly_neg(PG_FUNCTION_ARGS)
1223 {
1224 SPOLY *poly1 = PG_GETARG_SPOLY(0);
1225 SPOLY *poly2 = PG_GETARG_SPOLY(1);
1226
1227 PG_RETURN_BOOL(poly_poly_pos(poly1, poly2, false) == PGS_POLY_AVOID);
1228 }
1229
1230 Datum
spherepoly_cont_ellipse(PG_FUNCTION_ARGS)1231 spherepoly_cont_ellipse(PG_FUNCTION_ARGS)
1232 {
1233 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(1);
1234 SPOLY *poly = PG_GETARG_SPOLY(0);
1235
1236 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) == PGS_POLY_CONT_ELLIPSE);
1237 }
1238
1239 Datum
spherepoly_cont_ellipse_neg(PG_FUNCTION_ARGS)1240 spherepoly_cont_ellipse_neg(PG_FUNCTION_ARGS)
1241 {
1242 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(1);
1243 SPOLY *poly = PG_GETARG_SPOLY(0);
1244
1245 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) != PGS_POLY_CONT_ELLIPSE);
1246 }
1247
1248 Datum
spherepoly_cont_ellipse_com(PG_FUNCTION_ARGS)1249 spherepoly_cont_ellipse_com(PG_FUNCTION_ARGS)
1250 {
1251 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(0);
1252 SPOLY *poly = PG_GETARG_SPOLY(1);
1253
1254 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) == PGS_POLY_CONT_ELLIPSE);
1255 }
1256
1257 Datum
spherepoly_cont_ellipse_com_neg(PG_FUNCTION_ARGS)1258 spherepoly_cont_ellipse_com_neg(PG_FUNCTION_ARGS)
1259 {
1260 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(0);
1261 SPOLY *poly = PG_GETARG_SPOLY(1);
1262
1263 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) != PGS_POLY_CONT_ELLIPSE);
1264 }
1265
1266 Datum
sphereellipse_cont_poly(PG_FUNCTION_ARGS)1267 sphereellipse_cont_poly(PG_FUNCTION_ARGS)
1268 {
1269 SPOLY *poly = PG_GETARG_SPOLY(1);
1270 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(0);
1271
1272 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) == PGS_ELLIPSE_CONT_POLY);
1273 }
1274
1275 Datum
sphereellipse_cont_poly_neg(PG_FUNCTION_ARGS)1276 sphereellipse_cont_poly_neg(PG_FUNCTION_ARGS)
1277 {
1278 SPOLY *poly = PG_GETARG_SPOLY(1);
1279 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(0);
1280
1281 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) != PGS_ELLIPSE_CONT_POLY);
1282 }
1283
1284 Datum
sphereellipse_cont_poly_com(PG_FUNCTION_ARGS)1285 sphereellipse_cont_poly_com(PG_FUNCTION_ARGS)
1286 {
1287 SPOLY *poly = PG_GETARG_SPOLY(0);
1288 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(1);
1289
1290 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) == PGS_ELLIPSE_CONT_POLY);
1291 }
1292
1293 Datum
sphereellipse_cont_poly_com_neg(PG_FUNCTION_ARGS)1294 sphereellipse_cont_poly_com_neg(PG_FUNCTION_ARGS)
1295 {
1296 SPOLY *poly = PG_GETARG_SPOLY(0);
1297 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(1);
1298
1299 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) != PGS_ELLIPSE_CONT_POLY);
1300 }
1301
1302 Datum
spherepoly_overlap_ellipse(PG_FUNCTION_ARGS)1303 spherepoly_overlap_ellipse(PG_FUNCTION_ARGS)
1304 {
1305 SPOLY *poly = PG_GETARG_SPOLY(0);
1306 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(1);
1307
1308 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) > PGS_ELLIPSE_POLY_AVOID);
1309 }
1310
1311 Datum
spherepoly_overlap_ellipse_neg(PG_FUNCTION_ARGS)1312 spherepoly_overlap_ellipse_neg(PG_FUNCTION_ARGS)
1313 {
1314 SPOLY *poly = PG_GETARG_SPOLY(0);
1315 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(1);
1316
1317 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) == PGS_ELLIPSE_POLY_AVOID);
1318 }
1319
1320 Datum
spherepoly_overlap_ellipse_com(PG_FUNCTION_ARGS)1321 spherepoly_overlap_ellipse_com(PG_FUNCTION_ARGS)
1322 {
1323 SPOLY *poly = PG_GETARG_SPOLY(1);
1324 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(0);
1325
1326 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) > PGS_ELLIPSE_POLY_AVOID);
1327 }
1328
1329 Datum
spherepoly_overlap_ellipse_com_neg(PG_FUNCTION_ARGS)1330 spherepoly_overlap_ellipse_com_neg(PG_FUNCTION_ARGS)
1331 {
1332 SPOLY *poly = PG_GETARG_SPOLY(1);
1333 SELLIPSE *ell = (SELLIPSE *) PG_GETARG_POINTER(0);
1334
1335 PG_RETURN_BOOL(poly_ellipse_pos(poly, ell) == PGS_ELLIPSE_POLY_AVOID);
1336 }
1337
1338 Datum
spheretrans_poly(PG_FUNCTION_ARGS)1339 spheretrans_poly(PG_FUNCTION_ARGS)
1340 {
1341 SPOLY *sp = PG_GETARG_SPOLY(0);
1342 SEuler *se = (SEuler *) PG_GETARG_POINTER(1);
1343 SPOLY *out = (SPOLY *) palloc(VARSIZE(sp));
1344
1345 euler_spoly_trans(out, sp, se);
1346 PG_RETURN_POINTER(out);
1347 }
1348
1349 Datum
spheretrans_poly_inverse(PG_FUNCTION_ARGS)1350 spheretrans_poly_inverse(PG_FUNCTION_ARGS)
1351 {
1352 Datum sp = PG_GETARG_DATUM(0);
1353 SEuler *se = (SEuler *) PG_GETARG_POINTER(1);
1354 SEuler tmp;
1355 Datum ret;
1356
1357 spheretrans_inverse(&tmp, se);
1358 ret = DirectFunctionCall2(spheretrans_poly,
1359 sp, PointerGetDatum(&tmp));
1360 PG_RETURN_DATUM(ret);
1361 }
1362
1363 Datum
spherepoly_add_point(PG_FUNCTION_ARGS)1364 spherepoly_add_point(PG_FUNCTION_ARGS)
1365 {
1366 SPOLY *poly = (SPOLY *) PG_GETARG_POINTER(0);
1367 SPoint *p = (SPoint *) PG_GETARG_POINTER(1);
1368 int32 size = 0;
1369 SPOLY *poly_new = NULL;
1370
1371 if (p == NULL)
1372 {
1373 PG_RETURN_POINTER(poly);
1374 }
1375 if (poly == NULL)
1376 {
1377 size = offsetof(SPOLY, p[0]) +sizeof(SPoint);
1378 poly = (SPOLY *) palloc(size);
1379 memcpy((void *) &poly->p[0], (void *) p, sizeof(SPoint));
1380 SET_VARSIZE(poly, size);
1381 poly->npts = 1;
1382 PG_RETURN_POINTER(poly);
1383 }
1384
1385 poly = PG_GETARG_SPOLY(0);
1386
1387 /* skip if equal */
1388 if (spoint_eq(p, &poly->p[poly->npts - 1]))
1389 {
1390 PG_RETURN_POINTER(poly);
1391 }
1392
1393 /* Skip if distance is equal 180deg */
1394 if (FPeq(spoint_dist(p, &poly->p[poly->npts - 1]), PI))
1395 {
1396 elog(NOTICE, "spoly(spoint): Skip point, distance of previous point is 180deg");
1397 }
1398
1399 size = offsetof(SPOLY, p[0]) +sizeof(SPoint) * (poly->npts + 1);
1400 poly_new = palloc(size);
1401 memcpy((void *) poly_new, (void *) poly, VARSIZE(poly));
1402 poly_new->npts++;
1403 SET_VARSIZE(poly_new, size);
1404
1405 memcpy((void *) &poly_new->p[poly->npts], (void *) p, sizeof(SPoint));
1406 PG_RETURN_POINTER(poly_new);
1407 }
1408
1409
1410 Datum
spherepoly_add_points_finalize(PG_FUNCTION_ARGS)1411 spherepoly_add_points_finalize(PG_FUNCTION_ARGS)
1412 {
1413 SPOLY *poly = (SPOLY *) PG_GETARG_POINTER(0);
1414
1415 if (poly == NULL)
1416 {
1417 PG_RETURN_NULL();
1418 }
1419
1420 poly = PG_GETARG_SPOLY(0);
1421
1422 if (poly->npts < 3)
1423 {
1424 elog(NOTICE, "spoly(spoint): At least 3 points required");
1425 pfree(poly);
1426 PG_RETURN_NULL();
1427 }
1428 /* Skip if distance is equal to 180deg */
1429 if (FPeq(spoint_dist(&poly->p[0], &poly->p[poly->npts - 1]), PI))
1430 {
1431 elog(NOTICE, "spoly(spoint): Cannot close polygon. Distance between first and last point is 180deg");
1432 pfree(poly);
1433 PG_RETURN_NULL();
1434 }
1435
1436 if (!spherepoly_check(poly))
1437 {
1438 elog(NOTICE, "spoly(spoint): a line segment overlaps or polygon too large");
1439 pfree(poly);
1440 PG_RETURN_NULL();
1441 }
1442 PG_RETURN_POINTER(poly);
1443 }
1444