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