PostGIS  2.4.9dev-r@@SVN_REVISION@@
lwout_twkb.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) 2013 Nicklas Avén
22  *
23  **********************************************************************/
24 
25 
26 #include "lwout_twkb.h"
27 
28 /*
29 * GeometryType, and dimensions
30 */
31 static uint8_t lwgeom_twkb_type(const LWGEOM *geom)
32 {
33  uint8_t twkb_type = 0;
34 
35  LWDEBUGF(2, "Entered lwgeom_twkb_type",0);
36 
37  switch ( geom->type )
38  {
39  case POINTTYPE:
40  twkb_type = WKB_POINT_TYPE;
41  break;
42  case LINETYPE:
43  twkb_type = WKB_LINESTRING_TYPE;
44  break;
45  case POLYGONTYPE:
46  twkb_type = WKB_POLYGON_TYPE;
47  break;
48  case MULTIPOINTTYPE:
49  twkb_type = WKB_MULTIPOINT_TYPE;
50  break;
51  case MULTILINETYPE:
52  twkb_type = WKB_MULTILINESTRING_TYPE;
53  break;
54  case MULTIPOLYGONTYPE:
55  twkb_type = WKB_MULTIPOLYGON_TYPE;
56  break;
57  case COLLECTIONTYPE:
58  twkb_type = WKB_GEOMETRYCOLLECTION_TYPE;
59  break;
60  default:
61  lwerror("Unsupported geometry type: %s [%d]",
62  lwtype_name(geom->type), geom->type);
63  }
64  return twkb_type;
65 }
66 
67 
72 static size_t sizeof_bbox(TWKB_STATE *ts, int ndims)
73 {
74  int i;
75  uint8_t buf[16];
76  size_t size = 0;
77  LWDEBUGF(2, "Entered %s", __func__);
78  for ( i = 0; i < ndims; i++ )
79  {
80  size += varint_s64_encode_buf(ts->bbox_min[i], buf);
81  size += varint_s64_encode_buf((ts->bbox_max[i] - ts->bbox_min[i]), buf);
82  }
83  return size;
84 }
89 static void write_bbox(TWKB_STATE *ts, int ndims)
90 {
91  int i;
92  LWDEBUGF(2, "Entered %s", __func__);
93  for ( i = 0; i < ndims; i++ )
94  {
96  bytebuffer_append_varint(ts->header_buf, (ts->bbox_max[i] - ts->bbox_min[i]));
97  }
98 }
99 
100 
106 static int ptarray_to_twkb_buf(const POINTARRAY *pa, TWKB_GLOBALS *globals, TWKB_STATE *ts, int register_npoints, int minpoints)
107 {
108  int ndims = FLAGS_NDIMS(pa->flags);
109  int i, j;
110  bytebuffer_t b;
111  bytebuffer_t *b_p;
112  int64_t nextdelta[MAX_N_DIMS];
113  int npoints = 0;
114  size_t npoints_offset = 0;
115  uint32_t max_points_left = pa->npoints;
116 
117  LWDEBUGF(2, "Entered %s", __func__);
118 
119  /* Dispense with the empty case right away */
120  if ( pa->npoints == 0 && register_npoints )
121  {
122  LWDEBUGF(4, "Register npoints:%d", pa->npoints);
124  return 0;
125  }
126 
127  /* If npoints is more than 127 it is unpredictable how many bytes npoints will need */
128  /* Then we have to store the deltas in a temp buffer to later add them after npoints */
129  /* If noints is below 128 we know 1 byte will be needed */
130  /* Then we can make room for that 1 byte at once and write to */
131  /* ordinary buffer */
132  if( pa->npoints > 127 )
133  {
134  /* Independent buffer to hold the coordinates, so we can put the npoints */
135  /* into the stream once we know how many points we actually have */
136  bytebuffer_init_with_size(&b, 3 * ndims * pa->npoints);
137  b_p = &b;
138  }
139  else
140  {
141  /* We give an alias to our ordinary buffer */
142  b_p = ts->geom_buf;
143  if ( register_npoints )
144  {
145  /* We do not store a pointer to the place where we want the npoints value */
146  /* Instead we store how far from the beginning of the buffer we want the value */
147  /* That is because we otherwise will get in trouble if the buffer is reallocated */
148  npoints_offset = b_p->writecursor - b_p->buf_start;
149 
150  /* We just move the cursor 1 step to make room for npoints byte */
151  /* We use the function append_byte even if we have no value yet, */
152  /* since that gives us the check for big enough buffer and moves the cursor */
153  bytebuffer_append_byte(b_p, 0);
154  }
155  }
156 
157  for ( i = 0; i < pa->npoints; i++ )
158  {
159  double *dbl_ptr = (double*)getPoint_internal(pa, i);
160  int64_t diff = 0;
161 
162  /* Write this coordinate to the buffer as a varint */
163  for ( j = 0; j < ndims; j++ )
164  {
165  /* To get the relative coordinate we don't get the distance */
166  /* from the last point but instead the distance from our */
167  /* last accumulated point. This is important to not build up an */
168  /* accumulated error when rounding the coordinates */
169  nextdelta[j] = (int64_t) llround(globals->factor[j] * dbl_ptr[j]) - ts->accum_rels[j];
170  LWDEBUGF(4, "deltavalue: %d, ", nextdelta[j]);
171  diff += llabs(nextdelta[j]);
172  }
173 
174  /* Skipping the first point is not allowed */
175  /* If the sum(abs()) of all the deltas was zero, */
176  /* then this was a duplicate point, so we can ignore it */
177  if ( i > 0 && diff == 0 && max_points_left > minpoints )
178  {
179  max_points_left--;
180  continue;
181  }
182 
183  /* We really added a point, so... */
184  npoints++;
185 
186  /* Write this vertex to the temporary buffer as varints */
187  for ( j = 0; j < ndims; j++ )
188  {
189  ts->accum_rels[j] += nextdelta[j];
190  bytebuffer_append_varint(b_p, nextdelta[j]);
191  }
192 
193  /* See if this coordinate expands the bounding box */
194  if( globals->variant & TWKB_BBOX )
195  {
196  for ( j = 0; j < ndims; j++ )
197  {
198  if( ts->accum_rels[j] > ts->bbox_max[j] )
199  ts->bbox_max[j] = ts->accum_rels[j];
200 
201  if( ts->accum_rels[j] < ts->bbox_min[j] )
202  ts->bbox_min[j] = ts->accum_rels[j];
203  }
204  }
205 
206  }
207 
208  if ( pa->npoints > 127 )
209  {
210  /* Now write the temporary results into the main buffer */
211  /* First the npoints */
212  if ( register_npoints )
213  bytebuffer_append_uvarint(ts->geom_buf, npoints);
214  /* Now the coordinates */
216 
217  /* Clear our temporary buffer */
219  }
220  else
221  {
222  /* If we didn't use a temp buffer, we just write that npoints value */
223  /* to where it belongs*/
224  if ( register_npoints )
225  varint_u64_encode_buf(npoints, b_p->buf_start + npoints_offset);
226  }
227 
228  return 0;
229 }
230 
231 /******************************************************************
232 * POINTS
233 *******************************************************************/
234 
235 static int lwpoint_to_twkb_buf(const LWPOINT *pt, TWKB_GLOBALS *globals, TWKB_STATE *ts)
236 {
237  LWDEBUGF(2, "Entered %s", __func__);
238 
239  /* Set the coordinates (don't write npoints) */
240  ptarray_to_twkb_buf(pt->point, globals, ts, 0, 1);
241  return 0;
242 }
243 
244 /******************************************************************
245 * LINESTRINGS
246 *******************************************************************/
247 
248 static int lwline_to_twkb_buf(const LWLINE *line, TWKB_GLOBALS *globals, TWKB_STATE *ts)
249 {
250  LWDEBUGF(2, "Entered %s", __func__);
251 
252  /* Set the coordinates (do write npoints) */
253  ptarray_to_twkb_buf(line->points, globals, ts, 1, 2);
254  return 0;
255 }
256 
257 /******************************************************************
258 * POLYGONS
259 *******************************************************************/
260 
261 static int lwpoly_to_twkb_buf(const LWPOLY *poly, TWKB_GLOBALS *globals, TWKB_STATE *ts)
262 {
263  int i;
264 
265  /* Set the number of rings */
266  bytebuffer_append_uvarint(ts->geom_buf, (uint64_t) poly->nrings);
267 
268  for ( i = 0; i < poly->nrings; i++ )
269  {
270  /* Set the coordinates (do write npoints) */
271  ptarray_to_twkb_buf(poly->rings[i], globals, ts, 1, 4);
272  }
273 
274  return 0;
275 }
276 
277 
278 
279 /******************************************************************
280 * MULTI-GEOMETRYS (MultiPoint, MultiLinestring, MultiPolygon)
281 *******************************************************************/
282 
283 static int lwmulti_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *globals, TWKB_STATE *ts)
284 {
285  int i;
286  int nempty = 0;
287 
288  LWDEBUGF(2, "Entered %s", __func__);
289  LWDEBUGF(4, "Number of geometries in multi is %d", col->ngeoms);
290 
291  /* Deal with special case for MULTIPOINT: skip any empty points */
292  if ( col->type == MULTIPOINTTYPE )
293  {
294  for ( i = 0; i < col->ngeoms; i++ )
295  if ( lwgeom_is_empty(col->geoms[i]) )
296  nempty++;
297  }
298 
299  /* Set the number of geometries */
300  bytebuffer_append_uvarint(ts->geom_buf, (uint64_t) (col->ngeoms - nempty));
301 
302  /* We've been handed an idlist, so write it in */
303  if ( ts->idlist )
304  {
305  for ( i = 0; i < col->ngeoms; i++ )
306  {
307  /* Skip empty points in multipoints, we can't represent them */
308  if ( col->type == MULTIPOINTTYPE && lwgeom_is_empty(col->geoms[i]) )
309  continue;
310 
312  }
313 
314  /* Empty it out to nobody else uses it now */
315  ts->idlist = NULL;
316  }
317 
318  for ( i = 0; i < col->ngeoms; i++ )
319  {
320  /* Skip empty points in multipoints, we can't represent them */
321  if ( col->type == MULTIPOINTTYPE && lwgeom_is_empty(col->geoms[i]) )
322  continue;
323 
324  lwgeom_to_twkb_buf(col->geoms[i], globals, ts);
325  }
326  return 0;
327 }
328 
329 /******************************************************************
330 * GEOMETRYCOLLECTIONS
331 *******************************************************************/
332 
333 static int lwcollection_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *globals, TWKB_STATE *ts)
334 {
335  int i;
336 
337  LWDEBUGF(2, "Entered %s", __func__);
338  LWDEBUGF(4, "Number of geometries in collection is %d", col->ngeoms);
339 
340  /* Set the number of geometries */
341  bytebuffer_append_uvarint(ts->geom_buf, (uint64_t) col->ngeoms);
342 
343  /* We've been handed an idlist, so write it in */
344  if ( ts->idlist )
345  {
346  for ( i = 0; i < col->ngeoms; i++ )
348 
349  /* Empty it out to nobody else uses it now */
350  ts->idlist = NULL;
351  }
352 
353  /* Write in the sub-geometries */
354  for ( i = 0; i < col->ngeoms; i++ )
355  {
356  lwgeom_write_to_buffer(col->geoms[i], globals, ts);
357  }
358  return 0;
359 }
360 
361 
362 /******************************************************************
363 * Handle whole TWKB
364 *******************************************************************/
365 
366 static int lwgeom_to_twkb_buf(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *ts)
367 {
368  LWDEBUGF(2, "Entered %s", __func__);
369 
370  switch ( geom->type )
371  {
372  case POINTTYPE:
373  {
374  LWDEBUGF(4,"Type found is Point, %d", geom->type);
375  return lwpoint_to_twkb_buf((LWPOINT*) geom, globals, ts);
376  }
377  case LINETYPE:
378  {
379  LWDEBUGF(4,"Type found is Linestring, %d", geom->type);
380  return lwline_to_twkb_buf((LWLINE*) geom, globals, ts);
381  }
382  /* Polygon has 'nrings' and 'rings' elements */
383  case POLYGONTYPE:
384  {
385  LWDEBUGF(4,"Type found is Polygon, %d", geom->type);
386  return lwpoly_to_twkb_buf((LWPOLY*)geom, globals, ts);
387  }
388 
389  /* All these Collection types have 'ngeoms' and 'geoms' elements */
390  case MULTIPOINTTYPE:
391  case MULTILINETYPE:
392  case MULTIPOLYGONTYPE:
393  {
394  LWDEBUGF(4,"Type found is Multi, %d", geom->type);
395  return lwmulti_to_twkb_buf((LWCOLLECTION*)geom, globals, ts);
396  }
397  case COLLECTIONTYPE:
398  {
399  LWDEBUGF(4,"Type found is collection, %d", geom->type);
400  return lwcollection_to_twkb_buf((LWCOLLECTION*) geom, globals, ts);
401  }
402  /* Unknown type! */
403  default:
404  lwerror("Unsupported geometry type: %s [%d]", lwtype_name((geom)->type), (geom)->type);
405  }
406 
407  return 0;
408 }
409 
410 
411 static int lwgeom_write_to_buffer(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *parent_state)
412 {
413  int i, is_empty, has_z, has_m, ndims;
414  size_t bbox_size = 0, optional_precision_byte = 0;
415  uint8_t flag = 0, type_prec = 0;
416  bytebuffer_t header_bytebuffer, geom_bytebuffer;
417 
418  TWKB_STATE child_state;
419  memset(&child_state, 0, sizeof(TWKB_STATE));
420  child_state.header_buf = &header_bytebuffer;
421  child_state.geom_buf = &geom_bytebuffer;
422  child_state.idlist = parent_state->idlist;
423 
424  bytebuffer_init_with_size(child_state.header_buf, 16);
425  bytebuffer_init_with_size(child_state.geom_buf, 64);
426 
427  /* Read dimensionality from input */
428  has_z = lwgeom_has_z(geom);
429  has_m = lwgeom_has_m(geom);
430  ndims = lwgeom_ndims(geom);
431  is_empty = lwgeom_is_empty(geom);
432 
433  /* Do we need extended precision? If we have a Z or M we do. */
434  optional_precision_byte = (has_z || has_m);
435 
436  /* Both X and Y dimension use the same precision */
437  globals->factor[0] = pow(10, globals->prec_xy);
438  globals->factor[1] = globals->factor[0];
439 
440  /* Z and M dimensions have their own precisions */
441  if ( has_z )
442  globals->factor[2] = pow(10, globals->prec_z);
443  if ( has_m )
444  globals->factor[2 + has_z] = pow(10, globals->prec_m);
445 
446  /* Reset stats */
447  for ( i = 0; i < MAX_N_DIMS; i++ )
448  {
449  /* Reset bbox calculation */
450  child_state.bbox_max[i] = INT64_MIN;
451  child_state.bbox_min[i] = INT64_MAX;
452  /* Reset acumulated delta values to get absolute values on next point */
453  child_state.accum_rels[i] = 0;
454  }
455 
456  /* TYPE/PRECISION BYTE */
457  if ( abs(globals->prec_xy) > 7 )
458  lwerror("%s: X/Z precision cannot be greater than 7 or less than -7", __func__);
459 
460  /* Read the TWKB type number from the geometry */
461  TYPE_PREC_SET_TYPE(type_prec, lwgeom_twkb_type(geom));
462  /* Zig-zag the precision value before encoding it since it is a signed value */
463  TYPE_PREC_SET_PREC(type_prec, zigzag8(globals->prec_xy));
464  /* Write the type and precision byte */
465  bytebuffer_append_byte(child_state.header_buf, type_prec);
466 
467  /* METADATA BYTE */
468  /* Set first bit if we are going to store bboxes */
469  FIRST_BYTE_SET_BBOXES(flag, (globals->variant & TWKB_BBOX) && ! is_empty);
470  /* Set second bit if we are going to store resulting size */
471  FIRST_BYTE_SET_SIZES(flag, globals->variant & TWKB_SIZE);
472  /* There will be no ID-list (for now) */
473  FIRST_BYTE_SET_IDLIST(flag, parent_state->idlist && ! is_empty);
474  /* Are there higher dimensions */
475  FIRST_BYTE_SET_EXTENDED(flag, optional_precision_byte);
476  /* Empty? */
477  FIRST_BYTE_SET_EMPTY(flag, is_empty);
478  /* Write the header byte */
479  bytebuffer_append_byte(child_state.header_buf, flag);
480 
481  /* EXTENDED PRECISION BYTE (OPTIONAL) */
482  /* If needed, write the extended dim byte */
483  if( optional_precision_byte )
484  {
485  uint8_t flag = 0;
486 
487  if ( has_z && ( globals->prec_z > 7 || globals->prec_z < 0 ) )
488  lwerror("%s: Z precision cannot be negative or greater than 7", __func__);
489 
490  if ( has_m && ( globals->prec_m > 7 || globals->prec_m < 0 ) )
491  lwerror("%s: M precision cannot be negative or greater than 7", __func__);
492 
493  HIGHER_DIM_SET_HASZ(flag, has_z);
494  HIGHER_DIM_SET_HASM(flag, has_m);
495  HIGHER_DIM_SET_PRECZ(flag, globals->prec_z);
496  HIGHER_DIM_SET_PRECM(flag, globals->prec_m);
497  bytebuffer_append_byte(child_state.header_buf, flag);
498  }
499 
500  /* It the geometry is empty, we're almost done */
501  if ( is_empty )
502  {
503  /* If this output is sized, write the size of */
504  /* all following content, which is zero because */
505  /* there is none */
506  if ( globals->variant & TWKB_SIZE )
507  bytebuffer_append_byte(child_state.header_buf, 0);
508 
509  bytebuffer_append_bytebuffer(parent_state->geom_buf, child_state.header_buf);
511  bytebuffer_destroy_buffer(child_state.geom_buf);
512  return 0;
513  }
514 
515  /* Write the TWKB into the output buffer */
516  lwgeom_to_twkb_buf(geom, globals, &child_state);
517 
518  /*If we have a header_buf, we know that this function is called inside a collection*/
519  /*and then we have to merge the bboxes of the included geometries*/
520  /*and put the result to the parent (the collection)*/
521  if( (globals->variant & TWKB_BBOX) && parent_state->header_buf )
522  {
523  LWDEBUG(4,"Merge bboxes");
524  for ( i = 0; i < ndims; i++ )
525  {
526  if(child_state.bbox_min[i]<parent_state->bbox_min[i])
527  parent_state->bbox_min[i] = child_state.bbox_min[i];
528  if(child_state.bbox_max[i]>parent_state->bbox_max[i])
529  parent_state->bbox_max[i] = child_state.bbox_max[i];
530  }
531  }
532 
533  /* Did we have a box? If so, how big? */
534  bbox_size = 0;
535  if( globals->variant & TWKB_BBOX )
536  {
537  LWDEBUG(4,"We want boxes and will calculate required size");
538  bbox_size = sizeof_bbox(&child_state, ndims);
539  }
540 
541  /* Write the size if wanted */
542  if( globals->variant & TWKB_SIZE )
543  {
544  /* Here we have to add what we know will be written to header */
545  /* buffer after size value is written */
546  size_t size_to_register = bytebuffer_getlength(child_state.geom_buf);
547  size_to_register += bbox_size;
548  bytebuffer_append_uvarint(child_state.header_buf, size_to_register);
549  }
550 
551  if( globals->variant & TWKB_BBOX )
552  write_bbox(&child_state, ndims);
553 
554  bytebuffer_append_bytebuffer(parent_state->geom_buf,child_state.header_buf);
555  bytebuffer_append_bytebuffer(parent_state->geom_buf,child_state.geom_buf);
556 
558  bytebuffer_destroy_buffer(child_state.geom_buf);
559  return 0;
560 }
561 
562 
567 uint8_t*
568 lwgeom_to_twkb_with_idlist(const LWGEOM *geom, int64_t *idlist, uint8_t variant,
569  int8_t precision_xy, int8_t precision_z, int8_t precision_m,
570  size_t *twkb_size)
571 {
572  LWDEBUGF(2, "Entered %s", __func__);
573  LWDEBUGF(2, "variant value %x", variant);
574 
575  TWKB_GLOBALS tg;
576  TWKB_STATE ts;
577  bytebuffer_t geom_bytebuffer;
578 
579  uint8_t *twkb;
580 
581  memset(&ts, 0, sizeof(TWKB_STATE));
582  memset(&tg, 0, sizeof(TWKB_GLOBALS));
583 
584  tg.variant = variant;
585  tg.prec_xy = precision_xy;
586  tg.prec_z = precision_z;
587  tg.prec_m = precision_m;
588 
589  if ( idlist && ! lwgeom_is_collection(geom) )
590  {
591  lwerror("Only collections can support ID lists");
592  return NULL;
593  }
594 
595  if ( ! geom )
596  {
597  LWDEBUG(4,"Cannot convert NULL into TWKB.");
598  lwerror("Cannot convert NULL into TWKB");
599  return NULL;
600  }
601 
602  ts.idlist = idlist;
603  ts.header_buf = NULL;
604  ts.geom_buf = &geom_bytebuffer;
606  lwgeom_write_to_buffer(geom, &tg, &ts);
607 
608  twkb = bytebuffer_get_buffer_copy(ts.geom_buf, twkb_size);
610  return twkb;
611 }
612 
613 
614 uint8_t*
616  int8_t precision_xy, int8_t precision_z, int8_t precision_m,
617  size_t *twkb_size)
618 {
619  return lwgeom_to_twkb_with_idlist(geom, NULL, variant, precision_xy, precision_z, precision_m, twkb_size);
620 }
621 
622 
static int lwmulti_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *globals, TWKB_STATE *ts)
Definition: lwout_twkb.c:283
#define LINETYPE
Definition: liblwgeom.h:86
#define FIRST_BYTE_SET_EMPTY(flag, bool)
Definition: lwout_twkb.h:57
float factor[4]
Definition: lwout_twkb.h:82
uint8_t * writecursor
Definition: bytebuffer.h:42
#define HIGHER_DIM_SET_PRECM(flag, prec)
Definition: lwout_twkb.h:73
#define TYPE_PREC_SET_TYPE(flag, type)
Macros for manipulating the &#39;type_precision&#39; int.
Definition: lwout_twkb.h:66
uint8_t variant
Definition: cu_in_twkb.c:26
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM can contain sub-geometries or not.
Definition: lwgeom.c:1040
void bytebuffer_append_bytebuffer(bytebuffer_t *write_to, bytebuffer_t *write_from)
Writes a uint8_t value to the buffer.
Definition: bytebuffer.c:224
int npoints
Definition: liblwgeom.h:371
uint8_t type
Definition: liblwgeom.h:503
uint8_t variant
Definition: lwout_twkb.h:78
static int lwgeom_to_twkb_buf(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *ts)
Definition: lwout_twkb.c:366
#define POLYGONTYPE
Definition: liblwgeom.h:87
void bytebuffer_append_byte(bytebuffer_t *s, const uint8_t val)
Writes a uint8_t value to the buffer.
Definition: bytebuffer.c:197
#define MULTIPOINTTYPE
Definition: liblwgeom.h:88
static uint8_t lwgeom_twkb_type(const LWGEOM *geom)
Definition: lwout_twkb.c:31
#define LWDEBUG(level, msg)
Definition: lwgeom_log.h:83
static void write_bbox(TWKB_STATE *ts, int ndims)
Writes the bbox in varints in the form: xmin, xdelta, ymin, ydelta.
Definition: lwout_twkb.c:89
static int lwpoly_to_twkb_buf(const LWPOLY *poly, TWKB_GLOBALS *globals, TWKB_STATE *ts)
Definition: lwout_twkb.c:261
#define HIGHER_DIM_SET_HASZ(flag, bool)
Definition: lwout_twkb.h:69
static int lwline_to_twkb_buf(const LWLINE *line, TWKB_GLOBALS *globals, TWKB_STATE *ts)
Definition: lwout_twkb.c:248
size_t bytebuffer_getlength(const bytebuffer_t *s)
Returns the length of the current buffer.
Definition: bytebuffer.c:377
POINTARRAY * point
Definition: liblwgeom.h:411
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:885
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: lwgeom.c:899
int8_t prec_z
Definition: lwout_twkb.h:80
unsigned int uint32_t
Definition: uthash.h:78
uint8_t zigzag8(int8_t val)
Definition: varint.c:182
bytebuffer_t * header_buf
Definition: lwout_twkb.h:88
static size_t sizeof_bbox(TWKB_STATE *ts, int ndims)
Calculates the size of the bbox in varints in the form: xmin, xdelta, ymin, ydelta.
Definition: lwout_twkb.c:72
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
int64_t accum_rels[MAX_N_DIMS]
Definition: lwout_twkb.h:95
const int64_t * idlist
Definition: lwout_twkb.h:92
#define WKB_POLYGON_TYPE
#define FIRST_BYTE_SET_SIZES(flag, bool)
Definition: lwout_twkb.h:54
void bytebuffer_append_uvarint(bytebuffer_t *b, const uint64_t val)
Writes a unsigned varInt to the buffer.
Definition: bytebuffer.c:252
uint8_t flags
Definition: liblwgeom.h:369
uint8_t * lwgeom_to_twkb_with_idlist(const LWGEOM *geom, int64_t *idlist, uint8_t variant, int8_t precision_xy, int8_t precision_z, int8_t precision_m, size_t *twkb_size)
Convert LWGEOM to a char* in TWKB format.
Definition: lwout_twkb.c:568
LWGEOM ** geoms
Definition: liblwgeom.h:509
static int ptarray_to_twkb_buf(const POINTARRAY *pa, TWKB_GLOBALS *globals, TWKB_STATE *ts, int register_npoints, int minpoints)
Stores a pointarray as varints in the buffer , controls whether an npoints entry is added to the buff...
Definition: lwout_twkb.c:106
int8_t prec_xy
Definition: lwout_twkb.h:79
uint8_t * getPoint_internal(const POINTARRAY *pa, int n)
Definition: ptarray.c:1753
POINTARRAY ** rings
Definition: liblwgeom.h:457
int nrings
Definition: liblwgeom.h:455
#define WKB_POINT_TYPE
Well-Known Binary (WKB) Geometry Types.
#define FIRST_BYTE_SET_BBOXES(flag, bool)
Header true/false flags.
Definition: lwout_twkb.h:53
int8_t prec_m
Definition: lwout_twkb.h:81
#define WKB_LINESTRING_TYPE
#define TYPE_PREC_SET_PREC(flag, prec)
Definition: lwout_twkb.h:67
#define WKB_MULTIPOLYGON_TYPE
#define MAX_N_DIMS
Definition: lwout_twkb.h:43
#define HIGHER_DIM_SET_PRECZ(flag, prec)
Definition: lwout_twkb.h:72
#define WKB_MULTILINESTRING_TYPE
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:90
#define TWKB_BBOX
Definition: liblwgeom.h:2091
void bytebuffer_init_with_size(bytebuffer_t *s, size_t size)
Allocate just the internal buffer of an existing bytebuffer_t struct.
Definition: bytebuffer.c:71
#define FIRST_BYTE_SET_EXTENDED(flag, bool)
Definition: lwout_twkb.h:56
uint8_t * bytebuffer_get_buffer_copy(const bytebuffer_t *s, size_t *buffer_length)
Returns a copy of the internal buffer.
Definition: bytebuffer.c:173
#define WKB_MULTIPOINT_TYPE
static int lwgeom_write_to_buffer(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *parent_state)
Definition: lwout_twkb.c:411
int64_t bbox_max[MAX_N_DIMS]
Definition: lwout_twkb.h:94
size_t varint_u64_encode_buf(uint64_t val, uint8_t *buf)
Definition: varint.c:76
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
static int lwpoint_to_twkb_buf(const LWPOINT *pt, TWKB_GLOBALS *globals, TWKB_STATE *ts)
Definition: lwout_twkb.c:235
#define TWKB_SIZE
Definition: liblwgeom.h:2092
uint8_t type
Definition: liblwgeom.h:396
type
Definition: ovdump.py:41
size_t varint_s64_encode_buf(int64_t val, uint8_t *buf)
Definition: varint.c:89
#define HIGHER_DIM_SET_HASM(flag, bool)
Definition: lwout_twkb.h:70
uint8_t * buf_start
Definition: bytebuffer.h:41
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
Definition: lwgeom.c:1346
bytebuffer_t * geom_buf
Definition: lwout_twkb.h:89
#define MULTILINETYPE
Definition: liblwgeom.h:89
#define LWDEBUGF(level, msg,...)
Definition: lwgeom_log.h:88
#define FLAGS_NDIMS(flags)
Definition: liblwgeom.h:152
unsigned char uint8_t
Definition: uthash.h:79
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:892
#define FIRST_BYTE_SET_IDLIST(flag, bool)
Definition: lwout_twkb.h:55
void bytebuffer_append_varint(bytebuffer_t *b, const int64_t val)
Writes a signed varInt to the buffer.
Definition: bytebuffer.c:239
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:190
void bytebuffer_destroy_buffer(bytebuffer_t *s)
Free the bytebuffer_t and all memory managed within it.
Definition: bytebuffer.c:104
static int lwcollection_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *globals, TWKB_STATE *ts)
Definition: lwout_twkb.c:333
#define COLLECTIONTYPE
Definition: liblwgeom.h:91
#define WKB_GEOMETRYCOLLECTION_TYPE
int64_t bbox_min[MAX_N_DIMS]
Definition: lwout_twkb.h:93
uint8_t * lwgeom_to_twkb(const LWGEOM *geom, uint8_t variant, int8_t precision_xy, int8_t precision_z, int8_t precision_m, size_t *twkb_size)
Definition: lwout_twkb.c:615
POINTARRAY * points
Definition: liblwgeom.h:422