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