PostGIS  2.1.10dev-r@@SVN_REVISION@@
lwout_wkt.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  *
5  * Copyright (C) 2009 Paul Ramsey <pramsey@cleverelephant.ca>
6  *
7  * This is free software; you can redistribute and/or modify it under
8  * the terms of the GNU General Public Licence. See the COPYING file.
9  *
10  **********************************************************************/
11 
12 #include "liblwgeom_internal.h"
13 #include "lwgeom_log.h"
14 #include "stringbuffer.h"
15 
16 static void lwgeom_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, int precision, uint8_t variant);
17 
18 
19 /*
20 * ISO format uses both Z and M qualifiers.
21 * Extended format only uses an M qualifier for 3DM variants, where it is not
22 * clear what the third dimension represents.
23 * SFSQL format never has more than two dimensions, so no qualifiers.
24 */
25 static void dimension_qualifiers_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, uint8_t variant)
26 {
27 
28  /* Extended WKT: POINTM(0 0 0) */
29 #if 0
30  if ( (variant & WKT_EXTENDED) && ! (variant & WKT_IS_CHILD) && FLAGS_GET_M(geom->flags) && (!FLAGS_GET_Z(geom->flags)) )
31 #else
32  if ( (variant & WKT_EXTENDED) && FLAGS_GET_M(geom->flags) && (!FLAGS_GET_Z(geom->flags)) )
33 #endif
34  {
35  stringbuffer_append(sb, "M"); /* "M" */
36  return;
37  }
38 
39  /* ISO WKT: POINT ZM (0 0 0 0) */
40  if ( (variant & WKT_ISO) && (FLAGS_NDIMS(geom->flags) > 2) )
41  {
42  stringbuffer_append(sb, " ");
43  if ( FLAGS_GET_Z(geom->flags) )
44  stringbuffer_append(sb, "Z");
45  if ( FLAGS_GET_M(geom->flags) )
46  stringbuffer_append(sb, "M");
47  stringbuffer_append(sb, " ");
48  }
49 }
50 
51 /*
52 * Write an empty token out, padding with a space if
53 * necessary.
54 */
56 {
57  if ( ! strchr(" ,(", stringbuffer_lastchar(sb)) ) /* "EMPTY" */
58  {
59  stringbuffer_append(sb, " ");
60  }
61  stringbuffer_append(sb, "EMPTY");
62 }
63 
64 /*
65 * Point array is a list of coordinates. Depending on output mode,
66 * we may suppress some dimensions. ISO and Extended formats include
67 * all dimensions. Standard OGC output only includes X/Y coordinates.
68 */
69 static void ptarray_to_wkt_sb(const POINTARRAY *ptarray, stringbuffer_t *sb, int precision, uint8_t variant)
70 {
71  /* OGC only includes X/Y */
72  int dimensions = 2;
73  int i, j;
74 
75  /* ISO and extended formats include all dimensions */
76  if ( variant & ( WKT_ISO | WKT_EXTENDED ) )
77  dimensions = FLAGS_NDIMS(ptarray->flags);
78 
79  /* Opening paren? */
80  if ( ! (variant & WKT_NO_PARENS) )
81  stringbuffer_append(sb, "(");
82 
83  /* Digits and commas */
84  for (i = 0; i < ptarray->npoints; i++)
85  {
86  double *dbl_ptr = (double*)getPoint_internal(ptarray, i);
87 
88  /* Commas before ever coord but the first */
89  if ( i > 0 )
90  stringbuffer_append(sb, ",");
91 
92  for (j = 0; j < dimensions; j++)
93  {
94  /* Spaces before every ordinate but the first */
95  if ( j > 0 )
96  stringbuffer_append(sb, " ");
97  stringbuffer_aprintf(sb, "%.*g", precision, dbl_ptr[j]);
98  }
99  }
100 
101  /* Closing paren? */
102  if ( ! (variant & WKT_NO_PARENS) )
103  stringbuffer_append(sb, ")");
104 }
105 
106 /*
107 * A four-dimensional point will have different outputs depending on variant.
108 * ISO: POINT ZM (0 0 0 0)
109 * Extended: POINT(0 0 0 0)
110 * OGC: POINT(0 0)
111 * A three-dimensional m-point will have different outputs too.
112 * ISO: POINT M (0 0 0)
113 * Extended: POINTM(0 0 0)
114 * OGC: POINT(0 0)
115 */
116 static void lwpoint_to_wkt_sb(const LWPOINT *pt, stringbuffer_t *sb, int precision, uint8_t variant)
117 {
118  if ( ! (variant & WKT_NO_TYPE) )
119  {
120  stringbuffer_append(sb, "POINT"); /* "POINT" */
121  dimension_qualifiers_to_wkt_sb((LWGEOM*)pt, sb, variant);
122  }
123 
124  if ( lwpoint_is_empty(pt) )
125  {
126  empty_to_wkt_sb(sb);
127  return;
128  }
129 
130  ptarray_to_wkt_sb(pt->point, sb, precision, variant);
131 }
132 
133 /*
134 * LINESTRING(0 0 0, 1 1 1)
135 */
136 static void lwline_to_wkt_sb(const LWLINE *line, stringbuffer_t *sb, int precision, uint8_t variant)
137 {
138  if ( ! (variant & WKT_NO_TYPE) )
139  {
140  stringbuffer_append(sb, "LINESTRING"); /* "LINESTRING" */
141  dimension_qualifiers_to_wkt_sb((LWGEOM*)line, sb, variant);
142  }
143  if ( lwline_is_empty(line) )
144  {
145  empty_to_wkt_sb(sb);
146  return;
147  }
148 
149  ptarray_to_wkt_sb(line->points, sb, precision, variant);
150 }
151 
152 /*
153 * POLYGON(0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)
154 */
155 static void lwpoly_to_wkt_sb(const LWPOLY *poly, stringbuffer_t *sb, int precision, uint8_t variant)
156 {
157  int i = 0;
158  if ( ! (variant & WKT_NO_TYPE) )
159  {
160  stringbuffer_append(sb, "POLYGON"); /* "POLYGON" */
161  dimension_qualifiers_to_wkt_sb((LWGEOM*)poly, sb, variant);
162  }
163  if ( lwpoly_is_empty(poly) )
164  {
165  empty_to_wkt_sb(sb);
166  return;
167  }
168 
169  stringbuffer_append(sb, "(");
170  for ( i = 0; i < poly->nrings; i++ )
171  {
172  if ( i > 0 )
173  stringbuffer_append(sb, ",");
174  ptarray_to_wkt_sb(poly->rings[i], sb, precision, variant);
175  }
176  stringbuffer_append(sb, ")");
177 }
178 
179 /*
180 * CIRCULARSTRING
181 */
182 static void lwcircstring_to_wkt_sb(const LWCIRCSTRING *circ, stringbuffer_t *sb, int precision, uint8_t variant)
183 {
184  if ( ! (variant & WKT_NO_TYPE) )
185  {
186  stringbuffer_append(sb, "CIRCULARSTRING"); /* "CIRCULARSTRING" */
187  dimension_qualifiers_to_wkt_sb((LWGEOM*)circ, sb, variant);
188  }
189  if ( lwcircstring_is_empty(circ) )
190  {
191  empty_to_wkt_sb(sb);
192  return;
193  }
194  ptarray_to_wkt_sb(circ->points, sb, precision, variant);
195 }
196 
197 
198 /*
199 * Multi-points do not wrap their sub-members in parens, unlike other multi-geometries.
200 * MULTPOINT(0 0, 1 1) instead of MULTIPOINT((0 0),(1 1))
201 */
202 static void lwmpoint_to_wkt_sb(const LWMPOINT *mpoint, stringbuffer_t *sb, int precision, uint8_t variant)
203 {
204  int i = 0;
205  if ( ! (variant & WKT_NO_TYPE) )
206  {
207  stringbuffer_append(sb, "MULTIPOINT"); /* "MULTIPOINT" */
208  dimension_qualifiers_to_wkt_sb((LWGEOM*)mpoint, sb, variant);
209  }
210  if ( mpoint->ngeoms < 1 )
211  {
212  empty_to_wkt_sb(sb);
213  return;
214  }
215  stringbuffer_append(sb, "(");
216  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
217  for ( i = 0; i < mpoint->ngeoms; i++ )
218  {
219  if ( i > 0 )
220  stringbuffer_append(sb, ",");
221  /* We don't want type strings or parens on our subgeoms */
222  lwpoint_to_wkt_sb(mpoint->geoms[i], sb, precision, variant | WKT_NO_PARENS | WKT_NO_TYPE );
223  }
224  stringbuffer_append(sb, ")");
225 }
226 
227 /*
228 * MULTILINESTRING
229 */
230 static void lwmline_to_wkt_sb(const LWMLINE *mline, stringbuffer_t *sb, int precision, uint8_t variant)
231 {
232  int i = 0;
233 
234  if ( ! (variant & WKT_NO_TYPE) )
235  {
236  stringbuffer_append(sb, "MULTILINESTRING"); /* "MULTILINESTRING" */
237  dimension_qualifiers_to_wkt_sb((LWGEOM*)mline, sb, variant);
238  }
239  if ( mline->ngeoms < 1 )
240  {
241  empty_to_wkt_sb(sb);
242  return;
243  }
244 
245  stringbuffer_append(sb, "(");
246  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
247  for ( i = 0; i < mline->ngeoms; i++ )
248  {
249  if ( i > 0 )
250  stringbuffer_append(sb, ",");
251  /* We don't want type strings on our subgeoms */
252  lwline_to_wkt_sb(mline->geoms[i], sb, precision, variant | WKT_NO_TYPE );
253  }
254  stringbuffer_append(sb, ")");
255 }
256 
257 /*
258 * MULTIPOLYGON
259 */
260 static void lwmpoly_to_wkt_sb(const LWMPOLY *mpoly, stringbuffer_t *sb, int precision, uint8_t variant)
261 {
262  int i = 0;
263 
264  if ( ! (variant & WKT_NO_TYPE) )
265  {
266  stringbuffer_append(sb, "MULTIPOLYGON"); /* "MULTIPOLYGON" */
267  dimension_qualifiers_to_wkt_sb((LWGEOM*)mpoly, sb, variant);
268  }
269  if ( mpoly->ngeoms < 1 )
270  {
271  empty_to_wkt_sb(sb);
272  return;
273  }
274 
275  stringbuffer_append(sb, "(");
276  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
277  for ( i = 0; i < mpoly->ngeoms; i++ )
278  {
279  if ( i > 0 )
280  stringbuffer_append(sb, ",");
281  /* We don't want type strings on our subgeoms */
282  lwpoly_to_wkt_sb(mpoly->geoms[i], sb, precision, variant | WKT_NO_TYPE );
283  }
284  stringbuffer_append(sb, ")");
285 }
286 
287 /*
288 * Compound curves provide type information for their curved sub-geometries
289 * but not their linestring sub-geometries.
290 * COMPOUNDCURVE((0 0, 1 1), CURVESTRING(1 1, 2 2, 3 3))
291 */
292 static void lwcompound_to_wkt_sb(const LWCOMPOUND *comp, stringbuffer_t *sb, int precision, uint8_t variant)
293 {
294  int i = 0;
295 
296  if ( ! (variant & WKT_NO_TYPE) )
297  {
298  stringbuffer_append(sb, "COMPOUNDCURVE"); /* "COMPOUNDCURVE" */
299  dimension_qualifiers_to_wkt_sb((LWGEOM*)comp, sb, variant);
300  }
301  if ( comp->ngeoms < 1 )
302  {
303  empty_to_wkt_sb(sb);
304  return;
305  }
306 
307  stringbuffer_append(sb, "(");
308  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
309  for ( i = 0; i < comp->ngeoms; i++ )
310  {
311  int type = comp->geoms[i]->type;
312  if ( i > 0 )
313  stringbuffer_append(sb, ",");
314  /* Linestring subgeoms don't get type identifiers */
315  if ( type == LINETYPE )
316  {
317  lwline_to_wkt_sb((LWLINE*)comp->geoms[i], sb, precision, variant | WKT_NO_TYPE );
318  }
319  /* But circstring subgeoms *do* get type identifiers */
320  else if ( type == CIRCSTRINGTYPE )
321  {
322  lwcircstring_to_wkt_sb((LWCIRCSTRING*)comp->geoms[i], sb, precision, variant );
323  }
324  else
325  {
326  lwerror("lwcompound_to_wkt_sb: Unknown type recieved %d - %s", type, lwtype_name(type));
327  }
328  }
329  stringbuffer_append(sb, ")");
330 }
331 
332 /*
333 * Curve polygons provide type information for their curved rings
334 * but not their linestring rings.
335 * CURVEPOLYGON((0 0, 1 1, 0 1, 0 0), CURVESTRING(0 0, 1 1, 0 1, 0.5 1, 0 0))
336 */
337 static void lwcurvepoly_to_wkt_sb(const LWCURVEPOLY *cpoly, stringbuffer_t *sb, int precision, uint8_t variant)
338 {
339  int i = 0;
340 
341  if ( ! (variant & WKT_NO_TYPE) )
342  {
343  stringbuffer_append(sb, "CURVEPOLYGON"); /* "CURVEPOLYGON" */
344  dimension_qualifiers_to_wkt_sb((LWGEOM*)cpoly, sb, variant);
345  }
346  if ( cpoly->nrings < 1 )
347  {
348  empty_to_wkt_sb(sb);
349  return;
350  }
351  stringbuffer_append(sb, "(");
352  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
353  for ( i = 0; i < cpoly->nrings; i++ )
354  {
355  int type = cpoly->rings[i]->type;
356  if ( i > 0 )
357  stringbuffer_append(sb, ",");
358  switch (type)
359  {
360  case LINETYPE:
361  /* Linestring subgeoms don't get type identifiers */
362  lwline_to_wkt_sb((LWLINE*)cpoly->rings[i], sb, precision, variant | WKT_NO_TYPE );
363  break;
364  case CIRCSTRINGTYPE:
365  /* But circstring subgeoms *do* get type identifiers */
366  lwcircstring_to_wkt_sb((LWCIRCSTRING*)cpoly->rings[i], sb, precision, variant );
367  break;
368  case COMPOUNDTYPE:
369  /* And compoundcurve subgeoms *do* get type identifiers */
370  lwcompound_to_wkt_sb((LWCOMPOUND*)cpoly->rings[i], sb, precision, variant );
371  break;
372  default:
373  lwerror("lwcurvepoly_to_wkt_sb: Unknown type recieved %d - %s", type, lwtype_name(type));
374  }
375  }
376  stringbuffer_append(sb, ")");
377 }
378 
379 
380 /*
381 * Multi-curves provide type information for their curved sub-geometries
382 * but not their linear sub-geometries.
383 * MULTICURVE((0 0, 1 1), CURVESTRING(0 0, 1 1, 2 2))
384 */
385 static void lwmcurve_to_wkt_sb(const LWMCURVE *mcurv, stringbuffer_t *sb, int precision, uint8_t variant)
386 {
387  int i = 0;
388 
389  if ( ! (variant & WKT_NO_TYPE) )
390  {
391  stringbuffer_append(sb, "MULTICURVE"); /* "MULTICURVE" */
392  dimension_qualifiers_to_wkt_sb((LWGEOM*)mcurv, sb, variant);
393  }
394  if ( mcurv->ngeoms < 1 )
395  {
396  empty_to_wkt_sb(sb);
397  return;
398  }
399  stringbuffer_append(sb, "(");
400  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
401  for ( i = 0; i < mcurv->ngeoms; i++ )
402  {
403  int type = mcurv->geoms[i]->type;
404  if ( i > 0 )
405  stringbuffer_append(sb, ",");
406  switch (type)
407  {
408  case LINETYPE:
409  /* Linestring subgeoms don't get type identifiers */
410  lwline_to_wkt_sb((LWLINE*)mcurv->geoms[i], sb, precision, variant | WKT_NO_TYPE );
411  break;
412  case CIRCSTRINGTYPE:
413  /* But circstring subgeoms *do* get type identifiers */
414  lwcircstring_to_wkt_sb((LWCIRCSTRING*)mcurv->geoms[i], sb, precision, variant );
415  break;
416  case COMPOUNDTYPE:
417  /* And compoundcurve subgeoms *do* get type identifiers */
418  lwcompound_to_wkt_sb((LWCOMPOUND*)mcurv->geoms[i], sb, precision, variant );
419  break;
420  default:
421  lwerror("lwmcurve_to_wkt_sb: Unknown type recieved %d - %s", type, lwtype_name(type));
422  }
423  }
424  stringbuffer_append(sb, ")");
425 }
426 
427 
428 /*
429 * Multi-surfaces provide type information for their curved sub-geometries
430 * but not their linear sub-geometries.
431 * MULTISURFACE(((0 0, 1 1, 1 0, 0 0)), CURVEPOLYGON(CURVESTRING(0 0, 1 1, 2 2, 0 1, 0 0)))
432 */
433 static void lwmsurface_to_wkt_sb(const LWMSURFACE *msurf, stringbuffer_t *sb, int precision, uint8_t variant)
434 {
435  int i = 0;
436 
437  if ( ! (variant & WKT_NO_TYPE) )
438  {
439  stringbuffer_append(sb, "MULTISURFACE"); /* "MULTISURFACE" */
440  dimension_qualifiers_to_wkt_sb((LWGEOM*)msurf, sb, variant);
441  }
442  if ( msurf->ngeoms < 1 )
443  {
444  empty_to_wkt_sb(sb);
445  return;
446  }
447  stringbuffer_append(sb, "(");
448  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
449  for ( i = 0; i < msurf->ngeoms; i++ )
450  {
451  int type = msurf->geoms[i]->type;
452  if ( i > 0 )
453  stringbuffer_append(sb, ",");
454  switch (type)
455  {
456  case POLYGONTYPE:
457  /* Linestring subgeoms don't get type identifiers */
458  lwpoly_to_wkt_sb((LWPOLY*)msurf->geoms[i], sb, precision, variant | WKT_NO_TYPE );
459  break;
460  case CURVEPOLYTYPE:
461  /* But circstring subgeoms *do* get type identifiers */
462  lwcurvepoly_to_wkt_sb((LWCURVEPOLY*)msurf->geoms[i], sb, precision, variant);
463  break;
464  default:
465  lwerror("lwmsurface_to_wkt_sb: Unknown type recieved %d - %s", type, lwtype_name(type));
466  }
467  }
468  stringbuffer_append(sb, ")");
469 }
470 
471 /*
472 * Geometry collections provide type information for all their curved sub-geometries
473 * but not their linear sub-geometries.
474 * GEOMETRYCOLLECTION(POLYGON((0 0, 1 1, 1 0, 0 0)), CURVEPOLYGON(CURVESTRING(0 0, 1 1, 2 2, 0 1, 0 0)))
475 */
476 static void lwcollection_to_wkt_sb(const LWCOLLECTION *collection, stringbuffer_t *sb, int precision, uint8_t variant)
477 {
478  int i = 0;
479 
480  if ( ! (variant & WKT_NO_TYPE) )
481  {
482  stringbuffer_append(sb, "GEOMETRYCOLLECTION"); /* "GEOMETRYCOLLECTION" */
483  dimension_qualifiers_to_wkt_sb((LWGEOM*)collection, sb, variant);
484  }
485  if ( collection->ngeoms < 1 )
486  {
487  empty_to_wkt_sb(sb);
488  return;
489  }
490  stringbuffer_append(sb, "(");
491  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are children */
492  for ( i = 0; i < collection->ngeoms; i++ )
493  {
494  if ( i > 0 )
495  stringbuffer_append(sb, ",");
496  lwgeom_to_wkt_sb((LWGEOM*)collection->geoms[i], sb, precision, variant );
497  }
498  stringbuffer_append(sb, ")");
499 }
500 
501 /*
502 * TRIANGLE
503 */
504 static void lwtriangle_to_wkt_sb(const LWTRIANGLE *tri, stringbuffer_t *sb, int precision, uint8_t variant)
505 {
506  if ( ! (variant & WKT_NO_TYPE) )
507  {
508  stringbuffer_append(sb, "TRIANGLE"); /* "TRIANGLE" */
509  dimension_qualifiers_to_wkt_sb((LWGEOM*)tri, sb, variant);
510  }
511  if ( lwtriangle_is_empty(tri) )
512  {
513  empty_to_wkt_sb(sb);
514  return;
515  }
516 
517  stringbuffer_append(sb, "("); /* Triangles have extraneous brackets */
518  ptarray_to_wkt_sb(tri->points, sb, precision, variant);
519  stringbuffer_append(sb, ")");
520 }
521 
522 /*
523 * TIN
524 */
525 static void lwtin_to_wkt_sb(const LWTIN *tin, stringbuffer_t *sb, int precision, uint8_t variant)
526 {
527  int i = 0;
528 
529  if ( ! (variant & WKT_NO_TYPE) )
530  {
531  stringbuffer_append(sb, "TIN"); /* "TIN" */
532  dimension_qualifiers_to_wkt_sb((LWGEOM*)tin, sb, variant);
533  }
534  if ( tin->ngeoms < 1 )
535  {
536  empty_to_wkt_sb(sb);
537  return;
538  }
539 
540  stringbuffer_append(sb, "(");
541  for ( i = 0; i < tin->ngeoms; i++ )
542  {
543  if ( i > 0 )
544  stringbuffer_append(sb, ",");
545  /* We don't want type strings on our subgeoms */
546  lwtriangle_to_wkt_sb(tin->geoms[i], sb, precision, variant | WKT_NO_TYPE );
547  }
548  stringbuffer_append(sb, ")");
549 }
550 
551 /*
552 * POLYHEDRALSURFACE
553 */
554 static void lwpsurface_to_wkt_sb(const LWPSURFACE *psurf, stringbuffer_t *sb, int precision, uint8_t variant)
555 {
556  int i = 0;
557 
558  if ( ! (variant & WKT_NO_TYPE) )
559  {
560  stringbuffer_append(sb, "POLYHEDRALSURFACE"); /* "POLYHEDRALSURFACE" */
561  dimension_qualifiers_to_wkt_sb((LWGEOM*)psurf, sb, variant);
562  }
563  if ( psurf->ngeoms < 1 )
564  {
565  empty_to_wkt_sb(sb);
566  return;
567  }
568 
569  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
570 
571  stringbuffer_append(sb, "(");
572  for ( i = 0; i < psurf->ngeoms; i++ )
573  {
574  if ( i > 0 )
575  stringbuffer_append(sb, ",");
576  /* We don't want type strings on our subgeoms */
577  lwpoly_to_wkt_sb(psurf->geoms[i], sb, precision, variant | WKT_NO_TYPE );
578  }
579  stringbuffer_append(sb, ")");
580 }
581 
582 
583 /*
584 * Generic GEOMETRY
585 */
586 static void lwgeom_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, int precision, uint8_t variant)
587 {
588  LWDEBUGF(4, "lwgeom_to_wkt_sb: type %s, hasz %d, hasm %d",
589  lwtype_name(geom->type), (geom->type),
590  FLAGS_GET_Z(geom->flags)?1:0, FLAGS_GET_M(geom->flags)?1:0);
591 
592  switch (geom->type)
593  {
594  case POINTTYPE:
595  lwpoint_to_wkt_sb((LWPOINT*)geom, sb, precision, variant);
596  break;
597  case LINETYPE:
598  lwline_to_wkt_sb((LWLINE*)geom, sb, precision, variant);
599  break;
600  case POLYGONTYPE:
601  lwpoly_to_wkt_sb((LWPOLY*)geom, sb, precision, variant);
602  break;
603  case MULTIPOINTTYPE:
604  lwmpoint_to_wkt_sb((LWMPOINT*)geom, sb, precision, variant);
605  break;
606  case MULTILINETYPE:
607  lwmline_to_wkt_sb((LWMLINE*)geom, sb, precision, variant);
608  break;
609  case MULTIPOLYGONTYPE:
610  lwmpoly_to_wkt_sb((LWMPOLY*)geom, sb, precision, variant);
611  break;
612  case COLLECTIONTYPE:
613  lwcollection_to_wkt_sb((LWCOLLECTION*)geom, sb, precision, variant);
614  break;
615  case CIRCSTRINGTYPE:
616  lwcircstring_to_wkt_sb((LWCIRCSTRING*)geom, sb, precision, variant);
617  break;
618  case COMPOUNDTYPE:
619  lwcompound_to_wkt_sb((LWCOMPOUND*)geom, sb, precision, variant);
620  break;
621  case CURVEPOLYTYPE:
622  lwcurvepoly_to_wkt_sb((LWCURVEPOLY*)geom, sb, precision, variant);
623  break;
624  case MULTICURVETYPE:
625  lwmcurve_to_wkt_sb((LWMCURVE*)geom, sb, precision, variant);
626  break;
627  case MULTISURFACETYPE:
628  lwmsurface_to_wkt_sb((LWMSURFACE*)geom, sb, precision, variant);
629  break;
630  case TRIANGLETYPE:
631  lwtriangle_to_wkt_sb((LWTRIANGLE*)geom, sb, precision, variant);
632  break;
633  case TINTYPE:
634  lwtin_to_wkt_sb((LWTIN*)geom, sb, precision, variant);
635  break;
637  lwpsurface_to_wkt_sb((LWPSURFACE*)geom, sb, precision, variant);
638  break;
639  default:
640  lwerror("lwgeom_to_wkt_sb: Type %d - %s unsupported.",
641  geom->type, lwtype_name(geom->type));
642  }
643 }
644 
655 char* lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
656 {
657  stringbuffer_t *sb;
658  char *str = NULL;
659  if ( geom == NULL )
660  return NULL;
661  sb = stringbuffer_create();
662  /* Extended mode starts with an "SRID=" section for geoms that have one */
663  if ( (variant & WKT_EXTENDED) && lwgeom_has_srid(geom) )
664  {
665  stringbuffer_aprintf(sb, "SRID=%d;", geom->srid);
666  }
667  lwgeom_to_wkt_sb(geom, sb, precision, variant);
668  if ( stringbuffer_getstring(sb) == NULL )
669  {
670  lwerror("Uh oh");
671  return NULL;
672  }
673  str = stringbuffer_getstringcopy(sb);
674  if ( size_out )
675  *size_out = stringbuffer_getlength(sb) + 1;
677  return str;
678 }
679 
int ngeoms
Definition: liblwgeom.h:502
#define LINETYPE
Definition: liblwgeom.h:61
static void lwtin_to_wkt_sb(const LWTIN *tin, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:525
static void lwmcurve_to_wkt_sb(const LWMCURVE *mcurv, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:385
#define WKT_NO_PARENS
POINTARRAY * points
Definition: liblwgeom.h:389
#define MULTICURVETYPE
Definition: liblwgeom.h:70
int lwgeom_has_srid(const LWGEOM *geom)
Return true or false depending on whether a geometry has a valid SRID set.
Definition: lwgeom.c:1272
stringbuffer_t * stringbuffer_create(void)
Allocate a new stringbuffer_t.
Definition: stringbuffer.c:47
LWGEOM ** rings
Definition: liblwgeom.h:491
int npoints
Definition: liblwgeom.h:327
#define POLYGONTYPE
Definition: liblwgeom.h:62
static void lwpsurface_to_wkt_sb(const LWPSURFACE *psurf, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:554
char * stringbuffer_getstringcopy(stringbuffer_t *s)
Returns a newly allocated string large enough to contain the current state of the string...
Definition: stringbuffer.c:154
uint8_t flags
Definition: liblwgeom.h:353
#define CURVEPOLYTYPE
Definition: liblwgeom.h:69
#define COMPOUNDTYPE
Definition: liblwgeom.h:68
#define MULTIPOINTTYPE
Definition: liblwgeom.h:63
static void lwcurvepoly_to_wkt_sb(const LWCURVEPOLY *cpoly, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:337
#define TRIANGLETYPE
Definition: liblwgeom.h:73
static void dimension_qualifiers_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, uint8_t variant)
Definition: lwout_wkt.c:25
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:72
LWPOLY ** geoms
Definition: liblwgeom.h:530
static void lwcircstring_to_wkt_sb(const LWCIRCSTRING *circ, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:182
LWGEOM ** geoms
Definition: liblwgeom.h:478
static void lwtriangle_to_wkt_sb(const LWTRIANGLE *tri, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:504
POINTARRAY * point
Definition: liblwgeom.h:367
int32_t srid
Definition: liblwgeom.h:355
int ngeoms
Definition: liblwgeom.h:437
static void lwpoly_to_wkt_sb(const LWPOLY *poly, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:155
int stringbuffer_aprintf(stringbuffer_t *s, const char *fmt,...)
Appends a formatted string to the current string buffer, using the format and argument list provided...
Definition: stringbuffer.c:247
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:67
int stringbuffer_getlength(stringbuffer_t *s)
Returns the length of the current string, not including the null terminator (same behavior as strlen(...
Definition: stringbuffer.c:168
static void lwmline_to_wkt_sb(const LWMLINE *mline, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:230
int lwtriangle_is_empty(const LWTRIANGLE *triangle)
Definition: lwtriangle.c:162
static void lwmpoint_to_wkt_sb(const LWMPOINT *mpoint, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:202
int ngeoms
Definition: liblwgeom.h:541
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:164
#define WKT_ISO
Definition: liblwgeom.h:1776
uint8_t flags
Definition: liblwgeom.h:325
LWPOLY ** geoms
Definition: liblwgeom.h:452
LWGEOM ** geoms
Definition: liblwgeom.h:465
#define TINTYPE
Definition: liblwgeom.h:74
LWTRIANGLE ** geoms
Definition: liblwgeom.h:543
uint8_t * getPoint_internal(const POINTARRAY *pa, int n)
Definition: ptarray.c:1645
POINTARRAY ** rings
Definition: liblwgeom.h:413
#define WKT_IS_CHILD
#define WKT_NO_TYPE
Well-Known Text (WKT) Output Variant Types.
LWPOINT ** geoms
Definition: liblwgeom.h:426
int lwpoly_is_empty(const LWPOLY *poly)
Definition: lwpoly.c:327
int nrings
Definition: liblwgeom.h:411
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:106
static void lwmpoly_to_wkt_sb(const LWMPOLY *mpoly, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:260
static void ptarray_to_wkt_sb(const POINTARRAY *ptarray, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:69
int ngeoms
Definition: liblwgeom.h:450
int lwcircstring_is_empty(const LWCIRCSTRING *circ)
Definition: lwcircstring.c:263
static void lwgeom_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:586
static void empty_to_wkt_sb(stringbuffer_t *sb)
Definition: lwout_wkt.c:55
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:65
int lwline_is_empty(const LWLINE *line)
Definition: lwline.c:464
LWLINE ** geoms
Definition: liblwgeom.h:439
void stringbuffer_append(stringbuffer_t *s, const char *a)
Append the specified string to the stringbuffer_t.
Definition: stringbuffer.c:128
#define WKT_EXTENDED
Definition: liblwgeom.h:1778
int ngeoms
Definition: liblwgeom.h:515
void stringbuffer_destroy(stringbuffer_t *s)
Free the stringbuffer_t and all memory managed within it.
Definition: stringbuffer.c:72
static void lwcompound_to_wkt_sb(const LWCOMPOUND *comp, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:292
#define MULTISURFACETYPE
Definition: liblwgeom.h:71
LWGEOM ** geoms
Definition: liblwgeom.h:517
static void lwpoint_to_wkt_sb(const LWPOINT *pt, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:116
int ngeoms
Definition: liblwgeom.h:476
LWGEOM ** geoms
Definition: liblwgeom.h:504
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:60
static void lwcollection_to_wkt_sb(const LWCOLLECTION *collection, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:476
int lwpoint_is_empty(const LWPOINT *point)
Definition: lwpoint.c:258
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:107
uint8_t type
Definition: liblwgeom.h:352
const char * stringbuffer_getstring(stringbuffer_t *s)
Returns a reference to the internal string being managed by the stringbuffer.
Definition: stringbuffer.c:143
POINTARRAY * points
Definition: liblwgeom.h:400
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:655
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:67
char stringbuffer_lastchar(stringbuffer_t *s)
Return the last character in the buffer.
Definition: stringbuffer.c:116
#define MULTILINETYPE
Definition: liblwgeom.h:64
int ngeoms
Definition: liblwgeom.h:424
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:55
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:118
int ngeoms
Definition: liblwgeom.h:528
static void lwmsurface_to_wkt_sb(const LWMSURFACE *msurf, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:433
#define COLLECTIONTYPE
Definition: liblwgeom.h:66
POINTARRAY * points
Definition: liblwgeom.h:378
static void lwline_to_wkt_sb(const LWLINE *line, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:136