1 /*
2 
3  gg_geoscvt.c -- Gaia / GEOS conversion [Geometry]
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 
50 #if defined(_WIN32) && !defined(__MINGW32__)
51 #include "config-msvc.h"
52 #else
53 #include "config.h"
54 #endif
55 
56 #ifndef OMIT_GEOS		/* including GEOS */
57 #ifdef GEOS_REENTRANT
58 #ifdef GEOS_ONLY_REENTRANT
59 #define GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
60 #endif
61 #endif
62 #include <geos_c.h>
63 #endif
64 
65 #include <spatialite_private.h>
66 #include <spatialite/sqlite.h>
67 
68 #include <spatialite/gaiageo.h>
69 
70 #ifndef OMIT_GEOS		/* including GEOS */
71 
72 static GEOSGeometry *
toGeosGeometry(const void * cache,GEOSContextHandle_t handle,const gaiaGeomCollPtr gaia,int mode)73 toGeosGeometry (const void *cache, GEOSContextHandle_t handle,
74 		const gaiaGeomCollPtr gaia, int mode)
75 {
76 /* converting a GAIA Geometry into a GEOS Geometry */
77     int pts = 0;
78     int lns = 0;
79     int pgs = 0;
80     int type;
81     int geos_type;
82     unsigned int dims;
83     int iv;
84     int ib;
85     int nItem;
86     double x;
87     double y;
88     double z;
89     double m;
90     double x0 = 0.0;
91     double y0 = 0.0;
92     double z0 = 0.0;
93     gaiaPointPtr pt;
94     gaiaLinestringPtr ln;
95     gaiaPolygonPtr pg;
96     gaiaRingPtr rng;
97     GEOSGeometry *geos = NULL;
98     GEOSGeometry *geos_ext;
99     GEOSGeometry *geos_int;
100     GEOSGeometry *geos_item;
101     GEOSGeometry **geos_holes;
102     GEOSGeometry **geos_coll;
103     GEOSCoordSequence *cs;
104     int ring_points;
105     int n_items;
106 
107 #ifdef GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
108     if (handle == NULL)
109 	return NULL;
110 #endif
111     if (!gaia)
112 	return NULL;
113 
114 
115     pt = gaia->FirstPoint;
116     while (pt)
117       {
118 	  /* counting how many POINTs are there */
119 	  pts++;
120 	  pt = pt->Next;
121       }
122     ln = gaia->FirstLinestring;
123     while (ln)
124       {
125 	  /* counting how many LINESTRINGs are there */
126 	  lns++;
127 	  ln = ln->Next;
128       }
129     pg = gaia->FirstPolygon;
130     while (pg)
131       {
132 	  /* counting how many POLYGONs are there */
133 	  pgs++;
134 	  pg = pg->Next;
135       }
136     if (mode == GAIA2GEOS_ONLY_POINTS && pts == 0)
137 	return NULL;
138     if (mode == GAIA2GEOS_ONLY_LINESTRINGS && lns == 0)
139 	return NULL;
140     if (mode == GAIA2GEOS_ONLY_POLYGONS && pgs == 0)
141 	return NULL;
142     if (pts == 0 && lns == 0 && pgs == 0)
143 	return NULL;
144     else if (pts == 1 && lns == 0 && pgs == 0)
145       {
146 	  if (gaia->DeclaredType == GAIA_MULTIPOINT)
147 	      type = GAIA_MULTIPOINT;
148 	  else if (gaia->DeclaredType == GAIA_GEOMETRYCOLLECTION)
149 	      type = GAIA_GEOMETRYCOLLECTION;
150 	  else
151 	      type = GAIA_POINT;
152       }
153     else if (pts == 0 && lns == 1 && pgs == 0)
154       {
155 	  if (gaia->DeclaredType == GAIA_MULTILINESTRING)
156 	      type = GAIA_MULTILINESTRING;
157 	  else if (gaia->DeclaredType == GAIA_GEOMETRYCOLLECTION)
158 	      type = GAIA_GEOMETRYCOLLECTION;
159 	  else
160 	      type = GAIA_LINESTRING;
161       }
162     else if (pts == 0 && lns == 0 && pgs == 1)
163       {
164 	  if (gaia->DeclaredType == GAIA_MULTIPOLYGON)
165 	      type = GAIA_MULTIPOLYGON;
166 	  else if (gaia->DeclaredType == GAIA_GEOMETRYCOLLECTION)
167 	      type = GAIA_GEOMETRYCOLLECTION;
168 	  else
169 	      type = GAIA_POLYGON;
170       }
171     else if (pts > 1 && lns == 0 && pgs == 0)
172       {
173 	  if (gaia->DeclaredType == GAIA_GEOMETRYCOLLECTION)
174 	      type = GAIA_GEOMETRYCOLLECTION;
175 	  else
176 	      type = GAIA_MULTIPOINT;
177       }
178     else if (pts == 0 && lns > 1 && pgs == 0)
179       {
180 	  if (gaia->DeclaredType == GAIA_GEOMETRYCOLLECTION)
181 	      type = GAIA_GEOMETRYCOLLECTION;
182 	  else
183 	      type = GAIA_MULTILINESTRING;
184       }
185     else if (pts == 0 && lns == 0 && pgs > 1)
186       {
187 	  if (gaia->DeclaredType == GAIA_GEOMETRYCOLLECTION)
188 	      type = GAIA_GEOMETRYCOLLECTION;
189 	  else
190 	      type = GAIA_MULTIPOLYGON;
191       }
192     else
193 	type = GAIA_GEOMETRYCOLLECTION;
194     switch (gaia->DimensionModel)
195       {
196       case GAIA_XY_Z:
197       case GAIA_XY_Z_M:
198 	  dims = 3;
199 	  break;
200       default:
201 	  dims = 2;
202 	  break;
203       };
204     switch (type)
205       {
206       case GAIA_POINT:
207 	  if (mode == GAIA2GEOS_ALL || mode == GAIA2GEOS_ONLY_POINTS)
208 	    {
209 		pt = gaia->FirstPoint;
210 		if (handle != NULL)
211 		  {
212 		      cs = GEOSCoordSeq_create_r (handle, 1, dims);
213 		      switch (gaia->DimensionModel)
214 			{
215 			case GAIA_XY_Z:
216 			case GAIA_XY_Z_M:
217 			    GEOSCoordSeq_setX_r (handle, cs, 0, pt->X);
218 			    GEOSCoordSeq_setY_r (handle, cs, 0, pt->Y);
219 			    GEOSCoordSeq_setZ_r (handle, cs, 0, pt->Z);
220 			    break;
221 			default:
222 			    GEOSCoordSeq_setX_r (handle, cs, 0, pt->X);
223 			    GEOSCoordSeq_setY_r (handle, cs, 0, pt->Y);
224 			    break;
225 			};
226 		      geos = GEOSGeom_createPoint_r (handle, cs);
227 		  }
228 		else
229 		  {
230 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
231 		      cs = GEOSCoordSeq_create (1, dims);
232 		      switch (gaia->DimensionModel)
233 			{
234 			case GAIA_XY_Z:
235 			case GAIA_XY_Z_M:
236 			    GEOSCoordSeq_setX (cs, 0, pt->X);
237 			    GEOSCoordSeq_setY (cs, 0, pt->Y);
238 			    GEOSCoordSeq_setZ (cs, 0, pt->Z);
239 			    break;
240 			default:
241 			    GEOSCoordSeq_setX (cs, 0, pt->X);
242 			    GEOSCoordSeq_setY (cs, 0, pt->Y);
243 			    break;
244 			};
245 		      geos = GEOSGeom_createPoint (cs);
246 #endif
247 		  }
248 	    }
249 	  break;
250       case GAIA_LINESTRING:
251 	  if (mode == GAIA2GEOS_ALL || mode == GAIA2GEOS_ONLY_LINESTRINGS)
252 	    {
253 		ln = gaia->FirstLinestring;
254 		if (handle != NULL)
255 		    cs = GEOSCoordSeq_create_r (handle, ln->Points, dims);
256 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
257 		else
258 		    cs = GEOSCoordSeq_create (ln->Points, dims);
259 #endif
260 		for (iv = 0; iv < ln->Points; iv++)
261 		  {
262 		      switch (ln->DimensionModel)
263 			{
264 			case GAIA_XY_Z:
265 			    gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
266 			    if (handle != NULL)
267 			      {
268 				  GEOSCoordSeq_setX_r (handle, cs, iv, x);
269 				  GEOSCoordSeq_setY_r (handle, cs, iv, y);
270 				  GEOSCoordSeq_setZ_r (handle, cs, iv, z);
271 			      }
272 			    else
273 			      {
274 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
275 				  GEOSCoordSeq_setX (cs, iv, x);
276 				  GEOSCoordSeq_setY (cs, iv, y);
277 				  GEOSCoordSeq_setZ (cs, iv, z);
278 #endif
279 			      }
280 			    break;
281 			case GAIA_XY_M:
282 			    gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
283 			    if (handle != NULL)
284 			      {
285 				  GEOSCoordSeq_setX_r (handle, cs, iv, x);
286 				  GEOSCoordSeq_setY_r (handle, cs, iv, y);
287 			      }
288 			    else
289 			      {
290 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
291 				  GEOSCoordSeq_setX (cs, iv, x);
292 				  GEOSCoordSeq_setY (cs, iv, y);
293 #endif
294 			      }
295 			    break;
296 			case GAIA_XY_Z_M:
297 			    gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z, &m);
298 			    if (handle != NULL)
299 			      {
300 				  GEOSCoordSeq_setX_r (handle, cs, iv, x);
301 				  GEOSCoordSeq_setY_r (handle, cs, iv, y);
302 				  GEOSCoordSeq_setZ_r (handle, cs, iv, z);
303 			      }
304 			    else
305 			      {
306 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
307 				  GEOSCoordSeq_setX (cs, iv, x);
308 				  GEOSCoordSeq_setY (cs, iv, y);
309 				  GEOSCoordSeq_setZ (cs, iv, z);
310 #endif
311 			      }
312 			    break;
313 			default:
314 			    gaiaGetPoint (ln->Coords, iv, &x, &y);
315 			    if (handle != NULL)
316 			      {
317 				  GEOSCoordSeq_setX_r (handle, cs, iv, x);
318 				  GEOSCoordSeq_setY_r (handle, cs, iv, y);
319 			      }
320 			    else
321 			      {
322 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
323 				  GEOSCoordSeq_setX (cs, iv, x);
324 				  GEOSCoordSeq_setY (cs, iv, y);
325 #endif
326 			      }
327 			    break;
328 			};
329 		  }
330 		if (handle != NULL)
331 		    geos = GEOSGeom_createLineString_r (handle, cs);
332 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
333 		else
334 		    geos = GEOSGeom_createLineString (cs);
335 #endif
336 	    }
337 	  break;
338       case GAIA_POLYGON:
339 	  if (mode == GAIA2GEOS_ALL || mode == GAIA2GEOS_ONLY_POLYGONS)
340 	    {
341 		pg = gaia->FirstPolygon;
342 		rng = pg->Exterior;
343 		/* exterior ring */
344 		ring_points = rng->Points;
345 		if (cache)
346 		  {
347 		      if (gaiaIsNotClosedRing_r (cache, rng))
348 			  ring_points++;
349 		  }
350 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
351 		else
352 		  {
353 		      if (gaiaIsNotClosedRing (rng))
354 			  ring_points++;
355 		  }
356 #endif
357 		if (handle != NULL)
358 		    cs = GEOSCoordSeq_create_r (handle, ring_points, dims);
359 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
360 		else
361 		    cs = GEOSCoordSeq_create (ring_points, dims);
362 #endif
363 		for (iv = 0; iv < rng->Points; iv++)
364 		  {
365 		      switch (rng->DimensionModel)
366 			{
367 			case GAIA_XY_Z:
368 			    gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
369 			    if (iv == 0)
370 			      {
371 				  /* saving the first vertex */
372 				  x0 = x;
373 				  y0 = y;
374 				  z0 = z;
375 			      }
376 			    if (handle != NULL)
377 			      {
378 				  GEOSCoordSeq_setX_r (handle, cs, iv, x);
379 				  GEOSCoordSeq_setY_r (handle, cs, iv, y);
380 				  GEOSCoordSeq_setZ_r (handle, cs, iv, z);
381 			      }
382 			    else
383 			      {
384 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
385 				  GEOSCoordSeq_setX (cs, iv, x);
386 				  GEOSCoordSeq_setY (cs, iv, y);
387 				  GEOSCoordSeq_setZ (cs, iv, z);
388 #endif
389 			      }
390 			    break;
391 			case GAIA_XY_M:
392 			    gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
393 			    if (iv == 0)
394 			      {
395 				  /* saving the first vertex */
396 				  x0 = x;
397 				  y0 = y;
398 			      }
399 			    if (handle != NULL)
400 			      {
401 				  GEOSCoordSeq_setX_r (handle, cs, iv, x);
402 				  GEOSCoordSeq_setY_r (handle, cs, iv, y);
403 			      }
404 			    else
405 			      {
406 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
407 				  GEOSCoordSeq_setX (cs, iv, x);
408 				  GEOSCoordSeq_setY (cs, iv, y);
409 #endif
410 			      }
411 			    break;
412 			case GAIA_XY_Z_M:
413 			    gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z, &m);
414 			    if (iv == 0)
415 			      {
416 				  /* saving the first vertex */
417 				  x0 = x;
418 				  y0 = y;
419 				  z0 = z;
420 			      }
421 			    if (handle != NULL)
422 			      {
423 				  GEOSCoordSeq_setX_r (handle, cs, iv, x);
424 				  GEOSCoordSeq_setY_r (handle, cs, iv, y);
425 				  GEOSCoordSeq_setZ_r (handle, cs, iv, z);
426 			      }
427 			    else
428 			      {
429 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
430 				  GEOSCoordSeq_setX (cs, iv, x);
431 				  GEOSCoordSeq_setY (cs, iv, y);
432 				  GEOSCoordSeq_setZ (cs, iv, z);
433 #endif
434 			      }
435 			    break;
436 			default:
437 			    gaiaGetPoint (rng->Coords, iv, &x, &y);
438 			    if (iv == 0)
439 			      {
440 				  /* saving the first vertex */
441 				  x0 = x;
442 				  y0 = y;
443 			      }
444 			    if (handle != NULL)
445 			      {
446 				  GEOSCoordSeq_setX_r (handle, cs, iv, x);
447 				  GEOSCoordSeq_setY_r (handle, cs, iv, y);
448 			      }
449 			    else
450 			      {
451 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
452 				  GEOSCoordSeq_setX (cs, iv, x);
453 				  GEOSCoordSeq_setY (cs, iv, y);
454 #endif
455 			      }
456 			    break;
457 			};
458 		  }
459 		if (ring_points > rng->Points)
460 		  {
461 		      /* ensuring Ring's closure */
462 		      iv = ring_points - 1;
463 		      switch (rng->DimensionModel)
464 			{
465 			case GAIA_XY_Z:
466 			case GAIA_XY_Z_M:
467 			    if (handle != NULL)
468 			      {
469 				  GEOSCoordSeq_setX_r (handle, cs, iv, x0);
470 				  GEOSCoordSeq_setY_r (handle, cs, iv, y0);
471 				  GEOSCoordSeq_setZ_r (handle, cs, iv, z0);
472 			      }
473 			    else
474 			      {
475 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
476 				  GEOSCoordSeq_setX (cs, iv, x0);
477 				  GEOSCoordSeq_setY (cs, iv, y0);
478 				  GEOSCoordSeq_setZ (cs, iv, z0);
479 #endif
480 			      }
481 			    break;
482 			default:
483 			    if (handle != NULL)
484 			      {
485 				  GEOSCoordSeq_setX_r (handle, cs, iv, x0);
486 				  GEOSCoordSeq_setY_r (handle, cs, iv, y0);
487 			      }
488 			    else
489 			      {
490 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
491 				  GEOSCoordSeq_setX (cs, iv, x0);
492 				  GEOSCoordSeq_setY (cs, iv, y0);
493 #endif
494 			      }
495 			    break;
496 			};
497 		  }
498 		if (handle != NULL)
499 		    geos_ext = GEOSGeom_createLinearRing_r (handle, cs);
500 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
501 		else
502 		    geos_ext = GEOSGeom_createLinearRing (cs);
503 #endif
504 		geos_holes = NULL;
505 		if (pg->NumInteriors > 0)
506 		  {
507 		      geos_holes =
508 			  malloc (sizeof (GEOSGeometry *) * pg->NumInteriors);
509 		      for (ib = 0; ib < pg->NumInteriors; ib++)
510 			{
511 			    /* interior ring */
512 			    rng = pg->Interiors + ib;
513 			    ring_points = rng->Points;
514 			    if (cache != NULL)
515 			      {
516 				  if (gaiaIsNotClosedRing_r (cache, rng))
517 				      ring_points++;
518 			      }
519 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
520 			    else
521 			      {
522 				  if (gaiaIsNotClosedRing (rng))
523 				      ring_points++;
524 			      }
525 #endif
526 			    if (handle != NULL)
527 				cs = GEOSCoordSeq_create_r (handle, ring_points,
528 							    dims);
529 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
530 			    else
531 				cs = GEOSCoordSeq_create (ring_points, dims);
532 #endif
533 			    for (iv = 0; iv < rng->Points; iv++)
534 			      {
535 				  switch (rng->DimensionModel)
536 				    {
537 				    case GAIA_XY_Z:
538 					gaiaGetPointXYZ (rng->Coords, iv, &x,
539 							 &y, &z);
540 					if (iv == 0)
541 					  {
542 					      /* saving the first vertex */
543 					      x0 = x;
544 					      y0 = y;
545 					      z0 = z;
546 					  }
547 					if (handle != NULL)
548 					  {
549 					      GEOSCoordSeq_setX_r (handle, cs,
550 								   iv, x);
551 					      GEOSCoordSeq_setY_r (handle, cs,
552 								   iv, y);
553 					      GEOSCoordSeq_setZ_r (handle, cs,
554 								   iv, z);
555 					  }
556 					else
557 					  {
558 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
559 					      GEOSCoordSeq_setX (cs, iv, x);
560 					      GEOSCoordSeq_setY (cs, iv, y);
561 					      GEOSCoordSeq_setZ (cs, iv, z);
562 #endif
563 					  }
564 					break;
565 				    case GAIA_XY_M:
566 					gaiaGetPointXYM (rng->Coords, iv, &x,
567 							 &y, &m);
568 					if (iv == 0)
569 					  {
570 					      /* saving the first vertex */
571 					      x0 = x;
572 					      y0 = y;
573 					  }
574 					if (handle != NULL)
575 					  {
576 					      GEOSCoordSeq_setX_r (handle, cs,
577 								   iv, x);
578 					      GEOSCoordSeq_setY_r (handle, cs,
579 								   iv, y);
580 					  }
581 					else
582 					  {
583 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
584 					      GEOSCoordSeq_setX (cs, iv, x);
585 					      GEOSCoordSeq_setY (cs, iv, y);
586 #endif
587 					  }
588 					break;
589 				    case GAIA_XY_Z_M:
590 					gaiaGetPointXYZM (rng->Coords, iv, &x,
591 							  &y, &z, &m);
592 					if (iv == 0)
593 					  {
594 					      /* saving the first vertex */
595 					      x0 = x;
596 					      y0 = y;
597 					      z0 = z;
598 					  }
599 					if (handle != NULL)
600 					  {
601 					      GEOSCoordSeq_setX_r (handle, cs,
602 								   iv, x);
603 					      GEOSCoordSeq_setY_r (handle, cs,
604 								   iv, y);
605 					      GEOSCoordSeq_setZ_r (handle, cs,
606 								   iv, z);
607 					  }
608 					else
609 					  {
610 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
611 					      GEOSCoordSeq_setX (cs, iv, x);
612 					      GEOSCoordSeq_setY (cs, iv, y);
613 					      GEOSCoordSeq_setZ (cs, iv, z);
614 #endif
615 					  }
616 					break;
617 				    default:
618 					gaiaGetPoint (rng->Coords, iv, &x, &y);
619 					if (iv == 0)
620 					  {
621 					      /* saving the first vertex */
622 					      x0 = x;
623 					      y0 = y;
624 					  }
625 					if (handle != NULL)
626 					  {
627 					      GEOSCoordSeq_setX_r (handle, cs,
628 								   iv, x);
629 					      GEOSCoordSeq_setY_r (handle, cs,
630 								   iv, y);
631 					  }
632 					else
633 					  {
634 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
635 					      GEOSCoordSeq_setX (cs, iv, x);
636 					      GEOSCoordSeq_setY (cs, iv, y);
637 #endif
638 					  }
639 					break;
640 				    };
641 			      }
642 			    if (ring_points > rng->Points)
643 			      {
644 				  /* ensuring Ring's closure */
645 				  iv = ring_points - 1;
646 				  switch (rng->DimensionModel)
647 				    {
648 				    case GAIA_XY_Z:
649 				    case GAIA_XY_Z_M:
650 					if (handle != NULL)
651 					  {
652 					      GEOSCoordSeq_setX_r (handle, cs,
653 								   iv, x0);
654 					      GEOSCoordSeq_setY_r (handle, cs,
655 								   iv, y0);
656 					      GEOSCoordSeq_setZ_r (handle, cs,
657 								   iv, z0);
658 					  }
659 					else
660 					  {
661 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
662 					      GEOSCoordSeq_setX (cs, iv, x0);
663 					      GEOSCoordSeq_setY (cs, iv, y0);
664 					      GEOSCoordSeq_setZ (cs, iv, z0);
665 #endif
666 					  }
667 					break;
668 				    default:
669 					if (handle != NULL)
670 					  {
671 					      GEOSCoordSeq_setX_r (handle, cs,
672 								   iv, x0);
673 					      GEOSCoordSeq_setY_r (handle, cs,
674 								   iv, y0);
675 					  }
676 					else
677 					  {
678 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
679 					      GEOSCoordSeq_setX (cs, iv, x0);
680 					      GEOSCoordSeq_setY (cs, iv, y0);
681 #endif
682 					  }
683 					break;
684 				    };
685 			      }
686 			    if (handle != NULL)
687 				geos_int =
688 				    GEOSGeom_createLinearRing_r (handle, cs);
689 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
690 			    else
691 				geos_int = GEOSGeom_createLinearRing (cs);
692 #endif
693 			    *(geos_holes + ib) = geos_int;
694 			}
695 		  }
696 		if (handle != NULL)
697 		    geos =
698 			GEOSGeom_createPolygon_r (handle, geos_ext, geos_holes,
699 						  pg->NumInteriors);
700 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
701 		else
702 		    geos =
703 			GEOSGeom_createPolygon (geos_ext, geos_holes,
704 						pg->NumInteriors);
705 #endif
706 		if (geos_holes)
707 		    free (geos_holes);
708 	    }
709 	  break;
710       case GAIA_MULTIPOINT:
711       case GAIA_MULTILINESTRING:
712       case GAIA_MULTIPOLYGON:
713       case GAIA_GEOMETRYCOLLECTION:
714 	  nItem = 0;
715 	  if (mode == GAIA2GEOS_ONLY_POINTS)
716 	    {
717 		geos_coll = malloc (sizeof (GEOSGeometry *) * (pts));
718 		n_items = pts;
719 	    }
720 	  else if (mode == GAIA2GEOS_ONLY_LINESTRINGS)
721 	    {
722 		geos_coll = malloc (sizeof (GEOSGeometry *) * (lns));
723 		n_items = lns;
724 	    }
725 	  else if (mode == GAIA2GEOS_ONLY_POLYGONS)
726 	    {
727 		geos_coll = malloc (sizeof (GEOSGeometry *) * (pgs));
728 		n_items = pgs;
729 	    }
730 	  else
731 	    {
732 		geos_coll =
733 		    malloc (sizeof (GEOSGeometry *) * (pts + lns + pgs));
734 		n_items = pts + lns + pgs;
735 	    }
736 	  if (mode == GAIA2GEOS_ALL || mode == GAIA2GEOS_ONLY_POINTS)
737 	    {
738 		pt = gaia->FirstPoint;
739 		while (pt)
740 		  {
741 		      if (handle != NULL)
742 			  cs = GEOSCoordSeq_create_r (handle, 1, dims);
743 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
744 		      else
745 			  cs = GEOSCoordSeq_create (1, dims);
746 #endif
747 		      switch (pt->DimensionModel)
748 			{
749 			case GAIA_XY_Z:
750 			case GAIA_XY_Z_M:
751 			    if (handle != NULL)
752 			      {
753 				  GEOSCoordSeq_setX_r (handle, cs, 0, pt->X);
754 				  GEOSCoordSeq_setY_r (handle, cs, 0, pt->Y);
755 				  GEOSCoordSeq_setZ_r (handle, cs, 0, pt->Z);
756 			      }
757 			    else
758 			      {
759 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
760 				  GEOSCoordSeq_setX (cs, 0, pt->X);
761 				  GEOSCoordSeq_setY (cs, 0, pt->Y);
762 				  GEOSCoordSeq_setZ (cs, 0, pt->Z);
763 #endif
764 			      }
765 			    break;
766 			default:
767 			    if (handle != NULL)
768 			      {
769 				  GEOSCoordSeq_setX_r (handle, cs, 0, pt->X);
770 				  GEOSCoordSeq_setY_r (handle, cs, 0, pt->Y);
771 			      }
772 			    else
773 			      {
774 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
775 				  GEOSCoordSeq_setX (cs, 0, pt->X);
776 				  GEOSCoordSeq_setY (cs, 0, pt->Y);
777 #endif
778 			      }
779 			    break;
780 			};
781 		      if (handle != NULL)
782 			  geos_item = GEOSGeom_createPoint_r (handle, cs);
783 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
784 		      else
785 			  geos_item = GEOSGeom_createPoint (cs);
786 #endif
787 		      *(geos_coll + nItem++) = geos_item;
788 		      pt = pt->Next;
789 		  }
790 	    }
791 	  if (mode == GAIA2GEOS_ALL || mode == GAIA2GEOS_ONLY_LINESTRINGS)
792 	    {
793 		ln = gaia->FirstLinestring;
794 		while (ln)
795 		  {
796 		      if (handle != NULL)
797 			  cs = GEOSCoordSeq_create_r (handle, ln->Points, dims);
798 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
799 		      else
800 			  cs = GEOSCoordSeq_create (ln->Points, dims);
801 #endif
802 		      for (iv = 0; iv < ln->Points; iv++)
803 			{
804 			    switch (ln->DimensionModel)
805 			      {
806 			      case GAIA_XY_Z:
807 				  gaiaGetPointXYZ (ln->Coords, iv, &x, &y, &z);
808 				  if (handle != NULL)
809 				    {
810 					GEOSCoordSeq_setX_r (handle, cs, iv, x);
811 					GEOSCoordSeq_setY_r (handle, cs, iv, y);
812 					GEOSCoordSeq_setZ_r (handle, cs, iv, z);
813 				    }
814 				  else
815 				    {
816 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
817 					GEOSCoordSeq_setX (cs, iv, x);
818 					GEOSCoordSeq_setY (cs, iv, y);
819 					GEOSCoordSeq_setZ (cs, iv, z);
820 #endif
821 				    }
822 				  break;
823 			      case GAIA_XY_M:
824 				  gaiaGetPointXYM (ln->Coords, iv, &x, &y, &m);
825 				  if (handle != NULL)
826 				    {
827 					GEOSCoordSeq_setX_r (handle, cs, iv, x);
828 					GEOSCoordSeq_setY_r (handle, cs, iv, y);
829 				    }
830 				  else
831 				    {
832 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
833 					GEOSCoordSeq_setX (cs, iv, x);
834 					GEOSCoordSeq_setY (cs, iv, y);
835 #endif
836 				    }
837 				  break;
838 			      case GAIA_XY_Z_M:
839 				  gaiaGetPointXYZM (ln->Coords, iv, &x, &y, &z,
840 						    &m);
841 				  if (handle != NULL)
842 				    {
843 					GEOSCoordSeq_setX_r (handle, cs, iv, x);
844 					GEOSCoordSeq_setY_r (handle, cs, iv, y);
845 					GEOSCoordSeq_setZ_r (handle, cs, iv, z);
846 				    }
847 				  else
848 				    {
849 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
850 					GEOSCoordSeq_setX (cs, iv, x);
851 					GEOSCoordSeq_setY (cs, iv, y);
852 					GEOSCoordSeq_setZ (cs, iv, z);
853 #endif
854 				    }
855 				  break;
856 			      default:
857 				  gaiaGetPoint (ln->Coords, iv, &x, &y);
858 				  if (handle != NULL)
859 				    {
860 					GEOSCoordSeq_setX_r (handle, cs, iv, x);
861 					GEOSCoordSeq_setY_r (handle, cs, iv, y);
862 				    }
863 				  else
864 				    {
865 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
866 					GEOSCoordSeq_setX (cs, iv, x);
867 					GEOSCoordSeq_setY (cs, iv, y);
868 #endif
869 				    }
870 				  break;
871 			      };
872 			}
873 		      if (handle != NULL)
874 			  geos_item = GEOSGeom_createLineString_r (handle, cs);
875 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
876 		      else
877 			  geos_item = GEOSGeom_createLineString (cs);
878 #endif
879 		      *(geos_coll + nItem++) = geos_item;
880 		      ln = ln->Next;
881 		  }
882 	    }
883 	  if (mode == GAIA2GEOS_ALL || mode == GAIA2GEOS_ONLY_POLYGONS)
884 	    {
885 		pg = gaia->FirstPolygon;
886 		while (pg)
887 		  {
888 		      rng = pg->Exterior;
889 		      /* exterior ring */
890 		      ring_points = rng->Points;
891 		      if (cache != NULL)
892 			{
893 			    if (gaiaIsNotClosedRing_r (cache, rng))
894 				ring_points++;
895 			}
896 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
897 		      else
898 			{
899 			    if (gaiaIsNotClosedRing (rng))
900 				ring_points++;
901 			}
902 #endif
903 		      if (handle != NULL)
904 			  cs = GEOSCoordSeq_create_r (handle, ring_points,
905 						      dims);
906 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
907 		      else
908 			  cs = GEOSCoordSeq_create (ring_points, dims);
909 #endif
910 		      for (iv = 0; iv < rng->Points; iv++)
911 			{
912 			    switch (rng->DimensionModel)
913 			      {
914 			      case GAIA_XY_Z:
915 				  gaiaGetPointXYZ (rng->Coords, iv, &x, &y, &z);
916 				  if (iv == 0)
917 				    {
918 					/* saving the first vertex */
919 					x0 = x;
920 					y0 = y;
921 					z0 = z;
922 				    }
923 				  if (handle != NULL)
924 				    {
925 					GEOSCoordSeq_setX_r (handle, cs, iv, x);
926 					GEOSCoordSeq_setY_r (handle, cs, iv, y);
927 					GEOSCoordSeq_setZ_r (handle, cs, iv, z);
928 				    }
929 				  else
930 				    {
931 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
932 					GEOSCoordSeq_setX (cs, iv, x);
933 					GEOSCoordSeq_setY (cs, iv, y);
934 					GEOSCoordSeq_setZ (cs, iv, z);
935 #endif
936 				    }
937 				  break;
938 			      case GAIA_XY_M:
939 				  gaiaGetPointXYM (rng->Coords, iv, &x, &y, &m);
940 				  if (iv == 0)
941 				    {
942 					/* saving the first vertex */
943 					x0 = x;
944 					y0 = y;
945 				    }
946 				  if (handle != NULL)
947 				    {
948 					GEOSCoordSeq_setX_r (handle, cs, iv, x);
949 					GEOSCoordSeq_setY_r (handle, cs, iv, y);
950 				    }
951 				  else
952 				    {
953 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
954 					GEOSCoordSeq_setX (cs, iv, x);
955 					GEOSCoordSeq_setY (cs, iv, y);
956 #endif
957 				    }
958 				  break;
959 			      case GAIA_XY_Z_M:
960 				  gaiaGetPointXYZM (rng->Coords, iv, &x, &y, &z,
961 						    &m);
962 				  if (iv == 0)
963 				    {
964 					/* saving the first vertex */
965 					x0 = x;
966 					y0 = y;
967 					z0 = z;
968 				    }
969 				  if (handle != NULL)
970 				    {
971 					GEOSCoordSeq_setX_r (handle, cs, iv, x);
972 					GEOSCoordSeq_setY_r (handle, cs, iv, y);
973 					GEOSCoordSeq_setZ_r (handle, cs, iv, z);
974 				    }
975 				  else
976 				    {
977 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
978 					GEOSCoordSeq_setX (cs, iv, x);
979 					GEOSCoordSeq_setY (cs, iv, y);
980 					GEOSCoordSeq_setZ (cs, iv, z);
981 #endif
982 				    }
983 				  break;
984 			      default:
985 				  gaiaGetPoint (rng->Coords, iv, &x, &y);
986 				  if (iv == 0)
987 				    {
988 					/* saving the first vertex */
989 					x0 = x;
990 					y0 = y;
991 				    }
992 				  if (handle != NULL)
993 				    {
994 					GEOSCoordSeq_setX_r (handle, cs, iv, x);
995 					GEOSCoordSeq_setY_r (handle, cs, iv, y);
996 				    }
997 				  else
998 				    {
999 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1000 					GEOSCoordSeq_setX (cs, iv, x);
1001 					GEOSCoordSeq_setY (cs, iv, y);
1002 #endif
1003 				    }
1004 				  break;
1005 			      };
1006 			}
1007 		      if (ring_points > rng->Points)
1008 			{
1009 			    /* ensuring Ring's closure */
1010 			    iv = ring_points - 1;
1011 			    switch (rng->DimensionModel)
1012 			      {
1013 			      case GAIA_XY_Z:
1014 			      case GAIA_XY_Z_M:
1015 				  if (handle != NULL)
1016 				    {
1017 					GEOSCoordSeq_setX_r (handle, cs, iv,
1018 							     x0);
1019 					GEOSCoordSeq_setY_r (handle, cs, iv,
1020 							     y0);
1021 					GEOSCoordSeq_setZ_r (handle, cs, iv,
1022 							     z0);
1023 				    }
1024 				  else
1025 				    {
1026 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1027 					GEOSCoordSeq_setX (cs, iv, x0);
1028 					GEOSCoordSeq_setY (cs, iv, y0);
1029 					GEOSCoordSeq_setZ (cs, iv, z0);
1030 #endif
1031 				    }
1032 				  break;
1033 			      default:
1034 				  if (handle != NULL)
1035 				    {
1036 					GEOSCoordSeq_setX_r (handle, cs, iv,
1037 							     x0);
1038 					GEOSCoordSeq_setY_r (handle, cs, iv,
1039 							     y0);
1040 				    }
1041 				  else
1042 				    {
1043 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1044 					GEOSCoordSeq_setX (cs, iv, x0);
1045 					GEOSCoordSeq_setY (cs, iv, y0);
1046 #endif
1047 				    }
1048 				  break;
1049 			      };
1050 			}
1051 		      if (handle != NULL)
1052 			  geos_ext = GEOSGeom_createLinearRing_r (handle, cs);
1053 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1054 		      else
1055 			  geos_ext = GEOSGeom_createLinearRing (cs);
1056 #endif
1057 		      geos_holes = NULL;
1058 		      if (pg->NumInteriors > 0)
1059 			{
1060 			    geos_holes =
1061 				malloc (sizeof (GEOSGeometry *) *
1062 					pg->NumInteriors);
1063 			    for (ib = 0; ib < pg->NumInteriors; ib++)
1064 			      {
1065 				  /* interior ring */
1066 				  rng = pg->Interiors + ib;
1067 				  ring_points = rng->Points;
1068 				  if (cache != NULL)
1069 				    {
1070 					if (gaiaIsNotClosedRing_r (cache, rng))
1071 					    ring_points++;
1072 				    }
1073 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1074 				  else
1075 				    {
1076 					if (gaiaIsNotClosedRing (rng))
1077 					    ring_points++;
1078 				    }
1079 #endif
1080 				  if (handle != NULL)
1081 				      cs = GEOSCoordSeq_create_r (handle,
1082 								  ring_points,
1083 								  dims);
1084 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1085 				  else
1086 				      cs = GEOSCoordSeq_create (ring_points,
1087 								dims);
1088 #endif
1089 				  for (iv = 0; iv < rng->Points; iv++)
1090 				    {
1091 					switch (rng->DimensionModel)
1092 					  {
1093 					  case GAIA_XY_Z:
1094 					      gaiaGetPointXYZ (rng->Coords, iv,
1095 							       &x, &y, &z);
1096 					      if (iv == 0)
1097 						{
1098 						    /* saving the first vertex */
1099 						    x0 = x;
1100 						    y0 = y;
1101 						    z0 = z;
1102 						}
1103 					      if (handle != NULL)
1104 						{
1105 						    GEOSCoordSeq_setX_r (handle,
1106 									 cs, iv,
1107 									 x);
1108 						    GEOSCoordSeq_setY_r (handle,
1109 									 cs, iv,
1110 									 y);
1111 						    GEOSCoordSeq_setZ_r (handle,
1112 									 cs, iv,
1113 									 z);
1114 						}
1115 					      else
1116 						{
1117 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1118 						    GEOSCoordSeq_setX (cs, iv,
1119 								       x);
1120 						    GEOSCoordSeq_setY (cs, iv,
1121 								       y);
1122 						    GEOSCoordSeq_setZ (cs, iv,
1123 								       z);
1124 #endif
1125 						}
1126 					      break;
1127 					  case GAIA_XY_M:
1128 					      gaiaGetPointXYM (rng->Coords, iv,
1129 							       &x, &y, &m);
1130 					      if (iv == 0)
1131 						{
1132 						    /* saving the first vertex */
1133 						    x0 = x;
1134 						    y0 = y;
1135 						}
1136 					      if (handle != NULL)
1137 						{
1138 						    GEOSCoordSeq_setX_r (handle,
1139 									 cs, iv,
1140 									 x);
1141 						    GEOSCoordSeq_setY_r (handle,
1142 									 cs, iv,
1143 									 y);
1144 						}
1145 					      else
1146 						{
1147 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1148 						    GEOSCoordSeq_setX (cs, iv,
1149 								       x);
1150 						    GEOSCoordSeq_setY (cs, iv,
1151 								       y);
1152 #endif
1153 						}
1154 					      break;
1155 					  case GAIA_XY_Z_M:
1156 					      gaiaGetPointXYZM (rng->Coords, iv,
1157 								&x, &y, &z, &m);
1158 					      if (iv == 0)
1159 						{
1160 						    /* saving the first vertex */
1161 						    x0 = x;
1162 						    y0 = y;
1163 						    z0 = z;
1164 						}
1165 					      if (handle != NULL)
1166 						{
1167 						    GEOSCoordSeq_setX_r (handle,
1168 									 cs, iv,
1169 									 x);
1170 						    GEOSCoordSeq_setY_r (handle,
1171 									 cs, iv,
1172 									 y);
1173 						    GEOSCoordSeq_setZ_r (handle,
1174 									 cs, iv,
1175 									 z);
1176 						}
1177 					      else
1178 						{
1179 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1180 						    GEOSCoordSeq_setX (cs, iv,
1181 								       x);
1182 						    GEOSCoordSeq_setY (cs, iv,
1183 								       y);
1184 						    GEOSCoordSeq_setZ (cs, iv,
1185 								       z);
1186 #endif
1187 						}
1188 					      break;
1189 					  default:
1190 					      gaiaGetPoint (rng->Coords, iv, &x,
1191 							    &y);
1192 					      if (iv == 0)
1193 						{
1194 						    /* saving the first vertex */
1195 						    x0 = x;
1196 						    y0 = y;
1197 						}
1198 					      if (handle != NULL)
1199 						{
1200 						    GEOSCoordSeq_setX_r (handle,
1201 									 cs, iv,
1202 									 x);
1203 						    GEOSCoordSeq_setY_r (handle,
1204 									 cs, iv,
1205 									 y);
1206 						}
1207 					      else
1208 						{
1209 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1210 						    GEOSCoordSeq_setX (cs, iv,
1211 								       x);
1212 						    GEOSCoordSeq_setY (cs, iv,
1213 								       y);
1214 #endif
1215 						}
1216 					      break;
1217 					  };
1218 				    }
1219 				  if (ring_points > rng->Points)
1220 				    {
1221 					/* ensuring Ring's closure */
1222 					iv = ring_points - 1;
1223 					switch (rng->DimensionModel)
1224 					  {
1225 					  case GAIA_XY_Z:
1226 					  case GAIA_XY_Z_M:
1227 					      if (handle != NULL)
1228 						{
1229 						    GEOSCoordSeq_setX_r (handle,
1230 									 cs, iv,
1231 									 x0);
1232 						    GEOSCoordSeq_setY_r (handle,
1233 									 cs, iv,
1234 									 y0);
1235 						    GEOSCoordSeq_setZ_r (handle,
1236 									 cs, iv,
1237 									 z0);
1238 						}
1239 					      else
1240 						{
1241 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1242 						    GEOSCoordSeq_setX (cs, iv,
1243 								       x0);
1244 						    GEOSCoordSeq_setY (cs, iv,
1245 								       y0);
1246 						    GEOSCoordSeq_setZ (cs, iv,
1247 								       z0);
1248 #endif
1249 						}
1250 					      break;
1251 					  default:
1252 					      if (handle != NULL)
1253 						{
1254 						    GEOSCoordSeq_setX_r (handle,
1255 									 cs, iv,
1256 									 x0);
1257 						    GEOSCoordSeq_setY_r (handle,
1258 									 cs, iv,
1259 									 y0);
1260 						}
1261 					      else
1262 						{
1263 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1264 						    GEOSCoordSeq_setX (cs, iv,
1265 								       x0);
1266 						    GEOSCoordSeq_setY (cs, iv,
1267 								       y0);
1268 #endif
1269 						}
1270 					      break;
1271 					  };
1272 				    }
1273 				  if (handle != NULL)
1274 				      geos_int =
1275 					  GEOSGeom_createLinearRing_r (handle,
1276 								       cs);
1277 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1278 				  else
1279 				      geos_int = GEOSGeom_createLinearRing (cs);
1280 #endif
1281 				  *(geos_holes + ib) = geos_int;
1282 			      }
1283 			}
1284 		      if (handle != NULL)
1285 			  geos_item =
1286 			      GEOSGeom_createPolygon_r (handle, geos_ext,
1287 							geos_holes,
1288 							pg->NumInteriors);
1289 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1290 		      else
1291 			  geos_item =
1292 			      GEOSGeom_createPolygon (geos_ext, geos_holes,
1293 						      pg->NumInteriors);
1294 #endif
1295 		      if (geos_holes)
1296 			  free (geos_holes);
1297 		      *(geos_coll + nItem++) = geos_item;
1298 		      pg = pg->Next;
1299 		  }
1300 	    }
1301 	  geos_type = GEOS_GEOMETRYCOLLECTION;
1302 	  if (type == GAIA_MULTIPOINT)
1303 	      geos_type = GEOS_MULTIPOINT;
1304 	  if (type == GAIA_MULTILINESTRING)
1305 	      geos_type = GEOS_MULTILINESTRING;
1306 	  if (type == GAIA_MULTIPOLYGON)
1307 	      geos_type = GEOS_MULTIPOLYGON;
1308 	  if (handle != NULL)
1309 	      geos =
1310 		  GEOSGeom_createCollection_r (handle, geos_type, geos_coll,
1311 					       n_items);
1312 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1313 	  else
1314 	      geos = GEOSGeom_createCollection (geos_type, geos_coll, n_items);
1315 #endif
1316 	  if (geos_coll)
1317 	      free (geos_coll);
1318 	  break;
1319       default:
1320 	  geos = NULL;
1321       };
1322     if (geos)
1323       {
1324 	  if (handle != NULL)
1325 	      GEOSSetSRID_r (handle, geos, gaia->Srid);
1326 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1327 	  else
1328 	      GEOSSetSRID (geos, gaia->Srid);
1329 #endif
1330       }
1331     return geos;
1332 }
1333 
1334 static gaiaGeomCollPtr
fromGeosGeometry(GEOSContextHandle_t handle,const GEOSGeometry * geos,const int dimension_model)1335 fromGeosGeometry (GEOSContextHandle_t handle, const GEOSGeometry * geos,
1336 		  const int dimension_model)
1337 {
1338 /* converting a GEOS Geometry into a GAIA Geometry */
1339     int type;
1340     int itemType;
1341     unsigned int dims;
1342     int iv;
1343     int ib;
1344     int it;
1345     int sub_it;
1346     int nItems;
1347     int nSubItems;
1348     int holes;
1349     unsigned int points;
1350     double x;
1351     double y;
1352     double z;
1353     const GEOSCoordSequence *cs;
1354     const GEOSGeometry *geos_ring;
1355     const GEOSGeometry *geos_item;
1356     const GEOSGeometry *geos_sub_item;
1357     gaiaGeomCollPtr gaia = NULL;
1358     gaiaLinestringPtr ln;
1359     gaiaPolygonPtr pg;
1360     gaiaRingPtr rng;
1361 
1362 #ifdef GEOS_USE_ONLY_R_API	/* only fully thread-safe GEOS API */
1363     if (handle == NULL)
1364 	return NULL;
1365 #endif
1366     if (!geos)
1367 	return NULL;
1368 
1369     if (handle != NULL)
1370 	type = GEOSGeomTypeId_r (handle, geos);
1371 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1372     else
1373 	type = GEOSGeomTypeId (geos);
1374 #endif
1375     switch (type)
1376       {
1377       case GEOS_POINT:
1378 	  if (dimension_model == GAIA_XY_Z)
1379 	      gaia = gaiaAllocGeomCollXYZ ();
1380 	  else if (dimension_model == GAIA_XY_M)
1381 	      gaia = gaiaAllocGeomCollXYM ();
1382 	  else if (dimension_model == GAIA_XY_Z_M)
1383 	      gaia = gaiaAllocGeomCollXYZM ();
1384 	  else
1385 	      gaia = gaiaAllocGeomColl ();
1386 	  gaia->DeclaredType = GAIA_POINT;
1387 	  if (handle != NULL)
1388 	    {
1389 		gaia->Srid = GEOSGetSRID_r (handle, geos);
1390 		cs = GEOSGeom_getCoordSeq_r (handle, geos);
1391 		GEOSCoordSeq_getDimensions_r (handle, cs, &dims);
1392 	    }
1393 	  else
1394 	    {
1395 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1396 		gaia->Srid = GEOSGetSRID (geos);
1397 		cs = GEOSGeom_getCoordSeq (geos);
1398 		GEOSCoordSeq_getDimensions (cs, &dims);
1399 #endif
1400 	    }
1401 	  if (dims == 3)
1402 	    {
1403 		if (handle != NULL)
1404 		  {
1405 		      GEOSCoordSeq_getX_r (handle, cs, 0, &x);
1406 		      GEOSCoordSeq_getY_r (handle, cs, 0, &y);
1407 		      GEOSCoordSeq_getZ_r (handle, cs, 0, &z);
1408 		  }
1409 		else
1410 		  {
1411 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1412 		      GEOSCoordSeq_getX (cs, 0, &x);
1413 		      GEOSCoordSeq_getY (cs, 0, &y);
1414 		      GEOSCoordSeq_getZ (cs, 0, &z);
1415 #endif
1416 		  }
1417 	    }
1418 	  else
1419 	    {
1420 		if (handle != NULL)
1421 		  {
1422 		      GEOSCoordSeq_getX_r (handle, cs, 0, &x);
1423 		      GEOSCoordSeq_getY_r (handle, cs, 0, &y);
1424 		  }
1425 		else
1426 		  {
1427 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1428 		      GEOSCoordSeq_getX (cs, 0, &x);
1429 		      GEOSCoordSeq_getY (cs, 0, &y);
1430 #endif
1431 		  }
1432 		z = 0.0;
1433 	    }
1434 	  if (dimension_model == GAIA_XY_Z)
1435 	      gaiaAddPointToGeomCollXYZ (gaia, x, y, z);
1436 	  else if (dimension_model == GAIA_XY_M)
1437 	      gaiaAddPointToGeomCollXYM (gaia, x, y, 0.0);
1438 	  else if (dimension_model == GAIA_XY_Z_M)
1439 	      gaiaAddPointToGeomCollXYZM (gaia, x, y, z, 0.0);
1440 	  else
1441 	      gaiaAddPointToGeomColl (gaia, x, y);
1442 	  break;
1443       case GEOS_LINESTRING:
1444 	  if (dimension_model == GAIA_XY_Z)
1445 	      gaia = gaiaAllocGeomCollXYZ ();
1446 	  else if (dimension_model == GAIA_XY_M)
1447 	      gaia = gaiaAllocGeomCollXYM ();
1448 	  else if (dimension_model == GAIA_XY_Z_M)
1449 	      gaia = gaiaAllocGeomCollXYZM ();
1450 	  else
1451 	      gaia = gaiaAllocGeomColl ();
1452 	  gaia->DeclaredType = GAIA_LINESTRING;
1453 	  if (handle != NULL)
1454 	    {
1455 		gaia->Srid = GEOSGetSRID_r (handle, geos);
1456 		cs = GEOSGeom_getCoordSeq_r (handle, geos);
1457 		GEOSCoordSeq_getDimensions_r (handle, cs, &dims);
1458 		GEOSCoordSeq_getSize_r (handle, cs, &points);
1459 	    }
1460 	  else
1461 	    {
1462 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1463 		gaia->Srid = GEOSGetSRID (geos);
1464 		cs = GEOSGeom_getCoordSeq (geos);
1465 		GEOSCoordSeq_getDimensions (cs, &dims);
1466 		GEOSCoordSeq_getSize (cs, &points);
1467 #endif
1468 	    }
1469 	  ln = gaiaAddLinestringToGeomColl (gaia, points);
1470 	  for (iv = 0; iv < (int) points; iv++)
1471 	    {
1472 		if (dims == 3)
1473 		  {
1474 		      if (handle != NULL)
1475 			{
1476 			    GEOSCoordSeq_getX_r (handle, cs, iv, &x);
1477 			    GEOSCoordSeq_getY_r (handle, cs, iv, &y);
1478 			    GEOSCoordSeq_getZ_r (handle, cs, iv, &z);
1479 			}
1480 		      else
1481 			{
1482 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1483 			    GEOSCoordSeq_getX (cs, iv, &x);
1484 			    GEOSCoordSeq_getY (cs, iv, &y);
1485 			    GEOSCoordSeq_getZ (cs, iv, &z);
1486 #endif
1487 			}
1488 		  }
1489 		else
1490 		  {
1491 		      if (handle != NULL)
1492 			{
1493 			    GEOSCoordSeq_getX_r (handle, cs, iv, &x);
1494 			    GEOSCoordSeq_getY_r (handle, cs, iv, &y);
1495 			}
1496 		      else
1497 			{
1498 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1499 			    GEOSCoordSeq_getX (cs, iv, &x);
1500 			    GEOSCoordSeq_getY (cs, iv, &y);
1501 #endif
1502 			}
1503 		      z = 0.0;
1504 		  }
1505 		if (dimension_model == GAIA_XY_Z)
1506 		  {
1507 		      gaiaSetPointXYZ (ln->Coords, iv, x, y, z);
1508 		  }
1509 		else if (dimension_model == GAIA_XY_M)
1510 		  {
1511 		      gaiaSetPointXYM (ln->Coords, iv, x, y, 0.0);
1512 		  }
1513 		else if (dimension_model == GAIA_XY_Z_M)
1514 		  {
1515 		      gaiaSetPointXYZM (ln->Coords, iv, x, y, z, 0.0);
1516 		  }
1517 		else
1518 		  {
1519 		      gaiaSetPoint (ln->Coords, iv, x, y);
1520 		  }
1521 	    }
1522 	  break;
1523       case GEOS_POLYGON:
1524 	  if (dimension_model == GAIA_XY_Z)
1525 	      gaia = gaiaAllocGeomCollXYZ ();
1526 	  else if (dimension_model == GAIA_XY_M)
1527 	      gaia = gaiaAllocGeomCollXYM ();
1528 	  else if (dimension_model == GAIA_XY_Z_M)
1529 	      gaia = gaiaAllocGeomCollXYZM ();
1530 	  else
1531 	      gaia = gaiaAllocGeomColl ();
1532 	  gaia->DeclaredType = GAIA_POLYGON;
1533 	  if (handle != NULL)
1534 	      gaia->Srid = GEOSGetSRID_r (handle, geos);
1535 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1536 	  else
1537 	      gaia->Srid = GEOSGetSRID (geos);
1538 #endif
1539 	  /* exterior ring */
1540 	  if (handle != NULL)
1541 	    {
1542 		holes = GEOSGetNumInteriorRings_r (handle, geos);
1543 		geos_ring = GEOSGetExteriorRing_r (handle, geos);
1544 		cs = GEOSGeom_getCoordSeq_r (handle, geos_ring);
1545 		GEOSCoordSeq_getDimensions_r (handle, cs, &dims);
1546 		GEOSCoordSeq_getSize_r (handle, cs, &points);
1547 	    }
1548 	  else
1549 	    {
1550 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1551 		holes = GEOSGetNumInteriorRings (geos);
1552 		geos_ring = GEOSGetExteriorRing (geos);
1553 		cs = GEOSGeom_getCoordSeq (geos_ring);
1554 		GEOSCoordSeq_getDimensions (cs, &dims);
1555 		GEOSCoordSeq_getSize (cs, &points);
1556 #endif
1557 	    }
1558 	  pg = gaiaAddPolygonToGeomColl (gaia, points, holes);
1559 	  rng = pg->Exterior;
1560 	  for (iv = 0; iv < (int) points; iv++)
1561 	    {
1562 		if (dims == 3)
1563 		  {
1564 		      if (handle != NULL)
1565 			{
1566 			    GEOSCoordSeq_getX_r (handle, cs, iv, &x);
1567 			    GEOSCoordSeq_getY_r (handle, cs, iv, &y);
1568 			    GEOSCoordSeq_getZ_r (handle, cs, iv, &z);
1569 			}
1570 		      else
1571 			{
1572 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1573 			    GEOSCoordSeq_getX (cs, iv, &x);
1574 			    GEOSCoordSeq_getY (cs, iv, &y);
1575 			    GEOSCoordSeq_getZ (cs, iv, &z);
1576 #endif
1577 			}
1578 		  }
1579 		else
1580 		  {
1581 		      if (handle != NULL)
1582 			{
1583 			    GEOSCoordSeq_getX_r (handle, cs, iv, &x);
1584 			    GEOSCoordSeq_getY_r (handle, cs, iv, &y);
1585 			}
1586 		      else
1587 			{
1588 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1589 			    GEOSCoordSeq_getX (cs, iv, &x);
1590 			    GEOSCoordSeq_getY (cs, iv, &y);
1591 #endif
1592 			}
1593 		      z = 0.0;
1594 		  }
1595 		if (dimension_model == GAIA_XY_Z)
1596 		  {
1597 		      gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
1598 		  }
1599 		else if (dimension_model == GAIA_XY_M)
1600 		  {
1601 		      gaiaSetPointXYM (rng->Coords, iv, x, y, 0.0);
1602 		  }
1603 		else if (dimension_model == GAIA_XY_Z_M)
1604 		  {
1605 		      gaiaSetPointXYZM (rng->Coords, iv, x, y, z, 0.0);
1606 		  }
1607 		else
1608 		  {
1609 		      gaiaSetPoint (rng->Coords, iv, x, y);
1610 		  }
1611 	    }
1612 	  for (ib = 0; ib < holes; ib++)
1613 	    {
1614 		/* interior rings */
1615 		if (handle != NULL)
1616 		  {
1617 		      geos_ring = GEOSGetInteriorRingN_r (handle, geos, ib);
1618 		      cs = GEOSGeom_getCoordSeq_r (handle, geos_ring);
1619 		      GEOSCoordSeq_getDimensions_r (handle, cs, &dims);
1620 		      GEOSCoordSeq_getSize_r (handle, cs, &points);
1621 		  }
1622 		else
1623 		  {
1624 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1625 		      geos_ring = GEOSGetInteriorRingN (geos, ib);
1626 		      cs = GEOSGeom_getCoordSeq (geos_ring);
1627 		      GEOSCoordSeq_getDimensions (cs, &dims);
1628 		      GEOSCoordSeq_getSize (cs, &points);
1629 #endif
1630 		  }
1631 		rng = gaiaAddInteriorRing (pg, ib, points);
1632 		for (iv = 0; iv < (int) points; iv++)
1633 		  {
1634 		      if (dims == 3)
1635 			{
1636 			    if (handle != NULL)
1637 			      {
1638 				  GEOSCoordSeq_getX_r (handle, cs, iv, &x);
1639 				  GEOSCoordSeq_getY_r (handle, cs, iv, &y);
1640 				  GEOSCoordSeq_getZ_r (handle, cs, iv, &z);
1641 			      }
1642 			    else
1643 			      {
1644 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1645 				  GEOSCoordSeq_getX (cs, iv, &x);
1646 				  GEOSCoordSeq_getY (cs, iv, &y);
1647 				  GEOSCoordSeq_getZ (cs, iv, &z);
1648 #endif
1649 			      }
1650 			}
1651 		      else
1652 			{
1653 			    if (handle != NULL)
1654 			      {
1655 				  GEOSCoordSeq_getX_r (handle, cs, iv, &x);
1656 				  GEOSCoordSeq_getY_r (handle, cs, iv, &y);
1657 			      }
1658 			    else
1659 			      {
1660 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1661 				  GEOSCoordSeq_getX (cs, iv, &x);
1662 				  GEOSCoordSeq_getY (cs, iv, &y);
1663 #endif
1664 			      }
1665 			    z = 0.0;
1666 			}
1667 		      if (dimension_model == GAIA_XY_Z)
1668 			{
1669 			    gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
1670 			}
1671 		      else if (dimension_model == GAIA_XY_M)
1672 			{
1673 			    gaiaSetPointXYM (rng->Coords, iv, x, y, 0.0);
1674 			}
1675 		      else if (dimension_model == GAIA_XY_Z_M)
1676 			{
1677 			    gaiaSetPointXYZM (rng->Coords, iv, x, y, z, 0.0);
1678 			}
1679 		      else
1680 			{
1681 			    gaiaSetPoint (rng->Coords, iv, x, y);
1682 			}
1683 		  }
1684 	    }
1685 	  break;
1686       case GEOS_MULTIPOINT:
1687       case GEOS_MULTILINESTRING:
1688       case GEOS_MULTIPOLYGON:
1689       case GEOS_GEOMETRYCOLLECTION:
1690 	  if (dimension_model == GAIA_XY_Z)
1691 	      gaia = gaiaAllocGeomCollXYZ ();
1692 	  else if (dimension_model == GAIA_XY_M)
1693 	      gaia = gaiaAllocGeomCollXYM ();
1694 	  else if (dimension_model == GAIA_XY_Z_M)
1695 	      gaia = gaiaAllocGeomCollXYZM ();
1696 	  else
1697 	      gaia = gaiaAllocGeomColl ();
1698 	  if (type == GEOS_MULTIPOINT)
1699 	      gaia->DeclaredType = GAIA_MULTIPOINT;
1700 	  else if (type == GEOS_MULTILINESTRING)
1701 	      gaia->DeclaredType = GAIA_MULTILINESTRING;
1702 	  else if (type == GEOS_MULTIPOLYGON)
1703 	      gaia->DeclaredType = GAIA_MULTIPOLYGON;
1704 	  else
1705 	      gaia->DeclaredType = GAIA_GEOMETRYCOLLECTION;
1706 	  if (handle != NULL)
1707 	    {
1708 		gaia->Srid = GEOSGetSRID_r (handle, geos);
1709 		nItems = GEOSGetNumGeometries_r (handle, geos);
1710 	    }
1711 	  else
1712 	    {
1713 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1714 		gaia->Srid = GEOSGetSRID (geos);
1715 		nItems = GEOSGetNumGeometries (geos);
1716 #endif
1717 	    }
1718 	  for (it = 0; it < nItems; it++)
1719 	    {
1720 		/* looping on elementaty geometries */
1721 		if (handle != NULL)
1722 		  {
1723 		      geos_item = GEOSGetGeometryN_r (handle, geos, it);
1724 		      itemType = GEOSGeomTypeId_r (handle, geos_item);
1725 		  }
1726 		else
1727 		  {
1728 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1729 		      geos_item = GEOSGetGeometryN (geos, it);
1730 		      itemType = GEOSGeomTypeId (geos_item);
1731 #endif
1732 		  }
1733 		switch (itemType)
1734 		  {
1735 		  case GEOS_POINT:
1736 		      if (handle != NULL)
1737 			{
1738 			    cs = GEOSGeom_getCoordSeq_r (handle, geos_item);
1739 			    GEOSCoordSeq_getDimensions_r (handle, cs, &dims);
1740 			}
1741 		      else
1742 			{
1743 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1744 			    cs = GEOSGeom_getCoordSeq (geos_item);
1745 			    GEOSCoordSeq_getDimensions (cs, &dims);
1746 #endif
1747 			}
1748 		      if (dims == 3)
1749 			{
1750 			    if (handle != NULL)
1751 			      {
1752 				  GEOSCoordSeq_getX_r (handle, cs, 0, &x);
1753 				  GEOSCoordSeq_getY_r (handle, cs, 0, &y);
1754 				  GEOSCoordSeq_getZ_r (handle, cs, 0, &z);
1755 			      }
1756 			    else
1757 			      {
1758 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1759 				  GEOSCoordSeq_getX (cs, 0, &x);
1760 				  GEOSCoordSeq_getY (cs, 0, &y);
1761 				  GEOSCoordSeq_getZ (cs, 0, &z);
1762 #endif
1763 			      }
1764 			}
1765 		      else
1766 			{
1767 			    if (handle != NULL)
1768 			      {
1769 				  GEOSCoordSeq_getX_r (handle, cs, 0, &x);
1770 				  GEOSCoordSeq_getY_r (handle, cs, 0, &y);
1771 			      }
1772 			    else
1773 			      {
1774 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1775 				  GEOSCoordSeq_getX (cs, 0, &x);
1776 				  GEOSCoordSeq_getY (cs, 0, &y);
1777 #endif
1778 			      }
1779 			    z = 0.0;
1780 			}
1781 		      if (dimension_model == GAIA_XY_Z)
1782 			  gaiaAddPointToGeomCollXYZ (gaia, x, y, z);
1783 		      else if (dimension_model == GAIA_XY_M)
1784 			  gaiaAddPointToGeomCollXYM (gaia, x, y, 0.0);
1785 		      else if (dimension_model == GAIA_XY_Z_M)
1786 			  gaiaAddPointToGeomCollXYZM (gaia, x, y, z, 0.0);
1787 		      else
1788 			  gaiaAddPointToGeomColl (gaia, x, y);
1789 		      break;
1790 		  case GEOS_LINESTRING:
1791 		      if (handle != NULL)
1792 			{
1793 			    cs = GEOSGeom_getCoordSeq_r (handle, geos_item);
1794 			    GEOSCoordSeq_getDimensions_r (handle, cs, &dims);
1795 			    GEOSCoordSeq_getSize_r (handle, cs, &points);
1796 			}
1797 		      else
1798 			{
1799 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1800 			    cs = GEOSGeom_getCoordSeq (geos_item);
1801 			    GEOSCoordSeq_getDimensions (cs, &dims);
1802 			    GEOSCoordSeq_getSize (cs, &points);
1803 #endif
1804 			}
1805 		      ln = gaiaAddLinestringToGeomColl (gaia, points);
1806 		      for (iv = 0; iv < (int) points; iv++)
1807 			{
1808 			    if (dims == 3)
1809 			      {
1810 				  if (handle != NULL)
1811 				    {
1812 					GEOSCoordSeq_getX_r (handle, cs, iv,
1813 							     &x);
1814 					GEOSCoordSeq_getY_r (handle, cs, iv,
1815 							     &y);
1816 					GEOSCoordSeq_getZ_r (handle, cs, iv,
1817 							     &z);
1818 				    }
1819 				  else
1820 				    {
1821 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1822 					GEOSCoordSeq_getX (cs, iv, &x);
1823 					GEOSCoordSeq_getY (cs, iv, &y);
1824 					GEOSCoordSeq_getZ (cs, iv, &z);
1825 #endif
1826 				    }
1827 			      }
1828 			    else
1829 			      {
1830 				  if (handle != NULL)
1831 				    {
1832 					GEOSCoordSeq_getX_r (handle, cs, iv,
1833 							     &x);
1834 					GEOSCoordSeq_getY_r (handle, cs, iv,
1835 							     &y);
1836 				    }
1837 				  else
1838 				    {
1839 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1840 					GEOSCoordSeq_getX (cs, iv, &x);
1841 					GEOSCoordSeq_getY (cs, iv, &y);
1842 #endif
1843 				    }
1844 				  z = 0.0;
1845 			      }
1846 			    if (dimension_model == GAIA_XY_Z)
1847 			      {
1848 				  gaiaSetPointXYZ (ln->Coords, iv, x, y, z);
1849 			      }
1850 			    else if (dimension_model == GAIA_XY_M)
1851 			      {
1852 				  gaiaSetPointXYM (ln->Coords, iv, x, y, 0.0);
1853 			      }
1854 			    else if (dimension_model == GAIA_XY_Z_M)
1855 			      {
1856 				  gaiaSetPointXYZM (ln->Coords, iv, x, y, z,
1857 						    0.0);
1858 			      }
1859 			    else
1860 			      {
1861 				  gaiaSetPoint (ln->Coords, iv, x, y);
1862 			      }
1863 			}
1864 		      break;
1865 		  case GEOS_MULTILINESTRING:
1866 		      if (handle != NULL)
1867 			  nSubItems =
1868 			      GEOSGetNumGeometries_r (handle, geos_item);
1869 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1870 		      else
1871 			  nSubItems = GEOSGetNumGeometries (geos_item);
1872 #endif
1873 		      for (sub_it = 0; sub_it < nSubItems; sub_it++)
1874 			{
1875 			    /* looping on elementaty geometries */
1876 			    if (handle != NULL)
1877 			      {
1878 				  geos_sub_item =
1879 				      GEOSGetGeometryN_r (handle, geos_item,
1880 							  sub_it);
1881 				  cs = GEOSGeom_getCoordSeq_r (handle,
1882 							       geos_sub_item);
1883 				  GEOSCoordSeq_getDimensions_r (handle, cs,
1884 								&dims);
1885 				  GEOSCoordSeq_getSize_r (handle, cs, &points);
1886 			      }
1887 			    else
1888 			      {
1889 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1890 				  geos_sub_item =
1891 				      GEOSGetGeometryN (geos_item, sub_it);
1892 				  cs = GEOSGeom_getCoordSeq (geos_sub_item);
1893 				  GEOSCoordSeq_getDimensions (cs, &dims);
1894 				  GEOSCoordSeq_getSize (cs, &points);
1895 #endif
1896 			      }
1897 			    ln = gaiaAddLinestringToGeomColl (gaia, points);
1898 			    for (iv = 0; iv < (int) points; iv++)
1899 			      {
1900 				  if (dims == 3)
1901 				    {
1902 					if (handle != NULL)
1903 					  {
1904 					      GEOSCoordSeq_getX_r (handle, cs,
1905 								   iv, &x);
1906 					      GEOSCoordSeq_getY_r (handle, cs,
1907 								   iv, &y);
1908 					      GEOSCoordSeq_getZ_r (handle, cs,
1909 								   iv, &z);
1910 					  }
1911 					else
1912 					  {
1913 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1914 					      GEOSCoordSeq_getX (cs, iv, &x);
1915 					      GEOSCoordSeq_getY (cs, iv, &y);
1916 					      GEOSCoordSeq_getZ (cs, iv, &z);
1917 #endif
1918 					  }
1919 				    }
1920 				  else
1921 				    {
1922 					if (handle != NULL)
1923 					  {
1924 					      GEOSCoordSeq_getX_r (handle, cs,
1925 								   iv, &x);
1926 					      GEOSCoordSeq_getY_r (handle, cs,
1927 								   iv, &y);
1928 					  }
1929 					else
1930 					  {
1931 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1932 					      GEOSCoordSeq_getX (cs, iv, &x);
1933 					      GEOSCoordSeq_getY (cs, iv, &y);
1934 #endif
1935 					  }
1936 					z = 0.0;
1937 				    }
1938 				  if (dimension_model == GAIA_XY_Z)
1939 				    {
1940 					gaiaSetPointXYZ (ln->Coords, iv, x, y,
1941 							 z);
1942 				    }
1943 				  else if (dimension_model == GAIA_XY_M)
1944 				    {
1945 					gaiaSetPointXYM (ln->Coords, iv, x, y,
1946 							 0.0);
1947 				    }
1948 				  else if (dimension_model == GAIA_XY_Z_M)
1949 				    {
1950 					gaiaSetPointXYZM (ln->Coords, iv, x, y,
1951 							  z, 0.0);
1952 				    }
1953 				  else
1954 				    {
1955 					gaiaSetPoint (ln->Coords, iv, x, y);
1956 				    }
1957 			      }
1958 			}
1959 		      break;
1960 		  case GEOS_POLYGON:
1961 		      /* exterior ring */
1962 		      if (handle != NULL)
1963 			{
1964 			    holes =
1965 				GEOSGetNumInteriorRings_r (handle, geos_item);
1966 			    geos_ring =
1967 				GEOSGetExteriorRing_r (handle, geos_item);
1968 			    cs = GEOSGeom_getCoordSeq_r (handle, geos_ring);
1969 			    GEOSCoordSeq_getDimensions_r (handle, cs, &dims);
1970 			    GEOSCoordSeq_getSize_r (handle, cs, &points);
1971 			}
1972 		      else
1973 			{
1974 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
1975 			    holes = GEOSGetNumInteriorRings (geos_item);
1976 			    geos_ring = GEOSGetExteriorRing (geos_item);
1977 			    cs = GEOSGeom_getCoordSeq (geos_ring);
1978 			    GEOSCoordSeq_getDimensions (cs, &dims);
1979 			    GEOSCoordSeq_getSize (cs, &points);
1980 #endif
1981 			}
1982 		      pg = gaiaAddPolygonToGeomColl (gaia, points, holes);
1983 		      rng = pg->Exterior;
1984 		      for (iv = 0; iv < (int) points; iv++)
1985 			{
1986 			    if (dims == 3)
1987 			      {
1988 				  if (handle != NULL)
1989 				    {
1990 					GEOSCoordSeq_getX_r (handle, cs, iv,
1991 							     &x);
1992 					GEOSCoordSeq_getY_r (handle, cs, iv,
1993 							     &y);
1994 					GEOSCoordSeq_getZ_r (handle, cs, iv,
1995 							     &z);
1996 				    }
1997 				  else
1998 				    {
1999 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
2000 					GEOSCoordSeq_getX (cs, iv, &x);
2001 					GEOSCoordSeq_getY (cs, iv, &y);
2002 					GEOSCoordSeq_getZ (cs, iv, &z);
2003 #endif
2004 				    }
2005 			      }
2006 			    else
2007 			      {
2008 				  if (handle != NULL)
2009 				    {
2010 					GEOSCoordSeq_getX_r (handle, cs, iv,
2011 							     &x);
2012 					GEOSCoordSeq_getY_r (handle, cs, iv,
2013 							     &y);
2014 				    }
2015 				  else
2016 				    {
2017 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
2018 					GEOSCoordSeq_getX (cs, iv, &x);
2019 					GEOSCoordSeq_getY (cs, iv, &y);
2020 #endif
2021 				    }
2022 				  z = 0.0;
2023 			      }
2024 			    if (dimension_model == GAIA_XY_Z)
2025 			      {
2026 				  gaiaSetPointXYZ (rng->Coords, iv, x, y, z);
2027 			      }
2028 			    else if (dimension_model == GAIA_XY_M)
2029 			      {
2030 				  gaiaSetPointXYM (rng->Coords, iv, x, y, 0.0);
2031 			      }
2032 			    else if (dimension_model == GAIA_XY_Z_M)
2033 			      {
2034 				  gaiaSetPointXYZM (rng->Coords, iv, x, y, z,
2035 						    0.0);
2036 			      }
2037 			    else
2038 			      {
2039 				  gaiaSetPoint (rng->Coords, iv, x, y);
2040 			      }
2041 			}
2042 		      for (ib = 0; ib < holes; ib++)
2043 			{
2044 			    /* interior rings */
2045 			    if (handle != NULL)
2046 			      {
2047 				  geos_ring =
2048 				      GEOSGetInteriorRingN_r (handle, geos_item,
2049 							      ib);
2050 				  cs = GEOSGeom_getCoordSeq_r (handle,
2051 							       geos_ring);
2052 				  GEOSCoordSeq_getDimensions_r (handle, cs,
2053 								&dims);
2054 				  GEOSCoordSeq_getSize_r (handle, cs, &points);
2055 			      }
2056 			    else
2057 			      {
2058 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
2059 				  geos_ring =
2060 				      GEOSGetInteriorRingN (geos_item, ib);
2061 				  cs = GEOSGeom_getCoordSeq (geos_ring);
2062 				  GEOSCoordSeq_getDimensions (cs, &dims);
2063 				  GEOSCoordSeq_getSize (cs, &points);
2064 #endif
2065 			      }
2066 			    rng = gaiaAddInteriorRing (pg, ib, points);
2067 			    for (iv = 0; iv < (int) points; iv++)
2068 			      {
2069 				  if (dims == 3)
2070 				    {
2071 					if (handle != NULL)
2072 					  {
2073 					      GEOSCoordSeq_getX_r (handle, cs,
2074 								   iv, &x);
2075 					      GEOSCoordSeq_getY_r (handle, cs,
2076 								   iv, &y);
2077 					      GEOSCoordSeq_getZ_r (handle, cs,
2078 								   iv, &z);
2079 					  }
2080 					else
2081 					  {
2082 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
2083 					      GEOSCoordSeq_getX (cs, iv, &x);
2084 					      GEOSCoordSeq_getY (cs, iv, &y);
2085 					      GEOSCoordSeq_getZ (cs, iv, &z);
2086 #endif
2087 					  }
2088 				    }
2089 				  else
2090 				    {
2091 					if (handle != NULL)
2092 					  {
2093 					      GEOSCoordSeq_getX_r (handle, cs,
2094 								   iv, &x);
2095 					      GEOSCoordSeq_getY_r (handle, cs,
2096 								   iv, &y);
2097 					  }
2098 					else
2099 					  {
2100 #ifndef GEOS_USE_ONLY_R_API	/* obsolete versions non fully thread-safe */
2101 					      GEOSCoordSeq_getX (cs, iv, &x);
2102 					      GEOSCoordSeq_getY (cs, iv, &y);
2103 #endif
2104 					  }
2105 					z = 0.0;
2106 				    }
2107 				  if (dimension_model == GAIA_XY_Z)
2108 				    {
2109 					gaiaSetPointXYZ (rng->Coords, iv, x, y,
2110 							 z);
2111 				    }
2112 				  else if (dimension_model == GAIA_XY_M)
2113 				    {
2114 					gaiaSetPointXYM (rng->Coords, iv, x, y,
2115 							 0.0);
2116 				    }
2117 				  else if (dimension_model == GAIA_XY_Z_M)
2118 				    {
2119 					gaiaSetPointXYZM (rng->Coords, iv, x, y,
2120 							  z, 0.0);
2121 				    }
2122 				  else
2123 				    {
2124 					gaiaSetPoint (rng->Coords, iv, x, y);
2125 				    }
2126 			      }
2127 			}
2128 		      break;
2129 		  };
2130 	    }
2131 	  break;
2132       };
2133     return gaia;
2134 }
2135 
2136 GAIAGEO_DECLARE void *
gaiaToGeos(const gaiaGeomCollPtr gaia)2137 gaiaToGeos (const gaiaGeomCollPtr gaia)
2138 {
2139 /* converting a GAIA Geometry into a GEOS Geometry */
2140     return toGeosGeometry (NULL, NULL, gaia, GAIA2GEOS_ALL);
2141 }
2142 
2143 GAIAGEO_DECLARE void *
gaiaToGeos_r(const void * p_cache,const gaiaGeomCollPtr gaia)2144 gaiaToGeos_r (const void *p_cache, const gaiaGeomCollPtr gaia)
2145 {
2146 /* converting a GAIA Geometry into a GEOS Geometry */
2147     struct splite_internal_cache *cache =
2148 	(struct splite_internal_cache *) p_cache;
2149     GEOSContextHandle_t handle = NULL;
2150     if (cache == NULL)
2151 	return NULL;
2152     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2153 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2154 	return NULL;
2155     handle = cache->GEOS_handle;
2156     if (handle == NULL)
2157 	return NULL;
2158     return toGeosGeometry (cache, handle, gaia, GAIA2GEOS_ALL);
2159 }
2160 
2161 GAIAGEO_DECLARE void *
gaiaToGeosSelective(const gaiaGeomCollPtr gaia,int mode)2162 gaiaToGeosSelective (const gaiaGeomCollPtr gaia, int mode)
2163 {
2164 /* converting a GAIA Geometry into a GEOS Geometry (selected type) */
2165     if (mode == GAIA2GEOS_ONLY_POINTS || mode == GAIA2GEOS_ONLY_LINESTRINGS
2166 	|| mode == GAIA2GEOS_ONLY_POLYGONS)
2167 	;
2168     else
2169 	mode = GAIA2GEOS_ALL;
2170     return toGeosGeometry (NULL, NULL, gaia, mode);
2171 }
2172 
2173 GAIAGEO_DECLARE void *
gaiaToGeosSelective_r(const void * p_cache,const gaiaGeomCollPtr gaia,int mode)2174 gaiaToGeosSelective_r (const void *p_cache, const gaiaGeomCollPtr gaia,
2175 		       int mode)
2176 {
2177 /* converting a GAIA Geometry into a GEOS Geometry (selected type) */
2178     struct splite_internal_cache *cache =
2179 	(struct splite_internal_cache *) p_cache;
2180     GEOSContextHandle_t handle = NULL;
2181     if (cache == NULL)
2182 	return NULL;
2183     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2184 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2185 	return NULL;
2186     handle = cache->GEOS_handle;
2187     if (handle == NULL)
2188 	return NULL;
2189     if (mode == GAIA2GEOS_ONLY_POINTS || mode == GAIA2GEOS_ONLY_LINESTRINGS
2190 	|| mode == GAIA2GEOS_ONLY_POLYGONS)
2191 	;
2192     else
2193 	mode = GAIA2GEOS_ALL;
2194     return toGeosGeometry (cache, handle, gaia, mode);
2195 }
2196 
2197 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromGeos_XY(const void * xgeos)2198 gaiaFromGeos_XY (const void *xgeos)
2199 {
2200 /* converting a GEOS Geometry into a GAIA Geometry [XY] */
2201     const GEOSGeometry *geos = xgeos;
2202     return fromGeosGeometry (NULL, geos, GAIA_XY);
2203 }
2204 
2205 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromGeos_XYZ(const void * xgeos)2206 gaiaFromGeos_XYZ (const void *xgeos)
2207 {
2208 /* converting a GEOS Geometry into a GAIA Geometry [XYZ] */
2209     const GEOSGeometry *geos = xgeos;
2210     return fromGeosGeometry (NULL, geos, GAIA_XY_Z);
2211 }
2212 
2213 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromGeos_XYM(const void * xgeos)2214 gaiaFromGeos_XYM (const void *xgeos)
2215 {
2216 /* converting a GEOS Geometry into a GAIA Geometry [XYM] */
2217     const GEOSGeometry *geos = xgeos;
2218     return fromGeosGeometry (NULL, geos, GAIA_XY_M);
2219 }
2220 
2221 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromGeos_XYZM(const void * xgeos)2222 gaiaFromGeos_XYZM (const void *xgeos)
2223 {
2224 /* converting a GEOS Geometry into a GAIA Geometry [XYZM] */
2225     const GEOSGeometry *geos = xgeos;
2226     return fromGeosGeometry (NULL, geos, GAIA_XY_Z_M);
2227 }
2228 
2229 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromGeos_XY_r(const void * p_cache,const void * xgeos)2230 gaiaFromGeos_XY_r (const void *p_cache, const void *xgeos)
2231 {
2232 /* converting a GEOS Geometry into a GAIA Geometry [XY] */
2233     const GEOSGeometry *geos = xgeos;
2234     struct splite_internal_cache *cache =
2235 	(struct splite_internal_cache *) p_cache;
2236     GEOSContextHandle_t handle = NULL;
2237     if (cache == NULL)
2238 	return NULL;
2239     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2240 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2241 	return NULL;
2242     handle = cache->GEOS_handle;
2243     if (handle == NULL)
2244 	return NULL;
2245     return fromGeosGeometry (handle, geos, GAIA_XY);
2246 }
2247 
2248 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromGeos_XYZ_r(const void * p_cache,const void * xgeos)2249 gaiaFromGeos_XYZ_r (const void *p_cache, const void *xgeos)
2250 {
2251 /* converting a GEOS Geometry into a GAIA Geometry [XYZ] */
2252     const GEOSGeometry *geos = xgeos;
2253     struct splite_internal_cache *cache =
2254 	(struct splite_internal_cache *) p_cache;
2255     GEOSContextHandle_t handle = NULL;
2256     if (cache == NULL)
2257 	return NULL;
2258     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2259 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2260 	return NULL;
2261     handle = cache->GEOS_handle;
2262     if (handle == NULL)
2263 	return NULL;
2264     return fromGeosGeometry (handle, geos, GAIA_XY_Z);
2265 }
2266 
2267 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromGeos_XYM_r(const void * p_cache,const void * xgeos)2268 gaiaFromGeos_XYM_r (const void *p_cache, const void *xgeos)
2269 {
2270 /* converting a GEOS Geometry into a GAIA Geometry [XYM] */
2271     const GEOSGeometry *geos = xgeos;
2272     struct splite_internal_cache *cache =
2273 	(struct splite_internal_cache *) p_cache;
2274     GEOSContextHandle_t handle = NULL;
2275     if (cache == NULL)
2276 	return NULL;
2277     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2278 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2279 	return NULL;
2280     handle = cache->GEOS_handle;
2281     if (handle == NULL)
2282 	return NULL;
2283     return fromGeosGeometry (handle, geos, GAIA_XY_M);
2284 }
2285 
2286 GAIAGEO_DECLARE gaiaGeomCollPtr
gaiaFromGeos_XYZM_r(const void * p_cache,const void * xgeos)2287 gaiaFromGeos_XYZM_r (const void *p_cache, const void *xgeos)
2288 {
2289 /* converting a GEOS Geometry into a GAIA Geometry [XYZM] */
2290     const GEOSGeometry *geos = xgeos;
2291     struct splite_internal_cache *cache =
2292 	(struct splite_internal_cache *) p_cache;
2293     GEOSContextHandle_t handle = NULL;
2294     if (cache == NULL)
2295 	return NULL;
2296     if (cache->magic1 != SPATIALITE_CACHE_MAGIC1
2297 	|| cache->magic2 != SPATIALITE_CACHE_MAGIC2)
2298 	return NULL;
2299     handle = cache->GEOS_handle;
2300     if (handle == NULL)
2301 	return NULL;
2302     return fromGeosGeometry (handle, geos, GAIA_XY_Z_M);
2303 }
2304 
2305 #endif /* end including GEOS */
2306