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