PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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*/
31static uint8_t lwgeom_twkb_type(const LWGEOM *geom)
32{
33 uint8_t twkb_type = 0;
34
35 LWDEBUG(2, "Entered lwgeom_twkb_type");
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;
56 twkb_type = WKB_MULTIPOLYGON_TYPE;
57 break;
58 case TINTYPE:
59 case COLLECTIONTYPE:
61 break;
62 default:
63 lwerror("%s: Unsupported geometry type: %s", __func__, lwtype_name(geom->type));
64 }
65 return twkb_type;
66}
67
68
73static 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}
90static 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 {
98 }
99}
100
101
107static 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, (size_t)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 */
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: %lld, ", 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 )
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
236static 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
249static 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
258static 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
273static 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
295static 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
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
378static 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
429static 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 accumulated 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);
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
580 return 0;
581}
582
583
590 int64_t *idlist,
591 uint8_t variant,
592 int8_t precision_xy,
593 int8_t precision_z,
594 int8_t precision_m)
595{
596 LWDEBUGF(2, "Entered %s", __func__);
597 LWDEBUGF(2, "variant value %x", variant);
598
599 TWKB_GLOBALS tg;
600 TWKB_STATE ts;
601 bytebuffer_t geom_bytebuffer;
602
603 memset(&ts, 0, sizeof(TWKB_STATE));
604 memset(&tg, 0, sizeof(TWKB_GLOBALS));
605
606 tg.variant = variant;
607 tg.prec_xy = precision_xy;
608 tg.prec_z = precision_z;
609 tg.prec_m = precision_m;
610
611 if ( idlist && ! lwgeom_is_collection(geom) )
612 {
613 lwerror("Only collections can support ID lists");
614 return NULL;
615 }
616
617 if ( ! geom )
618 {
619 LWDEBUG(4,"Cannot convert NULL into TWKB.");
620 lwerror("Cannot convert NULL into TWKB");
621 return NULL;
622 }
623
624 ts.idlist = idlist;
625 ts.header_buf = NULL;
626 ts.geom_buf = &geom_bytebuffer;
628 lwgeom_write_to_buffer(geom, &tg, &ts);
629
632 return v;
633}
634
636lwgeom_to_twkb(const LWGEOM *geom, uint8_t variant, int8_t precision_xy, int8_t precision_z, int8_t precision_m)
637{
638 return lwgeom_to_twkb_with_idlist(geom, NULL, variant, precision_xy, precision_z, precision_m);
639}
640
641
void bytebuffer_destroy_buffer(bytebuffer_t *s)
Free the bytebuffer_t and all memory managed within it.
Definition bytebuffer.c:56
lwvarlena_t * bytebuffer_get_buffer_varlena(const bytebuffer_t *s)
Returns a copy of the internal buffer.
Definition bytebuffer.c:105
void bytebuffer_append_bytebuffer(bytebuffer_t *write_to, bytebuffer_t *write_from)
Writes a uint8_t value to the buffer.
Definition bytebuffer.c:140
size_t bytebuffer_getlength(const bytebuffer_t *s)
Returns the length of the current buffer.
Definition bytebuffer.c:176
void bytebuffer_append_byte(bytebuffer_t *s, const uint8_t val)
Writes a uint8_t value to the buffer.
Definition bytebuffer.c:127
void bytebuffer_append_uvarint(bytebuffer_t *b, const uint64_t val)
Writes a unsigned varInt to the buffer.
Definition bytebuffer.c:165
void bytebuffer_append_varint(bytebuffer_t *b, const int64_t val)
Writes a signed varInt to the buffer.
Definition bytebuffer.c:154
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
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
int lwgeom_ndims(const LWGEOM *geom)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition lwgeom.c:983
#define COLLECTIONTYPE
Definition liblwgeom.h:108
#define MULTILINETYPE
Definition liblwgeom.h:106
#define LINETYPE
Definition liblwgeom.h:103
#define MULTIPOINTTYPE
Definition liblwgeom.h:105
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:962
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:102
#define TINTYPE
Definition liblwgeom.h:116
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:107
#define FLAGS_NDIMS(flags)
Definition liblwgeom.h:179
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM contains sub-geometries or not This basically just checks that the struct ...
Definition lwgeom.c:1125
#define POLYGONTYPE
Definition liblwgeom.h:104
#define TWKB_SIZE
Definition liblwgeom.h:2228
#define TRIANGLETYPE
Definition liblwgeom.h:115
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:969
#define TWKB_BBOX
Definition liblwgeom.h:2227
#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:101
#define LWDEBUGF(level, msg,...)
Definition lwgeom_log.h:106
void void lwerror(const char *fmt,...) __attribute__((format(printf
Write a notice out to the error handler.
static uint8_t * getPoint_internal(const POINTARRAY *pa, uint32_t n)
Definition lwinline.h:75
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:199
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
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
lwvarlena_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)
Convert LWGEOM to a char* in TWKB format.
Definition lwout_twkb.c:589
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
lwvarlena_t * lwgeom_to_twkb(const LWGEOM *geom, uint8_t variant, int8_t precision_xy, int8_t precision_z, int8_t precision_m)
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:580
uint8_t type
Definition liblwgeom.h:578
LWGEOM ** geoms
Definition liblwgeom.h:575
uint8_t type
Definition liblwgeom.h:462
POINTARRAY * points
Definition liblwgeom.h:483
POINTARRAY * point
Definition liblwgeom.h:471
POINTARRAY ** rings
Definition liblwgeom.h:519
uint32_t nrings
Definition liblwgeom.h:524
POINTARRAY * points
Definition liblwgeom.h:495
lwflags_t flags
Definition liblwgeom.h:431
uint32_t npoints
Definition liblwgeom.h:427
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:44
uint8_t * buf_start
Definition bytebuffer.h:43
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:183