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