lwgeom_transform.o \
lwunionfind.o \
effectivearea.o \
- varint.o \
- twkb_tools.o
+ varint.o
NM_OBJS = \
lwspheroid.o
extern 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);
-extern uint8_t* twkb_to_twkbcoll(uint8_t **twkb, size_t *sizes,size_t *out_size, int64_t *idlist, int n);
-
/*******************************************************************************
* SQLMM internal functions - TODO: Move into separate header files
******************************************************************************/
*
* PostGIS - Spatial Types for PostgreSQL
*
- * Copyright (C) 2015 Paul Ramsey
* Copyright (C) 2014 Nicklas Avén
*
* This is free software; you can redistribute and/or modify it under
*
**********************************************************************/
-#include "lwin_twkb.h"
+#include <math.h>
+#include "liblwgeom_internal.h"
+#include "lwgeom_log.h"
+#include "varint.h"
+
+#define TWKB_IN_MAXCOORDS 4
+
+/**
+* Used for passing the parse state between the parsing functions.
+*/
+typedef struct
+{
+ /* Pointers to the bytes */
+ uint8_t *twkb; /* Points to start of TWKB */
+ uint8_t *twkb_end; /* Points to end of TWKB */
+ uint8_t *pos; /* Current read position */
+
+ uint32_t check; /* Simple validity checks on geometries */
+ uint32_t lwtype; /* Current type we are handling */
+
+ uint8_t has_bbox;
+ uint8_t has_size;
+ uint8_t has_idlist;
+ uint8_t has_z;
+ uint8_t has_m;
+ uint8_t is_empty;
+
+ /* Precision factors to convert ints to double */
+ double factor;
+ double factor_z;
+ double factor_m;
+
+ uint64_t size;
+
+ /* Info about current geometry */
+ uint8_t magic_byte; /* the magic byte contain info about if twkb contain id, size info, bboxes and precision */
+
+ int ndims; /* Number of dimensions */
+
+ int64_t *coords; /* An array to keep delta values from 4 dimensions */
+
+} twkb_parse_state;
/**
return val;
}
-inline double twkb_parse_state_double(twkb_parse_state *s, double factor)
+static inline double twkb_parse_state_double(twkb_parse_state *s, double factor)
{
size_t size;
int64_t val = varint_s64_decode(s->pos, s->twkb_end, &size);
}
-void header_from_twkb_state(twkb_parse_state *s)
+static void header_from_twkb_state(twkb_parse_state *s)
{
LWDEBUG(2,"Entering magicbyte_from_twkb_state");
+++ /dev/null
-/**********************************************************************
- *
- * PostGIS - Spatial Types for PostgreSQL
- *
- * Copyright (C) 2015 Paul Ramsey
- *
- * This is free software; you can redistribute and/or modify it under
- * the terms of the GNU General Public Licence. See the COPYING file.
- *
- **********************************************************************/
-
-#include <math.h>
-#include "liblwgeom_internal.h"
-#include "lwgeom_log.h"
-#include "varint.h"
-
-#define TWKB_IN_MAXCOORDS 4
-
-/**
-* Used for passing the parse state between the parsing functions.
-*/
-typedef struct
-{
- /* Pointers to the bytes */
- uint8_t *twkb; /* Points to start of TWKB */
- uint8_t *twkb_end; /* Points to end of TWKB */
- uint8_t *pos; /* Current read position */
-
- uint32_t check; /* Simple validity checks on geometries */
- uint32_t lwtype; /* Current type we are handling */
-
- uint8_t has_bbox;
- uint8_t has_size;
- uint8_t has_idlist;
- uint8_t has_z;
- uint8_t has_m;
- uint8_t is_empty;
-
- /* Precision factors to convert ints to double */
- double factor;
- double factor_z;
- double factor_m;
-
- uint64_t size;
-
- /* Info about current geometry */
- uint8_t magic_byte; /* the magic byte contain info about if twkb contain id, size info, bboxes and precision */
-
- int ndims; /* Number of dimensions */
-
- int64_t *coords; /* An array to keep delta values from 4 dimensions */
-
-} twkb_parse_state;
-
-
-void header_from_twkb_state(twkb_parse_state *s);
-inline double twkb_parse_state_double(twkb_parse_state *s, double factor);
* Calculates the size of the bbox in varints in the form:
* xmin, xdelta, ymin, ydelta
*/
-size_t sizeof_bbox(TWKB_STATE *ts, int ndims)
+static size_t sizeof_bbox(TWKB_STATE *ts, int ndims)
{
int i;
uint8_t buf[16];
* Writes the bbox in varints in the form:
* xmin, xdelta, ymin, ydelta
*/
-void write_bbox(TWKB_STATE *ts, int ndims)
+static void write_bbox(TWKB_STATE *ts, int ndims)
{
int i;
LWDEBUGF(2, "Entered %s", __func__);
* POINTS
*******************************************************************/
-int lwpoint_to_twkb_buf(const LWPOINT *pt, TWKB_GLOBALS *globals, TWKB_STATE *ts)
+static int lwpoint_to_twkb_buf(const LWPOINT *pt, TWKB_GLOBALS *globals, TWKB_STATE *ts)
{
LWDEBUGF(2, "Entered %s", __func__);
* LINESTRINGS
*******************************************************************/
-int lwline_to_twkb_buf(const LWLINE *line, TWKB_GLOBALS *globals, TWKB_STATE *ts)
+static int lwline_to_twkb_buf(const LWLINE *line, TWKB_GLOBALS *globals, TWKB_STATE *ts)
{
LWDEBUGF(2, "Entered %s", __func__);
* POLYGONS
*******************************************************************/
-int lwpoly_to_twkb_buf(const LWPOLY *poly, TWKB_GLOBALS *globals, TWKB_STATE *ts)
+static int lwpoly_to_twkb_buf(const LWPOLY *poly, TWKB_GLOBALS *globals, TWKB_STATE *ts)
{
int i;
* MULTI-GEOMETRYS (MultiPoint, MultiLinestring, MultiPolygon)
*******************************************************************/
-int lwmulti_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *globals, TWKB_STATE *ts)
+static int lwmulti_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *globals, TWKB_STATE *ts)
{
int i;
int nempty = 0;
* GEOMETRYCOLLECTIONS
*******************************************************************/
-int lwcollection_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *globals, TWKB_STATE *ts)
+static int lwcollection_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *globals, TWKB_STATE *ts)
{
int i;
* Handle whole TWKB
*******************************************************************/
-int lwgeom_to_twkb_buf(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *ts)
+static int lwgeom_to_twkb_buf(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *ts)
{
LWDEBUGF(2, "Entered %s", __func__);
}
-int lwgeom_write_to_buffer(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *parent_state)
+static int lwgeom_write_to_buffer(const LWGEOM *geom, TWKB_GLOBALS *globals, TWKB_STATE *parent_state)
{
int i, is_empty, has_z, has_m, ndims;
size_t bbox_size = 0, optional_precision_byte = 0;
int64_t accum_rels[MAX_N_DIMS]; /*Holds the acculmulated relative values*/
} TWKB_STATE;
-int lwgeom_to_twkb_buf(const LWGEOM *geom, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
-
-int lwpoint_to_twkb_buf(const LWPOINT *line, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
-int lwline_to_twkb_buf(const LWLINE *line, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
-int lwpoly_to_twkb_buf(const LWPOLY *poly, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
-int lwmulti_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *globals, TWKB_STATE *ts);
-int lwcollection_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
-int lwgeom_write_to_buffer(const LWGEOM *geom, TWKB_GLOBALS *global_values, TWKB_STATE *parent_state);
-
-size_t sizeof_bbox(TWKB_STATE *ts, int ndims);
-void write_bbox(TWKB_STATE *ts, int ndims);
-
+static int lwgeom_to_twkb_buf(const LWGEOM *geom, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
+static int lwpoint_to_twkb_buf(const LWPOINT *line, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
+static int lwline_to_twkb_buf(const LWLINE *line, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
+static int lwpoly_to_twkb_buf(const LWPOLY *poly, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
+static int lwcollection_to_twkb_buf(const LWCOLLECTION *col, TWKB_GLOBALS *global_values, TWKB_STATE *ts);
+static int lwgeom_write_to_buffer(const LWGEOM *geom, TWKB_GLOBALS *global_values, TWKB_STATE *parent_state);
+++ /dev/null
-/**********************************************************************
- *
- * PostGIS - Spatial Types for PostgreSQL
- *
- * Copyright (C) 2015 Nicklas Avén
- *
- * This is free software; you can redistribute and/or modify it under
- * the terms of the GNU General Public Licence. See the COPYING file.
- *
- **********************************************************************/
-
-#include <math.h>
-#include "liblwgeom_internal.h"
-#include "lwgeom_log.h"
-#include "varint.h"
-#include "lwout_twkb.h"
-#include "lwin_twkb.h"
-
-/**********************************************************************/
-
-typedef struct
-{
- int64_t bbox_min[MAX_N_DIMS];
- int64_t bbox_max[MAX_N_DIMS];
- double min_factor;
- double min_factor_z;
- double min_factor_m;
- int has_z;
- int has_m;
- int is_empty;
-} twkb_collection_data;
-
-
-/**
-* A function to collect many twkb-buffers into one collection
-*/
-static twkb_collection_data twkb_get_bboxes(uint8_t **twkb, size_t *sizes, int n)
-{
- LWDEBUG(2,"Entering box_maxmin");
- twkb_parse_state s;
- double min, max;
- int i;
- twkb_collection_data res;
- GBOX bbox;
- res.has_z = 0;
- res.has_m = 0;
- res.min_factor = res.min_factor_z = res.min_factor_m = 100000000;
- res.is_empty = 1;
- bbox.xmin = bbox.ymin = bbox.zmin = bbox.mmin = FLT_MAX;
- bbox.xmax = bbox.ymax = bbox.zmax = bbox.mmax = FLT_MIN;
-
- /*For each buffer, collect their bounding box*/
- for (i=0;i<n;i++)
- {
- LWDEBUGF(2,"Read header of buffer %d",i);
-
- /* Zero out the state */
- memset(&s, 0, sizeof(twkb_parse_state));
- /* Initialize the state appropriately */
- s.twkb = s.pos = twkb[i];
- s.twkb_end = twkb[i] + sizes[i];
- header_from_twkb_state(&s);
-
- if(!s.is_empty)
- res.is_empty = 0;
- if(!s.has_bbox)
- lwerror("We can only collect twkb with included bbox");
-
- /*read bbox and expand to all*/
-
- if(s.factor<res.min_factor)
- res.min_factor=s.factor;
-
- /* X */
- min = twkb_parse_state_double(&s, s.factor);
- if(min < bbox.xmin)
- bbox.xmin=min;
- max = min + twkb_parse_state_double(&s, s.factor);
- if(max > bbox.xmax)
- bbox.xmax=max;
- /* Y */
- min = twkb_parse_state_double(&s, s.factor);
- if(min < bbox.ymin)
- bbox.ymin=min;
- max = min + twkb_parse_state_double(&s, s.factor);
- if(max > bbox.ymax)
- bbox.ymax=max;
- /* Z */
- if ( s.has_z )
- {
- if(s.factor_z<res.min_factor_z)
- res.min_factor_z=s.factor_z;
- res.has_z= 1;
- min = twkb_parse_state_double(&s, s.factor_z);
- if(min < bbox.zmin)
- bbox.zmin=min;
- max = min + twkb_parse_state_double(&s, s.factor_z);
- if(max > bbox.zmax)
- bbox.zmax=max;
- }
- /* M */
- if ( s.has_m )
- {
- if(s.factor_m<res.min_factor_m)
- res.min_factor_m=s.factor_m;
- res.has_m= 1;
- min = twkb_parse_state_double(&s, s.factor_m);
- if(min < bbox.mmin)
- bbox.mmin=min;
- max = min + twkb_parse_state_double(&s, s.factor_m);
- if(max > bbox.mmax)
- bbox.mmax=max;
- }
- }
-
- res.bbox_min[0] = (int64_t) lround(bbox.xmin*res.min_factor);
- res.bbox_max[0] = (int64_t) lround(bbox.xmax*res.min_factor);
- res.bbox_min[1] = (int64_t) lround(bbox.ymin*res.min_factor);
- res.bbox_max[1] = (int64_t) lround(bbox.ymax*res.min_factor);
-
- if ( res.has_z )
- {
- res.bbox_min[2] = (int64_t) lround(bbox.zmin*res.min_factor);
- res.bbox_max[2] = (int64_t) lround(bbox.zmax*res.min_factor);
- }
- if ( res.has_m )
- {
- res.bbox_min[2+res.has_z] = (int64_t) lround(bbox.mmin*res.min_factor);
- res.bbox_max[2+res.has_z] = (int64_t) lround(bbox.mmax*res.min_factor);
- }
- return res;
-}
-
-static uint8_t* twkb_write_new_buffer(twkb_collection_data ts_data,uint8_t **twkb, size_t *sizes, size_t *out_size, int64_t *idlist, int n)
-{
- TWKB_STATE ts;
- int i;
- uint8_t type_prec = 0;
- uint8_t flag = 0;
- size_t size_to_register=0;
- uint8_t *twkb_out;
- int n_dims;
- int has_extended = (int) (ts_data.has_z||ts_data.has_m);
-
- /*Ok, we have all bounding boxes, then it's time to write*/
- ts.header_buf = bytebuffer_create_with_size(16);
- ts.geom_buf = bytebuffer_create_with_size(32);
-
- /* The type will always be COLLECTIONTYPE */
- TYPE_PREC_SET_TYPE(type_prec,COLLECTIONTYPE);
- /* Precision here is only for bbox. We use the worst precission we have found */
- TYPE_PREC_SET_PREC(type_prec, zigzag8((int) log10(ts_data.min_factor)));
- /* Write the type and precision byte */
- bytebuffer_append_byte(ts.header_buf, type_prec);
-
- /* METADATA BYTE */
- /* Always bboxes */
- FIRST_BYTE_SET_BBOXES(flag, 1);
- /* Always sizes */
- FIRST_BYTE_SET_SIZES(flag,1);
- /* Is there idlist? */
- FIRST_BYTE_SET_IDLIST(flag, idlist && !ts_data.is_empty);
- /* No extended byte */
- FIRST_BYTE_SET_EXTENDED(flag, has_extended);
- /* Write the header byte */
- bytebuffer_append_byte(ts.header_buf, flag);
-
- if(has_extended)
- {
- uint8_t flag = 0;
-
- if ( ts_data.has_z && (log10(ts_data.min_factor_z) > 7 || log10(ts_data.min_factor_z) < 0 ) )
- lwerror("%s: Z precision cannot be negative or greater than 7", __func__);
-
- if ( ts_data.has_m && ( log10(ts_data.min_factor_m) > 7 || log10(ts_data.min_factor_m)) )
- lwerror("%s: M precision cannot be negative or greater than 7", __func__);
-
- HIGHER_DIM_SET_HASZ(flag, ts_data.has_z);
- HIGHER_DIM_SET_HASM(flag, ts_data.has_m);
- HIGHER_DIM_SET_PRECZ(flag,(int) log10(ts_data.min_factor_z));
- HIGHER_DIM_SET_PRECM(flag,(int) log10(ts_data.min_factor_m));
- bytebuffer_append_byte(ts.header_buf, flag);
-
- }
-
- /*Write number of geometries*/
- bytebuffer_append_uvarint(ts.geom_buf, n);
-
- /* We've been handed an idlist, so write it in */
- if ( idlist )
- {
- for ( i = 0; i < n; i++ )
- {
- bytebuffer_append_varint(ts.geom_buf, idlist[i]);
- }
- }
-
- n_dims = 2 + ts_data.has_z+ts_data.has_m;
-
- for ( i = 0; i < n_dims; i++ )
- {
- ts.bbox_min[i]=ts_data.bbox_min[i];
- ts.bbox_max[i]=ts_data.bbox_max[i];
-
- size_to_register += sizes[i];
- }
-
- /*Write the size of our new collection from size-info to the end*/
- size_to_register += sizeof_bbox(&ts,n_dims) + bytebuffer_getlength(ts.geom_buf);
- bytebuffer_append_uvarint(ts.header_buf, size_to_register);
-
- /*Write the bbox to the buffer*/
- write_bbox(&ts, n_dims);
-
- /*Put the id-list after the header*/
- bytebuffer_append_bytebuffer(ts.header_buf,ts.geom_buf);
-
- /*Copy all ingoing buffers "as is" to the new buffer*/
- for ( i = 0; i < n; i++ )
- {
- bytebuffer_append_bulk(ts.header_buf, twkb[i], sizes[i]);
- }
-
-
- bytebuffer_destroy(ts.geom_buf);
-
- if ( out_size )
- *out_size = bytebuffer_getlength(ts.header_buf);
-
- twkb_out = ts.header_buf->buf_start;
-
- lwfree(ts.header_buf);
-
- return twkb_out;
-}
-/**
-* A function to collect many twkb-buffers into one collection
-*/
-uint8_t* twkb_to_twkbcoll(uint8_t **twkb, size_t *sizes,size_t *out_size, int64_t *idlist, int n)
-{
- LWDEBUG(2,"Entering twkb_to_twkbcoll");
-
- twkb_collection_data ts_data = twkb_get_bboxes(twkb, sizes, n);
-
- return twkb_write_new_buffer(ts_data,twkb, sizes, out_size, idlist, n);
-}
}
-PG_FUNCTION_INFO_V1(TWKBFromTWKBArray);
-Datum TWKBFromTWKBArray(PG_FUNCTION_ARGS)
-{
- ArrayType *arr_twkbs = NULL;
- ArrayType *arr_ids = NULL;
- int num_twkbs, num_ids, i = 0;
-
- ArrayIterator iter_twkbs, iter_ids;
- bool null_twkb, null_id;
- Datum val_twkb, val_id;
-
- uint8_t **col = NULL;
- size_t *sizes = NULL;
- int64_t *idlist = NULL;
-
- uint8_t *twkb;
- size_t twkb_size;
- size_t out_size;
- bytea *result;
- bytea *bytea_twkb;
- /* The first two arguments are required */
- if ( PG_NARGS() < 2 || PG_ARGISNULL(0) || PG_ARGISNULL(1) )
- PG_RETURN_NULL();
-
- arr_twkbs = PG_GETARG_ARRAYTYPE_P(0);
- arr_ids = PG_GETARG_ARRAYTYPE_P(1);
-
- num_twkbs = ArrayGetNItems(ARR_NDIM(arr_twkbs), ARR_DIMS(arr_twkbs));
- num_ids = ArrayGetNItems(ARR_NDIM(arr_ids), ARR_DIMS(arr_ids));
-
- if ( num_twkbs != num_ids )
- {
- elog(ERROR, "size of geometry[] and integer[] arrays must match");
- PG_RETURN_NULL();
- }
-
- /* Loop through array and build a collection of geometry and */
- /* a simple array of ids. If either side is NULL, skip it */
-
-#if POSTGIS_PGSQL_VERSION >= 95
- iter_twkbs = array_create_iterator(arr_twkbs, 0, NULL);
- iter_ids = array_create_iterator(arr_ids, 0, NULL);
-#else
- iter_twkbs = array_create_iterator(arr_twkbs, 0);
- iter_ids = array_create_iterator(arr_ids, 0);
-#endif
- /* Construct collection/idlist first time through */
- col = palloc0(num_twkbs * sizeof(void*));
- sizes = palloc0(num_twkbs * sizeof(size_t));
- idlist = palloc0(num_twkbs * sizeof(int64_t));
-
- while( array_iterate(iter_twkbs, &val_twkb, &null_twkb) &&
- array_iterate(iter_ids, &val_id, &null_id) )
- {
- int32_t uid;
-
- if ( null_twkb || null_id )
- {
- elog(NOTICE, "ST_CollectTWKB skipping NULL entry at position %d", i);
- continue;
- }
-
- bytea_twkb =(bytea*) DatumGetPointer(val_twkb);
- uid = DatumGetInt64(val_id);
-
-
-
- twkb_size=VARSIZE_ANY_EXHDR(bytea_twkb);
-
- /* Store the values */
- col[i] = (uint8_t*)VARDATA(bytea_twkb);
- sizes[i] = twkb_size;
- idlist[i] = uid;
- i++;
-
- }
-
- array_free_iterator(iter_twkbs);
- array_free_iterator(iter_ids);
-
-
- if(i==0)
- {
- elog(NOTICE, "No valid geometry - id pairs found");
- PG_FREE_IF_COPY(arr_twkbs, 0);
- PG_FREE_IF_COPY(arr_ids, 1);
- PG_RETURN_NULL();
- }
-
- /* Write out the TWKB */
- twkb = twkb_to_twkbcoll(col, sizes,&out_size, idlist, i);
-
- /* Convert to a bytea return type */
- result = palloc(out_size + VARHDRSZ);
- memcpy(VARDATA(result), twkb,out_size);
- SET_VARSIZE(result, out_size + VARHDRSZ);
-
- /* Clean up */
- //~ pfree(twkb);
- pfree(idlist);
- PG_FREE_IF_COPY(arr_twkbs, 0);
- PG_FREE_IF_COPY(arr_ids, 1);
-
- PG_RETURN_BYTEA_P(result);
- //~ PG_RETURN_NULL();
-}
-
-
/* puts a bbox inside the geometry */
PG_FUNCTION_INFO_V1(LWGEOM_addBBOX);
Datum LWGEOM_addBBOX(PG_FUNCTION_ARGS)
AS 'MODULE_PATHNAME', 'LWGEOM_collect_garray'
LANGUAGE 'c' IMMUTABLE STRICT;
--- Availability: 2.2.0
-CREATE OR REPLACE FUNCTION ST_CollectTWKB(twkb bytea[], ids bigint[])
- RETURNS bytea
- AS 'MODULE_PATHNAME','TWKBFromTWKBArray'
- LANGUAGE 'c' IMMUTABLE;
-
-- Availability: 1.2.2
CREATE AGGREGATE ST_MemUnion (
basetype = geometry,