1 /*
2 
3  gg_geometries.c -- Gaia geometric objects
4 
5  version 5.0, 2020 August 1
6 
7  Author: Sandro Furieri a.furieri@lqt.it
8 
9  ------------------------------------------------------------------------------
10 
11  Version: MPL 1.1/GPL 2.0/LGPL 2.1
12 
13  The contents of this file are subject to the Mozilla Public License Version
14  1.1 (the "License"); you may not use this file except in compliance with
15  the License. You may obtain a copy of the License at
16  http://www.mozilla.org/MPL/
17 
18 Software distributed under the License is distributed on an "AS IS" basis,
19 WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
20 for the specific language governing rights and limitations under the
21 License.
22 
23 The Original Code is the SpatiaLite library
24 
25 The Initial Developer of the Original Code is Alessandro Furieri
26 
27 Portions created by the Initial Developer are Copyright (C) 2008-2021
28 the Initial Developer. All Rights Reserved.
29 
30 Contributor(s):
31 
32 Alternatively, the contents of this file may be used under the terms of
33 either the GNU General Public License Version 2 or later (the "GPL"), or
34 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
35 in which case the provisions of the GPL or the LGPL are applicable instead
36 of those above. If you wish to allow use of your version of this file only
37 under the terms of either the GPL or the LGPL, and not to allow others to
38 use your version of this file under the terms of the MPL, indicate your
39 decision by deleting the provisions above and replace them with the notice
40 and other provisions required by the GPL or the LGPL. If you do not delete
41 the provisions above, a recipient may use your version of this file under
42 the terms of any one of the MPL, the GPL or the LGPL.
43 
44 */
45 
46 #include <sys/types.h>
47 #include <stdlib.h>
48 #include <stdio.h>
49 #include <memory.h>
50 #include <math.h>
51 #include <float.h>
52 
53 #if defined(_WIN32) && !defined(__MINGW32__)
54 #include "config-msvc.h"
55 #else
56 #include "config.h"
57 #endif
58 
59 #include <spatialite/sqlite.h>
60 
61 #include <spatialite/gaiageo.h>
62 
63 GAIAGEO_DECLARE gaiaPointPtr
gaiaAllocPoint(double x,double y)64 gaiaAllocPoint (double x, double y)
65 {
66 /* POINT object constructor */
67     gaiaPointPtr p = malloc (sizeof (gaiaPoint));
68     p->X = x;
69     p->Y = y;
70     p->Z = 0.0;
71     p->M = 0.0;
72     p->DimensionModel = GAIA_XY;
73     p->Next = NULL;
74     p->Prev = NULL;
75     return p;
76 }
77 
78 GAIAGEO_DECLARE gaiaPointPtr
gaiaAllocPointXYZ(double x,double y,double z)79 gaiaAllocPointXYZ (double x, double y, double z)
80 {
81 /* POINT object constructor */
82     gaiaPointPtr p = malloc (sizeof (gaiaPoint));
83     p->X = x;
84     p->Y = y;
85     p->Z = z;
86     p->M = 0.0;
87     p->DimensionModel = GAIA_XY_Z;
88     p->Next = NULL;
89     p->Prev = NULL;
90     return p;
91 }
92 
93 GAIAGEO_DECLARE gaiaPointPtr
gaiaAllocPointXYM(double x,double y,double m)94 gaiaAllocPointXYM (double x, double y, double m)
95 {
96 /* POINT object constructor */
97     gaiaPointPtr p = malloc (sizeof (gaiaPoint));
98     p->X = x;
99     p->Y = y;
100     p->Z = 0.0;
101     p->M = m;
102     p->DimensionModel = GAIA_XY_M;
103     p->Next = NULL;
104     p->Prev = NULL;
105     return p;
106 }
107 
108 GAIAGEO_DECLARE gaiaPointPtr
gaiaAllocPointXYZM(double x,double y,double z,double m)109 gaiaAllocPointXYZM (double x, double y, double z, double m)
110 {
111 /* POINT object constructor */
112     gaiaPointPtr p = malloc (sizeof (gaiaPoint));
113     p->X = x;
114     p->Y = y;
115     p->Z = z;
116     p->M = m;
117     p->DimensionModel = GAIA_XY_Z_M;
118     p->Next = NULL;
119     p->Prev = NULL;
120     return p;
121 }
122 
123 GAIAGEO_DECLARE void
gaiaFreePoint(gaiaPointPtr ptr)124 gaiaFreePoint (gaiaPointPtr ptr)
125 {
126 /* POINT object destructor */
127     if (ptr != NULL)
128 	free (ptr);
129 }
130 
131 GAIAGEO_DECLARE gaiaLinestringPtr
gaiaAllocLinestring(int vert)132 gaiaAllocLinestring (int vert)
133 {
134 /* LINESTRING object constructor */
135     gaiaLinestringPtr p = malloc (sizeof (gaiaLinestring));
136     p->Coords = malloc (sizeof (double) * (vert * 2));
137     p->Points = vert;
138     p->MinX = DBL_MAX;
139     p->MinY = DBL_MAX;
140     p->MaxX = -DBL_MAX;
141     p->MaxY = -DBL_MAX;
142     p->DimensionModel = GAIA_XY;
143     p->Next = NULL;
144     return p;
145 }
146 
147 GAIAGEO_DECLARE gaiaLinestringPtr
gaiaAllocLinestringXYZ(int vert)148 gaiaAllocLinestringXYZ (int vert)
149 {
150 /* LINESTRING object constructor */
151     gaiaLinestringPtr p = malloc (sizeof (gaiaLinestring));
152     p->Coords = malloc (sizeof (double) * (vert * 3));
153     p->Points = vert;
154     p->MinX = DBL_MAX;
155     p->MinY = DBL_MAX;
156     p->MaxX = -DBL_MAX;
157     p->MaxY = -DBL_MAX;
158     p->DimensionModel = GAIA_XY_Z;
159     p->Next = NULL;
160     return p;
161 }
162 
163 GAIAGEO_DECLARE gaiaLinestringPtr
gaiaAllocLinestringXYM(int vert)164 gaiaAllocLinestringXYM (int vert)
165 {
166 /* LINESTRING object constructor */
167     gaiaLinestringPtr p = malloc (sizeof (gaiaLinestring));
168     p->Coords = malloc (sizeof (double) * (vert * 3));
169     p->Points = vert;
170     p->MinX = DBL_MAX;
171     p->MinY = DBL_MAX;
172     p->MaxX = -DBL_MAX;
173     p->MaxY = -DBL_MAX;
174     p->DimensionModel = GAIA_XY_M;
175     p->Next = NULL;
176     return p;
177 }
178 
179 GAIAGEO_DECLARE gaiaLinestringPtr
gaiaAllocLinestringXYZM(int vert)180 gaiaAllocLinestringXYZM (int vert)
181 {
182 /* LINESTRING object constructor */
183     gaiaLinestringPtr p = malloc (sizeof (gaiaLinestring));
184     p->Coords = malloc (sizeof (double) * (vert * 4));
185     p->Points = vert;
186     p->MinX = DBL_MAX;
187     p->MinY = DBL_MAX;
188     p->MaxX = -DBL_MAX;
189     p->MaxY = -DBL_MAX;
190     p->DimensionModel = GAIA_XY_Z_M;
191     p->Next = NULL;
192     return p;
193 }
194 
195 GAIAGEO_DECLARE void
gaiaFreeLinestring(gaiaLinestringPtr ptr)196 gaiaFreeLinestring (gaiaLinestringPtr ptr)
197 {
198 /* LINESTRING object desctructror */
199     if (ptr)
200       {
201 	  if (ptr->Coords)
202 	      free (ptr->Coords);
203 	  free (ptr);
204       }
205 }
206 
207 GAIAGEO_DECLARE int
gaiaLineGetPoint(gaiaLinestringPtr ln,int v,double * x,double * y,double * z,double * m)208 gaiaLineGetPoint (gaiaLinestringPtr ln, int v, double *x, double *y, double *z,
209 		  double *m)
210 {
211 /* SAFE - getting coords for a vertex in LINESTRING */
212     double vx;
213     double vy;
214     double vz;
215     double vm;
216     *x = 0.0;
217     *y = 0.0;
218     *z = 0.0;
219     *m = 0.0;
220     if (!ln)
221 	return 0;
222     if (v < 0 || v >= ln->Points)
223 	return 0;
224     switch (ln->DimensionModel)
225       {
226       case GAIA_XY:
227 	  gaiaGetPoint (ln->Coords, v, &vx, &vy);
228 	  *x = vx;
229 	  *y = vy;
230 	  break;
231       case GAIA_XY_Z:
232 	  gaiaGetPointXYZ (ln->Coords, v, &vx, &vy, &vz);
233 	  *x = vx;
234 	  *y = vy;
235 	  *z = vz;
236 	  break;
237       case GAIA_XY_M:
238 	  gaiaGetPointXYM (ln->Coords, v, &vx, &vy, &vm);
239 	  *x = vx;
240 	  *y = vy;
241 	  *m = vm;
242 	  break;
243       case GAIA_XY_Z_M:
244 	  gaiaGetPointXYZM (ln->Coords, v, &vx, &vy, &vz, &vm);
245 	  *x = vx;
246 	  *y = vy;
247 	  *z = vz;
248 	  *m = vm;
249 	  break;
250       default:
251 	  return 0;
252       };
253     return 1;
254 }
255 
256 GAIAGEO_DECLARE int
gaiaLineSetPoint(gaiaLinestringPtr ln,int v,double x,double y,double z,double m)257 gaiaLineSetPoint (gaiaLinestringPtr ln, int v, double x, double y, double z,
258 		  double m)
259 {
260 /* SAFE - setting coords for a vertex in RING */
261     if (!ln)
262 	return 0;
263     if (v < 0 || v >= ln->Points)
264 	return 0;
265     switch (ln->DimensionModel)
266       {
267       case GAIA_XY:
268 	  gaiaSetPoint (ln->Coords, v, x, y);
269 	  break;
270       case GAIA_XY_Z:
271 	  gaiaSetPointXYZ (ln->Coords, v, x, y, z);
272 	  break;
273       case GAIA_XY_M:
274 	  gaiaSetPointXYM (ln->Coords, v, x, y, m);
275 	  break;
276       case GAIA_XY_Z_M:
277 	  gaiaSetPointXYZM (ln->Coords, v, x, y, z, m);
278 	  break;
279       default:
280 	  return 0;
281       };
282     return 1;
283 }
284 
285 GAIAGEO_DECLARE void
gaiaCopyLinestringCoords(gaiaLinestringPtr dst,gaiaLinestringPtr src)286 gaiaCopyLinestringCoords (gaiaLinestringPtr dst, gaiaLinestringPtr src)
287 {
288 /*
289 / copying coords from one Linestring to another
290 / maybe, converting from one Dimension Model to a different one
291 */
292     gaiaCopyLinestringCoordsEx (dst, src, 0.0, 0.0);
293 }
294 
295 GAIAGEO_DECLARE void
gaiaCopyLinestringCoordsEx(gaiaLinestringPtr dst,gaiaLinestringPtr src,double z_no_data,double m_no_data)296 gaiaCopyLinestringCoordsEx (gaiaLinestringPtr dst, gaiaLinestringPtr src,
297 			    double z_no_data, double m_no_data)
298 {
299 /*
300 / copying coords from one Linestring to another
301 / maybe, converting from one Dimension Model to a different one
302 */
303     int iv;
304     double x;
305     double y;
306     double z;
307     double m;
308     if (!src)
309 	return;
310     if (!dst)
311 	return;
312     if (src->Points != dst->Points)
313 	return;
314     for (iv = 0; iv < dst->Points; iv++)
315       {
316 	  z = z_no_data;
317 	  m = m_no_data;
318 	  if (src->DimensionModel == GAIA_XY_Z)
319 	    {
320 		gaiaGetPointXYZ (src->Coords, iv, &x, &y, &z);
321 	    }
322 	  else if (src->DimensionModel == GAIA_XY_M)
323 	    {
324 		gaiaGetPointXYM (src->Coords, iv, &x, &y, &m);
325 	    }
326 	  else if (src->DimensionModel == GAIA_XY_Z_M)
327 	    {
328 		gaiaGetPointXYZM (src->Coords, iv, &x, &y, &z, &m);
329 	    }
330 	  else
331 	    {
332 		gaiaGetPoint (src->Coords, iv, &x, &y);
333 	    }
334 	  if (dst->DimensionModel == GAIA_XY_Z)
335 	    {
336 		gaiaSetPointXYZ (dst->Coords, iv, x, y, z);
337 	    }
338 	  else if (dst->DimensionModel == GAIA_XY_M)
339 	    {
340 		gaiaSetPointXYM (dst->Coords, iv, x, y, m);
341 	    }
342 	  else if (dst->DimensionModel == GAIA_XY_Z_M)
343 	    {
344 		gaiaSetPointXYZM (dst->Coords, iv, x, y, z, m);
345 	    }
346 	  else
347 	    {
348 		gaiaSetPoint (dst->Coords, iv, x, y);
349 	    }
350       }
351 }
352 
353 GAIAGEO_DECLARE gaiaLinestringPtr
gaiaCloneLinestring(gaiaLinestringPtr line)354 gaiaCloneLinestring (gaiaLinestringPtr line)
355 {
356 /* clones a LINESTRING */
357     gaiaLinestringPtr new_line;
358     if (!line)
359 	return NULL;
360     if (line->DimensionModel == GAIA_XY_Z)
361 	new_line = gaiaAllocLinestringXYZ (line->Points);
362     else if (line->DimensionModel == GAIA_XY_M)
363 	new_line = gaiaAllocLinestringXYM (line->Points);
364     else if (line->DimensionModel == GAIA_XY_Z_M)
365 	new_line = gaiaAllocLinestringXYZM (line->Points);
366     else
367 	new_line = gaiaAllocLinestring (line->Points);
368     gaiaCopyLinestringCoords (new_line, line);
369     return new_line;
370 }
371 
372 GAIAGEO_DECLARE void
gaiaCopyLinestringCoordsReverse(gaiaLinestringPtr dst,gaiaLinestringPtr src)373 gaiaCopyLinestringCoordsReverse (gaiaLinestringPtr dst, gaiaLinestringPtr src)
374 {
375 /*
376 / copying coords from one Linestring to another in reverse order
377 / maybe, converting from one Dimension Model to a different one
378 */
379     int iv;
380     int iv2 = 0;
381     double x;
382     double y;
383     double z;
384     double m;
385     if (!src)
386 	return;
387     if (!dst)
388 	return;
389     if (src->Points != dst->Points)
390 	return;
391     for (iv = src->Points - 1; iv >= 0; iv--)
392       {
393 	  z = 0.0;
394 	  m = 0.0;
395 	  if (src->DimensionModel == GAIA_XY_Z)
396 	    {
397 		gaiaGetPointXYZ (src->Coords, iv, &x, &y, &z);
398 	    }
399 	  else if (src->DimensionModel == GAIA_XY_M)
400 	    {
401 		gaiaGetPointXYM (src->Coords, iv, &x, &y, &m);
402 	    }
403 	  else if (src->DimensionModel == GAIA_XY_Z_M)
404 	    {
405 		gaiaGetPointXYZM (src->Coords, iv, &x, &y, &z, &m);
406 	    }
407 	  else
408 	    {
409 		gaiaGetPoint (src->Coords, iv, &x, &y);
410 	    }
411 	  if (dst->DimensionModel == GAIA_XY_Z)
412 	    {
413 		gaiaSetPointXYZ (dst->Coords, iv2, x, y, z);
414 	    }
415 	  else if (dst->DimensionModel == GAIA_XY_M)
416 	    {
417 		gaiaSetPointXYM (dst->Coords, iv2, x, y, m);
418 	    }
419 	  else if (dst->DimensionModel == GAIA_XY_Z_M)
420 	    {
421 		gaiaSetPointXYZM (dst->Coords, iv2, x, y, z, m);
422 	    }
423 	  else
424 	    {
425 		gaiaSetPoint (dst->Coords, iv2, x, y);
426 	    }
427 	  iv2++;
428       }
429 }
430 
431 GAIAGEO_DECLARE gaiaLinestringPtr
gaiaCloneLinestringSpecial(gaiaLinestringPtr line,int mode)432 gaiaCloneLinestringSpecial (gaiaLinestringPtr line, int mode)
433 {
434 /* clones a LINESTRING (special) */
435     gaiaLinestringPtr new_line;
436     if (!line)
437 	return NULL;
438     if (mode != GAIA_REVERSE_ORDER)
439 	return gaiaCloneLinestring (line);
440 
441     if (line->DimensionModel == GAIA_XY_Z)
442 	new_line = gaiaAllocLinestringXYZ (line->Points);
443     else if (line->DimensionModel == GAIA_XY_M)
444 	new_line = gaiaAllocLinestringXYM (line->Points);
445     else if (line->DimensionModel == GAIA_XY_Z_M)
446 	new_line = gaiaAllocLinestringXYZM (line->Points);
447     else
448 	new_line = gaiaAllocLinestring (line->Points);
449     gaiaCopyLinestringCoordsReverse (new_line, line);
450     return new_line;
451 }
452 
453 GAIAGEO_DECLARE gaiaRingPtr
gaiaAllocRing(int vert)454 gaiaAllocRing (int vert)
455 {
456 /* ring object constructor */
457     gaiaRingPtr p = malloc (sizeof (gaiaRing));
458     p->Coords = malloc (sizeof (double) * (vert * 2));
459     p->Points = vert;
460     p->Link = NULL;
461     p->Clockwise = 0;
462     p->MinX = DBL_MAX;
463     p->MinY = DBL_MAX;
464     p->MaxX = -DBL_MAX;
465     p->MaxY = -DBL_MAX;
466     p->DimensionModel = GAIA_XY;
467     p->Next = NULL;
468     return p;
469 }
470 
471 GAIAGEO_DECLARE gaiaRingPtr
gaiaAllocRingXYZ(int vert)472 gaiaAllocRingXYZ (int vert)
473 {
474 /* ring object constructor */
475     gaiaRingPtr p = malloc (sizeof (gaiaRing));
476     p->Coords = malloc (sizeof (double) * (vert * 3));
477     p->Points = vert;
478     p->Link = NULL;
479     p->Clockwise = 0;
480     p->MinX = DBL_MAX;
481     p->MinY = DBL_MAX;
482     p->MaxX = -DBL_MAX;
483     p->MaxY = -DBL_MAX;
484     p->DimensionModel = GAIA_XY_Z;
485     p->Next = NULL;
486     return p;
487 }
488 
489 GAIAGEO_DECLARE gaiaRingPtr
gaiaAllocRingXYM(int vert)490 gaiaAllocRingXYM (int vert)
491 {
492 /* ring object constructor */
493     gaiaRingPtr p = malloc (sizeof (gaiaRing));
494     p->Coords = malloc (sizeof (double) * (vert * 3));
495     p->Points = vert;
496     p->Link = NULL;
497     p->Clockwise = 0;
498     p->MinX = DBL_MAX;
499     p->MinY = DBL_MAX;
500     p->MaxX = -DBL_MAX;
501     p->MaxY = -DBL_MAX;
502     p->DimensionModel = GAIA_XY_M;
503     p->Next = NULL;
504     return p;
505 }
506 
507 GAIAGEO_DECLARE gaiaRingPtr
gaiaAllocRingXYZM(int vert)508 gaiaAllocRingXYZM (int vert)
509 {
510 /* ring object constructor */
511     gaiaRingPtr p = malloc (sizeof (gaiaRing));
512     p->Coords = malloc (sizeof (double) * (vert * 4));
513     p->Points = vert;
514     p->Link = NULL;
515     p->Clockwise = 0;
516     p->MinX = DBL_MAX;
517     p->MinY = DBL_MAX;
518     p->MaxX = -DBL_MAX;
519     p->MaxY = -DBL_MAX;
520     p->DimensionModel = GAIA_XY_Z_M;
521     p->Next = NULL;
522     return p;
523 }
524 
525 GAIAGEO_DECLARE void
gaiaFreeRing(gaiaRingPtr ptr)526 gaiaFreeRing (gaiaRingPtr ptr)
527 {
528 /* ring object destructor */
529     if (ptr)
530       {
531 	  if (ptr->Coords)
532 	      free (ptr->Coords);
533 	  free (ptr);
534       }
535 }
536 
537 GAIAGEO_DECLARE int
gaiaRingGetPoint(gaiaRingPtr rng,int v,double * x,double * y,double * z,double * m)538 gaiaRingGetPoint (gaiaRingPtr rng, int v, double *x, double *y, double *z,
539 		  double *m)
540 {
541 /* SAFE - getting coords for a vertex in RING */
542     double vx;
543     double vy;
544     double vz;
545     double vm;
546     *x = 0.0;
547     *y = 0.0;
548     *z = 0.0;
549     *m = 0.0;
550     if (!rng)
551 	return 0;
552     if (v < 0 || v >= rng->Points)
553 	return 0;
554     switch (rng->DimensionModel)
555       {
556       case GAIA_XY:
557 	  gaiaGetPoint (rng->Coords, v, &vx, &vy);
558 	  *x = vx;
559 	  *y = vy;
560 	  break;
561       case GAIA_XY_Z:
562 	  gaiaGetPointXYZ (rng->Coords, v, &vx, &vy, &vz);
563 	  *x = vx;
564 	  *y = vy;
565 	  *z = vz;
566 	  break;
567       case GAIA_XY_M:
568 	  gaiaGetPointXYM (rng->Coords, v, &vx, &vy, &vm);
569 	  *x = vx;
570 	  *y = vy;
571 	  *m = vm;
572 	  break;
573       case GAIA_XY_Z_M:
574 	  gaiaGetPointXYZM (rng->Coords, v, &vx, &vy, &vz, &vm);
575 	  *x = vx;
576 	  *y = vy;
577 	  *z = vz;
578 	  *m = vm;
579 	  break;
580       default:
581 	  return 0;
582       };
583     return 1;
584 }
585 
586 GAIAGEO_DECLARE int
gaiaRingSetPoint(gaiaRingPtr rng,int v,double x,double y,double z,double m)587 gaiaRingSetPoint (gaiaRingPtr rng, int v, double x, double y, double z,
588 		  double m)
589 {
590 /* SAFE - getting coords for a vertex in RING */
591     if (!rng)
592 	return 0;
593     if (v < 0 || v >= rng->Points)
594 	return 0;
595     switch (rng->DimensionModel)
596       {
597       case GAIA_XY:
598 	  gaiaSetPoint (rng->Coords, v, x, y);
599 	  break;
600       case GAIA_XY_Z:
601 	  gaiaSetPointXYZ (rng->Coords, v, x, y, z);
602 	  break;
603       case GAIA_XY_M:
604 	  gaiaSetPointXYM (rng->Coords, v, x, y, m);
605 	  break;
606       case GAIA_XY_Z_M:
607 	  gaiaSetPointXYZM (rng->Coords, v, x, y, z, m);
608 	  break;
609       default:
610 	  return 0;
611       };
612     return 1;
613 }
614 
615 GAIAGEO_DECLARE void
gaiaCopyRingCoords(gaiaRingPtr dst,gaiaRingPtr src)616 gaiaCopyRingCoords (gaiaRingPtr dst, gaiaRingPtr src)
617 {
618 /*
619 / copying coords from one Ring to another
620 / maybe, converting from one Dimension Model to a different one
621 */
622     gaiaCopyRingCoordsEx (dst, src, 0.0, 0.0);
623 }
624 
625 GAIAGEO_DECLARE void
gaiaCopyRingCoordsEx(gaiaRingPtr dst,gaiaRingPtr src,double z_no_data,double m_no_data)626 gaiaCopyRingCoordsEx (gaiaRingPtr dst, gaiaRingPtr src, double z_no_data,
627 		      double m_no_data)
628 {
629 /*
630 / copying coords from one Ring to another
631 / maybe, converting from one Dimension Model to a different one
632 */
633     int iv;
634     double x;
635     double y;
636     double z;
637     double m;
638     if (!src)
639 	return;
640     if (!dst)
641 	return;
642     if (src->Points != dst->Points)
643 	return;
644     for (iv = 0; iv < dst->Points; iv++)
645       {
646 	  z = z_no_data;
647 	  m = m_no_data;
648 	  if (src->DimensionModel == GAIA_XY_Z)
649 	    {
650 		gaiaGetPointXYZ (src->Coords, iv, &x, &y, &z);
651 	    }
652 	  else if (src->DimensionModel == GAIA_XY_M)
653 	    {
654 		gaiaGetPointXYM (src->Coords, iv, &x, &y, &m);
655 	    }
656 	  else if (src->DimensionModel == GAIA_XY_Z_M)
657 	    {
658 		gaiaGetPointXYZM (src->Coords, iv, &x, &y, &z, &m);
659 	    }
660 	  else
661 	    {
662 		gaiaGetPoint (src->Coords, iv, &x, &y);
663 	    }
664 	  if (dst->DimensionModel == GAIA_XY_Z)
665 	    {
666 		gaiaSetPointXYZ (dst->Coords, iv, x, y, z);
667 	    }
668 	  else if (dst->DimensionModel == GAIA_XY_M)
669 	    {
670 		gaiaSetPointXYM (dst->Coords, iv, x, y, m);
671 	    }
672 	  else if (dst->DimensionModel == GAIA_XY_Z_M)
673 	    {
674 		gaiaSetPointXYZM (dst->Coords, iv, x, y, z, m);
675 	    }
676 	  else
677 	    {
678 		gaiaSetPoint (dst->Coords, iv, x, y);
679 	    }
680       }
681 }
682 
683 GAIAGEO_DECLARE gaiaRingPtr
gaiaCloneRing(gaiaRingPtr ring)684 gaiaCloneRing (gaiaRingPtr ring)
685 {
686 /* clones a RING */
687     gaiaRingPtr new_ring;
688     if (!ring)
689 	return NULL;
690     if (ring->DimensionModel == GAIA_XY_Z)
691 	new_ring = gaiaAllocRingXYZ (ring->Points);
692     else if (ring->DimensionModel == GAIA_XY_M)
693 	new_ring = gaiaAllocRingXYM (ring->Points);
694     else if (ring->DimensionModel == GAIA_XY_Z_M)
695 	new_ring = gaiaAllocRingXYZM (ring->Points);
696     else
697 	new_ring = gaiaAllocRing (ring->Points);
698     gaiaCopyRingCoords (new_ring, ring);
699     return new_ring;
700 }
701 
702 GAIAGEO_DECLARE void
gaiaCopyRingCoordsReverse(gaiaRingPtr dst,gaiaRingPtr src)703 gaiaCopyRingCoordsReverse (gaiaRingPtr dst, gaiaRingPtr src)
704 {
705 /*
706 / copying coords from one Ring to another in reverse order
707 / maybe, converting from one Dimension Model to a different one
708 */
709     int iv;
710     int iv2 = 0;
711     double x;
712     double y;
713     double z;
714     double m;
715     if (!src)
716 	return;
717     if (!dst)
718 	return;
719     if (src->Points != dst->Points)
720 	return;
721     for (iv = src->Points - 1; iv >= 0; iv--)
722       {
723 	  z = 0.0;
724 	  m = 0.0;
725 	  if (src->DimensionModel == GAIA_XY_Z)
726 	    {
727 		gaiaGetPointXYZ (src->Coords, iv, &x, &y, &z);
728 	    }
729 	  else if (src->DimensionModel == GAIA_XY_M)
730 	    {
731 		gaiaGetPointXYM (src->Coords, iv, &x, &y, &m);
732 	    }
733 	  else if (src->DimensionModel == GAIA_XY_Z_M)
734 	    {
735 		gaiaGetPointXYZM (src->Coords, iv, &x, &y, &z, &m);
736 	    }
737 	  else
738 	    {
739 		gaiaGetPoint (src->Coords, iv, &x, &y);
740 	    }
741 	  if (dst->DimensionModel == GAIA_XY_Z)
742 	    {
743 		gaiaSetPointXYZ (dst->Coords, iv2, x, y, z);
744 	    }
745 	  else if (dst->DimensionModel == GAIA_XY_M)
746 	    {
747 		gaiaSetPointXYM (dst->Coords, iv2, x, y, m);
748 	    }
749 	  else if (dst->DimensionModel == GAIA_XY_Z_M)
750 	    {
751 		gaiaSetPointXYZM (dst->Coords, iv2, x, y, z, m);
752 	    }
753 	  else
754 	    {
755 		gaiaSetPoint (dst->Coords, iv2, x, y);
756 	    }
757 	  iv2++;
758       }
759 }
760 
761 GAIAGEO_DECLARE gaiaRingPtr
gaiaCloneRingSpecial(gaiaRingPtr ring,int mode)762 gaiaCloneRingSpecial (gaiaRingPtr ring, int mode)
763 {
764 /* clones a RING (special) */
765     gaiaRingPtr new_ring;
766     if (!ring)
767 	return NULL;
768     if (mode != GAIA_REVERSE_ORDER)
769 	return gaiaCloneRing (ring);
770 
771     if (ring->DimensionModel == GAIA_XY_Z)
772 	new_ring = gaiaAllocRingXYZ (ring->Points);
773     else if (ring->DimensionModel == GAIA_XY_M)
774 	new_ring = gaiaAllocRingXYM (ring->Points);
775     else if (ring->DimensionModel == GAIA_XY_Z_M)
776 	new_ring = gaiaAllocRingXYZM (ring->Points);
777     else
778 	new_ring = gaiaAllocRing (ring->Points);
779     gaiaCopyRingCoordsReverse (new_ring, ring);
780     return new_ring;
781 }
782 
783 GAIAGEO_DECLARE gaiaPolygonPtr
gaiaClonePolygon(gaiaPolygonPtr polyg)784 gaiaClonePolygon (gaiaPolygonPtr polyg)
785 {
786 /* clones a POLYGON */
787     int ib;
788     gaiaPolygonPtr new_polyg;
789     gaiaRingPtr i_ring;
790     gaiaRingPtr o_ring;
791     if (!polyg)
792 	return NULL;
793     i_ring = polyg->Exterior;
794     if (polyg->DimensionModel == GAIA_XY_Z)
795 	new_polyg = gaiaAllocPolygonXYZ (i_ring->Points, polyg->NumInteriors);
796     else if (polyg->DimensionModel == GAIA_XY_M)
797 	new_polyg = gaiaAllocPolygonXYM (i_ring->Points, polyg->NumInteriors);
798     else if (polyg->DimensionModel == GAIA_XY_Z_M)
799 	new_polyg = gaiaAllocPolygonXYZM (i_ring->Points, polyg->NumInteriors);
800     else
801 	new_polyg = gaiaAllocPolygon (i_ring->Points, polyg->NumInteriors);
802     o_ring = new_polyg->Exterior;
803 /* copying points for the EXTERIOR RING */
804     gaiaCopyRingCoords (o_ring, i_ring);
805     for (ib = 0; ib < new_polyg->NumInteriors; ib++)
806       {
807 	  /* copying each INTERIOR RING [if any] */
808 	  i_ring = polyg->Interiors + ib;
809 	  o_ring = gaiaAddInteriorRing (new_polyg, ib, i_ring->Points);
810 	  gaiaCopyRingCoords (o_ring, i_ring);
811       }
812     return new_polyg;
813 }
814 
815 GAIAGEO_DECLARE gaiaPolygonPtr
gaiaClonePolygonSpecial(gaiaPolygonPtr polyg,int mode)816 gaiaClonePolygonSpecial (gaiaPolygonPtr polyg, int mode)
817 {
818 /* clones a POLYGON (special) */
819     int ib;
820     gaiaPolygonPtr new_polyg;
821     gaiaRingPtr i_ring;
822     gaiaRingPtr o_ring;
823     if (!polyg)
824 	return NULL;
825     if (mode == GAIA_REVERSE_ORDER || mode == GAIA_CW_ORDER
826 	|| mode == GAIA_CCW_ORDER)
827 	;
828     else
829 	return gaiaClonePolygon (polyg);
830 
831     i_ring = polyg->Exterior;
832     if (polyg->DimensionModel == GAIA_XY_Z)
833 	new_polyg = gaiaAllocPolygonXYZ (i_ring->Points, polyg->NumInteriors);
834     else if (polyg->DimensionModel == GAIA_XY_M)
835 	new_polyg = gaiaAllocPolygonXYM (i_ring->Points, polyg->NumInteriors);
836     else if (polyg->DimensionModel == GAIA_XY_Z_M)
837 	new_polyg = gaiaAllocPolygonXYZM (i_ring->Points, polyg->NumInteriors);
838     else
839 	new_polyg = gaiaAllocPolygon (i_ring->Points, polyg->NumInteriors);
840     o_ring = new_polyg->Exterior;
841 /* copying points for the EXTERIOR RING */
842     if (mode == GAIA_REVERSE_ORDER)
843 	gaiaCopyRingCoordsReverse (o_ring, i_ring);
844     else
845       {
846 	  gaiaClockwise (i_ring);
847 	  if (mode == GAIA_CCW_ORDER)
848 	    {
849 		/* returning a Counter-Clockwise Polygon */
850 		if (i_ring->Clockwise)
851 		    gaiaCopyRingCoordsReverse (o_ring, i_ring);
852 		else
853 		    gaiaCopyRingCoords (o_ring, i_ring);
854 	    }
855 	  else
856 	    {
857 		/* returning a Clockwise Polygon */
858 		if (i_ring->Clockwise)
859 		    gaiaCopyRingCoords (o_ring, i_ring);
860 		else
861 		    gaiaCopyRingCoordsReverse (o_ring, i_ring);
862 	    }
863       }
864     for (ib = 0; ib < new_polyg->NumInteriors; ib++)
865       {
866 	  /* copying each INTERIOR RING [if any] */
867 	  i_ring = polyg->Interiors + ib;
868 	  o_ring = gaiaAddInteriorRing (new_polyg, ib, i_ring->Points);
869 	  if (mode == GAIA_REVERSE_ORDER)
870 	      gaiaCopyRingCoordsReverse (o_ring, i_ring);
871 	  else
872 	    {
873 		if (mode == GAIA_CCW_ORDER)
874 		  {
875 		      /* returning a Counter-Clockwise Polygon */
876 		      if (i_ring->Clockwise)
877 			  gaiaCopyRingCoords (o_ring, i_ring);
878 		      else
879 			  gaiaCopyRingCoordsReverse (o_ring, i_ring);
880 		  }
881 		else
882 		  {
883 		      /* returning a Clockwise Polygon */
884 		      gaiaClockwise (i_ring);
885 		      if (i_ring->Clockwise)
886 			  gaiaCopyRingCoordsReverse (o_ring, i_ring);
887 		      else
888 			  gaiaCopyRingCoords (o_ring, i_ring);
889 		  }
890 	    }
891       }
892     return new_polyg;
893 }
894 
895 GAIAGEO_DECLARE int
gaiaCheckClockwise(gaiaGeomCollPtr geom)896 gaiaCheckClockwise (gaiaGeomCollPtr geom)
897 {
898 /* checking for a Clockwise Geometry */
899     int retval = 1;
900     gaiaPolygonPtr polyg;
901     int ib;
902     gaiaRingPtr i_ring;
903     if (!geom)
904 	return 1;
905 
906     polyg = geom->FirstPolygon;
907     while (polyg != NULL)
908       {
909 	  i_ring = polyg->Exterior;
910 	  gaiaClockwise (i_ring);
911 	  if (i_ring->Clockwise == 0)
912 	      retval = 0;
913 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
914 	    {
915 		/* checking each INTERIOR RING [if any] */
916 		i_ring = polyg->Interiors + ib;
917 		gaiaClockwise (i_ring);
918 		if (i_ring->Clockwise)
919 		    retval = 0;
920 	    }
921 	  polyg = polyg->Next;
922       }
923     return retval;
924 }
925 
926 GAIAGEO_DECLARE int
gaiaCheckCounterClockwise(gaiaGeomCollPtr geom)927 gaiaCheckCounterClockwise (gaiaGeomCollPtr geom)
928 {
929 /* checking for a CounterClockwise Geometry */
930     int retval = 1;
931     gaiaPolygonPtr polyg;
932     int ib;
933     gaiaRingPtr i_ring;
934     if (!geom)
935 	return 1;
936 
937     polyg = geom->FirstPolygon;
938     while (polyg != NULL)
939       {
940 	  i_ring = polyg->Exterior;
941 	  gaiaClockwise (i_ring);
942 	  if (i_ring->Clockwise)
943 	      retval = 0;
944 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
945 	    {
946 		/* checking each INTERIOR RING [if any] */
947 		i_ring = polyg->Interiors + ib;
948 		gaiaClockwise (i_ring);
949 		if (i_ring->Clockwise == 0)
950 		    retval = 0;
951 	    }
952 	  polyg = polyg->Next;
953       }
954     return retval;
955 }
956 
957 GAIAGEO_DECLARE gaiaPolygonPtr
gaiaAllocPolygon(int vert,int excl)958 gaiaAllocPolygon (int vert, int excl)
959 {
960 /* POLYGON object constructor */
961     gaiaPolygonPtr p;
962     gaiaRingPtr pP;
963     int ind;
964     p = malloc (sizeof (gaiaPolygon));
965     p->Exterior = gaiaAllocRing (vert);
966     p->NumInteriors = excl;
967     p->NextInterior = 0;
968     p->Next = NULL;
969     if (excl == 0)
970 	p->Interiors = NULL;
971     else
972 	p->Interiors = malloc (sizeof (gaiaRing) * excl);
973     for (ind = 0; ind < p->NumInteriors; ind++)
974       {
975 	  pP = p->Interiors + ind;
976 	  pP->Points = 0;
977 	  pP->Coords = NULL;
978 	  pP->Next = NULL;
979 	  pP->Link = 0;
980       }
981     p->MinX = DBL_MAX;
982     p->MinY = DBL_MAX;
983     p->MaxX = -DBL_MAX;
984     p->MaxY = -DBL_MAX;
985     p->DimensionModel = GAIA_XY;
986     return p;
987 }
988 
989 GAIAGEO_DECLARE gaiaPolygonPtr
gaiaAllocPolygonXYZ(int vert,int excl)990 gaiaAllocPolygonXYZ (int vert, int excl)
991 {
992 /* POLYGON object constructor */
993     gaiaPolygonPtr p;
994     gaiaRingPtr pP;
995     int ind;
996     p = malloc (sizeof (gaiaPolygon));
997     p->Exterior = gaiaAllocRingXYZ (vert);
998     p->NumInteriors = excl;
999     p->NextInterior = 0;
1000     p->Next = NULL;
1001     if (excl == 0)
1002 	p->Interiors = NULL;
1003     else
1004 	p->Interiors = malloc (sizeof (gaiaRing) * excl);
1005     for (ind = 0; ind < p->NumInteriors; ind++)
1006       {
1007 	  pP = p->Interiors + ind;
1008 	  pP->Points = 0;
1009 	  pP->Coords = NULL;
1010 	  pP->Next = NULL;
1011 	  pP->Link = 0;
1012       }
1013     p->MinX = DBL_MAX;
1014     p->MinY = DBL_MAX;
1015     p->MaxX = -DBL_MAX;
1016     p->MaxY = -DBL_MAX;
1017     p->DimensionModel = GAIA_XY_Z;
1018     return p;
1019 }
1020 
1021 GAIAGEO_DECLARE gaiaPolygonPtr
gaiaAllocPolygonXYM(int vert,int excl)1022 gaiaAllocPolygonXYM (int vert, int excl)
1023 {
1024 /* POLYGON object constructor */
1025     gaiaPolygonPtr p;
1026     gaiaRingPtr pP;
1027     int ind;
1028     p = malloc (sizeof (gaiaPolygon));
1029     p->Exterior = gaiaAllocRingXYM (vert);
1030     p->NumInteriors = excl;
1031     p->NextInterior = 0;
1032     p->Next = NULL;
1033     if (excl == 0)
1034 	p->Interiors = NULL;
1035     else
1036 	p->Interiors = malloc (sizeof (gaiaRing) * excl);
1037     for (ind = 0; ind < p->NumInteriors; ind++)
1038       {
1039 	  pP = p->Interiors + ind;
1040 	  pP->Points = 0;
1041 	  pP->Coords = NULL;
1042 	  pP->Next = NULL;
1043 	  pP->Link = 0;
1044       }
1045     p->MinX = DBL_MAX;
1046     p->MinY = DBL_MAX;
1047     p->MaxX = -DBL_MAX;
1048     p->MaxY = -DBL_MAX;
1049     p->DimensionModel = GAIA_XY_M;
1050     return p;
1051 }
1052 
1053 GAIAGEO_DECLARE gaiaPolygonPtr
gaiaAllocPolygonXYZM(int vert,int excl)1054 gaiaAllocPolygonXYZM (int vert, int excl)
1055 {
1056 /* POLYGON object constructor */
1057     gaiaPolygonPtr p;
1058     gaiaRingPtr pP;
1059     int ind;
1060     p = malloc (sizeof (gaiaPolygon));
1061     p->Exterior = gaiaAllocRingXYZM (vert);
1062     p->NumInteriors = excl;
1063     p->NextInterior = 0;
1064     p->Next = NULL;
1065     if (excl == 0)
1066 	p->Interiors = NULL;
1067     else
1068 	p->Interiors = malloc (sizeof (gaiaRing) * excl);
1069     for (ind = 0; ind < p->NumInteriors; ind++)
1070       {
1071 	  pP = p->Interiors + ind;
1072 	  pP->Points = 0;
1073 	  pP->Coords = NULL;
1074 	  pP->Next = NULL;
1075 	  pP->Link = 0;
1076       }
1077     p->MinX = DBL_MAX;
1078     p->MinY = DBL_MAX;
1079     p->MaxX = -DBL_MAX;
1080     p->MaxY = -DBL_MAX;
1081     p->DimensionModel = GAIA_XY_Z_M;
1082     return p;
1083 }
1084 
1085 GAIAGEO_DECLARE gaiaPolygonPtr
gaiaCreatePolygon(gaiaRingPtr ring)1086 gaiaCreatePolygon (gaiaRingPtr ring)
1087 {
1088 /* POLYGON object constructor */
1089     gaiaPolygonPtr p;
1090     p = malloc (sizeof (gaiaPolygon));
1091     p->DimensionModel = ring->DimensionModel;
1092     if (ring->DimensionModel == GAIA_XY_Z)
1093 	p->Exterior = gaiaAllocRingXYZ (ring->Points);
1094     else if (ring->DimensionModel == GAIA_XY_M)
1095 	p->Exterior = gaiaAllocRingXYM (ring->Points);
1096     else if (ring->DimensionModel == GAIA_XY_Z_M)
1097 	p->Exterior = gaiaAllocRingXYZM (ring->Points);
1098     else
1099 	p->Exterior = gaiaAllocRing (ring->Points);
1100     p->NumInteriors = 0;
1101     p->NextInterior = 0;
1102     p->Next = NULL;
1103     p->Interiors = NULL;
1104     gaiaCopyRingCoords (p->Exterior, ring);
1105     p->MinX = DBL_MAX;
1106     p->MinY = DBL_MAX;
1107     p->MaxX = -DBL_MAX;
1108     p->MaxY = -DBL_MAX;
1109     return p;
1110 }
1111 
1112 GAIAGEO_DECLARE void
gaiaFreePolygon(gaiaPolygonPtr p)1113 gaiaFreePolygon (gaiaPolygonPtr p)
1114 {
1115 /* POLYGON object destructor */
1116     gaiaRingPtr pP;
1117     int ind;
1118     if (p->Exterior)
1119 	gaiaFreeRing (p->Exterior);
1120     for (ind = 0; ind < p->NumInteriors; ind++)
1121       {
1122 	  pP = p->Interiors + ind;
1123 	  if (pP->Coords)
1124 	      free (pP->Coords);
1125       }
1126     if (p->Interiors)
1127 	free (p->Interiors);
1128     free (p);
1129 }
1130 
1131 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCloneGeomColl(gaiaGeomCollPtr geom)1132 gaiaCloneGeomColl (gaiaGeomCollPtr geom)
1133 {
1134 /* clones a GEOMETRYCOLLECTION */
1135     int ib;
1136     gaiaPointPtr point;
1137     gaiaLinestringPtr line;
1138     gaiaLinestringPtr new_line;
1139     gaiaPolygonPtr polyg;
1140     gaiaPolygonPtr new_polyg;
1141     gaiaGeomCollPtr new_geom;
1142     gaiaRingPtr i_ring;
1143     gaiaRingPtr o_ring;
1144     if (!geom)
1145 	return NULL;
1146     if (geom->DimensionModel == GAIA_XY_Z)
1147 	new_geom = gaiaAllocGeomCollXYZ ();
1148     else if (geom->DimensionModel == GAIA_XY_M)
1149 	new_geom = gaiaAllocGeomCollXYM ();
1150     else if (geom->DimensionModel == GAIA_XY_Z_M)
1151 	new_geom = gaiaAllocGeomCollXYZM ();
1152     else
1153 	new_geom = gaiaAllocGeomColl ();
1154     new_geom->Srid = geom->Srid;
1155     new_geom->DeclaredType = geom->DeclaredType;
1156     point = geom->FirstPoint;
1157     while (point)
1158       {
1159 	  /* copying POINTs */
1160 	  if (geom->DimensionModel == GAIA_XY_Z)
1161 	      gaiaAddPointToGeomCollXYZ (new_geom, point->X, point->Y,
1162 					 point->Z);
1163 	  else if (geom->DimensionModel == GAIA_XY_M)
1164 	      gaiaAddPointToGeomCollXYM (new_geom, point->X, point->Y,
1165 					 point->M);
1166 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
1167 	      gaiaAddPointToGeomCollXYZM (new_geom, point->X, point->Y,
1168 					  point->Z, point->M);
1169 	  else
1170 	      gaiaAddPointToGeomColl (new_geom, point->X, point->Y);
1171 	  point = point->Next;
1172       }
1173     line = geom->FirstLinestring;
1174     while (line)
1175       {
1176 	  /* copying LINESTRINGs */
1177 	  new_line = gaiaAddLinestringToGeomColl (new_geom, line->Points);
1178 	  gaiaCopyLinestringCoords (new_line, line);
1179 	  line = line->Next;
1180       }
1181     polyg = geom->FirstPolygon;
1182     while (polyg)
1183       {
1184 	  /* copying POLYGONs */
1185 	  i_ring = polyg->Exterior;
1186 	  new_polyg =
1187 	      gaiaAddPolygonToGeomColl (new_geom, i_ring->Points,
1188 					polyg->NumInteriors);
1189 	  o_ring = new_polyg->Exterior;
1190 	  /* copying points for the EXTERIOR RING */
1191 	  gaiaCopyRingCoords (o_ring, i_ring);
1192 	  for (ib = 0; ib < new_polyg->NumInteriors; ib++)
1193 	    {
1194 		/* copying each INTERIOR RING [if any] */
1195 		i_ring = polyg->Interiors + ib;
1196 		o_ring = gaiaAddInteriorRing (new_polyg, ib, i_ring->Points);
1197 		gaiaCopyRingCoords (o_ring, i_ring);
1198 	    }
1199 	  polyg = polyg->Next;
1200       }
1201     return new_geom;
1202 }
1203 
1204 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCloneGeomCollSpecial(gaiaGeomCollPtr geom,int mode)1205 gaiaCloneGeomCollSpecial (gaiaGeomCollPtr geom, int mode)
1206 {
1207 /* clones a GEOMETRYCOLLECTION (special) */
1208     int ib;
1209     gaiaPointPtr point;
1210     gaiaLinestringPtr line;
1211     gaiaLinestringPtr new_line;
1212     gaiaPolygonPtr polyg;
1213     gaiaPolygonPtr new_polyg;
1214     gaiaGeomCollPtr new_geom;
1215     gaiaRingPtr i_ring;
1216     gaiaRingPtr o_ring;
1217     if (!geom)
1218 	return NULL;
1219     if (mode == GAIA_REVERSE_ORDER || mode == GAIA_CW_ORDER
1220 	|| mode == GAIA_CCW_ORDER)
1221 	;
1222     else
1223 	return gaiaCloneGeomColl (geom);
1224 
1225     if (geom->DimensionModel == GAIA_XY_Z)
1226 	new_geom = gaiaAllocGeomCollXYZ ();
1227     else if (geom->DimensionModel == GAIA_XY_M)
1228 	new_geom = gaiaAllocGeomCollXYM ();
1229     else if (geom->DimensionModel == GAIA_XY_Z_M)
1230 	new_geom = gaiaAllocGeomCollXYZM ();
1231     else
1232 	new_geom = gaiaAllocGeomColl ();
1233     new_geom->Srid = geom->Srid;
1234     new_geom->DeclaredType = geom->DeclaredType;
1235     point = geom->FirstPoint;
1236     while (point)
1237       {
1238 	  /* copying POINTs */
1239 	  if (geom->DimensionModel == GAIA_XY_Z)
1240 	      gaiaAddPointToGeomCollXYZ (new_geom, point->X, point->Y,
1241 					 point->Z);
1242 	  else if (geom->DimensionModel == GAIA_XY_M)
1243 	      gaiaAddPointToGeomCollXYM (new_geom, point->X, point->Y,
1244 					 point->M);
1245 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
1246 	      gaiaAddPointToGeomCollXYZM (new_geom, point->X, point->Y,
1247 					  point->Z, point->M);
1248 	  else
1249 	      gaiaAddPointToGeomColl (new_geom, point->X, point->Y);
1250 	  point = point->Next;
1251       }
1252     line = geom->FirstLinestring;
1253     while (line)
1254       {
1255 	  /* copying LINESTRINGs */
1256 	  new_line = gaiaAddLinestringToGeomColl (new_geom, line->Points);
1257 	  if (mode == GAIA_REVERSE_ORDER)
1258 	      gaiaCopyLinestringCoordsReverse (new_line, line);
1259 	  else
1260 	      gaiaCopyLinestringCoords (new_line, line);
1261 	  line = line->Next;
1262       }
1263     polyg = geom->FirstPolygon;
1264     while (polyg)
1265       {
1266 	  /* copying POLYGONs */
1267 	  i_ring = polyg->Exterior;
1268 	  new_polyg =
1269 	      gaiaAddPolygonToGeomColl (new_geom, i_ring->Points,
1270 					polyg->NumInteriors);
1271 	  o_ring = new_polyg->Exterior;
1272 	  /* copying points for the EXTERIOR RING */
1273 	  if (mode == GAIA_REVERSE_ORDER)
1274 	      gaiaCopyRingCoordsReverse (o_ring, i_ring);
1275 	  else
1276 	    {
1277 		gaiaClockwise (i_ring);
1278 		if (mode == GAIA_CCW_ORDER)
1279 		  {
1280 		      /* Counter-Clockwise Polygon */
1281 		      if (i_ring->Clockwise)
1282 			  gaiaCopyRingCoordsReverse (o_ring, i_ring);
1283 		      else
1284 			  gaiaCopyRingCoords (o_ring, i_ring);
1285 		  }
1286 		else
1287 		  {
1288 		      /* Clockwise Polygon */
1289 		      if (i_ring->Clockwise)
1290 			  gaiaCopyRingCoords (o_ring, i_ring);
1291 		      else
1292 			  gaiaCopyRingCoordsReverse (o_ring, i_ring);
1293 		  }
1294 	    }
1295 	  for (ib = 0; ib < new_polyg->NumInteriors; ib++)
1296 	    {
1297 		/* copying each INTERIOR RING [if any] */
1298 		i_ring = polyg->Interiors + ib;
1299 		o_ring = gaiaAddInteriorRing (new_polyg, ib, i_ring->Points);
1300 		if (mode == GAIA_REVERSE_ORDER)
1301 		    gaiaCopyRingCoordsReverse (o_ring, i_ring);
1302 		else
1303 		  {
1304 		      gaiaClockwise (i_ring);
1305 		      if (mode == GAIA_CCW_ORDER)
1306 			{
1307 			    /* Counter-Clockwise Polygon */
1308 			    if (i_ring->Clockwise)
1309 				gaiaCopyRingCoords (o_ring, i_ring);
1310 			    else
1311 				gaiaCopyRingCoordsReverse (o_ring, i_ring);
1312 			}
1313 		      else
1314 			{
1315 			    /* Clockwise Polygon */
1316 			    if (i_ring->Clockwise)
1317 				gaiaCopyRingCoordsReverse (o_ring, i_ring);
1318 			    else
1319 				gaiaCopyRingCoords (o_ring, i_ring);
1320 			}
1321 		  }
1322 	    }
1323 	  polyg = polyg->Next;
1324       }
1325     return new_geom;
1326 }
1327 
1328 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCloneGeomCollPoints(gaiaGeomCollPtr geom)1329 gaiaCloneGeomCollPoints (gaiaGeomCollPtr geom)
1330 {
1331 /* clones a GEOMETRYCOLLECTION (Points only) */
1332     gaiaPointPtr point;
1333     gaiaGeomCollPtr new_geom;
1334     if (!geom)
1335 	return NULL;
1336     if (geom->DimensionModel == GAIA_XY_Z)
1337 	new_geom = gaiaAllocGeomCollXYZ ();
1338     else if (geom->DimensionModel == GAIA_XY_M)
1339 	new_geom = gaiaAllocGeomCollXYM ();
1340     else if (geom->DimensionModel == GAIA_XY_Z_M)
1341 	new_geom = gaiaAllocGeomCollXYZM ();
1342     else
1343 	new_geom = gaiaAllocGeomColl ();
1344     new_geom->Srid = geom->Srid;
1345     new_geom->DeclaredType = GAIA_MULTIPOINT;
1346     point = geom->FirstPoint;
1347     while (point)
1348       {
1349 	  /* copying POINTs */
1350 	  if (geom->DimensionModel == GAIA_XY_Z)
1351 	      gaiaAddPointToGeomCollXYZ (new_geom, point->X, point->Y,
1352 					 point->Z);
1353 	  else if (geom->DimensionModel == GAIA_XY_M)
1354 	      gaiaAddPointToGeomCollXYM (new_geom, point->X, point->Y,
1355 					 point->M);
1356 	  else if (geom->DimensionModel == GAIA_XY_Z_M)
1357 	      gaiaAddPointToGeomCollXYZM (new_geom, point->X, point->Y,
1358 					  point->Z, point->M);
1359 	  else
1360 	      gaiaAddPointToGeomColl (new_geom, point->X, point->Y);
1361 	  point = point->Next;
1362       }
1363     return new_geom;
1364 }
1365 
1366 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCloneGeomCollLinestrings(gaiaGeomCollPtr geom)1367 gaiaCloneGeomCollLinestrings (gaiaGeomCollPtr geom)
1368 {
1369 /* clones a GEOMETRYCOLLECTION (Linestrings only) */
1370     gaiaLinestringPtr line;
1371     gaiaLinestringPtr new_line;
1372     gaiaGeomCollPtr new_geom;
1373     if (!geom)
1374 	return NULL;
1375     if (geom->DimensionModel == GAIA_XY_Z)
1376 	new_geom = gaiaAllocGeomCollXYZ ();
1377     else if (geom->DimensionModel == GAIA_XY_M)
1378 	new_geom = gaiaAllocGeomCollXYM ();
1379     else if (geom->DimensionModel == GAIA_XY_Z_M)
1380 	new_geom = gaiaAllocGeomCollXYZM ();
1381     else
1382 	new_geom = gaiaAllocGeomColl ();
1383     new_geom->Srid = geom->Srid;
1384     new_geom->DeclaredType = GAIA_MULTILINESTRING;
1385     line = geom->FirstLinestring;
1386     while (line)
1387       {
1388 	  /* copying LINESTRINGs */
1389 	  new_line = gaiaAddLinestringToGeomColl (new_geom, line->Points);
1390 	  gaiaCopyLinestringCoords (new_line, line);
1391 	  line = line->Next;
1392       }
1393     return new_geom;
1394 }
1395 
1396 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCloneGeomCollPolygons(gaiaGeomCollPtr geom)1397 gaiaCloneGeomCollPolygons (gaiaGeomCollPtr geom)
1398 {
1399 /* clones a GEOMETRYCOLLECTION (Polygons only) */
1400     int ib;
1401     gaiaPolygonPtr polyg;
1402     gaiaPolygonPtr new_polyg;
1403     gaiaGeomCollPtr new_geom;
1404     gaiaRingPtr i_ring;
1405     gaiaRingPtr o_ring;
1406     if (!geom)
1407 	return NULL;
1408     if (geom->DimensionModel == GAIA_XY_Z)
1409 	new_geom = gaiaAllocGeomCollXYZ ();
1410     else if (geom->DimensionModel == GAIA_XY_M)
1411 	new_geom = gaiaAllocGeomCollXYM ();
1412     else if (geom->DimensionModel == GAIA_XY_Z_M)
1413 	new_geom = gaiaAllocGeomCollXYZM ();
1414     else
1415 	new_geom = gaiaAllocGeomColl ();
1416     new_geom->Srid = geom->Srid;
1417     new_geom->DeclaredType = GAIA_MULTIPOLYGON;
1418     polyg = geom->FirstPolygon;
1419     while (polyg)
1420       {
1421 	  /* copying POLYGONs */
1422 	  i_ring = polyg->Exterior;
1423 	  new_polyg =
1424 	      gaiaAddPolygonToGeomColl (new_geom, i_ring->Points,
1425 					polyg->NumInteriors);
1426 	  o_ring = new_polyg->Exterior;
1427 	  /* copying points for the EXTERIOR RING */
1428 	  gaiaCopyRingCoords (o_ring, i_ring);
1429 	  for (ib = 0; ib < new_polyg->NumInteriors; ib++)
1430 	    {
1431 		/* copying each INTERIOR RING [if any] */
1432 		i_ring = polyg->Interiors + ib;
1433 		o_ring = gaiaAddInteriorRing (new_polyg, ib, i_ring->Points);
1434 		gaiaCopyRingCoords (o_ring, i_ring);
1435 	    }
1436 	  polyg = polyg->Next;
1437       }
1438     return new_geom;
1439 }
1440 
1441 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCastGeomCollToXY(gaiaGeomCollPtr geom)1442 gaiaCastGeomCollToXY (gaiaGeomCollPtr geom)
1443 {
1444 /* clones a GEOMETRYCOLLECTION converting to XY-dimensions */
1445     int ib;
1446     gaiaPointPtr point;
1447     gaiaLinestringPtr line;
1448     gaiaLinestringPtr new_line;
1449     gaiaPolygonPtr polyg;
1450     gaiaPolygonPtr new_polyg;
1451     gaiaGeomCollPtr new_geom;
1452     gaiaRingPtr i_ring;
1453     gaiaRingPtr o_ring;
1454     if (!geom)
1455 	return NULL;
1456     new_geom = gaiaAllocGeomColl ();
1457     new_geom->Srid = geom->Srid;
1458     new_geom->DeclaredType = geom->DeclaredType;
1459     point = geom->FirstPoint;
1460     while (point)
1461       {
1462 	  /* copying POINTs */
1463 	  gaiaAddPointToGeomColl (new_geom, point->X, point->Y);
1464 	  point = point->Next;
1465       }
1466     line = geom->FirstLinestring;
1467     while (line)
1468       {
1469 	  /* copying LINESTRINGs */
1470 	  new_line = gaiaAddLinestringToGeomColl (new_geom, line->Points);
1471 	  gaiaCopyLinestringCoords (new_line, line);
1472 	  line = line->Next;
1473       }
1474     polyg = geom->FirstPolygon;
1475     while (polyg)
1476       {
1477 	  /* copying POLYGONs */
1478 	  i_ring = polyg->Exterior;
1479 	  new_polyg =
1480 	      gaiaAddPolygonToGeomColl (new_geom, i_ring->Points,
1481 					polyg->NumInteriors);
1482 	  o_ring = new_polyg->Exterior;
1483 	  /* copying points for the EXTERIOR RING */
1484 	  gaiaCopyRingCoords (o_ring, i_ring);
1485 	  for (ib = 0; ib < new_polyg->NumInteriors; ib++)
1486 	    {
1487 		/* copying each INTERIOR RING [if any] */
1488 		i_ring = polyg->Interiors + ib;
1489 		o_ring = gaiaAddInteriorRing (new_polyg, ib, i_ring->Points);
1490 		gaiaCopyRingCoords (o_ring, i_ring);
1491 	    }
1492 	  polyg = polyg->Next;
1493       }
1494     return new_geom;
1495 }
1496 
1497 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCastGeomCollToXYZ(gaiaGeomCollPtr geom)1498 gaiaCastGeomCollToXYZ (gaiaGeomCollPtr geom)
1499 {
1500 /* clones a GEOMETRYCOLLECTION converting to XYZ-dimensions */
1501     return gaiaCastGeomCollToXYZnoData (geom, 0.0);
1502 }
1503 
1504 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCastGeomCollToXYZnoData(gaiaGeomCollPtr geom,double no_data)1505 gaiaCastGeomCollToXYZnoData (gaiaGeomCollPtr geom, double no_data)
1506 {
1507 /* clones a GEOMETRYCOLLECTION converting to XYZ-dimensions */
1508     int ib;
1509     gaiaPointPtr point;
1510     gaiaLinestringPtr line;
1511     gaiaLinestringPtr new_line;
1512     gaiaPolygonPtr polyg;
1513     gaiaPolygonPtr new_polyg;
1514     gaiaGeomCollPtr new_geom;
1515     gaiaRingPtr i_ring;
1516     gaiaRingPtr o_ring;
1517     int has_z = 0;
1518     if (!geom)
1519 	return NULL;
1520     if (geom->DimensionModel == GAIA_XY_Z
1521 	|| geom->DimensionModel == GAIA_XY_Z_M)
1522 	has_z = 1;
1523     new_geom = gaiaAllocGeomCollXYZ ();
1524     new_geom->Srid = geom->Srid;
1525     new_geom->DeclaredType = geom->DeclaredType;
1526     point = geom->FirstPoint;
1527     while (point)
1528       {
1529 	  /* copying POINTs */
1530 	  if (has_z)
1531 	      gaiaAddPointToGeomCollXYZ (new_geom, point->X, point->Y,
1532 					 point->Z);
1533 	  else
1534 	      gaiaAddPointToGeomCollXYZ (new_geom, point->X, point->Y, no_data);
1535 	  point = point->Next;
1536       }
1537     line = geom->FirstLinestring;
1538     while (line)
1539       {
1540 	  /* copying LINESTRINGs */
1541 	  new_line = gaiaAddLinestringToGeomColl (new_geom, line->Points);
1542 	  gaiaCopyLinestringCoordsEx (new_line, line, no_data, 0.0);
1543 	  line = line->Next;
1544       }
1545     polyg = geom->FirstPolygon;
1546     while (polyg)
1547       {
1548 	  /* copying POLYGONs */
1549 	  i_ring = polyg->Exterior;
1550 	  new_polyg =
1551 	      gaiaAddPolygonToGeomColl (new_geom, i_ring->Points,
1552 					polyg->NumInteriors);
1553 	  o_ring = new_polyg->Exterior;
1554 	  /* copying points for the EXTERIOR RING */
1555 	  gaiaCopyRingCoordsEx (o_ring, i_ring, no_data, 0.0);
1556 	  for (ib = 0; ib < new_polyg->NumInteriors; ib++)
1557 	    {
1558 		/* copying each INTERIOR RING [if any] */
1559 		i_ring = polyg->Interiors + ib;
1560 		o_ring = gaiaAddInteriorRing (new_polyg, ib, i_ring->Points);
1561 		gaiaCopyRingCoordsEx (o_ring, i_ring, no_data, 0.0);
1562 	    }
1563 	  polyg = polyg->Next;
1564       }
1565     return new_geom;
1566 }
1567 
1568 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCastGeomCollToXYM(gaiaGeomCollPtr geom)1569 gaiaCastGeomCollToXYM (gaiaGeomCollPtr geom)
1570 {
1571 /* clones a GEOMETRYCOLLECTION converting to XYM-dimensions */
1572     return gaiaCastGeomCollToXYMnoData (geom, 0.0);
1573 }
1574 
1575 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCastGeomCollToXYMnoData(gaiaGeomCollPtr geom,double no_data)1576 gaiaCastGeomCollToXYMnoData (gaiaGeomCollPtr geom, double no_data)
1577 {
1578 /* clones a GEOMETRYCOLLECTION converting to XYM-dimensions */
1579     int ib;
1580     gaiaPointPtr point;
1581     gaiaLinestringPtr line;
1582     gaiaLinestringPtr new_line;
1583     gaiaPolygonPtr polyg;
1584     gaiaPolygonPtr new_polyg;
1585     gaiaGeomCollPtr new_geom;
1586     gaiaRingPtr i_ring;
1587     gaiaRingPtr o_ring;
1588     int has_m = 0;
1589     if (!geom)
1590 	return NULL;
1591     if (geom->DimensionModel == GAIA_XY_M
1592 	|| geom->DimensionModel == GAIA_XY_Z_M)
1593 	has_m = 1;
1594     new_geom = gaiaAllocGeomCollXYM ();
1595     new_geom->Srid = geom->Srid;
1596     new_geom->DeclaredType = geom->DeclaredType;
1597     point = geom->FirstPoint;
1598     while (point)
1599       {
1600 	  /* copying POINTs */
1601 	  if (has_m)
1602 	      gaiaAddPointToGeomCollXYM (new_geom, point->X, point->Y,
1603 					 point->M);
1604 	  else
1605 	      gaiaAddPointToGeomCollXYM (new_geom, point->X, point->Y, no_data);
1606 	  point = point->Next;
1607       }
1608     line = geom->FirstLinestring;
1609     while (line)
1610       {
1611 	  /* copying LINESTRINGs */
1612 	  new_line = gaiaAddLinestringToGeomColl (new_geom, line->Points);
1613 	  gaiaCopyLinestringCoordsEx (new_line, line, 0.0, no_data);
1614 	  line = line->Next;
1615       }
1616     polyg = geom->FirstPolygon;
1617     while (polyg)
1618       {
1619 	  /* copying POLYGONs */
1620 	  i_ring = polyg->Exterior;
1621 	  new_polyg =
1622 	      gaiaAddPolygonToGeomColl (new_geom, i_ring->Points,
1623 					polyg->NumInteriors);
1624 	  o_ring = new_polyg->Exterior;
1625 	  /* copying points for the EXTERIOR RING */
1626 	  gaiaCopyRingCoordsEx (o_ring, i_ring, 0.0, no_data);
1627 	  for (ib = 0; ib < new_polyg->NumInteriors; ib++)
1628 	    {
1629 		/* copying each INTERIOR RING [if any] */
1630 		i_ring = polyg->Interiors + ib;
1631 		o_ring = gaiaAddInteriorRing (new_polyg, ib, i_ring->Points);
1632 		gaiaCopyRingCoordsEx (o_ring, i_ring, 0.0, no_data);
1633 	    }
1634 	  polyg = polyg->Next;
1635       }
1636     return new_geom;
1637 }
1638 
1639 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCastGeomCollToXYZM(gaiaGeomCollPtr geom)1640 gaiaCastGeomCollToXYZM (gaiaGeomCollPtr geom)
1641 {
1642 /* clones a GEOMETRYCOLLECTION converting to XYZM-dimensions */
1643     return gaiaCastGeomCollToXYZMnoData (geom, 0.0, 0.0);
1644 }
1645 
1646 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaCastGeomCollToXYZMnoData(gaiaGeomCollPtr geom,double z_no_data,double m_no_data)1647 gaiaCastGeomCollToXYZMnoData (gaiaGeomCollPtr geom, double z_no_data,
1648 			      double m_no_data)
1649 {
1650 /* clones a GEOMETRYCOLLECTION converting to XYZM-dimensions */
1651     int ib;
1652     gaiaPointPtr point;
1653     gaiaLinestringPtr line;
1654     gaiaLinestringPtr new_line;
1655     gaiaPolygonPtr polyg;
1656     gaiaPolygonPtr new_polyg;
1657     gaiaGeomCollPtr new_geom;
1658     gaiaRingPtr i_ring;
1659     gaiaRingPtr o_ring;
1660     int has_z = 0;
1661     int has_m = 0;
1662     if (!geom)
1663 	return NULL;
1664     if (geom->DimensionModel == GAIA_XY_Z
1665 	|| geom->DimensionModel == GAIA_XY_Z_M)
1666 	has_z = 1;
1667     if (geom->DimensionModel == GAIA_XY_M
1668 	|| geom->DimensionModel == GAIA_XY_Z_M)
1669 	has_m = 1;
1670     new_geom = gaiaAllocGeomCollXYZM ();
1671     new_geom->Srid = geom->Srid;
1672     new_geom->DeclaredType = geom->DeclaredType;
1673     point = geom->FirstPoint;
1674     while (point)
1675       {
1676 	  /* copying POINTs */
1677 	  if (has_z && has_m)
1678 	      gaiaAddPointToGeomCollXYZM (new_geom, point->X, point->Y,
1679 					  point->Z, point->M);
1680 	  else if (has_z)
1681 	      gaiaAddPointToGeomCollXYZM (new_geom, point->X, point->Y,
1682 					  point->Z, m_no_data);
1683 	  else if (has_m)
1684 	      gaiaAddPointToGeomCollXYZM (new_geom, point->X, point->Y,
1685 					  z_no_data, point->M);
1686 	  else
1687 	      gaiaAddPointToGeomCollXYZM (new_geom, point->X, point->Y,
1688 					  z_no_data, m_no_data);
1689 	  point = point->Next;
1690       }
1691     line = geom->FirstLinestring;
1692     while (line)
1693       {
1694 	  /* copying LINESTRINGs */
1695 	  new_line = gaiaAddLinestringToGeomColl (new_geom, line->Points);
1696 	  gaiaCopyLinestringCoordsEx (new_line, line, z_no_data, m_no_data);
1697 	  line = line->Next;
1698       }
1699     polyg = geom->FirstPolygon;
1700     while (polyg)
1701       {
1702 	  /* copying POLYGONs */
1703 	  i_ring = polyg->Exterior;
1704 	  new_polyg =
1705 	      gaiaAddPolygonToGeomColl (new_geom, i_ring->Points,
1706 					polyg->NumInteriors);
1707 	  o_ring = new_polyg->Exterior;
1708 	  /* copying points for the EXTERIOR RING */
1709 	  gaiaCopyRingCoordsEx (o_ring, i_ring, z_no_data, m_no_data);
1710 	  for (ib = 0; ib < new_polyg->NumInteriors; ib++)
1711 	    {
1712 		/* copying each INTERIOR RING [if any] */
1713 		i_ring = polyg->Interiors + ib;
1714 		o_ring = gaiaAddInteriorRing (new_polyg, ib, i_ring->Points);
1715 		gaiaCopyRingCoordsEx (o_ring, i_ring, z_no_data, m_no_data);
1716 	    }
1717 	  polyg = polyg->Next;
1718       }
1719     return new_geom;
1720 }
1721 
1722 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaAllocGeomColl()1723 gaiaAllocGeomColl ()
1724 {
1725 /* GEOMETRYCOLLECTION object constructor */
1726     gaiaGeomCollPtr p = malloc (sizeof (gaiaGeomColl));
1727     p->Srid = 0;
1728     p->endian = ' ';
1729     p->offset = 0;
1730     p->FirstPoint = NULL;
1731     p->LastPoint = NULL;
1732     p->FirstLinestring = NULL;
1733     p->LastLinestring = NULL;
1734     p->FirstPolygon = NULL;
1735     p->LastPolygon = NULL;
1736     p->MinX = DBL_MAX;
1737     p->MinY = DBL_MAX;
1738     p->MaxX = -DBL_MAX;
1739     p->MaxY = -DBL_MAX;
1740     p->DimensionModel = GAIA_XY;
1741     p->DeclaredType = GAIA_UNKNOWN;
1742     p->Next = NULL;
1743     return p;
1744 }
1745 
1746 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaAllocGeomCollXYZ()1747 gaiaAllocGeomCollXYZ ()
1748 {
1749 /* GEOMETRYCOLLECTION object constructor */
1750     gaiaGeomCollPtr p = malloc (sizeof (gaiaGeomColl));
1751     p->Srid = 0;
1752     p->endian = ' ';
1753     p->offset = 0;
1754     p->FirstPoint = NULL;
1755     p->LastPoint = NULL;
1756     p->FirstLinestring = NULL;
1757     p->LastLinestring = NULL;
1758     p->FirstPolygon = NULL;
1759     p->LastPolygon = NULL;
1760     p->MinX = DBL_MAX;
1761     p->MinY = DBL_MAX;
1762     p->MaxX = -DBL_MAX;
1763     p->MaxY = -DBL_MAX;
1764     p->DimensionModel = GAIA_XY_Z;
1765     p->DeclaredType = GAIA_UNKNOWN;
1766     p->Next = NULL;
1767     return p;
1768 }
1769 
1770 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaAllocGeomCollXYM()1771 gaiaAllocGeomCollXYM ()
1772 {
1773 /* GEOMETRYCOLLECTION object constructor */
1774     gaiaGeomCollPtr p = malloc (sizeof (gaiaGeomColl));
1775     p->Srid = 0;
1776     p->endian = ' ';
1777     p->offset = 0;
1778     p->FirstPoint = NULL;
1779     p->LastPoint = NULL;
1780     p->FirstLinestring = NULL;
1781     p->LastLinestring = NULL;
1782     p->FirstPolygon = NULL;
1783     p->LastPolygon = NULL;
1784     p->MinX = DBL_MAX;
1785     p->MinY = DBL_MAX;
1786     p->MaxX = -DBL_MAX;
1787     p->MaxY = -DBL_MAX;
1788     p->DimensionModel = GAIA_XY_M;
1789     p->DeclaredType = GAIA_UNKNOWN;
1790     p->Next = NULL;
1791     return p;
1792 }
1793 
1794 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaAllocGeomCollXYZM()1795 gaiaAllocGeomCollXYZM ()
1796 {
1797 /* GEOMETRYCOLLECTION object constructor */
1798     gaiaGeomCollPtr p = malloc (sizeof (gaiaGeomColl));
1799     p->Srid = 0;
1800     p->endian = ' ';
1801     p->offset = 0;
1802     p->FirstPoint = NULL;
1803     p->LastPoint = NULL;
1804     p->FirstLinestring = NULL;
1805     p->LastLinestring = NULL;
1806     p->FirstPolygon = NULL;
1807     p->LastPolygon = NULL;
1808     p->MinX = DBL_MAX;
1809     p->MinY = DBL_MAX;
1810     p->MaxX = -DBL_MAX;
1811     p->MaxY = -DBL_MAX;
1812     p->DimensionModel = GAIA_XY_Z_M;
1813     p->DeclaredType = GAIA_UNKNOWN;
1814     p->Next = NULL;
1815     return p;
1816 }
1817 
1818 GAIAGEO_DECLARE void
gaiaFreeGeomColl(gaiaGeomCollPtr p)1819 gaiaFreeGeomColl (gaiaGeomCollPtr p)
1820 {
1821 /* GEOMETRYCOLLECTION object destructor */
1822     gaiaPointPtr pP;
1823     gaiaPointPtr pPn;
1824     gaiaLinestringPtr pL;
1825     gaiaLinestringPtr pLn;
1826     gaiaPolygonPtr pA;
1827     gaiaPolygonPtr pAn;
1828     if (!p)
1829 	return;
1830     pP = p->FirstPoint;
1831     while (pP != NULL)
1832       {
1833 	  pPn = pP->Next;
1834 	  gaiaFreePoint (pP);
1835 	  pP = pPn;
1836       }
1837     pL = p->FirstLinestring;
1838     while (pL != NULL)
1839       {
1840 	  pLn = pL->Next;
1841 	  gaiaFreeLinestring (pL);
1842 	  pL = pLn;
1843       }
1844     pA = p->FirstPolygon;
1845     while (pA != NULL)
1846       {
1847 	  pAn = pA->Next;
1848 	  gaiaFreePolygon (pA);
1849 	  pA = pAn;
1850       }
1851     free (p);
1852 }
1853 
1854 GAIAGEO_DECLARE void
gaiaAddPointToGeomColl(gaiaGeomCollPtr p,double x,double y)1855 gaiaAddPointToGeomColl (gaiaGeomCollPtr p, double x, double y)
1856 {
1857 /* adding a POINT to this GEOMETRYCOLLECTION */
1858     gaiaPointPtr point = gaiaAllocPoint (x, y);
1859     if (p->FirstPoint == NULL)
1860 	p->FirstPoint = point;
1861     if (p->LastPoint != NULL)
1862 	p->LastPoint->Next = point;
1863     p->LastPoint = point;
1864 }
1865 
1866 GAIAGEO_DECLARE void
gaiaAddPointToGeomCollXYZ(gaiaGeomCollPtr p,double x,double y,double z)1867 gaiaAddPointToGeomCollXYZ (gaiaGeomCollPtr p, double x, double y, double z)
1868 {
1869 /* adding a POINT to this GEOMETRYCOLLECTION */
1870     gaiaPointPtr point = gaiaAllocPointXYZ (x, y, z);
1871     if (p->FirstPoint == NULL)
1872 	p->FirstPoint = point;
1873     if (p->LastPoint != NULL)
1874 	p->LastPoint->Next = point;
1875     p->LastPoint = point;
1876 }
1877 
1878 GAIAGEO_DECLARE void
gaiaAddPointToGeomCollXYM(gaiaGeomCollPtr p,double x,double y,double m)1879 gaiaAddPointToGeomCollXYM (gaiaGeomCollPtr p, double x, double y, double m)
1880 {
1881 /* adding a POINT to this GEOMETRYCOLLECTION */
1882     gaiaPointPtr point = gaiaAllocPointXYM (x, y, m);
1883     if (p->FirstPoint == NULL)
1884 	p->FirstPoint = point;
1885     if (p->LastPoint != NULL)
1886 	p->LastPoint->Next = point;
1887     p->LastPoint = point;
1888 }
1889 
1890 GAIAGEO_DECLARE void
gaiaAddPointToGeomCollXYZM(gaiaGeomCollPtr p,double x,double y,double z,double m)1891 gaiaAddPointToGeomCollXYZM (gaiaGeomCollPtr p, double x, double y, double z,
1892 			    double m)
1893 {
1894 /* adding a POINT to this GEOMETRYCOLLECTION */
1895     gaiaPointPtr point = gaiaAllocPointXYZM (x, y, z, m);
1896     if (p->FirstPoint == NULL)
1897 	p->FirstPoint = point;
1898     if (p->LastPoint != NULL)
1899 	p->LastPoint->Next = point;
1900     p->LastPoint = point;
1901 }
1902 
1903 GAIAGEO_DECLARE gaiaLinestringPtr
gaiaAddLinestringToGeomColl(gaiaGeomCollPtr p,int vert)1904 gaiaAddLinestringToGeomColl (gaiaGeomCollPtr p, int vert)
1905 {
1906 /* adding a LINESTRING to this GEOMETRYCOLLECTION */
1907     gaiaLinestringPtr line;
1908     if (p->DimensionModel == GAIA_XY_Z)
1909 	line = gaiaAllocLinestringXYZ (vert);
1910     else if (p->DimensionModel == GAIA_XY_M)
1911 	line = gaiaAllocLinestringXYM (vert);
1912     else if (p->DimensionModel == GAIA_XY_Z_M)
1913 	line = gaiaAllocLinestringXYZM (vert);
1914     else
1915 	line = gaiaAllocLinestring (vert);
1916     if (p->FirstLinestring == NULL)
1917 	p->FirstLinestring = line;
1918     if (p->LastLinestring != NULL)
1919 	p->LastLinestring->Next = line;
1920     p->LastLinestring = line;
1921     return line;
1922 }
1923 
1924 GAIAGEO_DECLARE void
gaiaInsertLinestringInGeomColl(gaiaGeomCollPtr p,gaiaLinestringPtr line)1925 gaiaInsertLinestringInGeomColl (gaiaGeomCollPtr p, gaiaLinestringPtr line)
1926 {
1927 /* adding an existing LINESTRING to this GEOMETRYCOLLECTION */
1928     if (p->FirstLinestring == NULL)
1929 	p->FirstLinestring = line;
1930     if (p->LastLinestring != NULL)
1931 	p->LastLinestring->Next = line;
1932     p->LastLinestring = line;
1933 }
1934 
1935 GAIAGEO_DECLARE gaiaPolygonPtr
gaiaAddPolygonToGeomColl(gaiaGeomCollPtr p,int vert,int interiors)1936 gaiaAddPolygonToGeomColl (gaiaGeomCollPtr p, int vert, int interiors)
1937 {
1938 /* adding a POLYGON to this GEOMETRYCOLLECTION */
1939     gaiaPolygonPtr polyg;
1940     if (p->DimensionModel == GAIA_XY_Z)
1941 	polyg = gaiaAllocPolygonXYZ (vert, interiors);
1942     else if (p->DimensionModel == GAIA_XY_M)
1943 	polyg = gaiaAllocPolygonXYM (vert, interiors);
1944     else if (p->DimensionModel == GAIA_XY_Z_M)
1945 	polyg = gaiaAllocPolygonXYZM (vert, interiors);
1946     else
1947 	polyg = gaiaAllocPolygon (vert, interiors);
1948     if (p->FirstPolygon == NULL)
1949 	p->FirstPolygon = polyg;
1950     if (p->LastPolygon != NULL)
1951 	p->LastPolygon->Next = polyg;
1952     p->LastPolygon = polyg;
1953     return polyg;
1954 }
1955 
1956 GAIAGEO_DECLARE gaiaPolygonPtr
gaiaInsertPolygonInGeomColl(gaiaGeomCollPtr p,gaiaRingPtr ring)1957 gaiaInsertPolygonInGeomColl (gaiaGeomCollPtr p, gaiaRingPtr ring)
1958 {
1959 /* adding a POLYGON to this GEOMETRYCOLLECTION */
1960     gaiaPolygonPtr polyg;
1961     polyg = malloc (sizeof (gaiaPolygon));
1962     polyg->Exterior = ring;
1963     polyg->NumInteriors = 0;
1964     polyg->NextInterior = 0;
1965     polyg->DimensionModel = ring->DimensionModel;
1966     polyg->Next = NULL;
1967     polyg->Interiors = NULL;
1968     polyg->MinX = DBL_MAX;
1969     polyg->MinY = DBL_MAX;
1970     polyg->MaxX = -DBL_MAX;
1971     polyg->MaxY = -DBL_MAX;
1972     if (p->FirstPolygon == NULL)
1973 	p->FirstPolygon = polyg;
1974     if (p->LastPolygon != NULL)
1975 	p->LastPolygon->Next = polyg;
1976     p->LastPolygon = polyg;
1977     return polyg;
1978 }
1979 
1980 GAIAGEO_DECLARE gaiaRingPtr
gaiaAddInteriorRing(gaiaPolygonPtr p,int pos,int vert)1981 gaiaAddInteriorRing (gaiaPolygonPtr p, int pos, int vert)
1982 {
1983 /* adding an interior ring to some polygon */
1984     gaiaRingPtr pP = p->Interiors + pos;
1985     pP->Points = vert;
1986     pP->DimensionModel = p->DimensionModel;
1987     if (pP->DimensionModel == GAIA_XY_Z)
1988 	pP->Coords = malloc (sizeof (double) * (vert * 3));
1989     else if (pP->DimensionModel == GAIA_XY_M)
1990 	pP->Coords = malloc (sizeof (double) * (vert * 3));
1991     else if (pP->DimensionModel == GAIA_XY_Z_M)
1992 	pP->Coords = malloc (sizeof (double) * (vert * 4));
1993     else
1994 	pP->Coords = malloc (sizeof (double) * (vert * 2));
1995     return pP;
1996 }
1997 
1998 GAIAGEO_DECLARE void
gaiaInsertInteriorRing(gaiaPolygonPtr p,gaiaRingPtr ring)1999 gaiaInsertInteriorRing (gaiaPolygonPtr p, gaiaRingPtr ring)
2000 {
2001 /* adding an interior ring to some polygon */
2002     gaiaRingPtr hole;
2003     if (p->NumInteriors == 0)
2004       {
2005 	  /* this one is the first interior ring */
2006 	  p->NumInteriors++;
2007 	  p->Interiors = malloc (sizeof (gaiaRing));
2008 	  hole = p->Interiors;
2009       }
2010     else
2011       {
2012 	  /* some interior ring is already defined */
2013 	  gaiaRingPtr save = p->Interiors;
2014 	  p->Interiors = malloc (sizeof (gaiaRing) * (p->NumInteriors + 1));
2015 	  memcpy (p->Interiors, save, (sizeof (gaiaRing) * p->NumInteriors));
2016 	  free (save);
2017 	  hole = p->Interiors + p->NumInteriors;
2018 	  p->NumInteriors++;
2019       }
2020     hole->Points = ring->Points;
2021     hole->DimensionModel = p->DimensionModel;
2022     if (hole->DimensionModel == GAIA_XY_Z)
2023 	hole->Coords = malloc (sizeof (double) * (hole->Points * 3));
2024     else if (hole->DimensionModel == GAIA_XY_M)
2025 	hole->Coords = malloc (sizeof (double) * (hole->Points * 3));
2026     else if (hole->DimensionModel == GAIA_XY_Z_M)
2027 	hole->Coords = malloc (sizeof (double) * (hole->Points * 4));
2028     else
2029 	hole->Coords = malloc (sizeof (double) * (hole->Points * 2));
2030     gaiaCopyRingCoords (hole, ring);
2031 }
2032 
2033 GAIAGEO_DECLARE void
gaiaAddRingToPolyg(gaiaPolygonPtr polyg,gaiaRingPtr ring)2034 gaiaAddRingToPolyg (gaiaPolygonPtr polyg, gaiaRingPtr ring)
2035 {
2036 /* adds an interior ring to this POLYGON  */
2037     gaiaRingPtr old_interiors = NULL;
2038     if (!(polyg->Interiors))
2039       {
2040 	  /* this one is the first interior ring */
2041 	  polyg->Interiors = ring;
2042 	  polyg->NumInteriors = 1;
2043       }
2044     else
2045       {
2046 	  /* adding another interior ring */
2047 	  old_interiors = polyg->Interiors;
2048 	  polyg->Interiors =
2049 	      malloc (sizeof (gaiaRing) * (polyg->NumInteriors + 1));
2050 	  memcpy (polyg->Interiors, old_interiors,
2051 		  (sizeof (gaiaRing) * polyg->NumInteriors));
2052 	  memcpy (polyg->Interiors + polyg->NumInteriors, ring,
2053 		  sizeof (gaiaRing));
2054 	  (polyg->NumInteriors)++;
2055 	  free (old_interiors);
2056 	  free (ring);
2057       }
2058 }
2059 
2060 GAIAGEO_DECLARE gaiaDynamicLinePtr
gaiaAllocDynamicLine()2061 gaiaAllocDynamicLine ()
2062 {
2063 /* DYNAMIC LINE object constructor */
2064     gaiaDynamicLinePtr p = malloc (sizeof (gaiaDynamicLine));
2065     p->Error = 0;
2066     p->Srid = 0;
2067     p->First = NULL;
2068     p->Last = NULL;
2069     return p;
2070 }
2071 
2072 GAIAGEO_DECLARE void
gaiaFreeDynamicLine(gaiaDynamicLinePtr p)2073 gaiaFreeDynamicLine (gaiaDynamicLinePtr p)
2074 {
2075 /* DYNAMIC LINE object destructor */
2076     gaiaPointPtr pP;
2077     gaiaPointPtr pPn;
2078     pP = p->First;
2079     while (pP != NULL)
2080       {
2081 	  pPn = pP->Next;
2082 	  gaiaFreePoint (pP);
2083 	  pP = pPn;
2084       }
2085     free (p);
2086 }
2087 
2088 GAIAGEO_DECLARE gaiaPointPtr
gaiaAppendPointToDynamicLine(gaiaDynamicLinePtr p,double x,double y)2089 gaiaAppendPointToDynamicLine (gaiaDynamicLinePtr p, double x, double y)
2090 {
2091 /* inserts a new POINT to this DYNAMIC LINE after the last one */
2092     gaiaPointPtr point = gaiaAllocPoint (x, y);
2093     point->Prev = p->Last;
2094     if (p->First == NULL)
2095 	p->First = point;
2096     if (p->Last != NULL)
2097 	p->Last->Next = point;
2098     p->Last = point;
2099     return point;
2100 }
2101 
2102 GAIAGEO_DECLARE gaiaPointPtr
gaiaAppendPointZToDynamicLine(gaiaDynamicLinePtr p,double x,double y,double z)2103 gaiaAppendPointZToDynamicLine (gaiaDynamicLinePtr p, double x, double y,
2104 			       double z)
2105 {
2106 /* inserts a new POINT to this DYNAMIC LINE after the last one */
2107     gaiaPointPtr point = gaiaAllocPointXYZ (x, y, z);
2108     point->Prev = p->Last;
2109     if (p->First == NULL)
2110 	p->First = point;
2111     if (p->Last != NULL)
2112 	p->Last->Next = point;
2113     p->Last = point;
2114     return point;
2115 }
2116 
2117 GAIAGEO_DECLARE gaiaPointPtr
gaiaAppendPointMToDynamicLine(gaiaDynamicLinePtr p,double x,double y,double m)2118 gaiaAppendPointMToDynamicLine (gaiaDynamicLinePtr p, double x, double y,
2119 			       double m)
2120 {
2121 /* inserts a new POINT to this DYNAMIC LINE after the last one */
2122     gaiaPointPtr point = gaiaAllocPointXYM (x, y, m);
2123     point->Prev = p->Last;
2124     if (p->First == NULL)
2125 	p->First = point;
2126     if (p->Last != NULL)
2127 	p->Last->Next = point;
2128     p->Last = point;
2129     return point;
2130 }
2131 
2132 GAIAGEO_DECLARE gaiaPointPtr
gaiaAppendPointZMToDynamicLine(gaiaDynamicLinePtr p,double x,double y,double z,double m)2133 gaiaAppendPointZMToDynamicLine (gaiaDynamicLinePtr p, double x, double y,
2134 				double z, double m)
2135 {
2136 /* inserts a new POINT to this DYNAMIC LINE after the last one */
2137     gaiaPointPtr point = gaiaAllocPointXYZM (x, y, z, m);
2138     point->Prev = p->Last;
2139     if (p->First == NULL)
2140 	p->First = point;
2141     if (p->Last != NULL)
2142 	p->Last->Next = point;
2143     p->Last = point;
2144     return point;
2145 }
2146 
2147 GAIAGEO_DECLARE gaiaPointPtr
gaiaPrependPointToDynamicLine(gaiaDynamicLinePtr p,double x,double y)2148 gaiaPrependPointToDynamicLine (gaiaDynamicLinePtr p, double x, double y)
2149 {
2150 /* inserts a new POINT to this DYNAMIC LINE before the first one */
2151     gaiaPointPtr point = gaiaAllocPoint (x, y);
2152     point->Next = p->First;
2153     if (p->Last == NULL)
2154 	p->Last = point;
2155     if (p->First != NULL)
2156 	p->First->Prev = point;
2157     p->First = point;
2158     return point;
2159 }
2160 
2161 GAIAGEO_DECLARE gaiaPointPtr
gaiaPrependPointZToDynamicLine(gaiaDynamicLinePtr p,double x,double y,double z)2162 gaiaPrependPointZToDynamicLine (gaiaDynamicLinePtr p, double x, double y,
2163 				double z)
2164 {
2165 /* inserts a new POINT to this DYNAMIC LINE before the first one */
2166     gaiaPointPtr point = gaiaAllocPointXYZ (x, y, z);
2167     point->Next = p->First;
2168     if (p->Last == NULL)
2169 	p->Last = point;
2170     if (p->First != NULL)
2171 	p->First->Prev = point;
2172     p->First = point;
2173     return point;
2174 }
2175 
2176 GAIAGEO_DECLARE gaiaPointPtr
gaiaPrependPointMToDynamicLine(gaiaDynamicLinePtr p,double x,double y,double m)2177 gaiaPrependPointMToDynamicLine (gaiaDynamicLinePtr p, double x, double y,
2178 				double m)
2179 {
2180 /* inserts a new POINT to this DYNAMIC LINE before the first one */
2181     gaiaPointPtr point = gaiaAllocPointXYM (x, y, m);
2182     point->Next = p->First;
2183     if (p->Last == NULL)
2184 	p->Last = point;
2185     if (p->First != NULL)
2186 	p->First->Prev = point;
2187     p->First = point;
2188     return point;
2189 }
2190 
2191 GAIAGEO_DECLARE gaiaPointPtr
gaiaPrependPointZMToDynamicLine(gaiaDynamicLinePtr p,double x,double y,double z,double m)2192 gaiaPrependPointZMToDynamicLine (gaiaDynamicLinePtr p, double x, double y,
2193 				 double z, double m)
2194 {
2195 /* inserts a new POINT to this DYNAMIC LINE before the first one */
2196     gaiaPointPtr point = gaiaAllocPointXYZM (x, y, z, m);
2197     point->Next = p->First;
2198     if (p->Last == NULL)
2199 	p->Last = point;
2200     if (p->First != NULL)
2201 	p->First->Prev = point;
2202     p->First = point;
2203     return point;
2204 }
2205 
2206 GAIAGEO_DECLARE gaiaPointPtr
gaiaDynamicLineInsertAfter(gaiaDynamicLinePtr p,gaiaPointPtr pt,double x,double y)2207 gaiaDynamicLineInsertAfter (gaiaDynamicLinePtr p, gaiaPointPtr pt, double x,
2208 			    double y)
2209 {
2210 /* inserts a new POINT to this DYNAMIC LINE after the referenced POINT */
2211     gaiaPointPtr point = gaiaAllocPoint (x, y);
2212     point->Prev = pt;
2213     point->Next = pt->Next;
2214     if (pt->Next)
2215 	pt->Next->Prev = point;
2216     pt->Next = point;
2217     if (pt == p->Last)
2218 	p->Last = point;
2219     return point;
2220 }
2221 
2222 GAIAGEO_DECLARE gaiaPointPtr
gaiaDynamicLineInsertBefore(gaiaDynamicLinePtr p,gaiaPointPtr pt,double x,double y)2223 gaiaDynamicLineInsertBefore (gaiaDynamicLinePtr p, gaiaPointPtr pt, double x,
2224 			     double y)
2225 {
2226 /* inserts a new POINT to this DYNAMIC LINE before the referenced POINT */
2227     gaiaPointPtr point = gaiaAllocPoint (x, y);
2228     point->Next = pt;
2229     point->Prev = pt->Prev;
2230     if (pt->Prev)
2231 	pt->Prev->Next = point;
2232     pt->Prev = point;
2233     if (pt == p->First)
2234 	p->First = point;
2235     return point;
2236 }
2237 
2238 GAIAGEO_DECLARE void
gaiaDynamicLineDeletePoint(gaiaDynamicLinePtr p,gaiaPointPtr pt)2239 gaiaDynamicLineDeletePoint (gaiaDynamicLinePtr p, gaiaPointPtr pt)
2240 {
2241 /* deletes a POINT from this DYNAMIC LINE */
2242     if (pt->Prev)
2243 	pt->Prev->Next = pt->Next;
2244     if (pt->Next)
2245 	pt->Next->Prev = pt->Prev;
2246     if (pt == p->First)
2247 	p->First = pt->Next;
2248     if (pt == p->Last)
2249 	p->Last = pt->Prev;
2250     gaiaFreePoint (pt);
2251 }
2252 
2253 GAIAGEO_DECLARE gaiaDynamicLinePtr
gaiaCloneDynamicLine(gaiaDynamicLinePtr org)2254 gaiaCloneDynamicLine (gaiaDynamicLinePtr org)
2255 {
2256 /* creates a new line obtained by simply copying the current one */
2257     gaiaPointPtr pt;
2258     gaiaDynamicLinePtr dst = gaiaAllocDynamicLine ();
2259     pt = org->First;
2260     while (pt)
2261       {
2262 	  gaiaAppendPointToDynamicLine (dst, pt->X, pt->Y);
2263 	  pt = pt->Next;
2264       }
2265     return dst;
2266 }
2267 
2268 GAIAGEO_DECLARE gaiaDynamicLinePtr
gaiaReverseDynamicLine(gaiaDynamicLinePtr org)2269 gaiaReverseDynamicLine (gaiaDynamicLinePtr org)
2270 {
2271 /* creates a new line obtained by inverting the current one */
2272     gaiaPointPtr pt;
2273     gaiaDynamicLinePtr dst = gaiaAllocDynamicLine ();
2274     pt = org->Last;
2275     while (pt)
2276       {
2277 	  gaiaAppendPointToDynamicLine (dst, pt->X, pt->Y);
2278 	  pt = pt->Prev;
2279       }
2280     return dst;
2281 }
2282 
2283 GAIAGEO_DECLARE gaiaDynamicLinePtr
gaiaDynamicLineSplitBefore(gaiaDynamicLinePtr org,gaiaPointPtr point)2284 gaiaDynamicLineSplitBefore (gaiaDynamicLinePtr org, gaiaPointPtr point)
2285 {
2286 /* creates a new line obtained by cutting the current one in two */
2287     gaiaDynamicLinePtr dst = gaiaAllocDynamicLine ();
2288     dst->First = org->First;
2289     dst->Last = point->Prev;
2290     point->Prev->Next = NULL;
2291     org->First = point;
2292     point->Prev = NULL;
2293     return dst;
2294 }
2295 
2296 GAIAGEO_DECLARE gaiaDynamicLinePtr
gaiaDynamicLineSplitAfter(gaiaDynamicLinePtr org,gaiaPointPtr point)2297 gaiaDynamicLineSplitAfter (gaiaDynamicLinePtr org, gaiaPointPtr point)
2298 {
2299 /* creates a new line obtained by cutting the current one in two */
2300     gaiaDynamicLinePtr dst = gaiaAllocDynamicLine ();
2301     dst->First = point->Next;
2302     dst->Last = org->Last;
2303     point->Next->Prev = NULL;
2304     org->Last = point;
2305     point->Next = NULL;
2306     return dst;
2307 }
2308 
2309 GAIAGEO_DECLARE gaiaDynamicLinePtr
gaiaDynamicLineJoinAfter(gaiaDynamicLinePtr org,gaiaPointPtr point,gaiaDynamicLinePtr toJoin)2310 gaiaDynamicLineJoinAfter (gaiaDynamicLinePtr org, gaiaPointPtr point,
2311 			  gaiaDynamicLinePtr toJoin)
2312 {
2313 /* creates a new line obtained by joining the current one with another one */
2314     gaiaPointPtr pt;
2315     gaiaDynamicLinePtr dst = gaiaAllocDynamicLine ();
2316     pt = org->First;
2317     while (pt)
2318       {
2319 	  /* inserting the first slice since the delimiting POINT included */
2320 	  gaiaAppendPointToDynamicLine (dst, pt->X, pt->Y);
2321 	  if (pt == point)
2322 	      break;
2323 	  pt = pt->Next;
2324       }
2325     pt = toJoin->First;
2326     while (pt)
2327       {
2328 	  /* inserting the other line */
2329 	  gaiaAppendPointToDynamicLine (dst, pt->X, pt->Y);
2330 	  pt = pt->Next;
2331       }
2332     pt = point->Next;
2333     while (pt)
2334       {
2335 	  /* inserting the second slice after the delimiting POINT */
2336 	  gaiaAppendPointToDynamicLine (dst, pt->X, pt->Y);
2337 	  pt = pt->Next;
2338       }
2339     return dst;
2340 }
2341 
2342 GAIAGEO_DECLARE gaiaDynamicLinePtr
gaiaDynamicLineJoinBefore(gaiaDynamicLinePtr org,gaiaPointPtr point,gaiaDynamicLinePtr toJoin)2343 gaiaDynamicLineJoinBefore (gaiaDynamicLinePtr org, gaiaPointPtr point,
2344 			   gaiaDynamicLinePtr toJoin)
2345 {
2346 /* creates a new line obtained by joining the current one with another one */
2347     gaiaPointPtr pt;
2348     gaiaDynamicLinePtr dst = gaiaAllocDynamicLine ();
2349     pt = org->First;
2350     while (pt)
2351       {
2352 	  /* inserting the first slice since the delimiting POINT excluded */
2353 	  if (pt == point)
2354 	      break;
2355 	  gaiaAppendPointToDynamicLine (dst, pt->X, pt->Y);
2356 	  pt = pt->Next;
2357       }
2358     pt = toJoin->First;
2359     while (pt)
2360       {
2361 	  /* inserting the other line */
2362 	  gaiaAppendPointToDynamicLine (dst, pt->X, pt->Y);
2363 	  pt = pt->Next;
2364       }
2365     pt = point;
2366     while (pt)
2367       {
2368 	  /* inserting the second slice beginning from the delimiting POINT */
2369 	  gaiaAppendPointToDynamicLine (dst, pt->X, pt->Y);
2370 	  pt = pt->Next;
2371       }
2372     return dst;
2373 }
2374 
2375 GAIAGEO_DECLARE gaiaPointPtr
gaiaDynamicLineFindByCoords(gaiaDynamicLinePtr p,double x,double y)2376 gaiaDynamicLineFindByCoords (gaiaDynamicLinePtr p, double x, double y)
2377 {
2378 /* finds a POINT inside this DYNAMIC LINE */
2379     gaiaPointPtr pP;
2380     pP = p->First;
2381     while (pP != NULL)
2382       {
2383 	  if (pP->X == x && pP->Y == y)
2384 	      return pP;
2385 	  pP = pP->Next;
2386       }
2387     return NULL;
2388 }
2389 
2390 GAIAGEO_DECLARE gaiaPointPtr
gaiaDynamicLineFindByPos(gaiaDynamicLinePtr p,int pos)2391 gaiaDynamicLineFindByPos (gaiaDynamicLinePtr p, int pos)
2392 {
2393 /* finds a POINT inside this DYNAMIC LINE */
2394     int n = 0;
2395     gaiaPointPtr pP;
2396     pP = p->First;
2397     while (pP != NULL)
2398       {
2399 	  if (pos == n)
2400 	      return pP;
2401 	  n++;
2402 	  pP = pP->Next;
2403       }
2404     return NULL;
2405 }
2406 
2407 GAIAGEO_DECLARE gaiaDynamicLinePtr
gaiaCreateDynamicLine(double * coords,int points)2408 gaiaCreateDynamicLine (double *coords, int points)
2409 {
2410 /* creates a DynamicLine from an array of coordinates */
2411     int iv;
2412     double x;
2413     double y;
2414     gaiaDynamicLinePtr line = gaiaAllocDynamicLine ();
2415     for (iv = 0; iv < points; iv++)
2416       {
2417 	  gaiaGetPoint (coords, iv, &x, &y);
2418 	  gaiaAppendPointToDynamicLine (line, x, y);
2419       }
2420     return line;
2421 }
2422 
2423 GAIAGEO_DECLARE void
gaiaMbrLinestring(gaiaLinestringPtr line)2424 gaiaMbrLinestring (gaiaLinestringPtr line)
2425 {
2426 /* computes the MBR for this linestring */
2427     int iv;
2428     double x;
2429     double y;
2430     double z;
2431     double m;
2432     line->MinX = DBL_MAX;
2433     line->MinY = DBL_MAX;
2434     line->MaxX = -DBL_MAX;
2435     line->MaxY = -DBL_MAX;
2436     for (iv = 0; iv < line->Points; iv++)
2437       {
2438 	  if (line->DimensionModel == GAIA_XY_Z)
2439 	    {
2440 		gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2441 	    }
2442 	  else if (line->DimensionModel == GAIA_XY_M)
2443 	    {
2444 		gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
2445 	    }
2446 	  else if (line->DimensionModel == GAIA_XY_Z_M)
2447 	    {
2448 		gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
2449 	    }
2450 	  else
2451 	    {
2452 		gaiaGetPoint (line->Coords, iv, &x, &y);
2453 	    }
2454 	  if (x < line->MinX)
2455 	      line->MinX = x;
2456 	  if (y < line->MinY)
2457 	      line->MinY = y;
2458 	  if (x > line->MaxX)
2459 	      line->MaxX = x;
2460 	  if (y > line->MaxY)
2461 	      line->MaxY = y;
2462       }
2463 }
2464 
2465 GAIAGEO_DECLARE void
gaiaMbrRing(gaiaRingPtr rng)2466 gaiaMbrRing (gaiaRingPtr rng)
2467 {
2468 /* computes the MBR for this ring */
2469     int iv;
2470     double x;
2471     double y;
2472     double z;
2473     double m;
2474     rng->MinX = DBL_MAX;
2475     rng->MinY = DBL_MAX;
2476     rng->MaxX = -DBL_MAX;
2477     rng->MaxY = -DBL_MAX;
2478     for (iv = 0; iv < rng->Points; iv++)
2479       {
2480 	  if (rng->DimensionModel == GAIA_XY_Z)
2481 	    {
2482 		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2483 	    }
2484 	  else if (rng->DimensionModel == GAIA_XY_M)
2485 	    {
2486 		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2487 	    }
2488 	  else if (rng->DimensionModel == GAIA_XY_Z_M)
2489 	    {
2490 		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2491 	    }
2492 	  else
2493 	    {
2494 		gaiaGetPoint (rng->Coords, iv, &x, &y);
2495 	    }
2496 	  if (x < rng->MinX)
2497 	      rng->MinX = x;
2498 	  if (y < rng->MinY)
2499 	      rng->MinY = y;
2500 	  if (x > rng->MaxX)
2501 	      rng->MaxX = x;
2502 	  if (y > rng->MaxY)
2503 	      rng->MaxY = y;
2504       }
2505 }
2506 
2507 GAIAGEO_DECLARE void
gaiaMbrPolygon(gaiaPolygonPtr polyg)2508 gaiaMbrPolygon (gaiaPolygonPtr polyg)
2509 {
2510 /* computes the MBR for this polygon */
2511     gaiaRingPtr rng;
2512     polyg->MinX = DBL_MAX;
2513     polyg->MinY = DBL_MAX;
2514     polyg->MaxX = -DBL_MAX;
2515     polyg->MaxY = -DBL_MAX;
2516     rng = polyg->Exterior;
2517     gaiaMbrRing (rng);
2518     if (rng->MinX < polyg->MinX)
2519 	polyg->MinX = rng->MinX;
2520     if (rng->MinY < polyg->MinY)
2521 	polyg->MinY = rng->MinY;
2522     if (rng->MaxX > polyg->MaxX)
2523 	polyg->MaxX = rng->MaxX;
2524     if (rng->MaxY > polyg->MaxY)
2525 	polyg->MaxY = rng->MaxY;
2526 }
2527 
2528 GAIAGEO_DECLARE void
gaiaMbrGeometry(gaiaGeomCollPtr geom)2529 gaiaMbrGeometry (gaiaGeomCollPtr geom)
2530 {
2531 /* computes the MBR for this geometry */
2532     gaiaPointPtr point = NULL;
2533     gaiaLinestringPtr line = NULL;
2534     gaiaPolygonPtr polyg = NULL;
2535     geom->MinX = DBL_MAX;
2536     geom->MinY = DBL_MAX;
2537     geom->MaxX = -DBL_MAX;
2538     geom->MaxY = -DBL_MAX;
2539     point = geom->FirstPoint;
2540     while (point)
2541       {
2542 	  if (point->X < geom->MinX)
2543 	      geom->MinX = point->X;
2544 	  if (point->Y < geom->MinY)
2545 	      geom->MinY = point->Y;
2546 	  if (point->X > geom->MaxX)
2547 	      geom->MaxX = point->X;
2548 	  if (point->Y > geom->MaxY)
2549 	      geom->MaxY = point->Y;
2550 	  point = point->Next;
2551       }
2552     line = geom->FirstLinestring;
2553     while (line)
2554       {
2555 	  gaiaMbrLinestring (line);
2556 	  if (line->MinX < geom->MinX)
2557 	      geom->MinX = line->MinX;
2558 	  if (line->MinY < geom->MinY)
2559 	      geom->MinY = line->MinY;
2560 	  if (line->MaxX > geom->MaxX)
2561 	      geom->MaxX = line->MaxX;
2562 	  if (line->MaxY > geom->MaxY)
2563 	      geom->MaxY = line->MaxY;
2564 	  line = line->Next;
2565       }
2566     polyg = geom->FirstPolygon;
2567     while (polyg)
2568       {
2569 	  gaiaMbrPolygon (polyg);
2570 	  if (polyg->MinX < geom->MinX)
2571 	      geom->MinX = polyg->MinX;
2572 	  if (polyg->MinY < geom->MinY)
2573 	      geom->MinY = polyg->MinY;
2574 	  if (polyg->MaxX > geom->MaxX)
2575 	      geom->MaxX = polyg->MaxX;
2576 	  if (polyg->MaxY > geom->MaxY)
2577 	      geom->MaxY = polyg->MaxY;
2578 	  polyg = polyg->Next;
2579       }
2580 }
2581 
2582 GAIAGEO_DECLARE void
gaiaMRangeLinestring(gaiaLinestringPtr line,double * min,double * max)2583 gaiaMRangeLinestring (gaiaLinestringPtr line, double *min, double *max)
2584 {
2585 /* computes the M-range [min/max] for this linestring */
2586     int iv;
2587     double x;
2588     double y;
2589     double z;
2590     double m;
2591     *min = DBL_MAX;
2592     *max = -DBL_MAX;
2593     for (iv = 0; iv < line->Points; iv++)
2594       {
2595 	  m = 0.0;
2596 	  if (line->DimensionModel == GAIA_XY_Z)
2597 	    {
2598 		gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2599 	    }
2600 	  else if (line->DimensionModel == GAIA_XY_M)
2601 	    {
2602 		gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
2603 	    }
2604 	  else if (line->DimensionModel == GAIA_XY_Z_M)
2605 	    {
2606 		gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
2607 	    }
2608 	  else
2609 	    {
2610 		gaiaGetPoint (line->Coords, iv, &x, &y);
2611 	    }
2612 	  if (m < *min)
2613 	      *min = m;
2614 	  if (m > *max)
2615 	      *max = m;
2616       }
2617 }
2618 
2619 GAIAGEO_DECLARE void
gaiaMRangeLinestringEx(gaiaLinestringPtr line,double nodata,double * min,double * max)2620 gaiaMRangeLinestringEx (gaiaLinestringPtr line, double nodata, double *min,
2621 			double *max)
2622 {
2623 /* computes the M-range [min/max] for this linestring (NODATA flavor) */
2624     int iv;
2625     double x;
2626     double y;
2627     double z;
2628     double m;
2629     *min = DBL_MAX;
2630     *max = -DBL_MAX;
2631     for (iv = 0; iv < line->Points; iv++)
2632       {
2633 	  m = 0.0;
2634 	  if (line->DimensionModel == GAIA_XY_Z)
2635 	    {
2636 		gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2637 	    }
2638 	  else if (line->DimensionModel == GAIA_XY_M)
2639 	    {
2640 		gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
2641 	    }
2642 	  else if (line->DimensionModel == GAIA_XY_Z_M)
2643 	    {
2644 		gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
2645 	    }
2646 	  else
2647 	    {
2648 		gaiaGetPoint (line->Coords, iv, &x, &y);
2649 	    }
2650 	  if (m == nodata)
2651 	      continue;
2652 	  if (m < *min)
2653 	      *min = m;
2654 	  if (m > *max)
2655 	      *max = m;
2656       }
2657 }
2658 
2659 GAIAGEO_DECLARE void
gaiaMRangeRing(gaiaRingPtr rng,double * min,double * max)2660 gaiaMRangeRing (gaiaRingPtr rng, double *min, double *max)
2661 {
2662 /* computes the M-range [min/max] for this ring */
2663     int iv;
2664     double x;
2665     double y;
2666     double z;
2667     double m;
2668     *min = DBL_MAX;
2669     *max = -DBL_MAX;
2670     for (iv = 0; iv < rng->Points; iv++)
2671       {
2672 	  m = 0.0;
2673 	  if (rng->DimensionModel == GAIA_XY_Z)
2674 	    {
2675 		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2676 	    }
2677 	  else if (rng->DimensionModel == GAIA_XY_M)
2678 	    {
2679 		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2680 	    }
2681 	  else if (rng->DimensionModel == GAIA_XY_Z_M)
2682 	    {
2683 		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2684 	    }
2685 	  else
2686 	    {
2687 		gaiaGetPoint (rng->Coords, iv, &x, &y);
2688 	    }
2689 	  if (m < *min)
2690 	      *min = m;
2691 	  if (m > *max)
2692 	      *max = m;
2693       }
2694 }
2695 
2696 GAIAGEO_DECLARE void
gaiaMRangeRingEx(gaiaRingPtr rng,double nodata,double * min,double * max)2697 gaiaMRangeRingEx (gaiaRingPtr rng, double nodata, double *min, double *max)
2698 {
2699 /* computes the M-range [min/max] for this ring (NODATA flavor) */
2700     int iv;
2701     double x;
2702     double y;
2703     double z;
2704     double m;
2705     *min = DBL_MAX;
2706     *max = -DBL_MAX;
2707     for (iv = 0; iv < rng->Points; iv++)
2708       {
2709 	  m = 0.0;
2710 	  if (rng->DimensionModel == GAIA_XY_Z)
2711 	    {
2712 		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2713 	    }
2714 	  else if (rng->DimensionModel == GAIA_XY_M)
2715 	    {
2716 		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2717 	    }
2718 	  else if (rng->DimensionModel == GAIA_XY_Z_M)
2719 	    {
2720 		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2721 	    }
2722 	  else
2723 	    {
2724 		gaiaGetPoint (rng->Coords, iv, &x, &y);
2725 	    }
2726 	  if (m == nodata)
2727 	      continue;
2728 	  if (m < *min)
2729 	      *min = m;
2730 	  if (m > *max)
2731 	      *max = m;
2732       }
2733 }
2734 
2735 GAIAGEO_DECLARE void
gaiaMRangePolygon(gaiaPolygonPtr polyg,double * min,double * max)2736 gaiaMRangePolygon (gaiaPolygonPtr polyg, double *min, double *max)
2737 {
2738 /* computes the M-range [min/max] for this polygon */
2739     gaiaRingPtr rng;
2740     int ib;
2741     double r_min;
2742     double r_max;
2743     *min = DBL_MAX;
2744     *max = -DBL_MAX;
2745     rng = polyg->Exterior;
2746     gaiaMRangeRing (rng, &r_min, &r_max);
2747     if (r_min < *min)
2748 	*min = r_min;
2749     if (r_max > *max)
2750 	*max = r_max;
2751     for (ib = 0; ib < polyg->NumInteriors; ib++)
2752       {
2753 	  rng = polyg->Interiors + ib;
2754 	  gaiaMRangeRing (rng, &r_min, &r_max);
2755 	  if (r_min < *min)
2756 	      *min = r_min;
2757 	  if (r_max > *max)
2758 	      *max = r_max;
2759       }
2760 }
2761 
2762 GAIAGEO_DECLARE void
gaiaMRangePolygonEx(gaiaPolygonPtr polyg,double nodata,double * min,double * max)2763 gaiaMRangePolygonEx (gaiaPolygonPtr polyg, double nodata, double *min,
2764 		     double *max)
2765 {
2766 /* computes the M-range [min/max] for this polygon (NODATA flavor) */
2767     gaiaRingPtr rng;
2768     int ib;
2769     double r_min;
2770     double r_max;
2771     *min = DBL_MAX;
2772     *max = -DBL_MAX;
2773     rng = polyg->Exterior;
2774     gaiaMRangeRingEx (rng, nodata, &r_min, &r_max);
2775     if (r_min < *min)
2776 	*min = r_min;
2777     if (r_max > *max)
2778 	*max = r_max;
2779     for (ib = 0; ib < polyg->NumInteriors; ib++)
2780       {
2781 	  rng = polyg->Interiors + ib;
2782 	  gaiaMRangeRingEx (rng, nodata, &r_min, &r_max);
2783 	  if (r_min < *min)
2784 	      *min = r_min;
2785 	  if (r_max > *max)
2786 	      *max = r_max;
2787       }
2788 }
2789 
2790 GAIAGEO_DECLARE void
gaiaMRangeGeometry(gaiaGeomCollPtr geom,double * min,double * max)2791 gaiaMRangeGeometry (gaiaGeomCollPtr geom, double *min, double *max)
2792 {
2793 /* computes the M-range [min/max] for this geometry */
2794     gaiaPointPtr point = NULL;
2795     gaiaLinestringPtr line = NULL;
2796     gaiaPolygonPtr polyg = NULL;
2797     double m;
2798     double r_min;
2799     double r_max;
2800     *min = DBL_MAX;
2801     *max = -DBL_MAX;
2802     point = geom->FirstPoint;
2803     while (point)
2804       {
2805 	  m = 0.0;
2806 	  if (point->DimensionModel == GAIA_XY_M
2807 	      || point->DimensionModel == GAIA_XY_Z_M)
2808 	      m = point->M;
2809 	  if (m < *min)
2810 	      *min = m;
2811 	  if (m > *max)
2812 	      *max = m;
2813 	  point = point->Next;
2814       }
2815     line = geom->FirstLinestring;
2816     while (line)
2817       {
2818 	  gaiaMRangeLinestring (line, &r_min, &r_max);
2819 	  if (r_min < *min)
2820 	      *min = r_min;
2821 	  if (r_max > *max)
2822 	      *max = r_max;
2823 	  line = line->Next;
2824       }
2825     polyg = geom->FirstPolygon;
2826     while (polyg)
2827       {
2828 	  gaiaMRangePolygon (polyg, &r_min, &r_max);
2829 	  if (r_min < *min)
2830 	      *min = r_min;
2831 	  if (r_max > *max)
2832 	      *max = r_max;
2833 	  polyg = polyg->Next;
2834       }
2835 }
2836 
2837 GAIAGEO_DECLARE void
gaiaMRangeGeometryEx(gaiaGeomCollPtr geom,double nodata,double * min,double * max)2838 gaiaMRangeGeometryEx (gaiaGeomCollPtr geom, double nodata, double *min,
2839 		      double *max)
2840 {
2841 /* computes the M-range [min/max] for this geometry */
2842     gaiaPointPtr point = NULL;
2843     gaiaLinestringPtr line = NULL;
2844     gaiaPolygonPtr polyg = NULL;
2845     double m;
2846     double r_min;
2847     double r_max;
2848     *min = DBL_MAX;
2849     *max = -DBL_MAX;
2850     point = geom->FirstPoint;
2851     while (point)
2852       {
2853 	  m = 0.0;
2854 	  if (point->DimensionModel == GAIA_XY_M
2855 	      || point->DimensionModel == GAIA_XY_Z_M)
2856 	      m = point->M;
2857 	  if (m == nodata)
2858 	      continue;
2859 	  if (m < *min)
2860 	      *min = m;
2861 	  if (m > *max)
2862 	      *max = m;
2863 	  point = point->Next;
2864       }
2865     line = geom->FirstLinestring;
2866     while (line)
2867       {
2868 	  gaiaMRangeLinestringEx (line, nodata, &r_min, &r_max);
2869 	  if (r_min < *min)
2870 	      *min = r_min;
2871 	  if (r_max > *max)
2872 	      *max = r_max;
2873 	  line = line->Next;
2874       }
2875     polyg = geom->FirstPolygon;
2876     while (polyg)
2877       {
2878 	  gaiaMRangePolygonEx (polyg, nodata, &r_min, &r_max);
2879 	  if (r_min < *min)
2880 	      *min = r_min;
2881 	  if (r_max > *max)
2882 	      *max = r_max;
2883 	  polyg = polyg->Next;
2884       }
2885 }
2886 
2887 GAIAGEO_DECLARE void
gaiaZRangeLinestring(gaiaLinestringPtr line,double * min,double * max)2888 gaiaZRangeLinestring (gaiaLinestringPtr line, double *min, double *max)
2889 {
2890 /* computes the Z-range [min/max] for this linestring */
2891     int iv;
2892     double x;
2893     double y;
2894     double z;
2895     double m;
2896     *min = DBL_MAX;
2897     *max = -DBL_MAX;
2898     for (iv = 0; iv < line->Points; iv++)
2899       {
2900 	  z = 0.0;
2901 	  m = 0.0;
2902 	  if (line->DimensionModel == GAIA_XY_Z)
2903 	    {
2904 		gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2905 	    }
2906 	  else if (line->DimensionModel == GAIA_XY_M)
2907 	    {
2908 		gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
2909 	    }
2910 	  else if (line->DimensionModel == GAIA_XY_Z_M)
2911 	    {
2912 		gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
2913 	    }
2914 	  else
2915 	    {
2916 		gaiaGetPoint (line->Coords, iv, &x, &y);
2917 	    }
2918 	  if (z < *min)
2919 	      *min = z;
2920 	  if (z > *max)
2921 	      *max = z;
2922       }
2923 }
2924 
2925 GAIAGEO_DECLARE void
gaiaZRangeLinestringEx(gaiaLinestringPtr line,double nodata,double * min,double * max)2926 gaiaZRangeLinestringEx (gaiaLinestringPtr line, double nodata, double *min,
2927 			double *max)
2928 {
2929 /* computes the Z-range [min/max] for this linestring (NODATA flavor) */
2930     int iv;
2931     double x;
2932     double y;
2933     double z;
2934     double m;
2935     *min = DBL_MAX;
2936     *max = -DBL_MAX;
2937     for (iv = 0; iv < line->Points; iv++)
2938       {
2939 	  z = 0.0;
2940 	  m = 0.0;
2941 	  if (line->DimensionModel == GAIA_XY_Z)
2942 	    {
2943 		gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
2944 	    }
2945 	  else if (line->DimensionModel == GAIA_XY_M)
2946 	    {
2947 		gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
2948 	    }
2949 	  else if (line->DimensionModel == GAIA_XY_Z_M)
2950 	    {
2951 		gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
2952 	    }
2953 	  else
2954 	    {
2955 		gaiaGetPoint (line->Coords, iv, &x, &y);
2956 	    }
2957 	  if (z == nodata)
2958 	      continue;
2959 	  if (z < *min)
2960 	      *min = z;
2961 	  if (z > *max)
2962 	      *max = z;
2963       }
2964 }
2965 
2966 GAIAGEO_DECLARE void
gaiaZRangeRing(gaiaRingPtr rng,double * min,double * max)2967 gaiaZRangeRing (gaiaRingPtr rng, double *min, double *max)
2968 {
2969 /* computes the Z-range [min/max] for this ring */
2970     int iv;
2971     double x;
2972     double y;
2973     double z;
2974     double m;
2975     *min = DBL_MAX;
2976     *max = -DBL_MAX;
2977     for (iv = 0; iv < rng->Points; iv++)
2978       {
2979 	  z = 0.0;
2980 	  m = 0.0;
2981 	  if (rng->DimensionModel == GAIA_XY_Z)
2982 	    {
2983 		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
2984 	    }
2985 	  else if (rng->DimensionModel == GAIA_XY_M)
2986 	    {
2987 		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
2988 	    }
2989 	  else if (rng->DimensionModel == GAIA_XY_Z_M)
2990 	    {
2991 		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
2992 	    }
2993 	  else
2994 	    {
2995 		gaiaGetPoint (rng->Coords, iv, &x, &y);
2996 	    }
2997 	  if (z < *min)
2998 	      *min = z;
2999 	  if (z > *max)
3000 	      *max = z;
3001       }
3002 }
3003 
3004 GAIAGEO_DECLARE void
gaiaZRangeRingEx(gaiaRingPtr rng,double nodata,double * min,double * max)3005 gaiaZRangeRingEx (gaiaRingPtr rng, double nodata, double *min, double *max)
3006 {
3007 /* computes the Z-range [min/max] for this ring (NODATA flavor) */
3008     int iv;
3009     double x;
3010     double y;
3011     double z;
3012     double m;
3013     *min = DBL_MAX;
3014     *max = -DBL_MAX;
3015     for (iv = 0; iv < rng->Points; iv++)
3016       {
3017 	  z = 0.0;
3018 	  m = 0.0;
3019 	  if (rng->DimensionModel == GAIA_XY_Z)
3020 	    {
3021 		gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
3022 	    }
3023 	  else if (rng->DimensionModel == GAIA_XY_M)
3024 	    {
3025 		gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
3026 	    }
3027 	  else if (rng->DimensionModel == GAIA_XY_Z_M)
3028 	    {
3029 		gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
3030 	    }
3031 	  else
3032 	    {
3033 		gaiaGetPoint (rng->Coords, iv, &x, &y);
3034 	    }
3035 	  if (z == nodata)
3036 	      continue;
3037 	  if (z < *min)
3038 	      *min = z;
3039 	  if (z > *max)
3040 	      *max = z;
3041       }
3042 }
3043 
3044 GAIAGEO_DECLARE void
gaiaZRangePolygon(gaiaPolygonPtr polyg,double * min,double * max)3045 gaiaZRangePolygon (gaiaPolygonPtr polyg, double *min, double *max)
3046 {
3047 /* computes the Z-range [min/max] for this polygon */
3048     gaiaRingPtr rng;
3049     int ib;
3050     double r_min;
3051     double r_max;
3052     *min = DBL_MAX;
3053     *max = -DBL_MAX;
3054     rng = polyg->Exterior;
3055     gaiaZRangeRing (rng, &r_min, &r_max);
3056     if (r_min < *min)
3057 	*min = r_min;
3058     if (r_max > *max)
3059 	*max = r_max;
3060     for (ib = 0; ib < polyg->NumInteriors; ib++)
3061       {
3062 	  rng = polyg->Interiors + ib;
3063 	  gaiaZRangeRing (rng, &r_min, &r_max);
3064 	  if (r_min < *min)
3065 	      *min = r_min;
3066 	  if (r_max > *max)
3067 	      *max = r_max;
3068       }
3069 }
3070 
3071 GAIAGEO_DECLARE void
gaiaZRangePolygonEx(gaiaPolygonPtr polyg,double nodata,double * min,double * max)3072 gaiaZRangePolygonEx (gaiaPolygonPtr polyg, double nodata, double *min,
3073 		     double *max)
3074 {
3075 /* computes the Z-range [min/max] for this polygon (NODATA flavor) */
3076     gaiaRingPtr rng;
3077     int ib;
3078     double r_min;
3079     double r_max;
3080     *min = DBL_MAX;
3081     *max = -DBL_MAX;
3082     rng = polyg->Exterior;
3083     gaiaZRangeRingEx (rng, nodata, &r_min, &r_max);
3084     if (r_min < *min)
3085 	*min = r_min;
3086     if (r_max > *max)
3087 	*max = r_max;
3088     for (ib = 0; ib < polyg->NumInteriors; ib++)
3089       {
3090 	  rng = polyg->Interiors + ib;
3091 	  gaiaZRangeRingEx (rng, nodata, &r_min, &r_max);
3092 	  if (r_min < *min)
3093 	      *min = r_min;
3094 	  if (r_max > *max)
3095 	      *max = r_max;
3096       }
3097 }
3098 
3099 GAIAGEO_DECLARE void
gaiaZRangeGeometry(gaiaGeomCollPtr geom,double * min,double * max)3100 gaiaZRangeGeometry (gaiaGeomCollPtr geom, double *min, double *max)
3101 {
3102 /* computes the Z-range [min/max] for this geometry */
3103     gaiaPointPtr point = NULL;
3104     gaiaLinestringPtr line = NULL;
3105     gaiaPolygonPtr polyg = NULL;
3106     double z;
3107     double r_min;
3108     double r_max;
3109     *min = DBL_MAX;
3110     *max = -DBL_MAX;
3111     point = geom->FirstPoint;
3112     while (point)
3113       {
3114 	  z = 0.0;
3115 	  if (point->DimensionModel == GAIA_XY_Z
3116 	      || point->DimensionModel == GAIA_XY_Z_M)
3117 	      z = point->Z;
3118 	  if (z < *min)
3119 	      *min = z;
3120 	  if (z > *max)
3121 	      *max = z;
3122 	  point = point->Next;
3123       }
3124     line = geom->FirstLinestring;
3125     while (line)
3126       {
3127 	  gaiaZRangeLinestring (line, &r_min, &r_max);
3128 	  if (r_min < *min)
3129 	      *min = r_min;
3130 	  if (r_max > *max)
3131 	      *max = r_max;
3132 	  line = line->Next;
3133       }
3134     polyg = geom->FirstPolygon;
3135     while (polyg)
3136       {
3137 	  gaiaZRangePolygon (polyg, &r_min, &r_max);
3138 	  if (r_min < *min)
3139 	      *min = r_min;
3140 	  if (r_max > *max)
3141 	      *max = r_max;
3142 	  polyg = polyg->Next;
3143       }
3144 }
3145 
3146 GAIAGEO_DECLARE void
gaiaZRangeGeometryEx(gaiaGeomCollPtr geom,double nodata,double * min,double * max)3147 gaiaZRangeGeometryEx (gaiaGeomCollPtr geom, double nodata, double *min,
3148 		      double *max)
3149 {
3150 /* computes the Z-range [min/max] for this geometry (NODATA flavor) */
3151     gaiaPointPtr point = NULL;
3152     gaiaLinestringPtr line = NULL;
3153     gaiaPolygonPtr polyg = NULL;
3154     double z;
3155     double r_min;
3156     double r_max;
3157     *min = DBL_MAX;
3158     *max = -DBL_MAX;
3159     point = geom->FirstPoint;
3160     while (point)
3161       {
3162 	  z = 0.0;
3163 	  if (point->DimensionModel == GAIA_XY_Z
3164 	      || point->DimensionModel == GAIA_XY_Z_M)
3165 	      z = point->Z;
3166 	  if (z == nodata)
3167 	      continue;
3168 	  if (z < *min)
3169 	      *min = z;
3170 	  if (z > *max)
3171 	      *max = z;
3172 	  point = point->Next;
3173       }
3174     line = geom->FirstLinestring;
3175     while (line)
3176       {
3177 	  gaiaZRangeLinestringEx (line, nodata, &r_min, &r_max);
3178 	  if (r_min < *min)
3179 	      *min = r_min;
3180 	  if (r_max > *max)
3181 	      *max = r_max;
3182 	  line = line->Next;
3183       }
3184     polyg = geom->FirstPolygon;
3185     while (polyg)
3186       {
3187 	  gaiaZRangePolygonEx (polyg, nodata, &r_min, &r_max);
3188 	  if (r_min < *min)
3189 	      *min = r_min;
3190 	  if (r_max > *max)
3191 	      *max = r_max;
3192 	  polyg = polyg->Next;
3193       }
3194 }
3195 
3196 GAIAGEO_DECLARE int
gaiaDimension(gaiaGeomCollPtr geom)3197 gaiaDimension (gaiaGeomCollPtr geom)
3198 {
3199 /* determines the Dimension for this geometry */
3200     gaiaPointPtr point;
3201     gaiaLinestringPtr line;
3202     gaiaPolygonPtr polyg;
3203     int n_points = 0;
3204     int n_linestrings = 0;
3205     int n_polygons = 0;
3206     if (!geom)
3207 	return -1;
3208     point = geom->FirstPoint;
3209     while (point)
3210       {
3211 	  /* counts how many points are there */
3212 	  n_points++;
3213 	  point = point->Next;
3214       }
3215     line = geom->FirstLinestring;
3216     while (line)
3217       {
3218 	  /* counts how many linestrings are there */
3219 	  n_linestrings++;
3220 	  line = line->Next;
3221       }
3222     polyg = geom->FirstPolygon;
3223     while (polyg)
3224       {
3225 	  /* counts how many polygons are there */
3226 	  n_polygons++;
3227 	  polyg = polyg->Next;
3228       }
3229     if (n_points == 0 && n_linestrings == 0 && n_polygons == 0)
3230 	return -1;
3231     if (n_points > 0 && n_linestrings == 0 && n_polygons == 0)
3232 	return 0;
3233     if (n_linestrings > 0 && n_polygons == 0)
3234 	return 1;
3235     return 2;
3236 }
3237 
3238 GAIAGEO_DECLARE int
gaiaGeometryType(gaiaGeomCollPtr geom)3239 gaiaGeometryType (gaiaGeomCollPtr geom)
3240 {
3241 /* determines the Class for this geometry */
3242     gaiaPointPtr point;
3243     gaiaLinestringPtr line;
3244     gaiaPolygonPtr polyg;
3245     gaiaRingPtr ring;
3246     int ib;
3247     int n_points = 0;
3248     int n_linestrings = 0;
3249     int n_polygons = 0;
3250     int dm = GAIA_XY;
3251     if (!geom)
3252 	return GAIA_UNKNOWN;
3253     point = geom->FirstPoint;
3254     while (point)
3255       {
3256 	  /* counts how many points are there */
3257 	  n_points++;
3258 	  if (point->DimensionModel == GAIA_XY_Z)
3259 	    {
3260 		if (dm == GAIA_XY)
3261 		    dm = GAIA_XY_Z;
3262 		else if (dm == GAIA_XY_M)
3263 		    dm = GAIA_XY_Z_M;
3264 	    }
3265 	  else if (point->DimensionModel == GAIA_XY_M)
3266 	    {
3267 		if (dm == GAIA_XY)
3268 		    dm = GAIA_XY_M;
3269 		else if (dm == GAIA_XY_Z)
3270 		    dm = GAIA_XY_Z_M;
3271 	    }
3272 	  else if (point->DimensionModel == GAIA_XY_Z_M)
3273 	      dm = GAIA_XY_Z_M;
3274 	  point = point->Next;
3275       }
3276     line = geom->FirstLinestring;
3277     while (line)
3278       {
3279 	  /* counts how many linestrings are there */
3280 	  n_linestrings++;
3281 	  if (line->DimensionModel == GAIA_XY_Z)
3282 	    {
3283 		if (dm == GAIA_XY)
3284 		    dm = GAIA_XY_Z;
3285 		else if (dm == GAIA_XY_M)
3286 		    dm = GAIA_XY_Z_M;
3287 	    }
3288 	  else if (line->DimensionModel == GAIA_XY_M)
3289 	    {
3290 		if (dm == GAIA_XY)
3291 		    dm = GAIA_XY_M;
3292 		else if (dm == GAIA_XY_Z)
3293 		    dm = GAIA_XY_Z_M;
3294 	    }
3295 	  else if (line->DimensionModel == GAIA_XY_Z_M)
3296 	      dm = GAIA_XY_Z_M;
3297 	  line = line->Next;
3298       }
3299     polyg = geom->FirstPolygon;
3300     while (polyg)
3301       {
3302 	  /* counts how many polygons are there */
3303 	  n_polygons++;
3304 	  ring = polyg->Exterior;
3305 	  if (ring->DimensionModel == GAIA_XY_Z)
3306 	    {
3307 		if (dm == GAIA_XY)
3308 		    dm = GAIA_XY_Z;
3309 		else if (dm == GAIA_XY_M)
3310 		    dm = GAIA_XY_Z_M;
3311 	    }
3312 	  else if (ring->DimensionModel == GAIA_XY_M)
3313 	    {
3314 		if (dm == GAIA_XY)
3315 		    dm = GAIA_XY_M;
3316 		else if (dm == GAIA_XY_Z)
3317 		    dm = GAIA_XY_Z_M;
3318 	    }
3319 	  else if (ring->DimensionModel == GAIA_XY_Z_M)
3320 	      dm = GAIA_XY_Z_M;
3321 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
3322 	    {
3323 		ring = polyg->Interiors + ib;
3324 		if (ring->DimensionModel == GAIA_XY_Z)
3325 		  {
3326 		      if (dm == GAIA_XY)
3327 			  dm = GAIA_XY_Z;
3328 		      else if (dm == GAIA_XY_M)
3329 			  dm = GAIA_XY_Z_M;
3330 		  }
3331 		else if (ring->DimensionModel == GAIA_XY_M)
3332 		  {
3333 		      if (dm == GAIA_XY)
3334 			  dm = GAIA_XY_M;
3335 		      else if (dm == GAIA_XY_Z)
3336 			  dm = GAIA_XY_Z_M;
3337 		  }
3338 		else if (ring->DimensionModel == GAIA_XY_Z_M)
3339 		    dm = GAIA_XY_Z_M;
3340 	    }
3341 	  polyg = polyg->Next;
3342       }
3343     if (n_points == 0 && n_linestrings == 0 && n_polygons == 0)
3344 	return GAIA_UNKNOWN;
3345     if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
3346       {
3347 	  if (geom->DeclaredType == GAIA_MULTIPOINT)
3348 	    {
3349 		if (dm == GAIA_XY_Z)
3350 		    return GAIA_MULTIPOINTZ;
3351 		if (dm == GAIA_XY_M)
3352 		    return GAIA_MULTIPOINTM;
3353 		if (dm == GAIA_XY_Z_M)
3354 		    return GAIA_MULTIPOINTZM;
3355 		else
3356 		    return GAIA_MULTIPOINT;
3357 	    }
3358 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3359 	    {
3360 		if (dm == GAIA_XY_Z)
3361 		    return GAIA_GEOMETRYCOLLECTIONZ;
3362 		if (dm == GAIA_XY_M)
3363 		    return GAIA_GEOMETRYCOLLECTIONM;
3364 		if (dm == GAIA_XY_Z_M)
3365 		    return GAIA_GEOMETRYCOLLECTIONZM;
3366 		else
3367 		    return GAIA_GEOMETRYCOLLECTION;
3368 	    }
3369 	  else
3370 	    {
3371 		if (dm == GAIA_XY_Z)
3372 		    return GAIA_POINTZ;
3373 		if (dm == GAIA_XY_M)
3374 		    return GAIA_POINTM;
3375 		if (dm == GAIA_XY_Z_M)
3376 		    return GAIA_POINTZM;
3377 		else
3378 		    return GAIA_POINT;
3379 	    }
3380       }
3381     if (n_points > 0 && n_linestrings == 0 && n_polygons == 0)
3382       {
3383 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3384 	    {
3385 		if (dm == GAIA_XY_Z)
3386 		    return GAIA_GEOMETRYCOLLECTIONZ;
3387 		if (dm == GAIA_XY_M)
3388 		    return GAIA_GEOMETRYCOLLECTIONM;
3389 		if (dm == GAIA_XY_Z_M)
3390 		    return GAIA_GEOMETRYCOLLECTIONZM;
3391 		else
3392 		    return GAIA_GEOMETRYCOLLECTION;
3393 	    }
3394 	  else
3395 	    {
3396 		if (dm == GAIA_XY_Z)
3397 		    return GAIA_MULTIPOINTZ;
3398 		if (dm == GAIA_XY_M)
3399 		    return GAIA_MULTIPOINTM;
3400 		if (dm == GAIA_XY_Z_M)
3401 		    return GAIA_MULTIPOINTZM;
3402 		else
3403 		    return GAIA_MULTIPOINT;
3404 	    }
3405       }
3406     if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
3407       {
3408 	  if (geom->DeclaredType == GAIA_MULTILINESTRING)
3409 	    {
3410 		if (dm == GAIA_XY_Z)
3411 		    return GAIA_MULTILINESTRINGZ;
3412 		if (dm == GAIA_XY_M)
3413 		    return GAIA_MULTILINESTRINGM;
3414 		if (dm == GAIA_XY_Z_M)
3415 		    return GAIA_MULTILINESTRINGZM;
3416 		else
3417 		    return GAIA_MULTILINESTRING;
3418 	    }
3419 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3420 	    {
3421 		if (dm == GAIA_XY_Z)
3422 		    return GAIA_GEOMETRYCOLLECTIONZ;
3423 		if (dm == GAIA_XY_M)
3424 		    return GAIA_GEOMETRYCOLLECTIONM;
3425 		if (dm == GAIA_XY_Z_M)
3426 		    return GAIA_GEOMETRYCOLLECTIONZM;
3427 		else
3428 		    return GAIA_GEOMETRYCOLLECTION;
3429 	    }
3430 	  else
3431 	    {
3432 		if (dm == GAIA_XY_Z)
3433 		    return GAIA_LINESTRINGZ;
3434 		if (dm == GAIA_XY_M)
3435 		    return GAIA_LINESTRINGM;
3436 		if (dm == GAIA_XY_Z_M)
3437 		    return GAIA_LINESTRINGZM;
3438 		else
3439 		    return GAIA_LINESTRING;
3440 	    }
3441       }
3442     if (n_points == 0 && n_linestrings > 0 && n_polygons == 0)
3443       {
3444 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3445 	    {
3446 		if (dm == GAIA_XY_Z)
3447 		    return GAIA_GEOMETRYCOLLECTIONZ;
3448 		if (dm == GAIA_XY_M)
3449 		    return GAIA_GEOMETRYCOLLECTIONM;
3450 		if (dm == GAIA_XY_Z_M)
3451 		    return GAIA_GEOMETRYCOLLECTIONZM;
3452 		else
3453 		    return GAIA_GEOMETRYCOLLECTION;
3454 	    }
3455 	  else
3456 	    {
3457 		if (dm == GAIA_XY_Z)
3458 		    return GAIA_MULTILINESTRINGZ;
3459 		if (dm == GAIA_XY_M)
3460 		    return GAIA_MULTILINESTRINGM;
3461 		if (dm == GAIA_XY_Z_M)
3462 		    return GAIA_MULTILINESTRINGZM;
3463 		else
3464 		    return GAIA_MULTILINESTRING;
3465 	    }
3466       }
3467     if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
3468       {
3469 	  if (geom->DeclaredType == GAIA_MULTIPOLYGON)
3470 	    {
3471 		if (dm == GAIA_XY_Z)
3472 		    return GAIA_MULTIPOLYGONZ;
3473 		if (dm == GAIA_XY_M)
3474 		    return GAIA_MULTIPOLYGONM;
3475 		if (dm == GAIA_XY_Z_M)
3476 		    return GAIA_MULTIPOLYGONZM;
3477 		else
3478 		    return GAIA_MULTIPOLYGON;
3479 	    }
3480 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3481 	    {
3482 		if (dm == GAIA_XY_Z)
3483 		    return GAIA_GEOMETRYCOLLECTIONZ;
3484 		if (dm == GAIA_XY_M)
3485 		    return GAIA_GEOMETRYCOLLECTIONM;
3486 		if (dm == GAIA_XY_Z_M)
3487 		    return GAIA_GEOMETRYCOLLECTIONZM;
3488 		else
3489 		    return GAIA_GEOMETRYCOLLECTION;
3490 	    }
3491 	  else
3492 	    {
3493 		if (dm == GAIA_XY_Z)
3494 		    return GAIA_POLYGONZ;
3495 		if (dm == GAIA_XY_M)
3496 		    return GAIA_POLYGONM;
3497 		if (dm == GAIA_XY_Z_M)
3498 		    return GAIA_POLYGONZM;
3499 		else
3500 		    return GAIA_POLYGON;
3501 	    }
3502       }
3503     if (n_points == 0 && n_linestrings == 0 && n_polygons > 0)
3504       {
3505 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3506 	    {
3507 		if (dm == GAIA_XY_Z)
3508 		    return GAIA_GEOMETRYCOLLECTIONZ;
3509 		if (dm == GAIA_XY_M)
3510 		    return GAIA_GEOMETRYCOLLECTIONM;
3511 		if (dm == GAIA_XY_Z_M)
3512 		    return GAIA_GEOMETRYCOLLECTIONZM;
3513 		else
3514 		    return GAIA_GEOMETRYCOLLECTION;
3515 	    }
3516 	  else
3517 	    {
3518 		if (dm == GAIA_XY_Z)
3519 		    return GAIA_MULTIPOLYGONZ;
3520 		if (dm == GAIA_XY_M)
3521 		    return GAIA_MULTIPOLYGONM;
3522 		if (dm == GAIA_XY_Z_M)
3523 		    return GAIA_MULTIPOLYGONZM;
3524 		else
3525 		    return GAIA_MULTIPOLYGON;
3526 	    }
3527       }
3528     if (dm == GAIA_XY_Z)
3529 	return GAIA_GEOMETRYCOLLECTIONZ;
3530     if (dm == GAIA_XY_M)
3531 	return GAIA_GEOMETRYCOLLECTIONM;
3532     if (dm == GAIA_XY_Z_M)
3533 	return GAIA_GEOMETRYCOLLECTIONZM;
3534     else
3535 	return GAIA_GEOMETRYCOLLECTION;
3536 }
3537 
3538 GAIAGEO_DECLARE int
gaiaGeometryAliasType(gaiaGeomCollPtr geom)3539 gaiaGeometryAliasType (gaiaGeomCollPtr geom)
3540 {
3541 /* determines the AliasClass for this geometry */
3542     gaiaPointPtr point;
3543     gaiaLinestringPtr line;
3544     gaiaPolygonPtr polyg;
3545     int n_points = 0;
3546     int n_linestrings = 0;
3547     int n_polygons = 0;
3548     if (!geom)
3549 	return GAIA_UNKNOWN;
3550     point = geom->FirstPoint;
3551     while (point)
3552       {
3553 	  /* counts how many points are there */
3554 	  n_points++;
3555 	  point = point->Next;
3556       }
3557     line = geom->FirstLinestring;
3558     while (line)
3559       {
3560 	  /* counts how many linestrings are there */
3561 	  n_linestrings++;
3562 	  line = line->Next;
3563       }
3564     polyg = geom->FirstPolygon;
3565     while (polyg)
3566       {
3567 	  /* counts how many polygons are there */
3568 	  n_polygons++;
3569 	  polyg = polyg->Next;
3570       }
3571     if (n_points == 0 && n_linestrings == 0 && n_polygons == 0)
3572 	return GAIA_UNKNOWN;
3573     if (n_points == 1 && n_linestrings == 0 && n_polygons == 0)
3574       {
3575 	  if (geom->DeclaredType == GAIA_MULTIPOINT)
3576 	      return GAIA_MULTIPOINT;
3577 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3578 	      return GAIA_GEOMETRYCOLLECTION;
3579 	  else
3580 	      return GAIA_POINT;
3581       }
3582     if (n_points >= 1 && n_linestrings == 0 && n_polygons == 0)
3583       {
3584 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3585 	      return GAIA_GEOMETRYCOLLECTION;
3586 	  else
3587 	      return GAIA_MULTIPOINT;
3588       }
3589     if (n_points == 0 && n_linestrings == 1 && n_polygons == 0)
3590       {
3591 	  if (geom->DeclaredType == GAIA_MULTILINESTRING)
3592 	      return GAIA_MULTILINESTRING;
3593 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3594 	      return GAIA_GEOMETRYCOLLECTION;
3595 	  else
3596 	      return GAIA_LINESTRING;
3597       }
3598     if (n_points == 0 && n_linestrings >= 1 && n_polygons == 0)
3599       {
3600 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3601 	      return GAIA_GEOMETRYCOLLECTION;
3602 	  else
3603 	      return GAIA_MULTILINESTRING;
3604       }
3605     if (n_points == 0 && n_linestrings == 0 && n_polygons == 1)
3606       {
3607 	  if (geom->DeclaredType == GAIA_MULTIPOLYGON)
3608 	      return GAIA_MULTIPOLYGON;
3609 	  else if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3610 	      return GAIA_GEOMETRYCOLLECTION;
3611 	  else
3612 	      return GAIA_POLYGON;
3613       }
3614     if (n_points == 0 && n_linestrings == 0 && n_polygons >= 1)
3615       {
3616 	  if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3617 	      return GAIA_GEOMETRYCOLLECTION;
3618 	  else
3619 	      return GAIA_MULTIPOLYGON;
3620       }
3621     return GAIA_GEOMETRYCOLLECTION;
3622 }
3623 
3624 GAIAGEO_DECLARE int
gaiaIsEmpty(gaiaGeomCollPtr geom)3625 gaiaIsEmpty (gaiaGeomCollPtr geom)
3626 {
3627 /* checks if this GEOMETRYCOLLECTION is an empty one */
3628     if (!geom)
3629 	return 1;
3630     if (geom->FirstPoint != NULL)
3631       {
3632 	  /* there is at least one point */
3633 	  return 0;
3634       }
3635     if (geom->FirstLinestring != NULL)
3636       {
3637 	  /* there is at least one linestring */
3638 	  return 0;
3639       }
3640     if (geom->FirstPolygon != NULL)
3641       {
3642 	  /* there is at least one polygon */
3643 	  return 0;
3644       }
3645     return 1;
3646 }
3647 
3648 GAIAGEO_DECLARE int
gaiaIsClosed(gaiaLinestringPtr line)3649 gaiaIsClosed (gaiaLinestringPtr line)
3650 {
3651 /* checks if this linestring is a closed one */
3652     double x0;
3653     double y0;
3654     double x1;
3655     double y1;
3656     double z;
3657     double m;
3658     if (!line)
3659 	return 0;
3660     if (line->Points < 3)
3661 	return 0;
3662     if (line->DimensionModel == GAIA_XY_Z)
3663       {
3664 	  gaiaGetPointXYZ (line->Coords, 0, &x0, &y0, &z);
3665       }
3666     else if (line->DimensionModel == GAIA_XY_M)
3667       {
3668 	  gaiaGetPointXYM (line->Coords, 0, &x0, &y0, &m);
3669       }
3670     else if (line->DimensionModel == GAIA_XY_Z_M)
3671       {
3672 	  gaiaGetPointXYZM (line->Coords, 0, &x0, &y0, &z, &m);
3673       }
3674     else
3675       {
3676 	  gaiaGetPoint (line->Coords, 0, &x0, &y0);
3677       }
3678     if (line->DimensionModel == GAIA_XY_Z)
3679       {
3680 	  gaiaGetPointXYZ (line->Coords, (line->Points - 1), &x1, &y1, &z);
3681       }
3682     else if (line->DimensionModel == GAIA_XY_M)
3683       {
3684 	  gaiaGetPointXYM (line->Coords, (line->Points - 1), &x1, &y1, &m);
3685       }
3686     else if (line->DimensionModel == GAIA_XY_Z_M)
3687       {
3688 	  gaiaGetPointXYZM (line->Coords, (line->Points - 1), &x1, &y1, &z, &m);
3689       }
3690     else
3691       {
3692 	  gaiaGetPoint (line->Coords, (line->Points - 1), &x1, &y1);
3693       }
3694     if (x0 == x1 && y0 == y1)
3695 	return 1;
3696     return 0;
3697 }
3698 
3699 GAIAGEO_DECLARE int
gaiaMbrsEqual(gaiaGeomCollPtr mbr1,gaiaGeomCollPtr mbr2)3700 gaiaMbrsEqual (gaiaGeomCollPtr mbr1, gaiaGeomCollPtr mbr2)
3701 {
3702 /*
3703 / checks if two MBRs are identical
3704 /
3705 / returns 1 if TRUE
3706 / 0 if FALSE
3707 */
3708     if (mbr1->MinX != mbr2->MinX)
3709 	return 0;
3710     if (mbr1->MinY != mbr2->MinY)
3711 	return 0;
3712     if (mbr1->MaxX != mbr2->MaxX)
3713 	return 0;
3714     if (mbr1->MaxY != mbr2->MaxY)
3715 	return 0;
3716     return 1;
3717 }
3718 
3719 GAIAGEO_DECLARE int
gaiaMbrsDisjoint(gaiaGeomCollPtr mbr1,gaiaGeomCollPtr mbr2)3720 gaiaMbrsDisjoint (gaiaGeomCollPtr mbr1, gaiaGeomCollPtr mbr2)
3721 {
3722 /*
3723 / checks if two MBRs are disjoint
3724 /
3725 / returns 1 if TRUE
3726 / 0 if FALSE
3727 */
3728     if (mbr1->MinX > mbr2->MaxX)
3729 	return 1;
3730     if (mbr1->MinY > mbr2->MaxY)
3731 	return 1;
3732     if (mbr1->MaxX < mbr2->MinX)
3733 	return 1;
3734     if (mbr1->MaxY < mbr2->MinY)
3735 	return 1;
3736     if (mbr2->MinX > mbr1->MaxX)
3737 	return 1;
3738     if (mbr2->MinY > mbr1->MaxY)
3739 	return 1;
3740     if (mbr2->MaxX < mbr1->MinX)
3741 	return 1;
3742     if (mbr2->MaxY < mbr1->MinY)
3743 	return 1;
3744     return 0;
3745 }
3746 
3747 GAIAGEO_DECLARE int
gaiaMbrsTouches(gaiaGeomCollPtr mbr1,gaiaGeomCollPtr mbr2)3748 gaiaMbrsTouches (gaiaGeomCollPtr mbr1, gaiaGeomCollPtr mbr2)
3749 {
3750 /*
3751 / checks if two MBRs touches
3752 /
3753 / returns 1 if TRUE
3754 / 0 if FALSE
3755 */
3756     if (mbr1->MinX == mbr2->MinX)
3757 	return 1;
3758     if (mbr1->MinY == mbr2->MinY)
3759 	return 1;
3760     if (mbr1->MaxX == mbr2->MaxX)
3761 	return 1;
3762     if (mbr1->MaxY == mbr2->MaxY)
3763 	return 1;
3764     return 0;
3765 }
3766 
3767 GAIAGEO_DECLARE int
gaiaMbrsIntersects(gaiaGeomCollPtr mbr1,gaiaGeomCollPtr mbr2)3768 gaiaMbrsIntersects (gaiaGeomCollPtr mbr1, gaiaGeomCollPtr mbr2)
3769 {
3770 /*
3771 / checks if two MBRs intersect
3772 /
3773 / returns 1 if TRUE
3774 / 0 if FALSE
3775 */
3776     if (gaiaMbrsDisjoint (mbr1, mbr2))
3777 	return 0;
3778     return 1;
3779 }
3780 
3781 GAIAGEO_DECLARE int
gaiaMbrsOverlaps(gaiaGeomCollPtr mbr1,gaiaGeomCollPtr mbr2)3782 gaiaMbrsOverlaps (gaiaGeomCollPtr mbr1, gaiaGeomCollPtr mbr2)
3783 {
3784 /*
3785 / checks if two MBRs overlap
3786 /
3787 / returns 1 if TRUE
3788 / 0 if FALSE
3789 */
3790     if (gaiaMbrsDisjoint (mbr1, mbr2))
3791 	return 0;
3792     if (mbr1->MinX >= mbr2->MinX && mbr1->MinX <= mbr2->MaxX)
3793 	return 1;
3794     if (mbr1->MaxX >= mbr2->MinX && mbr1->MaxX <= mbr2->MaxX)
3795 	return 1;
3796     if (mbr1->MinY >= mbr2->MinY && mbr1->MinY <= mbr2->MaxY)
3797 	return 1;
3798     if (mbr1->MaxY >= mbr2->MinY && mbr1->MaxY <= mbr2->MaxY)
3799 	return 1;
3800     return 0;
3801 }
3802 
3803 GAIAGEO_DECLARE int
gaiaMbrsContains(gaiaGeomCollPtr mbr1,gaiaGeomCollPtr mbr2)3804 gaiaMbrsContains (gaiaGeomCollPtr mbr1, gaiaGeomCollPtr mbr2)
3805 {
3806 /*
3807 / checks if MBR-1 completely contains MBR-2
3808 /
3809 / returns 1 if TRUE
3810 / 0 if FALSE
3811 */
3812     int ok_1 = 0;
3813     int ok_2 = 0;
3814     int ok_3 = 0;
3815     int ok_4 = 0;
3816     if (mbr2->MinX >= mbr1->MinX && mbr2->MinX <= mbr1->MaxX)
3817 	ok_1 = 1;
3818     if (mbr2->MaxX >= mbr1->MinX && mbr2->MaxX <= mbr1->MaxX)
3819 	ok_2 = 1;
3820     if (mbr2->MinY >= mbr1->MinY && mbr2->MinY <= mbr1->MaxY)
3821 	ok_3 = 1;
3822     if (mbr2->MaxY >= mbr1->MinY && mbr2->MaxY <= mbr1->MaxY)
3823 	ok_4 = 1;
3824     if (ok_1 && ok_2 && ok_3 && ok_4)
3825 	return 1;
3826     return 0;
3827 }
3828 
3829 GAIAGEO_DECLARE int
gaiaMbrsWithin(gaiaGeomCollPtr mbr1,gaiaGeomCollPtr mbr2)3830 gaiaMbrsWithin (gaiaGeomCollPtr mbr1, gaiaGeomCollPtr mbr2)
3831 {
3832 /*
3833 / checks if MBR-2 completely contains MBR-1
3834 /
3835 / returns 1 if TRUE
3836 / 0 if FALSE
3837 */
3838     int ok_1 = 0;
3839     int ok_2 = 0;
3840     int ok_3 = 0;
3841     int ok_4 = 0;
3842     if (mbr1->MinX >= mbr2->MinX && mbr1->MinX <= mbr2->MaxX)
3843 	ok_1 = 1;
3844     if (mbr1->MaxX >= mbr2->MinX && mbr1->MaxX <= mbr2->MaxX)
3845 	ok_2 = 1;
3846     if (mbr1->MinY >= mbr2->MinY && mbr1->MinY <= mbr2->MaxY)
3847 	ok_3 = 1;
3848     if (mbr1->MaxY >= mbr2->MinY && mbr1->MaxY <= mbr2->MaxY)
3849 	ok_4 = 1;
3850     if (ok_1 && ok_2 && ok_3 && ok_4)
3851 	return 1;
3852     return 0;
3853 }
3854 
3855 static void
fatMakePoint(double x,double y,int srid,unsigned char ** result,int * size)3856 fatMakePoint (double x, double y, int srid, unsigned char **result, int *size)
3857 {
3858 /* build a Blob encoded Geometry representing a POINT */
3859     unsigned char *ptr;
3860     int endian_arch = gaiaEndianArch ();
3861 /* computing the Blob size and then allocating it */
3862     *size = 44;			/* header size */
3863     *size += (sizeof (double) * 2);	/* [x,y] coords */
3864     *result = malloc (*size);
3865     ptr = *result;
3866 /* setting the Blob value */
3867     *ptr = GAIA_MARK_START;	/* START signature */
3868     *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
3869     gaiaExport32 (ptr + 2, srid, 1, endian_arch);	/* the SRID */
3870     gaiaExport64 (ptr + 6, x, 1, endian_arch);	/* MBR - minimum X */
3871     gaiaExport64 (ptr + 14, y, 1, endian_arch);	/* MBR - minimum Y */
3872     gaiaExport64 (ptr + 22, x, 1, endian_arch);	/* MBR - maximum X */
3873     gaiaExport64 (ptr + 30, y, 1, endian_arch);	/* MBR - maximum Y */
3874     *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
3875     gaiaExport32 (ptr + 39, GAIA_POINT, 1, endian_arch);	/* class POINT */
3876     gaiaExport64 (ptr + 43, x, 1, endian_arch);	/* X */
3877     gaiaExport64 (ptr + 51, y, 1, endian_arch);	/* Y */
3878     *(ptr + 59) = GAIA_MARK_END;	/* END signature */
3879 }
3880 
3881 static void
tinyMakePoint(double x,double y,int srid,unsigned char ** result,int * size)3882 tinyMakePoint (double x, double y, int srid, unsigned char **result, int *size)
3883 {
3884 /* build a Blob encoded TinyPoint representing a POINT */
3885     unsigned char *ptr;
3886     int endian_arch = gaiaEndianArch ();
3887 /* allocating the BLOB */
3888     *size = 24;
3889     *result = malloc (*size);
3890     ptr = *result;
3891 /* setting the Blob value */
3892     *ptr = GAIA_MARK_START;	/* START signature */
3893     *(ptr + 1) = GAIA_TINYPOINT_LITTLE_ENDIAN;	/* byte ordering */
3894     gaiaExport32 (ptr + 2, srid, 1, endian_arch);	/* the SRID */
3895     *(ptr + 6) = GAIA_TINYPOINT_XY;	/* Point Type */
3896     gaiaExport64 (ptr + 7, x, 1, endian_arch);	/* X */
3897     gaiaExport64 (ptr + 15, y, 1, endian_arch);	/* Y */
3898     *(ptr + 23) = GAIA_MARK_END;	/* END signature */
3899 }
3900 
3901 GAIAGEO_DECLARE void
gaiaMakePoint(double x,double y,int srid,unsigned char ** result,int * size)3902 gaiaMakePoint (double x, double y, int srid, unsigned char **result, int *size)
3903 {
3904 /* always returns a BLOB-Geometry encoded POINT */
3905     gaiaMakePointEx (0, x, y, srid, result, size);
3906 }
3907 
3908 GAIAGEO_DECLARE void
gaiaMakePointEx(int tiny_point,double x,double y,int srid,unsigned char ** result,int * size)3909 gaiaMakePointEx (int tiny_point, double x, double y, int srid,
3910 		 unsigned char **result, int *size)
3911 {
3912 /* conditionally returns either a BLOB-Geometry or BLOB-TinyPoint encoded POINT */
3913     if (tiny_point)
3914 	tinyMakePoint (x, y, srid, result, size);
3915     else
3916 	fatMakePoint (x, y, srid, result, size);
3917 }
3918 
3919 static void
fatMakePointZ(double x,double y,double z,int srid,unsigned char ** result,int * size)3920 fatMakePointZ (double x, double y, double z, int srid, unsigned char **result,
3921 	       int *size)
3922 {
3923 /* build a Blob encoded Geometry representing a POINT Z */
3924     unsigned char *ptr;
3925     int endian_arch = gaiaEndianArch ();
3926 /* computing the Blob size and then allocating it */
3927     *size = 44;			/* header size */
3928     *size += (sizeof (double) * 3);	/* [x,y,z] coords */
3929     *result = malloc (*size);
3930     ptr = *result;
3931 /* setting the Blob value */
3932     *ptr = GAIA_MARK_START;	/* START signature */
3933     *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
3934     gaiaExport32 (ptr + 2, srid, 1, endian_arch);	/* the SRID */
3935     gaiaExport64 (ptr + 6, x, 1, endian_arch);	/* MBR - minimum X */
3936     gaiaExport64 (ptr + 14, y, 1, endian_arch);	/* MBR - minimum Y */
3937     gaiaExport64 (ptr + 22, x, 1, endian_arch);	/* MBR - maximum X */
3938     gaiaExport64 (ptr + 30, y, 1, endian_arch);	/* MBR - maximum Y */
3939     *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
3940     gaiaExport32 (ptr + 39, GAIA_POINTZ, 1, endian_arch);	/* class POINT */
3941     gaiaExport64 (ptr + 43, x, 1, endian_arch);	/* X */
3942     gaiaExport64 (ptr + 51, y, 1, endian_arch);	/* Y */
3943     gaiaExport64 (ptr + 59, z, 1, endian_arch);	/* Z */
3944     *(ptr + 67) = GAIA_MARK_END;	/* END signature */
3945 }
3946 
3947 static void
tinyMakePointZ(double x,double y,double z,int srid,unsigned char ** result,int * size)3948 tinyMakePointZ (double x, double y, double z, int srid, unsigned char **result,
3949 		int *size)
3950 {
3951 /* build a Blob encoded TinyPoint representing a POINT Z */
3952     unsigned char *ptr;
3953     int endian_arch = gaiaEndianArch ();
3954 /* allocating the BLOB */
3955     *size = 32;
3956     *result = malloc (*size);
3957     ptr = *result;
3958 /* setting the Blob value */
3959     *ptr = GAIA_MARK_START;	/* START signature */
3960     *(ptr + 1) = GAIA_TINYPOINT_LITTLE_ENDIAN;	/* byte ordering */
3961     gaiaExport32 (ptr + 2, srid, 1, endian_arch);	/* the SRID */
3962     *(ptr + 6) = GAIA_TINYPOINT_XYZ;	/* Point Type */
3963     gaiaExport64 (ptr + 7, x, 1, endian_arch);	/* X */
3964     gaiaExport64 (ptr + 15, y, 1, endian_arch);	/* Y */
3965     gaiaExport64 (ptr + 23, z, 1, endian_arch);	/* Z */
3966     *(ptr + 31) = GAIA_MARK_END;	/* END signature */
3967 }
3968 
3969 GAIAGEO_DECLARE void
gaiaMakePointZ(double x,double y,double z,int srid,unsigned char ** result,int * size)3970 gaiaMakePointZ (double x, double y, double z, int srid, unsigned char **result,
3971 		int *size)
3972 {
3973 /* always returns a BLOB-Geometry encoded POINT Z */
3974     gaiaMakePointZEx (0, x, y, z, srid, result, size);
3975 }
3976 
3977 GAIAGEO_DECLARE void
gaiaMakePointZEx(int tiny_point,double x,double y,double z,int srid,unsigned char ** result,int * size)3978 gaiaMakePointZEx (int tiny_point, double x, double y, double z, int srid,
3979 		  unsigned char **result, int *size)
3980 {
3981 /* conditionally returns either a BLOB-Geometry or BLOB-TinyPoint encoded POINT Z */
3982     if (tiny_point)
3983 	tinyMakePointZ (x, y, z, srid, result, size);
3984     else
3985 	fatMakePointZ (x, y, z, srid, result, size);
3986 }
3987 
3988 static void
fatMakePointM(double x,double y,double m,int srid,unsigned char ** result,int * size)3989 fatMakePointM (double x, double y, double m, int srid, unsigned char **result,
3990 	       int *size)
3991 {
3992 /* build a Blob encoded Geometry representing a POINT M */
3993     unsigned char *ptr;
3994     int endian_arch = gaiaEndianArch ();
3995 /* computing the Blob size and then allocating it */
3996     *size = 44;			/* header size */
3997     *size += (sizeof (double) * 3);	/* [x,y,z] coords */
3998     *result = malloc (*size);
3999     ptr = *result;
4000 /* setting the Blob value */
4001     *ptr = GAIA_MARK_START;	/* START signature */
4002     *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
4003     gaiaExport32 (ptr + 2, srid, 1, endian_arch);	/* the SRID */
4004     gaiaExport64 (ptr + 6, x, 1, endian_arch);	/* MBR - minimum X */
4005     gaiaExport64 (ptr + 14, y, 1, endian_arch);	/* MBR - minimum Y */
4006     gaiaExport64 (ptr + 22, x, 1, endian_arch);	/* MBR - maximum X */
4007     gaiaExport64 (ptr + 30, y, 1, endian_arch);	/* MBR - maximum Y */
4008     *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
4009     gaiaExport32 (ptr + 39, GAIA_POINTM, 1, endian_arch);	/* class POINT */
4010     gaiaExport64 (ptr + 43, x, 1, endian_arch);	/* X */
4011     gaiaExport64 (ptr + 51, y, 1, endian_arch);	/* Y */
4012     gaiaExport64 (ptr + 59, m, 1, endian_arch);	/* M */
4013     *(ptr + 67) = GAIA_MARK_END;	/* END signature */
4014 }
4015 
4016 static void
tinyMakePointM(double x,double y,double m,int srid,unsigned char ** result,int * size)4017 tinyMakePointM (double x, double y, double m, int srid, unsigned char **result,
4018 		int *size)
4019 {
4020 /* build a Blob encoded TinyPoint representing a POINT M */
4021     unsigned char *ptr;
4022     int endian_arch = gaiaEndianArch ();
4023 /* allocating the BLOB */
4024     *size = 32;
4025     *result = malloc (*size);
4026     ptr = *result;
4027 /* setting the Blob value */
4028     *ptr = GAIA_MARK_START;	/* START signature */
4029     *(ptr + 1) = GAIA_TINYPOINT_LITTLE_ENDIAN;	/* byte ordering */
4030     gaiaExport32 (ptr + 2, srid, 1, endian_arch);	/* the SRID */
4031     *(ptr + 6) = GAIA_TINYPOINT_XYM;	/* Point Type */
4032     gaiaExport64 (ptr + 7, x, 1, endian_arch);	/* X */
4033     gaiaExport64 (ptr + 15, y, 1, endian_arch);	/* Y */
4034     gaiaExport64 (ptr + 23, m, 1, endian_arch);	/* M */
4035     *(ptr + 31) = GAIA_MARK_END;	/* END signature */
4036 }
4037 
4038 GAIAGEO_DECLARE void
gaiaMakePointM(double x,double y,double m,int srid,unsigned char ** result,int * size)4039 gaiaMakePointM (double x, double y, double m, int srid, unsigned char **result,
4040 		int *size)
4041 {
4042 /* always returns a BLOB-Geometry encoded POINT M */
4043     gaiaMakePointMEx (0, x, y, m, srid, result, size);
4044 }
4045 
4046 GAIAGEO_DECLARE void
gaiaMakePointMEx(int tiny_point,double x,double y,double m,int srid,unsigned char ** result,int * size)4047 gaiaMakePointMEx (int tiny_point, double x, double y, double m, int srid,
4048 		  unsigned char **result, int *size)
4049 {
4050 /* conditionally returns either a BLOB-Geometry or BLOB-TinyPoint encoded POINT M */
4051     if (tiny_point)
4052 	tinyMakePointM (x, y, m, srid, result, size);
4053     else
4054 	fatMakePointM (x, y, m, srid, result, size);
4055 }
4056 
4057 static void
fatMakePointZM(double x,double y,double z,double m,int srid,unsigned char ** result,int * size)4058 fatMakePointZM (double x, double y, double z, double m, int srid,
4059 		unsigned char **result, int *size)
4060 {
4061 /* build a Blob encoded Geometry representing a POINT ZM */
4062     unsigned char *ptr;
4063     int endian_arch = gaiaEndianArch ();
4064 /* computing the Blob size and then allocating it */
4065     *size = 44;			/* header size */
4066     *size += (sizeof (double) * 4);	/* [x,y,z,m] coords */
4067     *result = malloc (*size);
4068     ptr = *result;
4069 /* setting the Blob value */
4070     *ptr = GAIA_MARK_START;	/* START signature */
4071     *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
4072     gaiaExport32 (ptr + 2, srid, 1, endian_arch);	/* the SRID */
4073     gaiaExport64 (ptr + 6, x, 1, endian_arch);	/* MBR - minimum X */
4074     gaiaExport64 (ptr + 14, y, 1, endian_arch);	/* MBR - minimum Y */
4075     gaiaExport64 (ptr + 22, x, 1, endian_arch);	/* MBR - maximum X */
4076     gaiaExport64 (ptr + 30, y, 1, endian_arch);	/* MBR - maximum Y */
4077     *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
4078     gaiaExport32 (ptr + 39, GAIA_POINTZM, 1, endian_arch);	/* class POINT */
4079     gaiaExport64 (ptr + 43, x, 1, endian_arch);	/* X */
4080     gaiaExport64 (ptr + 51, y, 1, endian_arch);	/* Y */
4081     gaiaExport64 (ptr + 59, z, 1, endian_arch);	/* Z */
4082     gaiaExport64 (ptr + 67, m, 1, endian_arch);	/* M */
4083     *(ptr + 75) = GAIA_MARK_END;	/* END signature */
4084 }
4085 
4086 static void
tinyMakePointZM(double x,double y,double z,double m,int srid,unsigned char ** result,int * size)4087 tinyMakePointZM (double x, double y, double z, double m, int srid,
4088 		 unsigned char **result, int *size)
4089 {
4090 /* build a Blob encoded TinyPoint representing a POINT ZM */
4091     unsigned char *ptr;
4092     int endian_arch = gaiaEndianArch ();
4093 /* allocating the BLOB */
4094     *size = 40;
4095     *result = malloc (*size);
4096     ptr = *result;
4097 /* setting the Blob value */
4098     *ptr = GAIA_MARK_START;	/* START signature */
4099     *(ptr + 1) = GAIA_TINYPOINT_LITTLE_ENDIAN;	/* byte ordering */
4100     gaiaExport32 (ptr + 2, srid, 1, endian_arch);	/* the SRID */
4101     *(ptr + 6) = GAIA_TINYPOINT_XYZM;	/* Point Type */
4102     gaiaExport64 (ptr + 7, x, 1, endian_arch);	/* X */
4103     gaiaExport64 (ptr + 15, y, 1, endian_arch);	/* Y */
4104     gaiaExport64 (ptr + 23, z, 1, endian_arch);	/* Z */
4105     gaiaExport64 (ptr + 31, m, 1, endian_arch);	/* M */
4106     *(ptr + 39) = GAIA_MARK_END;	/* END signature */
4107 }
4108 
4109 GAIAGEO_DECLARE void
gaiaMakePointZM(double x,double y,double z,double m,int srid,unsigned char ** result,int * size)4110 gaiaMakePointZM (double x, double y, double z, double m, int srid,
4111 		 unsigned char **result, int *size)
4112 {
4113 /* always returns a BLOB-Geometry encoded POINT ZM */
4114     gaiaMakePointZMEx (0, x, y, z, m, srid, result, size);
4115 }
4116 
4117 GAIAGEO_DECLARE void
gaiaMakePointZMEx(int tiny_point,double x,double y,double z,double m,int srid,unsigned char ** result,int * size)4118 gaiaMakePointZMEx (int tiny_point, double x, double y, double z, double m,
4119 		   int srid, unsigned char **result, int *size)
4120 {
4121 /* conditionally returns either a BLOB-Geometry or BLOB-TinyPoint encoded POINT ZM */
4122     if (tiny_point)
4123 	tinyMakePointZM (x, y, z, m, srid, result, size);
4124     else
4125 	fatMakePointZM (x, y, z, m, srid, result, size);
4126 }
4127 
4128 GAIAGEO_DECLARE void
gaiaMakeLine(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2,unsigned char ** result,int * size)4129 gaiaMakeLine (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2,
4130 	      unsigned char **result, int *size)
4131 {
4132 /* build a Blob encoded Geometry representing a LINESTRING (segment) */
4133     int pts;
4134     int lns;
4135     int pgs;
4136     gaiaPointPtr pt;
4137     gaiaLinestringPtr ln;
4138     gaiaPolygonPtr pg;
4139     gaiaGeomCollPtr g;
4140     int dims0 = 0;
4141     int dims1 = 0;
4142     int dims;
4143     double x0 = 0.0;
4144     double y0 = 0.0;
4145     double z0 = 0.0;
4146     double m0 = 0.0;
4147     double x1 = 0.0;
4148     double y1 = 0.0;
4149     double z1 = 0.0;
4150     double m1 = 0.0;
4151 
4152 /* checking if GEOM-1 simply is a POINT */
4153     if (geom1 == NULL)
4154       {
4155 	  *result = NULL;
4156 	  *size = 0;
4157 	  return;
4158       }
4159     pts = 0;
4160     lns = 0;
4161     pgs = 0;
4162     pt = geom1->FirstPoint;
4163     while (pt)
4164       {
4165 	  pts++;
4166 	  x0 = pt->X;
4167 	  y0 = pt->Y;
4168 	  z0 = pt->Z;
4169 	  m0 = pt->M;
4170 	  dims0 = pt->DimensionModel;
4171 	  pt = pt->Next;
4172       }
4173     ln = geom1->FirstLinestring;
4174     while (ln)
4175       {
4176 	  lns++;
4177 	  ln = ln->Next;
4178       }
4179     pg = geom1->FirstPolygon;
4180     while (pg)
4181       {
4182 	  pgs++;
4183 	  pg = pg->Next;
4184       }
4185     if (pts == 1 && lns == 0 && pgs == 0)
4186 	;
4187     else
4188       {
4189 	  /* failure: not a simple POINT */
4190 	  *result = NULL;
4191 	  *size = 0;
4192 	  return;
4193       }
4194 
4195 /* checking if GEOM-2 simply is a POINT */
4196     if (geom2 == NULL)
4197       {
4198 	  *result = NULL;
4199 	  *size = 0;
4200 	  return;
4201       }
4202     pts = 0;
4203     lns = 0;
4204     pgs = 0;
4205     pt = geom2->FirstPoint;
4206     while (pt)
4207       {
4208 	  pts++;
4209 	  x1 = pt->X;
4210 	  y1 = pt->Y;
4211 	  z1 = pt->Z;
4212 	  m1 = pt->M;
4213 	  dims1 = pt->DimensionModel;
4214 	  pt = pt->Next;
4215       }
4216     ln = geom2->FirstLinestring;
4217     while (ln)
4218       {
4219 	  lns++;
4220 	  ln = ln->Next;
4221       }
4222     pg = geom2->FirstPolygon;
4223     while (pg)
4224       {
4225 	  pgs++;
4226 	  pg = pg->Next;
4227       }
4228     if (pts == 1 && lns == 0 && pgs == 0)
4229 	;
4230     else
4231       {
4232 	  /* failure: not a simple POINT */
4233 	  *result = NULL;
4234 	  *size = 0;
4235 	  return;
4236       }
4237 
4238 /* building a new Geometry */
4239     if (dims0 == dims1)
4240 	dims = dims0;
4241     else
4242       {
4243 	  if (dims0 == GAIA_XY_Z_M || dims1 == GAIA_XY_Z_M)
4244 	      dims = GAIA_XY_Z_M;
4245 	  else if (dims0 == GAIA_XY_Z && dims1 == GAIA_XY_M)
4246 	      dims = GAIA_XY_Z_M;
4247 	  else if (dims0 == GAIA_XY_M && dims1 == GAIA_XY_Z)
4248 	      dims = GAIA_XY_Z_M;
4249 	  else if (dims0 == GAIA_XY_Z)
4250 	      dims = GAIA_XY_Z;
4251 	  else if (dims1 == GAIA_XY_Z)
4252 	      dims = GAIA_XY_Z;
4253 	  else if (dims0 == GAIA_XY_M)
4254 	      dims = GAIA_XY_M;
4255 	  else if (dims1 == GAIA_XY_M)
4256 	      dims = GAIA_XY_M;
4257 	  else
4258 	      dims = GAIA_XY;
4259       }
4260     if (dims == GAIA_XY_Z_M)
4261 	g = gaiaAllocGeomCollXYZM ();
4262     else if (dims == GAIA_XY_Z)
4263 	g = gaiaAllocGeomCollXYZ ();
4264     else if (dims == GAIA_XY_M)
4265 	g = gaiaAllocGeomCollXYM ();
4266     else
4267 	g = gaiaAllocGeomColl ();
4268     g->Srid = geom1->Srid;
4269     g->DeclaredType = GAIA_LINESTRING;
4270     ln = gaiaAddLinestringToGeomColl (g, 2);
4271     if (dims == GAIA_XY_Z_M)
4272       {
4273 	  gaiaSetPointXYZM (ln->Coords, 0, x0, y0, z0, m0);
4274 	  gaiaSetPointXYZM (ln->Coords, 1, x1, y1, z1, m1);
4275       }
4276     else if (dims == GAIA_XY_Z)
4277       {
4278 	  gaiaSetPointXYZ (ln->Coords, 0, x0, y0, z0);
4279 	  gaiaSetPointXYZ (ln->Coords, 1, x1, y1, z1);
4280       }
4281     else if (dims == GAIA_XY_M)
4282       {
4283 	  gaiaSetPointXYM (ln->Coords, 0, x0, y0, m0);
4284 	  gaiaSetPointXYM (ln->Coords, 1, x1, y1, m1);
4285       }
4286     else
4287       {
4288 	  gaiaSetPoint (ln->Coords, 0, x0, y0);
4289 	  gaiaSetPoint (ln->Coords, 1, x1, y1);
4290       }
4291 /* converting to Binary Blob */
4292     gaiaToSpatiaLiteBlobWkb (g, result, size);
4293     gaiaFreeGeomColl (g);
4294 }
4295 
4296 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaMergeGeometries(gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)4297 gaiaMergeGeometries (gaiaGeomCollPtr geom1, gaiaGeomCollPtr geom2)
4298 {
4299     return gaiaMergeGeometries_r (NULL, geom1, geom2);
4300 }
4301 
4302 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaMergeGeometries_r(const void * cache,gaiaGeomCollPtr geom1,gaiaGeomCollPtr geom2)4303 gaiaMergeGeometries_r (const void *cache, gaiaGeomCollPtr geom1,
4304 		       gaiaGeomCollPtr geom2)
4305 {
4306 /* mergine a second generic Geometries into the first one */
4307     gaiaPointPtr pt;
4308     gaiaLinestringPtr ln;
4309     gaiaLinestringPtr new_ln;
4310     gaiaPolygonPtr pg;
4311     gaiaPolygonPtr new_pg;
4312     gaiaRingPtr rng;
4313     gaiaRingPtr new_rng;
4314     double x;
4315     double y;
4316     double z;
4317     double m;
4318     int iv;
4319     int ib;
4320 
4321     if (geom1 == NULL || geom2 == NULL)
4322 	return NULL;
4323     if (cache != NULL)
4324 	cache = NULL;
4325 
4326     pt = geom2->FirstPoint;
4327     while (pt)
4328       {
4329 	  /* copying POINTs from GEOM-2 */
4330 	  z = 0.0;
4331 	  m = 0.0;
4332 	  if (pt->DimensionModel == GAIA_XY_Z_M)
4333 	    {
4334 		x = pt->X;
4335 		y = pt->Y;
4336 		z = pt->Z;
4337 		m = pt->M;
4338 	    }
4339 	  else if (pt->DimensionModel == GAIA_XY_Z)
4340 	    {
4341 		x = pt->X;
4342 		y = pt->Y;
4343 		z = pt->Z;
4344 	    }
4345 	  else if (pt->DimensionModel == GAIA_XY_M)
4346 	    {
4347 		x = pt->X;
4348 		y = pt->Y;
4349 		m = pt->M;
4350 	    }
4351 	  else
4352 	    {
4353 		x = pt->X;
4354 		y = pt->Y;
4355 	    }
4356 	  if (geom1->DimensionModel == GAIA_XY_Z_M)
4357 	    {
4358 		gaiaAddPointToGeomCollXYZM (geom1, x, y, z, m);
4359 	    }
4360 	  else if (geom1->DimensionModel == GAIA_XY_Z)
4361 	    {
4362 		gaiaAddPointToGeomCollXYZ (geom1, x, y, z);
4363 	    }
4364 	  else if (geom1->DimensionModel == GAIA_XY_M)
4365 	    {
4366 		gaiaAddPointToGeomCollXYM (geom1, x, y, m);
4367 	    }
4368 	  else
4369 	    {
4370 		gaiaAddPointToGeomColl (geom1, x, y);
4371 	    }
4372 	  pt = pt->Next;
4373       }
4374 
4375     ln = geom2->FirstLinestring;
4376     while (ln)
4377       {
4378 	  /* copying LINESTRINGs from GEOM-2 */
4379 	  new_ln = gaiaAddLinestringToGeomColl (geom1, ln->Points);
4380 	  for (iv = 0; iv < ln->Points; iv++)
4381 	    {
4382 		z = 0.0;
4383 		m = 0.0;
4384 		if (ln->DimensionModel == GAIA_XY_Z_M)
4385 		  {
4386 		      gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
4387 		  }
4388 		else if (ln->DimensionModel == GAIA_XY_Z)
4389 		  {
4390 		      gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
4391 		  }
4392 		else if (ln->DimensionModel == GAIA_XY_M)
4393 		  {
4394 		      gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
4395 		  }
4396 		else
4397 		  {
4398 		      gaiaGetPoint (ln->Coords, iv, &x, &y);
4399 		  }
4400 		if (new_ln->DimensionModel == GAIA_XY_Z_M)
4401 		  {
4402 		      gaiaSetPointXYZM (new_ln->Coords, iv, x, y, z, m);
4403 		  }
4404 		else if (new_ln->DimensionModel == GAIA_XY_Z)
4405 		  {
4406 		      gaiaSetPointXYZ (new_ln->Coords, iv, x, y, z);
4407 		  }
4408 		else if (new_ln->DimensionModel == GAIA_XY_M)
4409 		  {
4410 		      gaiaSetPointXYM (new_ln->Coords, iv, x, y, m);
4411 		  }
4412 		else
4413 		  {
4414 		      gaiaSetPoint (new_ln->Coords, iv, x, y);
4415 		  }
4416 	    }
4417 	  ln = ln->Next;
4418       }
4419 
4420     pg = geom2->FirstPolygon;
4421     while (pg)
4422       {
4423 	  /* copying POLYGONs from GEOM-2 */
4424 	  rng = pg->Exterior;
4425 	  new_pg =
4426 	      gaiaAddPolygonToGeomColl (geom1, rng->Points, pg->NumInteriors);
4427 	  new_rng = new_pg->Exterior;
4428 	  for (iv = 0; iv < rng->Points; iv++)
4429 	    {
4430 		/* Exterior Ring */
4431 		z = 0.0;
4432 		m = 0.0;
4433 		if (rng->DimensionModel == GAIA_XY_Z_M)
4434 		  {
4435 		      gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
4436 		  }
4437 		else if (rng->DimensionModel == GAIA_XY_Z)
4438 		  {
4439 		      gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
4440 		  }
4441 		else if (rng->DimensionModel == GAIA_XY_M)
4442 		  {
4443 		      gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
4444 		  }
4445 		else
4446 		  {
4447 		      gaiaGetPoint (rng->Coords, iv, &x, &y);
4448 		  }
4449 		if (new_rng->DimensionModel == GAIA_XY_Z_M)
4450 		  {
4451 		      gaiaSetPointXYZM (new_rng->Coords, iv, x, y, z, m);
4452 		  }
4453 		else if (new_rng->DimensionModel == GAIA_XY_Z)
4454 		  {
4455 		      gaiaSetPointXYZ (new_rng->Coords, iv, x, y, z);
4456 		  }
4457 		else if (new_rng->DimensionModel == GAIA_XY_M)
4458 		  {
4459 		      gaiaSetPointXYM (new_rng->Coords, iv, x, y, m);
4460 		  }
4461 		else
4462 		  {
4463 		      gaiaSetPoint (new_rng->Coords, iv, x, y);
4464 		  }
4465 	    }
4466 	  for (ib = 0; ib < pg->NumInteriors; ib++)
4467 	    {
4468 		/* Interior Rings */
4469 		rng = pg->Interiors + ib;
4470 		new_rng = gaiaAddInteriorRing (new_pg, ib, rng->Points);
4471 		for (iv = 0; iv < rng->Points; iv++)
4472 		  {
4473 		      z = 0.0;
4474 		      m = 0.0;
4475 		      if (rng->DimensionModel == GAIA_XY_Z_M)
4476 			{
4477 			    gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
4478 			}
4479 		      else if (rng->DimensionModel == GAIA_XY_Z)
4480 			{
4481 			    gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
4482 			}
4483 		      else if (rng->DimensionModel == GAIA_XY_M)
4484 			{
4485 			    gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
4486 			}
4487 		      else
4488 			{
4489 			    gaiaGetPoint (rng->Coords, iv, &x, &y);
4490 			}
4491 		      if (new_rng->DimensionModel == GAIA_XY_Z_M)
4492 			{
4493 			    gaiaSetPointXYZM (new_rng->Coords, iv, x, y, z, m);
4494 			}
4495 		      else if (new_rng->DimensionModel == GAIA_XY_Z)
4496 			{
4497 			    gaiaSetPointXYZ (new_rng->Coords, iv, x, y, z);
4498 			}
4499 		      else if (new_rng->DimensionModel == GAIA_XY_M)
4500 			{
4501 			    gaiaSetPointXYM (new_rng->Coords, iv, x, y, m);
4502 			}
4503 		      else
4504 			{
4505 			    gaiaSetPoint (new_rng->Coords, iv, x, y);
4506 			}
4507 		  }
4508 	    }
4509 	  pg = pg->Next;
4510       }
4511 
4512     return geom1;
4513 }
4514 
4515 GAIAGEO_DECLARE void
gaiaBuildMbr(double x1,double y1,double x2,double y2,int srid,unsigned char ** result,int * size)4516 gaiaBuildMbr (double x1, double y1, double x2, double y2, int srid,
4517 	      unsigned char **result, int *size)
4518 {
4519 /* build a Blob encoded Geometry representing an MBR */
4520     unsigned char *ptr;
4521     double minx;
4522     double maxx;
4523     double miny;
4524     double maxy;
4525     int endian_arch = gaiaEndianArch ();
4526 /* computing MinMax coords */
4527     if (x1 > x2)
4528       {
4529 	  maxx = x1;
4530 	  minx = x2;
4531       }
4532     else
4533       {
4534 	  minx = x1;
4535 	  maxx = x2;
4536       }
4537     if (y1 > y2)
4538       {
4539 	  maxy = y1;
4540 	  miny = y2;
4541       }
4542     else
4543       {
4544 	  miny = y1;
4545 	  maxy = y2;
4546       }
4547 /* computing the Blob size and then allocating it */
4548     *size = 44;			/* header size */
4549     *size += (8 + ((sizeof (double) * 2) * 5));	/* # rings + # points + [x.y] array - exterior ring */
4550     *result = malloc (*size);
4551     ptr = *result;
4552 /* setting the Blob value */
4553     *ptr = GAIA_MARK_START;	/* START signature */
4554     *(ptr + 1) = GAIA_LITTLE_ENDIAN;	/* byte ordering */
4555     gaiaExport32 (ptr + 2, srid, 1, endian_arch);	/* the SRID */
4556     gaiaExport64 (ptr + 6, minx, 1, endian_arch);	/* MBR - minimum X */
4557     gaiaExport64 (ptr + 14, miny, 1, endian_arch);	/* MBR - minimum Y */
4558     gaiaExport64 (ptr + 22, maxx, 1, endian_arch);	/* MBR - maximum X */
4559     gaiaExport64 (ptr + 30, maxy, 1, endian_arch);	/* MBR - maximum Y */
4560     *(ptr + 38) = GAIA_MARK_MBR;	/* MBR signature */
4561     gaiaExport32 (ptr + 39, GAIA_POLYGON, 1, endian_arch);	/* class POLYGON */
4562     gaiaExport32 (ptr + 43, 1, 1, endian_arch);	/* # rings */
4563     gaiaExport32 (ptr + 47, 5, 1, endian_arch);	/* # points - exterior ring */
4564     ptr += 51;
4565 /* setting Envelope points */
4566     gaiaExport64 (ptr, minx, 1, endian_arch);
4567     gaiaExport64 (ptr + 8, miny, 1, endian_arch);
4568     ptr += 16;
4569     gaiaExport64 (ptr, maxx, 1, endian_arch);
4570     gaiaExport64 (ptr + 8, miny, 1, endian_arch);
4571     ptr += 16;
4572     gaiaExport64 (ptr, maxx, 1, endian_arch);
4573     gaiaExport64 (ptr + 8, maxy, 1, endian_arch);
4574     ptr += 16;
4575     gaiaExport64 (ptr, minx, 1, endian_arch);
4576     gaiaExport64 (ptr + 8, maxy, 1, endian_arch);
4577     ptr += 16;
4578     gaiaExport64 (ptr, minx, 1, endian_arch);
4579     gaiaExport64 (ptr + 8, miny, 1, endian_arch);
4580     ptr += 16;
4581     *ptr = GAIA_MARK_END;	/* END signature */
4582 }
4583 
4584 GAIAGEO_DECLARE void
gaiaBuildCircleMbr(double x,double y,double radius,int srid,unsigned char ** result,int * size)4585 gaiaBuildCircleMbr (double x, double y, double radius, int srid,
4586 		    unsigned char **result, int *size)
4587 {
4588 /* build a Blob encoded Geometry representing an MBR */
4589     int sz;
4590     unsigned char *res = NULL;
4591     double minx = x - radius;
4592     double maxx = x + radius;
4593     double miny = y - radius;
4594     double maxy = y + radius;
4595     gaiaBuildMbr (minx, miny, maxx, maxy, srid, &res, &sz);
4596     if (!res)
4597       {
4598 	  *result = NULL;
4599 	  *size = 0;
4600       }
4601     else
4602       {
4603 	  *result = res;
4604 	  *size = sz;
4605       }
4606 }
4607 
4608 GAIAGEO_DECLARE void
gaiaBuildFilterMbr(double x1,double y1,double x2,double y2,int mode,unsigned char ** result,int * size)4609 gaiaBuildFilterMbr (double x1, double y1, double x2, double y2, int mode,
4610 		    unsigned char **result, int *size)
4611 {
4612 /* build a filter for an MBR */
4613     unsigned char *ptr;
4614     double minx;
4615     double maxx;
4616     double miny;
4617     double maxy;
4618     int endian_arch = gaiaEndianArch ();
4619     char filter = GAIA_FILTER_MBR_WITHIN;
4620     if (mode == GAIA_FILTER_MBR_CONTAINS)
4621 	filter = GAIA_FILTER_MBR_CONTAINS;
4622     if (mode == GAIA_FILTER_MBR_INTERSECTS)
4623 	filter = GAIA_FILTER_MBR_INTERSECTS;
4624     if (mode == GAIA_FILTER_MBR_DECLARE)
4625 	filter = GAIA_FILTER_MBR_DECLARE;
4626 /* computing MinMax coords */
4627     if (x1 > x2)
4628       {
4629 	  maxx = x1;
4630 	  minx = x2;
4631       }
4632     else
4633       {
4634 	  minx = x1;
4635 	  maxx = x2;
4636       }
4637     if (y1 > y2)
4638       {
4639 	  maxy = y1;
4640 	  miny = y2;
4641       }
4642     else
4643       {
4644 	  miny = y1;
4645 	  maxy = y2;
4646       }
4647 /* computing the Blob size and then allocating it */
4648     *size = 37;			/* MBR filter size */
4649     *result = malloc (*size);
4650     ptr = *result;
4651 /* setting the Blob value */
4652     *ptr = filter;		/* signature */
4653     ptr++;
4654     gaiaExport64 (ptr, minx, 1, endian_arch);	/* MBR - minimum X */
4655     ptr += 8;
4656     *ptr = filter;		/* signature */
4657     ptr++;
4658     gaiaExport64 (ptr, miny, 1, endian_arch);	/* MBR - minimum Y */
4659     ptr += 8;
4660     *ptr = filter;		/* signature */
4661     ptr++;
4662     gaiaExport64 (ptr, maxx, 1, endian_arch);	/* MBR - maximum X */
4663     ptr += 8;
4664     *ptr = filter;		/* signature */
4665     ptr++;
4666     gaiaExport64 (ptr, maxy, 1, endian_arch);	/* MBR - maximum Y */
4667     ptr += 8;
4668     *ptr = filter;		/* signature */
4669 }
4670 
4671 
4672 GAIAGEO_DECLARE int
gaiaParseFilterMbr(unsigned char * ptr,int size,double * minx,double * miny,double * maxx,double * maxy,int * mode)4673 gaiaParseFilterMbr (unsigned char *ptr, int size, double *minx, double *miny,
4674 		    double *maxx, double *maxy, int *mode)
4675 {
4676 /* parsing a filter for an MBR */
4677     char decl_mode;
4678     int endian_arch = gaiaEndianArch ();
4679     if (size != 37)
4680 	return 0;		/* cannot be an MBR Filter */
4681     if (!ptr)
4682 	return 0;		/* cannot be an MBR Filter */
4683     decl_mode = *(ptr + 0);
4684     if (decl_mode == GAIA_FILTER_MBR_WITHIN)
4685 	;
4686     else if (decl_mode == GAIA_FILTER_MBR_CONTAINS)
4687 	;
4688     else if (decl_mode == GAIA_FILTER_MBR_INTERSECTS)
4689 	;
4690     else if (decl_mode == GAIA_FILTER_MBR_DECLARE)
4691 	;
4692     else
4693 	return 0;		/* cannot be an MBR Filter */
4694     if (*(ptr + 9)
4695 	== decl_mode
4696 	&& *(ptr +
4697 	     18) ==
4698 	decl_mode && *(ptr + 27) == decl_mode && *(ptr + 36) == decl_mode)
4699 	;
4700     else
4701 	return 0;		/* cannot be an MBR Filter */
4702     *mode = decl_mode;
4703     *minx = gaiaImport64 (ptr + 1, 1, endian_arch);
4704     *miny = gaiaImport64 (ptr + 10, 1, endian_arch);
4705     *maxx = gaiaImport64 (ptr + 19, 1, endian_arch);
4706     *maxy = gaiaImport64 (ptr + 28, 1, endian_arch);
4707     return 1;
4708 }
4709 
4710 GAIAGEO_DECLARE int
gaiaGetMbrMinX(const unsigned char * blob,unsigned int size,double * minx)4711 gaiaGetMbrMinX (const unsigned char *blob, unsigned int size, double *minx)
4712 {
4713 /* returns the MinX coordinate value for a Blob encoded Geometry */
4714     int little_endian;
4715     int endian_arch = gaiaEndianArch ();
4716 
4717     if (size == 24 || size == 32 || size == 40)
4718       {
4719 	  /* testing for a possible TinyPoint BLOB */
4720 	  if (*(blob + 0) == GAIA_MARK_START &&
4721 	      (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN
4722 	       || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
4723 	      && *(blob + (size - 1)) == GAIA_MARK_END)
4724 	    {
4725 		if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN)
4726 		    little_endian = 1;
4727 		else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
4728 		    little_endian = 0;
4729 		else
4730 		    return 0;	/* unknown encoding; neither little-endian nor big-endian */
4731 		*minx = gaiaImport64 (blob + 7, little_endian, endian_arch);
4732 		return 1;
4733 	    }
4734       }
4735 
4736     if (size < 45)
4737 	return 0;		/* cannot be an internal BLOB WKB geometry */
4738     if (*(blob + 0) != GAIA_MARK_START)
4739 	return 0;		/* failed to recognize START signature */
4740     if (*(blob + (size - 1)) != GAIA_MARK_END)
4741 	return 0;		/* failed to recognize END signature */
4742     if (*(blob + 38) != GAIA_MARK_MBR)
4743 	return 0;		/* failed to recognize MBR signature */
4744     if (*(blob + 1) == GAIA_LITTLE_ENDIAN)
4745 	little_endian = 1;
4746     else if (*(blob + 1) == GAIA_BIG_ENDIAN)
4747 	little_endian = 0;
4748     else
4749 	return 0;		/* unknown encoding; neither little-endian nor big-endian */
4750     *minx = gaiaImport64 (blob + 6, little_endian, endian_arch);
4751     return 1;
4752 }
4753 
4754 GAIAGEO_DECLARE int
gaiaGetMbrMaxX(const unsigned char * blob,unsigned int size,double * maxx)4755 gaiaGetMbrMaxX (const unsigned char *blob, unsigned int size, double *maxx)
4756 {
4757 /* returns the MaxX coordinate value for a Blob encoded Geometry */
4758     int little_endian;
4759     int endian_arch = gaiaEndianArch ();
4760 
4761     if (size == 24 || size == 32 || size == 40)
4762       {
4763 	  /* testing for a possible TinyPoint BLOB */
4764 	  if (*(blob + 0) == GAIA_MARK_START &&
4765 	      (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN
4766 	       || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
4767 	      && *(blob + (size - 1)) == GAIA_MARK_END)
4768 	    {
4769 		if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN)
4770 		    little_endian = 1;
4771 		else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
4772 		    little_endian = 0;
4773 		else
4774 		    return 0;	/* unknown encoding; neither little-endian nor big-endian */
4775 		*maxx = gaiaImport64 (blob + 7, little_endian, endian_arch);
4776 		return 1;
4777 	    }
4778       }
4779 
4780     if (size < 45)
4781 	return 0;		/* cannot be an internal BLOB WKB geometry */
4782     if (*(blob + 0) != GAIA_MARK_START)
4783 	return 0;		/* failed to recognize START signature */
4784     if (*(blob + (size - 1)) != GAIA_MARK_END)
4785 	return 0;		/* failed to recognize END signature */
4786     if (*(blob + 38) != GAIA_MARK_MBR)
4787 	return 0;		/* failed to recognize MBR signature */
4788     if (*(blob + 1) == GAIA_LITTLE_ENDIAN)
4789 	little_endian = 1;
4790     else if (*(blob + 1) == GAIA_BIG_ENDIAN)
4791 	little_endian = 0;
4792     else
4793 	return 0;		/* unknown encoding; neither little-endian nor big-endian */
4794     *maxx = gaiaImport64 (blob + 22, little_endian, endian_arch);
4795     return 1;
4796 }
4797 
4798 GAIAGEO_DECLARE int
gaiaGetMbrMinY(const unsigned char * blob,unsigned int size,double * miny)4799 gaiaGetMbrMinY (const unsigned char *blob, unsigned int size, double *miny)
4800 {
4801 /* returns the MinY coordinate value for a Blob encoded Geometry */
4802     int little_endian;
4803     int endian_arch = gaiaEndianArch ();
4804 
4805     if (size == 24 || size == 32 || size == 40)
4806       {
4807 	  /* testing for a possible TinyPoint BLOB */
4808 	  if (*(blob + 0) == GAIA_MARK_START &&
4809 	      (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN
4810 	       || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
4811 	      && *(blob + (size - 1)) == GAIA_MARK_END)
4812 	    {
4813 		if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN)
4814 		    little_endian = 1;
4815 		else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
4816 		    little_endian = 0;
4817 		else
4818 		    return 0;	/* unknown encoding; neither little-endian nor big-endian */
4819 		*miny = gaiaImport64 (blob + 15, little_endian, endian_arch);
4820 		return 1;
4821 	    }
4822       }
4823 
4824     if (size < 45)
4825 	return 0;		/* cannot be an internal BLOB WKB geometry */
4826     if (*(blob + 0) != GAIA_MARK_START)
4827 	return 0;		/* failed to recognize START signature */
4828     if (*(blob + (size - 1)) != GAIA_MARK_END)
4829 	return 0;		/* failed to recognize END signature */
4830     if (*(blob + 38) != GAIA_MARK_MBR)
4831 	return 0;		/* failed to recognize MBR signature */
4832     if (*(blob + 1) == GAIA_LITTLE_ENDIAN)
4833 	little_endian = 1;
4834     else if (*(blob + 1) == GAIA_BIG_ENDIAN)
4835 	little_endian = 0;
4836     else
4837 	return 0;		/* unknown encoding; neither little-endian nor big-endian */
4838     *miny = gaiaImport64 (blob + 14, little_endian, endian_arch);
4839     return 1;
4840 }
4841 
4842 GAIAGEO_DECLARE int
gaiaGetMbrMaxY(const unsigned char * blob,unsigned int size,double * maxy)4843 gaiaGetMbrMaxY (const unsigned char *blob, unsigned int size, double *maxy)
4844 {
4845 /* returns the MaxY coordinate value for a Blob encoded Geometry */
4846     int little_endian;
4847     int endian_arch = gaiaEndianArch ();
4848 
4849     if (size == 24 || size == 32 || size == 40)
4850       {
4851 	  /* testing for a possible TinyPoint BLOB */
4852 	  if (*(blob + 0) == GAIA_MARK_START &&
4853 	      (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN
4854 	       || *(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
4855 	      && *(blob + (size - 1)) == GAIA_MARK_END)
4856 	    {
4857 		if (*(blob + 1) == GAIA_TINYPOINT_LITTLE_ENDIAN)
4858 		    little_endian = 1;
4859 		else if (*(blob + 1) == GAIA_TINYPOINT_BIG_ENDIAN)
4860 		    little_endian = 0;
4861 		else
4862 		    return 0;	/* unknown encoding; neither little-endian nor big-endian */
4863 		*maxy = gaiaImport64 (blob + 15, little_endian, endian_arch);
4864 		return 1;
4865 	    }
4866       }
4867 
4868     if (size < 45)
4869 	return 0;		/* cannot be an internal BLOB WKB geometry */
4870     if (*(blob + 0) != GAIA_MARK_START)
4871 	return 0;		/* failed to recognize START signature */
4872     if (*(blob + (size - 1)) != GAIA_MARK_END)
4873 	return 0;		/* failed to recognize END signature */
4874     if (*(blob + 38) != GAIA_MARK_MBR)
4875 	return 0;		/* failed to recognize MBR signature */
4876     if (*(blob + 1) == GAIA_LITTLE_ENDIAN)
4877 	little_endian = 1;
4878     else if (*(blob + 1) == GAIA_BIG_ENDIAN)
4879 	little_endian = 0;
4880     else
4881 	return 0;		/* unknown encoding; neither little-endian nor big-endian */
4882     *maxy = gaiaImport64 (blob + 30, little_endian, endian_arch);
4883     return 1;
4884 }
4885 
4886 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaAddMeasure(gaiaGeomCollPtr geom,double m_start,double m_end)4887 gaiaAddMeasure (gaiaGeomCollPtr geom, double m_start, double m_end)
4888 {
4889 /* linearly interpolates M-values between the start and end points. */
4890     double total_length;
4891     double progressive_length;
4892     gaiaGeomCollPtr geo2;
4893     gaiaLinestringPtr pL;
4894     gaiaLinestringPtr pL2;
4895     int iv;
4896     double x;
4897     double y;
4898     double z;
4899     double m;
4900     double x0;
4901     double y0;
4902     double mm;
4903     double percent;
4904     double interval = m_end - m_start;
4905 
4906     if (!geom)
4907 	return NULL;
4908 /* only Linestring or MultiLinestrings are accepted */
4909     if (geom->FirstPoint != NULL)
4910 	return NULL;
4911     if (geom->FirstPolygon != NULL)
4912 	return NULL;
4913     if (geom->FirstLinestring == NULL)
4914 	return NULL;
4915 
4916 /* computing the total length */
4917     total_length = 0.0;
4918     pL = geom->FirstLinestring;
4919     while (pL != NULL)
4920       {
4921 	  for (iv = 0; iv < pL->Points; iv++)
4922 	    {
4923 		z = 0.0;
4924 		m = 0.0;
4925 		if (pL->DimensionModel == GAIA_XY_Z)
4926 		  {
4927 		      gaiaGetPointXYZ (pL->Coords, iv, &x, &y, &z);
4928 		  }
4929 		else if (pL->DimensionModel == GAIA_XY_M)
4930 		  {
4931 		      gaiaGetPointXYM (pL->Coords, iv, &x, &y, &m);
4932 		  }
4933 		else if (pL->DimensionModel == GAIA_XY_Z_M)
4934 		  {
4935 		      gaiaGetPointXYZM (pL->Coords, iv, &x, &y, &z, &m);
4936 		  }
4937 		else
4938 		  {
4939 		      gaiaGetPoint (pL->Coords, iv, &x, &y);
4940 		  }
4941 
4942 		if (iv != 0)
4943 		    total_length +=
4944 			sqrt (((x0 - x) * (x0 - x)) + ((y0 - y) * (y0 - y)));
4945 		x0 = x;
4946 		y0 = y;
4947 	    }
4948 	  pL = pL->Next;
4949       }
4950 
4951 /* creating the output geometry */
4952     progressive_length = 0.0;
4953     if (geom->DimensionModel == GAIA_XY_Z)
4954 	geo2 = gaiaAllocGeomCollXYZM ();
4955     else if (geom->DimensionModel == GAIA_XY_M)
4956 	geo2 = gaiaAllocGeomCollXYM ();
4957     else if (geom->DimensionModel == GAIA_XY_Z_M)
4958 	geo2 = gaiaAllocGeomCollXYZM ();
4959     else
4960 	geo2 = gaiaAllocGeomCollXYM ();
4961     geo2->Srid = geom->Srid;
4962     pL = geom->FirstLinestring;
4963     while (pL != NULL)
4964       {
4965 	  pL2 = gaiaAddLinestringToGeomColl (geo2, pL->Points);
4966 	  for (iv = 0; iv < pL->Points; iv++)
4967 	    {
4968 		z = 0.0;
4969 		m = 0.0;
4970 		if (pL->DimensionModel == GAIA_XY_Z)
4971 		  {
4972 		      gaiaGetPointXYZ (pL->Coords, iv, &x, &y, &z);
4973 		  }
4974 		else if (pL->DimensionModel == GAIA_XY_M)
4975 		  {
4976 		      gaiaGetPointXYM (pL->Coords, iv, &x, &y, &m);
4977 		  }
4978 		else if (pL->DimensionModel == GAIA_XY_Z_M)
4979 		  {
4980 		      gaiaGetPointXYZM (pL->Coords, iv, &x, &y, &z, &m);
4981 		  }
4982 		else
4983 		  {
4984 		      gaiaGetPoint (pL->Coords, iv, &x, &y);
4985 		  }
4986 
4987 		if (iv != 0)
4988 		    progressive_length +=
4989 			sqrt (((x0 - x) * (x0 - x)) + ((y0 - y) * (y0 - y)));
4990 		x0 = x;
4991 		y0 = y;
4992 
4993 		/* linealy interpolating M-values */
4994 		percent = progressive_length / total_length;
4995 		mm = m_start + (interval * percent);
4996 		if (pL2->DimensionModel == GAIA_XY_M)
4997 		  {
4998 		      gaiaSetPointXYM (pL2->Coords, iv, x, y, mm);
4999 		  }
5000 		else
5001 		  {
5002 		      gaiaSetPointXYZM (pL2->Coords, iv, x, y, z, mm);
5003 		  }
5004 	    }
5005 	  pL = pL->Next;
5006       }
5007 
5008     return geo2;
5009 }
5010 
5011 GAIAGEO_DECLARE int
gaiaInterpolatePoint(const void * p_cache,gaiaGeomCollPtr line,gaiaGeomCollPtr point,double * m_value)5012 gaiaInterpolatePoint (const void *p_cache, gaiaGeomCollPtr line,
5013 		      gaiaGeomCollPtr point, double *m_value)
5014 {
5015 /* Will interpolate the M-value for a LinestringM at the point closest to the given Point */
5016     gaiaLinestringPtr pL;
5017     int iv;
5018     double x;
5019     double y;
5020     double m;
5021     double z;
5022     double fraction;
5023     double x0;
5024     double y0;
5025     double m0;
5026     double progressive_length;
5027     double pl0;
5028     double length;
5029     double normalized_len;
5030 
5031     if (!line)
5032 	return 0;
5033     if (!point)
5034 	return 0;
5035 /* only a Linestring M is accepted as the first geom */
5036     if (line->FirstPoint != NULL)
5037 	return 0;
5038     if (line->FirstPolygon != NULL)
5039 	return 0;
5040     if (line->FirstLinestring == NULL)
5041 	return 0;
5042     if (line->FirstLinestring != line->LastLinestring)
5043 	return 0;
5044     if (line->DimensionModel == GAIA_XY_M
5045 	|| line->DimensionModel == GAIA_XY_Z_M)
5046 	;
5047     else
5048 	return 0;
5049 /* only a Point is accepted as the second geom */
5050     if (point->FirstPolygon != NULL)
5051 	return 0;
5052     if (point->FirstLinestring != NULL)
5053 	return 0;
5054     if (point->FirstPoint == NULL)
5055 	return 0;
5056     if (point->FirstPoint != point->LastPoint)
5057 	return 0;
5058 
5059 #ifndef OMIT_GEOS		/* only if GEOS is supported */
5060 
5061 /* locating the Point along the Line */
5062     if (p_cache != NULL)
5063       {
5064 	  if (!gaiaGeomCollLengthOrPerimeter_r (p_cache, line, 0, &length))
5065 	      return 0;
5066 	  fraction = gaiaLineLocatePoint_r (p_cache, line, point);
5067       }
5068     else
5069       {
5070 	  if (!gaiaGeomCollLengthOrPerimeter (line, 0, &length))
5071 	      return 0;
5072 	  fraction = gaiaLineLocatePoint (line, point);
5073       }
5074     normalized_len = length * fraction;
5075 
5076     pL = line->FirstLinestring;
5077     if (fraction <= 0.0)
5078       {
5079 	  /* special case: assuming the start point */
5080 	  z = 0.0;
5081 	  if (pL->DimensionModel == GAIA_XY_M)
5082 	    {
5083 		gaiaGetPointXYM (pL->Coords, 0, &x, &y, &m);
5084 	    }
5085 	  else
5086 	    {
5087 		gaiaGetPointXYZM (pL->Coords, 0, &x, &y, &z, &m);
5088 	    }
5089 	  *m_value = m;
5090 	  return 1;
5091       }
5092     if (fraction >= 1.0)
5093       {
5094 	  /* special case: assuming the end point */
5095 	  z = 0.0;
5096 	  iv = pL->Points - 1;
5097 	  if (pL->DimensionModel == GAIA_XY_M)
5098 	    {
5099 		gaiaGetPointXYM (pL->Coords, iv, &x, &y, &m);
5100 	    }
5101 	  else
5102 	    {
5103 		gaiaGetPointXYZM (pL->Coords, iv, &x, &y, &z, &m);
5104 	    }
5105 	  *m_value = m;
5106 	  return 1;
5107       }
5108 
5109 /* computing the progressive length */
5110     progressive_length = 0.0;
5111     for (iv = 0; iv < pL->Points; iv++)
5112       {
5113 	  z = 0.0;
5114 	  if (pL->DimensionModel == GAIA_XY_M)
5115 	    {
5116 		gaiaGetPointXYM (pL->Coords, iv, &x, &y, &m);
5117 	    }
5118 	  else
5119 	    {
5120 		gaiaGetPointXYZM (pL->Coords, iv, &x, &y, &z, &m);
5121 	    }
5122 
5123 	  if (iv != 0)
5124 	    {
5125 		double length =
5126 		    sqrt (((x0 - x) * (x0 - x)) + ((y0 - y) * (y0 - y)));
5127 		progressive_length += length;
5128 
5129 		if (progressive_length == normalized_len)
5130 		  {
5131 		      /* special case: exactly intercepting a vertex */
5132 		      *m_value = m;
5133 		      return 1;
5134 		  }
5135 		if (progressive_length > normalized_len)
5136 		  {
5137 		      /* interpolating the M-Value */
5138 		      double interval = m - m0;
5139 		      double diff = normalized_len - pl0;
5140 		      double ratio = diff / length;
5141 		      *m_value = m0 + (interval * ratio);
5142 		      break;
5143 		  }
5144 	    }
5145 	  x0 = x;
5146 	  y0 = y;
5147 	  m0 = m;
5148 	  pl0 = progressive_length;
5149       }
5150     return 1;
5151 
5152 #else
5153     return 0;
5154 #endif /* end GEOS conditional */
5155 }
5156 
5157 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaLocateBetweenMeasures(gaiaGeomCollPtr geom,double m_start,double m_end)5158 gaiaLocateBetweenMeasures (gaiaGeomCollPtr geom, double m_start, double m_end)
5159 {
5160 /* extracts points/linestrings accordingly to a range of measures */
5161     gaiaPointPtr pt;
5162     gaiaLinestringPtr ln;
5163     gaiaLinestringPtr new_line;
5164     gaiaGeomCollPtr new_geom = NULL;
5165     gaiaDynamicLinePtr dyn = NULL;
5166     int iv;
5167     double x;
5168     double y;
5169     double z;
5170     double m;
5171     if (!geom)
5172 	return NULL;
5173     if (geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
5174 	return NULL;
5175     if (geom->FirstPolygon != NULL)
5176 	return NULL;
5177     if (geom->DimensionModel == GAIA_XY_M)
5178 	new_geom = gaiaAllocGeomCollXYM ();
5179     else if (geom->DimensionModel == GAIA_XY_Z_M)
5180 	new_geom = gaiaAllocGeomCollXYZM ();
5181     else
5182 	return NULL;
5183     new_geom->Srid = geom->Srid;
5184     new_geom->DeclaredType = geom->DeclaredType;
5185     pt = geom->FirstPoint;
5186     while (pt)
5187       {
5188 	  /* extracting POINTs */
5189 	  if (pt->M >= m_start && pt->M <= m_end)
5190 	    {
5191 		if (geom->DimensionModel == GAIA_XY_M)
5192 		    gaiaAddPointToGeomCollXYM (new_geom, pt->X, pt->Y, pt->M);
5193 		else if (geom->DimensionModel == GAIA_XY_Z_M)
5194 		    gaiaAddPointToGeomCollXYZM (new_geom, pt->X, pt->Y,
5195 						pt->Z, pt->M);
5196 	    }
5197 	  pt = pt->Next;
5198       }
5199     ln = geom->FirstLinestring;
5200     while (ln)
5201       {
5202 	  /* extracting LINESTRINGs */
5203 	  for (iv = 0; iv < ln->Points; iv++)
5204 	    {
5205 		z = 0.0;
5206 		if (ln->DimensionModel == GAIA_XY_Z_M)
5207 		  {
5208 		      gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
5209 		  }
5210 		else
5211 		  {
5212 		      gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
5213 		  }
5214 		if (m >= m_start && m <= m_end)
5215 		  {
5216 		      /* found a valid vertex */
5217 		      if (dyn == NULL)
5218 			  dyn = gaiaAllocDynamicLine ();
5219 		      if (ln->DimensionModel == GAIA_XY_Z_M)
5220 			  gaiaAppendPointZMToDynamicLine (dyn, x, y, z, m);
5221 		      else
5222 			  gaiaAppendPointMToDynamicLine (dyn, x, y, m);
5223 		  }
5224 		else
5225 		  {
5226 		      if (dyn != NULL)
5227 			{
5228 			    /* evaluting the latest sequence found */
5229 			    int cnt = 0;
5230 			    pt = dyn->First;
5231 			    while (pt)
5232 			      {
5233 				  /* counting how many points are there */
5234 				  cnt++;
5235 				  pt = pt->Next;
5236 			      }
5237 			    if (cnt > 1)
5238 			      {
5239 				  /* creating a Linestring */
5240 				  new_line =
5241 				      gaiaAddLinestringToGeomColl (new_geom,
5242 								   cnt);
5243 				  cnt = 0;
5244 				  pt = dyn->First;
5245 				  while (pt)
5246 				    {
5247 
5248 					if (new_line->DimensionModel ==
5249 					    GAIA_XY_Z_M)
5250 					  {
5251 					      gaiaSetPointXYZM
5252 						  (new_line->Coords, cnt, pt->X,
5253 						   pt->Y, pt->Z, pt->M);
5254 					  }
5255 					else
5256 					  {
5257 					      gaiaSetPointXYM (new_line->Coords,
5258 							       cnt, pt->X,
5259 							       pt->Y, pt->M);
5260 					  }
5261 					cnt++;
5262 					pt = pt->Next;
5263 				    }
5264 			      }
5265 			    else if (cnt == 1)
5266 			      {
5267 				  /* creating a Point */
5268 				  pt = dyn->First;
5269 				  if (geom->DimensionModel == GAIA_XY_M)
5270 				      gaiaAddPointToGeomCollXYM (new_geom,
5271 								 pt->X, pt->Y,
5272 								 pt->M);
5273 				  else if (geom->DimensionModel == GAIA_XY_Z_M)
5274 				      gaiaAddPointToGeomCollXYZM (new_geom,
5275 								  pt->X, pt->Y,
5276 								  pt->Z, pt->M);
5277 			      }
5278 			    gaiaFreeDynamicLine (dyn);
5279 			    dyn = NULL;
5280 			}
5281 		  }
5282 	    }
5283 	  if (dyn != NULL)
5284 	    {
5285 		/* evaluting the latest sequence found */
5286 		int cnt = 0;
5287 		pt = dyn->First;
5288 		while (pt)
5289 		  {
5290 		      /* counting how many points are there */
5291 		      cnt++;
5292 		      pt = pt->Next;
5293 		  }
5294 		if (cnt > 1)
5295 		  {
5296 		      /* creating a Linestring */
5297 		      new_line = gaiaAddLinestringToGeomColl (new_geom, cnt);
5298 		      cnt = 0;
5299 		      pt = dyn->First;
5300 		      while (pt)
5301 			{
5302 
5303 			    if (new_line->DimensionModel == GAIA_XY_Z_M)
5304 			      {
5305 				  gaiaSetPointXYZM (new_line->Coords, cnt,
5306 						    pt->X, pt->Y, pt->Z, pt->M);
5307 			      }
5308 			    else
5309 			      {
5310 				  gaiaSetPointXYM (new_line->Coords,
5311 						   cnt, pt->X, pt->Y, pt->M);
5312 			      }
5313 			    cnt++;
5314 			    pt = pt->Next;
5315 			}
5316 		  }
5317 		else if (cnt == 1)
5318 		  {
5319 		      /* creating a Point */
5320 		      pt = dyn->First;
5321 		      if (geom->DimensionModel == GAIA_XY_M)
5322 			  gaiaAddPointToGeomCollXYM (new_geom,
5323 						     pt->X, pt->Y, pt->M);
5324 		      else if (geom->DimensionModel == GAIA_XY_Z_M)
5325 			  gaiaAddPointToGeomCollXYZM (new_geom,
5326 						      pt->X, pt->Y,
5327 						      pt->Z, pt->M);
5328 		  }
5329 		gaiaFreeDynamicLine (dyn);
5330 		dyn = NULL;
5331 	    }
5332 	  ln = ln->Next;
5333       }
5334     if (new_geom->FirstPoint == NULL && new_geom->FirstLinestring == NULL)
5335       {
5336 	  /* empty result: returning NULL */
5337 	  gaiaFreeGeomColl (new_geom);
5338 	  return NULL;
5339       }
5340     return new_geom;
5341 }
5342 
5343 GAIAGEO_DECLARE int
gaiaIsValidTrajectory(gaiaGeomCollPtr geom)5344 gaiaIsValidTrajectory (gaiaGeomCollPtr geom)
5345 {
5346 /* Checks if a Geometry object is valid Trajectory */
5347     gaiaLinestringPtr ln;
5348     int iv;
5349     double x;
5350     double y;
5351     double z;
5352     double m;
5353     double prev_m;
5354     if (!geom)
5355 	return 0;
5356     if (geom->FirstPoint != NULL || geom->FirstLinestring == NULL
5357 	|| geom->FirstPolygon != NULL)
5358 	return 0;		/* not a Linestring */
5359     if (geom->FirstLinestring != geom->LastLinestring)
5360 	return 0;		/* not a simple Linestring */
5361     if (geom->DimensionModel == GAIA_XY_M
5362 	|| geom->DimensionModel == GAIA_XY_Z_M)
5363 	;
5364     else
5365 	return 0;		/* not supporting M_values */
5366     ln = geom->FirstLinestring;
5367     for (iv = 0; iv < ln->Points; iv++)
5368       {
5369 	  z = 0.0;
5370 	  if (ln->DimensionModel == GAIA_XY_Z_M)
5371 	    {
5372 		gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
5373 	    }
5374 	  else
5375 	    {
5376 		gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
5377 	    }
5378 	  if (iv != 0)
5379 	    {
5380 		if (m <= prev_m)
5381 		    return 0;
5382 	    }
5383 	  prev_m = m;
5384       }
5385     return 1;
5386 }
5387 
5388 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaTrajectoryInterpolatePoint(gaiaGeomCollPtr geom,double m_value)5389 gaiaTrajectoryInterpolatePoint (gaiaGeomCollPtr geom, double m_value)
5390 {
5391 /* attempts to interpolate a Point along a Trajectory accordingly to given M-Value */
5392     gaiaGeomCollPtr point;
5393     gaiaLinestringPtr ln;
5394     int iv;
5395     double x;
5396     double y;
5397     double z;
5398     double m;
5399     double prev_x;
5400     double prev_y;
5401     double prev_z;
5402     double prev_m;
5403     if (!gaiaIsValidTrajectory (geom))
5404 	return NULL;
5405 
5406 /* creating the Geometry to be returned */
5407     if (geom->DimensionModel == GAIA_XY_M)
5408 	point = gaiaAllocGeomCollXYM ();
5409     else if (geom->DimensionModel == GAIA_XY_Z_M)
5410 	point = gaiaAllocGeomCollXYZM ();
5411     else
5412 	return NULL;
5413     point->Srid = geom->Srid;
5414     point->DeclaredType = GAIA_POINT;
5415 
5416     ln = geom->FirstLinestring;
5417 /* testing if m < StartPoint */
5418     if (ln->DimensionModel == GAIA_XY_Z_M)
5419       {
5420 	  gaiaGetPointXYZM (ln->Coords, 0, &x, &y, &z, &m);
5421       }
5422     else
5423       {
5424 	  gaiaGetPointXYM (ln->Coords, 0, &x, &y, &m);
5425       }
5426     if (m_value < m)
5427       {
5428 	  if (ln->DimensionModel == GAIA_XY_Z_M)
5429 	      gaiaAddPointToGeomCollXYZM (point, x, y, z, m_value);
5430 	  else
5431 	      gaiaAddPointToGeomCollXYM (point, x, y, m_value);
5432 	  return point;
5433       }
5434 
5435 /* testing if m > EndPoint */
5436     iv = ln->Points - 1;
5437     if (ln->DimensionModel == GAIA_XY_Z_M)
5438       {
5439 	  gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
5440       }
5441     else
5442       {
5443 	  gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
5444       }
5445     if (m_value > m)
5446       {
5447 	  if (ln->DimensionModel == GAIA_XY_Z_M)
5448 	      gaiaAddPointToGeomCollXYZM (point, x, y, z, m_value);
5449 	  else
5450 	      gaiaAddPointToGeomCollXYM (point, x, y, m_value);
5451 	  return point;
5452       }
5453 
5454     prev_m = 0.0 - DBL_MAX;
5455     ln = geom->FirstLinestring;
5456     for (iv = 0; iv < ln->Points; iv++)
5457       {
5458 	  z = 0.0;
5459 	  if (ln->DimensionModel == GAIA_XY_Z_M)
5460 	    {
5461 		gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
5462 	    }
5463 	  else
5464 	    {
5465 		gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
5466 	    }
5467 	  if (m_value == m)
5468 	    {
5469 		if (ln->DimensionModel == GAIA_XY_Z_M)
5470 		    gaiaAddPointToGeomCollXYZM (point, x, y, z, m_value);
5471 		else
5472 		    gaiaAddPointToGeomCollXYM (point, x, y, m_value);
5473 		return point;
5474 	    }
5475 	  if (m_value > prev_m && m_value < m)
5476 	    {
5477 		/* interpolating the Point */
5478 		double ix;
5479 		double iy;
5480 		double iz;
5481 		double diff = m - prev_m;
5482 		double m_diff = m_value - prev_m;
5483 		double ratio = diff / m_diff;
5484 		diff = x - prev_x;
5485 		ix = prev_x + (diff / ratio);
5486 		diff = y - prev_y;
5487 		iy = prev_y + (diff / ratio);
5488 		diff = z - prev_z;
5489 		iz = prev_z + (diff / ratio);
5490 		if (ln->DimensionModel == GAIA_XY_Z_M)
5491 		    gaiaAddPointToGeomCollXYZM (point, ix, iy, iz, m_value);
5492 		else
5493 		    gaiaAddPointToGeomCollXYM (point, ix, iy, m_value);
5494 		return point;
5495 	    }
5496 	  prev_x = x;
5497 	  prev_y = y;
5498 	  prev_z = z;
5499 	  prev_m = m;
5500       }
5501 
5502     gaiaFreeGeomColl (point);
5503     return NULL;
5504 }
5505 
5506 static int
check_closed_multi_linestring(gaiaGeomCollPtr geom,int single)5507 check_closed_multi_linestring (gaiaGeomCollPtr geom, int single)
5508 {
5509 /* check if :
5510 /   - this geometry is a (multi) Linestring
5511 /   - all Linestrings are effectively closed
5512 */
5513     int pts = 0;
5514     int lns = 0;
5515     int pgs = 0;
5516     int closed = 0;
5517     gaiaPointPtr pt;
5518     gaiaLinestringPtr ln;
5519     gaiaPolygonPtr pg;
5520     pt = geom->FirstPoint;
5521     while (pt)
5522       {
5523 	  pts++;
5524 	  pt = pt->Next;
5525       }
5526     ln = geom->FirstLinestring;
5527     while (ln)
5528       {
5529 	  if (gaiaIsClosed (ln))
5530 	      closed++;
5531 	  lns++;
5532 	  ln = ln->Next;
5533       }
5534     pg = geom->FirstPolygon;
5535     while (pg)
5536       {
5537 	  pgs++;
5538 	  pg = pg->Next;
5539       }
5540     if (closed != lns)
5541 	return 0;
5542     if (single)
5543       {
5544 	  if (pts == 0 && lns == 1 && pgs == 0)
5545 	      return lns;
5546       }
5547     else
5548       {
5549 	  if (pts == 0 && lns >= 1 && pgs == 0)
5550 	      return lns;
5551       }
5552     return 0;
5553 }
5554 
5555 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaMakePolygon(gaiaGeomCollPtr exterior,gaiaGeomCollPtr interiors)5556 gaiaMakePolygon (gaiaGeomCollPtr exterior, gaiaGeomCollPtr interiors)
5557 {
5558 /* reassembling a Polygon from closed Linestrings */
5559     gaiaGeomCollPtr geom;
5560     gaiaPolygonPtr pg;
5561     gaiaRingPtr rng;
5562     gaiaLinestringPtr ln;
5563     int iv;
5564     double x;
5565     double y;
5566     double z;
5567     double m;
5568     int num_interiors = 0;
5569     int ib;
5570 
5571     if (exterior == NULL)
5572 	return NULL;
5573     if (!check_closed_multi_linestring (exterior, 1))
5574 	return NULL;
5575     if (interiors != NULL)
5576       {
5577 	  num_interiors = check_closed_multi_linestring (interiors, 0);
5578 	  if (!num_interiors)
5579 	      return NULL;
5580       }
5581 
5582 /* reassembling the Polygon */
5583     if (exterior->DimensionModel == GAIA_XY_Z)
5584 	geom = gaiaAllocGeomCollXYZ ();
5585     else if (exterior->DimensionModel == GAIA_XY_M)
5586 	geom = gaiaAllocGeomCollXYM ();
5587     else if (exterior->DimensionModel == GAIA_XY_Z_M)
5588 	geom = gaiaAllocGeomCollXYZM ();
5589     else
5590 	geom = gaiaAllocGeomColl ();
5591     geom->Srid = exterior->Srid;
5592     ln = exterior->FirstLinestring;
5593     pg = gaiaAddPolygonToGeomColl (geom, ln->Points, num_interiors);
5594     rng = pg->Exterior;
5595     for (iv = 0; iv < ln->Points; iv++)
5596       {
5597 	  /* exterior ring */
5598 	  m = 0.0;
5599 	  z = 0.0;
5600 	  switch (ln->DimensionModel)
5601 	    {
5602 	    case GAIA_XY:
5603 		gaiaGetPoint (ln->Coords, iv, &x, &y);
5604 		break;
5605 	    case GAIA_XY_Z:
5606 		gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
5607 		break;
5608 	    case GAIA_XY_M:
5609 		gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
5610 		break;
5611 	    case GAIA_XY_Z_M:
5612 		gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
5613 		break;
5614 	    default:
5615 		return 0;
5616 	    };
5617 	  switch (rng->DimensionModel)
5618 	    {
5619 	    case GAIA_XY:
5620 		gaiaSetPoint (rng->Coords, iv, x, y);
5621 		break;
5622 	    case GAIA_XY_Z:
5623 		gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
5624 		break;
5625 	    case GAIA_XY_M:
5626 		gaiaSetPointXYM (rng->Coords, iv, x, y, m);
5627 		break;
5628 	    case GAIA_XY_Z_M:
5629 		gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
5630 		break;
5631 	    };
5632       }
5633     if (interiors != NULL)
5634       {
5635 	  /* setting up the interior rings */
5636 	  ib = 0;
5637 	  ln = interiors->FirstLinestring;
5638 	  while (ln)
5639 	    {
5640 		rng = gaiaAddInteriorRing (pg, ib, ln->Points);
5641 		for (iv = 0; iv < ln->Points; iv++)
5642 		  {
5643 		      m = 0.0;
5644 		      z = 0.0;
5645 		      switch (ln->DimensionModel)
5646 			{
5647 			case GAIA_XY:
5648 			    gaiaGetPoint (ln->Coords, iv, &x, &y);
5649 			    break;
5650 			case GAIA_XY_Z:
5651 			    gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
5652 			    break;
5653 			case GAIA_XY_M:
5654 			    gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
5655 			    break;
5656 			case GAIA_XY_Z_M:
5657 			    gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
5658 			    break;
5659 			default:
5660 			    return 0;
5661 			};
5662 		      switch (rng->DimensionModel)
5663 			{
5664 			case GAIA_XY:
5665 			    gaiaSetPoint (rng->Coords, iv, x, y);
5666 			    break;
5667 			case GAIA_XY_Z:
5668 			    gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
5669 			    break;
5670 			case GAIA_XY_M:
5671 			    gaiaSetPointXYM (rng->Coords, iv, x, y, m);
5672 			    break;
5673 			case GAIA_XY_Z_M:
5674 			    gaiaSetPointXYZM (rng->Coords, iv, x, y, z, m);
5675 			    break;
5676 			};
5677 		  }
5678 		ib++;
5679 		ln = ln->Next;
5680 	    }
5681       }
5682     return geom;
5683 }
5684