1 #include "circle.h"
2 
3 /* Circle functions */
4 
5 PG_FUNCTION_INFO_V1(spherecircle_in);
6 PG_FUNCTION_INFO_V1(spherecircle_equal);
7 PG_FUNCTION_INFO_V1(spherecircle_equal_neg);
8 PG_FUNCTION_INFO_V1(spherecircle_distance);
9 PG_FUNCTION_INFO_V1(spherecircle_point_distance);
10 PG_FUNCTION_INFO_V1(spherecircle_point_distance_com);
11 PG_FUNCTION_INFO_V1(spherepoint_in_circle);
12 PG_FUNCTION_INFO_V1(spherepoint_in_circle_neg);
13 PG_FUNCTION_INFO_V1(spherepoint_in_circle_com);
14 PG_FUNCTION_INFO_V1(spherepoint_in_circle_com_neg);
15 PG_FUNCTION_INFO_V1(spherecircle_in_circle);
16 PG_FUNCTION_INFO_V1(spherecircle_in_circle_neg);
17 PG_FUNCTION_INFO_V1(spherecircle_in_circle_com);
18 PG_FUNCTION_INFO_V1(spherecircle_in_circle_com_neg);
19 PG_FUNCTION_INFO_V1(spherecircle_overlap);
20 PG_FUNCTION_INFO_V1(spherecircle_overlap_neg);
21 PG_FUNCTION_INFO_V1(spherecircle_center);
22 PG_FUNCTION_INFO_V1(spherecircle_radius);
23 PG_FUNCTION_INFO_V1(spherepoint_to_circle);
24 PG_FUNCTION_INFO_V1(spherecircle_by_center);
25 PG_FUNCTION_INFO_V1(spherecircle_area);
26 PG_FUNCTION_INFO_V1(spherecircle_circ);
27 PG_FUNCTION_INFO_V1(spheretrans_circle);
28 PG_FUNCTION_INFO_V1(spheretrans_circle_inverse);
29 
30 
31 bool
scircle_eq(const SCIRCLE * c1,const SCIRCLE * c2)32 scircle_eq(const SCIRCLE *c1, const SCIRCLE *c2)
33 {
34 	return (spoint_eq(&c1->center, &c2->center) &&
35 				FPeq(c1->radius, c2->radius));
36 }
37 
38 bool
spoint_in_circle(const SPoint * p,const SCIRCLE * c)39 spoint_in_circle(const SPoint *p, const SCIRCLE *c)
40 {
41 	float8 dist = spoint_dist(p, &c->center);
42 
43 	if (FPle(dist, c->radius))
44 	{
45 		return true;
46 	}
47 	return false;
48 }
49 
50 void
euler_scircle_trans(SCIRCLE * out,const SCIRCLE * in,const SEuler * se)51 euler_scircle_trans(SCIRCLE *out, const SCIRCLE *in, const SEuler *se)
52 {
53 	euler_spoint_trans(&out->center, &in->center, se);
54 	out->radius = in->radius;
55 }
56 
57 Datum
spherecircle_in(PG_FUNCTION_ARGS)58 spherecircle_in(PG_FUNCTION_ARGS)
59 {
60 	SCIRCLE	   *c = (SCIRCLE *) palloc(sizeof(SCIRCLE));
61 	char	   *s = PG_GETARG_CSTRING(0);
62 	double		lng,
63 				lat,
64 				radius;
65 
66 	init_buffer(s);
67 	sphere_yyparse();
68 	if (get_circle(&lng, &lat, &radius))
69 	{
70 		c->center.lng = lng;
71 		c->center.lat = lat;
72 		c->radius = radius;
73 		reset_buffer();
74 
75 		/*
76 		 * It's important to allow circles with radius 90 degrees!
77 		 */
78 		if (FPgt(c->radius, PIH))
79 		{
80 			pfree(c);
81 			c = NULL;
82 			elog(ERROR, "spherecircle_in: radius must be not greater than 90 degrees");
83 		}
84 		else if (FPeq(c->radius, PIH))
85 		{
86 			/* set "exact" 90 degrees */
87 			c->radius = PIH;
88 		}
89 		spoint_check(&c->center);
90 	}
91 	else
92 	{
93 		reset_buffer();
94 		pfree(c);
95 		c = NULL;
96 		elog(ERROR, "spherecircle_in: parse error");
97 	}
98 	PG_RETURN_POINTER(c);
99 }
100 
101 Datum
spherecircle_equal(PG_FUNCTION_ARGS)102 spherecircle_equal(PG_FUNCTION_ARGS)
103 {
104 	SCIRCLE	   *c1 = (SCIRCLE *) PG_GETARG_POINTER(0);
105 	SCIRCLE	   *c2 = (SCIRCLE *) PG_GETARG_POINTER(1);
106 
107 	PG_RETURN_BOOL(scircle_eq(c1, c2));
108 }
109 
110 Datum
spherecircle_equal_neg(PG_FUNCTION_ARGS)111 spherecircle_equal_neg(PG_FUNCTION_ARGS)
112 {
113 	SCIRCLE	   *c1 = (SCIRCLE *) PG_GETARG_POINTER(0);
114 	SCIRCLE	   *c2 = (SCIRCLE *) PG_GETARG_POINTER(1);
115 
116 	PG_RETURN_BOOL(!scircle_eq(c1, c2));
117 }
118 
119 Datum
spherecircle_distance(PG_FUNCTION_ARGS)120 spherecircle_distance(PG_FUNCTION_ARGS)
121 {
122 	SCIRCLE	   *c1 = (SCIRCLE *) PG_GETARG_POINTER(0);
123 	SCIRCLE	   *c2 = (SCIRCLE *) PG_GETARG_POINTER(1);
124 	float8		dist = spoint_dist(&c1->center, &c2->center);
125 
126 	dist -= (c1->radius + c2->radius);
127 	if (dist < 0.0)
128 	{
129 		dist = 0.0;
130 	}
131 	PG_RETURN_FLOAT8(dist);
132 }
133 
134 Datum
spherecircle_point_distance(PG_FUNCTION_ARGS)135 spherecircle_point_distance(PG_FUNCTION_ARGS)
136 {
137 	SCIRCLE	   *c = (SCIRCLE *) PG_GETARG_POINTER(0);
138 	SPoint	   *p = (SPoint *) PG_GETARG_POINTER(1);
139 	float8		dist = spoint_dist(&c->center, p);
140 
141 	dist = dist - c->radius;
142 	if (dist < 0.0)
143 	{
144 		dist = 0.0;
145 	}
146 	PG_RETURN_FLOAT8(dist);
147 }
148 
149 Datum
spherecircle_point_distance_com(PG_FUNCTION_ARGS)150 spherecircle_point_distance_com(PG_FUNCTION_ARGS)
151 {
152 	SPoint	   *p = (SPoint *) PG_GETARG_POINTER(0);
153 	SCIRCLE	   *c = (SCIRCLE *) PG_GETARG_POINTER(1);
154 	float8		dist = spoint_dist(&c->center, p);
155 
156 	dist = dist - c->radius;
157 	if (dist < 0.0)
158 	{
159 		dist = 0.0;
160 	}
161 	PG_RETURN_FLOAT8(dist);
162 }
163 
164 Datum
spherepoint_in_circle(PG_FUNCTION_ARGS)165 spherepoint_in_circle(PG_FUNCTION_ARGS)
166 {
167 	SPoint	   *p = (SPoint *) PG_GETARG_POINTER(0);
168 	SCIRCLE	   *c = (SCIRCLE *) PG_GETARG_POINTER(1);
169 
170 	PG_RETURN_BOOL(spoint_in_circle(p, c));
171 }
172 
173 Datum
spherepoint_in_circle_neg(PG_FUNCTION_ARGS)174 spherepoint_in_circle_neg(PG_FUNCTION_ARGS)
175 {
176 	SPoint	   *p = (SPoint *) PG_GETARG_POINTER(0);
177 	SCIRCLE    *c = (SCIRCLE *) PG_GETARG_POINTER(1);
178 
179 	PG_RETURN_BOOL(!spoint_in_circle(p, c));
180 }
181 
182 Datum
spherepoint_in_circle_com(PG_FUNCTION_ARGS)183 spherepoint_in_circle_com(PG_FUNCTION_ARGS)
184 {
185 	SPoint	   *p = (SPoint *) PG_GETARG_POINTER(1);
186 	SCIRCLE	   *c = (SCIRCLE *) PG_GETARG_POINTER(0);
187 
188 	PG_RETURN_BOOL(spoint_in_circle(p, c));
189 }
190 
191 Datum
spherepoint_in_circle_com_neg(PG_FUNCTION_ARGS)192 spherepoint_in_circle_com_neg(PG_FUNCTION_ARGS)
193 {
194 	SPoint	   *p = (SPoint *) PG_GETARG_POINTER(1);
195 	SCIRCLE	   *c = (SCIRCLE *) PG_GETARG_POINTER(0);
196 
197 	PG_RETURN_BOOL(!spoint_in_circle(p, c));
198 }
199 
200 Datum
spherecircle_in_circle(PG_FUNCTION_ARGS)201 spherecircle_in_circle(PG_FUNCTION_ARGS)
202 {
203 	SCIRCLE	   *c1 = (SCIRCLE *) PG_GETARG_POINTER(0);
204 	SCIRCLE	   *c2 = (SCIRCLE *) PG_GETARG_POINTER(1);
205 	float8		dist = spoint_dist(&c1->center, &c2->center);
206 
207 	if (scircle_eq(c1, c2))
208 	{
209 		PG_RETURN_BOOL(true);
210 	}
211 	else if (FPle((dist + c1->radius), c2->radius))
212 	{
213 		PG_RETURN_BOOL(true);
214 	}
215 	else
216 	{
217 		PG_RETURN_BOOL(false);
218 	}
219 }
220 
221 Datum
spherecircle_in_circle_neg(PG_FUNCTION_ARGS)222 spherecircle_in_circle_neg(PG_FUNCTION_ARGS)
223 {
224 	SCIRCLE	   *c1 = (SCIRCLE *) PG_GETARG_POINTER(0);
225 	SCIRCLE	   *c2 = (SCIRCLE *) PG_GETARG_POINTER(1);
226 	float8		dist = spoint_dist(&c1->center, &c2->center);
227 
228 	if (scircle_eq(c1, c2))
229 	{
230 		PG_RETURN_BOOL(false);
231 	}
232 	else if (FPgt((dist + c1->radius), c2->radius))
233 	{
234 		PG_RETURN_BOOL(true);
235 	}
236 	else
237 	{
238 		PG_RETURN_BOOL(false);
239 	}
240 }
241 
242 Datum
spherecircle_in_circle_com(PG_FUNCTION_ARGS)243 spherecircle_in_circle_com(PG_FUNCTION_ARGS)
244 {
245 	SCIRCLE	   *c1 = (SCIRCLE *) PG_GETARG_POINTER(1);
246 	SCIRCLE	   *c2 = (SCIRCLE *) PG_GETARG_POINTER(0);
247 	float8		dist = spoint_dist(&c1->center, &c2->center);
248 
249 	if (scircle_eq(c1, c2))
250 	{
251 		PG_RETURN_BOOL(true);
252 	}
253 	else if (FPle((dist + c1->radius), c2->radius))
254 	{
255 		PG_RETURN_BOOL(true);
256 	}
257 	else
258 	{
259 		PG_RETURN_BOOL(false);
260 	}
261 }
262 
263 Datum
spherecircle_in_circle_com_neg(PG_FUNCTION_ARGS)264 spherecircle_in_circle_com_neg(PG_FUNCTION_ARGS)
265 {
266 	SCIRCLE	   *c1 = (SCIRCLE *) PG_GETARG_POINTER(1);
267 	SCIRCLE	   *c2 = (SCIRCLE *) PG_GETARG_POINTER(0);
268 	float8		dist = spoint_dist(&c1->center, &c2->center);
269 
270 	if (scircle_eq(c1, c2))
271 	{
272 		PG_RETURN_BOOL(false);
273 	}
274 	else if (FPgt((dist + c1->radius), c2->radius))
275 	{
276 		PG_RETURN_BOOL(true);
277 	}
278 	else
279 	{
280 		PG_RETURN_BOOL(false);
281 	}
282 }
283 
284 Datum
spherecircle_overlap(PG_FUNCTION_ARGS)285 spherecircle_overlap(PG_FUNCTION_ARGS)
286 {
287 	SCIRCLE	   *c1 = (SCIRCLE *) PG_GETARG_POINTER(0);
288 	SCIRCLE	   *c2 = (SCIRCLE *) PG_GETARG_POINTER(1);
289 	float8		dist = spoint_dist(&c1->center, &c2->center);
290 
291 	if (scircle_eq(c1, c2))
292 	{
293 		PG_RETURN_BOOL(true);
294 	}
295 	else if (FPlt((c1->radius + c2->radius), dist))
296 	{
297 		PG_RETURN_BOOL(false);
298 	}
299 	else
300 	{
301 		PG_RETURN_BOOL(true);
302 	}
303 }
304 
305 Datum
spherecircle_overlap_neg(PG_FUNCTION_ARGS)306 spherecircle_overlap_neg(PG_FUNCTION_ARGS)
307 {
308 	SCIRCLE	   *c1 = (SCIRCLE *) PG_GETARG_POINTER(0);
309 	SCIRCLE	   *c2 = (SCIRCLE *) PG_GETARG_POINTER(1);
310 	float8		dist = spoint_dist(&c1->center, &c2->center);
311 
312 	if (scircle_eq(c1, c2))
313 	{
314 		PG_RETURN_BOOL(false);
315 	}
316 	else if (FPge((c1->radius + c2->radius), dist))
317 	{
318 		PG_RETURN_BOOL(false);
319 	}
320 	else
321 	{
322 		PG_RETURN_BOOL(true);
323 	}
324 }
325 
326 Datum
spherecircle_center(PG_FUNCTION_ARGS)327 spherecircle_center(PG_FUNCTION_ARGS)
328 {
329 	SCIRCLE	   *c = (SCIRCLE *) PG_GETARG_POINTER(0);
330 	SPoint	   *p = (SPoint *) palloc(sizeof(SPoint));
331 
332 	memcpy((void *) p, (void *) &c->center, sizeof(SPoint));
333 	PG_RETURN_POINTER(p);
334 }
335 
336 Datum
spherecircle_radius(PG_FUNCTION_ARGS)337 spherecircle_radius(PG_FUNCTION_ARGS)
338 {
339 	SCIRCLE	   *c = (SCIRCLE *) PG_GETARG_POINTER(0);
340 
341 	PG_RETURN_FLOAT8(c->radius);
342 }
343 
344 Datum
spherepoint_to_circle(PG_FUNCTION_ARGS)345 spherepoint_to_circle(PG_FUNCTION_ARGS)
346 {
347 	SPoint	   *p = (SPoint *) PG_GETARG_POINTER(0);
348 	SCIRCLE	   *c = (SCIRCLE *) palloc(sizeof(SCIRCLE));
349 
350 	memcpy((void *) &c->center, (void *) p, sizeof(SPoint));
351 	c->radius = 0;
352 	PG_RETURN_POINTER(c);
353 }
354 
355 Datum
spherecircle_by_center(PG_FUNCTION_ARGS)356 spherecircle_by_center(PG_FUNCTION_ARGS)
357 {
358 	SPoint	   *p = (SPoint *) PG_GETARG_POINTER(0);
359 	float8		rad = PG_GETARG_FLOAT8(1);
360 	SCIRCLE	   *c;
361 
362 	if (FPgt(rad, PIH) || FPlt(rad, 0.0))
363 	{
364 		elog(ERROR, "radius must be not greater than 90 degrees or less than 0");
365 		PG_RETURN_NULL();
366 	}
367 	c = (SCIRCLE *) palloc(sizeof(SCIRCLE));
368 	memcpy((void *) &c->center, (void *) p, sizeof(SPoint));
369 	c->radius = rad;
370 	PG_RETURN_POINTER(c);
371 }
372 
373 Datum
spherecircle_area(PG_FUNCTION_ARGS)374 spherecircle_area(PG_FUNCTION_ARGS)
375 {
376 	SCIRCLE	   *c = (SCIRCLE *) PG_GETARG_POINTER(0);
377 
378 	PG_RETURN_FLOAT8(PID * (1 - cos(c->radius)));
379 }
380 
381 Datum
spherecircle_circ(PG_FUNCTION_ARGS)382 spherecircle_circ(PG_FUNCTION_ARGS)
383 {
384 	SCIRCLE	   *c = (SCIRCLE *) PG_GETARG_POINTER(0);
385 
386 	PG_RETURN_FLOAT8(PID * (sin(c->radius)));
387 }
388 
389 Datum
spheretrans_circle(PG_FUNCTION_ARGS)390 spheretrans_circle(PG_FUNCTION_ARGS)
391 {
392 	SCIRCLE	   *sc = (SCIRCLE *) PG_GETARG_POINTER(0);
393 	SEuler	   *se = (SEuler *) PG_GETARG_POINTER(1);
394 	SCIRCLE	   *out = (SCIRCLE *) palloc(sizeof(SCIRCLE));
395 
396 	euler_scircle_trans(out, sc, se);
397 	PG_RETURN_POINTER(out);
398 }
399 
400 Datum
spheretrans_circle_inverse(PG_FUNCTION_ARGS)401 spheretrans_circle_inverse(PG_FUNCTION_ARGS)
402 {
403 	Datum		sc = PG_GETARG_DATUM(0);
404 	SEuler	   *se = (SEuler *) PG_GETARG_POINTER(1);
405 	SEuler		tmp;
406 	Datum		ret;
407 
408 	spheretrans_inverse(&tmp, se);
409 	ret = DirectFunctionCall2(spheretrans_circle,
410 							  sc, PointerGetDatum(&tmp));
411 	PG_RETURN_DATUM(ret);
412 }
413