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