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