1 /*
2 
3  gg_wkt.c -- Gaia common support for WKT encoded geometries
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 Klaus Foerster klaus.foerster@svg.cc
32 
33 Alternatively, the contents of this file may be used under the terms of
34 either the GNU General Public License Version 2 or later (the "GPL"), or
35 the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
36 in which case the provisions of the GPL or the LGPL are applicable instead
37 of those above. If you wish to allow use of your version of this file only
38 under the terms of either the GPL or the LGPL, and not to allow others to
39 use your version of this file under the terms of the MPL, indicate your
40 decision by deleting the provisions above and replace them with the notice
41 and other provisions required by the GPL or the LGPL. If you do not delete
42 the provisions above, a recipient may use your version of this file under
43 the terms of any one of the MPL, the GPL or the LGPL.
44 
45 */
46 
47 #include <sys/types.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <string.h>
51 
52 #if defined(_WIN32) && !defined(__MINGW32__)
53 #include "config-msvc.h"
54 #else
55 #include "config.h"
56 #endif
57 
58 #include <spatialite/sqlite.h>
59 
60 #include <spatialite/gaiageo.h>
61 
62 static void
gaiaOutClean(char * buffer)63 gaiaOutClean (char *buffer)
64 {
65 /* cleans unneeded trailing zeros */
66     int i;
67     for (i = strlen (buffer) - 1; i > 0; i--)
68       {
69 	  if (buffer[i] == '0')
70 	      buffer[i] = '\0';
71 	  else
72 	      break;
73       }
74     if (buffer[i] == '.')
75 	buffer[i] = '\0';
76     if (strcmp (buffer, "-0") == 0)
77       {
78 	  /* avoiding to return embarassing NEGATIVE ZEROes */
79 	  strcpy (buffer, "0");
80       }
81 
82     if (strcmp (buffer, "-1.#QNAN") == 0 || strcmp (buffer, "NaN") == 0
83 	|| strcmp (buffer, "1.#QNAN") == 0
84 	|| strcmp (buffer, "-1.#IND") == 0 || strcmp (buffer, "1.#IND") == 0)
85       {
86 	  /* on Windows a NaN could be represented in "odd" ways */
87 	  /* this is intended to restore a consistent behaviour  */
88 	  strcpy (buffer, "nan");
89       }
90 }
91 
92 GAIAGEO_DECLARE void
gaiaOutBufferInitialize(gaiaOutBufferPtr buf)93 gaiaOutBufferInitialize (gaiaOutBufferPtr buf)
94 {
95 /* initializing a dynamically growing output buffer */
96     buf->Buffer = NULL;
97     buf->WriteOffset = 0;
98     buf->BufferSize = 0;
99     buf->Error = 0;
100 }
101 
102 GAIAGEO_DECLARE void
gaiaOutBufferReset(gaiaOutBufferPtr buf)103 gaiaOutBufferReset (gaiaOutBufferPtr buf)
104 {
105 /* cleaning a dynamically growing output buffer */
106     if (buf->Buffer)
107 	free (buf->Buffer);
108     buf->Buffer = NULL;
109     buf->WriteOffset = 0;
110     buf->BufferSize = 0;
111     buf->Error = 0;
112 }
113 
114 GAIAGEO_DECLARE void
gaiaAppendToOutBuffer(gaiaOutBufferPtr buf,const char * text)115 gaiaAppendToOutBuffer (gaiaOutBufferPtr buf, const char *text)
116 {
117 /* appending a text string */
118     int len = strlen (text);
119     int free_size = buf->BufferSize - buf->WriteOffset;
120     if ((len + 1) > free_size)
121       {
122 	  /* we must allocate a bigger buffer */
123 	  int new_size;
124 	  char *new_buf;
125 	  if (buf->BufferSize == 0)
126 	      new_size = (len + 1) + 1024;
127 	  else if (buf->BufferSize <= 4196)
128 	      new_size = buf->BufferSize + (len + 1) + 4196;
129 	  else if (buf->BufferSize <= 65536)
130 	      new_size = buf->BufferSize + (len + 1) + 65536;
131 	  else
132 	      new_size = buf->BufferSize + (len + 1) + (1024 * 1024);
133 	  new_buf = malloc (new_size);
134 	  if (!new_buf)
135 	    {
136 		buf->Error = 1;
137 		return;
138 	    }
139 	  memcpy (new_buf, buf->Buffer, buf->WriteOffset);
140 	  if (buf->Buffer)
141 	      free (buf->Buffer);
142 	  buf->Buffer = new_buf;
143 	  buf->BufferSize = new_size;
144       }
145     strcpy (buf->Buffer + buf->WriteOffset, text);
146     buf->WriteOffset += len;
147 }
148 
149 static void
gaiaOutPointStrict(gaiaOutBufferPtr out_buf,gaiaPointPtr point,int precision)150 gaiaOutPointStrict (gaiaOutBufferPtr out_buf, gaiaPointPtr point, int precision)
151 {
152 /* formats a WKT POINT [Strict 2D] */
153     char *buf_x;
154     char *buf_y;
155     char *buf;
156     buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
157     gaiaOutClean (buf_x);
158     buf_y = sqlite3_mprintf ("%.*f", precision, point->Y);
159     gaiaOutClean (buf_y);
160     buf = sqlite3_mprintf ("%s %s", buf_x, buf_y);
161     sqlite3_free (buf_x);
162     sqlite3_free (buf_y);
163     gaiaAppendToOutBuffer (out_buf, buf);
164     sqlite3_free (buf);
165 }
166 
167 static void
gaiaOutPoint(gaiaOutBufferPtr out_buf,gaiaPointPtr point,int precision)168 gaiaOutPoint (gaiaOutBufferPtr out_buf, gaiaPointPtr point, int precision)
169 {
170 /* formats a WKT POINT */
171     char *buf_x;
172     char *buf_y;
173     char *buf;
174     if (precision < 0)
175 	buf_x = sqlite3_mprintf ("%1.6f", point->X);
176     else
177 	buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
178     gaiaOutClean (buf_x);
179     if (precision < 0)
180 	buf_y = sqlite3_mprintf ("%1.6f", point->Y);
181     else
182 	buf_y = sqlite3_mprintf ("%.*f", precision, point->Y);
183     gaiaOutClean (buf_y);
184     buf = sqlite3_mprintf ("%s %s", buf_x, buf_y);
185     sqlite3_free (buf_x);
186     sqlite3_free (buf_y);
187     gaiaAppendToOutBuffer (out_buf, buf);
188     sqlite3_free (buf);
189 }
190 
191 GAIAGEO_DECLARE void
gaiaOutPointZex(gaiaOutBufferPtr out_buf,gaiaPointPtr point,int precision)192 gaiaOutPointZex (gaiaOutBufferPtr out_buf, gaiaPointPtr point, int precision)
193 {
194 /* formats a WKT POINTZ */
195     char *buf_x;
196     char *buf_y;
197     char *buf_z;
198     char *buf;
199     if (precision < 0)
200 	buf_x = sqlite3_mprintf ("%1.6f", point->X);
201     else
202 	buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
203     gaiaOutClean (buf_x);
204     if (precision < 0)
205 	buf_y = sqlite3_mprintf ("%1.6f", point->Y);
206     else
207 	buf_y = sqlite3_mprintf ("%.*f", precision, point->Y);
208     gaiaOutClean (buf_y);
209     if (precision < 0)
210 	buf_z = sqlite3_mprintf ("%1.6f", point->Z);
211     else
212 	buf_z = sqlite3_mprintf ("%.*f", precision, point->Z);
213     gaiaOutClean (buf_z);
214     buf = sqlite3_mprintf ("%s %s %s", buf_x, buf_y, buf_z);
215     sqlite3_free (buf_x);
216     sqlite3_free (buf_y);
217     sqlite3_free (buf_z);
218     gaiaAppendToOutBuffer (out_buf, buf);
219     sqlite3_free (buf);
220 }
221 
222 GAIAGEO_DECLARE void
gaiaOutPointZ(gaiaOutBufferPtr out_buf,gaiaPointPtr point)223 gaiaOutPointZ (gaiaOutBufferPtr out_buf, gaiaPointPtr point)
224 {
225 /*
226 * formats a WKT POINTZ
227 * convenience method - default decimal precision
228 */
229     gaiaOutPointZex (out_buf, point, -1);
230 }
231 
232 static void
gaiaOutPointM(gaiaOutBufferPtr out_buf,gaiaPointPtr point,int precision)233 gaiaOutPointM (gaiaOutBufferPtr out_buf, gaiaPointPtr point, int precision)
234 {
235 /* formats a WKT POINTM */
236     char *buf_x;
237     char *buf_y;
238     char *buf_m;
239     char *buf;
240     if (precision < 0)
241 	buf_x = sqlite3_mprintf ("%1.6f", point->X);
242     else
243 	buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
244     gaiaOutClean (buf_x);
245     if (precision < 0)
246 	buf_y = sqlite3_mprintf ("%1.6f", point->Y);
247     else
248 	buf_y = sqlite3_mprintf ("%.*f", precision, point->Y);
249     gaiaOutClean (buf_y);
250     if (precision < 0)
251 	buf_m = sqlite3_mprintf ("%1.6f", point->M);
252     else
253 	buf_m = sqlite3_mprintf ("%.*f", precision, point->M);
254     gaiaOutClean (buf_m);
255     buf = sqlite3_mprintf ("%s %s %s", buf_x, buf_y, buf_m);
256     sqlite3_free (buf_x);
257     sqlite3_free (buf_y);
258     sqlite3_free (buf_m);
259     gaiaAppendToOutBuffer (out_buf, buf);
260     sqlite3_free (buf);
261 }
262 
263 static void
gaiaOutPointZM(gaiaOutBufferPtr out_buf,gaiaPointPtr point,int precision)264 gaiaOutPointZM (gaiaOutBufferPtr out_buf, gaiaPointPtr point, int precision)
265 {
266 /* formats a WKT POINTZM */
267     char *buf_x;
268     char *buf_y;
269     char *buf_z;
270     char *buf_m;
271     char *buf;
272     if (precision < 0)
273 	buf_x = sqlite3_mprintf ("%1.6f", point->X);
274     else
275 	buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
276     gaiaOutClean (buf_x);
277     if (precision < 0)
278 	buf_y = sqlite3_mprintf ("%1.6f", point->Y);
279     else
280 	buf_y = sqlite3_mprintf ("%.*f", precision, point->Y);
281     gaiaOutClean (buf_y);
282     if (precision < 0)
283 	buf_z = sqlite3_mprintf ("%1.6f", point->Z);
284     else
285 	buf_z = sqlite3_mprintf ("%.*f", precision, point->Z);
286     gaiaOutClean (buf_z);
287     if (precision < 0)
288 	buf_m = sqlite3_mprintf ("%1.6f", point->M);
289     else
290 	buf_m = sqlite3_mprintf ("%.*f", precision, point->M);
291     gaiaOutClean (buf_m);
292     buf = sqlite3_mprintf ("%s %s %s %s", buf_x, buf_y, buf_z, buf_m);
293     sqlite3_free (buf_x);
294     sqlite3_free (buf_y);
295     sqlite3_free (buf_z);
296     sqlite3_free (buf_m);
297     gaiaAppendToOutBuffer (out_buf, buf);
298     sqlite3_free (buf);
299 }
300 
301 static void
gaiaOutEwktPoint(gaiaOutBufferPtr out_buf,gaiaPointPtr point)302 gaiaOutEwktPoint (gaiaOutBufferPtr out_buf, gaiaPointPtr point)
303 {
304 /* formats an EWKT POINT */
305     char *buf_x;
306     char *buf_y;
307     char *buf;
308     buf_x = sqlite3_mprintf ("%1.15f", point->X);
309     gaiaOutClean (buf_x);
310     buf_y = sqlite3_mprintf ("%1.15f", point->Y);
311     gaiaOutClean (buf_y);
312     buf = sqlite3_mprintf ("%s %s", buf_x, buf_y);
313     sqlite3_free (buf_x);
314     sqlite3_free (buf_y);
315     gaiaAppendToOutBuffer (out_buf, buf);
316     sqlite3_free (buf);
317 }
318 
319 GAIAGEO_DECLARE void
gaiaOutEwktPointZ(gaiaOutBufferPtr out_buf,gaiaPointPtr point)320 gaiaOutEwktPointZ (gaiaOutBufferPtr out_buf, gaiaPointPtr point)
321 {
322 /* formats an EWKT POINTZ */
323     char *buf_x;
324     char *buf_y;
325     char *buf_z;
326     char *buf;
327     buf_x = sqlite3_mprintf ("%1.15f", point->X);
328     gaiaOutClean (buf_x);
329     buf_y = sqlite3_mprintf ("%1.15f", point->Y);
330     gaiaOutClean (buf_y);
331     buf_z = sqlite3_mprintf ("%1.15f", point->Z);
332     gaiaOutClean (buf_z);
333     buf = sqlite3_mprintf ("%s %s %s", buf_x, buf_y, buf_z);
334     sqlite3_free (buf_x);
335     sqlite3_free (buf_y);
336     sqlite3_free (buf_z);
337     gaiaAppendToOutBuffer (out_buf, buf);
338     sqlite3_free (buf);
339 }
340 
341 static void
gaiaOutEwktPointM(gaiaOutBufferPtr out_buf,gaiaPointPtr point)342 gaiaOutEwktPointM (gaiaOutBufferPtr out_buf, gaiaPointPtr point)
343 {
344 /* formats an EWKT POINTM */
345     char *buf_x;
346     char *buf_y;
347     char *buf_m;
348     char *buf;
349     buf_x = sqlite3_mprintf ("%1.15f", point->X);
350     gaiaOutClean (buf_x);
351     buf_y = sqlite3_mprintf ("%1.15f", point->Y);
352     gaiaOutClean (buf_y);
353     buf_m = sqlite3_mprintf ("%1.15f", point->M);
354     gaiaOutClean (buf_m);
355     buf = sqlite3_mprintf ("%s %s %s", buf_x, buf_y, buf_m);
356     sqlite3_free (buf_x);
357     sqlite3_free (buf_y);
358     sqlite3_free (buf_m);
359     gaiaAppendToOutBuffer (out_buf, buf);
360     sqlite3_free (buf);
361 }
362 
363 static void
gaiaOutEwktPointZM(gaiaOutBufferPtr out_buf,gaiaPointPtr point)364 gaiaOutEwktPointZM (gaiaOutBufferPtr out_buf, gaiaPointPtr point)
365 {
366 /* formats an EWKT POINTZM */
367     char *buf_x;
368     char *buf_y;
369     char *buf_z;
370     char *buf_m;
371     char *buf;
372     buf_x = sqlite3_mprintf ("%1.15f", point->X);
373     gaiaOutClean (buf_x);
374     buf_y = sqlite3_mprintf ("%1.15f", point->Y);
375     gaiaOutClean (buf_y);
376     buf_z = sqlite3_mprintf ("%1.15f", point->Z);
377     gaiaOutClean (buf_z);
378     buf_m = sqlite3_mprintf ("%1.15f", point->M);
379     gaiaOutClean (buf_m);
380     buf = sqlite3_mprintf ("%s %s %s %s", buf_x, buf_y, buf_z, buf_m);
381     sqlite3_free (buf_x);
382     sqlite3_free (buf_y);
383     sqlite3_free (buf_z);
384     sqlite3_free (buf_m);
385     gaiaAppendToOutBuffer (out_buf, buf);
386     sqlite3_free (buf);
387 }
388 
389 static void
gaiaOutLinestringStrict(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line,int precision)390 gaiaOutLinestringStrict (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line,
391 			 int precision)
392 {
393 /* formats a WKT LINESTRING [Strict 2D] */
394     char *buf_x;
395     char *buf_y;
396     char *buf;
397     double x;
398     double y;
399     double z;
400     double m;
401     int iv;
402     for (iv = 0; iv < line->Points; iv++)
403       {
404 	  if (line->DimensionModel == GAIA_XY_Z)
405 	    {
406 		gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
407 	    }
408 	  else if (line->DimensionModel == GAIA_XY_M)
409 	    {
410 		gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
411 	    }
412 	  else if (line->DimensionModel == GAIA_XY_Z_M)
413 	    {
414 		gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
415 	    }
416 	  else
417 	    {
418 		gaiaGetPoint (line->Coords, iv, &x, &y);
419 	    }
420 	  buf_x = sqlite3_mprintf ("%.*f", precision, x);
421 	  gaiaOutClean (buf_x);
422 	  buf_y = sqlite3_mprintf ("%.*f", precision, y);
423 	  gaiaOutClean (buf_y);
424 	  if (iv > 0)
425 	      buf = sqlite3_mprintf (",%s %s", buf_x, buf_y);
426 	  else
427 	      buf = sqlite3_mprintf ("%s %s", buf_x, buf_y);
428 	  sqlite3_free (buf_x);
429 	  sqlite3_free (buf_y);
430 	  gaiaAppendToOutBuffer (out_buf, buf);
431 	  sqlite3_free (buf);
432       }
433 }
434 
435 static void
gaiaOutLinestring(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line,int precision)436 gaiaOutLinestring (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line,
437 		   int precision)
438 {
439 /* formats a WKT LINESTRING */
440     char *buf_x;
441     char *buf_y;
442     char *buf;
443     double x;
444     double y;
445     int iv;
446     for (iv = 0; iv < line->Points; iv++)
447       {
448 	  gaiaGetPoint (line->Coords, iv, &x, &y);
449 	  if (precision < 0)
450 	      buf_x = sqlite3_mprintf ("%1.6f", x);
451 	  else
452 	      buf_x = sqlite3_mprintf ("%.*f", precision, x);
453 	  gaiaOutClean (buf_x);
454 	  if (precision < 0)
455 	      buf_y = sqlite3_mprintf ("%1.6f", y);
456 	  else
457 	      buf_y = sqlite3_mprintf ("%.*f", precision, y);
458 	  gaiaOutClean (buf_y);
459 	  if (iv > 0)
460 	      buf = sqlite3_mprintf (", %s %s", buf_x, buf_y);
461 	  else
462 	      buf = sqlite3_mprintf ("%s %s", buf_x, buf_y);
463 	  sqlite3_free (buf_x);
464 	  sqlite3_free (buf_y);
465 	  gaiaAppendToOutBuffer (out_buf, buf);
466 	  sqlite3_free (buf);
467       }
468 }
469 
470 GAIAGEO_DECLARE void
gaiaOutLinestringZex(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line,int precision)471 gaiaOutLinestringZex (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line,
472 		      int precision)
473 {
474 /* formats a WKT LINESTRINGZ */
475     char *buf_x;
476     char *buf_y;
477     char *buf_z;
478     char *buf;
479     double x;
480     double y;
481     double z;
482     int iv;
483     for (iv = 0; iv < line->Points; iv++)
484       {
485 	  gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
486 	  if (precision < 0)
487 	      buf_x = sqlite3_mprintf ("%1.6f", x);
488 	  else
489 	      buf_x = sqlite3_mprintf ("%.*f", precision, x);
490 	  gaiaOutClean (buf_x);
491 	  if (precision < 0)
492 	      buf_y = sqlite3_mprintf ("%1.6f", y);
493 	  else
494 	      buf_y = sqlite3_mprintf ("%.*f", precision, y);
495 	  gaiaOutClean (buf_y);
496 	  if (precision < 0)
497 	      buf_z = sqlite3_mprintf ("%1.6f", z);
498 	  else
499 	      buf_z = sqlite3_mprintf ("%.*f", precision, z);
500 	  gaiaOutClean (buf_z);
501 	  if (iv > 0)
502 	      buf = sqlite3_mprintf (", %s %s %s", buf_x, buf_y, buf_z);
503 	  else
504 	      buf = sqlite3_mprintf ("%s %s %s", buf_x, buf_y, buf_z);
505 	  sqlite3_free (buf_x);
506 	  sqlite3_free (buf_y);
507 	  sqlite3_free (buf_z);
508 	  gaiaAppendToOutBuffer (out_buf, buf);
509 	  sqlite3_free (buf);
510       }
511 }
512 
513 GAIAGEO_DECLARE void
gaiaOutLinestringZ(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line)514 gaiaOutLinestringZ (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line)
515 {
516 /*
517 * formats a WKT LINESTRINGZ
518 * convenience method - default decimal precision
519 */
520     gaiaOutLinestringZex (out_buf, line, -1);
521 }
522 
523 static void
gaiaOutLinestringM(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line,int precision)524 gaiaOutLinestringM (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line,
525 		    int precision)
526 {
527 /* formats a WKT LINESTRINGM */
528     char *buf_x;
529     char *buf_y;
530     char *buf_m;
531     char *buf;
532     double x;
533     double y;
534     double m;
535     int iv;
536     for (iv = 0; iv < line->Points; iv++)
537       {
538 	  gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
539 	  if (precision < 0)
540 	      buf_x = sqlite3_mprintf ("%1.6f", x);
541 	  else
542 	      buf_x = sqlite3_mprintf ("%.*f", precision, x);
543 	  gaiaOutClean (buf_x);
544 	  if (precision < 0)
545 	      buf_y = sqlite3_mprintf ("%1.6f", y);
546 	  else
547 	      buf_y = sqlite3_mprintf ("%.*f", precision, y);
548 	  gaiaOutClean (buf_y);
549 	  if (precision < 0)
550 	      buf_m = sqlite3_mprintf ("%1.6f", m);
551 	  else
552 	      buf_m = sqlite3_mprintf ("%.*f", precision, m);
553 	  gaiaOutClean (buf_m);
554 	  if (iv > 0)
555 	      buf = sqlite3_mprintf (", %s %s %s", buf_x, buf_y, buf_m);
556 	  else
557 	      buf = sqlite3_mprintf ("%s %s %s", buf_x, buf_y, buf_m);
558 	  sqlite3_free (buf_x);
559 	  sqlite3_free (buf_y);
560 	  sqlite3_free (buf_m);
561 	  gaiaAppendToOutBuffer (out_buf, buf);
562 	  sqlite3_free (buf);
563       }
564 }
565 
566 static void
gaiaOutLinestringZM(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line,int precision)567 gaiaOutLinestringZM (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line,
568 		     int precision)
569 {
570 /* formats a WKT LINESTRINGZM */
571     char *buf_x;
572     char *buf_y;
573     char *buf_z;
574     char *buf_m;
575     char *buf;
576     double x;
577     double y;
578     double z;
579     double m;
580     int iv;
581     for (iv = 0; iv < line->Points; iv++)
582       {
583 	  gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
584 	  if (precision < 0)
585 	      buf_x = sqlite3_mprintf ("%1.6f", x);
586 	  else
587 	      buf_x = sqlite3_mprintf ("%.*f", precision, x);
588 	  gaiaOutClean (buf_x);
589 	  if (precision < 0)
590 	      buf_y = sqlite3_mprintf ("%1.6f", y);
591 	  else
592 	      buf_y = sqlite3_mprintf ("%.*f", precision, y);
593 	  gaiaOutClean (buf_y);
594 	  if (precision < 0)
595 	      buf_z = sqlite3_mprintf ("%1.6f", z);
596 	  else
597 	      buf_z = sqlite3_mprintf ("%.*f", precision, z);
598 	  gaiaOutClean (buf_z);
599 	  if (precision < 0)
600 	      buf_m = sqlite3_mprintf ("%1.6f", m);
601 	  else
602 	      buf_m = sqlite3_mprintf ("%.*f", precision, m);
603 	  gaiaOutClean (buf_m);
604 	  if (iv > 0)
605 	      buf =
606 		  sqlite3_mprintf (", %s %s %s %s", buf_x, buf_y, buf_z, buf_m);
607 	  else
608 	      buf = sqlite3_mprintf ("%s %s %s %s", buf_x, buf_y, buf_z, buf_m);
609 	  sqlite3_free (buf_x);
610 	  sqlite3_free (buf_y);
611 	  sqlite3_free (buf_z);
612 	  sqlite3_free (buf_m);
613 	  gaiaAppendToOutBuffer (out_buf, buf);
614 	  sqlite3_free (buf);
615       }
616 }
617 
618 static void
gaiaOutEwktLinestring(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line)619 gaiaOutEwktLinestring (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line)
620 {
621 /* formats an EWKT LINESTRING */
622     char *buf_x;
623     char *buf_y;
624     char *buf;
625     double x;
626     double y;
627     int iv;
628     for (iv = 0; iv < line->Points; iv++)
629       {
630 	  gaiaGetPoint (line->Coords, iv, &x, &y);
631 	  buf_x = sqlite3_mprintf ("%1.15f", x);
632 	  gaiaOutClean (buf_x);
633 	  buf_y = sqlite3_mprintf ("%1.15f", y);
634 	  gaiaOutClean (buf_y);
635 	  if (iv > 0)
636 	      buf = sqlite3_mprintf (",%s %s", buf_x, buf_y);
637 	  else
638 	      buf = sqlite3_mprintf ("%s %s", buf_x, buf_y);
639 	  sqlite3_free (buf_x);
640 	  sqlite3_free (buf_y);
641 	  gaiaAppendToOutBuffer (out_buf, buf);
642 	  sqlite3_free (buf);
643       }
644 }
645 
646 GAIAGEO_DECLARE void
gaiaOutEwktLinestringZ(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line)647 gaiaOutEwktLinestringZ (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line)
648 {
649 /* formats an EWKT LINESTRINGZ */
650     char *buf_x;
651     char *buf_y;
652     char *buf_z;
653     char *buf;
654     double x;
655     double y;
656     double z;
657     int iv;
658     for (iv = 0; iv < line->Points; iv++)
659       {
660 	  gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
661 	  buf_x = sqlite3_mprintf ("%1.15f", x);
662 	  gaiaOutClean (buf_x);
663 	  buf_y = sqlite3_mprintf ("%1.15f", y);
664 	  gaiaOutClean (buf_y);
665 	  buf_z = sqlite3_mprintf ("%1.15f", z);
666 	  gaiaOutClean (buf_z);
667 	  if (iv > 0)
668 	      buf = sqlite3_mprintf (",%s %s %s", buf_x, buf_y, buf_z);
669 	  else
670 	      buf = sqlite3_mprintf ("%s %s %s", buf_x, buf_y, buf_z);
671 	  sqlite3_free (buf_x);
672 	  sqlite3_free (buf_y);
673 	  sqlite3_free (buf_z);
674 	  gaiaAppendToOutBuffer (out_buf, buf);
675 	  sqlite3_free (buf);
676       }
677 }
678 
679 static void
gaiaOutEwktLinestringM(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line)680 gaiaOutEwktLinestringM (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line)
681 {
682 /* formats an EWKT LINESTRINGM */
683     char *buf_x;
684     char *buf_y;
685     char *buf_m;
686     char *buf;
687     double x;
688     double y;
689     double m;
690     int iv;
691     for (iv = 0; iv < line->Points; iv++)
692       {
693 	  gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
694 	  buf_x = sqlite3_mprintf ("%1.15f", x);
695 	  gaiaOutClean (buf_x);
696 	  buf_y = sqlite3_mprintf ("%1.15f", y);
697 	  gaiaOutClean (buf_y);
698 	  buf_m = sqlite3_mprintf ("%1.15f", m);
699 	  gaiaOutClean (buf_m);
700 	  if (iv > 0)
701 	      buf = sqlite3_mprintf (",%s %s %s", buf_x, buf_y, buf_m);
702 	  else
703 	      buf = sqlite3_mprintf ("%s %s %s", buf_x, buf_y, buf_m);
704 	  sqlite3_free (buf_x);
705 	  sqlite3_free (buf_y);
706 	  sqlite3_free (buf_m);
707 	  gaiaAppendToOutBuffer (out_buf, buf);
708 	  sqlite3_free (buf);
709       }
710 }
711 
712 static void
gaiaOutEwktLinestringZM(gaiaOutBufferPtr out_buf,gaiaLinestringPtr line)713 gaiaOutEwktLinestringZM (gaiaOutBufferPtr out_buf, gaiaLinestringPtr line)
714 {
715 /* formats an EWKT LINESTRINGZM */
716     char *buf_x;
717     char *buf_y;
718     char *buf_z;
719     char *buf_m;
720     char *buf;
721     double x;
722     double y;
723     double z;
724     double m;
725     int iv;
726     for (iv = 0; iv < line->Points; iv++)
727       {
728 	  gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
729 	  buf_x = sqlite3_mprintf ("%1.15f", x);
730 	  gaiaOutClean (buf_x);
731 	  buf_y = sqlite3_mprintf ("%1.15f", y);
732 	  gaiaOutClean (buf_y);
733 	  buf_z = sqlite3_mprintf ("%1.15f", z);
734 	  gaiaOutClean (buf_z);
735 	  buf_m = sqlite3_mprintf ("%1.15f", m);
736 	  gaiaOutClean (buf_m);
737 	  if (iv > 0)
738 	      buf =
739 		  sqlite3_mprintf (",%s %s %s %s", buf_x, buf_y, buf_z, buf_m);
740 	  else
741 	      buf = sqlite3_mprintf ("%s %s %s %s", buf_x, buf_y, buf_z, buf_m);
742 	  sqlite3_free (buf_x);
743 	  sqlite3_free (buf_y);
744 	  sqlite3_free (buf_z);
745 	  sqlite3_free (buf_m);
746 	  gaiaAppendToOutBuffer (out_buf, buf);
747 	  sqlite3_free (buf);
748       }
749 }
750 
751 static void
gaiaOutPolygonStrict(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg,int precision)752 gaiaOutPolygonStrict (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg,
753 		      int precision)
754 {
755 /* formats a WKT POLYGON [Strict 2D] */
756     char *buf_x;
757     char *buf_y;
758     char *buf;
759     int ib;
760     int iv;
761     double x;
762     double y;
763     double z;
764     double m;
765     gaiaRingPtr ring = polyg->Exterior;
766     for (iv = 0; iv < ring->Points; iv++)
767       {
768 	  if (ring->DimensionModel == GAIA_XY_Z)
769 	    {
770 		gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
771 	    }
772 	  else if (ring->DimensionModel == GAIA_XY_M)
773 	    {
774 		gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
775 	    }
776 	  else if (ring->DimensionModel == GAIA_XY_Z_M)
777 	    {
778 		gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
779 	    }
780 	  else
781 	    {
782 		gaiaGetPoint (ring->Coords, iv, &x, &y);
783 	    }
784 	  buf_x = sqlite3_mprintf ("%.*f", precision, x);
785 	  gaiaOutClean (buf_x);
786 	  buf_y = sqlite3_mprintf ("%.*f", precision, y);
787 	  gaiaOutClean (buf_y);
788 	  if (iv == 0)
789 	      buf = sqlite3_mprintf ("(%s %s", buf_x, buf_y);
790 	  else if (iv == (ring->Points - 1))
791 	      buf = sqlite3_mprintf (",%s %s)", buf_x, buf_y);
792 	  else
793 	      buf = sqlite3_mprintf (",%s %s", buf_x, buf_y);
794 	  sqlite3_free (buf_x);
795 	  sqlite3_free (buf_y);
796 	  gaiaAppendToOutBuffer (out_buf, buf);
797 	  sqlite3_free (buf);
798       }
799     for (ib = 0; ib < polyg->NumInteriors; ib++)
800       {
801 	  ring = polyg->Interiors + ib;
802 	  for (iv = 0; iv < ring->Points; iv++)
803 	    {
804 		if (ring->DimensionModel == GAIA_XY_Z)
805 		  {
806 		      gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
807 		  }
808 		else if (ring->DimensionModel == GAIA_XY_M)
809 		  {
810 		      gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
811 		  }
812 		else if (ring->DimensionModel == GAIA_XY_Z_M)
813 		  {
814 		      gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
815 		  }
816 		else
817 		  {
818 		      gaiaGetPoint (ring->Coords, iv, &x, &y);
819 		  }
820 		buf_x = sqlite3_mprintf ("%.*f", precision, x);
821 		gaiaOutClean (buf_x);
822 		buf_y = sqlite3_mprintf ("%.*f", precision, y);
823 		gaiaOutClean (buf_y);
824 		if (iv == 0)
825 		    buf = sqlite3_mprintf (",(%s %s", buf_x, buf_y);
826 		else if (iv == (ring->Points - 1))
827 		    buf = sqlite3_mprintf (",%s %s)", buf_x, buf_y);
828 		else
829 		    buf = sqlite3_mprintf (",%s %s", buf_x, buf_y);
830 		sqlite3_free (buf_x);
831 		sqlite3_free (buf_y);
832 		gaiaAppendToOutBuffer (out_buf, buf);
833 		sqlite3_free (buf);
834 	    }
835       }
836 }
837 
838 static void
gaiaOutPolygon(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg,int precision)839 gaiaOutPolygon (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg, int precision)
840 {
841 /* formats a WKT POLYGON */
842     char *buf_x;
843     char *buf_y;
844     char *buf;
845     int ib;
846     int iv;
847     double x;
848     double y;
849     gaiaRingPtr ring = polyg->Exterior;
850     for (iv = 0; iv < ring->Points; iv++)
851       {
852 	  gaiaGetPoint (ring->Coords, iv, &x, &y);
853 	  if (precision < 0)
854 	      buf_x = sqlite3_mprintf ("%1.6f", x);
855 	  else
856 	      buf_x = sqlite3_mprintf ("%.*f", precision, x);
857 	  gaiaOutClean (buf_x);
858 	  if (precision < 0)
859 	      buf_y = sqlite3_mprintf ("%1.6f", y);
860 	  else
861 	      buf_y = sqlite3_mprintf ("%.*f", precision, y);
862 	  gaiaOutClean (buf_y);
863 	  if (iv == 0)
864 	      buf = sqlite3_mprintf ("(%s %s", buf_x, buf_y);
865 	  else if (iv == (ring->Points - 1))
866 	      buf = sqlite3_mprintf (", %s %s)", buf_x, buf_y);
867 	  else
868 	      buf = sqlite3_mprintf (", %s %s", buf_x, buf_y);
869 	  sqlite3_free (buf_x);
870 	  sqlite3_free (buf_y);
871 	  gaiaAppendToOutBuffer (out_buf, buf);
872 	  sqlite3_free (buf);
873       }
874     for (ib = 0; ib < polyg->NumInteriors; ib++)
875       {
876 	  ring = polyg->Interiors + ib;
877 	  for (iv = 0; iv < ring->Points; iv++)
878 	    {
879 		gaiaGetPoint (ring->Coords, iv, &x, &y);
880 		if (precision < 0)
881 		    buf_x = sqlite3_mprintf ("%1.6f", x);
882 		else
883 		    buf_x = sqlite3_mprintf ("%.*f", precision, x);
884 		gaiaOutClean (buf_x);
885 		if (precision < 0)
886 		    buf_y = sqlite3_mprintf ("%1.6f", y);
887 		else
888 		    buf_y = sqlite3_mprintf ("%.*f", precision, y);
889 		gaiaOutClean (buf_y);
890 		if (iv == 0)
891 		    buf = sqlite3_mprintf (", (%s %s", buf_x, buf_y);
892 		else if (iv == (ring->Points - 1))
893 		    buf = sqlite3_mprintf (", %s %s)", buf_x, buf_y);
894 		else
895 		    buf = sqlite3_mprintf (", %s %s", buf_x, buf_y);
896 		sqlite3_free (buf_x);
897 		sqlite3_free (buf_y);
898 		gaiaAppendToOutBuffer (out_buf, buf);
899 		sqlite3_free (buf);
900 	    }
901       }
902 }
903 
904 GAIAGEO_DECLARE void
gaiaOutPolygonZex(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg,int precision)905 gaiaOutPolygonZex (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg,
906 		   int precision)
907 {
908 /* formats a WKT POLYGONZ */
909     char *buf_x;
910     char *buf_y;
911     char *buf_z;
912     char *buf;
913     int ib;
914     int iv;
915     double x;
916     double y;
917     double z;
918     gaiaRingPtr ring = polyg->Exterior;
919     for (iv = 0; iv < ring->Points; iv++)
920       {
921 	  gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
922 	  if (precision < 0)
923 	      buf_x = sqlite3_mprintf ("%1.6f", x);
924 	  else
925 	      buf_x = sqlite3_mprintf ("%.*f", precision, x);
926 	  gaiaOutClean (buf_x);
927 	  if (precision < 0)
928 	      buf_y = sqlite3_mprintf ("%1.6f", y);
929 	  else
930 	      buf_y = sqlite3_mprintf ("%.*f", precision, y);
931 	  gaiaOutClean (buf_y);
932 	  if (precision < 0)
933 	      buf_z = sqlite3_mprintf ("%1.6f", z);
934 	  else
935 	      buf_z = sqlite3_mprintf ("%.*f", precision, z);
936 	  gaiaOutClean (buf_z);
937 	  if (iv == 0)
938 	      buf = sqlite3_mprintf ("(%s %s %s", buf_x, buf_y, buf_z);
939 	  else if (iv == (ring->Points - 1))
940 	      buf = sqlite3_mprintf (", %s %s %s)", buf_x, buf_y, buf_z);
941 	  else
942 	      buf = sqlite3_mprintf (", %s %s %s", buf_x, buf_y, buf_z);
943 	  sqlite3_free (buf_x);
944 	  sqlite3_free (buf_y);
945 	  sqlite3_free (buf_z);
946 	  gaiaAppendToOutBuffer (out_buf, buf);
947 	  sqlite3_free (buf);
948       }
949     for (ib = 0; ib < polyg->NumInteriors; ib++)
950       {
951 	  ring = polyg->Interiors + ib;
952 	  for (iv = 0; iv < ring->Points; iv++)
953 	    {
954 		gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
955 		if (precision < 0)
956 		    buf_x = sqlite3_mprintf ("%1.6f", x);
957 		else
958 		    buf_x = sqlite3_mprintf ("%.*f", precision, x);
959 		gaiaOutClean (buf_x);
960 		if (precision < 0)
961 		    buf_y = sqlite3_mprintf ("%1.6f", y);
962 		else
963 		    buf_y = sqlite3_mprintf ("%.*f", precision, y);
964 		gaiaOutClean (buf_y);
965 		if (precision < 0)
966 		    buf_z = sqlite3_mprintf ("%1.6f", z);
967 		else
968 		    buf_z = sqlite3_mprintf ("%.*f", precision, z);
969 		gaiaOutClean (buf_z);
970 		if (iv == 0)
971 		    buf = sqlite3_mprintf (", (%s %s %s", buf_x, buf_y, buf_z);
972 		else if (iv == (ring->Points - 1))
973 		    buf = sqlite3_mprintf (", %s %s %s)", buf_x, buf_y, buf_z);
974 		else
975 		    buf = sqlite3_mprintf (", %s %s %s", buf_x, buf_y, buf_z);
976 		sqlite3_free (buf_x);
977 		sqlite3_free (buf_y);
978 		sqlite3_free (buf_z);
979 		gaiaAppendToOutBuffer (out_buf, buf);
980 		sqlite3_free (buf);
981 	    }
982       }
983 }
984 
985 GAIAGEO_DECLARE void
gaiaOutPolygonZ(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg)986 gaiaOutPolygonZ (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg)
987 {
988 /*
989 * formats a WKT POLYGONZ
990 * convenience method - default decimal precision
991 */
992     gaiaOutPolygonZex (out_buf, polyg, -1);
993 }
994 
995 static void
gaiaOutPolygonM(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg,int precision)996 gaiaOutPolygonM (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg, int precision)
997 {
998 /* formats a WKT POLYGONM */
999     char *buf_x;
1000     char *buf_y;
1001     char *buf_m;
1002     char *buf;
1003     int ib;
1004     int iv;
1005     double x;
1006     double y;
1007     double m;
1008     gaiaRingPtr ring = polyg->Exterior;
1009     for (iv = 0; iv < ring->Points; iv++)
1010       {
1011 	  gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
1012 	  if (precision < 0)
1013 	      buf_x = sqlite3_mprintf ("%1.6f", x);
1014 	  else
1015 	      buf_x = sqlite3_mprintf ("%.*f", precision, x);
1016 	  gaiaOutClean (buf_x);
1017 	  if (precision < 0)
1018 	      buf_y = sqlite3_mprintf ("%1.6f", y);
1019 	  else
1020 	      buf_y = sqlite3_mprintf ("%.*f", precision, y);
1021 	  gaiaOutClean (buf_y);
1022 	  if (precision < 0)
1023 	      buf_m = sqlite3_mprintf ("%1.6f", m);
1024 	  else
1025 	      buf_m = sqlite3_mprintf ("%.*f", precision, m);
1026 	  gaiaOutClean (buf_m);
1027 	  if (iv == 0)
1028 	      buf = sqlite3_mprintf ("(%s %s %s", buf_x, buf_y, buf_m);
1029 	  else if (iv == (ring->Points - 1))
1030 	      buf = sqlite3_mprintf (", %s %s %s)", buf_x, buf_y, buf_m);
1031 	  else
1032 	      buf = sqlite3_mprintf (", %s %s %s", buf_x, buf_y, buf_m);
1033 	  sqlite3_free (buf_x);
1034 	  sqlite3_free (buf_y);
1035 	  sqlite3_free (buf_m);
1036 	  gaiaAppendToOutBuffer (out_buf, buf);
1037 	  sqlite3_free (buf);
1038       }
1039     for (ib = 0; ib < polyg->NumInteriors; ib++)
1040       {
1041 	  ring = polyg->Interiors + ib;
1042 	  for (iv = 0; iv < ring->Points; iv++)
1043 	    {
1044 		gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
1045 		if (precision < 0)
1046 		    buf_x = sqlite3_mprintf ("%1.6f", x);
1047 		else
1048 		    buf_x = sqlite3_mprintf ("%.*f", precision, x);
1049 		gaiaOutClean (buf_x);
1050 		if (precision < 0)
1051 		    buf_y = sqlite3_mprintf ("%1.6f", y);
1052 		else
1053 		    buf_y = sqlite3_mprintf ("%.*f", precision, y);
1054 		gaiaOutClean (buf_y);
1055 		if (precision < 0)
1056 		    buf_m = sqlite3_mprintf ("%1.6f", m);
1057 		else
1058 		    buf_m = sqlite3_mprintf ("%.*f", precision, m);
1059 		gaiaOutClean (buf_m);
1060 		if (iv == 0)
1061 		    buf = sqlite3_mprintf (", (%s %s %s", buf_x, buf_y, buf_m);
1062 		else if (iv == (ring->Points - 1))
1063 		    buf = sqlite3_mprintf (", %s %s %s)", buf_x, buf_y, buf_m);
1064 		else
1065 		    buf = sqlite3_mprintf (", %s %s %s", buf_x, buf_y, buf_m);
1066 		sqlite3_free (buf_x);
1067 		sqlite3_free (buf_y);
1068 		sqlite3_free (buf_m);
1069 		gaiaAppendToOutBuffer (out_buf, buf);
1070 		sqlite3_free (buf);
1071 	    }
1072       }
1073 }
1074 
1075 static void
gaiaOutPolygonZM(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg,int precision)1076 gaiaOutPolygonZM (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg, int precision)
1077 {
1078 /* formats a WKT POLYGONZM */
1079     char *buf_x;
1080     char *buf_y;
1081     char *buf_z;
1082     char *buf_m;
1083     char *buf;
1084     int ib;
1085     int iv;
1086     double x;
1087     double y;
1088     double z;
1089     double m;
1090     gaiaRingPtr ring = polyg->Exterior;
1091     for (iv = 0; iv < ring->Points; iv++)
1092       {
1093 	  gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
1094 	  if (precision < 0)
1095 	      buf_x = sqlite3_mprintf ("%1.6f", x);
1096 	  else
1097 	      buf_x = sqlite3_mprintf ("%.*f", precision, x);
1098 	  gaiaOutClean (buf_x);
1099 	  if (precision < 0)
1100 	      buf_y = sqlite3_mprintf ("%1.6f", y);
1101 	  else
1102 	      buf_y = sqlite3_mprintf ("%.*f", precision, y);
1103 	  gaiaOutClean (buf_y);
1104 	  if (precision < 0)
1105 	      buf_z = sqlite3_mprintf ("%1.6f", z);
1106 	  else
1107 	      buf_z = sqlite3_mprintf ("%.*f", precision, z);
1108 	  gaiaOutClean (buf_z);
1109 	  if (precision < 0)
1110 	      buf_m = sqlite3_mprintf ("%1.6f", m);
1111 	  else
1112 	      buf_m = sqlite3_mprintf ("%.*f", precision, m);
1113 	  gaiaOutClean (buf_m);
1114 	  if (iv == 0)
1115 	      buf =
1116 		  sqlite3_mprintf ("(%s %s %s %s", buf_x, buf_y, buf_z, buf_m);
1117 	  else if (iv == (ring->Points - 1))
1118 	      buf =
1119 		  sqlite3_mprintf (", %s %s %s %s)", buf_x, buf_y, buf_z,
1120 				   buf_m);
1121 	  else
1122 	      buf =
1123 		  sqlite3_mprintf (", %s %s %s %s", buf_x, buf_y, buf_z, buf_m);
1124 	  sqlite3_free (buf_x);
1125 	  sqlite3_free (buf_y);
1126 	  sqlite3_free (buf_z);
1127 	  sqlite3_free (buf_m);
1128 	  gaiaAppendToOutBuffer (out_buf, buf);
1129 	  sqlite3_free (buf);
1130       }
1131     for (ib = 0; ib < polyg->NumInteriors; ib++)
1132       {
1133 	  ring = polyg->Interiors + ib;
1134 	  for (iv = 0; iv < ring->Points; iv++)
1135 	    {
1136 		gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
1137 		if (precision < 0)
1138 		    buf_x = sqlite3_mprintf ("%1.6f", x);
1139 		else
1140 		    buf_x = sqlite3_mprintf ("%.*f", precision, x);
1141 		gaiaOutClean (buf_x);
1142 		if (precision < 0)
1143 		    buf_y = sqlite3_mprintf ("%1.6f", y);
1144 		else
1145 		    buf_y = sqlite3_mprintf ("%.*f", precision, y);
1146 		gaiaOutClean (buf_y);
1147 		if (precision < 0)
1148 		    buf_z = sqlite3_mprintf ("%1.6f", z);
1149 		else
1150 		    buf_z = sqlite3_mprintf ("%.*f", precision, z);
1151 		gaiaOutClean (buf_z);
1152 		if (precision < 0)
1153 		    buf_m = sqlite3_mprintf ("%1.6f", m);
1154 		else
1155 		    buf_m = sqlite3_mprintf ("%.*f", precision, m);
1156 		gaiaOutClean (buf_m);
1157 		if (iv == 0)
1158 		    buf =
1159 			sqlite3_mprintf (", (%s %s %s %s", buf_x, buf_y, buf_z,
1160 					 buf_m);
1161 		else if (iv == (ring->Points - 1))
1162 		    buf =
1163 			sqlite3_mprintf (", %s %s %s %s)", buf_x, buf_y, buf_z,
1164 					 buf_m);
1165 		else
1166 		    buf =
1167 			sqlite3_mprintf (", %s %s %s %s", buf_x, buf_y, buf_z,
1168 					 buf_m);
1169 		sqlite3_free (buf_x);
1170 		sqlite3_free (buf_y);
1171 		sqlite3_free (buf_z);
1172 		sqlite3_free (buf_m);
1173 		gaiaAppendToOutBuffer (out_buf, buf);
1174 		sqlite3_free (buf);
1175 	    }
1176       }
1177 }
1178 
1179 static void
gaiaOutEwktPolygon(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg)1180 gaiaOutEwktPolygon (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg)
1181 {
1182 /* formats an EWKT POLYGON */
1183     char *buf_x;
1184     char *buf_y;
1185     char *buf;
1186     int ib;
1187     int iv;
1188     double x;
1189     double y;
1190     gaiaRingPtr ring = polyg->Exterior;
1191     for (iv = 0; iv < ring->Points; iv++)
1192       {
1193 	  gaiaGetPoint (ring->Coords, iv, &x, &y);
1194 	  buf_x = sqlite3_mprintf ("%1.15f", x);
1195 	  gaiaOutClean (buf_x);
1196 	  buf_y = sqlite3_mprintf ("%1.15f", y);
1197 	  gaiaOutClean (buf_y);
1198 	  if (iv == 0)
1199 	      buf = sqlite3_mprintf ("(%s %s", buf_x, buf_y);
1200 	  else if (iv == (ring->Points - 1))
1201 	      buf = sqlite3_mprintf (",%s %s)", buf_x, buf_y);
1202 	  else
1203 	      buf = sqlite3_mprintf (",%s %s", buf_x, buf_y);
1204 	  sqlite3_free (buf_x);
1205 	  sqlite3_free (buf_y);
1206 	  gaiaAppendToOutBuffer (out_buf, buf);
1207 	  sqlite3_free (buf);
1208       }
1209     for (ib = 0; ib < polyg->NumInteriors; ib++)
1210       {
1211 	  ring = polyg->Interiors + ib;
1212 	  for (iv = 0; iv < ring->Points; iv++)
1213 	    {
1214 		gaiaGetPoint (ring->Coords, iv, &x, &y);
1215 		buf_x = sqlite3_mprintf ("%1.15f", x);
1216 		gaiaOutClean (buf_x);
1217 		buf_y = sqlite3_mprintf ("%1.15f", y);
1218 		gaiaOutClean (buf_y);
1219 		if (iv == 0)
1220 		    buf = sqlite3_mprintf (",(%s %s", buf_x, buf_y);
1221 		else if (iv == (ring->Points - 1))
1222 		    buf = sqlite3_mprintf (",%s %s)", buf_x, buf_y);
1223 		else
1224 		    buf = sqlite3_mprintf (",%s %s", buf_x, buf_y);
1225 		sqlite3_free (buf_x);
1226 		sqlite3_free (buf_y);
1227 		gaiaAppendToOutBuffer (out_buf, buf);
1228 		sqlite3_free (buf);
1229 	    }
1230       }
1231 }
1232 
1233 GAIAGEO_DECLARE void
gaiaOutEwktPolygonZ(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg)1234 gaiaOutEwktPolygonZ (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg)
1235 {
1236 /* formats an EWKT POLYGONZ */
1237     char *buf_x;
1238     char *buf_y;
1239     char *buf_z;
1240     char *buf;
1241     int ib;
1242     int iv;
1243     double x;
1244     double y;
1245     double z;
1246     gaiaRingPtr ring = polyg->Exterior;
1247     for (iv = 0; iv < ring->Points; iv++)
1248       {
1249 	  gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
1250 	  buf_x = sqlite3_mprintf ("%1.15f", x);
1251 	  gaiaOutClean (buf_x);
1252 	  buf_y = sqlite3_mprintf ("%1.15f", y);
1253 	  gaiaOutClean (buf_y);
1254 	  buf_z = sqlite3_mprintf ("%1.15f", z);
1255 	  gaiaOutClean (buf_z);
1256 	  if (iv == 0)
1257 	      buf = sqlite3_mprintf ("(%s %s %s", buf_x, buf_y, buf_z);
1258 	  else if (iv == (ring->Points - 1))
1259 	      buf = sqlite3_mprintf (",%s %s %s)", buf_x, buf_y, buf_z);
1260 	  else
1261 	      buf = sqlite3_mprintf (",%s %s %s", buf_x, buf_y, buf_z);
1262 	  sqlite3_free (buf_x);
1263 	  sqlite3_free (buf_y);
1264 	  sqlite3_free (buf_z);
1265 	  gaiaAppendToOutBuffer (out_buf, buf);
1266 	  sqlite3_free (buf);
1267       }
1268     for (ib = 0; ib < polyg->NumInteriors; ib++)
1269       {
1270 	  ring = polyg->Interiors + ib;
1271 	  for (iv = 0; iv < ring->Points; iv++)
1272 	    {
1273 		gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
1274 		buf_x = sqlite3_mprintf ("%1.15f", x);
1275 		gaiaOutClean (buf_x);
1276 		buf_y = sqlite3_mprintf ("%1.15f", y);
1277 		gaiaOutClean (buf_y);
1278 		buf_z = sqlite3_mprintf ("%1.15f", z);
1279 		gaiaOutClean (buf_z);
1280 		if (iv == 0)
1281 		    buf = sqlite3_mprintf (",(%s %s %s", buf_x, buf_y, buf_z);
1282 		else if (iv == (ring->Points - 1))
1283 		    buf = sqlite3_mprintf (",%s %s %s)", buf_x, buf_y, buf_z);
1284 		else
1285 		    buf = sqlite3_mprintf (",%s %s %s", buf_x, buf_y, buf_z);
1286 		sqlite3_free (buf_x);
1287 		sqlite3_free (buf_y);
1288 		sqlite3_free (buf_z);
1289 		gaiaAppendToOutBuffer (out_buf, buf);
1290 		sqlite3_free (buf);
1291 	    }
1292       }
1293 }
1294 
1295 static void
gaiaOutEwktPolygonM(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg)1296 gaiaOutEwktPolygonM (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg)
1297 {
1298 /* formats an EWKT POLYGONM */
1299     char *buf_x;
1300     char *buf_y;
1301     char *buf_m;
1302     char *buf;
1303     int ib;
1304     int iv;
1305     double x;
1306     double y;
1307     double m;
1308     gaiaRingPtr ring = polyg->Exterior;
1309     for (iv = 0; iv < ring->Points; iv++)
1310       {
1311 	  gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
1312 	  buf_x = sqlite3_mprintf ("%1.15f", x);
1313 	  gaiaOutClean (buf_x);
1314 	  buf_y = sqlite3_mprintf ("%1.15f", y);
1315 	  gaiaOutClean (buf_y);
1316 	  buf_m = sqlite3_mprintf ("%1.15f", m);
1317 	  gaiaOutClean (buf_m);
1318 	  if (iv == 0)
1319 	      buf = sqlite3_mprintf ("(%s %s %s", buf_x, buf_y, buf_m);
1320 	  else if (iv == (ring->Points - 1))
1321 	      buf = sqlite3_mprintf (",%s %s %s)", buf_x, buf_y, buf_m);
1322 	  else
1323 	      buf = sqlite3_mprintf (",%s %s %s", buf_x, buf_y, buf_m);
1324 	  sqlite3_free (buf_x);
1325 	  sqlite3_free (buf_y);
1326 	  sqlite3_free (buf_m);
1327 	  gaiaAppendToOutBuffer (out_buf, buf);
1328 	  sqlite3_free (buf);
1329       }
1330     for (ib = 0; ib < polyg->NumInteriors; ib++)
1331       {
1332 	  ring = polyg->Interiors + ib;
1333 	  for (iv = 0; iv < ring->Points; iv++)
1334 	    {
1335 		gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
1336 		buf_x = sqlite3_mprintf ("%1.15f", x);
1337 		gaiaOutClean (buf_x);
1338 		buf_y = sqlite3_mprintf ("%1.15f", y);
1339 		gaiaOutClean (buf_y);
1340 		buf_m = sqlite3_mprintf ("%1.15f", m);
1341 		gaiaOutClean (buf_m);
1342 		if (iv == 0)
1343 		    buf = sqlite3_mprintf (",(%s %s %s", buf_x, buf_y, buf_m);
1344 		else if (iv == (ring->Points - 1))
1345 		    buf = sqlite3_mprintf (",%s %s %s)", buf_x, buf_y, buf_m);
1346 		else
1347 		    buf = sqlite3_mprintf (",%s %s %s", buf_x, buf_y, buf_m);
1348 		sqlite3_free (buf_x);
1349 		sqlite3_free (buf_y);
1350 		sqlite3_free (buf_m);
1351 		gaiaAppendToOutBuffer (out_buf, buf);
1352 		sqlite3_free (buf);
1353 	    }
1354       }
1355 }
1356 
1357 static void
gaiaOutEwktPolygonZM(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polyg)1358 gaiaOutEwktPolygonZM (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polyg)
1359 {
1360 /* formats an EWKT POLYGONZM */
1361     char *buf_x;
1362     char *buf_y;
1363     char *buf_z;
1364     char *buf_m;
1365     char *buf;
1366     int ib;
1367     int iv;
1368     double x;
1369     double y;
1370     double z;
1371     double m;
1372     gaiaRingPtr ring = polyg->Exterior;
1373     for (iv = 0; iv < ring->Points; iv++)
1374       {
1375 	  gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
1376 	  buf_x = sqlite3_mprintf ("%1.15f", x);
1377 	  gaiaOutClean (buf_x);
1378 	  buf_y = sqlite3_mprintf ("%1.15f", y);
1379 	  gaiaOutClean (buf_y);
1380 	  buf_z = sqlite3_mprintf ("%1.15f", z);
1381 	  gaiaOutClean (buf_z);
1382 	  buf_m = sqlite3_mprintf ("%1.15f", m);
1383 	  gaiaOutClean (buf_m);
1384 	  if (iv == 0)
1385 	      buf =
1386 		  sqlite3_mprintf ("(%s %s %s %s", buf_x, buf_y, buf_z, buf_m);
1387 	  else if (iv == (ring->Points - 1))
1388 	      buf =
1389 		  sqlite3_mprintf (",%s %s %s %s)", buf_x, buf_y, buf_z, buf_m);
1390 	  else
1391 	      buf =
1392 		  sqlite3_mprintf (",%s %s %s %s", buf_x, buf_y, buf_z, buf_m);
1393 	  sqlite3_free (buf_x);
1394 	  sqlite3_free (buf_y);
1395 	  sqlite3_free (buf_z);
1396 	  sqlite3_free (buf_m);
1397 	  gaiaAppendToOutBuffer (out_buf, buf);
1398 	  sqlite3_free (buf);
1399       }
1400     for (ib = 0; ib < polyg->NumInteriors; ib++)
1401       {
1402 	  ring = polyg->Interiors + ib;
1403 	  for (iv = 0; iv < ring->Points; iv++)
1404 	    {
1405 		gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
1406 		buf_x = sqlite3_mprintf ("%1.15f", x);
1407 		gaiaOutClean (buf_x);
1408 		buf_y = sqlite3_mprintf ("%1.15f", y);
1409 		gaiaOutClean (buf_y);
1410 		buf_z = sqlite3_mprintf ("%1.15f", z);
1411 		gaiaOutClean (buf_z);
1412 		buf_m = sqlite3_mprintf ("%1.15f", m);
1413 		gaiaOutClean (buf_m);
1414 		if (iv == 0)
1415 		    buf =
1416 			sqlite3_mprintf (",(%s %s %s %s", buf_x, buf_y, buf_z,
1417 					 buf_m);
1418 		else if (iv == (ring->Points - 1))
1419 		    buf =
1420 			sqlite3_mprintf (",%s %s %s %s)", buf_x, buf_y, buf_z,
1421 					 buf_m);
1422 		else
1423 		    buf =
1424 			sqlite3_mprintf (",%s %s %s %s", buf_x, buf_y, buf_z,
1425 					 buf_m);
1426 		sqlite3_free (buf_x);
1427 		sqlite3_free (buf_y);
1428 		sqlite3_free (buf_z);
1429 		sqlite3_free (buf_m);
1430 		gaiaAppendToOutBuffer (out_buf, buf);
1431 		sqlite3_free (buf);
1432 	    }
1433       }
1434 }
1435 
1436 GAIAGEO_DECLARE void
gaiaOutWktEx(gaiaOutBufferPtr out_buf,gaiaGeomCollPtr geom,int precision)1437 gaiaOutWktEx (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom, int precision)
1438 {
1439 /* prints the WKT representation of current geometry */
1440     int pts = 0;
1441     int lns = 0;
1442     int pgs = 0;
1443     gaiaPointPtr point;
1444     gaiaLinestringPtr line;
1445     gaiaPolygonPtr polyg;
1446     if (!geom)
1447 	return;
1448     point = geom->FirstPoint;
1449     while (point)
1450       {
1451 	  /* counting how many POINTs are there */
1452 	  pts++;
1453 	  point = point->Next;
1454       }
1455     line = geom->FirstLinestring;
1456     while (line)
1457       {
1458 	  /* counting how many LINESTRINGs are there */
1459 	  lns++;
1460 	  line = line->Next;
1461       }
1462     polyg = geom->FirstPolygon;
1463     while (polyg)
1464       {
1465 	  /* counting how many POLYGONs are there */
1466 	  pgs++;
1467 	  polyg = polyg->Next;
1468       }
1469     if ((pts + lns + pgs) == 1
1470 	&& (geom->DeclaredType == GAIA_POINT
1471 	    || geom->DeclaredType == GAIA_LINESTRING
1472 	    || geom->DeclaredType == GAIA_POLYGON))
1473       {
1474 	  /* we have only one elementary geometry */
1475 	  point = geom->FirstPoint;
1476 	  while (point)
1477 	    {
1478 		if (point->DimensionModel == GAIA_XY_Z)
1479 		  {
1480 		      /* processing POINTZ */
1481 		      gaiaAppendToOutBuffer (out_buf, "POINT Z(");
1482 		      gaiaOutPointZex (out_buf, point, precision);
1483 		  }
1484 		else if (point->DimensionModel == GAIA_XY_M)
1485 		  {
1486 		      /* processing POINTM */
1487 		      gaiaAppendToOutBuffer (out_buf, "POINT M(");
1488 		      gaiaOutPointM (out_buf, point, precision);
1489 		  }
1490 		else if (point->DimensionModel == GAIA_XY_Z_M)
1491 		  {
1492 		      /* processing POINTZM */
1493 		      gaiaAppendToOutBuffer (out_buf, "POINT ZM(");
1494 		      gaiaOutPointZM (out_buf, point, precision);
1495 		  }
1496 		else
1497 		  {
1498 		      /* processing POINT */
1499 		      gaiaAppendToOutBuffer (out_buf, "POINT(");
1500 		      gaiaOutPoint (out_buf, point, precision);
1501 		  }
1502 		gaiaAppendToOutBuffer (out_buf, ")");
1503 		point = point->Next;
1504 	    }
1505 	  line = geom->FirstLinestring;
1506 	  while (line)
1507 	    {
1508 		if (line->DimensionModel == GAIA_XY_Z)
1509 		  {
1510 		      /* processing LINESTRINGZ */
1511 		      gaiaAppendToOutBuffer (out_buf, "LINESTRING Z(");
1512 		      gaiaOutLinestringZex (out_buf, line, precision);
1513 		  }
1514 		else if (line->DimensionModel == GAIA_XY_M)
1515 		  {
1516 		      /* processing LINESTRINGM */
1517 		      gaiaAppendToOutBuffer (out_buf, "LINESTRING M(");
1518 		      gaiaOutLinestringM (out_buf, line, precision);
1519 		  }
1520 		else if (line->DimensionModel == GAIA_XY_Z_M)
1521 		  {
1522 		      /* processing LINESTRINGZM */
1523 		      gaiaAppendToOutBuffer (out_buf, "LINESTRING ZM(");
1524 		      gaiaOutLinestringZM (out_buf, line, precision);
1525 		  }
1526 		else
1527 		  {
1528 		      /* processing LINESTRING */
1529 		      gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
1530 		      gaiaOutLinestring (out_buf, line, precision);
1531 		  }
1532 		gaiaAppendToOutBuffer (out_buf, ")");
1533 		line = line->Next;
1534 	    }
1535 	  polyg = geom->FirstPolygon;
1536 	  while (polyg)
1537 	    {
1538 		if (polyg->DimensionModel == GAIA_XY_Z)
1539 		  {
1540 		      /* processing POLYGONZ */
1541 		      gaiaAppendToOutBuffer (out_buf, "POLYGON Z(");
1542 		      gaiaOutPolygonZex (out_buf, polyg, precision);
1543 		  }
1544 		else if (polyg->DimensionModel == GAIA_XY_M)
1545 		  {
1546 		      /* processing POLYGONM */
1547 		      gaiaAppendToOutBuffer (out_buf, "POLYGON M(");
1548 		      gaiaOutPolygonM (out_buf, polyg, precision);
1549 		  }
1550 		else if (polyg->DimensionModel == GAIA_XY_Z_M)
1551 		  {
1552 		      /* processing POLYGONZM */
1553 		      gaiaAppendToOutBuffer (out_buf, "POLYGON ZM(");
1554 		      gaiaOutPolygonZM (out_buf, polyg, precision);
1555 		  }
1556 		else
1557 		  {
1558 		      /* processing POLYGON */
1559 		      gaiaAppendToOutBuffer (out_buf, "POLYGON(");
1560 		      gaiaOutPolygon (out_buf, polyg, precision);
1561 		  }
1562 		gaiaAppendToOutBuffer (out_buf, ")");
1563 		polyg = polyg->Next;
1564 	    }
1565       }
1566     else
1567       {
1568 	  /* we have some kind of complex geometry */
1569 	  if (pts > 0 && lns == 0 && pgs == 0
1570 	      && geom->DeclaredType == GAIA_MULTIPOINT)
1571 	    {
1572 		/* some kind of MULTIPOINT */
1573 		if (geom->DimensionModel == GAIA_XY_Z)
1574 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOINT Z(");
1575 		else if (geom->DimensionModel == GAIA_XY_M)
1576 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOINT M(");
1577 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1578 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOINT ZM(");
1579 		else
1580 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOINT(");
1581 		point = geom->FirstPoint;
1582 		while (point)
1583 		  {
1584 		      if (point->DimensionModel == GAIA_XY_Z)
1585 			{
1586 			    if (point != geom->FirstPoint)
1587 				gaiaAppendToOutBuffer (out_buf, ", ");
1588 			    gaiaOutPointZex (out_buf, point, precision);
1589 			}
1590 		      else if (point->DimensionModel == GAIA_XY_M)
1591 			{
1592 			    if (point != geom->FirstPoint)
1593 				gaiaAppendToOutBuffer (out_buf, ", ");
1594 			    gaiaOutPointM (out_buf, point, precision);
1595 			}
1596 		      else if (point->DimensionModel == GAIA_XY_Z_M)
1597 			{
1598 			    if (point != geom->FirstPoint)
1599 				gaiaAppendToOutBuffer (out_buf, ", ");
1600 			    gaiaOutPointZM (out_buf, point, precision);
1601 			}
1602 		      else
1603 			{
1604 			    if (point != geom->FirstPoint)
1605 				gaiaAppendToOutBuffer (out_buf, ", ");
1606 			    gaiaOutPoint (out_buf, point, precision);
1607 			}
1608 		      point = point->Next;
1609 		  }
1610 		gaiaAppendToOutBuffer (out_buf, ")");
1611 	    }
1612 	  else if (pts == 0 && lns > 0 && pgs == 0
1613 		   && geom->DeclaredType == GAIA_MULTILINESTRING)
1614 	    {
1615 		/* some kind of MULTILINESTRING */
1616 		if (geom->DimensionModel == GAIA_XY_Z)
1617 		    gaiaAppendToOutBuffer (out_buf, "MULTILINESTRING Z(");
1618 		else if (geom->DimensionModel == GAIA_XY_M)
1619 		    gaiaAppendToOutBuffer (out_buf, "MULTILINESTRING M(");
1620 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1621 		    gaiaAppendToOutBuffer (out_buf, "MULTILINESTRING ZM(");
1622 		else
1623 		    gaiaAppendToOutBuffer (out_buf, "MULTILINESTRING(");
1624 		line = geom->FirstLinestring;
1625 		while (line)
1626 		  {
1627 		      if (line != geom->FirstLinestring)
1628 			  gaiaAppendToOutBuffer (out_buf, ", (");
1629 		      else
1630 			  gaiaAppendToOutBuffer (out_buf, "(");
1631 		      if (line->DimensionModel == GAIA_XY_Z)
1632 			{
1633 			    gaiaOutLinestringZex (out_buf, line, precision);
1634 			    gaiaAppendToOutBuffer (out_buf, ")");
1635 			}
1636 		      else if (line->DimensionModel == GAIA_XY_M)
1637 			{
1638 			    gaiaOutLinestringM (out_buf, line, precision);
1639 			    gaiaAppendToOutBuffer (out_buf, ")");
1640 			}
1641 		      else if (line->DimensionModel == GAIA_XY_Z_M)
1642 			{
1643 			    gaiaOutLinestringZM (out_buf, line, precision);
1644 			    gaiaAppendToOutBuffer (out_buf, ")");
1645 			}
1646 		      else
1647 			{
1648 			    gaiaOutLinestring (out_buf, line, precision);
1649 			    gaiaAppendToOutBuffer (out_buf, ")");
1650 			}
1651 		      line = line->Next;
1652 		  }
1653 		gaiaAppendToOutBuffer (out_buf, ")");
1654 	    }
1655 	  else if (pts == 0 && lns == 0 && pgs > 0
1656 		   && geom->DeclaredType == GAIA_MULTIPOLYGON)
1657 	    {
1658 		/* some kind of MULTIPOLYGON */
1659 		if (geom->DimensionModel == GAIA_XY_Z)
1660 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOLYGON Z(");
1661 		else if (geom->DimensionModel == GAIA_XY_M)
1662 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOLYGON M(");
1663 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1664 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOLYGON ZM(");
1665 		else
1666 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOLYGON(");
1667 		polyg = geom->FirstPolygon;
1668 		while (polyg)
1669 		  {
1670 		      if (polyg != geom->FirstPolygon)
1671 			  gaiaAppendToOutBuffer (out_buf, ", (");
1672 		      else
1673 			  gaiaAppendToOutBuffer (out_buf, "(");
1674 		      if (polyg->DimensionModel == GAIA_XY_Z)
1675 			{
1676 			    gaiaOutPolygonZex (out_buf, polyg, precision);
1677 			    gaiaAppendToOutBuffer (out_buf, ")");
1678 			}
1679 		      else if (polyg->DimensionModel == GAIA_XY_M)
1680 			{
1681 			    gaiaOutPolygonM (out_buf, polyg, precision);
1682 			    gaiaAppendToOutBuffer (out_buf, ")");
1683 			}
1684 		      else if (polyg->DimensionModel == GAIA_XY_Z_M)
1685 			{
1686 			    gaiaOutPolygonZM (out_buf, polyg, precision);
1687 			    gaiaAppendToOutBuffer (out_buf, ")");
1688 			}
1689 		      else
1690 			{
1691 			    gaiaOutPolygon (out_buf, polyg, precision);
1692 			    gaiaAppendToOutBuffer (out_buf, ")");
1693 			}
1694 		      polyg = polyg->Next;
1695 		  }
1696 		gaiaAppendToOutBuffer (out_buf, ")");
1697 	    }
1698 	  else
1699 	    {
1700 		/* some kind of GEOMETRYCOLLECTION */
1701 		int ie = 0;
1702 		if (geom->DimensionModel == GAIA_XY_Z)
1703 		    gaiaAppendToOutBuffer (out_buf, "GEOMETRYCOLLECTION Z(");
1704 		else if (geom->DimensionModel == GAIA_XY_M)
1705 		    gaiaAppendToOutBuffer (out_buf, "GEOMETRYCOLLECTION M(");
1706 		else if (geom->DimensionModel == GAIA_XY_Z_M)
1707 		    gaiaAppendToOutBuffer (out_buf, "GEOMETRYCOLLECTION ZM(");
1708 		else
1709 		    gaiaAppendToOutBuffer (out_buf, "GEOMETRYCOLLECTION(");
1710 		point = geom->FirstPoint;
1711 		while (point)
1712 		  {
1713 		      /* processing POINTs */
1714 		      if (ie > 0)
1715 			  gaiaAppendToOutBuffer (out_buf, ", ");
1716 		      ie++;
1717 		      if (point->DimensionModel == GAIA_XY_Z)
1718 			{
1719 			    gaiaAppendToOutBuffer (out_buf, "POINT Z(");
1720 			    gaiaOutPointZex (out_buf, point, precision);
1721 			}
1722 		      else if (point->DimensionModel == GAIA_XY_M)
1723 			{
1724 			    gaiaAppendToOutBuffer (out_buf, "POINT M(");
1725 			    gaiaOutPointM (out_buf, point, precision);
1726 			}
1727 		      else if (point->DimensionModel == GAIA_XY_Z_M)
1728 			{
1729 			    gaiaAppendToOutBuffer (out_buf, "POINT ZM(");
1730 			    gaiaOutPointZM (out_buf, point, precision);
1731 			}
1732 		      else
1733 			{
1734 			    gaiaAppendToOutBuffer (out_buf, "POINT(");
1735 			    gaiaOutPoint (out_buf, point, precision);
1736 			}
1737 		      gaiaAppendToOutBuffer (out_buf, ")");
1738 		      point = point->Next;
1739 		  }
1740 		line = geom->FirstLinestring;
1741 		while (line)
1742 		  {
1743 		      /* processing LINESTRINGs */
1744 		      if (ie > 0)
1745 			  gaiaAppendToOutBuffer (out_buf, ", ");
1746 		      ie++;
1747 		      if (line->DimensionModel == GAIA_XY_Z)
1748 			{
1749 			    gaiaAppendToOutBuffer (out_buf, "LINESTRING Z(");
1750 			    gaiaOutLinestringZex (out_buf, line, precision);
1751 			}
1752 		      else if (line->DimensionModel == GAIA_XY_M)
1753 			{
1754 			    gaiaAppendToOutBuffer (out_buf, "LINESTRING M(");
1755 			    gaiaOutLinestringM (out_buf, line, precision);
1756 			}
1757 		      else if (line->DimensionModel == GAIA_XY_Z_M)
1758 			{
1759 			    gaiaAppendToOutBuffer (out_buf, "LINESTRING ZM(");
1760 			    gaiaOutLinestringZM (out_buf, line, precision);
1761 			}
1762 		      else
1763 			{
1764 			    gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
1765 			    gaiaOutLinestring (out_buf, line, precision);
1766 			}
1767 		      gaiaAppendToOutBuffer (out_buf, ")");
1768 		      line = line->Next;
1769 		  }
1770 		polyg = geom->FirstPolygon;
1771 		while (polyg)
1772 		  {
1773 		      /* processing POLYGONs */
1774 		      if (ie > 0)
1775 			  gaiaAppendToOutBuffer (out_buf, ", ");
1776 		      ie++;
1777 		      if (polyg->DimensionModel == GAIA_XY_Z)
1778 			{
1779 			    gaiaAppendToOutBuffer (out_buf, "POLYGON Z(");
1780 			    gaiaOutPolygonZex (out_buf, polyg, precision);
1781 			}
1782 		      else if (polyg->DimensionModel == GAIA_XY_M)
1783 			{
1784 			    gaiaAppendToOutBuffer (out_buf, "POLYGON M(");
1785 			    gaiaOutPolygonM (out_buf, polyg, precision);
1786 			}
1787 		      else if (polyg->DimensionModel == GAIA_XY_Z_M)
1788 			{
1789 			    gaiaAppendToOutBuffer (out_buf, "POLYGON ZM(");
1790 			    gaiaOutPolygonZM (out_buf, polyg, precision);
1791 			}
1792 		      else
1793 			{
1794 			    gaiaAppendToOutBuffer (out_buf, "POLYGON(");
1795 			    gaiaOutPolygon (out_buf, polyg, precision);
1796 			}
1797 		      gaiaAppendToOutBuffer (out_buf, ")");
1798 		      polyg = polyg->Next;
1799 		  }
1800 		gaiaAppendToOutBuffer (out_buf, ")");
1801 	    }
1802       }
1803 }
1804 
1805 GAIAGEO_DECLARE void
gaiaOutWkt(gaiaOutBufferPtr out_buf,gaiaGeomCollPtr geom)1806 gaiaOutWkt (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom)
1807 {
1808 /*
1809 * prints the WKT representation of current geometry
1810 * convenience method - default decimal precision
1811 */
1812     gaiaOutWktEx (out_buf, geom, -1);
1813 }
1814 
1815 GAIAGEO_DECLARE void
gaiaOutWktStrict(gaiaOutBufferPtr out_buf,gaiaGeomCollPtr geom,int precision)1816 gaiaOutWktStrict (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom, int precision)
1817 {
1818 /*
1819  * prints the WKT representation of current geometry
1820  * strictly conformant 2D WKT implementation
1821 */
1822     int pts = 0;
1823     int lns = 0;
1824     int pgs = 0;
1825     gaiaPointPtr point;
1826     gaiaLinestringPtr line;
1827     gaiaPolygonPtr polyg;
1828     if (precision > 18)
1829 	precision = 18;
1830     if (!geom)
1831 	return;
1832     point = geom->FirstPoint;
1833     while (point)
1834       {
1835 	  /* counting how many POINTs are there */
1836 	  pts++;
1837 	  point = point->Next;
1838       }
1839     line = geom->FirstLinestring;
1840     while (line)
1841       {
1842 	  /* counting how many LINESTRINGs are there */
1843 	  lns++;
1844 	  line = line->Next;
1845       }
1846     polyg = geom->FirstPolygon;
1847     while (polyg)
1848       {
1849 	  /* counting how many POLYGONs are there */
1850 	  pgs++;
1851 	  polyg = polyg->Next;
1852       }
1853     if ((pts + lns + pgs) == 1
1854 	&& (geom->DeclaredType == GAIA_POINT
1855 	    || geom->DeclaredType == GAIA_LINESTRING
1856 	    || geom->DeclaredType == GAIA_POLYGON))
1857       {
1858 	  /* we have only one elementary geometry */
1859 	  point = geom->FirstPoint;
1860 	  while (point)
1861 	    {
1862 		/* processing POINT */
1863 		gaiaAppendToOutBuffer (out_buf, "POINT(");
1864 		gaiaOutPointStrict (out_buf, point, precision);
1865 		gaiaAppendToOutBuffer (out_buf, ")");
1866 		point = point->Next;
1867 	    }
1868 	  line = geom->FirstLinestring;
1869 	  while (line)
1870 	    {
1871 		/* processing LINESTRING */
1872 		gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
1873 		gaiaOutLinestringStrict (out_buf, line, precision);
1874 		gaiaAppendToOutBuffer (out_buf, ")");
1875 		line = line->Next;
1876 	    }
1877 	  polyg = geom->FirstPolygon;
1878 	  while (polyg)
1879 	    {
1880 		/* processing POLYGON */
1881 		gaiaAppendToOutBuffer (out_buf, "POLYGON(");
1882 		gaiaOutPolygonStrict (out_buf, polyg, precision);
1883 		gaiaAppendToOutBuffer (out_buf, ")");
1884 		polyg = polyg->Next;
1885 	    }
1886       }
1887     else
1888       {
1889 	  /* we have some kind of complex geometry */
1890 	  if (pts > 0 && lns == 0 && pgs == 0
1891 	      && geom->DeclaredType == GAIA_MULTIPOINT)
1892 	    {
1893 		/* some kind of MULTIPOINT */
1894 		gaiaAppendToOutBuffer (out_buf, "MULTIPOINT(");
1895 		point = geom->FirstPoint;
1896 		while (point)
1897 		  {
1898 		      if (point != geom->FirstPoint)
1899 			  gaiaAppendToOutBuffer (out_buf, ",");
1900 		      gaiaOutPointStrict (out_buf, point, precision);
1901 		      point = point->Next;
1902 		  }
1903 		gaiaAppendToOutBuffer (out_buf, ")");
1904 	    }
1905 	  else if (pts == 0 && lns > 0 && pgs == 0
1906 		   && geom->DeclaredType == GAIA_MULTILINESTRING)
1907 	    {
1908 		/* some kind of MULTILINESTRING */
1909 		gaiaAppendToOutBuffer (out_buf, "MULTILINESTRING(");
1910 		line = geom->FirstLinestring;
1911 		while (line)
1912 		  {
1913 		      if (line != geom->FirstLinestring)
1914 			  gaiaAppendToOutBuffer (out_buf, ",(");
1915 		      else
1916 			  gaiaAppendToOutBuffer (out_buf, "(");
1917 		      gaiaOutLinestringStrict (out_buf, line, precision);
1918 		      gaiaAppendToOutBuffer (out_buf, ")");
1919 		      line = line->Next;
1920 		  }
1921 		gaiaAppendToOutBuffer (out_buf, ")");
1922 	    }
1923 	  else if (pts == 0 && lns == 0 && pgs > 0
1924 		   && geom->DeclaredType == GAIA_MULTIPOLYGON)
1925 	    {
1926 		/* some kind of MULTIPOLYGON */
1927 		gaiaAppendToOutBuffer (out_buf, "MULTIPOLYGON(");
1928 		polyg = geom->FirstPolygon;
1929 		while (polyg)
1930 		  {
1931 		      if (polyg != geom->FirstPolygon)
1932 			  gaiaAppendToOutBuffer (out_buf, ",(");
1933 		      else
1934 			  gaiaAppendToOutBuffer (out_buf, "(");
1935 		      gaiaOutPolygonStrict (out_buf, polyg, precision);
1936 		      gaiaAppendToOutBuffer (out_buf, ")");
1937 		      polyg = polyg->Next;
1938 		  }
1939 		gaiaAppendToOutBuffer (out_buf, ")");
1940 	    }
1941 	  else
1942 	    {
1943 		/* some kind of GEOMETRYCOLLECTION */
1944 		int ie = 0;
1945 		gaiaAppendToOutBuffer (out_buf, "GEOMETRYCOLLECTION(");
1946 		point = geom->FirstPoint;
1947 		while (point)
1948 		  {
1949 		      /* processing POINTs */
1950 		      if (ie > 0)
1951 			  gaiaAppendToOutBuffer (out_buf, ",");
1952 		      ie++;
1953 		      gaiaAppendToOutBuffer (out_buf, "POINT(");
1954 		      gaiaOutPointStrict (out_buf, point, precision);
1955 		      gaiaAppendToOutBuffer (out_buf, ")");
1956 		      point = point->Next;
1957 		  }
1958 		line = geom->FirstLinestring;
1959 		while (line)
1960 		  {
1961 		      /* processing LINESTRINGs */
1962 		      if (ie > 0)
1963 			  gaiaAppendToOutBuffer (out_buf, ",");
1964 		      ie++;
1965 		      gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
1966 		      gaiaOutLinestringStrict (out_buf, line, precision);
1967 		      gaiaAppendToOutBuffer (out_buf, ")");
1968 		      line = line->Next;
1969 		  }
1970 		polyg = geom->FirstPolygon;
1971 		while (polyg)
1972 		  {
1973 		      /* processing POLYGONs */
1974 		      if (ie > 0)
1975 			  gaiaAppendToOutBuffer (out_buf, ",");
1976 		      ie++;
1977 		      gaiaAppendToOutBuffer (out_buf, "POLYGON(");
1978 		      gaiaOutPolygonStrict (out_buf, polyg, precision);
1979 		      gaiaAppendToOutBuffer (out_buf, ")");
1980 		      polyg = polyg->Next;
1981 		  }
1982 		gaiaAppendToOutBuffer (out_buf, ")");
1983 	    }
1984       }
1985 }
1986 
1987 GAIAGEO_DECLARE void
gaiaToEWKT(gaiaOutBufferPtr out_buf,gaiaGeomCollPtr geom)1988 gaiaToEWKT (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom)
1989 {
1990 /* prints the EWKT representation of current geometry */
1991     char buf[128];
1992     int pts = 0;
1993     int lns = 0;
1994     int pgs = 0;
1995     gaiaPointPtr point;
1996     gaiaLinestringPtr line;
1997     gaiaPolygonPtr polyg;
1998     if (!geom)
1999 	return;
2000     sprintf (buf, "SRID=%d;", geom->Srid);
2001     gaiaAppendToOutBuffer (out_buf, buf);
2002     point = geom->FirstPoint;
2003     while (point)
2004       {
2005 	  /* counting how many POINTs are there */
2006 	  pts++;
2007 	  point = point->Next;
2008       }
2009     line = geom->FirstLinestring;
2010     while (line)
2011       {
2012 	  /* counting how many LINESTRINGs are there */
2013 	  lns++;
2014 	  line = line->Next;
2015       }
2016     polyg = geom->FirstPolygon;
2017     while (polyg)
2018       {
2019 	  /* counting how many POLYGONs are there */
2020 	  pgs++;
2021 	  polyg = polyg->Next;
2022       }
2023     if ((pts + lns + pgs) == 1
2024 	&& (geom->DeclaredType == GAIA_POINT
2025 	    || geom->DeclaredType == GAIA_LINESTRING
2026 	    || geom->DeclaredType == GAIA_POLYGON))
2027       {
2028 	  /* we have only one elementary geometry */
2029 	  point = geom->FirstPoint;
2030 	  while (point)
2031 	    {
2032 		if (point->DimensionModel == GAIA_XY_Z)
2033 		  {
2034 		      /* processing POINTZ */
2035 		      gaiaAppendToOutBuffer (out_buf, "POINT(");
2036 		      gaiaOutEwktPointZ (out_buf, point);
2037 		  }
2038 		else if (point->DimensionModel == GAIA_XY_M)
2039 		  {
2040 		      /* processing POINTM */
2041 		      gaiaAppendToOutBuffer (out_buf, "POINTM(");
2042 		      gaiaOutEwktPointM (out_buf, point);
2043 		  }
2044 		else if (point->DimensionModel == GAIA_XY_Z_M)
2045 		  {
2046 		      /* processing POINTZM */
2047 		      gaiaAppendToOutBuffer (out_buf, "POINT(");
2048 		      gaiaOutEwktPointZM (out_buf, point);
2049 		  }
2050 		else
2051 		  {
2052 		      /* processing POINT */
2053 		      gaiaAppendToOutBuffer (out_buf, "POINT(");
2054 		      gaiaOutEwktPoint (out_buf, point);
2055 		  }
2056 		gaiaAppendToOutBuffer (out_buf, ")");
2057 		point = point->Next;
2058 	    }
2059 	  line = geom->FirstLinestring;
2060 	  while (line)
2061 	    {
2062 		if (line->DimensionModel == GAIA_XY_Z)
2063 		  {
2064 		      /* processing LINESTRINGZ */
2065 		      gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
2066 		      gaiaOutEwktLinestringZ (out_buf, line);
2067 		  }
2068 		else if (line->DimensionModel == GAIA_XY_M)
2069 		  {
2070 		      /* processing LINESTRINGM */
2071 		      gaiaAppendToOutBuffer (out_buf, "LINESTRINGM(");
2072 		      gaiaOutEwktLinestringM (out_buf, line);
2073 		  }
2074 		else if (line->DimensionModel == GAIA_XY_Z_M)
2075 		  {
2076 		      /* processing LINESTRINGZM */
2077 		      gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
2078 		      gaiaOutEwktLinestringZM (out_buf, line);
2079 		  }
2080 		else
2081 		  {
2082 		      /* processing LINESTRING */
2083 		      gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
2084 		      gaiaOutEwktLinestring (out_buf, line);
2085 		  }
2086 		gaiaAppendToOutBuffer (out_buf, ")");
2087 		line = line->Next;
2088 	    }
2089 	  polyg = geom->FirstPolygon;
2090 	  while (polyg)
2091 	    {
2092 		if (polyg->DimensionModel == GAIA_XY_Z)
2093 		  {
2094 		      /* processing POLYGONZ */
2095 		      gaiaAppendToOutBuffer (out_buf, "POLYGON(");
2096 		      gaiaOutEwktPolygonZ (out_buf, polyg);
2097 		  }
2098 		else if (polyg->DimensionModel == GAIA_XY_M)
2099 		  {
2100 		      /* processing POLYGONM */
2101 		      gaiaAppendToOutBuffer (out_buf, "POLYGONM(");
2102 		      gaiaOutEwktPolygonM (out_buf, polyg);
2103 		  }
2104 		else if (polyg->DimensionModel == GAIA_XY_Z_M)
2105 		  {
2106 		      /* processing POLYGONZM */
2107 		      gaiaAppendToOutBuffer (out_buf, "POLYGON(");
2108 		      gaiaOutEwktPolygonZM (out_buf, polyg);
2109 		  }
2110 		else
2111 		  {
2112 		      /* processing POLYGON */
2113 		      gaiaAppendToOutBuffer (out_buf, "POLYGON(");
2114 		      gaiaOutEwktPolygon (out_buf, polyg);
2115 		  }
2116 		gaiaAppendToOutBuffer (out_buf, ")");
2117 		polyg = polyg->Next;
2118 	    }
2119       }
2120     else
2121       {
2122 	  /* we have some kind of complex geometry */
2123 	  if (pts > 0 && lns == 0 && pgs == 0
2124 	      && geom->DeclaredType == GAIA_MULTIPOINT)
2125 	    {
2126 		/* some kind of MULTIPOINT */
2127 		if (geom->DimensionModel == GAIA_XY_M)
2128 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOINTM(");
2129 		else
2130 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOINT(");
2131 		point = geom->FirstPoint;
2132 		while (point)
2133 		  {
2134 		      if (point->DimensionModel == GAIA_XY_Z)
2135 			{
2136 			    if (point != geom->FirstPoint)
2137 				gaiaAppendToOutBuffer (out_buf, ",");
2138 			    gaiaOutEwktPointZ (out_buf, point);
2139 			}
2140 		      else if (point->DimensionModel == GAIA_XY_M)
2141 			{
2142 			    if (point != geom->FirstPoint)
2143 				gaiaAppendToOutBuffer (out_buf, ",");
2144 			    gaiaOutEwktPointM (out_buf, point);
2145 			}
2146 		      else if (point->DimensionModel == GAIA_XY_Z_M)
2147 			{
2148 			    if (point != geom->FirstPoint)
2149 				gaiaAppendToOutBuffer (out_buf, ",");
2150 			    gaiaOutEwktPointZM (out_buf, point);
2151 			}
2152 		      else
2153 			{
2154 			    if (point != geom->FirstPoint)
2155 				gaiaAppendToOutBuffer (out_buf, ",");
2156 			    gaiaOutEwktPoint (out_buf, point);
2157 			}
2158 		      point = point->Next;
2159 		  }
2160 		gaiaAppendToOutBuffer (out_buf, ")");
2161 	    }
2162 	  else if (pts == 0 && lns > 0 && pgs == 0
2163 		   && geom->DeclaredType == GAIA_MULTILINESTRING)
2164 	    {
2165 		/* some kind of MULTILINESTRING */
2166 		if (geom->DimensionModel == GAIA_XY_M)
2167 		    gaiaAppendToOutBuffer (out_buf, "MULTILINESTRINGM(");
2168 		else
2169 		    gaiaAppendToOutBuffer (out_buf, "MULTILINESTRING(");
2170 		line = geom->FirstLinestring;
2171 		while (line)
2172 		  {
2173 		      if (line != geom->FirstLinestring)
2174 			  gaiaAppendToOutBuffer (out_buf, ",(");
2175 		      else
2176 			  gaiaAppendToOutBuffer (out_buf, "(");
2177 		      if (line->DimensionModel == GAIA_XY_Z)
2178 			{
2179 			    gaiaOutEwktLinestringZ (out_buf, line);
2180 			    gaiaAppendToOutBuffer (out_buf, ")");
2181 			}
2182 		      else if (line->DimensionModel == GAIA_XY_M)
2183 			{
2184 			    gaiaOutEwktLinestringM (out_buf, line);
2185 			    gaiaAppendToOutBuffer (out_buf, ")");
2186 			}
2187 		      else if (line->DimensionModel == GAIA_XY_Z_M)
2188 			{
2189 			    gaiaOutEwktLinestringZM (out_buf, line);
2190 			    gaiaAppendToOutBuffer (out_buf, ")");
2191 			}
2192 		      else
2193 			{
2194 			    gaiaOutEwktLinestring (out_buf, line);
2195 			    gaiaAppendToOutBuffer (out_buf, ")");
2196 			}
2197 		      line = line->Next;
2198 		  }
2199 		gaiaAppendToOutBuffer (out_buf, ")");
2200 	    }
2201 	  else if (pts == 0 && lns == 0 && pgs > 0
2202 		   && geom->DeclaredType == GAIA_MULTIPOLYGON)
2203 	    {
2204 		/* some kind of MULTIPOLYGON */
2205 		if (geom->DimensionModel == GAIA_XY_M)
2206 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOLYGONM(");
2207 		else
2208 		    gaiaAppendToOutBuffer (out_buf, "MULTIPOLYGON(");
2209 		polyg = geom->FirstPolygon;
2210 		while (polyg)
2211 		  {
2212 		      if (polyg != geom->FirstPolygon)
2213 			  gaiaAppendToOutBuffer (out_buf, ",(");
2214 		      else
2215 			  gaiaAppendToOutBuffer (out_buf, "(");
2216 		      if (polyg->DimensionModel == GAIA_XY_Z)
2217 			{
2218 			    gaiaOutEwktPolygonZ (out_buf, polyg);
2219 			    gaiaAppendToOutBuffer (out_buf, ")");
2220 			}
2221 		      else if (polyg->DimensionModel == GAIA_XY_M)
2222 			{
2223 			    gaiaOutEwktPolygonM (out_buf, polyg);
2224 			    gaiaAppendToOutBuffer (out_buf, ")");
2225 			}
2226 		      else if (polyg->DimensionModel == GAIA_XY_Z_M)
2227 			{
2228 			    gaiaOutEwktPolygonZM (out_buf, polyg);
2229 			    gaiaAppendToOutBuffer (out_buf, ")");
2230 			}
2231 		      else
2232 			{
2233 			    gaiaOutEwktPolygon (out_buf, polyg);
2234 			    gaiaAppendToOutBuffer (out_buf, ")");
2235 			}
2236 		      polyg = polyg->Next;
2237 		  }
2238 		gaiaAppendToOutBuffer (out_buf, ")");
2239 	    }
2240 	  else
2241 	    {
2242 		/* some kind of GEOMETRYCOLLECTION */
2243 		int ie = 0;
2244 		if (geom->DimensionModel == GAIA_XY_M)
2245 		    gaiaAppendToOutBuffer (out_buf, "GEOMETRYCOLLECTIONM(");
2246 		else
2247 		    gaiaAppendToOutBuffer (out_buf, "GEOMETRYCOLLECTION(");
2248 		point = geom->FirstPoint;
2249 		while (point)
2250 		  {
2251 		      /* processing POINTs */
2252 		      if (ie > 0)
2253 			  gaiaAppendToOutBuffer (out_buf, ",");
2254 		      ie++;
2255 		      if (point->DimensionModel == GAIA_XY_Z)
2256 			{
2257 			    gaiaAppendToOutBuffer (out_buf, "POINT(");
2258 			    gaiaOutEwktPointZ (out_buf, point);
2259 			}
2260 		      else if (point->DimensionModel == GAIA_XY_M)
2261 			{
2262 			    gaiaAppendToOutBuffer (out_buf, "POINTM(");
2263 			    gaiaOutEwktPointM (out_buf, point);
2264 			}
2265 		      else if (point->DimensionModel == GAIA_XY_Z_M)
2266 			{
2267 			    gaiaAppendToOutBuffer (out_buf, "POINT(");
2268 			    gaiaOutEwktPointZM (out_buf, point);
2269 			}
2270 		      else
2271 			{
2272 			    gaiaAppendToOutBuffer (out_buf, "POINT(");
2273 			    gaiaOutEwktPoint (out_buf, point);
2274 			}
2275 		      gaiaAppendToOutBuffer (out_buf, ")");
2276 		      point = point->Next;
2277 		  }
2278 		line = geom->FirstLinestring;
2279 		while (line)
2280 		  {
2281 		      /* processing LINESTRINGs */
2282 		      if (ie > 0)
2283 			  gaiaAppendToOutBuffer (out_buf, ",");
2284 		      ie++;
2285 		      if (line->DimensionModel == GAIA_XY_Z)
2286 			{
2287 			    gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
2288 			    gaiaOutEwktLinestringZ (out_buf, line);
2289 			}
2290 		      else if (line->DimensionModel == GAIA_XY_M)
2291 			{
2292 			    gaiaAppendToOutBuffer (out_buf, "LINESTRINGM(");
2293 			    gaiaOutEwktLinestringM (out_buf, line);
2294 			}
2295 		      else if (line->DimensionModel == GAIA_XY_Z_M)
2296 			{
2297 			    gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
2298 			    gaiaOutEwktLinestringZM (out_buf, line);
2299 			}
2300 		      else
2301 			{
2302 			    gaiaAppendToOutBuffer (out_buf, "LINESTRING(");
2303 			    gaiaOutEwktLinestring (out_buf, line);
2304 			}
2305 		      gaiaAppendToOutBuffer (out_buf, ")");
2306 		      line = line->Next;
2307 		  }
2308 		polyg = geom->FirstPolygon;
2309 		while (polyg)
2310 		  {
2311 		      /* processing POLYGONs */
2312 		      if (ie > 0)
2313 			  gaiaAppendToOutBuffer (out_buf, ",");
2314 		      ie++;
2315 		      if (polyg->DimensionModel == GAIA_XY_Z)
2316 			{
2317 			    gaiaAppendToOutBuffer (out_buf, "POLYGON(");
2318 			    gaiaOutEwktPolygonZ (out_buf, polyg);
2319 			}
2320 		      else if (polyg->DimensionModel == GAIA_XY_M)
2321 			{
2322 			    gaiaAppendToOutBuffer (out_buf, "POLYGONM(");
2323 			    gaiaOutEwktPolygonM (out_buf, polyg);
2324 			}
2325 		      else if (polyg->DimensionModel == GAIA_XY_Z_M)
2326 			{
2327 			    gaiaAppendToOutBuffer (out_buf, "POLYGON(");
2328 			    gaiaOutEwktPolygonZM (out_buf, polyg);
2329 			}
2330 		      else
2331 			{
2332 			    gaiaAppendToOutBuffer (out_buf, "POLYGON(");
2333 			    gaiaOutEwktPolygon (out_buf, polyg);
2334 			}
2335 		      gaiaAppendToOutBuffer (out_buf, ")");
2336 		      polyg = polyg->Next;
2337 		  }
2338 		gaiaAppendToOutBuffer (out_buf, ")");
2339 	    }
2340       }
2341 }
2342 
2343 /*
2344 /
2345 /  Gaia common support for SVG encoded geometries
2346 /
2347 ////////////////////////////////////////////////////////////
2348 /
2349 / Author: Klaus Foerster klaus.foerster@svg.cc
2350 / version 0.9. 2008 September 21
2351  /
2352  */
2353 
2354 static void
SvgCoords(gaiaOutBufferPtr out_buf,gaiaPointPtr point,int precision)2355 SvgCoords (gaiaOutBufferPtr out_buf, gaiaPointPtr point, int precision)
2356 {
2357 /* formats POINT as SVG-attributes x,y */
2358     char *buf_x;
2359     char *buf_y;
2360     char *buf;
2361     buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
2362     gaiaOutClean (buf_x);
2363     buf_y = sqlite3_mprintf ("%.*f", precision, point->Y * -1);
2364     gaiaOutClean (buf_y);
2365     buf = sqlite3_mprintf ("x=\"%s\" y=\"%s\"", buf_x, buf_y);
2366     sqlite3_free (buf_x);
2367     sqlite3_free (buf_y);
2368     gaiaAppendToOutBuffer (out_buf, buf);
2369     sqlite3_free (buf);
2370 }
2371 
2372 static void
SvgCircle(gaiaOutBufferPtr out_buf,gaiaPointPtr point,int precision)2373 SvgCircle (gaiaOutBufferPtr out_buf, gaiaPointPtr point, int precision)
2374 {
2375 /* formats POINT as SVG-attributes cx,cy */
2376     char *buf_x;
2377     char *buf_y;
2378     char *buf;
2379     buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
2380     gaiaOutClean (buf_x);
2381     buf_y = sqlite3_mprintf ("%.*f", precision, point->Y * -1);
2382     gaiaOutClean (buf_y);
2383     buf = sqlite3_mprintf ("cx=\"%s\" cy=\"%s\"", buf_x, buf_y);
2384     sqlite3_free (buf_x);
2385     sqlite3_free (buf_y);
2386     gaiaAppendToOutBuffer (out_buf, buf);
2387     sqlite3_free (buf);
2388 }
2389 
2390 static void
SvgPathRelative(gaiaOutBufferPtr out_buf,int dims,int points,double * coords,int precision,int closePath)2391 SvgPathRelative (gaiaOutBufferPtr out_buf, int dims, int points, double *coords,
2392 		 int precision, int closePath)
2393 {
2394 /* formats LINESTRING as SVG-path d-attribute with relative coordinate moves */
2395     char *buf_x;
2396     char *buf_y;
2397     char *buf;
2398     double x;
2399     double y;
2400     double z;
2401     double m;
2402     double lastX = 0.0;
2403     double lastY = 0.0;
2404     int iv;
2405     for (iv = 0; iv < points; iv++)
2406       {
2407 	  if (dims == GAIA_XY_Z)
2408 	    {
2409 		gaiaGetPointXYZ (coords, iv, &x, &y, &z);
2410 	    }
2411 	  else if (dims == GAIA_XY_M)
2412 	    {
2413 		gaiaGetPointXYM (coords, iv, &x, &y, &m);
2414 	    }
2415 	  else if (dims == GAIA_XY_Z_M)
2416 	    {
2417 		gaiaGetPointXYZM (coords, iv, &x, &y, &z, &m);
2418 	    }
2419 	  else
2420 	    {
2421 		gaiaGetPoint (coords, iv, &x, &y);
2422 	    }
2423 	  buf_x = sqlite3_mprintf ("%.*f", precision, x - lastX);
2424 	  gaiaOutClean (buf_x);
2425 	  buf_y = sqlite3_mprintf ("%.*f", precision, (y - lastY) * -1);
2426 	  gaiaOutClean (buf_y);
2427 	  if (iv == 0)
2428 	      buf = sqlite3_mprintf ("M %s %s l ", buf_x, buf_y);
2429 	  else
2430 	      buf = sqlite3_mprintf ("%s %s ", buf_x, buf_y);
2431 	  sqlite3_free (buf_x);
2432 	  sqlite3_free (buf_y);
2433 	  lastX = x;
2434 	  lastY = y;
2435 	  if (iv == points - 1 && closePath == 1)
2436 	      gaiaAppendToOutBuffer (out_buf, "z ");
2437 	  else
2438 	      gaiaAppendToOutBuffer (out_buf, buf);
2439 	  sqlite3_free (buf);
2440       }
2441 }
2442 
2443 static void
SvgPathAbsolute(gaiaOutBufferPtr out_buf,int dims,int points,double * coords,int precision,int closePath)2444 SvgPathAbsolute (gaiaOutBufferPtr out_buf, int dims, int points, double *coords,
2445 		 int precision, int closePath)
2446 {
2447 /* formats LINESTRING as SVG-path d-attribute with relative coordinate moves */
2448     char *buf_x;
2449     char *buf_y;
2450     char *buf;
2451     double x;
2452     double y;
2453     double z;
2454     double m;
2455     int iv;
2456     for (iv = 0; iv < points; iv++)
2457       {
2458 	  if (dims == GAIA_XY_Z)
2459 	    {
2460 		gaiaGetPointXYZ (coords, iv, &x, &y, &z);
2461 	    }
2462 	  else if (dims == GAIA_XY_M)
2463 	    {
2464 		gaiaGetPointXYM (coords, iv, &x, &y, &m);
2465 	    }
2466 	  else if (dims == GAIA_XY_Z_M)
2467 	    {
2468 		gaiaGetPointXYZM (coords, iv, &x, &y, &z, &m);
2469 	    }
2470 	  else
2471 	    {
2472 		gaiaGetPoint (coords, iv, &x, &y);
2473 	    }
2474 	  buf_x = sqlite3_mprintf ("%.*f", precision, x);
2475 	  gaiaOutClean (buf_x);
2476 	  buf_y = sqlite3_mprintf ("%.*f", precision, y * -1);
2477 	  gaiaOutClean (buf_y);
2478 	  if (iv == 0)
2479 	      buf = sqlite3_mprintf ("M %s %s L ", buf_x, buf_y);
2480 	  else
2481 	      buf = sqlite3_mprintf ("%s %s ", buf_x, buf_y);
2482 	  sqlite3_free (buf_x);
2483 	  sqlite3_free (buf_y);
2484 	  if (iv == points - 1 && closePath == 1)
2485 	      gaiaAppendToOutBuffer (out_buf, "z ");
2486 	  else
2487 	      gaiaAppendToOutBuffer (out_buf, buf);
2488 	  sqlite3_free (buf);
2489       }
2490 }
2491 
2492 GAIAGEO_DECLARE void
gaiaOutSvg(gaiaOutBufferPtr out_buf,gaiaGeomCollPtr geom,int relative,int precision)2493 gaiaOutSvg (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom, int relative,
2494 	    int precision)
2495 {
2496 /* prints the SVG representation of current geometry */
2497     int pts = 0;
2498     int lns = 0;
2499     int pgs = 0;
2500     int ib;
2501     gaiaPointPtr point;
2502     gaiaLinestringPtr line;
2503     gaiaPolygonPtr polyg;
2504     gaiaRingPtr ring;
2505     if (precision > 18)
2506 	precision = 18;
2507     if (!geom)
2508 	return;
2509     point = geom->FirstPoint;
2510     while (point)
2511       {
2512 	  /* counting how many POINTs are there */
2513 	  pts++;
2514 	  point = point->Next;
2515       }
2516     line = geom->FirstLinestring;
2517     while (line)
2518       {
2519 	  /* counting how many LINESTRINGs are there */
2520 	  lns++;
2521 	  line = line->Next;
2522       }
2523     polyg = geom->FirstPolygon;
2524     while (polyg)
2525       {
2526 	  /* counting how many POLYGONs are there */
2527 	  pgs++;
2528 	  polyg = polyg->Next;
2529       }
2530 
2531     if ((pts + lns + pgs) == 1)
2532       {
2533 	  /* we have only one elementary geometry */
2534 	  point = geom->FirstPoint;
2535 	  while (point)
2536 	    {
2537 		/* processing POINT */
2538 		if (relative == 1)
2539 		    SvgCoords (out_buf, point, precision);
2540 		else
2541 		    SvgCircle (out_buf, point, precision);
2542 		point = point->Next;
2543 	    }
2544 	  line = geom->FirstLinestring;
2545 	  while (line)
2546 	    {
2547 		/* processing LINESTRING */
2548 		if (relative == 1)
2549 		    SvgPathRelative (out_buf, line->DimensionModel,
2550 				     line->Points, line->Coords, precision, 0);
2551 		else
2552 		    SvgPathAbsolute (out_buf, line->DimensionModel,
2553 				     line->Points, line->Coords, precision, 0);
2554 		line = line->Next;
2555 	    }
2556 	  polyg = geom->FirstPolygon;
2557 	  while (polyg)
2558 	    {
2559 		/* process exterior and interior rings */
2560 		ring = polyg->Exterior;
2561 		if (relative == 1)
2562 		  {
2563 		      SvgPathRelative (out_buf, ring->DimensionModel,
2564 				       ring->Points, ring->Coords, precision,
2565 				       1);
2566 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
2567 			{
2568 			    ring = polyg->Interiors + ib;
2569 			    SvgPathRelative (out_buf, ring->DimensionModel,
2570 					     ring->Points, ring->Coords,
2571 					     precision, 1);
2572 			}
2573 		  }
2574 		else
2575 		  {
2576 		      SvgPathAbsolute (out_buf, ring->DimensionModel,
2577 				       ring->Points, ring->Coords, precision,
2578 				       1);
2579 		      for (ib = 0; ib < polyg->NumInteriors; ib++)
2580 			{
2581 			    ring = polyg->Interiors + ib;
2582 			    SvgPathAbsolute (out_buf, ring->DimensionModel,
2583 					     ring->Points, ring->Coords,
2584 					     precision, 1);
2585 			}
2586 		  }
2587 		polyg = polyg->Next;
2588 	    }
2589       }
2590     else
2591       {
2592 	  /* we have some kind of complex geometry */
2593 	  if (pts > 0 && lns == 0 && pgs == 0)
2594 	    {
2595 		/* this one is a MULTIPOINT */
2596 		point = geom->FirstPoint;
2597 		while (point)
2598 		  {
2599 		      /* processing POINTs */
2600 		      if (point != geom->FirstPoint)
2601 			  gaiaAppendToOutBuffer (out_buf, ",");
2602 		      if (relative == 1)
2603 			  SvgCoords (out_buf, point, precision);
2604 		      else
2605 			  SvgCircle (out_buf, point, precision);
2606 		      point = point->Next;
2607 		  }
2608 	    }
2609 	  else if (pts == 0 && lns > 0 && pgs == 0)
2610 	    {
2611 		/* this one is a MULTILINESTRING */
2612 		line = geom->FirstLinestring;
2613 		while (line)
2614 		  {
2615 		      /* processing LINESTRINGs */
2616 		      if (relative == 1)
2617 			  SvgPathRelative (out_buf, line->DimensionModel,
2618 					   line->Points, line->Coords,
2619 					   precision, 0);
2620 		      else
2621 			  SvgPathAbsolute (out_buf, line->DimensionModel,
2622 					   line->Points, line->Coords,
2623 					   precision, 0);
2624 		      line = line->Next;
2625 		  }
2626 	    }
2627 	  else if (pts == 0 && lns == 0 && pgs > 0)
2628 	    {
2629 		/* this one is a MULTIPOLYGON */
2630 		polyg = geom->FirstPolygon;
2631 		while (polyg)
2632 		  {
2633 		      /* processing POLYGONs */
2634 		      ring = polyg->Exterior;
2635 		      if (relative == 1)
2636 			{
2637 			    SvgPathRelative (out_buf, ring->DimensionModel,
2638 					     ring->Points, ring->Coords,
2639 					     precision, 1);
2640 			    for (ib = 0; ib < polyg->NumInteriors; ib++)
2641 			      {
2642 				  ring = polyg->Interiors + ib;
2643 				  SvgPathRelative (out_buf,
2644 						   ring->DimensionModel,
2645 						   ring->Points, ring->Coords,
2646 						   precision, 1);
2647 			      }
2648 			}
2649 		      else
2650 			{
2651 			    SvgPathAbsolute (out_buf, ring->DimensionModel,
2652 					     ring->Points, ring->Coords,
2653 					     precision, 1);
2654 			    for (ib = 0; ib < polyg->NumInteriors; ib++)
2655 			      {
2656 				  ring = polyg->Interiors + ib;
2657 				  SvgPathAbsolute (out_buf,
2658 						   ring->DimensionModel,
2659 						   ring->Points, ring->Coords,
2660 						   precision, 1);
2661 			      }
2662 			}
2663 		      polyg = polyg->Next;
2664 		  }
2665 	    }
2666 	  else
2667 	    {
2668 		/* this one is a GEOMETRYCOLLECTION */
2669 		int ie = 0;
2670 		point = geom->FirstPoint;
2671 		while (point)
2672 		  {
2673 		      /* processing POINTs */
2674 		      if (ie > 0)
2675 			{
2676 			    gaiaAppendToOutBuffer (out_buf, ";");
2677 			}
2678 		      ie++;
2679 		      if (relative == 1)
2680 			  SvgCoords (out_buf, point, precision);
2681 		      else
2682 			  SvgCircle (out_buf, point, precision);
2683 		      point = point->Next;
2684 		  }
2685 		line = geom->FirstLinestring;
2686 		while (line)
2687 		  {
2688 		      /* processing LINESTRINGs */
2689 		      if (ie > 0)
2690 			  gaiaAppendToOutBuffer (out_buf, ";");
2691 		      ie++;
2692 		      if (relative == 1)
2693 			  SvgPathRelative (out_buf, line->DimensionModel,
2694 					   line->Points, line->Coords,
2695 					   precision, 0);
2696 		      else
2697 			  SvgPathAbsolute (out_buf, line->DimensionModel,
2698 					   line->Points, line->Coords,
2699 					   precision, 0);
2700 		      line = line->Next;
2701 		  }
2702 		polyg = geom->FirstPolygon;
2703 		while (polyg)
2704 		  {
2705 		      /* processing POLYGONs */
2706 		      ie++;
2707 		      /* process exterior and interior rings */
2708 		      ring = polyg->Exterior;
2709 		      if (relative == 1)
2710 			{
2711 			    SvgPathRelative (out_buf, ring->DimensionModel,
2712 					     ring->Points, ring->Coords,
2713 					     precision, 1);
2714 			    for (ib = 0; ib < polyg->NumInteriors; ib++)
2715 			      {
2716 				  ring = polyg->Interiors + ib;
2717 				  SvgPathRelative (out_buf,
2718 						   ring->DimensionModel,
2719 						   ring->Points, ring->Coords,
2720 						   precision, 1);
2721 			      }
2722 			}
2723 		      else
2724 			{
2725 			    SvgPathAbsolute (out_buf, ring->DimensionModel,
2726 					     ring->Points, ring->Coords,
2727 					     precision, 1);
2728 			    for (ib = 0; ib < polyg->NumInteriors; ib++)
2729 			      {
2730 				  ring = polyg->Interiors + ib;
2731 				  SvgPathAbsolute (out_buf,
2732 						   ring->DimensionModel,
2733 						   ring->Points, ring->Coords,
2734 						   precision, 1);
2735 			      }
2736 			}
2737 		      polyg = polyg->Next;
2738 		  }
2739 	    }
2740       }
2741 
2742     if (out_buf->Error == 0 && out_buf->WriteOffset > 0)
2743       {
2744 	  /* sandro 2012-02-23 cleaning extra trailing spaces */
2745 	  int i;
2746 	  for (i = out_buf->WriteOffset - 1; i >= 0; i--)
2747 	    {
2748 		if (*(out_buf->Buffer + i) == ' ')
2749 		  {
2750 		      *(out_buf->Buffer + i) = '\0';
2751 		      out_buf->WriteOffset -= 1;
2752 		  }
2753 		else
2754 		    break;
2755 	    }
2756       }
2757 }
2758 
2759 /* END of Klaus Foerster SVG implementation */
2760 
2761 
2762 static char *
XmlClean(const char * string)2763 XmlClean (const char *string)
2764 {
2765 /* well formatting a text string for XML */
2766     int ind;
2767     char *clean;
2768     char *p_out;
2769     int len = strlen (string);
2770     clean = malloc (len * 3);
2771     if (!clean)
2772 	return NULL;
2773     p_out = clean;
2774     for (ind = 0; ind < len; ind++)
2775       {
2776 	  /* masking XML special chars */
2777 	  switch (string[ind])
2778 	    {
2779 	    case '&':
2780 		*p_out++ = '&';
2781 		*p_out++ = 'a';
2782 		*p_out++ = 'm';
2783 		*p_out++ = 'p';
2784 		*p_out++ = ';';
2785 		break;
2786 	    case '<':
2787 		*p_out++ = '&';
2788 		*p_out++ = 'l';
2789 		*p_out++ = 't';
2790 		*p_out++ = ';';
2791 		break;
2792 	    case '>':
2793 		*p_out++ = '&';
2794 		*p_out++ = 'g';
2795 		*p_out++ = 't';
2796 		*p_out++ = ';';
2797 		break;
2798 	    case '"':
2799 		*p_out++ = '&';
2800 		*p_out++ = 'q';
2801 		*p_out++ = 'u';
2802 		*p_out++ = 'o';
2803 		*p_out++ = 't';
2804 		*p_out++ = ';';
2805 		break;
2806 	    default:
2807 		*p_out++ = string[ind];
2808 		break;
2809 	    };
2810       }
2811     *p_out = '\0';
2812     return clean;
2813 }
2814 
2815 static void
out_kml_point(gaiaOutBufferPtr out_buf,gaiaPointPtr point,int precision)2816 out_kml_point (gaiaOutBufferPtr out_buf, gaiaPointPtr point, int precision)
2817 {
2818 /* formats POINT as KML [x,y] */
2819     char *buf_x = NULL;
2820     char *buf_y = NULL;
2821     char *buf_z = NULL;
2822     char *buf = NULL;
2823     buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
2824     gaiaOutClean (buf_x);
2825     buf_y = sqlite3_mprintf ("%.*f", precision, point->Y);
2826     gaiaOutClean (buf_y);
2827     if (point->DimensionModel == GAIA_XY_Z
2828 	|| point->DimensionModel == GAIA_XY_Z_M)
2829       {
2830 	  buf_z = sqlite3_mprintf ("%.*f", precision, point->Z);
2831 	  gaiaOutClean (buf_z);
2832       }
2833     gaiaAppendToOutBuffer (out_buf, "<Point><coordinates>");
2834     if (point->DimensionModel == GAIA_XY_Z
2835 	|| point->DimensionModel == GAIA_XY_Z_M)
2836       {
2837 	  buf = sqlite3_mprintf ("%s,%s,%s", buf_x, buf_y, buf_z);
2838 	  sqlite3_free (buf_z);
2839       }
2840     else
2841 	buf = sqlite3_mprintf ("%s,%s", buf_x, buf_y);
2842     sqlite3_free (buf_x);
2843     sqlite3_free (buf_y);
2844     gaiaAppendToOutBuffer (out_buf, buf);
2845     sqlite3_free (buf);
2846     gaiaAppendToOutBuffer (out_buf, "</coordinates></Point>");
2847 }
2848 
2849 static void
out_kml_linestring(gaiaOutBuffer * out_buf,int dims,int points,double * coords,int precision)2850 out_kml_linestring (gaiaOutBuffer * out_buf, int dims, int points,
2851 		    double *coords, int precision)
2852 {
2853 /* formats LINESTRING as KML [x,y] */
2854     char *buf_x = NULL;
2855     char *buf_y = NULL;
2856     char *buf_z = NULL;
2857     char *buf = NULL;
2858     int iv;
2859     double x = 0.0;
2860     double y = 0.0;
2861     double z = 0.0;
2862     double m = 0.0;
2863     gaiaAppendToOutBuffer (out_buf, "<LineString><coordinates>");
2864     for (iv = 0; iv < points; iv++)
2865       {
2866 	  /* exporting vertices */
2867 	  if (dims == GAIA_XY_Z)
2868 	    {
2869 		gaiaGetPointXYZ (coords, iv, &x, &y, &z);
2870 	    }
2871 	  else if (dims == GAIA_XY_M)
2872 	    {
2873 		gaiaGetPointXYM (coords, iv, &x, &y, &m);
2874 	    }
2875 	  else if (dims == GAIA_XY_Z_M)
2876 	    {
2877 		gaiaGetPointXYZM (coords, iv, &x, &y, &z, &m);
2878 	    }
2879 	  else
2880 	    {
2881 		gaiaGetPoint (coords, iv, &x, &y);
2882 	    }
2883 	  buf_x = sqlite3_mprintf ("%.*f", precision, x);
2884 	  gaiaOutClean (buf_x);
2885 	  buf_y = sqlite3_mprintf ("%.*f", precision, y);
2886 	  gaiaOutClean (buf_y);
2887 	  if (dims == GAIA_XY_Z || dims == GAIA_XY_Z_M)
2888 	    {
2889 		buf_z = sqlite3_mprintf ("%.*f", precision, z);
2890 		gaiaOutClean (buf_z);
2891 		if (iv == 0)
2892 		    buf = sqlite3_mprintf ("%s,%s,%s", buf_x, buf_y, buf_z);
2893 		else
2894 		    buf = sqlite3_mprintf (" %s,%s,%s", buf_x, buf_y, buf_z);
2895 		sqlite3_free (buf_z);
2896 	    }
2897 	  else
2898 	    {
2899 		if (iv == 0)
2900 		    buf = sqlite3_mprintf ("%s,%s", buf_x, buf_y);
2901 		else
2902 		    buf = sqlite3_mprintf (" %s,%s", buf_x, buf_y);
2903 	    }
2904 	  sqlite3_free (buf_x);
2905 	  sqlite3_free (buf_y);
2906 	  gaiaAppendToOutBuffer (out_buf, buf);
2907 	  sqlite3_free (buf);
2908       }
2909     gaiaAppendToOutBuffer (out_buf, "</coordinates></LineString>");
2910 }
2911 
2912 static void
out_kml_polygon(gaiaOutBufferPtr out_buf,gaiaPolygonPtr polygon,int precision)2913 out_kml_polygon (gaiaOutBufferPtr out_buf, gaiaPolygonPtr polygon,
2914 		 int precision)
2915 {
2916 /* formats POLYGON as KML [x,y] */
2917     char *buf_x = NULL;
2918     char *buf_y = NULL;
2919     char *buf_z = NULL;
2920     char *buf = NULL;
2921     gaiaRingPtr ring;
2922     int iv;
2923     int ib;
2924     double x = 0.0;
2925     double y = 0.0;
2926     double z = 0.0;
2927     double m = 0.0;
2928     gaiaAppendToOutBuffer (out_buf, "<Polygon>");
2929     gaiaAppendToOutBuffer (out_buf,
2930 			   "<outerBoundaryIs><LinearRing><coordinates>");
2931     ring = polygon->Exterior;
2932     for (iv = 0; iv < ring->Points; iv++)
2933       {
2934 	  /* exporting vertices [Exterior Ring] */
2935 	  if (ring->DimensionModel == GAIA_XY_Z)
2936 	    {
2937 		gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
2938 	    }
2939 	  else if (ring->DimensionModel == GAIA_XY_M)
2940 	    {
2941 		gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
2942 	    }
2943 	  else if (ring->DimensionModel == GAIA_XY_Z_M)
2944 	    {
2945 		gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
2946 	    }
2947 	  else
2948 	    {
2949 		gaiaGetPoint (ring->Coords, iv, &x, &y);
2950 	    }
2951 	  buf_x = sqlite3_mprintf ("%.*f", precision, x);
2952 	  gaiaOutClean (buf_x);
2953 	  buf_y = sqlite3_mprintf ("%.*f", precision, y);
2954 	  gaiaOutClean (buf_y);
2955 	  if (ring->DimensionModel == GAIA_XY_Z
2956 	      || ring->DimensionModel == GAIA_XY_Z_M)
2957 	    {
2958 		buf_z = sqlite3_mprintf ("%.*f", precision, z);
2959 		gaiaOutClean (buf_z);
2960 		if (iv == 0)
2961 		    buf = sqlite3_mprintf ("%s,%s,%s", buf_x, buf_y, buf_z);
2962 		else
2963 		    buf = sqlite3_mprintf (" %s,%s,%s", buf_x, buf_y, buf_z);
2964 		sqlite3_free (buf_z);
2965 	    }
2966 	  else
2967 	    {
2968 		if (iv == 0)
2969 		    buf = sqlite3_mprintf ("%s,%s", buf_x, buf_y);
2970 		else
2971 		    buf = sqlite3_mprintf (" %s,%s", buf_x, buf_y);
2972 	    }
2973 	  sqlite3_free (buf_x);
2974 	  sqlite3_free (buf_y);
2975 	  gaiaAppendToOutBuffer (out_buf, buf);
2976 	  sqlite3_free (buf);
2977       }
2978     gaiaAppendToOutBuffer (out_buf,
2979 			   "</coordinates></LinearRing></outerBoundaryIs>");
2980     for (ib = 0; ib < polygon->NumInteriors; ib++)
2981       {
2982 	  /* interior rings */
2983 	  ring = polygon->Interiors + ib;
2984 	  gaiaAppendToOutBuffer (out_buf,
2985 				 "<innerBoundaryIs><LinearRing><coordinates>");
2986 	  for (iv = 0; iv < ring->Points; iv++)
2987 	    {
2988 		/* exporting vertices [Interior Ring] */
2989 		if (ring->DimensionModel == GAIA_XY_Z)
2990 		  {
2991 		      gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
2992 		  }
2993 		else if (ring->DimensionModel == GAIA_XY_M)
2994 		  {
2995 		      gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
2996 		  }
2997 		else if (ring->DimensionModel == GAIA_XY_Z_M)
2998 		  {
2999 		      gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
3000 		  }
3001 		else
3002 		  {
3003 		      gaiaGetPoint (ring->Coords, iv, &x, &y);
3004 		  }
3005 		buf_x = sqlite3_mprintf ("%.*f", precision, x);
3006 		gaiaOutClean (buf_x);
3007 		buf_y = sqlite3_mprintf ("%.*f", precision, y);
3008 		gaiaOutClean (buf_y);
3009 		if (ring->DimensionModel == GAIA_XY_Z
3010 		    || ring->DimensionModel == GAIA_XY_Z_M)
3011 		  {
3012 		      buf_z = sqlite3_mprintf ("%.*f", precision, z);
3013 		      gaiaOutClean (buf_z);
3014 		      if (iv == 0)
3015 			  buf =
3016 			      sqlite3_mprintf ("%s,%s,%s", buf_x, buf_y, buf_z);
3017 		      else
3018 			  buf =
3019 			      sqlite3_mprintf (" %s,%s,%s", buf_x, buf_y,
3020 					       buf_z);
3021 		      sqlite3_free (buf_z);
3022 		  }
3023 		else
3024 		  {
3025 		      if (iv == 0)
3026 			  buf = sqlite3_mprintf ("%s,%s", buf_x, buf_y);
3027 		      else
3028 			  buf = sqlite3_mprintf (" %s,%s", buf_x, buf_y);
3029 		  }
3030 		sqlite3_free (buf_x);
3031 		sqlite3_free (buf_y);
3032 		gaiaAppendToOutBuffer (out_buf, buf);
3033 		sqlite3_free (buf);
3034 	    }
3035 	  gaiaAppendToOutBuffer (out_buf,
3036 				 "</coordinates></LinearRing></innerBoundaryIs>");
3037       }
3038     gaiaAppendToOutBuffer (out_buf, "</Polygon>");
3039 }
3040 
3041 GAIAGEO_DECLARE void
gaiaOutFullKml(gaiaOutBufferPtr out_buf,const char * name,const char * desc,gaiaGeomCollPtr geom,int precision)3042 gaiaOutFullKml (gaiaOutBufferPtr out_buf, const char *name, const char *desc,
3043 		gaiaGeomCollPtr geom, int precision)
3044 {
3045 /* prints the 'full' KML representation of current geometry */
3046     gaiaPointPtr point;
3047     gaiaLinestringPtr line;
3048     gaiaPolygonPtr polyg;
3049     int count = 0;
3050     char *xml_clean;
3051     if (!geom)
3052 	return;
3053     if (precision > 18)
3054 	precision = 18;
3055 
3056 /* counting how many elementary geometries are there */
3057     point = geom->FirstPoint;
3058     while (point)
3059       {
3060 	  count++;
3061 	  point = point->Next;
3062       }
3063     line = geom->FirstLinestring;
3064     while (line)
3065       {
3066 	  count++;
3067 	  line = line->Next;
3068       }
3069     polyg = geom->FirstPolygon;
3070     while (polyg)
3071       {
3072 	  count++;
3073 	  polyg = polyg->Next;
3074       }
3075     if (count == 1)
3076       {
3077 	  if (geom->DeclaredType == GAIA_MULTIPOINT ||
3078 	      geom->DeclaredType == GAIA_MULTILINESTRING ||
3079 	      geom->DeclaredType == GAIA_MULTIPOLYGON ||
3080 	      geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3081 	      count = 2;
3082       }
3083 
3084     gaiaAppendToOutBuffer (out_buf, "<Placemark><name>");
3085     xml_clean = XmlClean (name);
3086     if (xml_clean)
3087       {
3088 	  gaiaAppendToOutBuffer (out_buf, xml_clean);
3089 	  free (xml_clean);
3090       }
3091     else
3092 	gaiaAppendToOutBuffer (out_buf, " ");
3093     gaiaAppendToOutBuffer (out_buf, "</name><description>");
3094     xml_clean = XmlClean (desc);
3095     if (xml_clean)
3096       {
3097 	  gaiaAppendToOutBuffer (out_buf, xml_clean);
3098 	  free (xml_clean);
3099       }
3100     else
3101 	gaiaAppendToOutBuffer (out_buf, " ");
3102     gaiaAppendToOutBuffer (out_buf, "</description>");
3103 
3104     if (count > 1)
3105       {
3106 	  /* MultiGeometry start */
3107 	  gaiaAppendToOutBuffer (out_buf, "<MultiGeometry>");
3108       }
3109 
3110     point = geom->FirstPoint;
3111     while (point)
3112       {
3113 	  /* processing POINT */
3114 	  out_kml_point (out_buf, point, precision);
3115 	  point = point->Next;
3116       }
3117     line = geom->FirstLinestring;
3118     while (line)
3119       {
3120 	  /* processing LINESTRING */
3121 	  out_kml_linestring (out_buf, line->DimensionModel,
3122 			      line->Points, line->Coords, precision);
3123 	  line = line->Next;
3124       }
3125     polyg = geom->FirstPolygon;
3126     while (polyg)
3127       {
3128 	  /* processing POLYGON */
3129 	  out_kml_polygon (out_buf, polyg, precision);
3130 	  polyg = polyg->Next;
3131       }
3132 
3133     if (count > 1)
3134       {
3135 	  /* MultiGeometry end */
3136 	  gaiaAppendToOutBuffer (out_buf, "</MultiGeometry>");
3137       }
3138     gaiaAppendToOutBuffer (out_buf, "</Placemark>");
3139 }
3140 
3141 GAIAGEO_DECLARE void
gaiaOutBareKml(gaiaOutBufferPtr out_buf,gaiaGeomCollPtr geom,int precision)3142 gaiaOutBareKml (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom, int precision)
3143 {
3144 /* prints the 'bare' KML representation of current geometry */
3145     gaiaPointPtr point;
3146     gaiaLinestringPtr line;
3147     gaiaPolygonPtr polyg;
3148     int count = 0;
3149     if (!geom)
3150 	return;
3151     if (precision > 18)
3152 	precision = 18;
3153 
3154 /* counting how many elementary geometries are there */
3155     point = geom->FirstPoint;
3156     while (point)
3157       {
3158 	  count++;
3159 	  point = point->Next;
3160       }
3161     line = geom->FirstLinestring;
3162     while (line)
3163       {
3164 	  count++;
3165 	  line = line->Next;
3166       }
3167     polyg = geom->FirstPolygon;
3168     while (polyg)
3169       {
3170 	  count++;
3171 	  polyg = polyg->Next;
3172       }
3173     if (count == 1)
3174       {
3175 	  if (geom->DeclaredType == GAIA_MULTIPOINT ||
3176 	      geom->DeclaredType == GAIA_MULTILINESTRING ||
3177 	      geom->DeclaredType == GAIA_MULTIPOLYGON ||
3178 	      geom->DeclaredType == GAIA_GEOMETRYCOLLECTION)
3179 	      count = 2;
3180       }
3181 
3182     if (count > 1)
3183       {
3184 	  /* MultiGeometry start */
3185 	  gaiaAppendToOutBuffer (out_buf, "<MultiGeometry>");
3186       }
3187 
3188     point = geom->FirstPoint;
3189     while (point)
3190       {
3191 	  /* processing POINT */
3192 	  out_kml_point (out_buf, point, precision);
3193 	  point = point->Next;
3194       }
3195     line = geom->FirstLinestring;
3196     while (line)
3197       {
3198 	  /* processing LINESTRING */
3199 	  out_kml_linestring (out_buf, line->DimensionModel, line->Points,
3200 			      line->Coords, precision);
3201 	  line = line->Next;
3202       }
3203     polyg = geom->FirstPolygon;
3204     while (polyg)
3205       {
3206 	  /* processing POLYGON */
3207 	  out_kml_polygon (out_buf, polyg, precision);
3208 	  polyg = polyg->Next;
3209       }
3210 
3211     if (count > 1)
3212       {
3213 	  /* MultiGeometry end */
3214 	  gaiaAppendToOutBuffer (out_buf, "</MultiGeometry>");
3215       }
3216 }
3217 
3218 GAIAGEO_DECLARE void
gaiaOutGml(gaiaOutBufferPtr out_buf,int version,int precision,gaiaGeomCollPtr geom)3219 gaiaOutGml (gaiaOutBufferPtr out_buf, int version, int precision,
3220 	    gaiaGeomCollPtr geom)
3221 {
3222 /*
3223 / prints the GML representation of current geometry
3224 / *result* returns the encoded GML or NULL if any error is encountered
3225 */
3226     gaiaPointPtr point;
3227     gaiaLinestringPtr line;
3228     gaiaPolygonPtr polyg;
3229     gaiaRingPtr ring;
3230     int iv;
3231     int ib;
3232     double x;
3233     double y;
3234     double z;
3235     double m;
3236     int has_z;
3237     int is_multi = 1;
3238     int is_coll = 0;
3239     char buf[2048];
3240     char *xbuf;
3241     char *buf_x;
3242     char *buf_y;
3243     char *buf_z;
3244     if (!geom)
3245 	return;
3246     if (precision > 18)
3247 	precision = 18;
3248 
3249     switch (geom->DeclaredType)
3250       {
3251       case GAIA_POINT:
3252       case GAIA_LINESTRING:
3253       case GAIA_POLYGON:
3254 	  *buf = '\0';
3255 	  is_multi = 0;
3256 	  break;
3257       case GAIA_MULTIPOINT:
3258 	  if (geom->Srid <= 0)
3259 	      strcpy (buf, "<gml:MultiPoint>");
3260 	  else
3261 	      sprintf (buf, "<gml:MultiPoint srsName=\"EPSG:%d\">", geom->Srid);
3262 	  break;
3263       case GAIA_MULTILINESTRING:
3264 	  if (version == 3)
3265 	    {
3266 		if (geom->Srid <= 0)
3267 		    strcpy (buf, "<gml:MultiCurve>");
3268 		else
3269 		    sprintf (buf, "<gml:MultiCurve srsName=\"EPSG:%d\">",
3270 			     geom->Srid);
3271 	    }
3272 	  else
3273 	    {
3274 		if (geom->Srid <= 0)
3275 		    strcpy (buf, "<gml:MultiLineString>");
3276 		else
3277 		    sprintf (buf,
3278 			     "<gml:MultiLineString srsName=\"EPSG:%d\">",
3279 			     geom->Srid);
3280 	    }
3281 	  break;
3282       case GAIA_MULTIPOLYGON:
3283 	  if (version == 3)
3284 	    {
3285 		if (geom->Srid <= 0)
3286 		    strcpy (buf, "<gml:MultiSurface>");
3287 		else
3288 		    sprintf (buf, "<gml:MultiSurface srsName=\"EPSG:%d\">",
3289 			     geom->Srid);
3290 	    }
3291 	  else
3292 	    {
3293 		if (geom->Srid <= 0)
3294 		    strcpy (buf, "<gml:MultiPolygon>");
3295 		else
3296 		    sprintf (buf, "<gml:MultiPolygon srsName=\"EPSG:%d\">",
3297 			     geom->Srid);
3298 	    }
3299 	  break;
3300       default:
3301 	  if (geom->Srid <= 0)
3302 	      strcpy (buf, "<gml:MultiGeometry>");
3303 	  else
3304 	      sprintf (buf, "<gml:MultiGeometry srsName=\"EPSG:%d\">",
3305 		       geom->Srid);
3306 	  is_coll = 1;
3307 	  break;
3308       };
3309     gaiaAppendToOutBuffer (out_buf, buf);
3310     point = geom->FirstPoint;
3311     while (point)
3312       {
3313 	  /* processing POINT */
3314 	  if (is_multi)
3315 	    {
3316 		if (is_coll)
3317 		    strcpy (buf, "<gml:geometryMember>");
3318 		else
3319 		    strcpy (buf, "<gml:pointMember>");
3320 		strcat (buf, "<gml:Point>");
3321 	    }
3322 	  else
3323 	    {
3324 		if (geom->Srid <= 0)
3325 		    strcpy (buf, "<gml:Point>");
3326 		else
3327 		    sprintf (buf, "<gml:Point srsName=\"EPSG:%d\">",
3328 			     geom->Srid);
3329 	    }
3330 	  if (version == 3)
3331 	    {
3332 		if (point->DimensionModel == GAIA_XY_Z
3333 		    || point->DimensionModel == GAIA_XY_Z_M)
3334 		    strcat (buf, "<gml:pos srsDimension=\"3\">");
3335 		else
3336 		    strcat (buf, "<gml:pos srsDimension=\"2\">");
3337 	    }
3338 	  else
3339 	      strcat (buf, "<gml:coordinates>");
3340 	  gaiaAppendToOutBuffer (out_buf, buf);
3341 	  buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
3342 	  gaiaOutClean (buf_x);
3343 	  buf_y = sqlite3_mprintf ("%.*f", precision, point->Y);
3344 	  gaiaOutClean (buf_y);
3345 	  if (point->DimensionModel == GAIA_XY_Z
3346 	      || point->DimensionModel == GAIA_XY_Z_M)
3347 	    {
3348 		buf_z = sqlite3_mprintf ("%.*f", precision, point->Z);
3349 		gaiaOutClean (buf_z);
3350 		if (version == 3)
3351 		  {
3352 		      xbuf = sqlite3_mprintf ("%s %s %s", buf_x, buf_y, buf_z);
3353 		      sqlite3_free (buf_x);
3354 		      sqlite3_free (buf_y);
3355 		      sqlite3_free (buf_z);
3356 		  }
3357 		else
3358 		  {
3359 		      xbuf = sqlite3_mprintf ("%s,%s,%s", buf_x, buf_y, buf_z);
3360 		      sqlite3_free (buf_x);
3361 		      sqlite3_free (buf_y);
3362 		      sqlite3_free (buf_z);
3363 		  }
3364 	    }
3365 	  else
3366 	    {
3367 		if (version == 3)
3368 		  {
3369 		      xbuf = sqlite3_mprintf ("%s %s", buf_x, buf_y);
3370 		      sqlite3_free (buf_x);
3371 		      sqlite3_free (buf_y);
3372 		  }
3373 		else
3374 		  {
3375 		      xbuf = sqlite3_mprintf ("%s,%s", buf_x, buf_y);
3376 		      sqlite3_free (buf_x);
3377 		      sqlite3_free (buf_y);
3378 		  }
3379 	    }
3380 	  gaiaAppendToOutBuffer (out_buf, xbuf);
3381 	  sqlite3_free (xbuf);
3382 	  if (version == 3)
3383 	      strcpy (buf, "</gml:pos>");
3384 	  else
3385 	      strcpy (buf, "</gml:coordinates>");
3386 	  if (is_multi)
3387 	    {
3388 		strcat (buf, "</gml:Point>");
3389 		if (is_coll)
3390 		    strcat (buf, "</gml:geometryMember>");
3391 		else
3392 		    strcat (buf, "</gml:pointMember>");
3393 	    }
3394 	  else
3395 	      strcat (buf, "</gml:Point>");
3396 	  gaiaAppendToOutBuffer (out_buf, buf);
3397 	  point = point->Next;
3398       }
3399     line = geom->FirstLinestring;
3400     while (line)
3401       {
3402 	  /* processing LINESTRING */
3403 	  if (is_multi)
3404 	    {
3405 		if (version == 3)
3406 		  {
3407 		      if (is_coll)
3408 			  strcpy (buf, "<gml:geometryMember>");
3409 		      else
3410 			  strcpy (buf, "<gml:curveMember>");
3411 		      strcat (buf, "<gml:Curve>");
3412 		      strcat (buf, "<gml:segments>");
3413 		      strcat (buf, "<gml:LineStringSegment>");
3414 		      if (line->DimensionModel == GAIA_XY_Z
3415 			  || line->DimensionModel == GAIA_XY_Z_M)
3416 			  strcat (buf, "<gml:posList srsDimension=\"3\">");
3417 		      else
3418 			  strcat (buf, "<gml:posList srsDimension=\"2\">");
3419 		  }
3420 		else
3421 		  {
3422 		      if (is_coll)
3423 			  strcpy (buf, "<gml:geometryMember>");
3424 		      else
3425 			  strcpy (buf, "<gml:lineStringMember>");
3426 		      strcat (buf, "<gml:LineString>");
3427 		      strcat (buf, "<gml:coordinates>");
3428 		  }
3429 	    }
3430 	  else
3431 	    {
3432 		if (version == 3)
3433 		  {
3434 		      if (geom->Srid <= 0)
3435 			  strcpy (buf, "<gml:Curve>");
3436 		      else
3437 			  sprintf (buf, "<gml:Curve srsName=\"EPSG:%d\">",
3438 				   geom->Srid);
3439 		      strcat (buf, "<gml:segments>");
3440 		      strcat (buf, "<gml:LineStringSegment>");
3441 		      if (line->DimensionModel == GAIA_XY_Z
3442 			  || line->DimensionModel == GAIA_XY_Z_M)
3443 			  strcat (buf, "<gml:posList srsDimension=\"3\">");
3444 		      else
3445 			  strcat (buf, "<gml:posList srsDimension=\"2\">");
3446 		  }
3447 		else
3448 		  {
3449 		      if (geom->Srid <= 0)
3450 			  strcpy (buf, "<gml:LineString>");
3451 		      else
3452 			  sprintf (buf, "<gml:LineString srsName=\"EPSG:%d\">",
3453 				   geom->Srid);
3454 		      strcat (buf, "<gml:coordinates>");
3455 		  }
3456 	    }
3457 	  gaiaAppendToOutBuffer (out_buf, buf);
3458 	  for (iv = 0; iv < line->Points; iv++)
3459 	    {
3460 		/* exporting vertices */
3461 		has_z = 0;
3462 		z = 0.0;
3463 		if (line->DimensionModel == GAIA_XY_Z)
3464 		  {
3465 		      has_z = 1;
3466 		      gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
3467 		  }
3468 		else if (line->DimensionModel == GAIA_XY_M)
3469 		  {
3470 		      gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
3471 		  }
3472 		else if (line->DimensionModel == GAIA_XY_Z_M)
3473 		  {
3474 		      has_z = 1;
3475 		      gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
3476 		  }
3477 		else
3478 		  {
3479 		      gaiaGetPoint (line->Coords, iv, &x, &y);
3480 		  }
3481 		if (iv == 0)
3482 		    *buf = '\0';
3483 		else
3484 		    strcpy (buf, " ");
3485 		if (has_z)
3486 		  {
3487 		      buf_x = sqlite3_mprintf ("%.*f", precision, x);
3488 		      gaiaOutClean (buf_x);
3489 		      buf_y = sqlite3_mprintf ("%.*f", precision, y);
3490 		      gaiaOutClean (buf_y);
3491 		      buf_z = sqlite3_mprintf ("%.*f", precision, z);
3492 		      gaiaOutClean (buf_z);
3493 		      if (version == 3)
3494 			{
3495 			    xbuf =
3496 				sqlite3_mprintf ("%s%s %s %s", buf, buf_x,
3497 						 buf_y, buf_z);
3498 			    sqlite3_free (buf_x);
3499 			    sqlite3_free (buf_y);
3500 			    sqlite3_free (buf_z);
3501 			}
3502 		      else
3503 			{
3504 			    xbuf =
3505 				sqlite3_mprintf ("%s%s,%s,%s", buf, buf_x,
3506 						 buf_y, buf_z);
3507 			    sqlite3_free (buf_x);
3508 			    sqlite3_free (buf_y);
3509 			    sqlite3_free (buf_z);
3510 			}
3511 		  }
3512 		else
3513 		  {
3514 		      buf_x = sqlite3_mprintf ("%.*f", precision, x);
3515 		      gaiaOutClean (buf_x);
3516 		      buf_y = sqlite3_mprintf ("%.*f", precision, y);
3517 		      gaiaOutClean (buf_y);
3518 		      if (version == 3)
3519 			{
3520 			    xbuf =
3521 				sqlite3_mprintf ("%s%s %s", buf, buf_x, buf_y);
3522 			    sqlite3_free (buf_x);
3523 			    sqlite3_free (buf_y);
3524 			}
3525 		      else
3526 			{
3527 			    xbuf =
3528 				sqlite3_mprintf ("%s%s,%s", buf, buf_x, buf_y);
3529 			    sqlite3_free (buf_x);
3530 			    sqlite3_free (buf_y);
3531 			}
3532 		  }
3533 		gaiaAppendToOutBuffer (out_buf, xbuf);
3534 		sqlite3_free (xbuf);
3535 	    }
3536 	  if (is_multi)
3537 	    {
3538 		if (version == 3)
3539 		  {
3540 		      strcpy (buf, "</gml:posList>");
3541 		      strcat (buf, "</gml:LineStringSegment>");
3542 		      strcat (buf, "</gml:segments>");
3543 		      strcat (buf, "</gml:Curve>");
3544 		      if (is_coll)
3545 			  strcat (buf, "</gml:geometryMember>");
3546 		      else
3547 			  strcat (buf, "</gml:curveMember>");
3548 		  }
3549 		else
3550 		  {
3551 		      strcpy (buf, "</gml:coordinates>");
3552 		      strcat (buf, "</gml:LineString>");
3553 		      if (is_coll)
3554 			  strcat (buf, "</gml:geometryMember>");
3555 		      else
3556 			  strcat (buf, "</gml:lineStringMember>");
3557 		  }
3558 	    }
3559 	  else
3560 	    {
3561 		if (version == 3)
3562 		  {
3563 		      strcpy (buf, "</gml:posList>");
3564 		      strcat (buf, "</gml:LineStringSegment>");
3565 		      strcat (buf, "</gml:segments>");
3566 		      strcat (buf, "</gml:Curve>");
3567 		  }
3568 		else
3569 		  {
3570 		      strcpy (buf, "</gml:coordinates>");
3571 		      strcat (buf, "</gml:LineString>");
3572 		  }
3573 	    }
3574 	  gaiaAppendToOutBuffer (out_buf, buf);
3575 	  line = line->Next;
3576       }
3577     polyg = geom->FirstPolygon;
3578     while (polyg)
3579       {
3580 	  /* processing POLYGON */
3581 	  ring = polyg->Exterior;
3582 	  if (is_multi)
3583 	    {
3584 		if (version == 3)
3585 		  {
3586 		      if (is_coll)
3587 			  strcpy (buf, "<gml:geometryMember>");
3588 		      else
3589 			  strcpy (buf, "<gml:surfaceMember>");
3590 		      strcat (buf, "<gml:Polygon>");
3591 		      strcat (buf, "<gml:exterior>");
3592 		      strcat (buf, "<gml:LinearRing>");
3593 		      if (ring->DimensionModel == GAIA_XY_Z
3594 			  || ring->DimensionModel == GAIA_XY_Z_M)
3595 			  strcat (buf, "<gml:posList srsDimension=\"3\">");
3596 		      else
3597 			  strcat (buf, "<gml:posList srsDimension=\"2\">");
3598 		  }
3599 		else
3600 		  {
3601 		      if (is_coll)
3602 			  strcpy (buf, "<gml:geometryMember>");
3603 		      else
3604 			  strcpy (buf, "<gml:polygonMember>");
3605 		      strcat (buf, "<gml:Polygon>");
3606 		      strcat (buf, "<gml:outerBoundaryIs>");
3607 		      strcat (buf, "<gml:LinearRing>");
3608 		      strcat (buf, "<gml:coordinates>");
3609 		  }
3610 	    }
3611 	  else
3612 	    {
3613 		if (geom->Srid <= 0)
3614 		    strcpy (buf, "<gml:Polygon>");
3615 		else
3616 		    sprintf (buf, "<gml:Polygon srsName=\"EPSG:%d\">",
3617 			     geom->Srid);
3618 		if (version == 3)
3619 		  {
3620 		      strcat (buf, "<gml:exterior>");
3621 		      strcat (buf, "<gml:LinearRing>");
3622 		      if (ring->DimensionModel == GAIA_XY_Z
3623 			  || ring->DimensionModel == GAIA_XY_Z_M)
3624 			  strcat (buf, "<gml:posList srsDimension=\"3\">");
3625 		      else
3626 			  strcat (buf, "<gml:posList srsDimension=\"2\">");
3627 		  }
3628 		else
3629 		  {
3630 		      strcat (buf, "<gml:outerBoundaryIs>");
3631 		      strcat (buf, "<gml:LinearRing>");
3632 		      strcat (buf, "<gml:coordinates>");
3633 		  }
3634 	    }
3635 	  gaiaAppendToOutBuffer (out_buf, buf);
3636 	  for (iv = 0; iv < ring->Points; iv++)
3637 	    {
3638 		/* exporting vertices [Interior Ring] */
3639 		has_z = 0;
3640 		z = 0.0;
3641 		if (ring->DimensionModel == GAIA_XY_Z)
3642 		  {
3643 		      has_z = 1;
3644 		      gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
3645 		  }
3646 		else if (ring->DimensionModel == GAIA_XY_M)
3647 		  {
3648 		      gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
3649 		  }
3650 		else if (ring->DimensionModel == GAIA_XY_Z_M)
3651 		  {
3652 		      has_z = 1;
3653 		      gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
3654 		  }
3655 		else
3656 		  {
3657 		      gaiaGetPoint (ring->Coords, iv, &x, &y);
3658 		  }
3659 		if (iv == 0)
3660 		    *buf = '\0';
3661 		else
3662 		    strcpy (buf, " ");
3663 		if (has_z)
3664 		  {
3665 		      buf_x = sqlite3_mprintf ("%.*f", precision, x);
3666 		      gaiaOutClean (buf_x);
3667 		      buf_y = sqlite3_mprintf ("%.*f", precision, y);
3668 		      gaiaOutClean (buf_y);
3669 		      buf_z = sqlite3_mprintf ("%.*f", precision, z);
3670 		      gaiaOutClean (buf_z);
3671 		      if (version == 3)
3672 			{
3673 			    xbuf =
3674 				sqlite3_mprintf ("%s%s %s %s", buf, buf_x,
3675 						 buf_y, buf_z);
3676 			    sqlite3_free (buf_x);
3677 			    sqlite3_free (buf_y);
3678 			    sqlite3_free (buf_z);
3679 			}
3680 		      else
3681 			{
3682 			    xbuf =
3683 				sqlite3_mprintf ("%s%s,%s,%s", buf, buf_x,
3684 						 buf_y, buf_z);
3685 			    sqlite3_free (buf_x);
3686 			    sqlite3_free (buf_y);
3687 			    sqlite3_free (buf_z);
3688 			}
3689 		  }
3690 		else
3691 		  {
3692 		      buf_x = sqlite3_mprintf ("%.*f", precision, x);
3693 		      gaiaOutClean (buf_x);
3694 		      buf_y = sqlite3_mprintf ("%.*f", precision, y);
3695 		      gaiaOutClean (buf_y);
3696 		      if (version == 3)
3697 			{
3698 			    xbuf =
3699 				sqlite3_mprintf ("%s%s %s", buf, buf_x, buf_y);
3700 			    sqlite3_free (buf_x);
3701 			    sqlite3_free (buf_y);
3702 			}
3703 		      else
3704 			{
3705 			    xbuf =
3706 				sqlite3_mprintf ("%s%s,%s", buf, buf_x, buf_y);
3707 			    sqlite3_free (buf_x);
3708 			    sqlite3_free (buf_y);
3709 			}
3710 		  }
3711 		gaiaAppendToOutBuffer (out_buf, xbuf);
3712 		sqlite3_free (xbuf);
3713 	    }
3714 	  /* closing the Exterior Ring */
3715 	  if (version == 3)
3716 	    {
3717 		strcpy (buf, "</gml:posList>");
3718 		strcat (buf, "</gml:LinearRing>");
3719 		strcat (buf, "</gml:exterior>");
3720 	    }
3721 	  else
3722 	    {
3723 		strcpy (buf, "</gml:coordinates>");
3724 		strcat (buf, "</gml:LinearRing>");
3725 		strcat (buf, "</gml:outerBoundaryIs>");
3726 	    }
3727 	  gaiaAppendToOutBuffer (out_buf, buf);
3728 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
3729 	    {
3730 		/* interior rings */
3731 		ring = polyg->Interiors + ib;
3732 		if (version == 3)
3733 		  {
3734 		      strcpy (buf, "<gml:interior>");
3735 		      strcat (buf, "<gml:LinearRing>");
3736 		      if (ring->DimensionModel == GAIA_XY_Z
3737 			  || ring->DimensionModel == GAIA_XY_Z_M)
3738 			  strcat (buf, "<gml:posList srsDimension=\"3\">");
3739 		      else
3740 			  strcat (buf, "<gml:posList srsDimension=\"2\">");
3741 		  }
3742 		else
3743 		  {
3744 		      strcpy (buf, "<gml:innerBoundaryIs>");
3745 		      strcat (buf, "<gml:LinearRing>");
3746 		      strcat (buf, "<gml:coordinates>");
3747 		  }
3748 		gaiaAppendToOutBuffer (out_buf, buf);
3749 		for (iv = 0; iv < ring->Points; iv++)
3750 		  {
3751 		      /* exporting vertices [Interior Ring] */
3752 		      has_z = 0;
3753 		      z = 0.0;
3754 		      if (ring->DimensionModel == GAIA_XY_Z)
3755 			{
3756 			    has_z = 1;
3757 			    gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
3758 			}
3759 		      else if (ring->DimensionModel == GAIA_XY_M)
3760 			{
3761 			    gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
3762 			}
3763 		      else if (ring->DimensionModel == GAIA_XY_Z_M)
3764 			{
3765 			    has_z = 1;
3766 			    gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
3767 			}
3768 		      else
3769 			{
3770 			    gaiaGetPoint (ring->Coords, iv, &x, &y);
3771 			}
3772 		      if (iv == 0)
3773 			  *buf = '\0';
3774 		      else
3775 			  strcpy (buf, " ");
3776 		      if (has_z)
3777 			{
3778 			    buf_x = sqlite3_mprintf ("%.*f", precision, x);
3779 			    gaiaOutClean (buf_x);
3780 			    buf_y = sqlite3_mprintf ("%.*f", precision, y);
3781 			    gaiaOutClean (buf_y);
3782 			    buf_z = sqlite3_mprintf ("%.*f", precision, z);
3783 			    gaiaOutClean (buf_z);
3784 			    if (version == 3)
3785 			      {
3786 				  xbuf =
3787 				      sqlite3_mprintf ("%s%s %s %s", buf, buf_x,
3788 						       buf_y, buf_z);
3789 				  sqlite3_free (buf_x);
3790 				  sqlite3_free (buf_y);
3791 				  sqlite3_free (buf_z);
3792 			      }
3793 			    else
3794 			      {
3795 				  xbuf =
3796 				      sqlite3_mprintf ("%s%s,%s,%s", buf, buf_x,
3797 						       buf_y, buf_z);
3798 				  sqlite3_free (buf_x);
3799 				  sqlite3_free (buf_y);
3800 				  sqlite3_free (buf_z);
3801 			      }
3802 			}
3803 		      else
3804 			{
3805 			    buf_x = sqlite3_mprintf ("%.*f", precision, x);
3806 			    gaiaOutClean (buf_x);
3807 			    buf_y = sqlite3_mprintf ("%.*f", precision, y);
3808 			    gaiaOutClean (buf_y);
3809 			    if (version == 3)
3810 			      {
3811 				  xbuf =
3812 				      sqlite3_mprintf ("%s%s %s", buf, buf_x,
3813 						       buf_y);
3814 				  sqlite3_free (buf_x);
3815 				  sqlite3_free (buf_y);
3816 			      }
3817 			    else
3818 			      {
3819 				  xbuf =
3820 				      sqlite3_mprintf ("%s%s,%s", buf, buf_x,
3821 						       buf_y);
3822 				  sqlite3_free (buf_x);
3823 				  sqlite3_free (buf_y);
3824 			      }
3825 			}
3826 		      gaiaAppendToOutBuffer (out_buf, xbuf);
3827 		      sqlite3_free (xbuf);
3828 		  }
3829 		/* closing the Interior Ring */
3830 		if (version == 3)
3831 		  {
3832 		      strcpy (buf, "</gml:posList>");
3833 		      strcat (buf, "</gml:LinearRing>");
3834 		      strcat (buf, "</gml:interior>");
3835 		  }
3836 		else
3837 		  {
3838 		      strcpy (buf, "</gml:coordinates>");
3839 		      strcat (buf, "</gml:LinearRing>");
3840 		      strcat (buf, "</gml:innerBoundaryIs>");
3841 		  }
3842 		gaiaAppendToOutBuffer (out_buf, buf);
3843 	    }
3844 	  /* closing the Polygon */
3845 	  if (is_multi)
3846 	    {
3847 		if (version == 3)
3848 		  {
3849 		      strcpy (buf, "</gml:Polygon>");
3850 		      if (is_coll)
3851 			  strcat (buf, "</gml:geometryMember>");
3852 		      else
3853 			  strcat (buf, "</gml:surfaceMember>");
3854 		  }
3855 		else
3856 		  {
3857 		      strcpy (buf, "</gml:Polygon>");
3858 		      if (is_coll)
3859 			  strcat (buf, "</gml:geometryMember>");
3860 		      else
3861 			  strcat (buf, "</gml:polygonMember>");
3862 		  }
3863 	    }
3864 	  else
3865 	      strcpy (buf, "</gml:Polygon>");
3866 	  gaiaAppendToOutBuffer (out_buf, buf);
3867 	  polyg = polyg->Next;
3868       }
3869     switch (geom->DeclaredType)
3870       {
3871       case GAIA_POINT:
3872       case GAIA_LINESTRING:
3873       case GAIA_POLYGON:
3874 	  *buf = '\0';
3875 	  break;
3876       case GAIA_MULTIPOINT:
3877 	  sprintf (buf, "</gml:MultiPoint>");
3878 	  break;
3879       case GAIA_MULTILINESTRING:
3880 	  if (version == 3)
3881 	      sprintf (buf, "</gml:MultiCurve>");
3882 	  else
3883 	      sprintf (buf, "</gml:MultiLineString>");
3884 	  break;
3885       case GAIA_MULTIPOLYGON:
3886 	  if (version == 3)
3887 	      sprintf (buf, "</gml:MultiSurface>");
3888 	  else
3889 	      sprintf (buf, "</gml:MultiPolygon>");
3890 	  break;
3891       default:
3892 	  sprintf (buf, "</gml:MultiGeometry>");
3893 	  break;
3894       };
3895     gaiaAppendToOutBuffer (out_buf, buf);
3896 }
3897 
3898 GAIAGEO_DECLARE void
gaiaOutGeoJSON(gaiaOutBufferPtr out_buf,gaiaGeomCollPtr geom,int precision,int options)3899 gaiaOutGeoJSON (gaiaOutBufferPtr out_buf, gaiaGeomCollPtr geom, int precision,
3900 		int options)
3901 {
3902 /*
3903 / prints the GeoJSON representation of current geometry
3904 / *result* returns the encoded GeoJSON or NULL if any error is encountered
3905 */
3906     gaiaPointPtr point;
3907     gaiaLinestringPtr line;
3908     gaiaPolygonPtr polyg;
3909     gaiaRingPtr ring;
3910     int iv;
3911     int ib;
3912     double x;
3913     double y;
3914     double z;
3915     double m;
3916     int has_z;
3917     int is_multi = 0;
3918     int multi_count = 0;
3919     char *bbox;
3920     char crs[2048];
3921     char *buf;
3922     char *buf_x;
3923     char *buf_y;
3924     char *buf_m;
3925     char *buf_z = NULL;
3926     char endJson[16];
3927     if (!geom)
3928 	return;
3929     if (precision > 18)
3930 	precision = 18;
3931 
3932     if (options != 0)
3933       {
3934 	  bbox = NULL;
3935 	  *crs = '\0';
3936 	  if (geom->Srid > 0)
3937 	    {
3938 		if (options == 2 || options == 3)
3939 		  {
3940 		      /* including short CRS */
3941 		      sprintf (crs,
3942 			       ",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"EPSG:%d\"}}",
3943 			       geom->Srid);
3944 		  }
3945 		if (options == 4 || options == 5)
3946 		  {
3947 		      /* including long CRS */
3948 		      sprintf (crs,
3949 			       ",\"crs\":{\"type\":\"name\",\"properties\":{\"name\":\"urn:ogc:def:crs:EPSG:%d\"}}",
3950 			       geom->Srid);
3951 		  }
3952 	    }
3953 	  if (options == 1 || options == 3 || options == 5)
3954 	    {
3955 		/* including BBOX */
3956 		gaiaMbrGeometry (geom);
3957 		buf_x = sqlite3_mprintf ("%.*f", precision, geom->MinX);
3958 		gaiaOutClean (buf_x);
3959 		buf_y = sqlite3_mprintf ("%.*f", precision, geom->MinY);
3960 		gaiaOutClean (buf_y);
3961 		buf_z = sqlite3_mprintf ("%.*f", precision, geom->MaxX);
3962 		gaiaOutClean (buf_z);
3963 		buf_m = sqlite3_mprintf ("%.*f", precision, geom->MaxY);
3964 		gaiaOutClean (buf_m);
3965 		bbox =
3966 		    sqlite3_mprintf (",\"bbox\":[%s,%s,%s,%s]", buf_x, buf_y,
3967 				     buf_z, buf_m);
3968 		sqlite3_free (buf_x);
3969 		sqlite3_free (buf_y);
3970 		sqlite3_free (buf_z);
3971 		sqlite3_free (buf_m);
3972 	    }
3973 	  switch (geom->DeclaredType)
3974 	    {
3975 	    case GAIA_POINT:
3976 		buf =
3977 		    sqlite3_mprintf ("{\"type\":\"Point\"%s%s,\"coordinates\":",
3978 				     crs, bbox);
3979 		strcpy (endJson, "}");
3980 		break;
3981 	    case GAIA_LINESTRING:
3982 		buf =
3983 		    sqlite3_mprintf
3984 		    ("{\"type\":\"LineString\"%s%s,\"coordinates\":[", crs,
3985 		     bbox);
3986 		strcpy (endJson, "}");
3987 		break;
3988 	    case GAIA_POLYGON:
3989 		buf =
3990 		    sqlite3_mprintf
3991 		    ("{\"type\":\"Polygon\"%s%s,\"coordinates\":[", crs, bbox);
3992 		strcpy (endJson, "}");
3993 		break;
3994 	    case GAIA_MULTIPOINT:
3995 		buf =
3996 		    sqlite3_mprintf
3997 		    ("{\"type\":\"MultiPoint\"%s%s,\"coordinates\":[", crs,
3998 		     bbox);
3999 		strcpy (endJson, "]}");
4000 		break;
4001 	    case GAIA_MULTILINESTRING:
4002 		buf =
4003 		    sqlite3_mprintf
4004 		    ("{\"type\":\"MultiLineString\"%s%s,\"coordinates\":[[",
4005 		     crs, bbox);
4006 		strcpy (endJson, "]}");
4007 		break;
4008 	    case GAIA_MULTIPOLYGON:
4009 		buf =
4010 		    sqlite3_mprintf
4011 		    ("{\"type\":\"MultiPolygon\"%s%s,\"coordinates\":[[", crs,
4012 		     bbox);
4013 		strcpy (endJson, "]}");
4014 		break;
4015 	    default:
4016 		buf =
4017 		    sqlite3_mprintf
4018 		    ("{\"type\":\"GeometryCollection\"%s%s,\"geometries\":[",
4019 		     crs, bbox);
4020 		strcpy (endJson, "]}");
4021 		is_multi = 1;
4022 		break;
4023 	    };
4024 	  if (bbox)
4025 	      sqlite3_free (bbox);
4026       }
4027     else
4028       {
4029 	  /* omitting BBOX */
4030 	  switch (geom->DeclaredType)
4031 	    {
4032 	    case GAIA_POINT:
4033 		buf = sqlite3_mprintf ("{\"type\":\"Point\",\"coordinates\":");
4034 		strcpy (endJson, "}");
4035 		break;
4036 	    case GAIA_LINESTRING:
4037 		buf =
4038 		    sqlite3_mprintf
4039 		    ("{\"type\":\"LineString\",\"coordinates\":[");
4040 		strcpy (endJson, "}");
4041 		break;
4042 	    case GAIA_POLYGON:
4043 		buf =
4044 		    sqlite3_mprintf ("{\"type\":\"Polygon\",\"coordinates\":[");
4045 		strcpy (endJson, "}");
4046 		break;
4047 	    case GAIA_MULTIPOINT:
4048 		buf =
4049 		    sqlite3_mprintf
4050 		    ("{\"type\":\"MultiPoint\",\"coordinates\":[");
4051 		strcpy (endJson, "]}");
4052 		break;
4053 	    case GAIA_MULTILINESTRING:
4054 		buf =
4055 		    sqlite3_mprintf
4056 		    ("{\"type\":\"MultiLineString\",\"coordinates\":[[");
4057 		strcpy (endJson, "]}");
4058 		break;
4059 	    case GAIA_MULTIPOLYGON:
4060 		buf =
4061 		    sqlite3_mprintf
4062 		    ("{\"type\":\"MultiPolygon\",\"coordinates\":[[");
4063 		strcpy (endJson, "]}");
4064 		break;
4065 	    default:
4066 		buf =
4067 		    sqlite3_mprintf
4068 		    ("{\"type\":\"GeometryCollection\",\"geometries\":[");
4069 		strcpy (endJson, "]}");
4070 		is_multi = 1;
4071 		break;
4072 	    };
4073       }
4074     gaiaAppendToOutBuffer (out_buf, buf);
4075     sqlite3_free (buf);
4076     point = geom->FirstPoint;
4077     while (point)
4078       {
4079 	  /* processing POINT */
4080 	  if (is_multi)
4081 	    {
4082 		if (multi_count > 0)
4083 		    buf = ",{\"type\":\"Point\",\"coordinates\":";
4084 		else
4085 		    buf = "{\"type\":\"Point\",\"coordinates\":";
4086 		gaiaAppendToOutBuffer (out_buf, buf);
4087 	    }
4088 	  else if (point != geom->FirstPoint)
4089 	    {
4090 		/* adding a further Point */
4091 		gaiaAppendToOutBuffer (out_buf, ",");
4092 	    }
4093 	  buf_x = sqlite3_mprintf ("%.*f", precision, point->X);
4094 	  gaiaOutClean (buf_x);
4095 	  buf_y = sqlite3_mprintf ("%.*f", precision, point->Y);
4096 	  gaiaOutClean (buf_y);
4097 	  has_z = 0;
4098 	  if (point->DimensionModel == GAIA_XY_Z
4099 	      || point->DimensionModel == GAIA_XY_Z_M)
4100 	    {
4101 		buf_z = sqlite3_mprintf ("%.*f", precision, point->Z);
4102 		gaiaOutClean (buf_z);
4103 		has_z = 1;
4104 	    }
4105 	  if (has_z)
4106 	    {
4107 		buf = sqlite3_mprintf ("[%s,%s,%s]", buf_x, buf_y, buf_z);
4108 		sqlite3_free (buf_x);
4109 		sqlite3_free (buf_y);
4110 		sqlite3_free (buf_z);
4111 	    }
4112 	  else
4113 	    {
4114 		buf = sqlite3_mprintf ("[%s,%s]", buf_x, buf_y);
4115 		sqlite3_free (buf_x);
4116 		sqlite3_free (buf_y);
4117 	    }
4118 	  gaiaAppendToOutBuffer (out_buf, buf);
4119 	  sqlite3_free (buf);
4120 	  if (is_multi)
4121 	    {
4122 		gaiaAppendToOutBuffer (out_buf, "}");
4123 		multi_count++;
4124 	    }
4125 	  point = point->Next;
4126       }
4127     line = geom->FirstLinestring;
4128     while (line)
4129       {
4130 	  /* processing LINESTRING */
4131 	  if (is_multi)
4132 	    {
4133 		if (multi_count > 0)
4134 		    buf = ",{\"type\":\"LineString\",\"coordinates\":[";
4135 		else
4136 		    buf = "{\"type\":\"LineString\",\"coordinates\":[";
4137 		gaiaAppendToOutBuffer (out_buf, buf);
4138 	    }
4139 	  else if (line != geom->FirstLinestring)
4140 	    {
4141 		/* opening a further LineString */
4142 		gaiaAppendToOutBuffer (out_buf, ",[");
4143 	    }
4144 	  for (iv = 0; iv < line->Points; iv++)
4145 	    {
4146 		/* exporting vertices */
4147 		has_z = 0;
4148 		z = 0.0;
4149 		if (line->DimensionModel == GAIA_XY_Z)
4150 		  {
4151 		      has_z = 1;
4152 		      gaiaGetPointXYZ (line->Coords, iv, &x, &y, &z);
4153 		  }
4154 		else if (line->DimensionModel == GAIA_XY_M)
4155 		  {
4156 		      gaiaGetPointXYM (line->Coords, iv, &x, &y, &m);
4157 		  }
4158 		else if (line->DimensionModel == GAIA_XY_Z_M)
4159 		  {
4160 		      has_z = 1;
4161 		      gaiaGetPointXYZM (line->Coords, iv, &x, &y, &z, &m);
4162 		  }
4163 		else
4164 		  {
4165 		      gaiaGetPoint (line->Coords, iv, &x, &y);
4166 		  }
4167 		if (has_z)
4168 		  {
4169 		      buf_x = sqlite3_mprintf ("%.*f", precision, x);
4170 		      gaiaOutClean (buf_x);
4171 		      buf_y = sqlite3_mprintf ("%.*f", precision, y);
4172 		      gaiaOutClean (buf_y);
4173 		      buf_z = sqlite3_mprintf ("%.*f", precision, z);
4174 		      gaiaOutClean (buf_z);
4175 		      if (iv == 0)
4176 			  buf =
4177 			      sqlite3_mprintf ("[%s,%s,%s]", buf_x, buf_y,
4178 					       buf_z);
4179 		      else
4180 			  buf =
4181 			      sqlite3_mprintf (",[%s,%s,%s]", buf_x, buf_y,
4182 					       buf_z);
4183 		      sqlite3_free (buf_x);
4184 		      sqlite3_free (buf_y);
4185 		      sqlite3_free (buf_z);
4186 		  }
4187 		else
4188 		  {
4189 		      buf_x = sqlite3_mprintf ("%.*f", precision, x);
4190 		      gaiaOutClean (buf_x);
4191 		      buf_y = sqlite3_mprintf ("%.*f", precision, y);
4192 		      gaiaOutClean (buf_y);
4193 		      if (iv == 0)
4194 			  buf = sqlite3_mprintf ("[%s,%s]", buf_x, buf_y);
4195 		      else
4196 			  buf = sqlite3_mprintf (",[%s,%s]", buf_x, buf_y);
4197 		      sqlite3_free (buf_x);
4198 		      sqlite3_free (buf_y);
4199 		  }
4200 		gaiaAppendToOutBuffer (out_buf, buf);
4201 		sqlite3_free (buf);
4202 	    }
4203 	  /* closing the LineString */
4204 	  gaiaAppendToOutBuffer (out_buf, "]");
4205 	  if (is_multi)
4206 	    {
4207 		gaiaAppendToOutBuffer (out_buf, "}");
4208 		multi_count++;
4209 	    }
4210 	  line = line->Next;
4211       }
4212     polyg = geom->FirstPolygon;
4213     while (polyg)
4214       {
4215 	  /* processing POLYGON */
4216 	  if (is_multi)
4217 	    {
4218 		if (multi_count > 0)
4219 		    buf = ",{\"type\":\"Polygon\",\"coordinates\":[";
4220 		else
4221 		    buf = "{\"type\":\"Polygon\",\"coordinates\":[";
4222 		gaiaAppendToOutBuffer (out_buf, buf);
4223 	    }
4224 	  else if (polyg != geom->FirstPolygon)
4225 	    {
4226 		/* opening a further Polygon */
4227 		gaiaAppendToOutBuffer (out_buf, ",[");
4228 	    }
4229 	  ring = polyg->Exterior;
4230 	  for (iv = 0; iv < ring->Points; iv++)
4231 	    {
4232 		/* exporting vertices [Interior Ring] */
4233 		has_z = 0;
4234 		z = 0.0;
4235 		if (ring->DimensionModel == GAIA_XY_Z)
4236 		  {
4237 		      has_z = 1;
4238 		      gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
4239 		  }
4240 		else if (ring->DimensionModel == GAIA_XY_M)
4241 		  {
4242 		      gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
4243 		  }
4244 		else if (ring->DimensionModel == GAIA_XY_Z_M)
4245 		  {
4246 		      has_z = 1;
4247 		      gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
4248 		  }
4249 		else
4250 		  {
4251 		      gaiaGetPoint (ring->Coords, iv, &x, &y);
4252 		  }
4253 		if (has_z)
4254 		  {
4255 		      buf_x = sqlite3_mprintf ("%.*f", precision, x);
4256 		      gaiaOutClean (buf_x);
4257 		      buf_y = sqlite3_mprintf ("%.*f", precision, y);
4258 		      gaiaOutClean (buf_y);
4259 		      buf_z = sqlite3_mprintf ("%.*f", precision, z);
4260 		      gaiaOutClean (buf_z);
4261 		      if (iv == 0)
4262 			  buf =
4263 			      sqlite3_mprintf ("[[%s,%s,%s]", buf_x, buf_y,
4264 					       buf_z);
4265 		      else
4266 			  buf =
4267 			      sqlite3_mprintf (",[%s,%s,%s]", buf_x, buf_y,
4268 					       buf_z);
4269 		      sqlite3_free (buf_x);
4270 		      sqlite3_free (buf_y);
4271 		      sqlite3_free (buf_z);
4272 		  }
4273 		else
4274 		  {
4275 		      buf_x = sqlite3_mprintf ("%.*f", precision, x);
4276 		      gaiaOutClean (buf_x);
4277 		      buf_y = sqlite3_mprintf ("%.*f", precision, y);
4278 		      gaiaOutClean (buf_y);
4279 		      if (iv == 0)
4280 			  buf = sqlite3_mprintf ("[[%s,%s]", buf_x, buf_y);
4281 		      else
4282 			  buf = sqlite3_mprintf (",[%s,%s]", buf_x, buf_y);
4283 		      sqlite3_free (buf_x);
4284 		      sqlite3_free (buf_y);
4285 		  }
4286 		gaiaAppendToOutBuffer (out_buf, buf);
4287 		sqlite3_free (buf);
4288 	    }
4289 	  /* closing the Exterior Ring */
4290 	  gaiaAppendToOutBuffer (out_buf, "]");
4291 	  for (ib = 0; ib < polyg->NumInteriors; ib++)
4292 	    {
4293 		/* interior rings */
4294 		ring = polyg->Interiors + ib;
4295 		for (iv = 0; iv < ring->Points; iv++)
4296 		  {
4297 		      /* exporting vertices [Interior Ring] */
4298 		      has_z = 0;
4299 		      z = 0.0;
4300 		      if (ring->DimensionModel == GAIA_XY_Z)
4301 			{
4302 			    has_z = 1;
4303 			    gaiaGetPointXYZ (ring->Coords, iv, &x, &y, &z);
4304 			}
4305 		      else if (ring->DimensionModel == GAIA_XY_M)
4306 			{
4307 			    gaiaGetPointXYM (ring->Coords, iv, &x, &y, &m);
4308 			}
4309 		      else if (ring->DimensionModel == GAIA_XY_Z_M)
4310 			{
4311 			    has_z = 1;
4312 			    gaiaGetPointXYZM (ring->Coords, iv, &x, &y, &z, &m);
4313 			}
4314 		      else
4315 			{
4316 			    gaiaGetPoint (ring->Coords, iv, &x, &y);
4317 			}
4318 		      if (has_z)
4319 			{
4320 			    buf_x = sqlite3_mprintf ("%.*f", precision, x);
4321 			    gaiaOutClean (buf_x);
4322 			    buf_y = sqlite3_mprintf ("%.*f", precision, y);
4323 			    gaiaOutClean (buf_y);
4324 			    buf_z = sqlite3_mprintf ("%.*f", precision, z);
4325 			    gaiaOutClean (buf_z);
4326 			    if (iv == 0)
4327 				buf =
4328 				    sqlite3_mprintf (",[[%s,%s,%s]", buf_x,
4329 						     buf_y, buf_z);
4330 			    else
4331 				buf =
4332 				    sqlite3_mprintf (",[%s,%s,%s]", buf_x,
4333 						     buf_y, buf_z);
4334 			    sqlite3_free (buf_x);
4335 			    sqlite3_free (buf_y);
4336 			    sqlite3_free (buf_z);
4337 			}
4338 		      else
4339 			{
4340 			    buf_x = sqlite3_mprintf ("%.*f", precision, x);
4341 			    gaiaOutClean (buf_x);
4342 			    buf_y = sqlite3_mprintf ("%.*f", precision, y);
4343 			    gaiaOutClean (buf_y);
4344 			    if (iv == 0)
4345 				buf =
4346 				    sqlite3_mprintf (",[[%s,%s]", buf_x, buf_y);
4347 			    else
4348 				buf =
4349 				    sqlite3_mprintf (",[%s,%s]", buf_x, buf_y);
4350 			    sqlite3_free (buf_x);
4351 			    sqlite3_free (buf_y);
4352 			}
4353 		      gaiaAppendToOutBuffer (out_buf, buf);
4354 		      sqlite3_free (buf);
4355 		  }
4356 		/* closing the Interior Ring */
4357 		gaiaAppendToOutBuffer (out_buf, "]");
4358 	    }
4359 	  /* closing the Polygon */
4360 	  gaiaAppendToOutBuffer (out_buf, "]");
4361 	  if (is_multi)
4362 	    {
4363 		gaiaAppendToOutBuffer (out_buf, "}");
4364 		multi_count++;
4365 	    }
4366 	  polyg = polyg->Next;
4367       }
4368     gaiaAppendToOutBuffer (out_buf, endJson);
4369 }
4370