diff --git a/README.md b/README.md index 8e52e22..af463a0 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,18 @@ Now that you have created two tables, you'll see entries for them in the `pointc > INSERT INTO patches (pa) > SELECT PC_Patch(pt) FROM points GROUP BY id/10; + +**PC_MakePatch(pcid integer, vals float8[])** returns **pcpatch** + +> Given a valid `pcid` schema number and an array of doubles that matches the schema, construct a new `pcpatch`. +> Array size must be a multiple of the number of dimensions. +> +> SELECT PC_AsText(PC_MakePatch(1, ARRAY[-126.99,45.01,1,0, -126.98,45.02,2,0, -126.97,45.03,3,0])); + +> {"pcid":1,"pts":[ +> [-126.99,45.01,1,0],[-126.98,45.02,2,0],[-126.97,45.03,3,0] +> ]} + **PC_NumPoints(p pcpatch)** returns **integer** > Return the number of points in this patch. diff --git a/lib/cunit/cu_pc_patch.c b/lib/cunit/cu_pc_patch.c index 74f5364..09baae1 100644 --- a/lib/cunit/cu_pc_patch.c +++ b/lib/cunit/cu_pc_patch.c @@ -187,8 +187,8 @@ test_patch_hex_out() double d0[4] = { 0.02, 0.03, 0.05, 6 }; double d1[4] = { 0.02, 0.03, 0.05, 8 }; - PCPOINT *pt0 = pc_point_from_double_array(simpleschema, d0, 4); - PCPOINT *pt1 = pc_point_from_double_array(simpleschema, d1, 4); + PCPOINT *pt0 = pc_point_from_double_array(simpleschema, d0, 0, 4); + PCPOINT *pt1 = pc_point_from_double_array(simpleschema, d1, 0, 4); PCPATCH_UNCOMPRESSED *pa; uint8_t *wkb; diff --git a/lib/pc_api.h b/lib/pc_api.h index fefab64..dca1235 100644 --- a/lib/pc_api.h +++ b/lib/pc_api.h @@ -322,8 +322,8 @@ PCPOINT* pc_point_make(const PCSCHEMA *s); /** Create a new readonly PCPOINT on top of a data buffer */ PCPOINT* pc_point_from_data(const PCSCHEMA *s, const uint8_t *data); -/** Create a new read/write PCPOINT from a double array */ -PCPOINT* pc_point_from_double_array(const PCSCHEMA *s, double *array, uint32_t nelems); +/** Create a new read/write PCPOINT from a double array with an offset */ +PCPOINT* pc_point_from_double_array(const PCSCHEMA *s, double *array, uint32_t offset, uint32_t stride); /** * Return an allocated double array of doubles representing point values diff --git a/lib/pc_point.c b/lib/pc_point.c index f958ade..832941a 100644 --- a/lib/pc_point.c +++ b/lib/pc_point.c @@ -217,8 +217,9 @@ pc_point_to_string(const PCPOINT *pt) return str; } + PCPOINT * -pc_point_from_double_array(const PCSCHEMA *s, double *array, uint32_t nelems) +pc_point_from_double_array(const PCSCHEMA *s, double *array, uint32_t offset, uint32_t stride) { int i; PCPOINT *pt; @@ -229,9 +230,9 @@ pc_point_from_double_array(const PCSCHEMA *s, double *array, uint32_t nelems) return NULL; } - if ( s->ndims != nelems ) + if ( stride != s->ndims ) { - pcerror("number of elements in schema and array differ in pc_point_from_double_array"); + pcerror("number of elements in schema and array do not match in pc_point_from_double_array"); return NULL; } @@ -241,9 +242,9 @@ pc_point_from_double_array(const PCSCHEMA *s, double *array, uint32_t nelems) pt->schema = s; pt->readonly = PC_FALSE; - for ( i = 0; i < nelems; i++ ) + for ( i = 0; i < stride; i++ ) { - if ( PC_FAILURE == pc_point_set_double_by_index(pt, i, array[i]) ) + if ( PC_FAILURE == pc_point_set_double_by_index(pt, i, array[offset + i]) ) { pcerror("failed to write value into dimension %d in pc_point_from_double_array", i); return NULL; diff --git a/pgsql/expected/pointcloud.out b/pgsql/expected/pointcloud.out index 0965e49..79df7a7 100644 --- a/pgsql/expected/pointcloud.out +++ b/pgsql/expected/pointcloud.out @@ -728,4 +728,11 @@ FROM ( SELECT PC_Patch(PC_MakePoint(1, ARRAY[-1,0,4862413,1])) p ) foo; {"pcid":10,"pts":[[-1,0,1,1,1,1,1]]} | "none" (1 row) +-- test PC_Patch from float8 array +SELECT pc_astext(PC_MakePatch(1, ARRAY[-1,0,5,1, -1,0,6,1, -1,0,7,1])); + pc_astext +----------------------------------------------------- + {"pcid":1,"pts":[[-1,0,5,1],[-1,0,6,1],[-1,0,7,1]]} +(1 row) + TRUNCATE pointcloud_formats; diff --git a/pgsql/pc_access.c b/pgsql/pc_access.c index 855553c..fda1d03 100644 --- a/pgsql/pc_access.c +++ b/pgsql/pc_access.c @@ -23,6 +23,7 @@ void pc_cstring_array_free(const char **array, int nelems); Datum pcpoint_get_value(PG_FUNCTION_ARGS); Datum pcpoint_get_values(PG_FUNCTION_ARGS); Datum pcpatch_from_pcpoint_array(PG_FUNCTION_ARGS); +Datum pcpatch_from_float_array(PG_FUNCTION_ARGS); Datum pcpatch_from_pcpatch_array(PG_FUNCTION_ARGS); Datum pcpatch_uncompress(PG_FUNCTION_ARGS); Datum pcpatch_compress(PG_FUNCTION_ARGS); @@ -329,6 +330,60 @@ Datum pcpatch_from_pcpoint_array(PG_FUNCTION_ARGS) PG_RETURN_POINTER(serpa); } + +PG_FUNCTION_INFO_V1(pcpatch_from_float_array); +Datum pcpatch_from_float_array(PG_FUNCTION_ARGS) +{ + int i, ndims, nelems, npoints; + float8 *vals; + PCPATCH *pa; + PCPOINTLIST *pl; + SERIALIZED_PATCH *serpa; + uint32 pcid = PG_GETARG_INT32(0); + ArrayType *arrptr = PG_GETARG_ARRAYTYPE_P(1); + PCSCHEMA *schema = pc_schema_from_pcid(pcid, fcinfo); + + if ( ! schema ) + elog(ERROR, "unable to load schema for pcid = %d", pcid); + + if ( ARR_ELEMTYPE(arrptr) != FLOAT8OID ) + elog(ERROR, "array must be of float8[]"); + + if ( ARR_NDIM(arrptr) != 1 ) + elog(ERROR, "float8[] must have one dimension"); + + if ( ARR_HASNULL(arrptr) ) + elog(ERROR, "float8[] must not have null elements"); + + ndims = schema->ndims; + nelems = ARR_DIMS(arrptr)[0]; + + if ( nelems % ndims != 0 ) { + elog(ERROR, "array dimensions do not match schema dimensions of pcid = %d", pcid); + } + + npoints = nelems / ndims; + + vals = (float8*) ARR_DATA_PTR(arrptr); + pl = pc_pointlist_make(nelems); + + for ( i = 0; i < npoints; ++i ) { + + PCPOINT* pt = pc_point_from_double_array(schema, vals, i * ndims, ndims); + pc_pointlist_add_point(pl, pt); + } + + pa = pc_patch_from_pointlist(pl); + pc_pointlist_free(pl); + if ( ! pa ) + PG_RETURN_NULL(); + + serpa = pc_patch_serialize(pa, NULL); + + pc_patch_free(pa); + PG_RETURN_POINTER(serpa); +} + typedef struct { ArrayBuildState *s; diff --git a/pgsql/pc_inout.c b/pgsql/pc_inout.c index 9eafc48..1378a80 100644 --- a/pgsql/pc_inout.c +++ b/pgsql/pc_inout.c @@ -224,7 +224,7 @@ Datum pcpoint_from_double_array(PG_FUNCTION_ARGS) elog(ERROR, "array dimensions do not match schema dimensions of pcid = %d", pcid); vals = (float8*) ARR_DATA_PTR(arrptr); - pt = pc_point_from_double_array(schema, vals, nelems); + pt = pc_point_from_double_array(schema, vals, 0, nelems); serpt = pc_point_serialize(pt); pc_point_free(pt); diff --git a/pgsql/pointcloud.sql.in b/pgsql/pointcloud.sql.in index d0a1d78..bed0cd7 100644 --- a/pgsql/pointcloud.sql.in +++ b/pgsql/pointcloud.sql.in @@ -229,6 +229,11 @@ CREATE OR REPLACE FUNCTION PC_AsBinary(p pcpoint) -- PCPATCH ------------------------------------------------------------------- + +CREATE OR REPLACE FUNCTION PC_MakePatch(pcid integer, vals float8[]) + RETURNS pcpatch AS 'MODULE_PATHNAME', 'pcpatch_from_float_array' + LANGUAGE 'c' IMMUTABLE STRICT; + CREATE OR REPLACE FUNCTION pcpatch_in(cstring) RETURNS pcpatch AS 'MODULE_PATHNAME', 'pcpatch_in' LANGUAGE 'c' IMMUTABLE STRICT; diff --git a/pgsql/sql/pointcloud.sql b/pgsql/sql/pointcloud.sql index f2bf5f6..8552d9d 100644 --- a/pgsql/sql/pointcloud.sql +++ b/pgsql/sql/pointcloud.sql @@ -451,4 +451,9 @@ SELECT PC_AsText(PC_Transform(p, 10, 1.0)) t, PC_Summary(PC_Transform(p, 10, 1.0))::json->'compr' c FROM ( SELECT PC_Patch(PC_MakePoint(1, ARRAY[-1,0,4862413,1])) p ) foo; + +-- test PC_Patch from float8 array +SELECT pc_astext(PC_MakePatch(1, ARRAY[-1,0,5,1, -1,0,6,1, -1,0,7,1])); + + TRUNCATE pointcloud_formats;