PostGIS  3.0.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  static size_t buffer_size = 128;
89  char coord[buffer_size];
90 
91  /* ISO and extended formats include all dimensions */
92  if ( variant & ( WKT_ISO | WKT_EXTENDED ) )
93  dimensions = FLAGS_NDIMS(ptarray->flags);
94 
95  /* Opening paren? */
96  if ( ! (variant & WKT_NO_PARENS) )
97  stringbuffer_append(sb, "(");
98 
99  /* Digits and commas */
100  for (i = 0; i < ptarray->npoints; i++)
101  {
102  double *dbl_ptr = (double*)getPoint_internal(ptarray, i);
103 
104  /* Commas before ever coord but the first */
105  if ( i > 0 )
106  stringbuffer_append(sb, ",");
107 
108  for (j = 0; j < dimensions; j++)
109  {
110  /* Spaces before every ordinate but the first */
111  if ( j > 0 )
112  stringbuffer_append(sb, " ");
113  lwprint_double(dbl_ptr[j],
114  precision,
115  coord,
116  buffer_size);
117  stringbuffer_append(sb, coord);
118  }
119  }
120 
121  /* Closing paren? */
122  if ( ! (variant & WKT_NO_PARENS) )
123  stringbuffer_append(sb, ")");
124 }
125 
126 /*
127 * A four-dimensional point will have different outputs depending on variant.
128 * ISO: POINT ZM (0 0 0 0)
129 * Extended: POINT(0 0 0 0)
130 * OGC: POINT(0 0)
131 * A three-dimensional m-point will have different outputs too.
132 * ISO: POINT M (0 0 0)
133 * Extended: POINTM(0 0 0)
134 * OGC: POINT(0 0)
135 */
137 {
138  if ( ! (variant & WKT_NO_TYPE) )
139  {
140  stringbuffer_append(sb, "POINT"); /* "POINT" */
141  dimension_qualifiers_to_wkt_sb((LWGEOM*)pt, sb, variant);
142  }
143 
144  if ( lwpoint_is_empty(pt) )
145  {
146  empty_to_wkt_sb(sb);
147  return;
148  }
149 
150  ptarray_to_wkt_sb(pt->point, sb, precision, variant);
151 }
152 
153 /*
154 * LINESTRING(0 0 0, 1 1 1)
155 */
156 static void lwline_to_wkt_sb(const LWLINE *line, stringbuffer_t *sb, int precision, uint8_t variant)
157 {
158  if ( ! (variant & WKT_NO_TYPE) )
159  {
160  stringbuffer_append(sb, "LINESTRING"); /* "LINESTRING" */
161  dimension_qualifiers_to_wkt_sb((LWGEOM*)line, sb, variant);
162  }
163  if ( lwline_is_empty(line) )
164  {
165  empty_to_wkt_sb(sb);
166  return;
167  }
168 
169  ptarray_to_wkt_sb(line->points, sb, precision, variant);
170 }
171 
172 /*
173 * POLYGON(0 0 1, 1 0 1, 1 1 1, 0 1 1, 0 0 1)
174 */
175 static void lwpoly_to_wkt_sb(const LWPOLY *poly, stringbuffer_t *sb, int precision, uint8_t variant)
176 {
177  uint32_t i = 0;
178  if ( ! (variant & WKT_NO_TYPE) )
179  {
180  stringbuffer_append(sb, "POLYGON"); /* "POLYGON" */
181  dimension_qualifiers_to_wkt_sb((LWGEOM*)poly, sb, variant);
182  }
183  if ( lwpoly_is_empty(poly) )
184  {
185  empty_to_wkt_sb(sb);
186  return;
187  }
188 
189  stringbuffer_append(sb, "(");
190  for ( i = 0; i < poly->nrings; i++ )
191  {
192  if ( i > 0 )
193  stringbuffer_append(sb, ",");
194  ptarray_to_wkt_sb(poly->rings[i], sb, precision, variant);
195  }
196  stringbuffer_append(sb, ")");
197 }
198 
199 /*
200 * CIRCULARSTRING
201 */
203 {
204  if ( ! (variant & WKT_NO_TYPE) )
205  {
206  stringbuffer_append(sb, "CIRCULARSTRING"); /* "CIRCULARSTRING" */
207  dimension_qualifiers_to_wkt_sb((LWGEOM*)circ, sb, variant);
208  }
209  if ( lwcircstring_is_empty(circ) )
210  {
211  empty_to_wkt_sb(sb);
212  return;
213  }
214  ptarray_to_wkt_sb(circ->points, sb, precision, variant);
215 }
216 
217 
218 /*
219 * Multi-points do not wrap their sub-members in parens, unlike other multi-geometries.
220 * MULTPOINT(0 0, 1 1) instead of MULTIPOINT((0 0),(1 1))
221 */
222 static void lwmpoint_to_wkt_sb(const LWMPOINT *mpoint, stringbuffer_t *sb, int precision, uint8_t variant)
223 {
224  uint32_t i = 0;
225  if ( ! (variant & WKT_NO_TYPE) )
226  {
227  stringbuffer_append(sb, "MULTIPOINT"); /* "MULTIPOINT" */
228  dimension_qualifiers_to_wkt_sb((LWGEOM*)mpoint, sb, variant);
229  }
230  if ( mpoint->ngeoms < 1 )
231  {
232  empty_to_wkt_sb(sb);
233  return;
234  }
235  stringbuffer_append(sb, "(");
236  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
237  for ( i = 0; i < mpoint->ngeoms; i++ )
238  {
239  if ( i > 0 )
240  stringbuffer_append(sb, ",");
241  /* We don't want type strings or parens on our subgeoms */
242  lwpoint_to_wkt_sb(mpoint->geoms[i], sb, precision, variant | WKT_NO_PARENS | WKT_NO_TYPE );
243  }
244  stringbuffer_append(sb, ")");
245 }
246 
247 /*
248 * MULTILINESTRING
249 */
250 static void lwmline_to_wkt_sb(const LWMLINE *mline, stringbuffer_t *sb, int precision, uint8_t variant)
251 {
252  uint32_t i = 0;
253 
254  if ( ! (variant & WKT_NO_TYPE) )
255  {
256  stringbuffer_append(sb, "MULTILINESTRING"); /* "MULTILINESTRING" */
257  dimension_qualifiers_to_wkt_sb((LWGEOM*)mline, sb, variant);
258  }
259  if ( mline->ngeoms < 1 )
260  {
261  empty_to_wkt_sb(sb);
262  return;
263  }
264 
265  stringbuffer_append(sb, "(");
266  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
267  for ( i = 0; i < mline->ngeoms; i++ )
268  {
269  if ( i > 0 )
270  stringbuffer_append(sb, ",");
271  /* We don't want type strings on our subgeoms */
272  lwline_to_wkt_sb(mline->geoms[i], sb, precision, variant | WKT_NO_TYPE );
273  }
274  stringbuffer_append(sb, ")");
275 }
276 
277 /*
278 * MULTIPOLYGON
279 */
280 static void lwmpoly_to_wkt_sb(const LWMPOLY *mpoly, stringbuffer_t *sb, int precision, uint8_t variant)
281 {
282  uint32_t i = 0;
283 
284  if ( ! (variant & WKT_NO_TYPE) )
285  {
286  stringbuffer_append(sb, "MULTIPOLYGON"); /* "MULTIPOLYGON" */
287  dimension_qualifiers_to_wkt_sb((LWGEOM*)mpoly, sb, variant);
288  }
289  if ( mpoly->ngeoms < 1 )
290  {
291  empty_to_wkt_sb(sb);
292  return;
293  }
294 
295  stringbuffer_append(sb, "(");
296  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
297  for ( i = 0; i < mpoly->ngeoms; i++ )
298  {
299  if ( i > 0 )
300  stringbuffer_append(sb, ",");
301  /* We don't want type strings on our subgeoms */
302  lwpoly_to_wkt_sb(mpoly->geoms[i], sb, precision, variant | WKT_NO_TYPE );
303  }
304  stringbuffer_append(sb, ")");
305 }
306 
307 /*
308 * Compound curves provide type information for their curved sub-geometries
309 * but not their linestring sub-geometries.
310 * COMPOUNDCURVE((0 0, 1 1), CURVESTRING(1 1, 2 2, 3 3))
311 */
313 {
314  uint32_t i = 0;
315 
316  if ( ! (variant & WKT_NO_TYPE) )
317  {
318  stringbuffer_append(sb, "COMPOUNDCURVE"); /* "COMPOUNDCURVE" */
319  dimension_qualifiers_to_wkt_sb((LWGEOM*)comp, sb, variant);
320  }
321  if ( comp->ngeoms < 1 )
322  {
323  empty_to_wkt_sb(sb);
324  return;
325  }
326 
327  stringbuffer_append(sb, "(");
328  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
329  for ( i = 0; i < comp->ngeoms; i++ )
330  {
331  int type = comp->geoms[i]->type;
332  if ( i > 0 )
333  stringbuffer_append(sb, ",");
334  /* Linestring subgeoms don't get type identifiers */
335  if ( type == LINETYPE )
336  {
337  lwline_to_wkt_sb((LWLINE*)comp->geoms[i], sb, precision, variant | WKT_NO_TYPE );
338  }
339  /* But circstring subgeoms *do* get type identifiers */
340  else if ( type == CIRCSTRINGTYPE )
341  {
342  lwcircstring_to_wkt_sb((LWCIRCSTRING*)comp->geoms[i], sb, precision, variant );
343  }
344  else
345  {
346  lwerror("lwcompound_to_wkt_sb: Unknown type received %d - %s", type, lwtype_name(type));
347  }
348  }
349  stringbuffer_append(sb, ")");
350 }
351 
352 /*
353 * Curve polygons provide type information for their curved rings
354 * but not their linestring rings.
355 * CURVEPOLYGON((0 0, 1 1, 0 1, 0 0), CURVESTRING(0 0, 1 1, 0 1, 0.5 1, 0 0))
356 */
358 {
359  uint32_t i = 0;
360 
361  if ( ! (variant & WKT_NO_TYPE) )
362  {
363  stringbuffer_append(sb, "CURVEPOLYGON"); /* "CURVEPOLYGON" */
364  dimension_qualifiers_to_wkt_sb((LWGEOM*)cpoly, sb, variant);
365  }
366  if ( cpoly->nrings < 1 )
367  {
368  empty_to_wkt_sb(sb);
369  return;
370  }
371  stringbuffer_append(sb, "(");
372  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
373  for ( i = 0; i < cpoly->nrings; i++ )
374  {
375  int type = cpoly->rings[i]->type;
376  if ( i > 0 )
377  stringbuffer_append(sb, ",");
378  switch (type)
379  {
380  case LINETYPE:
381  /* Linestring subgeoms don't get type identifiers */
382  lwline_to_wkt_sb((LWLINE*)cpoly->rings[i], sb, precision, variant | WKT_NO_TYPE );
383  break;
384  case CIRCSTRINGTYPE:
385  /* But circstring subgeoms *do* get type identifiers */
386  lwcircstring_to_wkt_sb((LWCIRCSTRING*)cpoly->rings[i], sb, precision, variant );
387  break;
388  case COMPOUNDTYPE:
389  /* And compoundcurve subgeoms *do* get type identifiers */
390  lwcompound_to_wkt_sb((LWCOMPOUND*)cpoly->rings[i], sb, precision, variant );
391  break;
392  default:
393  lwerror("lwcurvepoly_to_wkt_sb: Unknown type received %d - %s", type, lwtype_name(type));
394  }
395  }
396  stringbuffer_append(sb, ")");
397 }
398 
399 
400 /*
401 * Multi-curves provide type information for their curved sub-geometries
402 * but not their linear sub-geometries.
403 * MULTICURVE((0 0, 1 1), CURVESTRING(0 0, 1 1, 2 2))
404 */
406 {
407  uint32_t i = 0;
408 
409  if ( ! (variant & WKT_NO_TYPE) )
410  {
411  stringbuffer_append(sb, "MULTICURVE"); /* "MULTICURVE" */
412  dimension_qualifiers_to_wkt_sb((LWGEOM*)mcurv, sb, variant);
413  }
414  if ( mcurv->ngeoms < 1 )
415  {
416  empty_to_wkt_sb(sb);
417  return;
418  }
419  stringbuffer_append(sb, "(");
420  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
421  for ( i = 0; i < mcurv->ngeoms; i++ )
422  {
423  int type = mcurv->geoms[i]->type;
424  if ( i > 0 )
425  stringbuffer_append(sb, ",");
426  switch (type)
427  {
428  case LINETYPE:
429  /* Linestring subgeoms don't get type identifiers */
430  lwline_to_wkt_sb((LWLINE*)mcurv->geoms[i], sb, precision, variant | WKT_NO_TYPE );
431  break;
432  case CIRCSTRINGTYPE:
433  /* But circstring subgeoms *do* get type identifiers */
434  lwcircstring_to_wkt_sb((LWCIRCSTRING*)mcurv->geoms[i], sb, precision, variant );
435  break;
436  case COMPOUNDTYPE:
437  /* And compoundcurve subgeoms *do* get type identifiers */
438  lwcompound_to_wkt_sb((LWCOMPOUND*)mcurv->geoms[i], sb, precision, variant );
439  break;
440  default:
441  lwerror("lwmcurve_to_wkt_sb: Unknown type received %d - %s", type, lwtype_name(type));
442  }
443  }
444  stringbuffer_append(sb, ")");
445 }
446 
447 
448 /*
449 * Multi-surfaces provide type information for their curved sub-geometries
450 * but not their linear sub-geometries.
451 * MULTISURFACE(((0 0, 1 1, 1 0, 0 0)), CURVEPOLYGON(CURVESTRING(0 0, 1 1, 2 2, 0 1, 0 0)))
452 */
454 {
455  uint32_t i = 0;
456 
457  if ( ! (variant & WKT_NO_TYPE) )
458  {
459  stringbuffer_append(sb, "MULTISURFACE"); /* "MULTISURFACE" */
460  dimension_qualifiers_to_wkt_sb((LWGEOM*)msurf, sb, variant);
461  }
462  if ( msurf->ngeoms < 1 )
463  {
464  empty_to_wkt_sb(sb);
465  return;
466  }
467  stringbuffer_append(sb, "(");
468  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
469  for ( i = 0; i < msurf->ngeoms; i++ )
470  {
471  int type = msurf->geoms[i]->type;
472  if ( i > 0 )
473  stringbuffer_append(sb, ",");
474  switch (type)
475  {
476  case POLYGONTYPE:
477  /* Linestring subgeoms don't get type identifiers */
478  lwpoly_to_wkt_sb((LWPOLY*)msurf->geoms[i], sb, precision, variant | WKT_NO_TYPE );
479  break;
480  case CURVEPOLYTYPE:
481  /* But circstring subgeoms *do* get type identifiers */
482  lwcurvepoly_to_wkt_sb((LWCURVEPOLY*)msurf->geoms[i], sb, precision, variant);
483  break;
484  default:
485  lwerror("lwmsurface_to_wkt_sb: Unknown type received %d - %s", type, lwtype_name(type));
486  }
487  }
488  stringbuffer_append(sb, ")");
489 }
490 
491 /*
492 * Geometry collections provide type information for all their curved sub-geometries
493 * but not their linear sub-geometries.
494 * GEOMETRYCOLLECTION(POLYGON((0 0, 1 1, 1 0, 0 0)), CURVEPOLYGON(CURVESTRING(0 0, 1 1, 2 2, 0 1, 0 0)))
495 */
497 {
498  uint32_t i = 0;
499 
500  if ( ! (variant & WKT_NO_TYPE) )
501  {
502  stringbuffer_append(sb, "GEOMETRYCOLLECTION"); /* "GEOMETRYCOLLECTION" */
503  dimension_qualifiers_to_wkt_sb((LWGEOM*)collection, sb, variant);
504  }
505  if ( collection->ngeoms < 1 )
506  {
507  empty_to_wkt_sb(sb);
508  return;
509  }
510  stringbuffer_append(sb, "(");
511  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are children */
512  for ( i = 0; i < collection->ngeoms; i++ )
513  {
514  if ( i > 0 )
515  stringbuffer_append(sb, ",");
516  lwgeom_to_wkt_sb((LWGEOM*)collection->geoms[i], sb, precision, variant );
517  }
518  stringbuffer_append(sb, ")");
519 }
520 
521 /*
522 * TRIANGLE
523 */
525 {
526  if ( ! (variant & WKT_NO_TYPE) )
527  {
528  stringbuffer_append(sb, "TRIANGLE"); /* "TRIANGLE" */
529  dimension_qualifiers_to_wkt_sb((LWGEOM*)tri, sb, variant);
530  }
531  if ( lwtriangle_is_empty(tri) )
532  {
533  empty_to_wkt_sb(sb);
534  return;
535  }
536 
537  stringbuffer_append(sb, "("); /* Triangles have extraneous brackets */
538  ptarray_to_wkt_sb(tri->points, sb, precision, variant);
539  stringbuffer_append(sb, ")");
540 }
541 
542 /*
543 * TIN
544 */
545 static void lwtin_to_wkt_sb(const LWTIN *tin, stringbuffer_t *sb, int precision, uint8_t variant)
546 {
547  uint32_t i = 0;
548 
549  if ( ! (variant & WKT_NO_TYPE) )
550  {
551  stringbuffer_append(sb, "TIN"); /* "TIN" */
552  dimension_qualifiers_to_wkt_sb((LWGEOM*)tin, sb, variant);
553  }
554  if ( tin->ngeoms < 1 )
555  {
556  empty_to_wkt_sb(sb);
557  return;
558  }
559 
560  stringbuffer_append(sb, "(");
561  for ( i = 0; i < tin->ngeoms; i++ )
562  {
563  if ( i > 0 )
564  stringbuffer_append(sb, ",");
565  /* We don't want type strings on our subgeoms */
566  lwtriangle_to_wkt_sb(tin->geoms[i], sb, precision, variant | WKT_NO_TYPE );
567  }
568  stringbuffer_append(sb, ")");
569 }
570 
571 /*
572 * POLYHEDRALSURFACE
573 */
575 {
576  uint32_t i = 0;
577 
578  if ( ! (variant & WKT_NO_TYPE) )
579  {
580  stringbuffer_append(sb, "POLYHEDRALSURFACE"); /* "POLYHEDRALSURFACE" */
581  dimension_qualifiers_to_wkt_sb((LWGEOM*)psurf, sb, variant);
582  }
583  if ( psurf->ngeoms < 1 )
584  {
585  empty_to_wkt_sb(sb);
586  return;
587  }
588 
589  variant = variant | WKT_IS_CHILD; /* Inform the sub-geometries they are childre */
590 
591  stringbuffer_append(sb, "(");
592  for ( i = 0; i < psurf->ngeoms; i++ )
593  {
594  if ( i > 0 )
595  stringbuffer_append(sb, ",");
596  /* We don't want type strings on our subgeoms */
597  lwpoly_to_wkt_sb(psurf->geoms[i], sb, precision, variant | WKT_NO_TYPE );
598  }
599  stringbuffer_append(sb, ")");
600 }
601 
602 
603 /*
604 * Generic GEOMETRY
605 */
606 static void lwgeom_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, int precision, uint8_t variant)
607 {
608  LWDEBUGF(4, "lwgeom_to_wkt_sb: type %s, hasz %d, hasm %d",
609  lwtype_name(geom->type), (geom->type),
610  FLAGS_GET_Z(geom->flags)?1:0, FLAGS_GET_M(geom->flags)?1:0);
611 
612  switch (geom->type)
613  {
614  case POINTTYPE:
615  lwpoint_to_wkt_sb((LWPOINT*)geom, sb, precision, variant);
616  break;
617  case LINETYPE:
618  lwline_to_wkt_sb((LWLINE*)geom, sb, precision, variant);
619  break;
620  case POLYGONTYPE:
621  lwpoly_to_wkt_sb((LWPOLY*)geom, sb, precision, variant);
622  break;
623  case MULTIPOINTTYPE:
624  lwmpoint_to_wkt_sb((LWMPOINT*)geom, sb, precision, variant);
625  break;
626  case MULTILINETYPE:
627  lwmline_to_wkt_sb((LWMLINE*)geom, sb, precision, variant);
628  break;
629  case MULTIPOLYGONTYPE:
630  lwmpoly_to_wkt_sb((LWMPOLY*)geom, sb, precision, variant);
631  break;
632  case COLLECTIONTYPE:
633  lwcollection_to_wkt_sb((LWCOLLECTION*)geom, sb, precision, variant);
634  break;
635  case CIRCSTRINGTYPE:
636  lwcircstring_to_wkt_sb((LWCIRCSTRING*)geom, sb, precision, variant);
637  break;
638  case COMPOUNDTYPE:
639  lwcompound_to_wkt_sb((LWCOMPOUND*)geom, sb, precision, variant);
640  break;
641  case CURVEPOLYTYPE:
642  lwcurvepoly_to_wkt_sb((LWCURVEPOLY*)geom, sb, precision, variant);
643  break;
644  case MULTICURVETYPE:
645  lwmcurve_to_wkt_sb((LWMCURVE*)geom, sb, precision, variant);
646  break;
647  case MULTISURFACETYPE:
648  lwmsurface_to_wkt_sb((LWMSURFACE*)geom, sb, precision, variant);
649  break;
650  case TRIANGLETYPE:
651  lwtriangle_to_wkt_sb((LWTRIANGLE*)geom, sb, precision, variant);
652  break;
653  case TINTYPE:
654  lwtin_to_wkt_sb((LWTIN*)geom, sb, precision, variant);
655  break;
657  lwpsurface_to_wkt_sb((LWPSURFACE*)geom, sb, precision, variant);
658  break;
659  default:
660  lwerror("lwgeom_to_wkt_sb: Type %d - %s unsupported.",
661  geom->type, lwtype_name(geom->type));
662  }
663 }
664 
676 char* lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
677 {
678  stringbuffer_t *sb;
679  char *str = NULL;
680  if ( geom == NULL )
681  return NULL;
682  sb = stringbuffer_create();
683  /* Extended mode starts with an "SRID=" section for geoms that have one */
684  if ( (variant & WKT_EXTENDED) && lwgeom_has_srid(geom) )
685  {
686  stringbuffer_aprintf(sb, "SRID=%d;", geom->srid);
687  }
688  lwgeom_to_wkt_sb(geom, sb, precision, variant);
689  if ( stringbuffer_getstring(sb) == NULL )
690  {
691  lwerror("Uh oh");
692  return NULL;
693  }
694  str = stringbuffer_getstringcopy(sb);
695  if ( size_out )
696  *size_out = stringbuffer_getlength(sb) + 1;
698  return str;
699 }
700 
#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:545
int lwprint_double(double d, int maxdd, char *buf, size_t bufsize)
Definition: lwprint.c:490
static void lwmcurve_to_wkt_sb(const LWMCURVE *mcurv, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:405
#define WKT_NO_PARENS
POINTARRAY * points
Definition: liblwgeom.h:435
uint32_t ngeoms
Definition: liblwgeom.h:561
#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:1377
uint8_t variant
Definition: cu_in_twkb.c:26
uint32_t ngeoms
Definition: liblwgeom.h:470
stringbuffer_t * stringbuffer_create(void)
Allocate a new stringbuffer_t.
Definition: stringbuffer.c:33
static void stringbuffer_append(stringbuffer_t *s, const char *a)
Append the specified string to the stringbuffer_t.
Definition: stringbuffer.h:88
LWGEOM ** rings
Definition: liblwgeom.h:537
uint32_t ngeoms
Definition: liblwgeom.h:496
#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:574
char * stringbuffer_getstringcopy(stringbuffer_t *s)
Returns a newly allocated string large enough to contain the current state of the string...
Definition: stringbuffer.c:124
uint8_t flags
Definition: liblwgeom.h:399
#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:357
#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:576
uint32_t ngeoms
Definition: liblwgeom.h:574
static void lwcircstring_to_wkt_sb(const LWCIRCSTRING *circ, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:202
LWGEOM ** geoms
Definition: liblwgeom.h:524
uint32_t ngeoms
Definition: liblwgeom.h:509
static void lwtriangle_to_wkt_sb(const LWTRIANGLE *tri, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:524
POINTARRAY * point
Definition: liblwgeom.h:413
int32_t srid
Definition: liblwgeom.h:401
static void lwpoly_to_wkt_sb(const LWPOLY *poly, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:175
uint32_t nrings
Definition: liblwgeom.h:457
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:217
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:138
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:250
int lwtriangle_is_empty(const LWTRIANGLE *triangle)
static void lwmpoint_to_wkt_sb(const LWMPOINT *mpoint, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:222
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:216
#define WKT_ISO
Definition: liblwgeom.h:2036
uint8_t flags
Definition: liblwgeom.h:371
LWPOLY ** geoms
Definition: liblwgeom.h:498
LWGEOM ** geoms
Definition: liblwgeom.h:511
#define TINTYPE
Definition: liblwgeom.h:98
LWTRIANGLE ** geoms
Definition: liblwgeom.h:589
uint32_t ngeoms
Definition: liblwgeom.h:522
POINTARRAY ** rings
Definition: liblwgeom.h:459
#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:472
int lwpoly_is_empty(const LWPOLY *poly)
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; 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:280
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)
static void lwgeom_to_wkt_sb(const LWGEOM *geom, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:606
static void empty_to_wkt_sb(stringbuffer_t *sb)
Definition: lwout_wkt.c:69
uint8_t type
Definition: liblwgeom.h:570
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:89
uint32_t ngeoms
Definition: liblwgeom.h:483
int lwline_is_empty(const LWLINE *line)
LWLINE ** geoms
Definition: liblwgeom.h:485
#define WKT_EXTENDED
Definition: liblwgeom.h:2038
void stringbuffer_destroy(stringbuffer_t *s)
Free the stringbuffer_t and all memory managed within it.
Definition: stringbuffer.c:76
static void lwcompound_to_wkt_sb(const LWCOMPOUND *comp, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:312
#define MULTISURFACETYPE
Definition: liblwgeom.h:95
LWGEOM ** geoms
Definition: liblwgeom.h:563
static void lwpoint_to_wkt_sb(const LWPOINT *pt, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:136
LWGEOM ** geoms
Definition: liblwgeom.h:550
#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:496
int lwpoint_is_empty(const LWPOINT *point)
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:140
uint8_t type
Definition: liblwgeom.h:398
type
Definition: ovdump.py:41
const char * stringbuffer_getstring(stringbuffer_t *s)
Returns a reference to the internal string being managed by the stringbuffer.
Definition: stringbuffer.c:113
POINTARRAY * points
Definition: liblwgeom.h:446
uint32_t nrings
Definition: liblwgeom.h:535
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:676
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:91
char stringbuffer_lastchar(stringbuffer_t *s)
Return the last character in the buffer.
Definition: stringbuffer.c:98
uint32_t ngeoms
Definition: liblwgeom.h:548
#define MULTILINETYPE
Definition: liblwgeom.h:88
uint32_t ngeoms
Definition: liblwgeom.h:587
#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:453
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
#define COLLECTIONTYPE
Definition: liblwgeom.h:90
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition: lwinline.h:67
POINTARRAY * points
Definition: liblwgeom.h:424
static void lwline_to_wkt_sb(const LWLINE *line, stringbuffer_t *sb, int precision, uint8_t variant)
Definition: lwout_wkt.c:156
uint32_t npoints
Definition: liblwgeom.h:373