mirror of
https://github.com/pgpointcloud/pointcloud.git
synced 2025-12-08 20:36:04 +00:00
Merge pull request #291 from pblottiere/upgrade_code_layout
Use custom LLVM clang-format style for .c and .h files
This commit is contained in:
commit
ecbc19741c
2
.clang-format
Normal file
2
.clang-format
Normal file
@ -0,0 +1,2 @@
|
||||
BasedOnStyle: llvm
|
||||
BreakBeforeBraces: Allman
|
||||
@ -4,22 +4,6 @@
|
||||
root = true
|
||||
|
||||
# tab indentation
|
||||
[**.{c,h,c.in,hpp,cpp}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[sort_r.h]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[**.{sql.in,sql}]
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
@ -27,11 +11,3 @@ end_of_line = lf
|
||||
insert_final_newline = true
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
|
||||
|
||||
# Matches the exact file .travis.yml
|
||||
[.travis.yml]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
|
||||
|
||||
14
.github/workflows/code_layout.yml
vendored
14
.github/workflows/code_layout.yml
vendored
@ -7,8 +7,18 @@ on:
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
code:
|
||||
name: Code layout
|
||||
c_code_layout:
|
||||
name: C linter
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- name: Check out repository code
|
||||
uses: actions/checkout@v2
|
||||
- name: Install clang-format
|
||||
run: sudo apt-get install clang-format
|
||||
- name: Clang-format check
|
||||
run: clang-format --dry-run --Werror -style=file lib/*.c lib/*.cpp lib/*.hpp lib/*.h lib/cunit/*.c lib/cunit/*.h
|
||||
sql_code_layout:
|
||||
name: SQL linter
|
||||
runs-on: ubuntu-18.04
|
||||
steps:
|
||||
- name: Install nvm
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
/***********************************************************************
|
||||
* cu_pc_schema.c
|
||||
*
|
||||
* Testing for the schema API functions
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
* cu_pc_schema.c
|
||||
*
|
||||
* Testing for the schema API functions
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "CUnit/Basic.h"
|
||||
#include "cu_tester.h"
|
||||
@ -16,526 +16,514 @@ static PCSCHEMA *schema = NULL;
|
||||
static const char *xmlfile = "data/pdal-schema.xml";
|
||||
|
||||
/* Setup/teardown for this suite */
|
||||
static int
|
||||
init_suite(void)
|
||||
static int init_suite(void)
|
||||
{
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !schema ) return 1;
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!schema)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
clean_suite(void)
|
||||
static int clean_suite(void)
|
||||
{
|
||||
pc_schema_free(schema);
|
||||
return 0;
|
||||
pc_schema_free(schema);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* TESTS **************************************************************/
|
||||
|
||||
|
||||
static PCBYTES initbytes(uint8_t *bytes, size_t size, uint32_t interp)
|
||||
{
|
||||
PCBYTES pcb;
|
||||
pcb.bytes = bytes;
|
||||
pcb.size = size;
|
||||
pcb.interpretation = interp;
|
||||
pcb.npoints = pcb.size / pc_interpretation_size(pcb.interpretation);
|
||||
pcb.compression = PC_DIM_NONE;
|
||||
pcb.readonly = PC_TRUE;
|
||||
return pcb;
|
||||
PCBYTES pcb;
|
||||
pcb.bytes = bytes;
|
||||
pcb.size = size;
|
||||
pcb.interpretation = interp;
|
||||
pcb.npoints = pcb.size / pc_interpretation_size(pcb.interpretation);
|
||||
pcb.compression = PC_DIM_NONE;
|
||||
pcb.readonly = PC_TRUE;
|
||||
return pcb;
|
||||
}
|
||||
|
||||
/*
|
||||
* Run-length encode a byte stream by word.
|
||||
* Lots of identical words means great
|
||||
* compression ratios.
|
||||
*/
|
||||
static void
|
||||
test_run_length_encoding()
|
||||
* Run-length encode a byte stream by word.
|
||||
* Lots of identical words means great
|
||||
* compression ratios.
|
||||
*/
|
||||
static void test_run_length_encoding()
|
||||
{
|
||||
char *bytes;
|
||||
int nr;
|
||||
PCBYTES pcb, epcb, pcb2;
|
||||
char *bytes;
|
||||
int nr;
|
||||
PCBYTES pcb, epcb, pcb2;
|
||||
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
uint32_t npoints;
|
||||
uint32_t interpretation;
|
||||
uint32_t compression;
|
||||
uint8_t *bytes;
|
||||
} PCBYTES;
|
||||
*/
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
uint32_t npoints;
|
||||
uint32_t interpretation;
|
||||
uint32_t compression;
|
||||
uint8_t *bytes;
|
||||
} PCBYTES;
|
||||
*/
|
||||
|
||||
bytes = "aaaabbbbccdde";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 5);
|
||||
bytes = "aaaabbbbccdde";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 5);
|
||||
|
||||
bytes = "a";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 1);
|
||||
bytes = "a";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 1);
|
||||
|
||||
bytes = "aa";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 1);
|
||||
bytes = "aa";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 1);
|
||||
|
||||
bytes = "ab";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 2);
|
||||
bytes = "ab";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 2);
|
||||
|
||||
bytes = "abcdefg";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 7);
|
||||
bytes = "abcdefg";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 7);
|
||||
|
||||
bytes = "aabcdefg";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 7);
|
||||
bytes = "aabcdefg";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 7);
|
||||
|
||||
bytes = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 1);
|
||||
bytes = "cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
||||
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
||||
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
||||
"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"
|
||||
"cccccccccccccccccccccccccccc";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
nr = pc_bytes_run_count(&pcb);
|
||||
CU_ASSERT_EQUAL(nr, 1);
|
||||
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
pcb2 = pc_bytes_run_length_decode(epcb);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
pcb2 = pc_bytes_run_length_decode(epcb);
|
||||
|
||||
CU_ASSERT_EQUAL(pcb.compression, PC_DIM_NONE);
|
||||
CU_ASSERT_EQUAL(epcb.compression, PC_DIM_RLE);
|
||||
CU_ASSERT_EQUAL(pcb2.compression, PC_DIM_NONE);
|
||||
CU_ASSERT_EQUAL(pcb.compression, PC_DIM_NONE);
|
||||
CU_ASSERT_EQUAL(epcb.compression, PC_DIM_RLE);
|
||||
CU_ASSERT_EQUAL(pcb2.compression, PC_DIM_NONE);
|
||||
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
CU_ASSERT_EQUAL(pcb.size, pcb2.size);
|
||||
CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
CU_ASSERT_EQUAL(pcb.size, pcb2.size);
|
||||
CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
|
||||
bytes = "aabcdefg";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
pcb2 = pc_bytes_run_length_decode(epcb);
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
CU_ASSERT_EQUAL(pcb.size, pcb2.size);
|
||||
CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
bytes = "aabcdefg";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
pcb2 = pc_bytes_run_length_decode(epcb);
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
CU_ASSERT_EQUAL(pcb.size, pcb2.size);
|
||||
CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
|
||||
bytes = (char *)((uint32_t[]){ 10, 10, 10, 20, 20, 30, 20, 20 });
|
||||
pcb = initbytes((uint8_t *)bytes, 8, PC_UINT32);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
pcb2 = pc_bytes_run_length_decode(epcb);
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
CU_ASSERT_EQUAL(pcb.size, pcb2.size);
|
||||
CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
|
||||
bytes = (char*)((uint16_t[]){ 10, 10, 10, 20, 20, 30, 20, 20 });
|
||||
pcb = initbytes((uint8_t *)bytes, 8, PC_UINT16);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
pcb2 = pc_bytes_run_length_decode(epcb);
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
CU_ASSERT_EQUAL(pcb.size, pcb2.size);
|
||||
CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
bytes = (char *)((uint32_t[]){10, 10, 10, 20, 20, 30, 20, 20});
|
||||
pcb = initbytes((uint8_t *)bytes, 8, PC_UINT32);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
pcb2 = pc_bytes_run_length_decode(epcb);
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
CU_ASSERT_EQUAL(pcb.size, pcb2.size);
|
||||
CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
|
||||
bytes = (char *)((uint16_t[]){10, 10, 10, 20, 20, 30, 20, 20});
|
||||
pcb = initbytes((uint8_t *)bytes, 8, PC_UINT16);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
pcb2 = pc_bytes_run_length_decode(epcb);
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
CU_ASSERT_EQUAL(pcb.size, pcb2.size);
|
||||
CU_ASSERT_EQUAL(pcb.npoints, pcb2.npoints);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Strip the common bits off a stream and pack the
|
||||
* remaining bits in behind. Test bit counting and
|
||||
* round-trip encode/decode paths.
|
||||
*/
|
||||
static void
|
||||
test_sigbits_encoding()
|
||||
* Strip the common bits off a stream and pack the
|
||||
* remaining bits in behind. Test bit counting and
|
||||
* round-trip encode/decode paths.
|
||||
*/
|
||||
static void test_sigbits_encoding()
|
||||
{
|
||||
uint8_t *bytes;
|
||||
uint16_t *bytes16, *ebytes16;
|
||||
uint32_t *bytes32, *ebytes32;
|
||||
uint64_t *bytes64, *ebytes64;
|
||||
uint8_t *bytes;
|
||||
uint16_t *bytes16, *ebytes16;
|
||||
uint32_t *bytes32, *ebytes32;
|
||||
uint64_t *bytes64, *ebytes64;
|
||||
|
||||
uint32_t count, nelems;
|
||||
uint8_t common8;
|
||||
uint16_t common16;
|
||||
uint32_t common32;
|
||||
uint64_t common64;
|
||||
PCBYTES pcb, epcb, pcb2;
|
||||
uint32_t count, nelems;
|
||||
uint8_t common8;
|
||||
uint16_t common16;
|
||||
uint32_t common32;
|
||||
uint64_t common64;
|
||||
PCBYTES pcb, epcb, pcb2;
|
||||
|
||||
/*
|
||||
01100001 a
|
||||
01100010 b
|
||||
01100011 c
|
||||
01100000 `
|
||||
*/
|
||||
bytes = (uint8_t *)"abc";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_UINT8);
|
||||
common8 = pc_bytes_sigbits_count_8(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(count, 6);
|
||||
CU_ASSERT_EQUAL(common8, '`');
|
||||
/*
|
||||
01100001 a
|
||||
01100010 b
|
||||
01100011 c
|
||||
01100000 `
|
||||
*/
|
||||
bytes = (uint8_t *)"abc";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_UINT8);
|
||||
common8 = pc_bytes_sigbits_count_8(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(count, 6);
|
||||
CU_ASSERT_EQUAL(common8, '`');
|
||||
|
||||
bytes = (uint8_t *)"abcdef";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_UINT8);
|
||||
common8 = pc_bytes_sigbits_count_8(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(count, 5);
|
||||
CU_ASSERT_EQUAL(common8, '`');
|
||||
bytes = (uint8_t *)"abcdef";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_UINT8);
|
||||
common8 = pc_bytes_sigbits_count_8(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(count, 5);
|
||||
CU_ASSERT_EQUAL(common8, '`');
|
||||
|
||||
/*
|
||||
0110000101100001 aa
|
||||
0110001001100010 bb
|
||||
0110001101100011 cc
|
||||
0110000000000000 24576
|
||||
*/
|
||||
bytes = (uint8_t *)"aabbcc";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_UINT16);
|
||||
count = pc_bytes_sigbits_count(&pcb);
|
||||
CU_ASSERT_EQUAL(count, 6);
|
||||
/*
|
||||
0110000101100001 aa
|
||||
0110001001100010 bb
|
||||
0110001101100011 cc
|
||||
0110000000000000 24576
|
||||
*/
|
||||
bytes = (uint8_t *)"aabbcc";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_UINT16);
|
||||
count = pc_bytes_sigbits_count(&pcb);
|
||||
CU_ASSERT_EQUAL(count, 6);
|
||||
|
||||
/*
|
||||
"abca" encoded:
|
||||
base a b c a
|
||||
01100000 01 10 11 01
|
||||
*/
|
||||
bytes = (uint8_t *)"abcaabcaabcbabcc";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen((char *)bytes), PC_INT8);
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
CU_ASSERT_EQUAL(epcb.bytes[0], 2); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[1], 96); /* common bits */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[2], 109); /* packed byte */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[3], 109); /* packed byte */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[4], 110); /* packed byte */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[5], 111); /* packed byte */
|
||||
pc_bytes_free(epcb);
|
||||
/*
|
||||
"abca" encoded:
|
||||
base a b c a
|
||||
01100000 01 10 11 01
|
||||
*/
|
||||
bytes = (uint8_t *)"abcaabcaabcbabcc";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen((char *)bytes), PC_INT8);
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
CU_ASSERT_EQUAL(epcb.bytes[0], 2); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[1], 96); /* common bits */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[2], 109); /* packed byte */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[3], 109); /* packed byte */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[4], 110); /* packed byte */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[5], 111); /* packed byte */
|
||||
pc_bytes_free(epcb);
|
||||
|
||||
/*
|
||||
"abca" encoded:
|
||||
base a b c d a b
|
||||
01100000 001 010 011 100 001 010
|
||||
*/
|
||||
bytes = (uint8_t *)"abcdab";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_INT8);
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
CU_ASSERT_EQUAL(epcb.bytes[0], 3); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[1], 96); /* common bits */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[2], 41); /* packed byte */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[3], 194); /* packed byte */
|
||||
/*
|
||||
"abca" encoded:
|
||||
base a b c d a b
|
||||
01100000 001 010 011 100 001 010
|
||||
*/
|
||||
bytes = (uint8_t *)"abcdab";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_INT8);
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
CU_ASSERT_EQUAL(epcb.bytes[0], 3); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[1], 96); /* common bits */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[2], 41); /* packed byte */
|
||||
CU_ASSERT_EQUAL(epcb.bytes[3], 194); /* packed byte */
|
||||
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[0], 'a');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[1], 'b');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[2], 'c');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[3], 'd');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[4], 'a');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[5], 'b');
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[0], 'a');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[1], 'b');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[2], 'c');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[3], 'd');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[4], 'a');
|
||||
CU_ASSERT_EQUAL(pcb2.bytes[5], 'b');
|
||||
|
||||
CU_ASSERT_EQUAL(pcb.compression, PC_DIM_NONE);
|
||||
CU_ASSERT_EQUAL(epcb.compression, PC_DIM_SIGBITS);
|
||||
CU_ASSERT_EQUAL(pcb2.compression, PC_DIM_NONE);
|
||||
CU_ASSERT_EQUAL(pcb.compression, PC_DIM_NONE);
|
||||
CU_ASSERT_EQUAL(epcb.compression, PC_DIM_SIGBITS);
|
||||
CU_ASSERT_EQUAL(pcb2.compression, PC_DIM_NONE);
|
||||
|
||||
pc_bytes_free(pcb2);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
pc_bytes_free(epcb);
|
||||
|
||||
/* Test the 16 bit implementation path */
|
||||
nelems = 6;
|
||||
bytes16 = (uint16_t[]){
|
||||
24929, /* 0110000101100001 */
|
||||
24930, /* 0110000101100010 */
|
||||
24931, /* 0110000101100011 */
|
||||
24932, /* 0110000101100100 */
|
||||
24933, /* 0110000101100101 */
|
||||
24934 /* 0110000101100110 */
|
||||
};
|
||||
/* encoded 0110000101100 001 010 011 100 101 110 */
|
||||
bytes = (uint8_t*)bytes16;
|
||||
pcb = initbytes(bytes, nelems*2, PC_INT16);
|
||||
/* Test the 16 bit implementation path */
|
||||
nelems = 6;
|
||||
bytes16 = (uint16_t[]){
|
||||
24929, /* 0110000101100001 */
|
||||
24930, /* 0110000101100010 */
|
||||
24931, /* 0110000101100011 */
|
||||
24932, /* 0110000101100100 */
|
||||
24933, /* 0110000101100101 */
|
||||
24934 /* 0110000101100110 */
|
||||
};
|
||||
/* encoded 0110000101100 001 010 011 100 101 110 */
|
||||
bytes = (uint8_t *)bytes16;
|
||||
pcb = initbytes(bytes, nelems * 2, PC_INT16);
|
||||
|
||||
/* Test the 16 bit implementation path */
|
||||
common16 = pc_bytes_sigbits_count_16(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(common16, 24928);
|
||||
CU_ASSERT_EQUAL(count, 13);
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
ebytes16 = (uint16_t*)(epcb.bytes);
|
||||
// printf("commonbits %d\n", commonbits);
|
||||
CU_ASSERT_EQUAL(ebytes16[0], 3); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(ebytes16[1], 24928); /* common bits */
|
||||
CU_ASSERT_EQUAL(ebytes16[2], 10699); /* packed uint16 one */
|
||||
/* Test the 16 bit implementation path */
|
||||
common16 = pc_bytes_sigbits_count_16(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(common16, 24928);
|
||||
CU_ASSERT_EQUAL(count, 13);
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
ebytes16 = (uint16_t *)(epcb.bytes);
|
||||
// printf("commonbits %d\n", commonbits);
|
||||
CU_ASSERT_EQUAL(ebytes16[0], 3); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(ebytes16[1], 24928); /* common bits */
|
||||
CU_ASSERT_EQUAL(ebytes16[2], 10699); /* packed uint16 one */
|
||||
|
||||
/* uint8_t* pc_bytes_sigbits_decode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems) */
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
pc_bytes_free(epcb);
|
||||
bytes16 = (uint16_t*)(pcb2.bytes);
|
||||
CU_ASSERT_EQUAL(bytes16[0], 24929);
|
||||
CU_ASSERT_EQUAL(bytes16[1], 24930);
|
||||
CU_ASSERT_EQUAL(bytes16[2], 24931);
|
||||
CU_ASSERT_EQUAL(bytes16[3], 24932);
|
||||
CU_ASSERT_EQUAL(bytes16[4], 24933);
|
||||
CU_ASSERT_EQUAL(bytes16[5], 24934);
|
||||
pc_bytes_free(pcb2);
|
||||
/* uint8_t* pc_bytes_sigbits_decode(const uint8_t *bytes, uint32_t
|
||||
* interpretation, uint32_t nelems) */
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
pc_bytes_free(epcb);
|
||||
bytes16 = (uint16_t *)(pcb2.bytes);
|
||||
CU_ASSERT_EQUAL(bytes16[0], 24929);
|
||||
CU_ASSERT_EQUAL(bytes16[1], 24930);
|
||||
CU_ASSERT_EQUAL(bytes16[2], 24931);
|
||||
CU_ASSERT_EQUAL(bytes16[3], 24932);
|
||||
CU_ASSERT_EQUAL(bytes16[4], 24933);
|
||||
CU_ASSERT_EQUAL(bytes16[5], 24934);
|
||||
pc_bytes_free(pcb2);
|
||||
|
||||
/* Test the 32 bit implementation path */
|
||||
nelems = 6;
|
||||
/* Test the 32 bit implementation path */
|
||||
nelems = 6;
|
||||
|
||||
bytes32 = (uint32_t[]){
|
||||
103241, /* 0000000000000001 1001 0011 0100 1001 */
|
||||
103251, /* 0000000000000001 1001 0011 0101 0011 */
|
||||
103261, /* 0000000000000001 1001 0011 0101 1101 */
|
||||
103271, /* 0000000000000001 1001 0011 0110 0111 */
|
||||
103281, /* 0000000000000001 1001 0011 0111 0001 */
|
||||
103291 /* 0000000000000001 1001 0011 0111 1011 */
|
||||
};
|
||||
bytes = (uint8_t*)bytes32;
|
||||
pcb = initbytes(bytes, nelems*4, PC_INT32);
|
||||
bytes32 = (uint32_t[]){
|
||||
103241, /* 0000000000000001 1001 0011 0100 1001 */
|
||||
103251, /* 0000000000000001 1001 0011 0101 0011 */
|
||||
103261, /* 0000000000000001 1001 0011 0101 1101 */
|
||||
103271, /* 0000000000000001 1001 0011 0110 0111 */
|
||||
103281, /* 0000000000000001 1001 0011 0111 0001 */
|
||||
103291 /* 0000000000000001 1001 0011 0111 1011 */
|
||||
};
|
||||
bytes = (uint8_t *)bytes32;
|
||||
pcb = initbytes(bytes, nelems * 4, PC_INT32);
|
||||
|
||||
common32 = pc_bytes_sigbits_count_32(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(count, 26); /* common bits count */
|
||||
CU_ASSERT_EQUAL(common32, 103232);
|
||||
common32 = pc_bytes_sigbits_count_32(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(count, 26); /* common bits count */
|
||||
CU_ASSERT_EQUAL(common32, 103232);
|
||||
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
ebytes32 = (uint32_t*)(epcb.bytes);
|
||||
CU_ASSERT_EQUAL(ebytes32[0], 6); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(ebytes32[1], 103232); /* common bits */
|
||||
CU_ASSERT_EQUAL(ebytes32[2], 624388039); /* packed uint32 */
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
ebytes32 = (uint32_t *)(epcb.bytes);
|
||||
CU_ASSERT_EQUAL(ebytes32[0], 6); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(ebytes32[1], 103232); /* common bits */
|
||||
CU_ASSERT_EQUAL(ebytes32[2], 624388039); /* packed uint32 */
|
||||
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
pc_bytes_free(epcb);
|
||||
bytes32 = (uint32_t*)(pcb2.bytes);
|
||||
CU_ASSERT_EQUAL(bytes32[0], 103241);
|
||||
CU_ASSERT_EQUAL(bytes32[1], 103251);
|
||||
CU_ASSERT_EQUAL(bytes32[2], 103261);
|
||||
CU_ASSERT_EQUAL(bytes32[3], 103271);
|
||||
CU_ASSERT_EQUAL(bytes32[4], 103281);
|
||||
CU_ASSERT_EQUAL(bytes32[5], 103291);
|
||||
pc_bytes_free(pcb2);
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
pc_bytes_free(epcb);
|
||||
bytes32 = (uint32_t *)(pcb2.bytes);
|
||||
CU_ASSERT_EQUAL(bytes32[0], 103241);
|
||||
CU_ASSERT_EQUAL(bytes32[1], 103251);
|
||||
CU_ASSERT_EQUAL(bytes32[2], 103261);
|
||||
CU_ASSERT_EQUAL(bytes32[3], 103271);
|
||||
CU_ASSERT_EQUAL(bytes32[4], 103281);
|
||||
CU_ASSERT_EQUAL(bytes32[5], 103291);
|
||||
pc_bytes_free(pcb2);
|
||||
|
||||
/* What if all the words are the same? */
|
||||
nelems = 6;
|
||||
bytes16 = (uint16_t[]){
|
||||
24929, /* 0000000000000001 1001 0011 0100 1001 */
|
||||
24929, /* 0000000000000001 1001 0011 0101 0011 */
|
||||
24929, /* 0000000000000001 1001 0011 0101 1101 */
|
||||
24929, /* 0000000000000001 1001 0011 0110 0111 */
|
||||
24929, /* 0000000000000001 1001 0011 0111 0001 */
|
||||
24929 /* 0000000000000001 1001 0011 0111 1011 */
|
||||
};
|
||||
bytes = (uint8_t*)bytes16;
|
||||
pcb = initbytes(bytes, nelems*2, PC_INT16);
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
/* What if all the words are the same? */
|
||||
nelems = 6;
|
||||
bytes16 = (uint16_t[]){
|
||||
24929, /* 0000000000000001 1001 0011 0100 1001 */
|
||||
24929, /* 0000000000000001 1001 0011 0101 0011 */
|
||||
24929, /* 0000000000000001 1001 0011 0101 1101 */
|
||||
24929, /* 0000000000000001 1001 0011 0110 0111 */
|
||||
24929, /* 0000000000000001 1001 0011 0111 0001 */
|
||||
24929 /* 0000000000000001 1001 0011 0111 1011 */
|
||||
};
|
||||
bytes = (uint8_t *)bytes16;
|
||||
pcb = initbytes(bytes, nelems * 2, PC_INT16);
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
|
||||
/* Test the 64 bit implementation path */
|
||||
/* Test the 64 bit implementation path */
|
||||
|
||||
nelems = 6;
|
||||
nelems = 6;
|
||||
|
||||
bytes64 = (uint64_t[]){
|
||||
103241, /* 32x0 0000000000000001 1001 0011 0100 1001 */
|
||||
103251, /* 32x0 0000000000000001 1001 0011 0101 0011 */
|
||||
103261, /* 32x0 0000000000000001 1001 0011 0101 1101 */
|
||||
103271, /* 32x0 0000000000000001 1001 0011 0110 0111 */
|
||||
103281, /* 32x0 0000000000000001 1001 0011 0111 0001 */
|
||||
103291 /* 32x0 0000000000000001 1001 0011 0111 1011 */
|
||||
};
|
||||
bytes = (uint8_t*)bytes64;
|
||||
pcb = initbytes(bytes, nelems*8, PC_INT64);
|
||||
bytes64 = (uint64_t[]){
|
||||
103241, /* 32x0 0000000000000001 1001 0011 0100 1001 */
|
||||
103251, /* 32x0 0000000000000001 1001 0011 0101 0011 */
|
||||
103261, /* 32x0 0000000000000001 1001 0011 0101 1101 */
|
||||
103271, /* 32x0 0000000000000001 1001 0011 0110 0111 */
|
||||
103281, /* 32x0 0000000000000001 1001 0011 0111 0001 */
|
||||
103291 /* 32x0 0000000000000001 1001 0011 0111 1011 */
|
||||
};
|
||||
bytes = (uint8_t *)bytes64;
|
||||
pcb = initbytes(bytes, nelems * 8, PC_INT64);
|
||||
|
||||
common64 = pc_bytes_sigbits_count_64(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(count, 58); /* common bits count */
|
||||
CU_ASSERT_EQUAL(common64, 103232);
|
||||
common64 = pc_bytes_sigbits_count_64(&pcb, &count);
|
||||
CU_ASSERT_EQUAL(count, 58); /* common bits count */
|
||||
CU_ASSERT_EQUAL(common64, 103232);
|
||||
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
ebytes64 = (uint64_t*)(epcb.bytes);
|
||||
CU_ASSERT_EQUAL(ebytes64[0], 6); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(ebytes64[1], 103232); /* common bits */
|
||||
CU_ASSERT_EQUAL(ebytes64[2], 2681726210471362560); /* packed uint64 */
|
||||
epcb = pc_bytes_sigbits_encode(pcb);
|
||||
ebytes64 = (uint64_t *)(epcb.bytes);
|
||||
CU_ASSERT_EQUAL(ebytes64[0], 6); /* unique bit count */
|
||||
CU_ASSERT_EQUAL(ebytes64[1], 103232); /* common bits */
|
||||
CU_ASSERT_EQUAL(ebytes64[2], 2681726210471362560); /* packed uint64 */
|
||||
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
pc_bytes_free(epcb);
|
||||
bytes64 = (uint64_t*)(pcb2.bytes);
|
||||
CU_ASSERT_EQUAL(bytes64[0], 103241);
|
||||
CU_ASSERT_EQUAL(bytes64[1], 103251);
|
||||
CU_ASSERT_EQUAL(bytes64[2], 103261);
|
||||
CU_ASSERT_EQUAL(bytes64[3], 103271);
|
||||
CU_ASSERT_EQUAL(bytes64[4], 103281);
|
||||
CU_ASSERT_EQUAL(bytes64[5], 103291);
|
||||
pc_bytes_free(pcb2);
|
||||
pcb2 = pc_bytes_sigbits_decode(epcb);
|
||||
pc_bytes_free(epcb);
|
||||
bytes64 = (uint64_t *)(pcb2.bytes);
|
||||
CU_ASSERT_EQUAL(bytes64[0], 103241);
|
||||
CU_ASSERT_EQUAL(bytes64[1], 103251);
|
||||
CU_ASSERT_EQUAL(bytes64[2], 103261);
|
||||
CU_ASSERT_EQUAL(bytes64[3], 103271);
|
||||
CU_ASSERT_EQUAL(bytes64[4], 103281);
|
||||
CU_ASSERT_EQUAL(bytes64[5], 103291);
|
||||
pc_bytes_free(pcb2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Encode and decode a byte stream. Data matches?
|
||||
*/
|
||||
static void
|
||||
test_zlib_encoding()
|
||||
* Encode and decode a byte stream. Data matches?
|
||||
*/
|
||||
static void test_zlib_encoding()
|
||||
{
|
||||
uint8_t *bytes;
|
||||
PCBYTES pcb, epcb, pcb2;
|
||||
/*
|
||||
uint8_t *
|
||||
pc_bytes_zlib_encode(const uint8_t *bytes, uint32_t interpretation, uint32_t nelems)
|
||||
uint8_t *
|
||||
pc_bytes_zlib_decode(const uint8_t *bytes, uint32_t interpretation)
|
||||
*/
|
||||
bytes = (uint8_t *)"abcaabcaabcbabcc";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_INT8);
|
||||
epcb = pc_bytes_zlib_encode(pcb);
|
||||
pcb2 = pc_bytes_zlib_decode(epcb);
|
||||
uint8_t *bytes;
|
||||
PCBYTES pcb, epcb, pcb2;
|
||||
/*
|
||||
uint8_t *
|
||||
pc_bytes_zlib_encode(const uint8_t *bytes, uint32_t interpretation, uint32_t
|
||||
nelems) uint8_t * pc_bytes_zlib_decode(const uint8_t *bytes, uint32_t
|
||||
interpretation)
|
||||
*/
|
||||
bytes = (uint8_t *)"abcaabcaabcbabcc";
|
||||
pcb = initbytes(bytes, strlen((char *)bytes), PC_INT8);
|
||||
epcb = pc_bytes_zlib_encode(pcb);
|
||||
pcb2 = pc_bytes_zlib_decode(epcb);
|
||||
|
||||
CU_ASSERT_EQUAL(pcb.compression, PC_DIM_NONE);
|
||||
CU_ASSERT_EQUAL(epcb.compression, PC_DIM_ZLIB);
|
||||
CU_ASSERT_EQUAL(pcb2.compression, PC_DIM_NONE);
|
||||
CU_ASSERT_EQUAL(pcb.compression, PC_DIM_NONE);
|
||||
CU_ASSERT_EQUAL(epcb.compression, PC_DIM_ZLIB);
|
||||
CU_ASSERT_EQUAL(pcb2.compression, PC_DIM_NONE);
|
||||
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
CU_ASSERT_EQUAL(memcmp(pcb.bytes, pcb2.bytes, pcb.size), 0);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(pcb2);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_rle_filter()
|
||||
static void test_rle_filter()
|
||||
{
|
||||
char *bytes;
|
||||
PCBYTES pcb, epcb, fpcb;
|
||||
PCBITMAP *map1, *map2;
|
||||
int i;
|
||||
char *bytes;
|
||||
PCBYTES pcb, epcb, fpcb;
|
||||
PCBITMAP *map1, *map2;
|
||||
int i;
|
||||
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
uint32_t npoints;
|
||||
uint32_t interpretation;
|
||||
uint32_t compression;
|
||||
uint8_t *bytes;
|
||||
} PCBYTES;
|
||||
*/
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
uint32_t npoints;
|
||||
uint32_t interpretation;
|
||||
uint32_t compression;
|
||||
uint8_t *bytes;
|
||||
} PCBYTES;
|
||||
*/
|
||||
|
||||
bytes = "aaaabbbbccdd";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
CU_ASSERT_EQUAL(epcb.bytes[0], 4);
|
||||
bytes = "aaaabbbbccdd";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
CU_ASSERT_EQUAL(epcb.bytes[0], 4);
|
||||
|
||||
map1 = pc_bytes_bitmap(&epcb, PC_GT, 'b', 'b');
|
||||
CU_ASSERT_EQUAL(map1->nset, 4);
|
||||
map2 = pc_bytes_bitmap(&epcb, PC_GT, 'a', 'a');
|
||||
CU_ASSERT_EQUAL(map2->nset, 8);
|
||||
map1 = pc_bytes_bitmap(&epcb, PC_GT, 'b', 'b');
|
||||
CU_ASSERT_EQUAL(map1->nset, 4);
|
||||
map2 = pc_bytes_bitmap(&epcb, PC_GT, 'a', 'a');
|
||||
CU_ASSERT_EQUAL(map2->nset, 8);
|
||||
|
||||
fpcb = pc_bytes_filter(&epcb, map1, NULL);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[0], 2);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[1], 'c');
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[2], 2);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[3], 'd');
|
||||
CU_ASSERT_EQUAL(fpcb.size, 4);
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 4);
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bitmap_free(map1);
|
||||
fpcb = pc_bytes_filter(&epcb, map1, NULL);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[0], 2);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[1], 'c');
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[2], 2);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[3], 'd');
|
||||
CU_ASSERT_EQUAL(fpcb.size, 4);
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 4);
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bitmap_free(map1);
|
||||
|
||||
fpcb = pc_bytes_filter(&epcb, map2, NULL);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[0], 4);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[1], 'b');
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[2], 2);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[3], 'c');
|
||||
CU_ASSERT_EQUAL(fpcb.size, 6);
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 8);
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bitmap_free(map2);
|
||||
pc_bytes_free(epcb);
|
||||
fpcb = pc_bytes_filter(&epcb, map2, NULL);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[0], 4);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[1], 'b');
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[2], 2);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[3], 'c');
|
||||
CU_ASSERT_EQUAL(fpcb.size, 6);
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 8);
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bitmap_free(map2);
|
||||
pc_bytes_free(epcb);
|
||||
|
||||
bytes = (char *)((uint32_t[]){ 10, 10, 10, 20, 20, 30, 20, 20 });
|
||||
pcb = initbytes((uint8_t *)bytes, 8*4, PC_UINT32);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
map1 = pc_bytes_bitmap(&epcb, PC_LT, 25, 25); /* strip out the 30 */
|
||||
CU_ASSERT_EQUAL(map1->nset, 7);
|
||||
fpcb = pc_bytes_filter(&epcb, map1, NULL);
|
||||
CU_ASSERT_EQUAL(fpcb.size, 15); /* three runs (2x10, 2x20, 2x20), of 5 bytes eachh */
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 7);
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bytes_free(pcb);
|
||||
pc_bitmap_free(map1);
|
||||
bytes = (char *)((uint32_t[]){10, 10, 10, 20, 20, 30, 20, 20});
|
||||
pcb = initbytes((uint8_t *)bytes, 8 * 4, PC_UINT32);
|
||||
epcb = pc_bytes_run_length_encode(pcb);
|
||||
map1 = pc_bytes_bitmap(&epcb, PC_LT, 25, 25); /* strip out the 30 */
|
||||
CU_ASSERT_EQUAL(map1->nset, 7);
|
||||
fpcb = pc_bytes_filter(&epcb, map1, NULL);
|
||||
CU_ASSERT_EQUAL(fpcb.size,
|
||||
15); /* three runs (2x10, 2x20, 2x20), of 5 bytes eachh */
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 7);
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bytes_free(pcb);
|
||||
pc_bitmap_free(map1);
|
||||
|
||||
bytes = (char *)((uint16_t[]){ 1, 2, 3, 4, 5, 6, 7, 8 });
|
||||
pcb = initbytes((uint8_t *)bytes, 8*2, PC_UINT16);
|
||||
map1 = pc_bytes_bitmap(&pcb, PC_BETWEEN, 2.5, 4.5); /* everything except entries 3 and 4 */
|
||||
CU_ASSERT_EQUAL(map1->nset, 2);
|
||||
fpcb = pc_bytes_filter(&epcb, map1, NULL); /* Should have only two entry, 10, 20 */
|
||||
CU_ASSERT_EQUAL(fpcb.size, 10); /* two runs (1x10, 1x20), of 5 bytes eachh */
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 2);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[0], 1);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[5], 1);
|
||||
memcpy(&i, fpcb.bytes+1, 4);
|
||||
CU_ASSERT_EQUAL(i, 10);
|
||||
memcpy(&i, fpcb.bytes+6, 4);
|
||||
CU_ASSERT_EQUAL(i, 20);
|
||||
bytes = (char *)((uint16_t[]){1, 2, 3, 4, 5, 6, 7, 8});
|
||||
pcb = initbytes((uint8_t *)bytes, 8 * 2, PC_UINT16);
|
||||
map1 = pc_bytes_bitmap(&pcb, PC_BETWEEN, 2.5,
|
||||
4.5); /* everything except entries 3 and 4 */
|
||||
CU_ASSERT_EQUAL(map1->nset, 2);
|
||||
fpcb = pc_bytes_filter(&epcb, map1,
|
||||
NULL); /* Should have only two entry, 10, 20 */
|
||||
CU_ASSERT_EQUAL(fpcb.size, 10); /* two runs (1x10, 1x20), of 5 bytes eachh */
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 2);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[0], 1);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[5], 1);
|
||||
memcpy(&i, fpcb.bytes + 1, 4);
|
||||
CU_ASSERT_EQUAL(i, 10);
|
||||
memcpy(&i, fpcb.bytes + 6, 4);
|
||||
CU_ASSERT_EQUAL(i, 20);
|
||||
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bytes_free(pcb);
|
||||
pc_bitmap_free(map1);
|
||||
pc_bytes_free(epcb);
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bytes_free(pcb);
|
||||
pc_bitmap_free(map1);
|
||||
pc_bytes_free(epcb);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void
|
||||
test_uncompressed_filter()
|
||||
static void test_uncompressed_filter()
|
||||
{
|
||||
char *bytes;
|
||||
PCBYTES pcb, fpcb;
|
||||
PCBITMAP *map1;
|
||||
char *bytes;
|
||||
PCBYTES pcb, fpcb;
|
||||
PCBITMAP *map1;
|
||||
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
uint32_t npoints;
|
||||
uint32_t interpretation;
|
||||
uint32_t compression;
|
||||
uint8_t *bytes;
|
||||
} PCBYTES;
|
||||
*/
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
uint32_t npoints;
|
||||
uint32_t interpretation;
|
||||
uint32_t compression;
|
||||
uint8_t *bytes;
|
||||
} PCBYTES;
|
||||
*/
|
||||
|
||||
bytes = "aaaabbbbccdd";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
CU_ASSERT_EQUAL(pcb.bytes[0], 'a');
|
||||
CU_ASSERT_EQUAL(pcb.npoints, 12);
|
||||
bytes = "aaaabbbbccdd";
|
||||
pcb = initbytes((uint8_t *)bytes, strlen(bytes), PC_UINT8);
|
||||
CU_ASSERT_EQUAL(pcb.bytes[0], 'a');
|
||||
CU_ASSERT_EQUAL(pcb.npoints, 12);
|
||||
|
||||
map1 = pc_bytes_bitmap(&pcb, PC_GT, 'b', 'b');
|
||||
CU_ASSERT_EQUAL(map1->nset, 4);
|
||||
|
||||
fpcb = pc_bytes_filter(&pcb, map1, NULL);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[0], 'c');
|
||||
CU_ASSERT_EQUAL(fpcb.size, 4);
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 4);
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bitmap_free(map1);
|
||||
// pc_bytes_free(epcb);
|
||||
map1 = pc_bytes_bitmap(&pcb, PC_GT, 'b', 'b');
|
||||
CU_ASSERT_EQUAL(map1->nset, 4);
|
||||
|
||||
fpcb = pc_bytes_filter(&pcb, map1, NULL);
|
||||
CU_ASSERT_EQUAL(fpcb.bytes[0], 'c');
|
||||
CU_ASSERT_EQUAL(fpcb.size, 4);
|
||||
CU_ASSERT_EQUAL(fpcb.npoints, 4);
|
||||
pc_bytes_free(fpcb);
|
||||
pc_bitmap_free(map1);
|
||||
// pc_bytes_free(epcb);
|
||||
}
|
||||
|
||||
|
||||
/* REGISTER ***********************************************************/
|
||||
|
||||
CU_TestInfo bytes_tests[] = {
|
||||
PC_TEST(test_run_length_encoding),
|
||||
PC_TEST(test_sigbits_encoding),
|
||||
PC_TEST(test_zlib_encoding),
|
||||
PC_TEST(test_rle_filter),
|
||||
PC_TEST(test_uncompressed_filter),
|
||||
CU_TEST_INFO_NULL
|
||||
};
|
||||
PC_TEST(test_run_length_encoding), PC_TEST(test_sigbits_encoding),
|
||||
PC_TEST(test_zlib_encoding), PC_TEST(test_rle_filter),
|
||||
PC_TEST(test_uncompressed_filter), CU_TEST_INFO_NULL};
|
||||
|
||||
CU_SuiteInfo bytes_suite = {
|
||||
.pName = "bytes",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = bytes_tests
|
||||
};
|
||||
CU_SuiteInfo bytes_suite = {.pName = "bytes",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = bytes_tests};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,11 +1,11 @@
|
||||
/***********************************************************************
|
||||
* cu_pc_patch_lazperf.c
|
||||
*
|
||||
* Testing for the LazPerf API functions
|
||||
*
|
||||
* Copyright (c) 2016 Paul Blottiere, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
* cu_pc_patch_lazperf.c
|
||||
*
|
||||
* Testing for the LazPerf API functions
|
||||
*
|
||||
* Copyright (c) 2016 Paul Blottiere, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "CUnit/Basic.h"
|
||||
#include "cu_tester.h"
|
||||
@ -15,323 +15,318 @@
|
||||
static PCSCHEMA *simpleschema = NULL;
|
||||
static PCSCHEMA *multipledimschema = NULL;
|
||||
static const char *simplexmlfile = "data/simple-schema.xml";
|
||||
static const char *multipledimxmlfile = "data/simple-schema-laz-multiple-dim.xml";
|
||||
static const char *multipledimxmlfile =
|
||||
"data/simple-schema-laz-multiple-dim.xml";
|
||||
|
||||
/* Setup/teardown for this suite */
|
||||
static int
|
||||
init_suite(void)
|
||||
static int init_suite(void)
|
||||
{
|
||||
char *xmlstr = file_to_str(simplexmlfile);
|
||||
simpleschema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !simpleschema ) return 1;
|
||||
char *xmlstr = file_to_str(simplexmlfile);
|
||||
simpleschema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!simpleschema)
|
||||
return 1;
|
||||
|
||||
xmlstr = file_to_str(multipledimxmlfile);
|
||||
multipledimschema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !multipledimschema ) return 1;
|
||||
xmlstr = file_to_str(multipledimxmlfile);
|
||||
multipledimschema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!multipledimschema)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
clean_suite(void)
|
||||
static int clean_suite(void)
|
||||
{
|
||||
pc_schema_free(simpleschema);
|
||||
pc_schema_free(multipledimschema);
|
||||
return 0;
|
||||
pc_schema_free(simpleschema);
|
||||
pc_schema_free(multipledimschema);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_LAZPERF
|
||||
static void
|
||||
test_schema_compression_lazperf(void)
|
||||
static void test_schema_compression_lazperf(void)
|
||||
{
|
||||
PCSCHEMA *myschema = NULL;
|
||||
char *myxmlfile = "data/simple-schema-laz.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
myschema = pc_schema_from_xml(xmlstr);
|
||||
PCSCHEMA *myschema = NULL;
|
||||
char *myxmlfile = "data/simple-schema-laz.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
myschema = pc_schema_from_xml(xmlstr);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
int compression = myschema->compression;
|
||||
CU_ASSERT_EQUAL(compression, PC_LAZPERF);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
int compression = myschema->compression;
|
||||
CU_ASSERT_EQUAL(compression, PC_LAZPERF);
|
||||
|
||||
pc_schema_free(myschema);
|
||||
pcfree(xmlstr);
|
||||
pc_schema_free(myschema);
|
||||
pcfree(xmlstr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_patch_lazperf()
|
||||
static void test_patch_lazperf()
|
||||
{
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 400;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal;
|
||||
PCPATCH_UNCOMPRESSED *paul, *pauref;
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 400;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal;
|
||||
PCPATCH_UNCOMPRESSED *paul, *pauref;
|
||||
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
|
||||
for ( i = 0; i < npts; i++ )
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i*2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i*1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i*0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
for (i = 0; i < npts; i++)
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i * 2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i * 1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i * 0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
|
||||
// compress the list in a lazperf patch
|
||||
pal = pc_patch_lazperf_from_pointlist( pl );
|
||||
// compress the list in a lazperf patch
|
||||
pal = pc_patch_lazperf_from_pointlist(pl);
|
||||
|
||||
// get an uncompressed patch from the lazperf patch
|
||||
paul = pc_patch_uncompressed_from_lazperf( pal );
|
||||
// get an uncompressed patch from the lazperf patch
|
||||
paul = pc_patch_uncompressed_from_lazperf(pal);
|
||||
|
||||
// get an uncompressed patch directly from the pointlist
|
||||
pauref = pc_patch_uncompressed_from_pointlist( pl );
|
||||
// get an uncompressed patch directly from the pointlist
|
||||
pauref = pc_patch_uncompressed_from_pointlist(pl);
|
||||
|
||||
// test the number of points
|
||||
CU_ASSERT_EQUAL(pal->npoints, pauref->npoints);
|
||||
CU_ASSERT_EQUAL(paul->npoints, pauref->npoints);
|
||||
// test the number of points
|
||||
CU_ASSERT_EQUAL(pal->npoints, pauref->npoints);
|
||||
CU_ASSERT_EQUAL(paul->npoints, pauref->npoints);
|
||||
|
||||
// test bounds
|
||||
CU_ASSERT_DOUBLE_EQUAL(pal->bounds.xmax, pauref->bounds.xmax, 0.0001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(paul->bounds.ymax, pauref->bounds.ymax, 0.000001);
|
||||
// test bounds
|
||||
CU_ASSERT_DOUBLE_EQUAL(pal->bounds.xmax, pauref->bounds.xmax, 0.0001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(paul->bounds.ymax, pauref->bounds.ymax, 0.000001);
|
||||
|
||||
// test type
|
||||
CU_ASSERT_EQUAL(pal->type, PC_LAZPERF);
|
||||
CU_ASSERT_EQUAL(paul->type, pauref->type);
|
||||
// test type
|
||||
CU_ASSERT_EQUAL(pal->type, PC_LAZPERF);
|
||||
CU_ASSERT_EQUAL(paul->type, pauref->type);
|
||||
|
||||
// test readonly
|
||||
CU_ASSERT_EQUAL(pauref->readonly, paul->readonly);
|
||||
CU_ASSERT_EQUAL(pauref->readonly, pal->readonly);
|
||||
// test readonly
|
||||
CU_ASSERT_EQUAL(pauref->readonly, paul->readonly);
|
||||
CU_ASSERT_EQUAL(pauref->readonly, pal->readonly);
|
||||
|
||||
// test datasize
|
||||
CU_ASSERT_EQUAL(paul->datasize, pauref->datasize);
|
||||
// test datasize
|
||||
CU_ASSERT_EQUAL(paul->datasize, pauref->datasize);
|
||||
|
||||
// free
|
||||
pc_pointlist_free(pl);
|
||||
pc_patch_free( (PCPATCH*) pal );
|
||||
pc_patch_free((PCPATCH*) paul);
|
||||
pc_patch_free((PCPATCH*) pauref);
|
||||
// free
|
||||
pc_pointlist_free(pl);
|
||||
pc_patch_free((PCPATCH *)pal);
|
||||
pc_patch_free((PCPATCH *)paul);
|
||||
pc_patch_free((PCPATCH *)pauref);
|
||||
}
|
||||
|
||||
static void
|
||||
test_pointlist_lazperf()
|
||||
static void test_pointlist_lazperf()
|
||||
{
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 400;
|
||||
PCPOINTLIST *pl1, *pl2;
|
||||
PCPATCH_LAZPERF *pch1;
|
||||
PCPATCH_UNCOMPRESSED *pa1, *pa2;
|
||||
char *wkt1, *wkt2;
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 400;
|
||||
PCPOINTLIST *pl1, *pl2;
|
||||
PCPATCH_LAZPERF *pch1;
|
||||
PCPATCH_UNCOMPRESSED *pa1, *pa2;
|
||||
char *wkt1, *wkt2;
|
||||
|
||||
// build a list of points
|
||||
pl1 = pc_pointlist_make(npts);
|
||||
// build a list of points
|
||||
pl1 = pc_pointlist_make(npts);
|
||||
|
||||
for ( i = 0; i < npts; i++ )
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i*2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i*1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i*0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl1, pt);
|
||||
}
|
||||
for (i = 0; i < npts; i++)
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i * 2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i * 1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i * 0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl1, pt);
|
||||
}
|
||||
|
||||
// compress the list in a lazperf patch
|
||||
pch1 = pc_patch_lazperf_from_pointlist( pl1 );
|
||||
// compress the list in a lazperf patch
|
||||
pch1 = pc_patch_lazperf_from_pointlist(pl1);
|
||||
|
||||
// decompress the lazperf patch in a pointlist
|
||||
pl2 = pc_pointlist_from_lazperf(pch1);
|
||||
// decompress the lazperf patch in a pointlist
|
||||
pl2 = pc_pointlist_from_lazperf(pch1);
|
||||
|
||||
// test that the string representation of pointlist is equal
|
||||
pa1 = pc_patch_uncompressed_from_pointlist( pl1 );
|
||||
pa2 = pc_patch_uncompressed_from_lazperf( pch1 );
|
||||
// test that the string representation of pointlist is equal
|
||||
pa1 = pc_patch_uncompressed_from_pointlist(pl1);
|
||||
pa2 = pc_patch_uncompressed_from_lazperf(pch1);
|
||||
|
||||
wkt1 = pc_patch_uncompressed_to_string(pa1);
|
||||
wkt2 = pc_patch_uncompressed_to_string(pa2);
|
||||
wkt1 = pc_patch_uncompressed_to_string(pa1);
|
||||
wkt2 = pc_patch_uncompressed_to_string(pa2);
|
||||
|
||||
CU_ASSERT_STRING_EQUAL(wkt1, wkt2);
|
||||
CU_ASSERT_STRING_EQUAL(wkt1, wkt2);
|
||||
|
||||
pc_patch_free((PCPATCH*) pch1 );
|
||||
pc_patch_free((PCPATCH*) pa1);
|
||||
pc_patch_free((PCPATCH*) pa2);
|
||||
pc_pointlist_free(pl1);
|
||||
pc_pointlist_free(pl2);
|
||||
pcfree(wkt1);
|
||||
pcfree(wkt2);
|
||||
pc_patch_free((PCPATCH *)pch1);
|
||||
pc_patch_free((PCPATCH *)pa1);
|
||||
pc_patch_free((PCPATCH *)pa2);
|
||||
pc_pointlist_free(pl1);
|
||||
pc_pointlist_free(pl2);
|
||||
pcfree(wkt1);
|
||||
pcfree(wkt2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_to_string_lazperf()
|
||||
static void test_to_string_lazperf()
|
||||
{
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 400;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal;
|
||||
PCPATCH_UNCOMPRESSED *pau;
|
||||
char *str1, *str2;
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 400;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal;
|
||||
PCPATCH_UNCOMPRESSED *pau;
|
||||
char *str1, *str2;
|
||||
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
|
||||
for ( i = 0; i < npts; i++ )
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i*2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i*1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i*0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
for (i = 0; i < npts; i++)
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i * 2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i * 1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i * 0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
|
||||
// build patch
|
||||
pau = pc_patch_uncompressed_from_pointlist(pl);
|
||||
pal = pc_patch_lazperf_from_pointlist(pl);
|
||||
// build patch
|
||||
pau = pc_patch_uncompressed_from_pointlist(pl);
|
||||
pal = pc_patch_lazperf_from_pointlist(pl);
|
||||
|
||||
// get string
|
||||
str1 = pc_patch_uncompressed_to_string(pau);
|
||||
str2 = pc_patch_lazperf_to_string(pal);
|
||||
// get string
|
||||
str1 = pc_patch_uncompressed_to_string(pau);
|
||||
str2 = pc_patch_lazperf_to_string(pal);
|
||||
|
||||
// compare
|
||||
CU_ASSERT_STRING_EQUAL(str1, str2);
|
||||
// compare
|
||||
CU_ASSERT_STRING_EQUAL(str1, str2);
|
||||
|
||||
// free
|
||||
pc_patch_free((PCPATCH*) pal);
|
||||
pc_patch_free((PCPATCH*) pau);
|
||||
pc_pointlist_free(pl);
|
||||
pcfree(str1);
|
||||
pcfree(str2);
|
||||
// free
|
||||
pc_patch_free((PCPATCH *)pal);
|
||||
pc_patch_free((PCPATCH *)pau);
|
||||
pc_pointlist_free(pl);
|
||||
pcfree(str1);
|
||||
pcfree(str2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_wkb_lazperf()
|
||||
static void test_wkb_lazperf()
|
||||
{
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 400;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal1, *pal2;
|
||||
PCPATCH_UNCOMPRESSED *pau;
|
||||
uint8_t *wkb1, *wkb2;
|
||||
size_t wkbsize;
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 400;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal1, *pal2;
|
||||
PCPATCH_UNCOMPRESSED *pau;
|
||||
uint8_t *wkb1, *wkb2;
|
||||
size_t wkbsize;
|
||||
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
|
||||
for ( i = 0; i < npts; i++ )
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i*2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i*1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i*0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
for (i = 0; i < npts; i++)
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i * 2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i * 1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i * 0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
|
||||
// build patch lazperf
|
||||
pal1 = pc_patch_lazperf_from_pointlist(pl);
|
||||
// build patch lazperf
|
||||
pal1 = pc_patch_lazperf_from_pointlist(pl);
|
||||
|
||||
// get the corresponding wkb
|
||||
wkb1 = pc_patch_lazperf_to_wkb(pal1, &wkbsize);
|
||||
// get the corresponding wkb
|
||||
wkb1 = pc_patch_lazperf_to_wkb(pal1, &wkbsize);
|
||||
|
||||
// rebuild a lazperf patch thanks to the wkb
|
||||
pal2 = (PCPATCH_LAZPERF*) pc_patch_lazperf_from_wkb( pal1->schema, wkb1, wkbsize);
|
||||
// rebuild a lazperf patch thanks to the wkb
|
||||
pal2 =
|
||||
(PCPATCH_LAZPERF *)pc_patch_lazperf_from_wkb(pal1->schema, wkb1, wkbsize);
|
||||
|
||||
// get the wkb reference
|
||||
pau = pc_patch_uncompressed_from_pointlist(pl);
|
||||
wkb2 = pc_patch_uncompressed_to_wkb( pau, &wkbsize );
|
||||
// get the wkb reference
|
||||
pau = pc_patch_uncompressed_from_pointlist(pl);
|
||||
wkb2 = pc_patch_uncompressed_to_wkb(pau, &wkbsize);
|
||||
|
||||
// compare wkb
|
||||
CU_ASSERT_STRING_EQUAL(wkb1, wkb2);
|
||||
// compare wkb
|
||||
CU_ASSERT_STRING_EQUAL(wkb1, wkb2);
|
||||
|
||||
// free
|
||||
pc_patch_free((PCPATCH*) pal1);
|
||||
pc_patch_free((PCPATCH*) pal2);
|
||||
pc_patch_free((PCPATCH*) pau);
|
||||
pc_pointlist_free(pl);
|
||||
pcfree(wkb1);
|
||||
pcfree(wkb2);
|
||||
// free
|
||||
pc_patch_free((PCPATCH *)pal1);
|
||||
pc_patch_free((PCPATCH *)pal2);
|
||||
pc_patch_free((PCPATCH *)pau);
|
||||
pc_pointlist_free(pl);
|
||||
pcfree(wkb1);
|
||||
pcfree(wkb2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_patch_filter_lazperf_zero_point()
|
||||
static void test_patch_filter_lazperf_zero_point()
|
||||
{
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 5;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal;
|
||||
PCPATCH *pa;
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 5;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal;
|
||||
PCPATCH *pa;
|
||||
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
|
||||
for ( i = 0; i < npts; i++ )
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i*2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i*1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i*0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
for (i = 0; i < npts; i++)
|
||||
{
|
||||
pt = pc_point_make(simpleschema);
|
||||
pc_point_set_double_by_name(pt, "x", i * 2.0);
|
||||
pc_point_set_double_by_name(pt, "y", i * 1.9);
|
||||
pc_point_set_double_by_name(pt, "Z", i * 0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
|
||||
// build patch lazperf
|
||||
pal = pc_patch_lazperf_from_pointlist(pl);
|
||||
// build patch lazperf
|
||||
pal = pc_patch_lazperf_from_pointlist(pl);
|
||||
|
||||
// filter with a resulting patch of 0 point(s)
|
||||
pa = pc_patch_filter((PCPATCH*) pal, 0, PC_BETWEEN, 0.0, 0.0);
|
||||
CU_ASSERT_EQUAL(pa->npoints, 0);
|
||||
// filter with a resulting patch of 0 point(s)
|
||||
pa = pc_patch_filter((PCPATCH *)pal, 0, PC_BETWEEN, 0.0, 0.0);
|
||||
CU_ASSERT_EQUAL(pa->npoints, 0);
|
||||
|
||||
pc_patch_free((PCPATCH*) pal);
|
||||
pc_patch_free((PCPATCH*) pa);
|
||||
pc_pointlist_free(pl);
|
||||
pc_patch_free((PCPATCH *)pal);
|
||||
pc_patch_free((PCPATCH *)pa);
|
||||
pc_pointlist_free(pl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_patch_compression_with_multiple_dimension()
|
||||
static void test_patch_compression_with_multiple_dimension()
|
||||
{
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 5;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal;
|
||||
PCPATCH_UNCOMPRESSED *pau;
|
||||
char *str1, *str2;
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
int npts = 5;
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_LAZPERF *pal;
|
||||
PCPATCH_UNCOMPRESSED *pau;
|
||||
char *str1, *str2;
|
||||
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
// build a list of points
|
||||
pl = pc_pointlist_make(npts);
|
||||
|
||||
for ( i = 0; i < npts; i++ )
|
||||
{
|
||||
pt = pc_point_make(multipledimschema);
|
||||
pc_point_set_double_by_name(pt, "x", i*2);
|
||||
pc_point_set_double_by_name(pt, "y", i*1.9);
|
||||
pc_point_set_double_by_name(pt, "z", i*0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
for (i = 0; i < npts; i++)
|
||||
{
|
||||
pt = pc_point_make(multipledimschema);
|
||||
pc_point_set_double_by_name(pt, "x", i * 2);
|
||||
pc_point_set_double_by_name(pt, "y", i * 1.9);
|
||||
pc_point_set_double_by_name(pt, "z", i * 0.34);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
|
||||
// build patchs
|
||||
pal = pc_patch_lazperf_from_pointlist(pl);
|
||||
pau = pc_patch_uncompressed_from_pointlist(pl);
|
||||
// build patchs
|
||||
pal = pc_patch_lazperf_from_pointlist(pl);
|
||||
pau = pc_patch_uncompressed_from_pointlist(pl);
|
||||
|
||||
// compare str result
|
||||
str1 = pc_patch_lazperf_to_string(pal);
|
||||
str2 = pc_patch_uncompressed_to_string(pau);
|
||||
// compare str result
|
||||
str1 = pc_patch_lazperf_to_string(pal);
|
||||
str2 = pc_patch_uncompressed_to_string(pau);
|
||||
|
||||
CU_ASSERT_STRING_EQUAL(str1, str2);
|
||||
CU_ASSERT_STRING_EQUAL(str1, str2);
|
||||
|
||||
pc_patch_free((PCPATCH*) pal);
|
||||
pc_patch_free((PCPATCH*) pau);
|
||||
pc_pointlist_free(pl);
|
||||
pcfree(str1);
|
||||
pcfree(str2);
|
||||
pc_patch_free((PCPATCH *)pal);
|
||||
pc_patch_free((PCPATCH *)pau);
|
||||
pc_pointlist_free(pl);
|
||||
pcfree(str1);
|
||||
pcfree(str2);
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -339,20 +334,17 @@ test_patch_compression_with_multiple_dimension()
|
||||
|
||||
CU_TestInfo lazperf_tests[] = {
|
||||
#ifdef HAVE_LAZPERF
|
||||
PC_TEST(test_schema_compression_lazperf),
|
||||
PC_TEST(test_patch_lazperf),
|
||||
PC_TEST(test_pointlist_lazperf),
|
||||
PC_TEST(test_to_string_lazperf),
|
||||
PC_TEST(test_wkb_lazperf),
|
||||
PC_TEST(test_patch_filter_lazperf_zero_point),
|
||||
PC_TEST(test_patch_compression_with_multiple_dimension),
|
||||
PC_TEST(test_schema_compression_lazperf),
|
||||
PC_TEST(test_patch_lazperf),
|
||||
PC_TEST(test_pointlist_lazperf),
|
||||
PC_TEST(test_to_string_lazperf),
|
||||
PC_TEST(test_wkb_lazperf),
|
||||
PC_TEST(test_patch_filter_lazperf_zero_point),
|
||||
PC_TEST(test_patch_compression_with_multiple_dimension),
|
||||
#endif
|
||||
CU_TEST_INFO_NULL
|
||||
};
|
||||
CU_TEST_INFO_NULL};
|
||||
|
||||
CU_SuiteInfo lazperf_suite = {
|
||||
.pName = "lazperf",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = lazperf_tests
|
||||
};
|
||||
CU_SuiteInfo lazperf_suite = {.pName = "lazperf",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = lazperf_tests};
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
/***********************************************************************
|
||||
* cu_pc_schema.c
|
||||
*
|
||||
* Testing for the schema API functions
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
* cu_pc_schema.c
|
||||
*
|
||||
* Testing for the schema API functions
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "CUnit/Basic.h"
|
||||
#include "cu_tester.h"
|
||||
@ -17,10 +17,10 @@ static PCSCHEMA *schema_xy = NULL;
|
||||
static PCSCHEMA *schema_xyz = NULL;
|
||||
static PCSCHEMA *schema_xym = NULL;
|
||||
static PCSCHEMA *schema_xyzm = NULL;
|
||||
static const char *xmlfile = "data/simple-schema.xml";
|
||||
static const char *xmlfile_xy = "data/simple-schema-xy.xml";
|
||||
static const char *xmlfile_xyz = "data/simple-schema-xyz.xml";
|
||||
static const char *xmlfile_xym = "data/simple-schema-xym.xml";
|
||||
static const char *xmlfile = "data/simple-schema.xml";
|
||||
static const char *xmlfile_xy = "data/simple-schema-xy.xml";
|
||||
static const char *xmlfile_xyz = "data/simple-schema-xyz.xml";
|
||||
static const char *xmlfile_xym = "data/simple-schema-xym.xml";
|
||||
static const char *xmlfile_xyzm = "data/simple-schema-xyzm.xml";
|
||||
|
||||
// SIMPLE SCHEMA
|
||||
@ -30,308 +30,294 @@ static const char *xmlfile_xyzm = "data/simple-schema-xyzm.xml";
|
||||
// int16_t intensity
|
||||
|
||||
/* Setup/teardown for this suite */
|
||||
static int
|
||||
init_suite(void)
|
||||
static int init_suite(void)
|
||||
{
|
||||
char *xmlstr;
|
||||
char *xmlstr;
|
||||
|
||||
xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !schema ) return 1;
|
||||
xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!schema)
|
||||
return 1;
|
||||
|
||||
xmlstr = file_to_str(xmlfile_xy);
|
||||
schema_xy = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !schema_xy ) return 1;
|
||||
xmlstr = file_to_str(xmlfile_xy);
|
||||
schema_xy = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!schema_xy)
|
||||
return 1;
|
||||
|
||||
xmlstr = file_to_str(xmlfile_xyz);
|
||||
schema_xyz = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !schema_xyz ) return 1;
|
||||
xmlstr = file_to_str(xmlfile_xyz);
|
||||
schema_xyz = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!schema_xyz)
|
||||
return 1;
|
||||
|
||||
xmlstr = file_to_str(xmlfile_xym);
|
||||
schema_xym = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !schema_xym ) return 1;
|
||||
xmlstr = file_to_str(xmlfile_xym);
|
||||
schema_xym = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!schema_xym)
|
||||
return 1;
|
||||
|
||||
xmlstr = file_to_str(xmlfile_xyzm);
|
||||
schema_xyzm = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !schema_xyzm ) return 1;
|
||||
return 0;
|
||||
xmlstr = file_to_str(xmlfile_xyzm);
|
||||
schema_xyzm = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!schema_xyzm)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
clean_suite(void)
|
||||
static int clean_suite(void)
|
||||
{
|
||||
pc_schema_free(schema);
|
||||
pc_schema_free(schema_xy);
|
||||
pc_schema_free(schema_xyz);
|
||||
pc_schema_free(schema_xym);
|
||||
pc_schema_free(schema_xyzm);
|
||||
return 0;
|
||||
pc_schema_free(schema);
|
||||
pc_schema_free(schema_xy);
|
||||
pc_schema_free(schema_xyz);
|
||||
pc_schema_free(schema_xym);
|
||||
pc_schema_free(schema_xyzm);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* TESTS **************************************************************/
|
||||
|
||||
static void
|
||||
test_point_hex_inout()
|
||||
static void test_point_hex_inout()
|
||||
{
|
||||
// byte: endianness (1 = NDR, 0 = XDR)
|
||||
// uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
// uchar[]: pointdata (interpret relative to pcid)
|
||||
// byte: endianness (1 = NDR, 0 = XDR)
|
||||
// uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
// uchar[]: pointdata (interpret relative to pcid)
|
||||
|
||||
double d;
|
||||
char *hexbuf = "00000000010000000100000002000000030004";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPOINT *pt = pc_point_from_wkb(schema, wkb, hexsize/2);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "X", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.01, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Y", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.02, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.03, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Intensity", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 4, 0.0001);
|
||||
CU_ASSERT_FAILURE(pc_point_get_double_by_name(pt, "M", &d));
|
||||
pc_point_free(pt);
|
||||
pcfree(wkb);
|
||||
|
||||
hexbuf = "01010000000100000002000000030000000500";
|
||||
hexsize = strlen(hexbuf);
|
||||
wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
pt = pc_point_from_wkb(schema, wkb, hexsize/2);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "X", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.01, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Y", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.02, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.03, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Intensity", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 5, 0.0001);
|
||||
CU_ASSERT_FAILURE(pc_point_get_double_by_name(pt, "M", &d));
|
||||
pc_point_free(pt);
|
||||
pcfree(wkb);
|
||||
double d;
|
||||
char *hexbuf = "00000000010000000100000002000000030004";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPOINT *pt = pc_point_from_wkb(schema, wkb, hexsize / 2);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "X", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.01, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Y", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.02, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.03, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Intensity", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 4, 0.0001);
|
||||
CU_ASSERT_FAILURE(pc_point_get_double_by_name(pt, "M", &d));
|
||||
pc_point_free(pt);
|
||||
pcfree(wkb);
|
||||
|
||||
hexbuf = "01010000000100000002000000030000000500";
|
||||
hexsize = strlen(hexbuf);
|
||||
wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
pt = pc_point_from_wkb(schema, wkb, hexsize / 2);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "X", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.01, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Y", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.02, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 0.03, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Intensity", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, 5, 0.0001);
|
||||
CU_ASSERT_FAILURE(pc_point_get_double_by_name(pt, "M", &d));
|
||||
pc_point_free(pt);
|
||||
pcfree(wkb);
|
||||
}
|
||||
|
||||
static void
|
||||
test_point_access()
|
||||
static void test_point_access()
|
||||
{
|
||||
PCPOINT *pt;
|
||||
double a1, a2, a3, a4, b1, b2, b3, b4;
|
||||
int idx = 0;
|
||||
double *allvals;
|
||||
PCPOINT *pt;
|
||||
double a1, a2, a3, a4, b1, b2, b3, b4;
|
||||
int idx = 0;
|
||||
double *allvals;
|
||||
|
||||
pt = pc_point_make(schema);
|
||||
CU_ASSERT_PTR_NOT_NULL( pt );
|
||||
pt = pc_point_make(schema);
|
||||
CU_ASSERT_PTR_NOT_NULL(pt);
|
||||
|
||||
/* One at a time */
|
||||
idx = 0;
|
||||
a1 = 1.5;
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_index(pt, idx, a1));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_index(pt, idx, &b1));
|
||||
// printf("d1=%g, d2=%g\n", a1, b1);
|
||||
CU_ASSERT_DOUBLE_EQUAL(a1, b1, 0.0000001);
|
||||
/* One at a time */
|
||||
idx = 0;
|
||||
a1 = 1.5;
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_index(pt, idx, a1));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_index(pt, idx, &b1));
|
||||
// printf("d1=%g, d2=%g\n", a1, b1);
|
||||
CU_ASSERT_DOUBLE_EQUAL(a1, b1, 0.0000001);
|
||||
|
||||
idx = 2;
|
||||
a2 = 1501500.12;
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_index(pt, idx, a2));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_index(pt, idx, &b2));
|
||||
CU_ASSERT_DOUBLE_EQUAL(a2, b2, 0.0000001);
|
||||
idx = 2;
|
||||
a2 = 1501500.12;
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_index(pt, idx, a2));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_index(pt, idx, &b2));
|
||||
CU_ASSERT_DOUBLE_EQUAL(a2, b2, 0.0000001);
|
||||
|
||||
a3 = 91;
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_name(pt, "Intensity", a3));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Intensity", &b3));
|
||||
CU_ASSERT_DOUBLE_EQUAL(a3, b3, 0.0000001);
|
||||
a3 = 91;
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_name(pt, "Intensity", a3));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Intensity", &b3));
|
||||
CU_ASSERT_DOUBLE_EQUAL(a3, b3, 0.0000001);
|
||||
|
||||
pc_point_free(pt);
|
||||
pc_point_free(pt);
|
||||
|
||||
/* All at once */
|
||||
pt = pc_point_make(schema);
|
||||
a1 = 1.5;
|
||||
a2 = 1501500.12;
|
||||
a3 = 91;
|
||||
a4 = 200;
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_index(pt, 0, a1));
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_index(pt, 1, a2));
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_name(pt, "Intensity", a3));
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_name(pt, "Z", a4));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_index(pt, 0, &b1));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_index(pt, 1, &b2));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Intensity", &b3));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &b4));
|
||||
CU_ASSERT_DOUBLE_EQUAL(a1, b1, 0.0000001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(a2, b2, 0.0000001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(a3, b3, 0.0000001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(a4, b4, 0.0000001);
|
||||
/* All at once */
|
||||
pt = pc_point_make(schema);
|
||||
a1 = 1.5;
|
||||
a2 = 1501500.12;
|
||||
a3 = 91;
|
||||
a4 = 200;
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_index(pt, 0, a1));
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_index(pt, 1, a2));
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_name(pt, "Intensity", a3));
|
||||
CU_ASSERT_SUCCESS(pc_point_set_double_by_name(pt, "Z", a4));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_index(pt, 0, &b1));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_index(pt, 1, &b2));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Intensity", &b3));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &b4));
|
||||
CU_ASSERT_DOUBLE_EQUAL(a1, b1, 0.0000001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(a2, b2, 0.0000001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(a3, b3, 0.0000001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(a4, b4, 0.0000001);
|
||||
|
||||
/* as a double array */
|
||||
pc_point_set_double_by_index(pt, 0, a1);
|
||||
pc_point_set_double_by_index(pt, 1, a2);
|
||||
pc_point_set_double_by_index(pt, 2, a3);
|
||||
pc_point_set_double_by_index(pt, 3, a4);
|
||||
allvals = pc_point_to_double_array(pt);
|
||||
CU_ASSERT_DOUBLE_EQUAL(allvals[0], a1, 0.0000001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(allvals[1], a2, 0.0000001);
|
||||
//printf("allvals[2]:%g\n", allvals[2]);
|
||||
CU_ASSERT_DOUBLE_EQUAL(allvals[2], a3, 0.0000001);
|
||||
//printf("allvals[3]:%g\n", allvals[3]);
|
||||
CU_ASSERT_DOUBLE_EQUAL(allvals[3], a4, 0.0000001);
|
||||
pcfree(allvals);
|
||||
|
||||
pc_point_free(pt);
|
||||
/* as a double array */
|
||||
pc_point_set_double_by_index(pt, 0, a1);
|
||||
pc_point_set_double_by_index(pt, 1, a2);
|
||||
pc_point_set_double_by_index(pt, 2, a3);
|
||||
pc_point_set_double_by_index(pt, 3, a4);
|
||||
allvals = pc_point_to_double_array(pt);
|
||||
CU_ASSERT_DOUBLE_EQUAL(allvals[0], a1, 0.0000001);
|
||||
CU_ASSERT_DOUBLE_EQUAL(allvals[1], a2, 0.0000001);
|
||||
// printf("allvals[2]:%g\n", allvals[2]);
|
||||
CU_ASSERT_DOUBLE_EQUAL(allvals[2], a3, 0.0000001);
|
||||
// printf("allvals[3]:%g\n", allvals[3]);
|
||||
CU_ASSERT_DOUBLE_EQUAL(allvals[3], a4, 0.0000001);
|
||||
pcfree(allvals);
|
||||
|
||||
pc_point_free(pt);
|
||||
}
|
||||
|
||||
static void
|
||||
test_point_xyzm()
|
||||
static void test_point_xyzm()
|
||||
{
|
||||
PCPOINT *pt;
|
||||
double x = 1;
|
||||
double y = 40;
|
||||
double z = 160;
|
||||
double m = 640;
|
||||
double d;
|
||||
PCPOINT *pt;
|
||||
double x = 1;
|
||||
double y = 40;
|
||||
double z = 160;
|
||||
double m = 640;
|
||||
double d;
|
||||
|
||||
pt = pc_point_make(schema_xyz);
|
||||
CU_ASSERT_PTR_NOT_NULL( pt );
|
||||
pt = pc_point_make(schema_xyz);
|
||||
CU_ASSERT_PTR_NOT_NULL(pt);
|
||||
|
||||
CU_ASSERT_SUCCESS(pc_point_set_x(pt, x));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "X", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, x, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_x(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, x, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_set_x(pt, x));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "X", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, x, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_x(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, x, 0.000001);
|
||||
|
||||
CU_ASSERT_SUCCESS(pc_point_set_y(pt, y));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Y", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, y, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_y(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, y, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_set_y(pt, y));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Y", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, y, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_y(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, y, 0.000001);
|
||||
|
||||
CU_ASSERT_SUCCESS(pc_point_set_z(pt, z));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, z, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_z(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, z, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_set_z(pt, z));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, z, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_z(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, z, 0.000001);
|
||||
|
||||
CU_ASSERT_FAILURE(pc_point_set_m(pt, m));
|
||||
CU_ASSERT_FAILURE(pc_point_get_double_by_name(pt, "M", &d));
|
||||
CU_ASSERT_FAILURE(pc_point_get_m(pt, &d));
|
||||
CU_ASSERT_FAILURE(pc_point_set_m(pt, m));
|
||||
CU_ASSERT_FAILURE(pc_point_get_double_by_name(pt, "M", &d));
|
||||
CU_ASSERT_FAILURE(pc_point_get_m(pt, &d));
|
||||
|
||||
pc_point_free(pt);
|
||||
pc_point_free(pt);
|
||||
|
||||
pt = pc_point_make(schema_xyzm);
|
||||
CU_ASSERT_PTR_NOT_NULL( pt );
|
||||
pt = pc_point_make(schema_xyzm);
|
||||
CU_ASSERT_PTR_NOT_NULL(pt);
|
||||
|
||||
CU_ASSERT_SUCCESS(pc_point_set_x(pt, x));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "X", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, x, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_x(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, x, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_set_x(pt, x));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "X", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, x, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_x(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, x, 0.000001);
|
||||
|
||||
CU_ASSERT_SUCCESS(pc_point_set_y(pt, y));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Y", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, y, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_y(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, y, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_set_y(pt, y));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Y", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, y, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_y(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, y, 0.000001);
|
||||
|
||||
CU_ASSERT_SUCCESS(pc_point_set_z(pt, z));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, z, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_z(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, z, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_set_z(pt, z));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "Z", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, z, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_z(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, z, 0.000001);
|
||||
|
||||
CU_ASSERT_SUCCESS(pc_point_set_m(pt, m));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "M", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, m, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_m(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, m, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_set_m(pt, m));
|
||||
CU_ASSERT_SUCCESS(pc_point_get_double_by_name(pt, "M", &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, m, 0.000001);
|
||||
CU_ASSERT_SUCCESS(pc_point_get_m(pt, &d));
|
||||
CU_ASSERT_DOUBLE_EQUAL(d, m, 0.000001);
|
||||
|
||||
pc_point_free(pt);
|
||||
pc_point_free(pt);
|
||||
}
|
||||
|
||||
void test_point_geometry_bytes(const PCSCHEMA *s, size_t expectedgeomwkbsize,
|
||||
const char *pthexbytes, const char *expectedgeomhexbytes)
|
||||
const char *pthexbytes,
|
||||
const char *expectedgeomhexbytes)
|
||||
{
|
||||
/* point
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uchar[]: data (interpret relative to pcid)
|
||||
*/
|
||||
/* point
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uchar[]: data (interpret relative to pcid)
|
||||
*/
|
||||
|
||||
/* geometry
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: point type (XYZ=01000080, XYM=01000040, XY=01000000, XYZM=010000C0)
|
||||
double[]: XY(Z?)(M?) coordinates
|
||||
*/
|
||||
/* geometry
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: point type (XYZ=01000080, XYM=01000040, XY=01000000,
|
||||
XYZM=010000C0) double[]: XY(Z?)(M?) coordinates
|
||||
*/
|
||||
|
||||
PCPOINT *pt;
|
||||
uint8_t *ptwkb, *geomwkb;
|
||||
char *geomhexbytes;
|
||||
size_t pthexsize, geomwkbsize;
|
||||
PCPOINT *pt;
|
||||
uint8_t *ptwkb, *geomwkb;
|
||||
char *geomhexbytes;
|
||||
size_t pthexsize, geomwkbsize;
|
||||
|
||||
pthexsize = strlen(pthexbytes);
|
||||
ptwkb = pc_bytes_from_hexbytes(pthexbytes, pthexsize);
|
||||
pt = pc_point_from_wkb(s, ptwkb, pthexsize/2);
|
||||
CU_ASSERT_PTR_NOT_NULL(pt);
|
||||
geomwkb = pc_point_to_geometry_wkb(pt, &geomwkbsize);
|
||||
CU_ASSERT_EQUAL(geomwkbsize,expectedgeomwkbsize);
|
||||
geomhexbytes = pc_hexbytes_from_bytes(geomwkb,geomwkbsize);
|
||||
CU_ASSERT_STRING_EQUAL(geomhexbytes, expectedgeomhexbytes);
|
||||
pthexsize = strlen(pthexbytes);
|
||||
ptwkb = pc_bytes_from_hexbytes(pthexbytes, pthexsize);
|
||||
pt = pc_point_from_wkb(s, ptwkb, pthexsize / 2);
|
||||
CU_ASSERT_PTR_NOT_NULL(pt);
|
||||
geomwkb = pc_point_to_geometry_wkb(pt, &geomwkbsize);
|
||||
CU_ASSERT_EQUAL(geomwkbsize, expectedgeomwkbsize);
|
||||
geomhexbytes = pc_hexbytes_from_bytes(geomwkb, geomwkbsize);
|
||||
CU_ASSERT_STRING_EQUAL(geomhexbytes, expectedgeomhexbytes);
|
||||
|
||||
pcfree(geomhexbytes);
|
||||
pcfree(geomwkb);
|
||||
pc_point_free(pt);
|
||||
pcfree(ptwkb);
|
||||
pcfree(geomhexbytes);
|
||||
pcfree(geomwkb);
|
||||
pc_point_free(pt);
|
||||
pcfree(ptwkb);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_point_geometry()
|
||||
static void test_point_geometry()
|
||||
{
|
||||
// pt XYI = 1 2 3, scale = 1 2 1, geom XY = 1 4
|
||||
test_point_geometry_bytes(schema_xy, 5+2*8,
|
||||
"000000000100000001000000020003",
|
||||
"0101000000000000000000F03F0000000000001040"
|
||||
);
|
||||
// pt XYI = 1 2 3, scale = 1 2 1, geom XY = 1 4
|
||||
test_point_geometry_bytes(schema_xy, 5 + 2 * 8,
|
||||
"000000000100000001000000020003",
|
||||
"0101000000000000000000F03F0000000000001040");
|
||||
|
||||
// pt XYZI = 1 2 3 4, scale = 1 2 4 1, geom XYZ = 1 2 3
|
||||
test_point_geometry_bytes(schema_xyz, 5+3*8,
|
||||
"00000000010000000100000002000000030004",
|
||||
"0101000080000000000000F03F00000000000010400000000000002840"
|
||||
);
|
||||
// pt XYZI = 1 2 3 4, scale = 1 2 4 1, geom XYZ = 1 2 3
|
||||
test_point_geometry_bytes(
|
||||
schema_xyz, 5 + 3 * 8, "00000000010000000100000002000000030004",
|
||||
"0101000080000000000000F03F00000000000010400000000000002840");
|
||||
|
||||
// pt XYMI = 1 2 3 4, scale = 1 2 4 1, geom XYM = 1 4 12
|
||||
test_point_geometry_bytes(schema_xym, 5+3*8,
|
||||
"00000000010000000100000002000000030004",
|
||||
"0101000040000000000000F03F00000000000010400000000000002840"
|
||||
);
|
||||
|
||||
// pt XYZMI = 1 2 3 4 5, scale = 1 2 4 8 1, geom XYZM = 1 4 12 32
|
||||
test_point_geometry_bytes(schema_xyzm, 5+4*8,
|
||||
"0000000001000000010000000200000003000000040005",
|
||||
"01010000C0000000000000F03F000000000000104000000000000028400000000000004040"
|
||||
);
|
||||
// pt XYMI = 1 2 3 4, scale = 1 2 4 1, geom XYM = 1 4 12
|
||||
test_point_geometry_bytes(
|
||||
schema_xym, 5 + 3 * 8, "00000000010000000100000002000000030004",
|
||||
"0101000040000000000000F03F00000000000010400000000000002840");
|
||||
|
||||
// pt XYZMI = 1 2 3 4 5, scale = 1 2 4 8 1, geom XYZM = 1 4 12 32
|
||||
test_point_geometry_bytes(schema_xyzm, 5 + 4 * 8,
|
||||
"0000000001000000010000000200000003000000040005",
|
||||
"01010000C0000000000000F03F000000000000104000000000"
|
||||
"000028400000000000004040");
|
||||
}
|
||||
|
||||
/* REGISTER ***********************************************************/
|
||||
|
||||
CU_TestInfo point_tests[] = {
|
||||
PC_TEST(test_point_hex_inout),
|
||||
PC_TEST(test_point_access),
|
||||
PC_TEST(test_point_xyzm),
|
||||
PC_TEST(test_point_geometry),
|
||||
CU_TEST_INFO_NULL
|
||||
};
|
||||
PC_TEST(test_point_hex_inout), PC_TEST(test_point_access),
|
||||
PC_TEST(test_point_xyzm), PC_TEST(test_point_geometry), CU_TEST_INFO_NULL};
|
||||
|
||||
CU_SuiteInfo point_suite = {
|
||||
.pName = "point",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = point_tests
|
||||
};
|
||||
CU_SuiteInfo point_suite = {.pName = "point",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = point_tests};
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
/***********************************************************************
|
||||
* cu_pc_schema.c
|
||||
*
|
||||
* Testing for the schema API functions
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
* cu_pc_schema.c
|
||||
*
|
||||
* Testing for the schema API functions
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "CUnit/Basic.h"
|
||||
#include "cu_tester.h"
|
||||
@ -16,449 +16,428 @@ static PCSCHEMA *schema = NULL;
|
||||
static const char *xmlfile = "data/pdal-schema.xml";
|
||||
|
||||
/* Setup/teardown for this suite */
|
||||
static int
|
||||
init_suite(void)
|
||||
static int init_suite(void)
|
||||
{
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
return schema ? 0 : -1;
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
return schema ? 0 : -1;
|
||||
}
|
||||
|
||||
static int
|
||||
clean_suite(void)
|
||||
static int clean_suite(void)
|
||||
{
|
||||
pc_schema_free(schema);
|
||||
return 0;
|
||||
pc_schema_free(schema);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* TESTS **************************************************************/
|
||||
|
||||
static void
|
||||
test_schema_from_xml()
|
||||
static void test_schema_from_xml()
|
||||
{
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
pcfree(xmlstr);
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
pcfree(xmlstr);
|
||||
|
||||
// char *schemastr = pc_schema_to_json(schema);
|
||||
// printf("ndims %d\n", schema->ndims);
|
||||
// printf("name0 %s\n", schema->dims[0]->name);
|
||||
// printf("%s\n", schemastr);
|
||||
// char *schemastr = pc_schema_to_json(schema);
|
||||
// printf("ndims %d\n", schema->ndims);
|
||||
// printf("name0 %s\n", schema->dims[0]->name);
|
||||
// printf("%s\n", schemastr);
|
||||
|
||||
pc_schema_free(myschema);
|
||||
pc_schema_free(myschema);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_from_xml_with_empty_description()
|
||||
static void test_schema_from_xml_with_empty_description()
|
||||
{
|
||||
char *myxmlfile = "data/simple-schema-empty-description.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
char *myxmlfile = "data/simple-schema-empty-description.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
|
||||
pc_schema_free(myschema);
|
||||
pcfree(xmlstr);
|
||||
pc_schema_free(myschema);
|
||||
pcfree(xmlstr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_from_xml_with_no_name()
|
||||
static void test_schema_from_xml_with_no_name()
|
||||
{
|
||||
char *myxmlfile = "data/simple-schema-no-name.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
char *myxmlfile = "data/simple-schema-no-name.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
|
||||
pc_schema_free(myschema);
|
||||
pcfree(xmlstr);
|
||||
pc_schema_free(myschema);
|
||||
pcfree(xmlstr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_from_xml_with_empty_name()
|
||||
static void test_schema_from_xml_with_empty_name()
|
||||
{
|
||||
char *myxmlfile = "data/simple-schema-empty-name.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
char *myxmlfile = "data/simple-schema-empty-name.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
|
||||
pc_schema_free(myschema);
|
||||
pcfree(xmlstr);
|
||||
pc_schema_free(myschema);
|
||||
pcfree(xmlstr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_size()
|
||||
static void test_schema_size()
|
||||
{
|
||||
size_t sz = schema->size;
|
||||
CU_ASSERT_EQUAL(sz, 37);
|
||||
size_t sz = schema->size;
|
||||
CU_ASSERT_EQUAL(sz, 37);
|
||||
}
|
||||
|
||||
static void
|
||||
test_dimension_get()
|
||||
static void test_dimension_get()
|
||||
{
|
||||
PCDIMENSION *d;
|
||||
PCDIMENSION *d;
|
||||
|
||||
d = pc_schema_get_dimension(schema, 0);
|
||||
CU_ASSERT_EQUAL(d->position, 0);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "X");
|
||||
d = pc_schema_get_dimension(schema, 0);
|
||||
CU_ASSERT_EQUAL(d->position, 0);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "X");
|
||||
|
||||
d = pc_schema_get_dimension(schema, 1);
|
||||
CU_ASSERT_EQUAL(d->position, 1);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "Y");
|
||||
d = pc_schema_get_dimension(schema, 1);
|
||||
CU_ASSERT_EQUAL(d->position, 1);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "Y");
|
||||
|
||||
d = pc_schema_get_dimension_by_name(schema, "nothinghere");
|
||||
CU_ASSERT_EQUAL(d, NULL);
|
||||
d = pc_schema_get_dimension_by_name(schema, "nothinghere");
|
||||
CU_ASSERT_EQUAL(d, NULL);
|
||||
|
||||
d = pc_schema_get_dimension_by_name(schema, "Z");
|
||||
CU_ASSERT_EQUAL(d->position, 2);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "Z");
|
||||
d = pc_schema_get_dimension_by_name(schema, "Z");
|
||||
CU_ASSERT_EQUAL(d->position, 2);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "Z");
|
||||
|
||||
d = pc_schema_get_dimension_by_name(schema, "z");
|
||||
CU_ASSERT_EQUAL(d->position, 2);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "Z");
|
||||
d = pc_schema_get_dimension_by_name(schema, "z");
|
||||
CU_ASSERT_EQUAL(d->position, 2);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "Z");
|
||||
|
||||
d = pc_schema_get_dimension_by_name(schema, "y");
|
||||
// printf("name %s\n", d->name);
|
||||
// printf("position %d\n", d->position);
|
||||
CU_ASSERT_EQUAL(d->position, 1);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "Y");
|
||||
d = pc_schema_get_dimension_by_name(schema, "y");
|
||||
// printf("name %s\n", d->name);
|
||||
// printf("position %d\n", d->position);
|
||||
CU_ASSERT_EQUAL(d->position, 1);
|
||||
CU_ASSERT_STRING_EQUAL(d->name, "Y");
|
||||
}
|
||||
|
||||
static void
|
||||
test_dimension_byteoffsets()
|
||||
static void test_dimension_byteoffsets()
|
||||
{
|
||||
PCDIMENSION *d;
|
||||
int i;
|
||||
int prev_byteoffset;
|
||||
int prev_size;
|
||||
int pc_size;
|
||||
|
||||
for ( i = 0; i < schema->ndims; i++ )
|
||||
{
|
||||
d = pc_schema_get_dimension(schema, i);
|
||||
// printf("d=%d name='%s' size=%d byteoffset=%d\n", i, d->name, d->size, d->byteoffset);
|
||||
if ( i > 0 )
|
||||
{
|
||||
CU_ASSERT_EQUAL(prev_size, pc_size);
|
||||
CU_ASSERT_EQUAL(prev_size, d->byteoffset - prev_byteoffset);
|
||||
}
|
||||
prev_byteoffset = d->byteoffset;
|
||||
prev_size = d->size;
|
||||
pc_size = pc_interpretation_size(d->interpretation);
|
||||
}
|
||||
PCDIMENSION *d;
|
||||
int i;
|
||||
int prev_byteoffset;
|
||||
int prev_size;
|
||||
int pc_size;
|
||||
|
||||
for (i = 0; i < schema->ndims; i++)
|
||||
{
|
||||
d = pc_schema_get_dimension(schema, i);
|
||||
// printf("d=%d name='%s' size=%d byteoffset=%d\n", i, d->name, d->size,
|
||||
// d->byteoffset);
|
||||
if (i > 0)
|
||||
{
|
||||
CU_ASSERT_EQUAL(prev_size, pc_size);
|
||||
CU_ASSERT_EQUAL(prev_size, d->byteoffset - prev_byteoffset);
|
||||
}
|
||||
prev_byteoffset = d->byteoffset;
|
||||
prev_size = d->size;
|
||||
pc_size = pc_interpretation_size(d->interpretation);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_invalid_xy()
|
||||
static void test_schema_invalid_xy()
|
||||
{
|
||||
// See https://github.com/pgpointcloud/pointcloud/issues/28
|
||||
char *xmlstr = "<pc:PointCloudSchema xmlns:pc='x'><pc:dimension>1</pc:dimension></pc:PointCloudSchema>";
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NULL(myschema);
|
||||
// See https://github.com/pgpointcloud/pointcloud/issues/28
|
||||
char *xmlstr =
|
||||
"<pc:PointCloudSchema "
|
||||
"xmlns:pc='x'><pc:dimension>1</pc:dimension></pc:PointCloudSchema>";
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NULL(myschema);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_missing_dimension()
|
||||
static void test_schema_missing_dimension()
|
||||
{
|
||||
char *myxmlfile = "data/simple-schema-missing-dimension.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
char *myxmlfile = "data/simple-schema-missing-dimension.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
|
||||
CU_ASSERT_PTR_NULL(myschema);
|
||||
CU_ASSERT_PTR_NULL(myschema);
|
||||
|
||||
pcfree(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
test_schema_empty()
|
||||
static void test_schema_empty()
|
||||
{
|
||||
char *xmlstr = "";
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
char *xmlstr = "";
|
||||
PCSCHEMA *myschema = pc_schema_from_xml(xmlstr);
|
||||
|
||||
CU_ASSERT_PTR_NULL(myschema);
|
||||
CU_ASSERT_PTR_NULL(myschema);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_compression(void)
|
||||
static void test_schema_compression(void)
|
||||
{
|
||||
int compression = schema->compression;
|
||||
CU_ASSERT_EQUAL(compression, PC_DIMENSIONAL);
|
||||
int compression = schema->compression;
|
||||
CU_ASSERT_EQUAL(compression, PC_DIMENSIONAL);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_clone(void)
|
||||
static void test_schema_clone(void)
|
||||
{
|
||||
int i;
|
||||
PCSCHEMA *clone = pc_schema_clone(schema);
|
||||
hashtable *hash, *chash;
|
||||
CU_ASSERT_EQUAL(clone->pcid, schema->pcid);
|
||||
CU_ASSERT_EQUAL(clone->ndims, schema->ndims);
|
||||
CU_ASSERT_EQUAL(clone->size, schema->size);
|
||||
CU_ASSERT_EQUAL(clone->srid, schema->srid);
|
||||
CU_ASSERT_EQUAL(clone->xdim->position, schema->xdim->position);
|
||||
CU_ASSERT_EQUAL(clone->ydim->position, schema->ydim->position);
|
||||
CU_ASSERT_EQUAL(clone->zdim->position, schema->zdim->position);
|
||||
CU_ASSERT_EQUAL(clone->mdim->position, schema->mdim->position);
|
||||
CU_ASSERT_EQUAL(clone->compression, schema->compression);
|
||||
CU_ASSERT_NOT_EQUAL(clone->xdim, schema->xdim); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->ydim, schema->ydim); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->zdim, schema->zdim); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->mdim, schema->mdim); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->dims, schema->dims); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->namehash, schema->namehash); /* deep clone */
|
||||
hash = schema->namehash;
|
||||
chash = clone->namehash;
|
||||
CU_ASSERT_EQUAL(chash->tablelength, hash->tablelength);
|
||||
CU_ASSERT_EQUAL(chash->entrycount, hash->entrycount);
|
||||
CU_ASSERT_EQUAL(chash->loadlimit, hash->loadlimit);
|
||||
CU_ASSERT_EQUAL(chash->primeindex, hash->primeindex);
|
||||
CU_ASSERT_EQUAL(chash->hashfn, hash->hashfn);
|
||||
CU_ASSERT_EQUAL(chash->eqfn, hash->eqfn);
|
||||
CU_ASSERT(chash->table != hash->table); /* deep clone */
|
||||
for (i=0; i<schema->ndims; ++i) {
|
||||
PCDIMENSION *dim = schema->dims[i];
|
||||
PCDIMENSION *cdim = clone->dims[i];
|
||||
CU_ASSERT(dim != cdim); /* deep clone */
|
||||
CU_ASSERT_STRING_EQUAL(cdim->name, dim->name);
|
||||
CU_ASSERT_STRING_EQUAL(cdim->description, dim->description);
|
||||
CU_ASSERT_EQUAL(cdim->position, dim->position);
|
||||
CU_ASSERT_EQUAL(cdim->size, dim->size);
|
||||
CU_ASSERT_EQUAL(cdim->byteoffset, dim->byteoffset);
|
||||
CU_ASSERT_EQUAL(cdim->interpretation, dim->interpretation);
|
||||
CU_ASSERT_EQUAL(cdim->scale, dim->scale);
|
||||
CU_ASSERT_EQUAL(cdim->offset, dim->offset);
|
||||
CU_ASSERT_EQUAL(cdim->active, dim->active);
|
||||
/* hash table is correctly setup */
|
||||
CU_ASSERT_EQUAL(cdim, hashtable_search(clone->namehash, dim->name) );
|
||||
}
|
||||
int i;
|
||||
PCSCHEMA *clone = pc_schema_clone(schema);
|
||||
hashtable *hash, *chash;
|
||||
CU_ASSERT_EQUAL(clone->pcid, schema->pcid);
|
||||
CU_ASSERT_EQUAL(clone->ndims, schema->ndims);
|
||||
CU_ASSERT_EQUAL(clone->size, schema->size);
|
||||
CU_ASSERT_EQUAL(clone->srid, schema->srid);
|
||||
CU_ASSERT_EQUAL(clone->xdim->position, schema->xdim->position);
|
||||
CU_ASSERT_EQUAL(clone->ydim->position, schema->ydim->position);
|
||||
CU_ASSERT_EQUAL(clone->zdim->position, schema->zdim->position);
|
||||
CU_ASSERT_EQUAL(clone->mdim->position, schema->mdim->position);
|
||||
CU_ASSERT_EQUAL(clone->compression, schema->compression);
|
||||
CU_ASSERT_NOT_EQUAL(clone->xdim, schema->xdim); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->ydim, schema->ydim); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->zdim, schema->zdim); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->mdim, schema->mdim); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->dims, schema->dims); /* deep clone */
|
||||
CU_ASSERT_NOT_EQUAL(clone->namehash, schema->namehash); /* deep clone */
|
||||
hash = schema->namehash;
|
||||
chash = clone->namehash;
|
||||
CU_ASSERT_EQUAL(chash->tablelength, hash->tablelength);
|
||||
CU_ASSERT_EQUAL(chash->entrycount, hash->entrycount);
|
||||
CU_ASSERT_EQUAL(chash->loadlimit, hash->loadlimit);
|
||||
CU_ASSERT_EQUAL(chash->primeindex, hash->primeindex);
|
||||
CU_ASSERT_EQUAL(chash->hashfn, hash->hashfn);
|
||||
CU_ASSERT_EQUAL(chash->eqfn, hash->eqfn);
|
||||
CU_ASSERT(chash->table != hash->table); /* deep clone */
|
||||
for (i = 0; i < schema->ndims; ++i)
|
||||
{
|
||||
PCDIMENSION *dim = schema->dims[i];
|
||||
PCDIMENSION *cdim = clone->dims[i];
|
||||
CU_ASSERT(dim != cdim); /* deep clone */
|
||||
CU_ASSERT_STRING_EQUAL(cdim->name, dim->name);
|
||||
CU_ASSERT_STRING_EQUAL(cdim->description, dim->description);
|
||||
CU_ASSERT_EQUAL(cdim->position, dim->position);
|
||||
CU_ASSERT_EQUAL(cdim->size, dim->size);
|
||||
CU_ASSERT_EQUAL(cdim->byteoffset, dim->byteoffset);
|
||||
CU_ASSERT_EQUAL(cdim->interpretation, dim->interpretation);
|
||||
CU_ASSERT_EQUAL(cdim->scale, dim->scale);
|
||||
CU_ASSERT_EQUAL(cdim->offset, dim->offset);
|
||||
CU_ASSERT_EQUAL(cdim->active, dim->active);
|
||||
/* hash table is correctly setup */
|
||||
CU_ASSERT_EQUAL(cdim, hashtable_search(clone->namehash, dim->name));
|
||||
}
|
||||
|
||||
pc_schema_free(clone);
|
||||
pc_schema_free(clone);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_clone_empty_description(void)
|
||||
static void test_schema_clone_empty_description(void)
|
||||
{
|
||||
PCSCHEMA *myschema, *clone;
|
||||
PCSCHEMA *myschema, *clone;
|
||||
|
||||
char *myxmlfile = "data/simple-schema-empty-description.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
char *myxmlfile = "data/simple-schema-empty-description.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
|
||||
myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
|
||||
clone = pc_schema_clone(myschema);
|
||||
CU_ASSERT_PTR_NOT_NULL(clone);
|
||||
CU_ASSERT_EQUAL(clone->ndims, myschema->ndims);
|
||||
CU_ASSERT_NOT_EQUAL(clone->dims[0]->name, myschema->dims[0]->name);
|
||||
CU_ASSERT_STRING_EQUAL(clone->dims[0]->name, myschema->dims[0]->name);
|
||||
CU_ASSERT_EQUAL(clone->dims[0]->description, myschema->dims[0]->description);
|
||||
pc_schema_free(myschema);
|
||||
pc_schema_free(clone);
|
||||
pcfree(xmlstr);
|
||||
clone = pc_schema_clone(myschema);
|
||||
CU_ASSERT_PTR_NOT_NULL(clone);
|
||||
CU_ASSERT_EQUAL(clone->ndims, myschema->ndims);
|
||||
CU_ASSERT_NOT_EQUAL(clone->dims[0]->name, myschema->dims[0]->name);
|
||||
CU_ASSERT_STRING_EQUAL(clone->dims[0]->name, myschema->dims[0]->name);
|
||||
CU_ASSERT_EQUAL(clone->dims[0]->description, myschema->dims[0]->description);
|
||||
pc_schema_free(myschema);
|
||||
pc_schema_free(clone);
|
||||
pcfree(xmlstr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_clone_no_name(void)
|
||||
static void test_schema_clone_no_name(void)
|
||||
{
|
||||
PCSCHEMA *myschema, *clone;
|
||||
PCSCHEMA *myschema, *clone;
|
||||
|
||||
/* See https://github.com/pgpointcloud/pointcloud/issues/66 */
|
||||
char *myxmlfile = "data/simple-schema-no-name.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
/* See https://github.com/pgpointcloud/pointcloud/issues/66 */
|
||||
char *myxmlfile = "data/simple-schema-no-name.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
|
||||
myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
clone = pc_schema_clone(myschema);
|
||||
CU_ASSERT_PTR_NOT_NULL(clone);
|
||||
CU_ASSERT_EQUAL(clone->ndims, myschema->ndims);
|
||||
CU_ASSERT_PTR_NULL(clone->dims[0]->name);
|
||||
CU_ASSERT_PTR_NULL(clone->dims[0]->description);
|
||||
pc_schema_free(myschema);
|
||||
pc_schema_free(clone);
|
||||
pcfree(xmlstr);
|
||||
myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
clone = pc_schema_clone(myschema);
|
||||
CU_ASSERT_PTR_NOT_NULL(clone);
|
||||
CU_ASSERT_EQUAL(clone->ndims, myschema->ndims);
|
||||
CU_ASSERT_PTR_NULL(clone->dims[0]->name);
|
||||
CU_ASSERT_PTR_NULL(clone->dims[0]->description);
|
||||
pc_schema_free(myschema);
|
||||
pc_schema_free(clone);
|
||||
pcfree(xmlstr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_clone_empty_name(void)
|
||||
static void test_schema_clone_empty_name(void)
|
||||
{
|
||||
PCSCHEMA *myschema, *clone;
|
||||
PCSCHEMA *myschema, *clone;
|
||||
|
||||
char *myxmlfile = "data/simple-schema-empty-name.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
char *myxmlfile = "data/simple-schema-empty-name.xml";
|
||||
char *xmlstr = file_to_str(myxmlfile);
|
||||
|
||||
myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
clone = pc_schema_clone(myschema);
|
||||
CU_ASSERT_PTR_NOT_NULL(clone);
|
||||
CU_ASSERT_EQUAL(clone->ndims, myschema->ndims);
|
||||
CU_ASSERT_PTR_NULL(clone->dims[0]->name);
|
||||
CU_ASSERT_PTR_NULL(clone->dims[0]->description);
|
||||
pc_schema_free(myschema);
|
||||
pc_schema_free(clone);
|
||||
pcfree(xmlstr);
|
||||
myschema = pc_schema_from_xml(xmlstr);
|
||||
CU_ASSERT_PTR_NOT_NULL(myschema);
|
||||
clone = pc_schema_clone(myschema);
|
||||
CU_ASSERT_PTR_NOT_NULL(clone);
|
||||
CU_ASSERT_EQUAL(clone->ndims, myschema->ndims);
|
||||
CU_ASSERT_PTR_NULL(clone->dims[0]->name);
|
||||
CU_ASSERT_PTR_NULL(clone->dims[0]->description);
|
||||
pc_schema_free(myschema);
|
||||
pc_schema_free(clone);
|
||||
pcfree(xmlstr);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_same_dimensions(void)
|
||||
static void test_schema_same_dimensions(void)
|
||||
{
|
||||
PCSCHEMA *s1, *s2;
|
||||
PCDIMENSION *tmp;
|
||||
PCDIMENSION dim;
|
||||
PCSCHEMA *s1, *s2;
|
||||
PCDIMENSION *tmp;
|
||||
PCDIMENSION dim;
|
||||
|
||||
char *xmlfile = "data/simple-schema.xml";
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
char *xmlfile = "data/simple-schema.xml";
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
|
||||
s1 = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
s1 = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
|
||||
s2 = pc_schema_clone(s1);
|
||||
s2 = pc_schema_clone(s1);
|
||||
|
||||
// same schemas
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_TRUE);
|
||||
// same schemas
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_TRUE);
|
||||
|
||||
// different number of dimensions
|
||||
s2->ndims = 1;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_FALSE);
|
||||
s2->ndims = s1->ndims;
|
||||
// different number of dimensions
|
||||
s2->ndims = 1;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_FALSE);
|
||||
s2->ndims = s1->ndims;
|
||||
|
||||
// different dimension positions
|
||||
tmp = s2->dims[0];
|
||||
s2->dims[0] = s2->dims[1];
|
||||
s2->dims[1] = tmp;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_FALSE);
|
||||
s2->dims[1] = s2->dims[0];
|
||||
s2->dims[0] = tmp;
|
||||
// different dimension positions
|
||||
tmp = s2->dims[0];
|
||||
s2->dims[0] = s2->dims[1];
|
||||
s2->dims[1] = tmp;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_FALSE);
|
||||
s2->dims[1] = s2->dims[0];
|
||||
s2->dims[0] = tmp;
|
||||
|
||||
// different dimension name
|
||||
tmp = s2->dims[0];
|
||||
dim.name = pcstrdup("foo");
|
||||
dim.interpretation = tmp->interpretation;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
pcfree(dim.name);
|
||||
// different dimension name
|
||||
tmp = s2->dims[0];
|
||||
dim.name = pcstrdup("foo");
|
||||
dim.interpretation = tmp->interpretation;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
pcfree(dim.name);
|
||||
|
||||
// different interpretations
|
||||
tmp = s2->dims[0];
|
||||
dim.name = tmp->name;
|
||||
dim.interpretation = PC_FLOAT;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
// different interpretations
|
||||
tmp = s2->dims[0];
|
||||
dim.name = tmp->name;
|
||||
dim.interpretation = PC_FLOAT;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_dimensions(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
|
||||
pc_schema_free(s1);
|
||||
pc_schema_free(s2);
|
||||
pc_schema_free(s1);
|
||||
pc_schema_free(s2);
|
||||
}
|
||||
|
||||
static void
|
||||
test_schema_same_interpretations(void)
|
||||
static void test_schema_same_interpretations(void)
|
||||
{
|
||||
PCSCHEMA *s1, *s2;
|
||||
PCDIMENSION *tmp;
|
||||
PCDIMENSION dim;
|
||||
PCSCHEMA *s1, *s2;
|
||||
PCDIMENSION *tmp;
|
||||
PCDIMENSION dim;
|
||||
|
||||
char *xmlfile = "data/simple-schema.xml";
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
char *xmlfile = "data/simple-schema.xml";
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
|
||||
s1 = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
s1 = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
|
||||
s2 = pc_schema_clone(s1);
|
||||
s2 = pc_schema_clone(s1);
|
||||
|
||||
// same schemas
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_TRUE);
|
||||
// same schemas
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_TRUE);
|
||||
|
||||
// different srid
|
||||
s2->srid = 100;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_FALSE);
|
||||
s2->srid = s1->srid;
|
||||
// different srid
|
||||
s2->srid = 100;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_FALSE);
|
||||
s2->srid = s1->srid;
|
||||
|
||||
// different dimension positions
|
||||
tmp = s2->dims[0];
|
||||
s2->dims[0] = s2->dims[1];
|
||||
s2->dims[1] = tmp;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_TRUE);
|
||||
s2->dims[1] = s2->dims[0];
|
||||
s2->dims[0] = tmp;
|
||||
// different dimension positions
|
||||
tmp = s2->dims[0];
|
||||
s2->dims[0] = s2->dims[1];
|
||||
s2->dims[1] = tmp;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_TRUE);
|
||||
s2->dims[1] = s2->dims[0];
|
||||
s2->dims[0] = tmp;
|
||||
|
||||
// first dimension in s1 doesn't exist in s2, and first dimension
|
||||
// in s2 does not exist in s1
|
||||
tmp = s2->dims[0];
|
||||
dim.name = pcstrdup("foo");
|
||||
dim.interpretation = tmp->interpretation;
|
||||
dim.scale = tmp->scale;
|
||||
dim.offset = tmp->offset;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_TRUE);
|
||||
s2->dims[0] = tmp;
|
||||
pcfree(dim.name);
|
||||
// first dimension in s1 doesn't exist in s2, and first dimension
|
||||
// in s2 does not exist in s1
|
||||
tmp = s2->dims[0];
|
||||
dim.name = pcstrdup("foo");
|
||||
dim.interpretation = tmp->interpretation;
|
||||
dim.scale = tmp->scale;
|
||||
dim.offset = tmp->offset;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_TRUE);
|
||||
s2->dims[0] = tmp;
|
||||
pcfree(dim.name);
|
||||
|
||||
// different interpretations for a dimension
|
||||
tmp = s2->dims[0];
|
||||
dim.name = tmp->name;
|
||||
dim.interpretation = PC_FLOAT;
|
||||
dim.scale = tmp->scale;
|
||||
dim.offset = tmp->offset;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
// different interpretations for a dimension
|
||||
tmp = s2->dims[0];
|
||||
dim.name = tmp->name;
|
||||
dim.interpretation = PC_FLOAT;
|
||||
dim.scale = tmp->scale;
|
||||
dim.offset = tmp->offset;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
|
||||
// different scales for a dimension
|
||||
tmp = s2->dims[0];
|
||||
dim.name = tmp->name;
|
||||
dim.interpretation = tmp->interpretation;
|
||||
dim.scale = 0.08;
|
||||
dim.offset = tmp->offset;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
// different scales for a dimension
|
||||
tmp = s2->dims[0];
|
||||
dim.name = tmp->name;
|
||||
dim.interpretation = tmp->interpretation;
|
||||
dim.scale = 0.08;
|
||||
dim.offset = tmp->offset;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
|
||||
// different offsets for a dimension
|
||||
tmp = s2->dims[0];
|
||||
dim.name = tmp->name;
|
||||
dim.interpretation = tmp->interpretation;
|
||||
dim.scale = tmp->scale;
|
||||
dim.offset = 80;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
// different offsets for a dimension
|
||||
tmp = s2->dims[0];
|
||||
dim.name = tmp->name;
|
||||
dim.interpretation = tmp->interpretation;
|
||||
dim.scale = tmp->scale;
|
||||
dim.offset = 80;
|
||||
s2->dims[0] = &dim;
|
||||
CU_ASSERT_EQUAL(pc_schema_same_interpretations(s1, s2), PC_FALSE);
|
||||
s2->dims[0] = tmp;
|
||||
|
||||
pc_schema_free(s1);
|
||||
pc_schema_free(s2);
|
||||
pc_schema_free(s1);
|
||||
pc_schema_free(s2);
|
||||
}
|
||||
|
||||
/* REGISTER ***********************************************************/
|
||||
|
||||
CU_TestInfo schema_tests[] = {
|
||||
PC_TEST(test_schema_from_xml),
|
||||
PC_TEST(test_schema_from_xml_with_empty_description),
|
||||
PC_TEST(test_schema_from_xml_with_empty_name),
|
||||
PC_TEST(test_schema_from_xml_with_no_name),
|
||||
PC_TEST(test_schema_size),
|
||||
PC_TEST(test_dimension_get),
|
||||
PC_TEST(test_dimension_byteoffsets),
|
||||
PC_TEST(test_schema_compression),
|
||||
PC_TEST(test_schema_invalid_xy),
|
||||
PC_TEST(test_schema_missing_dimension),
|
||||
PC_TEST(test_schema_empty),
|
||||
PC_TEST(test_schema_clone),
|
||||
PC_TEST(test_schema_clone_empty_description),
|
||||
PC_TEST(test_schema_clone_no_name),
|
||||
PC_TEST(test_schema_clone_empty_name),
|
||||
PC_TEST(test_schema_same_dimensions),
|
||||
PC_TEST(test_schema_same_interpretations),
|
||||
CU_TEST_INFO_NULL
|
||||
};
|
||||
PC_TEST(test_schema_from_xml),
|
||||
PC_TEST(test_schema_from_xml_with_empty_description),
|
||||
PC_TEST(test_schema_from_xml_with_empty_name),
|
||||
PC_TEST(test_schema_from_xml_with_no_name),
|
||||
PC_TEST(test_schema_size),
|
||||
PC_TEST(test_dimension_get),
|
||||
PC_TEST(test_dimension_byteoffsets),
|
||||
PC_TEST(test_schema_compression),
|
||||
PC_TEST(test_schema_invalid_xy),
|
||||
PC_TEST(test_schema_missing_dimension),
|
||||
PC_TEST(test_schema_empty),
|
||||
PC_TEST(test_schema_clone),
|
||||
PC_TEST(test_schema_clone_empty_description),
|
||||
PC_TEST(test_schema_clone_no_name),
|
||||
PC_TEST(test_schema_clone_empty_name),
|
||||
PC_TEST(test_schema_same_dimensions),
|
||||
PC_TEST(test_schema_same_interpretations),
|
||||
CU_TEST_INFO_NULL};
|
||||
|
||||
CU_SuiteInfo schema_suite = {
|
||||
.pName = "schema",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = schema_tests
|
||||
};
|
||||
CU_SuiteInfo schema_suite = {.pName = "schema",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = schema_tests};
|
||||
|
||||
@ -1,9 +1,9 @@
|
||||
/***********************************************************************
|
||||
* cu_pc_sort.c
|
||||
*
|
||||
* Testing for the schema API functions
|
||||
*
|
||||
***********************************************************************/
|
||||
* cu_pc_sort.c
|
||||
*
|
||||
* Testing for the schema API functions
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "CUnit/Basic.h"
|
||||
#include "cu_tester.h"
|
||||
@ -21,375 +21,372 @@ static const double precision = 0.000001;
|
||||
// int16_t intensity
|
||||
|
||||
/* Setup/teardown for this suite */
|
||||
static int
|
||||
init_suite(void)
|
||||
static int init_suite(void)
|
||||
{
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !schema ) return 1;
|
||||
return 0;
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!schema)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
clean_suite(void)
|
||||
static int clean_suite(void)
|
||||
{
|
||||
pc_schema_free(schema);
|
||||
return 0;
|
||||
pc_schema_free(schema);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* TESTS **************************************************************/
|
||||
|
||||
static void
|
||||
test_sort_simple()
|
||||
static void test_sort_simple()
|
||||
{
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000003000000050006 pt1 (XYZi)
|
||||
// 0000000200000001000000040008 pt2 (XYZi)
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000003000000050006 pt1 (XYZi)
|
||||
// 0000000200000001000000040008 pt2 (XYZi)
|
||||
|
||||
// init data
|
||||
PCPOINTLIST *lisort;
|
||||
PCPATCH *pasort;
|
||||
double d1;
|
||||
double d2;
|
||||
char *hexbuf = "0000000000000000000000000200000008000000030000000500060000000200000001000000040008";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
// init data
|
||||
PCPOINTLIST *lisort;
|
||||
PCPATCH *pasort;
|
||||
double d1;
|
||||
double d2;
|
||||
char *hexbuf = "0000000000000000000000000200000008000000030000000500060000000"
|
||||
"200000001000000040008";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize/2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *X[] = {"X"};
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize / 2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *X[] = {"X"};
|
||||
|
||||
// check that initial data are not sorted
|
||||
pc_point_get_double_by_name(pc_pointlist_get_point(li, 0), "X", &d1);
|
||||
pc_point_get_double_by_name(pc_pointlist_get_point(li, 1), "X", &d2);
|
||||
// check that initial data are not sorted
|
||||
pc_point_get_double_by_name(pc_pointlist_get_point(li, 0), "X", &d1);
|
||||
pc_point_get_double_by_name(pc_pointlist_get_point(li, 1), "X", &d2);
|
||||
|
||||
CU_ASSERT_DOUBLE_EQUAL(d1, 0.08, precision);
|
||||
CU_ASSERT_DOUBLE_EQUAL(d2, 0.02, precision);
|
||||
CU_ASSERT_DOUBLE_EQUAL(d1, 0.08, precision);
|
||||
CU_ASSERT_DOUBLE_EQUAL(d2, 0.02, precision);
|
||||
|
||||
// sort on X attribute and check if data are well sorted
|
||||
pasort = pc_patch_sort(pa, X, 1);
|
||||
lisort = pc_pointlist_from_patch(pasort);
|
||||
// sort on X attribute and check if data are well sorted
|
||||
pasort = pc_patch_sort(pa, X, 1);
|
||||
lisort = pc_pointlist_from_patch(pasort);
|
||||
|
||||
pc_point_get_double_by_name(pc_pointlist_get_point(lisort, 0), "X", &d1);
|
||||
pc_point_get_double_by_name(pc_pointlist_get_point(lisort, 1), "X", &d2);
|
||||
pc_point_get_double_by_name(pc_pointlist_get_point(lisort, 0), "X", &d1);
|
||||
pc_point_get_double_by_name(pc_pointlist_get_point(lisort, 1), "X", &d2);
|
||||
|
||||
CU_ASSERT_DOUBLE_EQUAL(d1, 0.02, precision);
|
||||
CU_ASSERT_DOUBLE_EQUAL(d2, 0.08, precision);
|
||||
CU_ASSERT_DOUBLE_EQUAL(d1, 0.02, precision);
|
||||
CU_ASSERT_DOUBLE_EQUAL(d2, 0.08, precision);
|
||||
|
||||
// free
|
||||
pc_pointlist_free(li);
|
||||
pc_pointlist_free(lisort);
|
||||
pc_patch_free(pa);
|
||||
pc_patch_free(pasort);
|
||||
pcfree(wkb);
|
||||
// free
|
||||
pc_pointlist_free(li);
|
||||
pc_pointlist_free(lisort);
|
||||
pc_patch_free(pa);
|
||||
pc_patch_free(pasort);
|
||||
pcfree(wkb);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_consistency()
|
||||
static void test_sort_consistency()
|
||||
{
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000003000000050006 pt1 (XYZi)
|
||||
// 0000000200000001000000040008 pt2 (XYZi)
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000003000000050006 pt1 (XYZi)
|
||||
// 0000000200000001000000040008 pt2 (XYZi)
|
||||
|
||||
// init data
|
||||
PCPATCH *pasort;
|
||||
char *pastr, *pasortstr;
|
||||
uint8_t *wkbsort;
|
||||
char *hexbuf = "0000000000000000000000000200000008000000030000000500060000000200000001000000040008";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize/2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *X[] = {"X"};
|
||||
// init data
|
||||
PCPATCH *pasort;
|
||||
char *pastr, *pasortstr;
|
||||
uint8_t *wkbsort;
|
||||
char *hexbuf = "0000000000000000000000000200000008000000030000000500060000000"
|
||||
"200000001000000040008";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize / 2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *X[] = {"X"};
|
||||
|
||||
// sort on X attribute
|
||||
pasort = pc_patch_sort(pa, X, 1);
|
||||
// sort on X attribute
|
||||
pasort = pc_patch_sort(pa, X, 1);
|
||||
|
||||
//chek consistency
|
||||
wkbsort = pc_patch_to_wkb(pasort, &hexsize);
|
||||
CU_ASSERT_EQUAL(pc_wkb_get_pcid(wkb), pc_wkb_get_pcid(wkbsort));
|
||||
CU_ASSERT_EQUAL(wkb_get_npoints(wkb), wkb_get_npoints(wkbsort));
|
||||
CU_ASSERT_EQUAL(wkb_get_compression(wkb), wkb_get_compression(wkbsort));
|
||||
// chek consistency
|
||||
wkbsort = pc_patch_to_wkb(pasort, &hexsize);
|
||||
CU_ASSERT_EQUAL(pc_wkb_get_pcid(wkb), pc_wkb_get_pcid(wkbsort));
|
||||
CU_ASSERT_EQUAL(wkb_get_npoints(wkb), wkb_get_npoints(wkbsort));
|
||||
CU_ASSERT_EQUAL(wkb_get_compression(wkb), wkb_get_compression(wkbsort));
|
||||
|
||||
pastr = pc_patch_to_string(pa);
|
||||
CU_ASSERT_STRING_EQUAL(pastr, "{\"pcid\":0,\"pts\":[[0.08,0.03,0.05,6],[0.02,0.01,0.04,8]]}");
|
||||
pastr = pc_patch_to_string(pa);
|
||||
CU_ASSERT_STRING_EQUAL(
|
||||
pastr, "{\"pcid\":0,\"pts\":[[0.08,0.03,0.05,6],[0.02,0.01,0.04,8]]}");
|
||||
|
||||
pasortstr = pc_patch_to_string(pasort);
|
||||
CU_ASSERT_STRING_EQUAL(pasortstr, "{\"pcid\":0,\"pts\":[[0.02,0.01,0.04,8],[0.08,0.03,0.05,6]]}");
|
||||
pasortstr = pc_patch_to_string(pasort);
|
||||
CU_ASSERT_STRING_EQUAL(
|
||||
pasortstr,
|
||||
"{\"pcid\":0,\"pts\":[[0.02,0.01,0.04,8],[0.08,0.03,0.05,6]]}");
|
||||
|
||||
// free
|
||||
pcfree(wkb);
|
||||
pcfree(wkbsort);
|
||||
pcfree(pastr);
|
||||
pcfree(pasortstr);
|
||||
pc_patch_free(pasort);
|
||||
pc_patch_free(pa);
|
||||
pc_pointlist_free(li);
|
||||
// free
|
||||
pcfree(wkb);
|
||||
pcfree(wkbsort);
|
||||
pcfree(pastr);
|
||||
pcfree(pasortstr);
|
||||
pc_patch_free(pasort);
|
||||
pc_patch_free(pa);
|
||||
pc_pointlist_free(li);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_one_point()
|
||||
static void test_sort_one_point()
|
||||
{
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000001 npoints
|
||||
// 0000000200000003000000050006 pt1 (XYZi)
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000001 npoints
|
||||
// 0000000200000003000000050006 pt1 (XYZi)
|
||||
|
||||
// init data
|
||||
PCPATCH *pasort;
|
||||
char *pastr, *pasortstr;
|
||||
uint8_t *wkbsort;
|
||||
char *hexbuf = "000000000000000000000000010000000200000003000000050006";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize/2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *X[] = {"X"};
|
||||
// init data
|
||||
PCPATCH *pasort;
|
||||
char *pastr, *pasortstr;
|
||||
uint8_t *wkbsort;
|
||||
char *hexbuf = "000000000000000000000000010000000200000003000000050006";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize / 2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *X[] = {"X"};
|
||||
|
||||
// sort on X attribute
|
||||
pasort = pc_patch_sort(pa, X, 1);
|
||||
// sort on X attribute
|
||||
pasort = pc_patch_sort(pa, X, 1);
|
||||
|
||||
// check consistency
|
||||
wkbsort = pc_patch_to_wkb(pasort, &hexsize);
|
||||
CU_ASSERT_EQUAL(pc_wkb_get_pcid(wkb), pc_wkb_get_pcid(wkbsort));
|
||||
CU_ASSERT_EQUAL(wkb_get_npoints(wkb), wkb_get_npoints(wkbsort));
|
||||
CU_ASSERT_EQUAL(wkb_get_compression(wkb), wkb_get_compression(wkbsort));
|
||||
// check consistency
|
||||
wkbsort = pc_patch_to_wkb(pasort, &hexsize);
|
||||
CU_ASSERT_EQUAL(pc_wkb_get_pcid(wkb), pc_wkb_get_pcid(wkbsort));
|
||||
CU_ASSERT_EQUAL(wkb_get_npoints(wkb), wkb_get_npoints(wkbsort));
|
||||
CU_ASSERT_EQUAL(wkb_get_compression(wkb), wkb_get_compression(wkbsort));
|
||||
|
||||
pastr = pc_patch_to_string(pa);
|
||||
pasortstr = pc_patch_to_string(pasort);
|
||||
CU_ASSERT_STRING_EQUAL(pastr, pasortstr);
|
||||
pastr = pc_patch_to_string(pa);
|
||||
pasortstr = pc_patch_to_string(pasort);
|
||||
CU_ASSERT_STRING_EQUAL(pastr, pasortstr);
|
||||
|
||||
// free
|
||||
pcfree(wkb);
|
||||
pcfree(wkbsort);
|
||||
pcfree(pastr);
|
||||
pcfree(pasortstr);
|
||||
pc_patch_free(pa);
|
||||
pc_patch_free(pasort);
|
||||
pc_pointlist_free(li);
|
||||
// free
|
||||
pcfree(wkb);
|
||||
pcfree(wkbsort);
|
||||
pcfree(pastr);
|
||||
pcfree(pasortstr);
|
||||
pc_patch_free(pa);
|
||||
pc_patch_free(pasort);
|
||||
pc_pointlist_free(li);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_stable()
|
||||
static void test_sort_stable()
|
||||
{
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000003000000050006 pt1 (XYZi)
|
||||
// 0000000200000003000000040008 pt2 (XYZi)
|
||||
// 0000000200000003000000040009 pt3 (XYZi)
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000003000000050006 pt1 (XYZi)
|
||||
// 0000000200000003000000040008 pt2 (XYZi)
|
||||
// 0000000200000003000000040009 pt3 (XYZi)
|
||||
|
||||
// init data
|
||||
PCPATCH *pasort;
|
||||
char *hexbuf = "00000000000000000000000003000000080000000300000005000600000002000000030000000400080000000200000003000000040009";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize/2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *dims[] = {"Y"};
|
||||
// init data
|
||||
PCPATCH *pasort;
|
||||
char *hexbuf = "0000000000000000000000000300000008000000030000000500060000000"
|
||||
"2000000030000000400080000000200000003000000040009";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize / 2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *dims[] = {"Y"};
|
||||
|
||||
// sort on Y attribute
|
||||
pasort = pc_patch_sort(pa, dims, 1);
|
||||
// sort on Y attribute
|
||||
pasort = pc_patch_sort(pa, dims, 1);
|
||||
|
||||
// check that sort is stable
|
||||
char *pastr = pc_patch_to_string(pa);
|
||||
char *pasortstr = pc_patch_to_string(pasort);
|
||||
CU_ASSERT_STRING_EQUAL(pastr, pasortstr);
|
||||
// check that sort is stable
|
||||
char *pastr = pc_patch_to_string(pa);
|
||||
char *pasortstr = pc_patch_to_string(pasort);
|
||||
CU_ASSERT_STRING_EQUAL(pastr, pasortstr);
|
||||
|
||||
// free
|
||||
free(pastr);
|
||||
free(pasortstr);
|
||||
pcfree(wkb);
|
||||
pc_patch_free(pa);
|
||||
pc_patch_free(pasort);
|
||||
pc_pointlist_free(li);
|
||||
// free
|
||||
free(pastr);
|
||||
free(pasortstr);
|
||||
pcfree(wkb);
|
||||
pc_patch_free(pa);
|
||||
pc_patch_free(pasort);
|
||||
pc_pointlist_free(li);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_patch_is_sorted_no_compression()
|
||||
static void test_sort_patch_is_sorted_no_compression()
|
||||
{
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000003000000050006 pt1 (XYZi)
|
||||
// 0000000200000003000000040008 pt2 (XYZi)
|
||||
// 0000000200000003000000040009 pt3 (XYZi)
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000003000000050006 pt1 (XYZi)
|
||||
// 0000000200000003000000040008 pt2 (XYZi)
|
||||
// 0000000200000003000000040009 pt3 (XYZi)
|
||||
|
||||
// init data
|
||||
PCPATCH *pasort;
|
||||
char *hexbuf = "00000000000000000000000003000000080000000300000005000600000002000000030000000400080000000200000003000000040009";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize/2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *X[] = {"X"};
|
||||
// init data
|
||||
PCPATCH *pasort;
|
||||
char *hexbuf = "0000000000000000000000000300000008000000030000000500060000000"
|
||||
"2000000030000000400080000000200000003000000040009";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize / 2);
|
||||
PCPOINTLIST *li = pc_pointlist_from_patch(pa);
|
||||
const char *X[] = {"X"};
|
||||
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, X, 1, PC_FALSE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, X, 1, PC_TRUE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, X, 1, PC_FALSE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, X, 1, PC_TRUE), PC_FALSE);
|
||||
|
||||
pasort = pc_patch_sort(pa, X, 1);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort, X, 1, PC_FALSE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort, X, 1, PC_TRUE), PC_TRUE);
|
||||
pasort = pc_patch_sort(pa, X, 1);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort, X, 1, PC_FALSE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort, X, 1, PC_TRUE), PC_TRUE);
|
||||
|
||||
// free
|
||||
pcfree(wkb);
|
||||
pc_patch_free(pa);
|
||||
pc_patch_free(pasort);
|
||||
pc_pointlist_free(li);
|
||||
// free
|
||||
pcfree(wkb);
|
||||
pc_patch_free(pa);
|
||||
pc_patch_free(pasort);
|
||||
pc_pointlist_free(li);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_patch_is_sorted_compression_dimensional(enum DIMCOMPRESSIONS dimcomp)
|
||||
{
|
||||
// init data
|
||||
PCPATCH_DIMENSIONAL *padim1, *padim2, *padimsort;
|
||||
PCPOINT *pt;
|
||||
PCPOINTLIST *pl;
|
||||
int i;
|
||||
int ndims = 1;
|
||||
int npts = PCDIMSTATS_MIN_SAMPLE+1; // force to keep custom compression
|
||||
const char *X[] = {"X"};
|
||||
// init data
|
||||
PCPATCH_DIMENSIONAL *padim1, *padim2, *padimsort;
|
||||
PCPOINT *pt;
|
||||
PCPOINTLIST *pl;
|
||||
int i;
|
||||
int ndims = 1;
|
||||
int npts = PCDIMSTATS_MIN_SAMPLE + 1; // force to keep custom compression
|
||||
const char *X[] = {"X"};
|
||||
|
||||
// build a dimensional patch
|
||||
pl = pc_pointlist_make(npts);
|
||||
// build a dimensional patch
|
||||
pl = pc_pointlist_make(npts);
|
||||
|
||||
for ( i = npts; i >= 0; i-- )
|
||||
{
|
||||
pt = pc_point_make(schema);
|
||||
pc_point_set_double_by_name(pt, "x", i);
|
||||
pc_point_set_double_by_name(pt, "y", i);
|
||||
pc_point_set_double_by_name(pt, "Z", i);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
for (i = npts; i >= 0; i--)
|
||||
{
|
||||
pt = pc_point_make(schema);
|
||||
pc_point_set_double_by_name(pt, "x", i);
|
||||
pc_point_set_double_by_name(pt, "y", i);
|
||||
pc_point_set_double_by_name(pt, "Z", i);
|
||||
pc_point_set_double_by_name(pt, "intensity", 10);
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
}
|
||||
|
||||
padim1 = pc_patch_dimensional_from_pointlist(pl);
|
||||
padim1 = pc_patch_dimensional_from_pointlist(pl);
|
||||
|
||||
// set dimensional compression for each dimension
|
||||
PCDIMSTATS *stats = pc_dimstats_make(schema);
|
||||
pc_dimstats_update(stats, padim1);
|
||||
for ( i = 0; i<padim1->schema->ndims; i++ )
|
||||
stats->stats[i].recommended_compression = dimcomp;
|
||||
// set dimensional compression for each dimension
|
||||
PCDIMSTATS *stats = pc_dimstats_make(schema);
|
||||
pc_dimstats_update(stats, padim1);
|
||||
for (i = 0; i < padim1->schema->ndims; i++)
|
||||
stats->stats[i].recommended_compression = dimcomp;
|
||||
|
||||
// compress patch
|
||||
padim2 = pc_patch_dimensional_compress(padim1, stats);
|
||||
// compress patch
|
||||
padim2 = pc_patch_dimensional_compress(padim1, stats);
|
||||
|
||||
// test that patch is not sorted
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted((PCPATCH*) padim2, X, ndims, PC_FALSE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted((PCPATCH*) padim2, X, ndims, PC_TRUE), PC_FALSE);
|
||||
// test that patch is not sorted
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted((PCPATCH *)padim2, X, ndims, PC_FALSE),
|
||||
PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted((PCPATCH *)padim2, X, ndims, PC_TRUE),
|
||||
PC_FALSE);
|
||||
|
||||
// sort
|
||||
padimsort = (PCPATCH_DIMENSIONAL*) pc_patch_sort((PCPATCH*) padim2, X, 1);
|
||||
// sort
|
||||
padimsort = (PCPATCH_DIMENSIONAL *)pc_patch_sort((PCPATCH *)padim2, X, 1);
|
||||
|
||||
// test that resulting data is sorted
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted((PCPATCH*) padimsort, X, ndims, PC_TRUE), PC_TRUE);
|
||||
// test that resulting data is sorted
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted((PCPATCH *)padimsort, X, ndims, PC_TRUE),
|
||||
PC_TRUE);
|
||||
|
||||
// free
|
||||
pc_dimstats_free(stats);
|
||||
pc_patch_free((PCPATCH *)padim1);
|
||||
pc_patch_free((PCPATCH *)padim2);
|
||||
pc_patch_free((PCPATCH *)padimsort);
|
||||
pc_pointlist_free(pl);
|
||||
// free
|
||||
pc_dimstats_free(stats);
|
||||
pc_patch_free((PCPATCH *)padim1);
|
||||
pc_patch_free((PCPATCH *)padim2);
|
||||
pc_patch_free((PCPATCH *)padimsort);
|
||||
pc_pointlist_free(pl);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_patch_is_sorted_compression_dimensional_none()
|
||||
static void test_sort_patch_is_sorted_compression_dimensional_none()
|
||||
{
|
||||
test_sort_patch_is_sorted_compression_dimensional(PC_DIM_NONE);
|
||||
test_sort_patch_is_sorted_compression_dimensional(PC_DIM_NONE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_patch_is_sorted_compression_dimensional_zlib()
|
||||
static void test_sort_patch_is_sorted_compression_dimensional_zlib()
|
||||
{
|
||||
test_sort_patch_is_sorted_compression_dimensional(PC_DIM_ZLIB);
|
||||
test_sort_patch_is_sorted_compression_dimensional(PC_DIM_ZLIB);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_patch_is_sorted_compression_dimensional_rle()
|
||||
static void test_sort_patch_is_sorted_compression_dimensional_rle()
|
||||
{
|
||||
test_sort_patch_is_sorted_compression_dimensional(PC_DIM_RLE);
|
||||
test_sort_patch_is_sorted_compression_dimensional(PC_DIM_RLE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_patch_is_sorted_compression_dimensional_sigbits()
|
||||
static void test_sort_patch_is_sorted_compression_dimensional_sigbits()
|
||||
{
|
||||
test_sort_patch_is_sorted_compression_dimensional(PC_DIM_SIGBITS);
|
||||
test_sort_patch_is_sorted_compression_dimensional(PC_DIM_SIGBITS);
|
||||
}
|
||||
|
||||
static void
|
||||
test_sort_patch_ndims()
|
||||
static void test_sort_patch_ndims()
|
||||
{
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000001000000050006 pt1 (XYZi)
|
||||
// 0000000200000003000000040008 pt2 (XYZi)
|
||||
// 0000000200000002000000040008 pt2 (XYZi)
|
||||
// 00 endian (big)
|
||||
// 00000000 pcid
|
||||
// 00000000 compression
|
||||
// 00000002 npoints
|
||||
// 0000000800000001000000050006 pt1 (XYZi)
|
||||
// 0000000200000003000000040008 pt2 (XYZi)
|
||||
// 0000000200000002000000040008 pt2 (XYZi)
|
||||
|
||||
// init data
|
||||
PCPATCH *pasort1, *pasort2;
|
||||
char *hexbuf = "00000000000000000000000003000000080000000400000005000600000002000000030000000400080000000200000002000000040009";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize/2);
|
||||
const char *X[] = {"X"};
|
||||
const char *Y[] = {"Y"};
|
||||
const char *X_Y[] = {"X", "Y"};
|
||||
// init data
|
||||
PCPATCH *pasort1, *pasort2;
|
||||
char *hexbuf = "0000000000000000000000000300000008000000040000000500060000000"
|
||||
"2000000030000000400080000000200000002000000040009";
|
||||
size_t hexsize = strlen(hexbuf);
|
||||
uint8_t *wkb = pc_bytes_from_hexbytes(hexbuf, hexsize);
|
||||
PCPATCH *pa = pc_patch_from_wkb(schema, wkb, hexsize / 2);
|
||||
const char *X[] = {"X"};
|
||||
const char *Y[] = {"Y"};
|
||||
const char *X_Y[] = {"X", "Y"};
|
||||
|
||||
// test that initial data is not sorted
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, X, 1, PC_FALSE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, Y, 1, PC_FALSE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, X_Y, 2, PC_FALSE), PC_FALSE);
|
||||
// test that initial data is not sorted
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, X, 1, PC_FALSE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, Y, 1, PC_FALSE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pa, X_Y, 2, PC_FALSE), PC_FALSE);
|
||||
|
||||
// sort on X attribute and test
|
||||
pasort1 = pc_patch_sort(pa, X, 1);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort1, X, 1, PC_TRUE), PC_TRUE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort1, Y, 1, PC_TRUE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort1, X_Y, 2, PC_TRUE), PC_FALSE);
|
||||
// sort on X attribute and test
|
||||
pasort1 = pc_patch_sort(pa, X, 1);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort1, X, 1, PC_TRUE), PC_TRUE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort1, Y, 1, PC_TRUE), PC_FALSE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort1, X_Y, 2, PC_TRUE), PC_FALSE);
|
||||
|
||||
// sort on X and Y and tst
|
||||
pasort2 = pc_patch_sort(pa, X_Y, 2);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort2, X, 1, PC_TRUE), PC_TRUE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort2, Y, 1, PC_TRUE), PC_TRUE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort2, X_Y, 2, PC_TRUE), PC_TRUE);
|
||||
// sort on X and Y and tst
|
||||
pasort2 = pc_patch_sort(pa, X_Y, 2);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort2, X, 1, PC_TRUE), PC_TRUE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort2, Y, 1, PC_TRUE), PC_TRUE);
|
||||
CU_ASSERT_EQUAL(pc_patch_is_sorted(pasort2, X_Y, 2, PC_TRUE), PC_TRUE);
|
||||
|
||||
// free
|
||||
pcfree(wkb);
|
||||
pc_patch_free(pasort1);
|
||||
pc_patch_free(pasort2);
|
||||
pc_patch_free(pa);
|
||||
// free
|
||||
pcfree(wkb);
|
||||
pc_patch_free(pasort1);
|
||||
pc_patch_free(pasort2);
|
||||
pc_patch_free(pa);
|
||||
}
|
||||
|
||||
/* REGISTER ***********************************************************/
|
||||
|
||||
CU_TestInfo sort_tests[] = {
|
||||
PC_TEST(test_sort_simple),
|
||||
PC_TEST(test_sort_consistency),
|
||||
PC_TEST(test_sort_one_point),
|
||||
PC_TEST(test_sort_stable),
|
||||
PC_TEST(test_sort_patch_is_sorted_no_compression),
|
||||
PC_TEST(test_sort_patch_is_sorted_compression_dimensional_none),
|
||||
PC_TEST(test_sort_patch_is_sorted_compression_dimensional_zlib),
|
||||
PC_TEST(test_sort_patch_is_sorted_compression_dimensional_sigbits),
|
||||
PC_TEST(test_sort_patch_is_sorted_compression_dimensional_rle),
|
||||
PC_TEST(test_sort_patch_ndims),
|
||||
CU_TEST_INFO_NULL
|
||||
};
|
||||
PC_TEST(test_sort_simple),
|
||||
PC_TEST(test_sort_consistency),
|
||||
PC_TEST(test_sort_one_point),
|
||||
PC_TEST(test_sort_stable),
|
||||
PC_TEST(test_sort_patch_is_sorted_no_compression),
|
||||
PC_TEST(test_sort_patch_is_sorted_compression_dimensional_none),
|
||||
PC_TEST(test_sort_patch_is_sorted_compression_dimensional_zlib),
|
||||
PC_TEST(test_sort_patch_is_sorted_compression_dimensional_sigbits),
|
||||
PC_TEST(test_sort_patch_is_sorted_compression_dimensional_rle),
|
||||
PC_TEST(test_sort_patch_ndims),
|
||||
CU_TEST_INFO_NULL};
|
||||
|
||||
CU_SuiteInfo sort_suite = {
|
||||
.pName = "sort",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = sort_tests
|
||||
};
|
||||
CU_SuiteInfo sort_suite = {.pName = "sort",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = sort_tests};
|
||||
|
||||
@ -1,109 +1,104 @@
|
||||
/***********************************************************************
|
||||
* cu_pc_util.c
|
||||
*
|
||||
* Testing for the util functions
|
||||
*
|
||||
* Portions Copyright (c) 2017, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
* cu_pc_util.c
|
||||
*
|
||||
* Testing for the util functions
|
||||
*
|
||||
* Portions Copyright (c) 2017, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "CUnit/Basic.h"
|
||||
#include "cu_tester.h"
|
||||
|
||||
|
||||
/* GLOBALS ************************************************************/
|
||||
|
||||
static PCSCHEMA *schema = NULL;
|
||||
static const char *xmlfile = "data/pdal-schema.xml";
|
||||
|
||||
/* Setup/teardown for this suite */
|
||||
static int
|
||||
init_suite(void)
|
||||
static int init_suite(void)
|
||||
{
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if ( !schema ) return 1;
|
||||
char *xmlstr = file_to_str(xmlfile);
|
||||
schema = pc_schema_from_xml(xmlstr);
|
||||
pcfree(xmlstr);
|
||||
if (!schema)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
clean_suite(void)
|
||||
static int clean_suite(void)
|
||||
{
|
||||
pc_schema_free(schema);
|
||||
return 0;
|
||||
pc_schema_free(schema);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* TESTS **************************************************************/
|
||||
|
||||
static void
|
||||
test_bounding_diagonal_wkb_from_bounds()
|
||||
static void test_bounding_diagonal_wkb_from_bounds()
|
||||
{
|
||||
PCBOUNDS bounds;
|
||||
size_t wkbsize;
|
||||
uint8_t *wkb;
|
||||
char *wkbhex;
|
||||
PCBOUNDS bounds;
|
||||
size_t wkbsize;
|
||||
uint8_t *wkb;
|
||||
char *wkbhex;
|
||||
|
||||
bounds.xmin = -10;
|
||||
bounds.xmax = 10;
|
||||
bounds.ymin = -10;
|
||||
bounds.ymax = 10;
|
||||
bounds.xmin = -10;
|
||||
bounds.xmax = 10;
|
||||
bounds.ymin = -10;
|
||||
bounds.ymax = 10;
|
||||
|
||||
wkb = pc_bounding_diagonal_wkb_from_bounds(&bounds, schema, &wkbsize);
|
||||
CU_ASSERT(wkb != NULL);
|
||||
CU_ASSERT(wkbsize == 41);
|
||||
wkb = pc_bounding_diagonal_wkb_from_bounds(&bounds, schema, &wkbsize);
|
||||
CU_ASSERT(wkb != NULL);
|
||||
CU_ASSERT(wkbsize == 41);
|
||||
|
||||
wkbhex = pc_hexbytes_from_bytes(wkb, wkbsize);
|
||||
CU_ASSERT(wkbhex != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(wkbhex, "01020000000200000000000000000024C000000000000024C000000000000024400000000000002440");
|
||||
wkbhex = pc_hexbytes_from_bytes(wkb, wkbsize);
|
||||
CU_ASSERT(wkbhex != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(wkbhex, "01020000000200000000000000000024C000000000000"
|
||||
"024C000000000000024400000000000002440");
|
||||
|
||||
pcfree(wkb);
|
||||
pcfree(wkbhex);
|
||||
pcfree(wkb);
|
||||
pcfree(wkbhex);
|
||||
}
|
||||
|
||||
static void
|
||||
test_bounding_diagonal_wkb_from_stats()
|
||||
static void test_bounding_diagonal_wkb_from_stats()
|
||||
{
|
||||
PCSTATS *stats;
|
||||
size_t wkbsize;
|
||||
uint8_t *wkb;
|
||||
char *wkbhex;
|
||||
PCSTATS *stats;
|
||||
size_t wkbsize;
|
||||
uint8_t *wkb;
|
||||
char *wkbhex;
|
||||
|
||||
stats = pc_stats_new(schema);
|
||||
stats = pc_stats_new(schema);
|
||||
|
||||
pc_point_set_x(&stats->min, -10);
|
||||
pc_point_set_x(&stats->max, 10);
|
||||
pc_point_set_y(&stats->min, -10);
|
||||
pc_point_set_y(&stats->max, 10);
|
||||
pc_point_set_z(&stats->min, -10);
|
||||
pc_point_set_z(&stats->max, 10);
|
||||
pc_point_set_x(&stats->min, -10);
|
||||
pc_point_set_x(&stats->max, 10);
|
||||
pc_point_set_y(&stats->min, -10);
|
||||
pc_point_set_y(&stats->max, 10);
|
||||
pc_point_set_z(&stats->min, -10);
|
||||
pc_point_set_z(&stats->max, 10);
|
||||
|
||||
wkb = pc_bounding_diagonal_wkb_from_stats(stats, &wkbsize);
|
||||
CU_ASSERT(wkb != NULL);
|
||||
CU_ASSERT(wkbsize == 73);
|
||||
wkb = pc_bounding_diagonal_wkb_from_stats(stats, &wkbsize);
|
||||
CU_ASSERT(wkb != NULL);
|
||||
CU_ASSERT(wkbsize == 73);
|
||||
|
||||
wkbhex = pc_hexbytes_from_bytes(wkb, wkbsize);
|
||||
CU_ASSERT(wkbhex != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(wkbhex, "01020000C00200000000000000000024C000000000000024C000000000000024C000000000000000000000000000002440000000000000244000000000000024400000000000000000");
|
||||
wkbhex = pc_hexbytes_from_bytes(wkb, wkbsize);
|
||||
CU_ASSERT(wkbhex != NULL);
|
||||
CU_ASSERT_STRING_EQUAL(wkbhex,
|
||||
"01020000C00200000000000000000024C000000000000024C0000"
|
||||
"00000000024C00000000000000000000000000000244000000000"
|
||||
"0000244000000000000024400000000000000000");
|
||||
|
||||
pc_stats_free(stats);
|
||||
pcfree(wkb);
|
||||
pcfree(wkbhex);
|
||||
pc_stats_free(stats);
|
||||
pcfree(wkb);
|
||||
pcfree(wkbhex);
|
||||
}
|
||||
|
||||
/* REGISTER ***********************************************************/
|
||||
|
||||
CU_TestInfo util_tests[] = {
|
||||
PC_TEST(test_bounding_diagonal_wkb_from_bounds),
|
||||
PC_TEST(test_bounding_diagonal_wkb_from_stats),
|
||||
CU_TEST_INFO_NULL
|
||||
};
|
||||
CU_TestInfo util_tests[] = {PC_TEST(test_bounding_diagonal_wkb_from_bounds),
|
||||
PC_TEST(test_bounding_diagonal_wkb_from_stats),
|
||||
CU_TEST_INFO_NULL};
|
||||
|
||||
CU_SuiteInfo util_suite = {
|
||||
.pName = "util",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = util_tests
|
||||
};
|
||||
CU_SuiteInfo util_suite = {.pName = "util",
|
||||
.pInitFunc = init_suite,
|
||||
.pCleanupFunc = clean_suite,
|
||||
.pTests = util_tests};
|
||||
|
||||
@ -1,19 +1,19 @@
|
||||
/***********************************************************************
|
||||
* cu_tester.c
|
||||
*
|
||||
* Testing harness for PgSQL PointClouds
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
* cu_tester.c
|
||||
*
|
||||
* Testing harness for PgSQL PointClouds
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "cu_tester.h"
|
||||
#include "CUnit/Basic.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "CUnit/Basic.h"
|
||||
#include "cu_tester.h"
|
||||
|
||||
/* Contains the most recent error message generated by rterror. */
|
||||
static char cu_error_msg[MAX_CUNIT_MSG_LENGTH+1];
|
||||
static char cu_error_msg[MAX_CUNIT_MSG_LENGTH + 1];
|
||||
|
||||
/* ADD YOUR SUITE HERE (1 of 2) */
|
||||
extern CU_SuiteInfo schema_suite;
|
||||
@ -25,22 +25,19 @@ extern CU_SuiteInfo sort_suite;
|
||||
extern CU_SuiteInfo util_suite;
|
||||
|
||||
/**
|
||||
* CUnit error handler
|
||||
* Log message in a global var instead of printing in stdout/stderr
|
||||
*
|
||||
* CAUTION: Not stop execution on pcerror case !!!
|
||||
*/
|
||||
* CUnit error handler
|
||||
* Log message in a global var instead of printing in stdout/stderr
|
||||
*
|
||||
* CAUTION: Not stop execution on pcerror case !!!
|
||||
*/
|
||||
static void cu_message_handler(const char *fmt, va_list ap)
|
||||
{
|
||||
vsnprintf(cu_error_msg, MAX_CUNIT_MSG_LENGTH-1, fmt, ap);
|
||||
cu_error_msg[MAX_CUNIT_MSG_LENGTH-1] = '\0';
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
void cu_error_msg_reset() {
|
||||
memset(cu_error_msg, '\0', MAX_CUNIT_MSG_LENGTH);
|
||||
vsnprintf(cu_error_msg, MAX_CUNIT_MSG_LENGTH - 1, fmt, ap);
|
||||
cu_error_msg[MAX_CUNIT_MSG_LENGTH - 1] = '\0';
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void cu_error_msg_reset() { memset(cu_error_msg, '\0', MAX_CUNIT_MSG_LENGTH); }
|
||||
|
||||
/*
|
||||
** The main() function for setting up and running the tests.
|
||||
@ -49,180 +46,197 @@ void cu_error_msg_reset() {
|
||||
*/
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
/* ADD YOUR SUITE HERE (2 of 2) */
|
||||
CU_SuiteInfo suites[] =
|
||||
{
|
||||
schema_suite,
|
||||
patch_suite,
|
||||
point_suite,
|
||||
bytes_suite,
|
||||
lazperf_suite,
|
||||
sort_suite,
|
||||
util_suite,
|
||||
CU_SUITE_INFO_NULL
|
||||
};
|
||||
/* ADD YOUR SUITE HERE (2 of 2) */
|
||||
CU_SuiteInfo suites[] = {schema_suite, patch_suite, point_suite,
|
||||
bytes_suite, lazperf_suite, sort_suite,
|
||||
util_suite, CU_SUITE_INFO_NULL};
|
||||
|
||||
int index;
|
||||
char *suite_name;
|
||||
CU_pSuite suite_to_run;
|
||||
char *test_name;
|
||||
CU_pTest test_to_run;
|
||||
CU_ErrorCode errCode = 0;
|
||||
CU_pTestRegistry registry;
|
||||
int num_run;
|
||||
int num_failed;
|
||||
int index;
|
||||
char *suite_name;
|
||||
CU_pSuite suite_to_run;
|
||||
char *test_name;
|
||||
CU_pTest test_to_run;
|
||||
CU_ErrorCode errCode = 0;
|
||||
CU_pTestRegistry registry;
|
||||
int num_run;
|
||||
int num_failed;
|
||||
|
||||
/* Set up to use the system memory management / logging */
|
||||
pc_install_default_handlers();
|
||||
/* Set up to use the system memory management / logging */
|
||||
pc_install_default_handlers();
|
||||
|
||||
pc_set_handlers(0, 0, 0, cu_message_handler, cu_message_handler, cu_message_handler);
|
||||
pc_set_handlers(0, 0, 0, cu_message_handler, cu_message_handler,
|
||||
cu_message_handler);
|
||||
|
||||
/* initialize the CUnit test registry */
|
||||
if (CUE_SUCCESS != CU_initialize_registry())
|
||||
{
|
||||
errCode = CU_get_error();
|
||||
printf(" Error attempting to initialize registry: %d. See CUError.h for error code list.\n", errCode);
|
||||
return errCode;
|
||||
}
|
||||
/* initialize the CUnit test registry */
|
||||
if (CUE_SUCCESS != CU_initialize_registry())
|
||||
{
|
||||
errCode = CU_get_error();
|
||||
printf(" Error attempting to initialize registry: %d. See CUError.h "
|
||||
"for error code list.\n",
|
||||
errCode);
|
||||
return errCode;
|
||||
}
|
||||
|
||||
/* Register all the test suites. */
|
||||
if (CUE_SUCCESS != CU_register_suites(suites))
|
||||
{
|
||||
errCode = CU_get_error();
|
||||
printf(" Error attempting to register test suites: %d. See CUError.h for error code list.\n", errCode);
|
||||
return errCode;
|
||||
}
|
||||
/* Register all the test suites. */
|
||||
if (CUE_SUCCESS != CU_register_suites(suites))
|
||||
{
|
||||
errCode = CU_get_error();
|
||||
printf(" Error attempting to register test suites: %d. See CUError.h "
|
||||
"for error code list.\n",
|
||||
errCode);
|
||||
return errCode;
|
||||
}
|
||||
|
||||
/* Run all tests using the CUnit Basic interface */
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
if (argc <= 1)
|
||||
{
|
||||
errCode = CU_basic_run_tests();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* NOTE: The cunit functions used here (CU_get_registry, CU_get_suite_by_name, and CU_get_test_by_name) are
|
||||
* listed with the following warning: "Internal CUnit system functions. Should not be routinely called by users."
|
||||
* However, there didn't seem to be any other way to get tests by name, so we're calling them. */
|
||||
registry = CU_get_registry();
|
||||
for (index = 1; index < argc; index++)
|
||||
{
|
||||
suite_name = argv[index];
|
||||
test_name = NULL;
|
||||
suite_to_run = CU_get_suite_by_name(suite_name, registry);
|
||||
if (NULL == suite_to_run)
|
||||
{
|
||||
/* See if it's a test name instead of a suite name. */
|
||||
suite_to_run = registry->pSuite;
|
||||
while (suite_to_run != NULL)
|
||||
{
|
||||
test_to_run = CU_get_test_by_name(suite_name, suite_to_run);
|
||||
if (test_to_run != NULL)
|
||||
{
|
||||
/* It was a test name. */
|
||||
test_name = suite_name;
|
||||
suite_name = suite_to_run->pName;
|
||||
break;
|
||||
}
|
||||
suite_to_run = suite_to_run->pNext;
|
||||
}
|
||||
}
|
||||
if (suite_to_run == NULL)
|
||||
{
|
||||
printf("\n'%s' does not appear to be either a suite name or a test name.\n\n", suite_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (test_name != NULL)
|
||||
{
|
||||
/* Run only this test. */
|
||||
printf("\nRunning test '%s' in suite '%s'.\n", test_name, suite_name);
|
||||
/* This should be CU_basic_run_test, but that method is broken, see:
|
||||
* https://sourceforge.net/tracker/?func=detail&aid=2851925&group_id=32992&atid=407088
|
||||
* This one doesn't output anything for success, so we have to do it manually. */
|
||||
errCode = CU_run_test(suite_to_run, test_to_run);
|
||||
if (errCode != CUE_SUCCESS)
|
||||
{
|
||||
printf(" Error attempting to run tests: %d. See CUError.h for error code list.\n", errCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_run = CU_get_number_of_asserts();
|
||||
num_failed = CU_get_number_of_failures();
|
||||
printf("\n %s - asserts - %3d passed, %3d failed, %3d total.\n\n",
|
||||
(0 == num_failed ? "PASSED" : "FAILED"), (num_run - num_failed), num_failed, num_run);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Run all the tests in the suite. */
|
||||
printf("\nRunning all tests in suite '%s'.\n", suite_name);
|
||||
/* This should be CU_basic_run_suite, but that method is broken, see:
|
||||
* https://sourceforge.net/tracker/?func=detail&aid=2851925&group_id=32992&atid=407088
|
||||
* This one doesn't output anything for success, so we have to do it manually. */
|
||||
errCode = CU_run_suite(suite_to_run);
|
||||
if (errCode != CUE_SUCCESS)
|
||||
{
|
||||
printf(" Error attempting to run tests: %d. See CUError.h for error code list.\n", errCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_run = CU_get_number_of_tests_run();
|
||||
num_failed = CU_get_number_of_tests_failed();
|
||||
printf("\n %s - tests - %3d passed, %3d failed, %3d total.\n",
|
||||
(0 == num_failed ? "PASSED" : "FAILED"), (num_run - num_failed), num_failed, num_run);
|
||||
num_run = CU_get_number_of_asserts();
|
||||
num_failed = CU_get_number_of_failures();
|
||||
printf(" - asserts - %3d passed, %3d failed, %3d total.\n\n",
|
||||
(num_run - num_failed), num_failed, num_run);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Presumably if the CU_basic_run_[test|suite] functions worked, we wouldn't have to do this. */
|
||||
CU_basic_show_failures(CU_get_failure_list());
|
||||
printf("\n\n"); /* basic_show_failures leaves off line breaks. */
|
||||
}
|
||||
num_failed = CU_get_number_of_failures();
|
||||
CU_cleanup_registry();
|
||||
return num_failed;
|
||||
/* Run all tests using the CUnit Basic interface */
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
if (argc <= 1)
|
||||
{
|
||||
errCode = CU_basic_run_tests();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* NOTE: The cunit functions used here (CU_get_registry,
|
||||
* CU_get_suite_by_name, and CU_get_test_by_name) are listed with the
|
||||
* following warning: "Internal CUnit system functions. Should not be
|
||||
* routinely called by users." However, there didn't seem to be any
|
||||
* other way to get tests by name, so we're calling them. */
|
||||
registry = CU_get_registry();
|
||||
for (index = 1; index < argc; index++)
|
||||
{
|
||||
suite_name = argv[index];
|
||||
test_name = NULL;
|
||||
suite_to_run = CU_get_suite_by_name(suite_name, registry);
|
||||
if (NULL == suite_to_run)
|
||||
{
|
||||
/* See if it's a test name instead of a suite name. */
|
||||
suite_to_run = registry->pSuite;
|
||||
while (suite_to_run != NULL)
|
||||
{
|
||||
test_to_run = CU_get_test_by_name(suite_name, suite_to_run);
|
||||
if (test_to_run != NULL)
|
||||
{
|
||||
/* It was a test name. */
|
||||
test_name = suite_name;
|
||||
suite_name = suite_to_run->pName;
|
||||
break;
|
||||
}
|
||||
suite_to_run = suite_to_run->pNext;
|
||||
}
|
||||
}
|
||||
if (suite_to_run == NULL)
|
||||
{
|
||||
printf("\n'%s' does not appear to be either a suite name or a "
|
||||
"test "
|
||||
"name.\n\n",
|
||||
suite_name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (test_name != NULL)
|
||||
{
|
||||
/* Run only this test. */
|
||||
printf("\nRunning test '%s' in suite '%s'.\n", test_name, suite_name);
|
||||
/* This should be CU_basic_run_test, but that method is
|
||||
* broken, see:
|
||||
* https://sourceforge.net/tracker/?func=detail&aid=2851925&group_id=32992&atid=407088
|
||||
* This one doesn't output anything for success, so we have
|
||||
* to do it manually. */
|
||||
errCode = CU_run_test(suite_to_run, test_to_run);
|
||||
if (errCode != CUE_SUCCESS)
|
||||
{
|
||||
printf(" Error attempting to run tests: %d. See "
|
||||
"CUError.h for "
|
||||
"error code list.\n",
|
||||
errCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_run = CU_get_number_of_asserts();
|
||||
num_failed = CU_get_number_of_failures();
|
||||
printf("\n %s - asserts - %3d passed, %3d failed, "
|
||||
"%3d total.\n\n",
|
||||
(0 == num_failed ? "PASSED" : "FAILED"),
|
||||
(num_run - num_failed), num_failed, num_run);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Run all the tests in the suite. */
|
||||
printf("\nRunning all tests in suite '%s'.\n", suite_name);
|
||||
/* This should be CU_basic_run_suite, but that method is
|
||||
* broken, see:
|
||||
* https://sourceforge.net/tracker/?func=detail&aid=2851925&group_id=32992&atid=407088
|
||||
* This one doesn't output anything for success, so we have
|
||||
* to do it manually. */
|
||||
errCode = CU_run_suite(suite_to_run);
|
||||
if (errCode != CUE_SUCCESS)
|
||||
{
|
||||
printf(" Error attempting to run tests: %d. See "
|
||||
"CUError.h for "
|
||||
"error code list.\n",
|
||||
errCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
num_run = CU_get_number_of_tests_run();
|
||||
num_failed = CU_get_number_of_tests_failed();
|
||||
printf("\n %s - tests - %3d passed, %3d failed, "
|
||||
"%3d total.\n",
|
||||
(0 == num_failed ? "PASSED" : "FAILED"),
|
||||
(num_run - num_failed), num_failed, num_run);
|
||||
num_run = CU_get_number_of_asserts();
|
||||
num_failed = CU_get_number_of_failures();
|
||||
printf(" - asserts - %3d passed, %3d failed, "
|
||||
"%3d total.\n\n",
|
||||
(num_run - num_failed), num_failed, num_run);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Presumably if the CU_basic_run_[test|suite] functions worked, we
|
||||
* wouldn't have to do this. */
|
||||
CU_basic_show_failures(CU_get_failure_list());
|
||||
printf("\n\n"); /* basic_show_failures leaves off line breaks. */
|
||||
}
|
||||
num_failed = CU_get_number_of_failures();
|
||||
CU_cleanup_registry();
|
||||
return num_failed;
|
||||
}
|
||||
|
||||
/* UTILITY ************************************************************/
|
||||
|
||||
char*
|
||||
file_to_str(const char *fname)
|
||||
char *file_to_str(const char *fname)
|
||||
{
|
||||
FILE *fr;
|
||||
char fullpath[512];
|
||||
size_t lnsz;
|
||||
size_t sz = 8192;
|
||||
char *str = pcalloc(sz);
|
||||
char *ptr = str;
|
||||
size_t MAXLINELEN = 8192;
|
||||
char buf[MAXLINELEN];
|
||||
FILE *fr;
|
||||
char fullpath[512];
|
||||
size_t lnsz;
|
||||
size_t sz = 8192;
|
||||
char *str = pcalloc(sz);
|
||||
char *ptr = str;
|
||||
size_t MAXLINELEN = 8192;
|
||||
char buf[MAXLINELEN];
|
||||
|
||||
snprintf(fullpath, 512, "%s/lib/cunit/%s", PROJECT_SOURCE_DIR, fname);
|
||||
fr = fopen (fullpath, "rt");
|
||||
snprintf(fullpath, 512, "%s/lib/cunit/%s", PROJECT_SOURCE_DIR, fname);
|
||||
fr = fopen(fullpath, "rt");
|
||||
|
||||
while (fr && fgets(buf, MAXLINELEN, fr) != NULL)
|
||||
{
|
||||
if (buf[0] == '\0')
|
||||
continue;
|
||||
lnsz = strlen(buf);
|
||||
if ( ptr - str + lnsz > sz )
|
||||
{
|
||||
size_t bsz = ptr - str;
|
||||
sz *= 2;
|
||||
str = pcrealloc(str, sz);
|
||||
ptr = str + bsz;
|
||||
}
|
||||
memcpy(ptr, buf, lnsz);
|
||||
ptr += lnsz;
|
||||
}
|
||||
while (fr && fgets(buf, MAXLINELEN, fr) != NULL)
|
||||
{
|
||||
if (buf[0] == '\0')
|
||||
continue;
|
||||
lnsz = strlen(buf);
|
||||
if (ptr - str + lnsz > sz)
|
||||
{
|
||||
size_t bsz = ptr - str;
|
||||
sz *= 2;
|
||||
str = pcrealloc(str, sz);
|
||||
ptr = str + bsz;
|
||||
}
|
||||
memcpy(ptr, buf, lnsz);
|
||||
ptr += lnsz;
|
||||
}
|
||||
|
||||
*ptr = '\0';
|
||||
fclose(fr);
|
||||
*ptr = '\0';
|
||||
fclose(fr);
|
||||
|
||||
return str;
|
||||
return str;
|
||||
}
|
||||
|
||||
@ -1,24 +1,27 @@
|
||||
/***********************************************************************
|
||||
* cu_tester.h
|
||||
*
|
||||
* Testing harness for PgSQL PointClouds header
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
* cu_tester.h
|
||||
*
|
||||
* Testing harness for PgSQL PointClouds header
|
||||
*
|
||||
* Portions Copyright (c) 2012, OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _CU_TESTER_H
|
||||
#define _CU_TESTER_H
|
||||
|
||||
#include "pc_api_internal.h"
|
||||
|
||||
#define PC_TEST(test_func) { #test_func, test_func }
|
||||
#define PC_TEST(test_func) \
|
||||
{ \
|
||||
#test_func, test_func \
|
||||
}
|
||||
#define MAX_CUNIT_MSG_LENGTH 512
|
||||
#define CU_ASSERT_SUCCESS(rv) CU_ASSERT( (rv) == PC_SUCCESS )
|
||||
#define CU_ASSERT_FAILURE(rv) CU_ASSERT( (rv) == PC_FAILURE )
|
||||
#define CU_ASSERT_SUCCESS(rv) CU_ASSERT((rv) == PC_SUCCESS)
|
||||
#define CU_ASSERT_FAILURE(rv) CU_ASSERT((rv) == PC_FAILURE)
|
||||
|
||||
/* Read a file (XML) into a cstring */
|
||||
char* file_to_str(const char *fname);
|
||||
char *file_to_str(const char *fname);
|
||||
|
||||
/* Resets cu_error_msg back to blank. */
|
||||
void cu_error_msg_reset(void);
|
||||
|
||||
539
lib/hashtable.c
539
lib/hashtable.c
@ -1,11 +1,11 @@
|
||||
/* Copyright (C) 2004 Christopher Clark <firstname.lastname@cl.cam.ac.uk> */
|
||||
|
||||
#include "hashtable.h"
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include <ctype.h>
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Use appropriate allocators for this deployment */
|
||||
/* Remove this for use in other contexts */
|
||||
@ -14,337 +14,320 @@
|
||||
#define free pcfree
|
||||
#define realloc pcrealloc
|
||||
|
||||
|
||||
/*
|
||||
* Credit for primes table: Aaron Krowne
|
||||
* http://br.endernet.org/~akrowne/
|
||||
* http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
|
||||
*/
|
||||
static const unsigned int primes[] =
|
||||
{
|
||||
53, 97, 193, 389,
|
||||
769, 1543, 3079, 6151,
|
||||
12289, 24593, 49157, 98317,
|
||||
196613, 393241, 786433, 1572869,
|
||||
3145739, 6291469, 12582917, 25165843,
|
||||
50331653, 100663319, 201326611, 402653189,
|
||||
805306457, 1610612741
|
||||
};
|
||||
const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]);
|
||||
* Credit for primes table: Aaron Krowne
|
||||
* http://br.endernet.org/~akrowne/
|
||||
* http://planetmath.org/encyclopedia/GoodHashTablePrimes.html
|
||||
*/
|
||||
static const unsigned int primes[] = {
|
||||
53, 97, 193, 389, 769, 1543, 3079,
|
||||
6151, 12289, 24593, 49157, 98317, 196613, 393241,
|
||||
786433, 1572869, 3145739, 6291469, 12582917, 25165843, 50331653,
|
||||
100663319, 201326611, 402653189, 805306457, 1610612741};
|
||||
const unsigned int prime_table_length = sizeof(primes) / sizeof(primes[0]);
|
||||
const float max_load_factor = 0.65;
|
||||
|
||||
|
||||
/*****************************************************************************/
|
||||
/* hash_str */
|
||||
unsigned int hash_str(const void *vstr)
|
||||
{
|
||||
unsigned int hash = 0;
|
||||
int c;
|
||||
const char *str = (const char*)vstr;
|
||||
unsigned int hash = 0;
|
||||
int c;
|
||||
const char *str = (const char *)vstr;
|
||||
|
||||
while ((c = tolower(*str++)))
|
||||
{
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
}
|
||||
while ((c = tolower(*str++)))
|
||||
{
|
||||
hash = c + (hash << 6) + (hash << 16) - hash;
|
||||
}
|
||||
|
||||
return hash;
|
||||
return hash;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* str_eq */
|
||||
int
|
||||
str_eq(const void *str1, const void *str2)
|
||||
int str_eq(const void *str1, const void *str2)
|
||||
{
|
||||
return 0 == strcasecmp((const char*)str1, (const char*)str2);
|
||||
return 0 == strcasecmp((const char *)str1, (const char *)str2);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* create_string_hashtable */
|
||||
hashtable *
|
||||
create_string_hashtable()
|
||||
hashtable *create_string_hashtable()
|
||||
{
|
||||
return create_hashtable(16, hash_str, str_eq);
|
||||
return create_hashtable(16, hash_str, str_eq);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
hashtable *
|
||||
create_hashtable(
|
||||
unsigned int minsize,
|
||||
unsigned int (*hashf) (const void*),
|
||||
int (*eqf) (const void*,const void*))
|
||||
hashtable *create_hashtable(unsigned int minsize,
|
||||
unsigned int (*hashf)(const void *),
|
||||
int (*eqf)(const void *, const void *))
|
||||
{
|
||||
hashtable *h;
|
||||
unsigned int pindex, size = primes[0];
|
||||
/* Check requested hashtable isn't too large */
|
||||
if (minsize > (1u << 30)) return NULL;
|
||||
/* Enforce size as prime */
|
||||
for (pindex=0; pindex < prime_table_length; pindex++)
|
||||
{
|
||||
if (primes[pindex] > minsize)
|
||||
{
|
||||
size = primes[pindex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
h = (hashtable *)malloc(sizeof(hashtable));
|
||||
if (NULL == h) return NULL; /*oom*/
|
||||
h->table = (struct entry **)malloc(sizeof(struct entry*) * size);
|
||||
if (NULL == h->table)
|
||||
{
|
||||
free(h); /*oom*/
|
||||
return NULL;
|
||||
}
|
||||
memset(h->table, 0, size * sizeof(struct entry *));
|
||||
h->tablelength = size;
|
||||
h->primeindex = pindex;
|
||||
h->entrycount = 0;
|
||||
h->hashfn = hashf;
|
||||
h->eqfn = eqf;
|
||||
h->loadlimit = (unsigned int) ceil(size * max_load_factor);
|
||||
return h;
|
||||
hashtable *h;
|
||||
unsigned int pindex, size = primes[0];
|
||||
/* Check requested hashtable isn't too large */
|
||||
if (minsize > (1u << 30))
|
||||
return NULL;
|
||||
/* Enforce size as prime */
|
||||
for (pindex = 0; pindex < prime_table_length; pindex++)
|
||||
{
|
||||
if (primes[pindex] > minsize)
|
||||
{
|
||||
size = primes[pindex];
|
||||
break;
|
||||
}
|
||||
}
|
||||
h = (hashtable *)malloc(sizeof(hashtable));
|
||||
if (NULL == h)
|
||||
return NULL; /*oom*/
|
||||
h->table = (struct entry **)malloc(sizeof(struct entry *) * size);
|
||||
if (NULL == h->table)
|
||||
{
|
||||
free(h); /*oom*/
|
||||
return NULL;
|
||||
}
|
||||
memset(h->table, 0, size * sizeof(struct entry *));
|
||||
h->tablelength = size;
|
||||
h->primeindex = pindex;
|
||||
h->entrycount = 0;
|
||||
h->hashfn = hashf;
|
||||
h->eqfn = eqf;
|
||||
h->loadlimit = (unsigned int)ceil(size * max_load_factor);
|
||||
return h;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
unsigned int
|
||||
hash(hashtable *h, const void *k)
|
||||
unsigned int hash(hashtable *h, const void *k)
|
||||
{
|
||||
/* Aim to protect against poor hash functions by adding logic here
|
||||
* - logic taken from java 1.4 hashtable source */
|
||||
unsigned int i = h->hashfn(k);
|
||||
i += ~(i << 9);
|
||||
i ^= ((i >> 14) | (i << 18)); /* >>> */
|
||||
i += (i << 4);
|
||||
i ^= ((i >> 10) | (i << 22)); /* >>> */
|
||||
return i;
|
||||
/* Aim to protect against poor hash functions by adding logic here
|
||||
* - logic taken from java 1.4 hashtable source */
|
||||
unsigned int i = h->hashfn(k);
|
||||
i += ~(i << 9);
|
||||
i ^= ((i >> 14) | (i << 18)); /* >>> */
|
||||
i += (i << 4);
|
||||
i ^= ((i >> 10) | (i << 22)); /* >>> */
|
||||
return i;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
static int
|
||||
hashtable_expand(hashtable *h)
|
||||
static int hashtable_expand(hashtable *h)
|
||||
{
|
||||
/* Double the size of the table to accomodate more entries */
|
||||
struct entry **newtable;
|
||||
struct entry *e;
|
||||
struct entry **pE;
|
||||
unsigned int newsize, i, index;
|
||||
/* Check we're not hitting max capacity */
|
||||
if (h->primeindex == (prime_table_length - 1)) return 0;
|
||||
newsize = primes[++(h->primeindex)];
|
||||
/* Double the size of the table to accomodate more entries */
|
||||
struct entry **newtable;
|
||||
struct entry *e;
|
||||
struct entry **pE;
|
||||
unsigned int newsize, i, index;
|
||||
/* Check we're not hitting max capacity */
|
||||
if (h->primeindex == (prime_table_length - 1))
|
||||
return 0;
|
||||
newsize = primes[++(h->primeindex)];
|
||||
|
||||
newtable = (struct entry **)malloc(sizeof(struct entry*) * newsize);
|
||||
if (NULL != newtable)
|
||||
{
|
||||
memset(newtable, 0, newsize * sizeof(struct entry *));
|
||||
/* This algorithm is not 'stable'. ie. it reverses the list
|
||||
* when it transfers entries between the tables */
|
||||
for (i = 0; i < h->tablelength; i++)
|
||||
{
|
||||
while (NULL != (e = h->table[i]))
|
||||
{
|
||||
h->table[i] = e->next;
|
||||
index = indexFor(newsize,e->h);
|
||||
e->next = newtable[index];
|
||||
newtable[index] = e;
|
||||
}
|
||||
}
|
||||
free(h->table);
|
||||
h->table = newtable;
|
||||
}
|
||||
/* Plan B: realloc instead */
|
||||
else
|
||||
{
|
||||
newtable = (struct entry **)
|
||||
realloc(h->table, newsize * sizeof(struct entry *));
|
||||
if (NULL == newtable)
|
||||
{
|
||||
(h->primeindex)--;
|
||||
return 0;
|
||||
}
|
||||
h->table = newtable;
|
||||
memset(newtable[h->tablelength], 0, newsize - h->tablelength);
|
||||
for (i = 0; i < h->tablelength; i++)
|
||||
{
|
||||
for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE)
|
||||
{
|
||||
index = indexFor(newsize,e->h);
|
||||
if (index == i)
|
||||
{
|
||||
pE = &(e->next);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pE = e->next;
|
||||
e->next = newtable[index];
|
||||
newtable[index] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
h->tablelength = newsize;
|
||||
h->loadlimit = (unsigned int) ceil(newsize * max_load_factor);
|
||||
return -1;
|
||||
newtable = (struct entry **)malloc(sizeof(struct entry *) * newsize);
|
||||
if (NULL != newtable)
|
||||
{
|
||||
memset(newtable, 0, newsize * sizeof(struct entry *));
|
||||
/* This algorithm is not 'stable'. ie. it reverses the list
|
||||
* when it transfers entries between the tables */
|
||||
for (i = 0; i < h->tablelength; i++)
|
||||
{
|
||||
while (NULL != (e = h->table[i]))
|
||||
{
|
||||
h->table[i] = e->next;
|
||||
index = indexFor(newsize, e->h);
|
||||
e->next = newtable[index];
|
||||
newtable[index] = e;
|
||||
}
|
||||
}
|
||||
free(h->table);
|
||||
h->table = newtable;
|
||||
}
|
||||
/* Plan B: realloc instead */
|
||||
else
|
||||
{
|
||||
newtable =
|
||||
(struct entry **)realloc(h->table, newsize * sizeof(struct entry *));
|
||||
if (NULL == newtable)
|
||||
{
|
||||
(h->primeindex)--;
|
||||
return 0;
|
||||
}
|
||||
h->table = newtable;
|
||||
memset(newtable[h->tablelength], 0, newsize - h->tablelength);
|
||||
for (i = 0; i < h->tablelength; i++)
|
||||
{
|
||||
for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE)
|
||||
{
|
||||
index = indexFor(newsize, e->h);
|
||||
if (index == i)
|
||||
{
|
||||
pE = &(e->next);
|
||||
}
|
||||
else
|
||||
{
|
||||
*pE = e->next;
|
||||
e->next = newtable[index];
|
||||
newtable[index] = e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
h->tablelength = newsize;
|
||||
h->loadlimit = (unsigned int)ceil(newsize * max_load_factor);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
unsigned int
|
||||
hashtable_count(hashtable *h)
|
||||
{
|
||||
return h->entrycount;
|
||||
}
|
||||
unsigned int hashtable_count(hashtable *h) { return h->entrycount; }
|
||||
|
||||
/*****************************************************************************/
|
||||
int
|
||||
hashtable_insert(hashtable *h, void *k, void *v)
|
||||
int hashtable_insert(hashtable *h, void *k, void *v)
|
||||
{
|
||||
/* This method allows duplicate keys - but they shouldn't be used */
|
||||
unsigned int index;
|
||||
struct entry *e;
|
||||
if (++(h->entrycount) > h->loadlimit)
|
||||
{
|
||||
/* Ignore the return value. If expand fails, we should
|
||||
* still try cramming just this value into the existing table
|
||||
* -- we may not have memory for a larger table, but one more
|
||||
* element may be ok. Next time we insert, we'll try expanding again.*/
|
||||
hashtable_expand(h);
|
||||
}
|
||||
e = (struct entry *)malloc(sizeof(struct entry));
|
||||
if (NULL == e)
|
||||
{
|
||||
--(h->entrycount); /*oom*/
|
||||
return 0;
|
||||
}
|
||||
e->h = hash(h,k);
|
||||
index = indexFor(h->tablelength,e->h);
|
||||
e->k = k;
|
||||
e->v = v;
|
||||
e->next = h->table[index];
|
||||
h->table[index] = e;
|
||||
return -1;
|
||||
/* This method allows duplicate keys - but they shouldn't be used */
|
||||
unsigned int index;
|
||||
struct entry *e;
|
||||
if (++(h->entrycount) > h->loadlimit)
|
||||
{
|
||||
/* Ignore the return value. If expand fails, we should
|
||||
* still try cramming just this value into the existing table
|
||||
* -- we may not have memory for a larger table, but one more
|
||||
* element may be ok. Next time we insert, we'll try expanding again.*/
|
||||
hashtable_expand(h);
|
||||
}
|
||||
e = (struct entry *)malloc(sizeof(struct entry));
|
||||
if (NULL == e)
|
||||
{
|
||||
--(h->entrycount); /*oom*/
|
||||
return 0;
|
||||
}
|
||||
e->h = hash(h, k);
|
||||
index = indexFor(h->tablelength, e->h);
|
||||
e->k = k;
|
||||
e->v = v;
|
||||
e->next = h->table[index];
|
||||
h->table[index] = e;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void * /* returns value associated with key */
|
||||
hashtable_search(hashtable *h, const void *k)
|
||||
{
|
||||
struct entry *e;
|
||||
unsigned int hashvalue, index;
|
||||
hashvalue = hash(h,k);
|
||||
index = indexFor(h->tablelength,hashvalue);
|
||||
e = h->table[index];
|
||||
while (NULL != e)
|
||||
{
|
||||
/* Check hash value to short circuit heavier comparison */
|
||||
if ((hashvalue == e->h) && (h->eqfn(k, e->k))) return e->v;
|
||||
e = e->next;
|
||||
}
|
||||
return NULL;
|
||||
struct entry *e;
|
||||
unsigned int hashvalue, index;
|
||||
hashvalue = hash(h, k);
|
||||
index = indexFor(h->tablelength, hashvalue);
|
||||
e = h->table[index];
|
||||
while (NULL != e)
|
||||
{
|
||||
/* Check hash value to short circuit heavier comparison */
|
||||
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
|
||||
return e->v;
|
||||
e = e->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
void * /* returns value associated with key */
|
||||
hashtable_remove(hashtable *h, void *k)
|
||||
{
|
||||
/* TODO: consider compacting the table when the load factor drops enough,
|
||||
* or provide a 'compact' method. */
|
||||
/* TODO: consider compacting the table when the load factor drops enough,
|
||||
* or provide a 'compact' method. */
|
||||
|
||||
struct entry *e;
|
||||
struct entry **pE;
|
||||
void *v;
|
||||
unsigned int hashvalue, index;
|
||||
struct entry *e;
|
||||
struct entry **pE;
|
||||
void *v;
|
||||
unsigned int hashvalue, index;
|
||||
|
||||
hashvalue = hash(h,k);
|
||||
index = indexFor(h->tablelength,hash(h,k));
|
||||
pE = &(h->table[index]);
|
||||
e = *pE;
|
||||
while (NULL != e)
|
||||
{
|
||||
/* Check hash value to short circuit heavier comparison */
|
||||
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
|
||||
{
|
||||
*pE = e->next;
|
||||
h->entrycount--;
|
||||
v = e->v;
|
||||
free(e->k);
|
||||
free(e);
|
||||
return v;
|
||||
}
|
||||
pE = &(e->next);
|
||||
e = e->next;
|
||||
}
|
||||
return NULL;
|
||||
hashvalue = hash(h, k);
|
||||
index = indexFor(h->tablelength, hash(h, k));
|
||||
pE = &(h->table[index]);
|
||||
e = *pE;
|
||||
while (NULL != e)
|
||||
{
|
||||
/* Check hash value to short circuit heavier comparison */
|
||||
if ((hashvalue == e->h) && (h->eqfn(k, e->k)))
|
||||
{
|
||||
*pE = e->next;
|
||||
h->entrycount--;
|
||||
v = e->v;
|
||||
free(e->k);
|
||||
free(e);
|
||||
return v;
|
||||
}
|
||||
pE = &(e->next);
|
||||
e = e->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
/* destroy */
|
||||
void
|
||||
hashtable_destroy(hashtable *h, int free_values)
|
||||
void hashtable_destroy(hashtable *h, int free_values)
|
||||
{
|
||||
unsigned int i;
|
||||
struct entry *e, *f;
|
||||
struct entry **table = h->table;
|
||||
if (free_values)
|
||||
{
|
||||
for (i = 0; i < h->tablelength; i++)
|
||||
{
|
||||
e = table[i];
|
||||
while (NULL != e)
|
||||
{
|
||||
f = e;
|
||||
e = e->next;
|
||||
free(f->k);
|
||||
free(f->v);
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < h->tablelength; i++)
|
||||
{
|
||||
e = table[i];
|
||||
while (NULL != e)
|
||||
{
|
||||
f = e;
|
||||
e = e->next;
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(h->table);
|
||||
free(h);
|
||||
unsigned int i;
|
||||
struct entry *e, *f;
|
||||
struct entry **table = h->table;
|
||||
if (free_values)
|
||||
{
|
||||
for (i = 0; i < h->tablelength; i++)
|
||||
{
|
||||
e = table[i];
|
||||
while (NULL != e)
|
||||
{
|
||||
f = e;
|
||||
e = e->next;
|
||||
free(f->k);
|
||||
free(f->v);
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = 0; i < h->tablelength; i++)
|
||||
{
|
||||
e = table[i];
|
||||
while (NULL != e)
|
||||
{
|
||||
f = e;
|
||||
e = e->next;
|
||||
free(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
free(h->table);
|
||||
free(h);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002, Christopher Clark
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
* Copyright (c) 2002, Christopher Clark
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
289
lib/hashtable.h
289
lib/hashtable.h
@ -7,82 +7,81 @@
|
||||
|
||||
typedef struct entry
|
||||
{
|
||||
void *k, *v;
|
||||
unsigned int h;
|
||||
struct entry *next;
|
||||
void *k, *v;
|
||||
unsigned int h;
|
||||
struct entry *next;
|
||||
} entry;
|
||||
|
||||
typedef struct hashtable
|
||||
{
|
||||
unsigned int tablelength;
|
||||
entry **table;
|
||||
unsigned int entrycount;
|
||||
unsigned int loadlimit;
|
||||
unsigned int primeindex;
|
||||
unsigned int (*hashfn) (const void *k);
|
||||
int (*eqfn) (const void *k1, const void *k2);
|
||||
unsigned int tablelength;
|
||||
entry **table;
|
||||
unsigned int entrycount;
|
||||
unsigned int loadlimit;
|
||||
unsigned int primeindex;
|
||||
unsigned int (*hashfn)(const void *k);
|
||||
int (*eqfn)(const void *k1, const void *k2);
|
||||
} hashtable;
|
||||
|
||||
/*****************************************************************************/
|
||||
unsigned int
|
||||
hash(hashtable *h, const void *k);
|
||||
unsigned int hash(hashtable *h, const void *k);
|
||||
|
||||
/* Example of use:
|
||||
*
|
||||
* hashtable *h;
|
||||
* struct some_key *k;
|
||||
* struct some_value *v;
|
||||
*
|
||||
* static unsigned int hash_from_key_fn( void *k );
|
||||
* static int keys_equal_fn ( void *key1, void *key2 );
|
||||
*
|
||||
* h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
|
||||
* k = (struct some_key *) malloc(sizeof(struct some_key));
|
||||
* v = (struct some_value *) malloc(sizeof(struct some_value));
|
||||
*
|
||||
* (initialise k and v to suitable values)
|
||||
*
|
||||
* if (! hashtable_insert(h,k,v) )
|
||||
* { exit(-1); }
|
||||
*
|
||||
* if (NULL == (found = hashtable_search(h,k) ))
|
||||
* { printf("not found!"); }
|
||||
*
|
||||
* if (NULL == (found = hashtable_remove(h,k) ))
|
||||
* { printf("Not found\n"); }
|
||||
*
|
||||
*/
|
||||
*
|
||||
* hashtable *h;
|
||||
* struct some_key *k;
|
||||
* struct some_value *v;
|
||||
*
|
||||
* static unsigned int hash_from_key_fn( void *k );
|
||||
* static int keys_equal_fn ( void *key1, void *key2 );
|
||||
*
|
||||
* h = create_hashtable(16, hash_from_key_fn, keys_equal_fn);
|
||||
* k = (struct some_key *) malloc(sizeof(struct some_key));
|
||||
* v = (struct some_value *) malloc(sizeof(struct some_value));
|
||||
*
|
||||
* (initialise k and v to suitable values)
|
||||
*
|
||||
* if (! hashtable_insert(h,k,v) )
|
||||
* { exit(-1); }
|
||||
*
|
||||
* if (NULL == (found = hashtable_search(h,k) ))
|
||||
* { printf("not found!"); }
|
||||
*
|
||||
* if (NULL == (found = hashtable_remove(h,k) ))
|
||||
* { printf("Not found\n"); }
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* Macros may be used to define type-safe(r) hashtable access functions, with
|
||||
* methods specialized to take known key and value types as parameters.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Insert this at the start of your file:
|
||||
*
|
||||
* DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
|
||||
* DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
|
||||
* DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
|
||||
*
|
||||
* This defines the functions 'insert_some', 'search_some' and 'remove_some'.
|
||||
* These operate just like hashtable_insert etc., with the same parameters,
|
||||
* but their function signatures have 'struct some_key *' rather than
|
||||
* 'void *', and hence can generate compile time errors if your program is
|
||||
* supplying incorrect data as a key (and similarly for value).
|
||||
*
|
||||
* Note that the hash and key equality functions passed to create_hashtable
|
||||
* still take 'void *' parameters instead of 'some key *'. This shouldn't be
|
||||
* a difficult issue as they're only defined and passed once, and the other
|
||||
* functions will ensure that only valid keys are supplied to them.
|
||||
*
|
||||
* The cost for this checking is increased code size and runtime overhead
|
||||
* - if performance is important, it may be worth switching back to the
|
||||
* unsafe methods once your program has been debugged with the safe methods.
|
||||
* This just requires switching to some simple alternative defines - eg:
|
||||
* #define insert_some hashtable_insert
|
||||
*
|
||||
*/
|
||||
* Macros may be used to define type-safe(r) hashtable access functions, with
|
||||
* methods specialized to take known key and value types as parameters.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* Insert this at the start of your file:
|
||||
*
|
||||
* DEFINE_HASHTABLE_INSERT(insert_some, struct some_key, struct some_value);
|
||||
* DEFINE_HASHTABLE_SEARCH(search_some, struct some_key, struct some_value);
|
||||
* DEFINE_HASHTABLE_REMOVE(remove_some, struct some_key, struct some_value);
|
||||
*
|
||||
* This defines the functions 'insert_some', 'search_some' and 'remove_some'.
|
||||
* These operate just like hashtable_insert etc., with the same parameters,
|
||||
* but their function signatures have 'struct some_key *' rather than
|
||||
* 'void *', and hence can generate compile time errors if your program is
|
||||
* supplying incorrect data as a key (and similarly for value).
|
||||
*
|
||||
* Note that the hash and key equality functions passed to create_hashtable
|
||||
* still take 'void *' parameters instead of 'some key *'. This shouldn't be
|
||||
* a difficult issue as they're only defined and passed once, and the other
|
||||
* functions will ensure that only valid keys are supplied to them.
|
||||
*
|
||||
* The cost for this checking is increased code size and runtime overhead
|
||||
* - if performance is important, it may be worth switching back to the
|
||||
* unsafe methods once your program has been debugged with the safe methods.
|
||||
* This just requires switching to some simple alternative defines - eg:
|
||||
* #define insert_some hashtable_insert
|
||||
*
|
||||
*/
|
||||
|
||||
/*****************************************************************************
|
||||
* create_hashtable
|
||||
@ -94,20 +93,16 @@ hash(hashtable *h, const void *k);
|
||||
* @return newly created hashtable or NULL on failure
|
||||
*/
|
||||
|
||||
hashtable *
|
||||
create_hashtable(unsigned int minsize,
|
||||
unsigned int (*hashfunction) (const void*),
|
||||
int (*key_eq_fn) (const void*,const void*));
|
||||
|
||||
hashtable *create_hashtable(unsigned int minsize,
|
||||
unsigned int (*hashfunction)(const void *),
|
||||
int (*key_eq_fn)(const void *, const void *));
|
||||
|
||||
/*****************************************************************************
|
||||
* create_string_hashtable
|
||||
* @name create_string_hashtable
|
||||
* @return hashtable for string keys, with start size of 16
|
||||
*/
|
||||
hashtable *
|
||||
create_string_hashtable(void);
|
||||
|
||||
* create_string_hashtable
|
||||
* @name create_string_hashtable
|
||||
* @return hashtable for string keys, with start size of 16
|
||||
*/
|
||||
hashtable *create_string_hashtable(void);
|
||||
|
||||
/*****************************************************************************
|
||||
* hashtable_insert
|
||||
@ -128,14 +123,13 @@ create_string_hashtable(void);
|
||||
* If in doubt, remove before insert.
|
||||
*/
|
||||
|
||||
int
|
||||
hashtable_insert(hashtable *h, void *k, void *v);
|
||||
int hashtable_insert(hashtable *h, void *k, void *v);
|
||||
|
||||
#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
|
||||
int fnname (hashtable *h, keytype *k, valuetype *v) \
|
||||
{ \
|
||||
return hashtable_insert(h,k,v); \
|
||||
}
|
||||
#define DEFINE_HASHTABLE_INSERT(fnname, keytype, valuetype) \
|
||||
int fnname(hashtable *h, keytype *k, valuetype *v) \
|
||||
{ \
|
||||
return hashtable_insert(h, k, v); \
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* hashtable_search
|
||||
@ -146,14 +140,13 @@ int fnname (hashtable *h, keytype *k, valuetype *v) \
|
||||
* @return the value associated with the key, or NULL if none found
|
||||
*/
|
||||
|
||||
void *
|
||||
hashtable_search(hashtable *h, const void *k);
|
||||
void *hashtable_search(hashtable *h, const void *k);
|
||||
|
||||
#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
|
||||
valuetype * fnname (hashtable *h, keytype *k) \
|
||||
{ \
|
||||
return (valuetype *) (hashtable_search(h,k)); \
|
||||
}
|
||||
#define DEFINE_HASHTABLE_SEARCH(fnname, keytype, valuetype) \
|
||||
valuetype *fnname(hashtable *h, keytype *k) \
|
||||
{ \
|
||||
return (valuetype *)(hashtable_search(h, k)); \
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* hashtable_remove
|
||||
@ -167,30 +160,26 @@ valuetype * fnname (hashtable *h, keytype *k) \
|
||||
void * /* returns value */
|
||||
hashtable_remove(hashtable *h, void *k);
|
||||
|
||||
#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
|
||||
valuetype * fnname (hashtable *h, keytype *k) \
|
||||
{ \
|
||||
return (valuetype *) (hashtable_remove(h,k)); \
|
||||
}
|
||||
|
||||
#define DEFINE_HASHTABLE_REMOVE(fnname, keytype, valuetype) \
|
||||
valuetype *fnname(hashtable *h, keytype *k) \
|
||||
{ \
|
||||
return (valuetype *)(hashtable_remove(h, k)); \
|
||||
}
|
||||
|
||||
/**
|
||||
* @name hash_str
|
||||
* @param str the string to hash
|
||||
* @return the hash value
|
||||
*/
|
||||
unsigned int
|
||||
hash_str(const void *str);
|
||||
* @name hash_str
|
||||
* @param str the string to hash
|
||||
* @return the hash value
|
||||
*/
|
||||
unsigned int hash_str(const void *str);
|
||||
|
||||
/**
|
||||
* @name str_eq
|
||||
* @param str1 the string to compare
|
||||
* @param str2 the string to compare
|
||||
* @return 1 if equal 0 if not
|
||||
*/
|
||||
int
|
||||
str_eq(const void *str1, const void *str2);
|
||||
|
||||
* @name str_eq
|
||||
* @param str1 the string to compare
|
||||
* @param str2 the string to compare
|
||||
* @return 1 if equal 0 if not
|
||||
*/
|
||||
int str_eq(const void *str1, const void *str2);
|
||||
|
||||
/*****************************************************************************
|
||||
* hashtable_count
|
||||
@ -199,9 +188,7 @@ str_eq(const void *str1, const void *str2);
|
||||
* @param h the hashtable
|
||||
* @return the number of items stored in the hashtable
|
||||
*/
|
||||
unsigned int
|
||||
hashtable_count(hashtable *h);
|
||||
|
||||
unsigned int hashtable_count(hashtable *h);
|
||||
|
||||
/*****************************************************************************
|
||||
* hashtable_destroy
|
||||
@ -211,51 +198,47 @@ hashtable_count(hashtable *h);
|
||||
* @param free_values whether to call 'free' on the remaining values
|
||||
*/
|
||||
|
||||
void
|
||||
hashtable_destroy(hashtable *h, int free_values);
|
||||
|
||||
|
||||
void hashtable_destroy(hashtable *h, int free_values);
|
||||
|
||||
/*****************************************************************************/
|
||||
/* indexFor */
|
||||
static inline unsigned int
|
||||
indexFor(unsigned int tablelength, unsigned int hashvalue)
|
||||
static inline unsigned int indexFor(unsigned int tablelength,
|
||||
unsigned int hashvalue)
|
||||
{
|
||||
return (hashvalue % tablelength);
|
||||
return (hashvalue % tablelength);
|
||||
};
|
||||
|
||||
|
||||
#endif /* __HASHTABLE_CWC22_H__ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 2002, Christopher Clark
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
* Copyright (c) 2002, Christopher Clark
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* * Neither the name of the original author; nor the names of any contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
|
||||
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
@ -1,263 +1,253 @@
|
||||
/***********************************************************************
|
||||
* lazperf_adapter.cpp
|
||||
*
|
||||
* LazPerf compression/decompression
|
||||
*
|
||||
* Copyright (c) 2016 Paul Blottiere, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
* lazperf_adapter.cpp
|
||||
*
|
||||
* LazPerf compression/decompression
|
||||
*
|
||||
* Copyright (c) 2016 Paul Blottiere, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "lazperf_adapter.hpp"
|
||||
|
||||
#ifdef HAVE_LAZPERF
|
||||
|
||||
/**********************************************************************
|
||||
* C API
|
||||
*/
|
||||
size_t
|
||||
lazperf_compress_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa, uint8_t **compressed)
|
||||
* C API
|
||||
*/
|
||||
size_t lazperf_compress_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa,
|
||||
uint8_t **compressed)
|
||||
{
|
||||
size_t size = 1;
|
||||
size_t size = 1;
|
||||
|
||||
LazPerfBuf buf;
|
||||
LazPerfCompressor engine(pa->schema, buf);
|
||||
LazPerfBuf buf;
|
||||
LazPerfCompressor engine(pa->schema, buf);
|
||||
|
||||
if (engine.compress(pa->data, pa->datasize) == pa->npoints)
|
||||
{
|
||||
size = buf.buf.size();
|
||||
*compressed = (uint8_t*) malloc(size);
|
||||
*compressed = (uint8_t*) memcpy(*compressed, buf.data(), size);
|
||||
}
|
||||
if (engine.compress(pa->data, pa->datasize) == pa->npoints)
|
||||
{
|
||||
size = buf.buf.size();
|
||||
*compressed = (uint8_t *)malloc(size);
|
||||
*compressed = (uint8_t *)memcpy(*compressed, buf.data(), size);
|
||||
}
|
||||
|
||||
// log
|
||||
// lazperf_dump(pa);
|
||||
// lazperf_dump(*compressed, size);
|
||||
// log
|
||||
// lazperf_dump(pa);
|
||||
// lazperf_dump(*compressed, size);
|
||||
|
||||
return size;
|
||||
return size;
|
||||
}
|
||||
|
||||
size_t
|
||||
lazperf_uncompress_from_compressed(const PCPATCH_LAZPERF *pa, uint8_t **decompressed)
|
||||
size_t lazperf_uncompress_from_compressed(const PCPATCH_LAZPERF *pa,
|
||||
uint8_t **decompressed)
|
||||
{
|
||||
size_t size = -1;
|
||||
size_t datasize = pa->schema->size * pa->npoints;
|
||||
size_t size = -1;
|
||||
size_t datasize = pa->schema->size * pa->npoints;
|
||||
|
||||
LazPerfBuf buf;
|
||||
buf.putBytes(pa->lazperf, pa->lazperfsize);
|
||||
LazPerfDecompressor engine(pa->schema, buf);
|
||||
LazPerfBuf buf;
|
||||
buf.putBytes(pa->lazperf, pa->lazperfsize);
|
||||
LazPerfDecompressor engine(pa->schema, buf);
|
||||
|
||||
*decompressed = (uint8_t*) malloc(datasize);
|
||||
*decompressed = (uint8_t *)malloc(datasize);
|
||||
|
||||
if (engine.decompress(*decompressed, datasize) == pa->npoints)
|
||||
size = buf.buf.size();
|
||||
if (engine.decompress(*decompressed, datasize) == pa->npoints)
|
||||
size = buf.buf.size();
|
||||
|
||||
// log
|
||||
// lazperf_dump(pa);
|
||||
// lazperf_dump(*decompressed, datasize);
|
||||
// log
|
||||
// lazperf_dump(pa);
|
||||
// lazperf_dump(*decompressed, datasize);
|
||||
|
||||
return size;
|
||||
return size;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* INTERNAL CPP
|
||||
*/
|
||||
* INTERNAL CPP
|
||||
*/
|
||||
// utility functions
|
||||
void
|
||||
lazperf_dump(uint8_t *data, const size_t size)
|
||||
void lazperf_dump(uint8_t *data, const size_t size)
|
||||
{
|
||||
std::cout << "DUMP DATA: " << std::endl;
|
||||
std::cout << " - datasize: " << size << std::endl;
|
||||
std::cout << " - data: ";
|
||||
for (int i = 0; i < size; ++i)
|
||||
printf("%02x ", data[i]);
|
||||
std::cout << std::endl;
|
||||
std::cout << "DUMP DATA: " << std::endl;
|
||||
std::cout << " - datasize: " << size << std::endl;
|
||||
std::cout << " - data: ";
|
||||
for (int i = 0; i < size; ++i)
|
||||
printf("%02x ", data[i]);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
lazperf_dump(const PCPATCH_UNCOMPRESSED* p)
|
||||
void lazperf_dump(const PCPATCH_UNCOMPRESSED *p)
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << "DUMP UNCOMPRESSED PATCH: " << std::endl;
|
||||
std::cout << " - type: " << p->type << std::endl;
|
||||
std::cout << " - schema->size " << p->schema->size << std::endl;
|
||||
std::cout << " - readonly: " << p->readonly << std::endl;
|
||||
std::cout << " - npoints: " << p->npoints << std::endl;
|
||||
std::cout << " - maxpoints: " << p->maxpoints << std::endl;
|
||||
std::cout << " - datasize: " << p->datasize << std::endl;
|
||||
std::cout << " - data: ";
|
||||
for (int i = 0; i < p->datasize; ++i)
|
||||
printf("%02x ", p->data[i]);
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "DUMP UNCOMPRESSED PATCH: " << std::endl;
|
||||
std::cout << " - type: " << p->type << std::endl;
|
||||
std::cout << " - schema->size " << p->schema->size << std::endl;
|
||||
std::cout << " - readonly: " << p->readonly << std::endl;
|
||||
std::cout << " - npoints: " << p->npoints << std::endl;
|
||||
std::cout << " - maxpoints: " << p->maxpoints << std::endl;
|
||||
std::cout << " - datasize: " << p->datasize << std::endl;
|
||||
std::cout << " - data: ";
|
||||
for (int i = 0; i < p->datasize; ++i)
|
||||
printf("%02x ", p->data[i]);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
void
|
||||
lazperf_dump(const PCPATCH_LAZPERF* p)
|
||||
void lazperf_dump(const PCPATCH_LAZPERF *p)
|
||||
{
|
||||
std::cout << std::endl;
|
||||
std::cout << "DUMP LAZPERF PATCH: " << std::endl;
|
||||
std::cout << " - type: " << p->type << std::endl;
|
||||
std::cout << " - schema->size " << p->schema->size << std::endl;
|
||||
std::cout << " - readonly: " << p->readonly << std::endl;
|
||||
std::cout << " - npoints: " << p->npoints << std::endl;
|
||||
std::cout << " - lazperfsize: " << p->lazperfsize << std::endl;
|
||||
std::cout << " - lazperf: ";
|
||||
for (int i = 0; i < p->lazperfsize; ++i)
|
||||
printf("%02x ", p->lazperf[i]);
|
||||
std::cout << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "DUMP LAZPERF PATCH: " << std::endl;
|
||||
std::cout << " - type: " << p->type << std::endl;
|
||||
std::cout << " - schema->size " << p->schema->size << std::endl;
|
||||
std::cout << " - readonly: " << p->readonly << std::endl;
|
||||
std::cout << " - npoints: " << p->npoints << std::endl;
|
||||
std::cout << " - lazperfsize: " << p->lazperfsize << std::endl;
|
||||
std::cout << " - lazperf: ";
|
||||
for (int i = 0; i < p->lazperfsize; ++i)
|
||||
printf("%02x ", p->lazperf[i]);
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// LazPerf class
|
||||
template<typename LazPerfEngine, typename LazPerfCoder>
|
||||
LazPerf<LazPerfEngine, LazPerfCoder>::LazPerf(const PCSCHEMA *pcschema, LazPerfBuf &buf)
|
||||
: _pcschema(pcschema)
|
||||
, _coder(buf)
|
||||
, _pointsize(0)
|
||||
template <typename LazPerfEngine, typename LazPerfCoder>
|
||||
LazPerf<LazPerfEngine, LazPerfCoder>::LazPerf(const PCSCHEMA *pcschema,
|
||||
LazPerfBuf &buf)
|
||||
: _pcschema(pcschema), _coder(buf), _pointsize(0)
|
||||
{
|
||||
}
|
||||
|
||||
template<typename LazPerfEngine, typename LazPerfCoder>
|
||||
template <typename LazPerfEngine, typename LazPerfCoder>
|
||||
LazPerf<LazPerfEngine, LazPerfCoder>::~LazPerf()
|
||||
{
|
||||
}
|
||||
|
||||
template<typename LazPerfEngine, typename LazPerfCoder>
|
||||
void
|
||||
LazPerf<LazPerfEngine, LazPerfCoder>::initSchema()
|
||||
template <typename LazPerfEngine, typename LazPerfCoder>
|
||||
void LazPerf<LazPerfEngine, LazPerfCoder>::initSchema()
|
||||
{
|
||||
for (int i = 0; i < _pcschema->ndims; i++)
|
||||
addField(_pcschema->dims[i]);
|
||||
for (int i = 0; i < _pcschema->ndims; i++)
|
||||
addField(_pcschema->dims[i]);
|
||||
}
|
||||
|
||||
template<typename LazPerfEngine, typename LazPerfCoder>
|
||||
bool
|
||||
LazPerf<LazPerfEngine, LazPerfCoder>::addField(const PCDIMENSION *dim)
|
||||
template <typename LazPerfEngine, typename LazPerfCoder>
|
||||
bool LazPerf<LazPerfEngine, LazPerfCoder>::addField(const PCDIMENSION *dim)
|
||||
{
|
||||
bool rc = true;
|
||||
bool rc = true;
|
||||
|
||||
switch(dim->interpretation)
|
||||
{
|
||||
case PC_INT8:
|
||||
{
|
||||
_engine->template add_field<I8>();
|
||||
break;
|
||||
}
|
||||
case PC_UINT8:
|
||||
{
|
||||
_engine->template add_field<U8>();
|
||||
break;
|
||||
}
|
||||
case PC_INT16:
|
||||
{
|
||||
_engine->template add_field<I16>();
|
||||
break;
|
||||
}
|
||||
case PC_UINT16:
|
||||
{
|
||||
_engine->template add_field<U16>();
|
||||
break;
|
||||
}
|
||||
case PC_INT32:
|
||||
{
|
||||
_engine->template add_field<I32>();
|
||||
break;
|
||||
}
|
||||
case PC_UINT32:
|
||||
{
|
||||
_engine->template add_field<U32>();
|
||||
break;
|
||||
}
|
||||
case PC_INT64:
|
||||
{
|
||||
_engine->template add_field<I32>();
|
||||
_engine->template add_field<I32>();
|
||||
break;
|
||||
}
|
||||
case PC_UINT64:
|
||||
{
|
||||
_engine->template add_field<U32>();
|
||||
_engine->template add_field<U32>();
|
||||
break;
|
||||
}
|
||||
case PC_DOUBLE:
|
||||
{
|
||||
_engine->template add_field<U32>();
|
||||
_engine->template add_field<U32>();
|
||||
break;
|
||||
}
|
||||
case PC_FLOAT:
|
||||
{
|
||||
_engine->template add_field<I32>();
|
||||
break;
|
||||
}
|
||||
case PC_UNKNOWN:
|
||||
default:
|
||||
rc = false;
|
||||
}
|
||||
switch (dim->interpretation)
|
||||
{
|
||||
case PC_INT8:
|
||||
{
|
||||
_engine->template add_field<I8>();
|
||||
break;
|
||||
}
|
||||
case PC_UINT8:
|
||||
{
|
||||
_engine->template add_field<U8>();
|
||||
break;
|
||||
}
|
||||
case PC_INT16:
|
||||
{
|
||||
_engine->template add_field<I16>();
|
||||
break;
|
||||
}
|
||||
case PC_UINT16:
|
||||
{
|
||||
_engine->template add_field<U16>();
|
||||
break;
|
||||
}
|
||||
case PC_INT32:
|
||||
{
|
||||
_engine->template add_field<I32>();
|
||||
break;
|
||||
}
|
||||
case PC_UINT32:
|
||||
{
|
||||
_engine->template add_field<U32>();
|
||||
break;
|
||||
}
|
||||
case PC_INT64:
|
||||
{
|
||||
_engine->template add_field<I32>();
|
||||
_engine->template add_field<I32>();
|
||||
break;
|
||||
}
|
||||
case PC_UINT64:
|
||||
{
|
||||
_engine->template add_field<U32>();
|
||||
_engine->template add_field<U32>();
|
||||
break;
|
||||
}
|
||||
case PC_DOUBLE:
|
||||
{
|
||||
_engine->template add_field<U32>();
|
||||
_engine->template add_field<U32>();
|
||||
break;
|
||||
}
|
||||
case PC_FLOAT:
|
||||
{
|
||||
_engine->template add_field<I32>();
|
||||
break;
|
||||
}
|
||||
case PC_UNKNOWN:
|
||||
default:
|
||||
rc = false;
|
||||
}
|
||||
|
||||
if (rc)
|
||||
_pointsize += dim->size;
|
||||
if (rc)
|
||||
_pointsize += dim->size;
|
||||
|
||||
return rc;
|
||||
return rc;
|
||||
}
|
||||
|
||||
// LazPerf Compressor
|
||||
LazPerfCompressor::LazPerfCompressor(const PCSCHEMA *pcschema, LazPerfBuf &output)
|
||||
: LazPerf(pcschema, output)
|
||||
LazPerfCompressor::LazPerfCompressor(const PCSCHEMA *pcschema,
|
||||
LazPerfBuf &output)
|
||||
: LazPerf(pcschema, output)
|
||||
{
|
||||
_engine = laszip::formats::make_dynamic_compressor(_coder);
|
||||
initSchema();
|
||||
_engine = laszip::formats::make_dynamic_compressor(_coder);
|
||||
initSchema();
|
||||
}
|
||||
|
||||
LazPerfCompressor::~LazPerfCompressor()
|
||||
LazPerfCompressor::~LazPerfCompressor() {}
|
||||
|
||||
size_t LazPerfCompressor::compress(const uint8_t *input, const size_t inputsize)
|
||||
{
|
||||
}
|
||||
size_t size = 0;
|
||||
|
||||
size_t
|
||||
LazPerfCompressor::compress(const uint8_t *input, const size_t inputsize)
|
||||
{
|
||||
size_t size = 0;
|
||||
const uint8_t *end = input + inputsize;
|
||||
|
||||
const uint8_t *end = input + inputsize;
|
||||
while (input + _pointsize <= end)
|
||||
{
|
||||
_engine->compress((const char *)input);
|
||||
input += _pointsize;
|
||||
size++;
|
||||
}
|
||||
|
||||
while (input + _pointsize <= end)
|
||||
{
|
||||
_engine->compress((const char*) input);
|
||||
input += _pointsize;
|
||||
size++;
|
||||
}
|
||||
_coder.done();
|
||||
|
||||
_coder.done();
|
||||
|
||||
return size;
|
||||
return size;
|
||||
}
|
||||
|
||||
// LazPerf Decompressor
|
||||
LazPerfDecompressor::LazPerfDecompressor(const PCSCHEMA *pcschema, LazPerfBuf &input)
|
||||
: LazPerf(pcschema, input)
|
||||
LazPerfDecompressor::LazPerfDecompressor(const PCSCHEMA *pcschema,
|
||||
LazPerfBuf &input)
|
||||
: LazPerf(pcschema, input)
|
||||
{
|
||||
_engine = laszip::formats::make_dynamic_decompressor(_coder);
|
||||
initSchema();
|
||||
_engine = laszip::formats::make_dynamic_decompressor(_coder);
|
||||
initSchema();
|
||||
}
|
||||
|
||||
LazPerfDecompressor::~LazPerfDecompressor()
|
||||
LazPerfDecompressor::~LazPerfDecompressor() {}
|
||||
|
||||
size_t LazPerfDecompressor::decompress(uint8_t *output, const size_t outputsize)
|
||||
{
|
||||
}
|
||||
size_t size = 0;
|
||||
|
||||
size_t
|
||||
LazPerfDecompressor::decompress(uint8_t *output, const size_t outputsize)
|
||||
{
|
||||
size_t size = 0;
|
||||
const uint8_t *end = output + outputsize;
|
||||
|
||||
const uint8_t *end = output + outputsize;
|
||||
while (output + _pointsize <= end)
|
||||
{
|
||||
_engine->decompress((char *)output);
|
||||
output += _pointsize;
|
||||
size++;
|
||||
}
|
||||
|
||||
while (output + _pointsize <= end)
|
||||
{
|
||||
_engine->decompress((char*) output);
|
||||
output += _pointsize;
|
||||
size++;
|
||||
}
|
||||
|
||||
return size;
|
||||
return size;
|
||||
}
|
||||
|
||||
#endif // HAVE_LAZPERF
|
||||
|
||||
@ -1,23 +1,31 @@
|
||||
/***********************************************************************
|
||||
* lazperf_adapter.h
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
*
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
* Copyright (c) 2013 OpenGeo
|
||||
* Copyright (c) 2017 Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
* lazperf_adapter.h
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
*
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
* Copyright (c) 2013 OpenGeo
|
||||
* Copyright (c) 2017 Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _LAZPERF_ADAPTER_H
|
||||
#define _LAZPERF_ADAPTER_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pc_api_internal.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
size_t lazperf_compress_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa, uint8_t **compressed);
|
||||
size_t lazperf_uncompress_from_compressed(const PCPATCH_LAZPERF *pa, uint8_t **decompressed);
|
||||
size_t lazperf_compress_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa,
|
||||
uint8_t **compressed);
|
||||
size_t lazperf_uncompress_from_compressed(const PCPATCH_LAZPERF *pa,
|
||||
uint8_t **decompressed);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
/***********************************************************************
|
||||
* lazperf_adapter.hpp
|
||||
*
|
||||
* LazPerf compression/decompression
|
||||
*
|
||||
* Copyright (c) 2016 Paul Blottiere, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
* lazperf_adapter.hpp
|
||||
*
|
||||
* LazPerf compression/decompression
|
||||
*
|
||||
* Copyright (c) 2016 Paul Blottiere, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
@ -14,55 +14,57 @@
|
||||
#ifdef HAVE_LAZPERF
|
||||
#include <laz-perf/common/common.hpp>
|
||||
#include <laz-perf/compressor.hpp>
|
||||
#include <laz-perf/decoder.hpp>
|
||||
#include <laz-perf/decompressor.hpp>
|
||||
#include <laz-perf/encoder.hpp>
|
||||
#include <laz-perf/decoder.hpp>
|
||||
#include <laz-perf/formats.hpp>
|
||||
#include <laz-perf/las.hpp>
|
||||
|
||||
/**********************************************************************
|
||||
* C API
|
||||
*/
|
||||
* C API
|
||||
*/
|
||||
#include "lazperf_adapter.h"
|
||||
|
||||
/**********************************************************************
|
||||
* INTERNAL CPP
|
||||
*/
|
||||
* INTERNAL CPP
|
||||
*/
|
||||
// utility functions
|
||||
void lazperf_dump( uint8_t* data, const size_t size );
|
||||
void lazperf_dump( const PCPATCH_UNCOMPRESSED *p );
|
||||
void lazperf_dump( const PCPATCH_LAZPERF *p );
|
||||
void lazperf_dump(uint8_t *data, const size_t size);
|
||||
void lazperf_dump(const PCPATCH_UNCOMPRESSED *p);
|
||||
void lazperf_dump(const PCPATCH_LAZPERF *p);
|
||||
|
||||
// struct which capture data coming from the compressor
|
||||
struct LazPerfBuf {
|
||||
LazPerfBuf() : buf(), idx(0) {}
|
||||
struct LazPerfBuf
|
||||
{
|
||||
LazPerfBuf() : buf(), idx(0) {}
|
||||
|
||||
const uint8_t* data() {
|
||||
return reinterpret_cast<const uint8_t*>(buf.data());
|
||||
}
|
||||
const uint8_t *data()
|
||||
{
|
||||
return reinterpret_cast<const uint8_t *>(buf.data());
|
||||
}
|
||||
|
||||
void putBytes(const unsigned char* b, size_t len) {
|
||||
while(len --) {
|
||||
buf.push_back(*b++);
|
||||
}
|
||||
}
|
||||
void putBytes(const unsigned char *b, size_t len)
|
||||
{
|
||||
while (len--)
|
||||
{
|
||||
buf.push_back(*b++);
|
||||
}
|
||||
}
|
||||
|
||||
void putByte(const unsigned char b) {
|
||||
buf.push_back(b);
|
||||
}
|
||||
void putByte(const unsigned char b) { buf.push_back(b); }
|
||||
|
||||
unsigned char getByte() {
|
||||
return buf[idx++];
|
||||
}
|
||||
unsigned char getByte() { return buf[idx++]; }
|
||||
|
||||
void getBytes(unsigned char *b, int len) {
|
||||
for (int i = 0 ; i < len ; i ++) {
|
||||
b[i] = getByte();
|
||||
}
|
||||
}
|
||||
void getBytes(unsigned char *b, int len)
|
||||
{
|
||||
for (int i = 0; i < len; i++)
|
||||
{
|
||||
b[i] = getByte();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> buf;
|
||||
size_t idx;
|
||||
std::vector<unsigned char> buf;
|
||||
size_t idx;
|
||||
};
|
||||
|
||||
// some typedef
|
||||
@ -73,42 +75,44 @@ typedef laszip::formats::dynamic_field_compressor<Encoder>::ptr Compressor;
|
||||
typedef laszip::formats::dynamic_field_decompressor<Decoder>::ptr Decompressor;
|
||||
|
||||
// LazPerf class
|
||||
template<typename LazPerfEngine, typename LazPerfCoder>
|
||||
class LazPerf {
|
||||
template <typename LazPerfEngine, typename LazPerfCoder> class LazPerf
|
||||
{
|
||||
|
||||
public:
|
||||
LazPerf( const PCSCHEMA *pcschema, LazPerfBuf &buf );
|
||||
~LazPerf();
|
||||
public:
|
||||
LazPerf(const PCSCHEMA *pcschema, LazPerfBuf &buf);
|
||||
~LazPerf();
|
||||
|
||||
size_t pointsize() const { return _pointsize; }
|
||||
size_t pointsize() const { return _pointsize; }
|
||||
|
||||
protected:
|
||||
void initSchema();
|
||||
bool addField(const PCDIMENSION *dim);
|
||||
protected:
|
||||
void initSchema();
|
||||
bool addField(const PCDIMENSION *dim);
|
||||
|
||||
const PCSCHEMA *_pcschema;
|
||||
LazPerfCoder _coder;
|
||||
LazPerfEngine _engine;
|
||||
size_t _pointsize;
|
||||
const PCSCHEMA *_pcschema;
|
||||
LazPerfCoder _coder;
|
||||
LazPerfEngine _engine;
|
||||
size_t _pointsize;
|
||||
};
|
||||
|
||||
// compressor
|
||||
class LazPerfCompressor : public LazPerf<Compressor, Encoder> {
|
||||
class LazPerfCompressor : public LazPerf<Compressor, Encoder>
|
||||
{
|
||||
|
||||
public:
|
||||
LazPerfCompressor( const PCSCHEMA *pcschema, LazPerfBuf &output);
|
||||
~LazPerfCompressor();
|
||||
public:
|
||||
LazPerfCompressor(const PCSCHEMA *pcschema, LazPerfBuf &output);
|
||||
~LazPerfCompressor();
|
||||
|
||||
size_t compress( const uint8_t *input, const size_t inputsize );
|
||||
size_t compress(const uint8_t *input, const size_t inputsize);
|
||||
};
|
||||
|
||||
// decompressor
|
||||
class LazPerfDecompressor : public LazPerf<Decompressor, Decoder> {
|
||||
class LazPerfDecompressor : public LazPerf<Decompressor, Decoder>
|
||||
{
|
||||
|
||||
public:
|
||||
LazPerfDecompressor( const PCSCHEMA *pcschema, LazPerfBuf &input );
|
||||
~LazPerfDecompressor();
|
||||
public:
|
||||
LazPerfDecompressor(const PCSCHEMA *pcschema, LazPerfBuf &input);
|
||||
~LazPerfDecompressor();
|
||||
|
||||
size_t decompress( uint8_t *data, const size_t datasize );
|
||||
size_t decompress(uint8_t *data, const size_t datasize);
|
||||
};
|
||||
#endif // HAVE_LAZPERF
|
||||
|
||||
397
lib/pc_api.h
397
lib/pc_api.h
@ -1,276 +1,269 @@
|
||||
/***********************************************************************
|
||||
* pc_api.h
|
||||
*
|
||||
* Structures and function signatures for point clouds
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_api.h
|
||||
*
|
||||
* Structures and function signatures for point clouds
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _PC_API_H
|
||||
#define _PC_API_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "pc_config.h"
|
||||
#include "hashtable.h"
|
||||
#include "pc_config.h"
|
||||
|
||||
#ifndef __GNUC__
|
||||
#define __attribute__ (x)
|
||||
#endif
|
||||
|
||||
/**********************************************************************
|
||||
* DATA STRUCTURES
|
||||
*/
|
||||
* DATA STRUCTURES
|
||||
*/
|
||||
|
||||
/**
|
||||
* Compression types for PCPOINTS in a PCPATCH
|
||||
*/
|
||||
* Compression types for PCPOINTS in a PCPATCH
|
||||
*/
|
||||
enum COMPRESSIONS
|
||||
{
|
||||
PC_NONE = 0,
|
||||
PC_DIMENSIONAL = 1,
|
||||
PC_LAZPERF = 2
|
||||
PC_NONE = 0,
|
||||
PC_DIMENSIONAL = 1,
|
||||
PC_LAZPERF = 2
|
||||
};
|
||||
|
||||
/**
|
||||
* Flags of endianness for inter-architecture
|
||||
* data transfers.
|
||||
*/
|
||||
* Flags of endianness for inter-architecture
|
||||
* data transfers.
|
||||
*/
|
||||
enum ENDIANS
|
||||
{
|
||||
PC_XDR = 0, /* Big */
|
||||
PC_NDR = 1 /* Little */
|
||||
PC_XDR = 0, /* Big */
|
||||
PC_NDR = 1 /* Little */
|
||||
};
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PC_GT,
|
||||
PC_LT,
|
||||
PC_EQUAL,
|
||||
PC_BETWEEN
|
||||
PC_GT,
|
||||
PC_LT,
|
||||
PC_EQUAL,
|
||||
PC_BETWEEN
|
||||
} PC_FILTERTYPE;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* We need to hold a cached in-memory version of the format's
|
||||
* XML structure for speed, and this is it.
|
||||
*/
|
||||
* We need to hold a cached in-memory version of the format's
|
||||
* XML structure for speed, and this is it.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
char *name;
|
||||
char *description;
|
||||
uint32_t position;
|
||||
uint32_t size;
|
||||
uint32_t byteoffset;
|
||||
uint32_t interpretation;
|
||||
double scale;
|
||||
double offset;
|
||||
uint8_t active;
|
||||
char *name;
|
||||
char *description;
|
||||
uint32_t position;
|
||||
uint32_t size;
|
||||
uint32_t byteoffset;
|
||||
uint32_t interpretation;
|
||||
double scale;
|
||||
double offset;
|
||||
uint8_t active;
|
||||
} PCDIMENSION;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t pcid; /* Unique ID for schema */
|
||||
uint32_t ndims; /* How many dimensions does this schema have? */
|
||||
size_t size; /* How wide (bytes) is a point with this schema? */
|
||||
PCDIMENSION **dims; /* Array of dimension pointers */
|
||||
uint32_t srid; /* Foreign key reference to SPATIAL_REF_SYS */
|
||||
PCDIMENSION *xdim; /* pointer to the x dimension within dims */
|
||||
PCDIMENSION *ydim; /* pointer to the y dimension within dims */
|
||||
PCDIMENSION *zdim; /* pointer to the z dimension within dims */
|
||||
PCDIMENSION *mdim; /* pointer to the m dimension within dims */
|
||||
uint32_t compression; /* Compression type applied to the data */
|
||||
hashtable *namehash; /* Look-up from dimension name to pointer */
|
||||
uint32_t pcid; /* Unique ID for schema */
|
||||
uint32_t ndims; /* How many dimensions does this schema have? */
|
||||
size_t size; /* How wide (bytes) is a point with this schema? */
|
||||
PCDIMENSION **dims; /* Array of dimension pointers */
|
||||
uint32_t srid; /* Foreign key reference to SPATIAL_REF_SYS */
|
||||
PCDIMENSION *xdim; /* pointer to the x dimension within dims */
|
||||
PCDIMENSION *ydim; /* pointer to the y dimension within dims */
|
||||
PCDIMENSION *zdim; /* pointer to the z dimension within dims */
|
||||
PCDIMENSION *mdim; /* pointer to the m dimension within dims */
|
||||
uint32_t compression; /* Compression type applied to the data */
|
||||
hashtable *namehash; /* Look-up from dimension name to pointer */
|
||||
} PCSCHEMA;
|
||||
|
||||
/* Used for dimensional patch statistics */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t total_runs;
|
||||
uint32_t total_commonbits;
|
||||
uint32_t recommended_compression;
|
||||
uint32_t total_runs;
|
||||
uint32_t total_commonbits;
|
||||
uint32_t recommended_compression;
|
||||
} PCDIMSTAT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t ndims;
|
||||
uint32_t total_points;
|
||||
uint32_t total_patches;
|
||||
PCDIMSTAT *stats;
|
||||
int32_t ndims;
|
||||
uint32_t total_points;
|
||||
uint32_t total_patches;
|
||||
PCDIMSTAT *stats;
|
||||
} PCDIMSTATS;
|
||||
|
||||
/**
|
||||
* Uncompressed structure for in-memory handling
|
||||
* of points. A read-only PgSQL point can be wrapped in
|
||||
* one of these by pointing the data element at the
|
||||
* PgSQL memory and setting the capacity to 0
|
||||
* to indicate it is read-only.
|
||||
*/
|
||||
* Uncompressed structure for in-memory handling
|
||||
* of points. A read-only PgSQL point can be wrapped in
|
||||
* one of these by pointing the data element at the
|
||||
* PgSQL memory and setting the capacity to 0
|
||||
* to indicate it is read-only.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
int8_t readonly;
|
||||
const PCSCHEMA *schema;
|
||||
uint8_t *data; /* A serialized version of the data */
|
||||
int8_t readonly;
|
||||
const PCSCHEMA *schema;
|
||||
uint8_t *data; /* A serialized version of the data */
|
||||
} PCPOINT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *mem; /* An opaque memory buffer to be freed on destruction if not NULL */
|
||||
uint32_t npoints;
|
||||
uint32_t maxpoints;
|
||||
PCPOINT **points;
|
||||
void *mem; /* An opaque memory buffer to be freed on destruction if not NULL
|
||||
*/
|
||||
uint32_t npoints;
|
||||
uint32_t maxpoints;
|
||||
PCPOINT **points;
|
||||
} PCPOINTLIST;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t size;
|
||||
uint32_t npoints;
|
||||
uint32_t interpretation;
|
||||
uint32_t compression;
|
||||
uint32_t readonly;
|
||||
uint8_t *bytes;
|
||||
size_t size;
|
||||
uint32_t npoints;
|
||||
uint32_t interpretation;
|
||||
uint32_t compression;
|
||||
uint32_t readonly;
|
||||
uint8_t *bytes;
|
||||
} PCBYTES;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
double xmin;
|
||||
double xmax;
|
||||
double ymin;
|
||||
double ymax;
|
||||
double xmin;
|
||||
double xmax;
|
||||
double ymin;
|
||||
double ymax;
|
||||
} PCBOUNDS;
|
||||
|
||||
/* Used for generic patch statistics */
|
||||
typedef struct
|
||||
{
|
||||
PCPOINT min;
|
||||
PCPOINT max;
|
||||
PCPOINT avg;
|
||||
}
|
||||
PCSTATS;
|
||||
PCPOINT min;
|
||||
PCPOINT max;
|
||||
PCPOINT avg;
|
||||
} PCSTATS;
|
||||
|
||||
/**
|
||||
* Uncompressed Structure for in-memory handling
|
||||
* of patches. A read-only PgSQL patch can be wrapped in
|
||||
* one of these by pointing the data element at the
|
||||
* PgSQL memory and setting the capacity to 0
|
||||
* to indicate it is read-only.
|
||||
*/
|
||||
* Uncompressed Structure for in-memory handling
|
||||
* of patches. A read-only PgSQL patch can be wrapped in
|
||||
* one of these by pointing the data element at the
|
||||
* PgSQL memory and setting the capacity to 0
|
||||
* to indicate it is read-only.
|
||||
*/
|
||||
|
||||
#define PCPATCH_COMMON \
|
||||
int type; \
|
||||
int8_t readonly; \
|
||||
const PCSCHEMA *schema; \
|
||||
uint32_t npoints; \
|
||||
PCBOUNDS bounds; \
|
||||
PCSTATS *stats;
|
||||
#define PCPATCH_COMMON \
|
||||
int type; \
|
||||
int8_t readonly; \
|
||||
const PCSCHEMA *schema; \
|
||||
uint32_t npoints; \
|
||||
PCBOUNDS bounds; \
|
||||
PCSTATS *stats;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PCPATCH_COMMON
|
||||
PCPATCH_COMMON
|
||||
} PCPATCH;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PCPATCH_COMMON
|
||||
uint32_t maxpoints; /* How many points we can hold (or 0 for read-only) */
|
||||
size_t datasize;
|
||||
uint8_t *data; /* A serialized version of the data */
|
||||
PCPATCH_COMMON
|
||||
uint32_t maxpoints; /* How many points we can hold (or 0 for read-only) */
|
||||
size_t datasize;
|
||||
uint8_t *data; /* A serialized version of the data */
|
||||
} PCPATCH_UNCOMPRESSED;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PCPATCH_COMMON
|
||||
PCBYTES *bytes;
|
||||
PCPATCH_COMMON
|
||||
PCBYTES *bytes;
|
||||
} PCPATCH_DIMENSIONAL;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
PCPATCH_COMMON
|
||||
size_t lazperfsize;
|
||||
uint8_t *lazperf;
|
||||
PCPATCH_COMMON
|
||||
size_t lazperfsize;
|
||||
uint8_t *lazperf;
|
||||
} PCPATCH_LAZPERF;
|
||||
|
||||
|
||||
/* Global function signatures for memory/logging handlers. */
|
||||
typedef void* (*pc_allocator)(size_t size);
|
||||
typedef void* (*pc_reallocator)(void *mem, size_t size);
|
||||
typedef void (*pc_deallocator)(void *mem);
|
||||
typedef void (*pc_message_handler)(const char *string, va_list ap)
|
||||
__attribute__ (( format (printf, 1, 0) ));
|
||||
|
||||
|
||||
typedef void *(*pc_allocator)(size_t size);
|
||||
typedef void *(*pc_reallocator)(void *mem, size_t size);
|
||||
typedef void (*pc_deallocator)(void *mem);
|
||||
typedef void (*pc_message_handler)(const char *string, va_list ap)
|
||||
__attribute__((format(printf, 1, 0)));
|
||||
|
||||
/**********************************************************************
|
||||
* MEMORY MANAGEMENT
|
||||
*/
|
||||
* MEMORY MANAGEMENT
|
||||
*/
|
||||
|
||||
/** Allocate memory using the appropriate means (system/db) */
|
||||
void* pcalloc(size_t size);
|
||||
void *pcalloc(size_t size);
|
||||
/** Reallocate memory using the appropriate means (system/db) */
|
||||
void* pcrealloc(void* mem, size_t size);
|
||||
void *pcrealloc(void *mem, size_t size);
|
||||
/** Free memory using the appropriate means (system/db) */
|
||||
void pcfree(void* mem);
|
||||
void pcfree(void *mem);
|
||||
/** Emit an error message using the appropriate means (system/db) */
|
||||
void pcerror(const char *fmt, ...);
|
||||
void pcerror(const char *fmt, ...);
|
||||
/** Emit an info message using the appropriate means (system/db) */
|
||||
void pcinfo(const char *fmt, ...);
|
||||
void pcinfo(const char *fmt, ...);
|
||||
/** Emit a warning message using the appropriate means (system/db) */
|
||||
void pcwarn(const char *fmt, ...);
|
||||
void pcwarn(const char *fmt, ...);
|
||||
|
||||
/** Set custom memory allocators and messaging (used by PgSQL module) */
|
||||
void pc_set_handlers(
|
||||
pc_allocator allocator, pc_reallocator reallocator,
|
||||
pc_deallocator deallocator, pc_message_handler error_handler,
|
||||
pc_message_handler info_handler, pc_message_handler warning_handler
|
||||
);
|
||||
void pc_set_handlers(pc_allocator allocator, pc_reallocator reallocator,
|
||||
pc_deallocator deallocator,
|
||||
pc_message_handler error_handler,
|
||||
pc_message_handler info_handler,
|
||||
pc_message_handler warning_handler);
|
||||
|
||||
/** Set program to use system memory allocators and messaging */
|
||||
void pc_install_default_handlers(void);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* UTILITY
|
||||
*/
|
||||
* UTILITY
|
||||
*/
|
||||
|
||||
/** Convert binary to hex */
|
||||
uint8_t* pc_bytes_from_hexbytes(const char *hexbuf, size_t hexsize);
|
||||
uint8_t *pc_bytes_from_hexbytes(const char *hexbuf, size_t hexsize);
|
||||
/** Convert hex to binary */
|
||||
char* pc_hexbytes_from_bytes(const uint8_t *bytebuf, size_t bytesize);
|
||||
char *pc_hexbytes_from_bytes(const uint8_t *bytebuf, size_t bytesize);
|
||||
/** Read the the PCID from WKB form of a POINT/PATCH */
|
||||
uint32_t pc_wkb_get_pcid(const uint8_t *wkb);
|
||||
/** Build an empty #PCDIMSTATS based on the schema */
|
||||
PCDIMSTATS* pc_dimstats_make(const PCSCHEMA *schema);
|
||||
PCDIMSTATS *pc_dimstats_make(const PCSCHEMA *schema);
|
||||
/** Get compression name from enum */
|
||||
const char* pc_compression_name(int num);
|
||||
|
||||
|
||||
const char *pc_compression_name(int num);
|
||||
|
||||
/**********************************************************************
|
||||
* SCHEMAS
|
||||
*/
|
||||
* SCHEMAS
|
||||
*/
|
||||
|
||||
/** Release the memory in a schema structure */
|
||||
void pc_schema_free(PCSCHEMA *pcs);
|
||||
/** Build a schema structure from the XML serialisation */
|
||||
PCSCHEMA *pc_schema_from_xml(const char *xmlstr);
|
||||
/** Print out JSON readable format of schema */
|
||||
char* pc_schema_to_json(const PCSCHEMA *pcs);
|
||||
char *pc_schema_to_json(const PCSCHEMA *pcs);
|
||||
/** Extract dimension information by position */
|
||||
PCDIMENSION* pc_schema_get_dimension(const PCSCHEMA *s, uint32_t dim);
|
||||
PCDIMENSION *pc_schema_get_dimension(const PCSCHEMA *s, uint32_t dim);
|
||||
/** Extract dimension information by name */
|
||||
PCDIMENSION* pc_schema_get_dimension_by_name(const PCSCHEMA *s, const char *name);
|
||||
PCDIMENSION *pc_schema_get_dimension_by_name(const PCSCHEMA *s,
|
||||
const char *name);
|
||||
/** Check if the schema has all the information we need to work with data */
|
||||
uint32_t pc_schema_is_valid(const PCSCHEMA *s);
|
||||
/** Create a full copy of the schema and dimensions it contains */
|
||||
PCSCHEMA* pc_schema_clone(const PCSCHEMA *s);
|
||||
PCSCHEMA *pc_schema_clone(const PCSCHEMA *s);
|
||||
/** Add/overwrite a dimension in a schema */
|
||||
void pc_schema_set_dimension(PCSCHEMA *s, PCDIMENSION *d);
|
||||
/** Check/set the xyzm positions in the dimension list */
|
||||
@ -282,13 +275,12 @@ uint32_t pc_schema_same_dimensions(const PCSCHEMA *s1, const PCSCHEMA *s2);
|
||||
/** Check whether the schemas have compatible dimension interpretations */
|
||||
uint32_t pc_schema_same_interpretations(const PCSCHEMA *s1, const PCSCHEMA *s2);
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* PCPOINTLIST
|
||||
*/
|
||||
* PCPOINTLIST
|
||||
*/
|
||||
|
||||
/** Allocate a pointlist */
|
||||
PCPOINTLIST* pc_pointlist_make(uint32_t npoints);
|
||||
PCPOINTLIST *pc_pointlist_make(uint32_t npoints);
|
||||
|
||||
/** Free a pointlist, including the points contained therein */
|
||||
void pc_pointlist_free(PCPOINTLIST *pl);
|
||||
@ -297,34 +289,36 @@ void pc_pointlist_free(PCPOINTLIST *pl);
|
||||
void pc_pointlist_add_point(PCPOINTLIST *pl, PCPOINT *pt);
|
||||
|
||||
/** Get a point from the list */
|
||||
PCPOINT* pc_pointlist_get_point(const PCPOINTLIST *pl, int i);
|
||||
|
||||
PCPOINT *pc_pointlist_get_point(const PCPOINTLIST *pl, int i);
|
||||
|
||||
/**********************************************************************
|
||||
* PCPOINT
|
||||
*/
|
||||
* PCPOINT
|
||||
*/
|
||||
|
||||
/** Create a new PCPOINT */
|
||||
PCPOINT* pc_point_make(const PCSCHEMA *s);
|
||||
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);
|
||||
PCPOINT *pc_point_from_data(const PCSCHEMA *s, const uint8_t *data);
|
||||
|
||||
/** 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);
|
||||
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
|
||||
*
|
||||
* The number of elements in the array is equal to pt->schema->n_dims
|
||||
*/
|
||||
double* pc_point_to_double_array(const PCPOINT *pt);
|
||||
* Return an allocated double array of doubles representing point values
|
||||
*
|
||||
* The number of elements in the array is equal to pt->schema->n_dims
|
||||
*/
|
||||
double *pc_point_to_double_array(const PCPOINT *pt);
|
||||
|
||||
/** Frees the PTPOINT and data (if not readonly). Does not free referenced schema */
|
||||
/** Frees the PTPOINT and data (if not readonly). Does not free referenced
|
||||
* schema */
|
||||
void pc_point_free(PCPOINT *pt);
|
||||
|
||||
/** Get dimension value by dimension name */
|
||||
int pc_point_get_double_by_name(const PCPOINT *pt, const char *name, double *val);
|
||||
int pc_point_get_double_by_name(const PCPOINT *pt, const char *name,
|
||||
double *val);
|
||||
|
||||
/** Get dimension value by dimension index */
|
||||
int pc_point_get_double_by_index(const PCPOINT *pt, uint32_t idx, double *val);
|
||||
@ -366,47 +360,50 @@ int pc_point_set_z(PCPOINT *pt, double val);
|
||||
int pc_point_set_m(PCPOINT *pt, double val);
|
||||
|
||||
/** Create a new readwrite PCPOINT from a hex byte array */
|
||||
PCPOINT* pc_point_from_wkb(const PCSCHEMA *s, uint8_t *wkb, size_t wkbsize);
|
||||
PCPOINT *pc_point_from_wkb(const PCSCHEMA *s, uint8_t *wkb, size_t wkbsize);
|
||||
|
||||
/** Returns serialized form of point */
|
||||
uint8_t* pc_point_to_wkb(const PCPOINT *pt, size_t *wkbsize);
|
||||
uint8_t *pc_point_to_wkb(const PCPOINT *pt, size_t *wkbsize);
|
||||
|
||||
/** Returns text form of point */
|
||||
char* pc_point_to_string(const PCPOINT *pt);
|
||||
char *pc_point_to_string(const PCPOINT *pt);
|
||||
|
||||
/** Return the OGC WKB version of the point */
|
||||
uint8_t* pc_point_to_geometry_wkb(const PCPOINT *pt, size_t *wkbsize);
|
||||
uint8_t *pc_point_to_geometry_wkb(const PCPOINT *pt, size_t *wkbsize);
|
||||
|
||||
/**********************************************************************
|
||||
* PCPATCH
|
||||
*/
|
||||
* PCPATCH
|
||||
*/
|
||||
|
||||
/** Create new PCPATCH from a PCPOINT set. Copies data, doesn't take ownership of points */
|
||||
PCPATCH* pc_patch_from_pointlist(const PCPOINTLIST *ptl);
|
||||
/** Create new PCPATCH from a PCPOINT set. Copies data, doesn't take ownership
|
||||
* of points */
|
||||
PCPATCH *pc_patch_from_pointlist(const PCPOINTLIST *ptl);
|
||||
|
||||
/** Returns a list of points extracted from patch */
|
||||
PCPOINTLIST* pc_pointlist_from_patch(const PCPATCH *patch);
|
||||
PCPOINTLIST *pc_pointlist_from_patch(const PCPATCH *patch);
|
||||
|
||||
/** Merge a set of patches into a single patch */
|
||||
PCPATCH* pc_patch_from_patchlist(PCPATCH **palist, int numpatches);
|
||||
PCPATCH *pc_patch_from_patchlist(PCPATCH **palist, int numpatches);
|
||||
|
||||
/** Free patch memory, respecting read-only status. Does not free referenced schema */
|
||||
/** Free patch memory, respecting read-only status. Does not free referenced
|
||||
* schema */
|
||||
void pc_patch_free(PCPATCH *patch);
|
||||
|
||||
/** Create a compressed copy, using the compression schema referenced in the PCSCHEMA */
|
||||
PCPATCH* pc_patch_compress(const PCPATCH *patch, void *userdata);
|
||||
/** Create a compressed copy, using the compression schema referenced in the
|
||||
* PCSCHEMA */
|
||||
PCPATCH *pc_patch_compress(const PCPATCH *patch, void *userdata);
|
||||
|
||||
/** Create an uncompressed copy */
|
||||
PCPATCH * pc_patch_uncompress(const PCPATCH *patch);
|
||||
PCPATCH *pc_patch_uncompress(const PCPATCH *patch);
|
||||
|
||||
/** Create a new readwrite PCPOINT from a byte array */
|
||||
PCPATCH* pc_patch_from_wkb(const PCSCHEMA *s, uint8_t *wkb, size_t wkbsize);
|
||||
PCPATCH *pc_patch_from_wkb(const PCSCHEMA *s, uint8_t *wkb, size_t wkbsize);
|
||||
|
||||
/** Returns serialized form of point */
|
||||
uint8_t* pc_patch_to_wkb(const PCPATCH *patch, size_t *wkbsize);
|
||||
uint8_t *pc_patch_to_wkb(const PCPATCH *patch, size_t *wkbsize);
|
||||
|
||||
/** Returns text form of patch */
|
||||
char* pc_patch_to_string(const PCPATCH *patch);
|
||||
char *pc_patch_to_string(const PCPATCH *patch);
|
||||
|
||||
/** Return byte buffer size of serialization */
|
||||
size_t pc_patch_dimensional_serialized_size(const PCPATCH_DIMENSIONAL *patch);
|
||||
@ -418,13 +415,15 @@ size_t pc_bytes_serialized_size(const PCBYTES *pcb);
|
||||
int pc_bytes_serialize(const PCBYTES *pcb, uint8_t *buf, size_t *size);
|
||||
|
||||
/** Read a buffer up into a bytes structure */
|
||||
int pc_bytes_deserialize(const uint8_t *buf, const PCDIMENSION *dim, PCBYTES *pcb, int readonly, int flip_endian);
|
||||
int pc_bytes_deserialize(const uint8_t *buf, const PCDIMENSION *dim,
|
||||
PCBYTES *pcb, int readonly, int flip_endian);
|
||||
|
||||
/** Wrap serialized stats in a new stats objects */
|
||||
PCSTATS* pc_stats_new_from_data(const PCSCHEMA *schema, const uint8_t *mindata, const uint8_t *maxdata, const uint8_t *avgdata);
|
||||
PCSTATS *pc_stats_new_from_data(const PCSCHEMA *schema, const uint8_t *mindata,
|
||||
const uint8_t *maxdata, const uint8_t *avgdata);
|
||||
|
||||
/** Allocate a stats object */
|
||||
PCSTATS* pc_stats_new(const PCSCHEMA *schema);
|
||||
PCSTATS *pc_stats_new(const PCSCHEMA *schema);
|
||||
|
||||
/** Free a stats object */
|
||||
void pc_stats_free(PCSTATS *stats);
|
||||
@ -442,22 +441,29 @@ int pc_patch_compute_extent(PCPATCH *patch);
|
||||
int pc_bounds_intersects(const PCBOUNDS *b1, const PCBOUNDS *b2);
|
||||
|
||||
/** Returns OGC WKB of the bounding diagonal of XY bounds */
|
||||
uint8_t* pc_bounding_diagonal_wkb_from_bounds(const PCBOUNDS *bounds, const PCSCHEMA *schema, size_t *wkbsize);
|
||||
uint8_t *pc_bounding_diagonal_wkb_from_bounds(const PCBOUNDS *bounds,
|
||||
const PCSCHEMA *schema,
|
||||
size_t *wkbsize);
|
||||
|
||||
/** Returns OGC WKB of the bounding diagonal of XY, XYZ, XYM or XYZM bounds */
|
||||
uint8_t* pc_bounding_diagonal_wkb_from_stats(const PCSTATS *stats, size_t *wkbsize);
|
||||
uint8_t *pc_bounding_diagonal_wkb_from_stats(const PCSTATS *stats,
|
||||
size_t *wkbsize);
|
||||
|
||||
/** Subset batch based on less-than condition on dimension */
|
||||
PCPATCH* pc_patch_filter_lt_by_name(const PCPATCH *pa, const char *name, double val);
|
||||
PCPATCH *pc_patch_filter_lt_by_name(const PCPATCH *pa, const char *name,
|
||||
double val);
|
||||
|
||||
/** Subset batch based on greater-than condition on dimension */
|
||||
PCPATCH* pc_patch_filter_gt_by_name(const PCPATCH *pa, const char *name, double val);
|
||||
PCPATCH *pc_patch_filter_gt_by_name(const PCPATCH *pa, const char *name,
|
||||
double val);
|
||||
|
||||
/** Subset batch based on equality condition on dimension */
|
||||
PCPATCH* pc_patch_filter_equal_by_name(const PCPATCH *pa, const char *name, double val);
|
||||
PCPATCH *pc_patch_filter_equal_by_name(const PCPATCH *pa, const char *name,
|
||||
double val);
|
||||
|
||||
/** Subset batch based on range condition on dimension */
|
||||
PCPATCH* pc_patch_filter_between_by_name(const PCPATCH *pa, const char *name, double val1, double val2);
|
||||
PCPATCH *pc_patch_filter_between_by_name(const PCPATCH *pa, const char *name,
|
||||
double val1, double val2);
|
||||
|
||||
/** get point n */
|
||||
PCPOINT *pc_patch_pointn(const PCPATCH *patch, int n);
|
||||
@ -466,15 +472,18 @@ PCPOINT *pc_patch_pointn(const PCPATCH *patch, int n);
|
||||
PCPATCH *pc_patch_sort(const PCPATCH *pa, const char **name, int ndims);
|
||||
|
||||
/** True/false if the patch is sorted on dimension */
|
||||
uint32_t pc_patch_is_sorted(const PCPATCH *pa, const char **name, int ndims, char strict);
|
||||
uint32_t pc_patch_is_sorted(const PCPATCH *pa, const char **name, int ndims,
|
||||
char strict);
|
||||
|
||||
/** Subset batch based on index */
|
||||
PCPATCH* pc_patch_range(const PCPATCH *pa, int first, int count);
|
||||
PCPATCH *pc_patch_range(const PCPATCH *pa, int first, int count);
|
||||
|
||||
/** assign a schema to the patch */
|
||||
PCPATCH *pc_patch_set_schema(PCPATCH *patch, const PCSCHEMA *schema, double def);
|
||||
PCPATCH *pc_patch_set_schema(PCPATCH *patch, const PCSCHEMA *schema,
|
||||
double def);
|
||||
|
||||
/** transform the patch based on the passed schema */
|
||||
PCPATCH *pc_patch_transform(const PCPATCH *patch, const PCSCHEMA *schema, double def);
|
||||
PCPATCH *pc_patch_transform(const PCPATCH *patch, const PCSCHEMA *schema,
|
||||
double def);
|
||||
|
||||
#endif /* _PC_API_H */
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
/***********************************************************************
|
||||
* pc_api_internal.h
|
||||
*
|
||||
* Signatures we need to share within the library, but not for
|
||||
* use outside it.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
*
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
* Copyright (c) 2013 OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_api_internal.h
|
||||
*
|
||||
* Signatures we need to share within the library, but not for
|
||||
* use outside it.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
*
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
* Copyright (c) 2013 OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#ifndef _PC_API_INTERNAL_H
|
||||
#define _PC_API_INTERNAL_H
|
||||
@ -18,76 +18,79 @@
|
||||
#include "pc_api.h"
|
||||
|
||||
/**
|
||||
* Utility defines
|
||||
*/
|
||||
* Utility defines
|
||||
*/
|
||||
#define PC_TRUE 1
|
||||
#define PC_FALSE 0
|
||||
#define PC_SUCCESS 1
|
||||
#define PC_FAILURE 0
|
||||
|
||||
/**
|
||||
* How many compression types do we support?
|
||||
*/
|
||||
* How many compression types do we support?
|
||||
*/
|
||||
#define PCCOMPRESSIONTYPES 2
|
||||
|
||||
/**
|
||||
* Memory allocation for patch starts at 64 points
|
||||
*/
|
||||
* Memory allocation for patch starts at 64 points
|
||||
*/
|
||||
#define PCPATCH_DEFAULT_MAXPOINTS 64
|
||||
|
||||
/**
|
||||
* How many points to sample before considering
|
||||
* a PCDIMSTATS done?
|
||||
*/
|
||||
* How many points to sample before considering
|
||||
* a PCDIMSTATS done?
|
||||
*/
|
||||
#define PCDIMSTATS_MIN_SAMPLE 10000
|
||||
|
||||
/**
|
||||
* Interpretation types for our dimension descriptions
|
||||
*/
|
||||
* Interpretation types for our dimension descriptions
|
||||
*/
|
||||
#define NUM_INTERPRETATIONS 11
|
||||
|
||||
enum INTERPRETATIONS
|
||||
{
|
||||
PC_UNKNOWN = 0,
|
||||
PC_INT8 = 1, PC_UINT8 = 2,
|
||||
PC_INT16 = 3, PC_UINT16 = 4,
|
||||
PC_INT32 = 5, PC_UINT32 = 6,
|
||||
PC_INT64 = 7, PC_UINT64 = 8,
|
||||
PC_DOUBLE = 9, PC_FLOAT = 10
|
||||
PC_UNKNOWN = 0,
|
||||
PC_INT8 = 1,
|
||||
PC_UINT8 = 2,
|
||||
PC_INT16 = 3,
|
||||
PC_UINT16 = 4,
|
||||
PC_INT32 = 5,
|
||||
PC_UINT32 = 6,
|
||||
PC_INT64 = 7,
|
||||
PC_UINT64 = 8,
|
||||
PC_DOUBLE = 9,
|
||||
PC_FLOAT = 10
|
||||
};
|
||||
|
||||
enum DIMCOMPRESSIONS
|
||||
{
|
||||
PC_DIM_NONE = 0,
|
||||
PC_DIM_RLE = 1,
|
||||
PC_DIM_SIGBITS = 2,
|
||||
PC_DIM_ZLIB = 3
|
||||
PC_DIM_NONE = 0,
|
||||
PC_DIM_RLE = 1,
|
||||
PC_DIM_SIGBITS = 2,
|
||||
PC_DIM_ZLIB = 3
|
||||
};
|
||||
|
||||
/* PCDOUBLESTAT are members of PCDOUBLESTATS */
|
||||
typedef struct
|
||||
{
|
||||
double min;
|
||||
double max;
|
||||
double sum;
|
||||
double min;
|
||||
double max;
|
||||
double sum;
|
||||
} PCDOUBLESTAT;
|
||||
|
||||
/* PCDOUBLESTATS are internal to calculating stats in this module */
|
||||
typedef struct
|
||||
{
|
||||
uint32_t npoints;
|
||||
PCDOUBLESTAT *dims;
|
||||
uint32_t npoints;
|
||||
PCDOUBLESTAT *dims;
|
||||
} PCDOUBLESTATS;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint32_t nset;
|
||||
uint32_t npoints;
|
||||
uint8_t *map;
|
||||
uint32_t nset;
|
||||
uint32_t npoints;
|
||||
uint8_t *map;
|
||||
} PCBITMAP;
|
||||
|
||||
|
||||
/** What is the endianness of this system? */
|
||||
char machine_endian(void);
|
||||
|
||||
@ -116,7 +119,9 @@ uint8_t *wkb_set_uint32(uint8_t *wkb, uint32_t i);
|
||||
uint8_t *wkb_set_char(uint8_t *wkb, char c);
|
||||
|
||||
/** Force a byte array into the machine endianness */
|
||||
uint8_t* uncompressed_bytes_flip_endian(const uint8_t *bytebuf, const PCSCHEMA *schema, uint32_t npoints);
|
||||
uint8_t *uncompressed_bytes_flip_endian(const uint8_t *bytebuf,
|
||||
const PCSCHEMA *schema,
|
||||
uint32_t npoints);
|
||||
|
||||
/** Update a value using the scale/offset info from a dimension */
|
||||
double pc_value_scale_offset(double val, const PCDIMENSION *dim);
|
||||
@ -134,90 +139,109 @@ int pc_double_to_ptr(uint8_t *ptr, uint32_t interpretation, double val);
|
||||
size_t pc_interpretation_size(uint32_t interp);
|
||||
|
||||
/** Convert XML string token to type interpretation number */
|
||||
const char * pc_interpretation_string(uint32_t interp);
|
||||
const char *pc_interpretation_string(uint32_t interp);
|
||||
|
||||
/** Copy a string within the global memory management context */
|
||||
char* pcstrdup(const char *str);
|
||||
char *pcstrdup(const char *str);
|
||||
|
||||
/** Scales/offsets double, casts to appropriate dimension type, and writes into point */
|
||||
/** Scales/offsets double, casts to appropriate dimension type, and writes into
|
||||
* point */
|
||||
int pc_point_set_double_by_index(PCPOINT *pt, uint32_t idx, double val);
|
||||
|
||||
/** Scales/offsets double, casts to appropriate dimension type, and writes into point */
|
||||
/** Scales/offsets double, casts to appropriate dimension type, and writes into
|
||||
* point */
|
||||
int pc_point_set_double_by_name(PCPOINT *pt, const char *name, double val);
|
||||
|
||||
/** Scales/offsets double, casts to appropriate dimension type, and writes into point */
|
||||
/** Scales/offsets double, casts to appropriate dimension type, and writes into
|
||||
* point */
|
||||
int pc_point_set_double(PCPOINT *pt, const PCDIMENSION *dim, double val);
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* DIMENSION STATISTICS
|
||||
*/
|
||||
* DIMENSION STATISTICS
|
||||
*/
|
||||
|
||||
/** Analyze the bytes in the #PCPATCH_DIMENSIONAL and update the #PCDIMSTATS */
|
||||
int pc_dimstats_update(PCDIMSTATS *pds, const PCPATCH_DIMENSIONAL *pdl);
|
||||
/** Free the PCDIMSTATS memory */
|
||||
void pc_dimstats_free(PCDIMSTATS *pds);
|
||||
char* pc_dimstats_to_string(const PCDIMSTATS *pds);
|
||||
|
||||
char *pc_dimstats_to_string(const PCDIMSTATS *pds);
|
||||
|
||||
/****************************************************************************
|
||||
* PATCHES
|
||||
*/
|
||||
* PATCHES
|
||||
*/
|
||||
|
||||
/** Returns newly allocated patch that only contains the points fitting the filter condition */
|
||||
PCPATCH* pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2);
|
||||
/** Returns newly allocated patch that only contains the points fitting the
|
||||
* filter condition */
|
||||
PCPATCH *pc_patch_filter(const PCPATCH *pa, uint32_t dimnum,
|
||||
PC_FILTERTYPE filter, double val1, double val2);
|
||||
void pc_patch_free_stats(PCPATCH *pa);
|
||||
|
||||
/* DIMENSIONAL PATCHES */
|
||||
char* pc_patch_dimensional_to_string(const PCPATCH_DIMENSIONAL *pa);
|
||||
PCPATCH_DIMENSIONAL* pc_patch_dimensional_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa);
|
||||
PCPATCH_DIMENSIONAL* pc_patch_dimensional_compress(const PCPATCH_DIMENSIONAL *pdl, PCDIMSTATS *pds);
|
||||
PCPATCH_DIMENSIONAL* pc_patch_dimensional_decompress(const PCPATCH_DIMENSIONAL *pdl);
|
||||
char *pc_patch_dimensional_to_string(const PCPATCH_DIMENSIONAL *pa);
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa);
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_compress(const PCPATCH_DIMENSIONAL *pdl, PCDIMSTATS *pds);
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_decompress(const PCPATCH_DIMENSIONAL *pdl);
|
||||
void pc_patch_dimensional_free(PCPATCH_DIMENSIONAL *pdl);
|
||||
int pc_patch_dimensional_compute_extent(PCPATCH_DIMENSIONAL *pdl);
|
||||
uint8_t* pc_patch_dimensional_to_wkb(const PCPATCH_DIMENSIONAL *patch, size_t *wkbsize);
|
||||
PCPATCH* pc_patch_dimensional_from_wkb(const PCSCHEMA *schema, const uint8_t *wkb, size_t wkbsize);
|
||||
PCPATCH_DIMENSIONAL* pc_patch_dimensional_from_pointlist(const PCPOINTLIST *pdl);
|
||||
PCPOINTLIST* pc_pointlist_from_dimensional(const PCPATCH_DIMENSIONAL *pdl);
|
||||
PCPATCH_DIMENSIONAL* pc_patch_dimensional_clone(const PCPATCH_DIMENSIONAL *patch);
|
||||
uint8_t *pc_patch_dimensional_to_wkb(const PCPATCH_DIMENSIONAL *patch,
|
||||
size_t *wkbsize);
|
||||
PCPATCH *pc_patch_dimensional_from_wkb(const PCSCHEMA *schema,
|
||||
const uint8_t *wkb, size_t wkbsize);
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_from_pointlist(const PCPOINTLIST *pdl);
|
||||
PCPOINTLIST *pc_pointlist_from_dimensional(const PCPATCH_DIMENSIONAL *pdl);
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_clone(const PCPATCH_DIMENSIONAL *patch);
|
||||
PCPOINT *pc_patch_dimensional_pointn(const PCPATCH_DIMENSIONAL *pdl, int n);
|
||||
|
||||
/* UNCOMPRESSED PATCHES */
|
||||
char* pc_patch_uncompressed_to_string(const PCPATCH_UNCOMPRESSED *patch);
|
||||
uint8_t* pc_patch_uncompressed_to_wkb(const PCPATCH_UNCOMPRESSED *patch, size_t *wkbsize);
|
||||
PCPATCH* pc_patch_uncompressed_from_wkb(const PCSCHEMA *s, const uint8_t *wkb, size_t wkbsize);
|
||||
PCPATCH_UNCOMPRESSED* pc_patch_uncompressed_make(const PCSCHEMA *s, uint32_t maxpoints);
|
||||
char *pc_patch_uncompressed_to_string(const PCPATCH_UNCOMPRESSED *patch);
|
||||
uint8_t *pc_patch_uncompressed_to_wkb(const PCPATCH_UNCOMPRESSED *patch,
|
||||
size_t *wkbsize);
|
||||
PCPATCH *pc_patch_uncompressed_from_wkb(const PCSCHEMA *s, const uint8_t *wkb,
|
||||
size_t wkbsize);
|
||||
PCPATCH_UNCOMPRESSED *pc_patch_uncompressed_make(const PCSCHEMA *s,
|
||||
uint32_t maxpoints);
|
||||
int pc_patch_uncompressed_compute_extent(PCPATCH_UNCOMPRESSED *patch);
|
||||
int pc_patch_uncompressed_compute_stats(PCPATCH_UNCOMPRESSED *patch);
|
||||
void pc_patch_uncompressed_free(PCPATCH_UNCOMPRESSED *patch);
|
||||
uint8_t *pc_patch_uncompressed_readonly(PCPATCH_UNCOMPRESSED *patch);
|
||||
PCPOINTLIST* pc_pointlist_from_uncompressed(const PCPATCH_UNCOMPRESSED *patch);
|
||||
PCPATCH_UNCOMPRESSED* pc_patch_uncompressed_from_pointlist(const PCPOINTLIST *pl);
|
||||
PCPATCH_UNCOMPRESSED* pc_patch_uncompressed_from_dimensional(const PCPATCH_DIMENSIONAL *pdl);
|
||||
PCPOINTLIST *pc_pointlist_from_uncompressed(const PCPATCH_UNCOMPRESSED *patch);
|
||||
PCPATCH_UNCOMPRESSED *
|
||||
pc_patch_uncompressed_from_pointlist(const PCPOINTLIST *pl);
|
||||
PCPATCH_UNCOMPRESSED *
|
||||
pc_patch_uncompressed_from_dimensional(const PCPATCH_DIMENSIONAL *pdl);
|
||||
int pc_patch_uncompressed_add_point(PCPATCH_UNCOMPRESSED *c, const PCPOINT *p);
|
||||
PCPOINT *pc_patch_uncompressed_pointn(const PCPATCH_UNCOMPRESSED *patch, int n);
|
||||
|
||||
/* LAZPERF PATCHES */
|
||||
PCPATCH_LAZPERF* pc_patch_lazperf_from_pointlist(const PCPOINTLIST *pl);
|
||||
PCPATCH_LAZPERF* pc_patch_lazperf_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa);
|
||||
PCPOINTLIST* pc_pointlist_from_lazperf(const PCPATCH_LAZPERF *palaz);
|
||||
PCPATCH_UNCOMPRESSED* pc_patch_uncompressed_from_lazperf(const PCPATCH_LAZPERF *palaz);
|
||||
PCPATCH_LAZPERF *pc_patch_lazperf_from_pointlist(const PCPOINTLIST *pl);
|
||||
PCPATCH_LAZPERF *
|
||||
pc_patch_lazperf_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa);
|
||||
PCPOINTLIST *pc_pointlist_from_lazperf(const PCPATCH_LAZPERF *palaz);
|
||||
PCPATCH_UNCOMPRESSED *
|
||||
pc_patch_uncompressed_from_lazperf(const PCPATCH_LAZPERF *palaz);
|
||||
int pc_patch_lazperf_compute_extent(PCPATCH_LAZPERF *patch);
|
||||
char* pc_patch_lazperf_to_string(const PCPATCH_LAZPERF *pa);
|
||||
char *pc_patch_lazperf_to_string(const PCPATCH_LAZPERF *pa);
|
||||
void pc_patch_lazperf_free(PCPATCH_LAZPERF *palaz);
|
||||
uint8_t* pc_patch_lazperf_to_wkb(const PCPATCH_LAZPERF *patch, size_t *wkbsize);
|
||||
PCPATCH* pc_patch_lazperf_from_wkb(const PCSCHEMA *schema, const uint8_t *wkb, size_t wkbsize);
|
||||
uint8_t *pc_patch_lazperf_to_wkb(const PCPATCH_LAZPERF *patch, size_t *wkbsize);
|
||||
PCPATCH *pc_patch_lazperf_from_wkb(const PCSCHEMA *schema, const uint8_t *wkb,
|
||||
size_t wkbsize);
|
||||
PCPOINT *pc_patch_lazperf_pointn(const PCPATCH_LAZPERF *patch, int n);
|
||||
|
||||
/****************************************************************************
|
||||
* BYTES
|
||||
*/
|
||||
* BYTES
|
||||
*/
|
||||
|
||||
/** Construct empty byte array (zero out attribute and allocate byte buffer) */
|
||||
PCBYTES pc_bytes_make(const PCDIMENSION *dim, uint32_t npoints);
|
||||
/** Empty the byte array (free the byte buffer) */
|
||||
void pc_bytes_free(PCBYTES bytes);
|
||||
/** Apply the compresstion to the byte array in place, freeing the original byte buffer */
|
||||
/** Apply the compresstion to the byte array in place, freeing the original byte
|
||||
* buffer */
|
||||
PCBYTES pc_bytes_encode(PCBYTES pcb, int compression);
|
||||
/** Convert the bytes in #PCBYTES to PC_DIM_NONE compression */
|
||||
PCBYTES pc_bytes_decode(PCBYTES epcb);
|
||||
@ -239,19 +263,25 @@ PCBYTES pc_bytes_zlib_decode(const PCBYTES pcb);
|
||||
uint32_t pc_bytes_run_count(const PCBYTES *pcb);
|
||||
/** How many bits are shared by all elements of this array? */
|
||||
uint32_t pc_bytes_sigbits_count(const PCBYTES *pcb);
|
||||
/** Using an 8-bit word, what is the common word and number of bits in common? */
|
||||
uint8_t pc_bytes_sigbits_count_8 (const PCBYTES *pcb, uint32_t *nsigbits);
|
||||
/** Using an 16-bit word, what is the common word and number of bits in common? */
|
||||
/** Using an 8-bit word, what is the common word and number of bits in common?
|
||||
*/
|
||||
uint8_t pc_bytes_sigbits_count_8(const PCBYTES *pcb, uint32_t *nsigbits);
|
||||
/** Using an 16-bit word, what is the common word and number of bits in common?
|
||||
*/
|
||||
uint16_t pc_bytes_sigbits_count_16(const PCBYTES *pcb, uint32_t *nsigbits);
|
||||
/** Using an 32-bit word, what is the common word and number of bits in common? */
|
||||
/** Using an 32-bit word, what is the common word and number of bits in common?
|
||||
*/
|
||||
uint32_t pc_bytes_sigbits_count_32(const PCBYTES *pcb, uint32_t *nsigbits);
|
||||
/** Using an 64-bit word, what is the common word and number of bits in common? */
|
||||
/** Using an 64-bit word, what is the common word and number of bits in common?
|
||||
*/
|
||||
uint64_t pc_bytes_sigbits_count_64(const PCBYTES *pcb, uint32_t *nsigbits);
|
||||
|
||||
/* NOTE: stats are gathered without applying scale and offset */
|
||||
PCBYTES pc_bytes_filter(const PCBYTES *pcb, const PCBITMAP *map, PCDOUBLESTAT *stats);
|
||||
PCBYTES pc_bytes_filter(const PCBYTES *pcb, const PCBITMAP *map,
|
||||
PCDOUBLESTAT *stats);
|
||||
|
||||
PCBITMAP* pc_bytes_bitmap(const PCBYTES *pcb, PC_FILTERTYPE filter, double val1, double val2);
|
||||
PCBITMAP *pc_bytes_bitmap(const PCBYTES *pcb, PC_FILTERTYPE filter, double val1,
|
||||
double val2);
|
||||
int pc_bytes_minmax(const PCBYTES *pcb, double *min, double *max, double *avg);
|
||||
|
||||
/** getting the n-th point out of a PCBYTE into a buffer */
|
||||
@ -263,30 +293,29 @@ void pc_bytes_zlib_to_ptr(uint8_t *buf, PCBYTES pcb, int n);
|
||||
void pc_bytes_to_ptr(uint8_t *buf, PCBYTES pcb, int n);
|
||||
|
||||
/****************************************************************************
|
||||
* BOUNDS
|
||||
*/
|
||||
* BOUNDS
|
||||
*/
|
||||
|
||||
/** Initialize with very large mins and very small maxes */
|
||||
void pc_bounds_init(PCBOUNDS *b);
|
||||
/** Copy a bounds */
|
||||
PCSTATS* pc_stats_clone(const PCSTATS *stats);
|
||||
PCSTATS *pc_stats_clone(const PCSTATS *stats);
|
||||
/** Expand extents of b1 to encompass b2 */
|
||||
void pc_bounds_merge(PCBOUNDS *b1, const PCBOUNDS *b2);
|
||||
|
||||
/****************************************************************************
|
||||
* BITMAPS
|
||||
*/
|
||||
* BITMAPS
|
||||
*/
|
||||
|
||||
/** Allocate new unset bitmap */
|
||||
PCBITMAP* pc_bitmap_new(uint32_t npoints);
|
||||
PCBITMAP *pc_bitmap_new(uint32_t npoints);
|
||||
/** Deallocate bitmap */
|
||||
void pc_bitmap_free(PCBITMAP *map);
|
||||
/** Set indicated bit on bitmap if filter and value are consistent */
|
||||
void pc_bitmap_filter(PCBITMAP *map, PC_FILTERTYPE filter, int i, double d, double val1, double val2);
|
||||
void pc_bitmap_filter(PCBITMAP *map, PC_FILTERTYPE filter, int i, double d,
|
||||
double val1, double val2);
|
||||
|
||||
/** Read indicated bit of bitmap */
|
||||
#define pc_bitmap_get(map, i) ((map)->map[(i)])
|
||||
|
||||
|
||||
|
||||
#endif /* _PC_API_INTERNAL_H */
|
||||
|
||||
3131
lib/pc_bytes.c
3131
lib/pc_bytes.c
File diff suppressed because it is too large
Load Diff
@ -1,142 +1,136 @@
|
||||
/***********************************************************************
|
||||
* pc_dimstats.c
|
||||
*
|
||||
* Support for "dimensional compression", which is a catch-all
|
||||
* term for applying compression separately on each dimension
|
||||
* of a PCPATCH collection of PCPOINTS.
|
||||
*
|
||||
* Depending on the character of the data, one of these schemes
|
||||
* will be used:
|
||||
*
|
||||
* - run-length encoding
|
||||
* - significant-bit removal
|
||||
* - deflate
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_dimstats.c
|
||||
*
|
||||
* Support for "dimensional compression", which is a catch-all
|
||||
* term for applying compression separately on each dimension
|
||||
* of a PCPATCH collection of PCPOINTS.
|
||||
*
|
||||
* Depending on the character of the data, one of these schemes
|
||||
* will be used:
|
||||
*
|
||||
* - run-length encoding
|
||||
* - significant-bit removal
|
||||
* - deflate
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <assert.h>
|
||||
#include "pc_api_internal.h"
|
||||
#include "stringbuffer.h"
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
|
||||
PCDIMSTATS *
|
||||
pc_dimstats_make(const PCSCHEMA *schema)
|
||||
PCDIMSTATS *pc_dimstats_make(const PCSCHEMA *schema)
|
||||
{
|
||||
PCDIMSTATS *pds;
|
||||
pds = pcalloc(sizeof(PCDIMSTATS));
|
||||
pds->ndims = schema->ndims;
|
||||
pds->stats = pcalloc(pds->ndims * sizeof(PCDIMSTAT));
|
||||
return pds;
|
||||
PCDIMSTATS *pds;
|
||||
pds = pcalloc(sizeof(PCDIMSTATS));
|
||||
pds->ndims = schema->ndims;
|
||||
pds->stats = pcalloc(pds->ndims * sizeof(PCDIMSTAT));
|
||||
return pds;
|
||||
}
|
||||
|
||||
void
|
||||
pc_dimstats_free(PCDIMSTATS *pds)
|
||||
void pc_dimstats_free(PCDIMSTATS *pds)
|
||||
{
|
||||
if ( pds->stats )
|
||||
pcfree(pds->stats);
|
||||
pcfree(pds);
|
||||
if (pds->stats)
|
||||
pcfree(pds->stats);
|
||||
pcfree(pds);
|
||||
}
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
uint32_t total_runs;
|
||||
uint32_t total_commonbits;
|
||||
uint32_t recommended_compression;
|
||||
uint32_t total_runs;
|
||||
uint32_t total_commonbits;
|
||||
uint32_t recommended_compression;
|
||||
} PCDIMSTAT;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int32_t ndims;
|
||||
uint32_t total_points;
|
||||
uint32_t total_patches;
|
||||
PCDIMSTAT *stats;
|
||||
int32_t ndims;
|
||||
uint32_t total_points;
|
||||
uint32_t total_patches;
|
||||
PCDIMSTAT *stats;
|
||||
} PCDIMSTATS;
|
||||
*/
|
||||
|
||||
char *
|
||||
pc_dimstats_to_string(const PCDIMSTATS *pds)
|
||||
char *pc_dimstats_to_string(const PCDIMSTATS *pds)
|
||||
{
|
||||
int i;
|
||||
stringbuffer_t *sb = stringbuffer_create();
|
||||
char *str;
|
||||
int i;
|
||||
stringbuffer_t *sb = stringbuffer_create();
|
||||
char *str;
|
||||
|
||||
stringbuffer_aprintf(sb,
|
||||
"{\"ndims\":%d,\"total_points\":%d,\"total_patches\":%d,\"dims\":[",
|
||||
pds->ndims,
|
||||
pds->total_points,
|
||||
pds->total_patches
|
||||
);
|
||||
stringbuffer_aprintf(
|
||||
sb, "{\"ndims\":%d,\"total_points\":%d,\"total_patches\":%d,\"dims\":[",
|
||||
pds->ndims, pds->total_points, pds->total_patches);
|
||||
|
||||
for ( i = 0; i < pds->ndims; i++ )
|
||||
{
|
||||
if ( i ) stringbuffer_append(sb, ",");
|
||||
stringbuffer_aprintf(sb,
|
||||
"{\"total_runs\":%d,\"total_commonbits\":%d,\"recommended_compression\":%d}",
|
||||
pds->stats[i].total_runs,
|
||||
pds->stats[i].total_commonbits,
|
||||
pds->stats[i].recommended_compression
|
||||
);
|
||||
}
|
||||
stringbuffer_append(sb, "]}");
|
||||
for (i = 0; i < pds->ndims; i++)
|
||||
{
|
||||
if (i)
|
||||
stringbuffer_append(sb, ",");
|
||||
stringbuffer_aprintf(sb,
|
||||
"{\"total_runs\":%d,\"total_commonbits\":%d,"
|
||||
"\"recommended_compression\":%d}",
|
||||
pds->stats[i].total_runs,
|
||||
pds->stats[i].total_commonbits,
|
||||
pds->stats[i].recommended_compression);
|
||||
}
|
||||
stringbuffer_append(sb, "]}");
|
||||
|
||||
str = stringbuffer_getstringcopy(sb);
|
||||
stringbuffer_destroy(sb);
|
||||
return str;
|
||||
str = stringbuffer_getstringcopy(sb);
|
||||
stringbuffer_destroy(sb);
|
||||
return str;
|
||||
}
|
||||
|
||||
int
|
||||
pc_dimstats_update(PCDIMSTATS *pds, const PCPATCH_DIMENSIONAL *pdl)
|
||||
int pc_dimstats_update(PCDIMSTATS *pds, const PCPATCH_DIMENSIONAL *pdl)
|
||||
{
|
||||
int i;
|
||||
const PCSCHEMA *schema = pdl->schema;
|
||||
int i;
|
||||
const PCSCHEMA *schema = pdl->schema;
|
||||
|
||||
/* Update global stats */
|
||||
pds->total_points += pdl->npoints;
|
||||
pds->total_patches += 1;
|
||||
/* Update global stats */
|
||||
pds->total_points += pdl->npoints;
|
||||
pds->total_patches += 1;
|
||||
|
||||
/* Update dimensional stats */
|
||||
for ( i = 0; i < pds->ndims; i++ )
|
||||
{
|
||||
PCBYTES pcb = pdl->bytes[i];
|
||||
pds->stats[i].total_runs += pc_bytes_run_count(&pcb);
|
||||
pds->stats[i].total_commonbits += pc_bytes_sigbits_count(&pcb);
|
||||
}
|
||||
/* Update dimensional stats */
|
||||
for (i = 0; i < pds->ndims; i++)
|
||||
{
|
||||
PCBYTES pcb = pdl->bytes[i];
|
||||
pds->stats[i].total_runs += pc_bytes_run_count(&pcb);
|
||||
pds->stats[i].total_commonbits += pc_bytes_sigbits_count(&pcb);
|
||||
}
|
||||
|
||||
/* Update recommended compression schema */
|
||||
for ( i = 0; i < pds->ndims; i++ )
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(schema, i);
|
||||
/* Uncompressed size, foreach point, one value entry */
|
||||
double raw_size = pds->total_points * dim->size;
|
||||
/* RLE size, for each run, one count byte and one value entry */
|
||||
double rle_size = pds->stats[i].total_runs * (dim->size + 1);
|
||||
/* Sigbits size, for each patch, one header and n bits for each entry */
|
||||
double avg_commonbits_per_patch = pds->stats[i].total_commonbits / pds->total_patches;
|
||||
double avg_uniquebits_per_patch = 8*dim->size - avg_commonbits_per_patch;
|
||||
double sigbits_size = pds->total_patches * 2 * dim->size + pds->total_points * avg_uniquebits_per_patch / 8;
|
||||
/* Default to ZLib */
|
||||
pds->stats[i].recommended_compression = PC_DIM_ZLIB;
|
||||
/* Only use rle and sigbits compression on integer values */
|
||||
/* If we can do better than 4:1 we might beat zlib */
|
||||
if ( dim->interpretation != PC_DOUBLE )
|
||||
{
|
||||
/* If sigbits is better than 4:1, use that */
|
||||
if ( raw_size/sigbits_size > 1.6 )
|
||||
{
|
||||
pds->stats[i].recommended_compression = PC_DIM_SIGBITS;
|
||||
}
|
||||
/* If RLE size is even better, use that. */
|
||||
if ( raw_size/rle_size > 4.0 )
|
||||
{
|
||||
pds->stats[i].recommended_compression = PC_DIM_RLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PC_SUCCESS;
|
||||
/* Update recommended compression schema */
|
||||
for (i = 0; i < pds->ndims; i++)
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(schema, i);
|
||||
/* Uncompressed size, foreach point, one value entry */
|
||||
double raw_size = pds->total_points * dim->size;
|
||||
/* RLE size, for each run, one count byte and one value entry */
|
||||
double rle_size = pds->stats[i].total_runs * (dim->size + 1);
|
||||
/* Sigbits size, for each patch, one header and n bits for each entry */
|
||||
double avg_commonbits_per_patch =
|
||||
pds->stats[i].total_commonbits / pds->total_patches;
|
||||
double avg_uniquebits_per_patch = 8 * dim->size - avg_commonbits_per_patch;
|
||||
double sigbits_size = pds->total_patches * 2 * dim->size +
|
||||
pds->total_points * avg_uniquebits_per_patch / 8;
|
||||
/* Default to ZLib */
|
||||
pds->stats[i].recommended_compression = PC_DIM_ZLIB;
|
||||
/* Only use rle and sigbits compression on integer values */
|
||||
/* If we can do better than 4:1 we might beat zlib */
|
||||
if (dim->interpretation != PC_DOUBLE)
|
||||
{
|
||||
/* If sigbits is better than 4:1, use that */
|
||||
if (raw_size / sigbits_size > 1.6)
|
||||
{
|
||||
pds->stats[i].recommended_compression = PC_DIM_SIGBITS;
|
||||
}
|
||||
/* If RLE size is even better, use that. */
|
||||
if (raw_size / rle_size > 4.0)
|
||||
{
|
||||
pds->stats[i].recommended_compression = PC_DIM_RLE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return PC_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
554
lib/pc_filter.c
554
lib/pc_filter.c
@ -1,346 +1,364 @@
|
||||
/***********************************************************************
|
||||
* pc_filter.c
|
||||
*
|
||||
* Pointclound patch filtering.
|
||||
*
|
||||
* Copyright (c) 2013 OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_filter.c
|
||||
*
|
||||
* Pointclound patch filtering.
|
||||
*
|
||||
* Copyright (c) 2013 OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "pc_api_internal.h"
|
||||
#include <assert.h>
|
||||
#include <float.h>
|
||||
|
||||
|
||||
PCBITMAP *
|
||||
pc_bitmap_new(uint32_t npoints)
|
||||
PCBITMAP *pc_bitmap_new(uint32_t npoints)
|
||||
{
|
||||
PCBITMAP *map = pcalloc(sizeof(PCBITMAP));
|
||||
map->map = pcalloc(sizeof(uint8_t)*npoints);
|
||||
map->npoints = npoints;
|
||||
map->nset = 0;
|
||||
return map;
|
||||
PCBITMAP *map = pcalloc(sizeof(PCBITMAP));
|
||||
map->map = pcalloc(sizeof(uint8_t) * npoints);
|
||||
map->npoints = npoints;
|
||||
map->nset = 0;
|
||||
return map;
|
||||
}
|
||||
|
||||
void
|
||||
pc_bitmap_free(PCBITMAP *map)
|
||||
void pc_bitmap_free(PCBITMAP *map)
|
||||
{
|
||||
if (map->map) pcfree(map->map);
|
||||
pcfree(map);
|
||||
if (map->map)
|
||||
pcfree(map->map);
|
||||
pcfree(map);
|
||||
}
|
||||
|
||||
static inline void
|
||||
pc_bitmap_set(PCBITMAP *map, int i, int val)
|
||||
static inline void pc_bitmap_set(PCBITMAP *map, int i, int val)
|
||||
{
|
||||
uint8_t curval = map->map[i];
|
||||
if ( val && (!curval) )
|
||||
map->nset++;
|
||||
if ( (!val) && curval )
|
||||
map->nset--;
|
||||
uint8_t curval = map->map[i];
|
||||
if (val && (!curval))
|
||||
map->nset++;
|
||||
if ((!val) && curval)
|
||||
map->nset--;
|
||||
|
||||
map->map[i] = (val!=0);
|
||||
map->map[i] = (val != 0);
|
||||
}
|
||||
|
||||
void
|
||||
pc_bitmap_filter(PCBITMAP *map, PC_FILTERTYPE filter, int i, double d, double val1, double val2)
|
||||
void pc_bitmap_filter(PCBITMAP *map, PC_FILTERTYPE filter, int i, double d,
|
||||
double val1, double val2)
|
||||
{
|
||||
switch ( filter )
|
||||
{
|
||||
case PC_GT:
|
||||
pc_bitmap_set(map, i, (d > val1 ? 1 : 0));
|
||||
break;
|
||||
case PC_LT:
|
||||
pc_bitmap_set(map, i, (d < val1 ? 1 : 0));
|
||||
break;
|
||||
case PC_EQUAL:
|
||||
pc_bitmap_set(map, i, (d == val1 ? 1 : 0));
|
||||
break;
|
||||
case PC_BETWEEN:
|
||||
pc_bitmap_set(map, i, (d > val1 && d < val2 ? 1 : 0));
|
||||
break;
|
||||
}
|
||||
switch (filter)
|
||||
{
|
||||
case PC_GT:
|
||||
pc_bitmap_set(map, i, (d > val1 ? 1 : 0));
|
||||
break;
|
||||
case PC_LT:
|
||||
pc_bitmap_set(map, i, (d < val1 ? 1 : 0));
|
||||
break;
|
||||
case PC_EQUAL:
|
||||
pc_bitmap_set(map, i, (d == val1 ? 1 : 0));
|
||||
break;
|
||||
case PC_BETWEEN:
|
||||
pc_bitmap_set(map, i, (d > val1 && d < val2 ? 1 : 0));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static PCBITMAP *
|
||||
pc_patch_uncompressed_bitmap(const PCPATCH_UNCOMPRESSED *pa, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2)
|
||||
static PCBITMAP *pc_patch_uncompressed_bitmap(const PCPATCH_UNCOMPRESSED *pa,
|
||||
uint32_t dimnum,
|
||||
PC_FILTERTYPE filter, double val1,
|
||||
double val2)
|
||||
{
|
||||
PCPOINT pt;
|
||||
uint32_t i = 0;
|
||||
uint8_t *buf = pa->data;
|
||||
double d;
|
||||
size_t sz = pa->schema->size;
|
||||
PCBITMAP *map = pc_bitmap_new(pa->npoints);
|
||||
PCPOINT pt;
|
||||
uint32_t i = 0;
|
||||
uint8_t *buf = pa->data;
|
||||
double d;
|
||||
size_t sz = pa->schema->size;
|
||||
PCBITMAP *map = pc_bitmap_new(pa->npoints);
|
||||
|
||||
pt.readonly = PC_TRUE;
|
||||
pt.schema = pa->schema;
|
||||
pt.readonly = PC_TRUE;
|
||||
pt.schema = pa->schema;
|
||||
|
||||
while ( i < pa->npoints )
|
||||
{
|
||||
pt.data = buf;
|
||||
pc_point_get_double(&pt, pa->schema->dims[dimnum], &d);
|
||||
/* Apply the filter to the bitmap */
|
||||
pc_bitmap_filter(map, filter, i, d, val1, val2);
|
||||
/* Advance data pointer and counter */
|
||||
buf += sz;
|
||||
i++;
|
||||
}
|
||||
while (i < pa->npoints)
|
||||
{
|
||||
pt.data = buf;
|
||||
pc_point_get_double(&pt, pa->schema->dims[dimnum], &d);
|
||||
/* Apply the filter to the bitmap */
|
||||
pc_bitmap_filter(map, filter, i, d, val1, val2);
|
||||
/* Advance data pointer and counter */
|
||||
buf += sz;
|
||||
i++;
|
||||
}
|
||||
|
||||
return map;
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
static PCPATCH_UNCOMPRESSED *
|
||||
pc_patch_uncompressed_filter(const PCPATCH_UNCOMPRESSED *pu, const PCBITMAP *map)
|
||||
pc_patch_uncompressed_filter(const PCPATCH_UNCOMPRESSED *pu,
|
||||
const PCBITMAP *map)
|
||||
{
|
||||
int i = 0;
|
||||
size_t sz = pu->schema->size;
|
||||
PCPATCH_UNCOMPRESSED *fpu = pc_patch_uncompressed_make(pu->schema, map->nset);
|
||||
uint8_t *buf = pu->data;
|
||||
uint8_t *fbuf = fpu->data;
|
||||
int i = 0;
|
||||
size_t sz = pu->schema->size;
|
||||
PCPATCH_UNCOMPRESSED *fpu = pc_patch_uncompressed_make(pu->schema, map->nset);
|
||||
uint8_t *buf = pu->data;
|
||||
uint8_t *fbuf = fpu->data;
|
||||
|
||||
assert(map->npoints == pu->npoints);
|
||||
assert(map->npoints == pu->npoints);
|
||||
|
||||
while ( i < pu->npoints )
|
||||
{
|
||||
if ( pc_bitmap_get(map, i) )
|
||||
{
|
||||
memcpy(fbuf, buf, sz);
|
||||
fbuf += sz;
|
||||
}
|
||||
buf += sz;
|
||||
i++;
|
||||
}
|
||||
while (i < pu->npoints)
|
||||
{
|
||||
if (pc_bitmap_get(map, i))
|
||||
{
|
||||
memcpy(fbuf, buf, sz);
|
||||
fbuf += sz;
|
||||
}
|
||||
buf += sz;
|
||||
i++;
|
||||
}
|
||||
|
||||
fpu->maxpoints = fpu->npoints = map->nset;
|
||||
fpu->maxpoints = fpu->npoints = map->nset;
|
||||
|
||||
if ( PC_FAILURE == pc_patch_uncompressed_compute_extent(fpu) )
|
||||
{
|
||||
pcerror("%s: failed to compute patch extent", __func__);
|
||||
return NULL;
|
||||
}
|
||||
if (PC_FAILURE == pc_patch_uncompressed_compute_extent(fpu))
|
||||
{
|
||||
pcerror("%s: failed to compute patch extent", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( PC_FAILURE == pc_patch_uncompressed_compute_stats(fpu) )
|
||||
{
|
||||
pcerror("%s: failed to compute patch stats", __func__);
|
||||
return NULL;
|
||||
}
|
||||
if (PC_FAILURE == pc_patch_uncompressed_compute_stats(fpu))
|
||||
{
|
||||
pcerror("%s: failed to compute patch stats", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return fpu;
|
||||
return fpu;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static PCBITMAP *
|
||||
pc_patch_dimensional_bitmap(const PCPATCH_DIMENSIONAL *pdl, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2)
|
||||
static PCBITMAP *pc_patch_dimensional_bitmap(const PCPATCH_DIMENSIONAL *pdl,
|
||||
uint32_t dimnum,
|
||||
PC_FILTERTYPE filter, double val1,
|
||||
double val2)
|
||||
{
|
||||
assert(dimnum < pdl->schema->ndims);
|
||||
double unscaled1 = pc_value_unscale_unoffset(val1, pdl->schema->dims[dimnum]);
|
||||
double unscaled2 = pc_value_unscale_unoffset(val2, pdl->schema->dims[dimnum]);
|
||||
assert(dimnum < pdl->schema->ndims);
|
||||
double unscaled1 = pc_value_unscale_unoffset(val1, pdl->schema->dims[dimnum]);
|
||||
double unscaled2 = pc_value_unscale_unoffset(val2, pdl->schema->dims[dimnum]);
|
||||
|
||||
return pc_bytes_bitmap(&(pdl->bytes[dimnum]), filter, unscaled1, unscaled2);
|
||||
return pc_bytes_bitmap(&(pdl->bytes[dimnum]), filter, unscaled1, unscaled2);
|
||||
}
|
||||
|
||||
static PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_filter(const PCPATCH_DIMENSIONAL *pdl, const PCBITMAP *map)
|
||||
{
|
||||
int i = 0;
|
||||
PCPATCH_DIMENSIONAL *fpdl = pc_patch_dimensional_clone(pdl);
|
||||
int i = 0;
|
||||
PCPATCH_DIMENSIONAL *fpdl = pc_patch_dimensional_clone(pdl);
|
||||
|
||||
fpdl->stats = pc_stats_clone(pdl->stats);
|
||||
fpdl->npoints = map->nset;
|
||||
fpdl->stats = pc_stats_clone(pdl->stats);
|
||||
fpdl->npoints = map->nset;
|
||||
|
||||
for ( i = 0; i < pdl->schema->ndims; i++ )
|
||||
{
|
||||
PCDIMENSION *dim;
|
||||
PCDOUBLESTAT stats;
|
||||
stats.min = FLT_MAX;
|
||||
stats.max = -1*FLT_MAX;
|
||||
stats.sum = 0;
|
||||
fpdl->bytes[i] = pc_bytes_filter(&(pdl->bytes[i]), map, &stats);
|
||||
for (i = 0; i < pdl->schema->ndims; i++)
|
||||
{
|
||||
PCDIMENSION *dim;
|
||||
PCDOUBLESTAT stats;
|
||||
stats.min = FLT_MAX;
|
||||
stats.max = -1 * FLT_MAX;
|
||||
stats.sum = 0;
|
||||
fpdl->bytes[i] = pc_bytes_filter(&(pdl->bytes[i]), map, &stats);
|
||||
|
||||
/* Apply scale and offset */
|
||||
dim = pdl->schema->dims[i];
|
||||
stats.min = pc_value_scale_offset(stats.min, dim);
|
||||
stats.max = pc_value_scale_offset(stats.max, dim);
|
||||
stats.sum = pc_value_scale_offset(stats.sum, dim);
|
||||
|
||||
/* Apply scale and offset */
|
||||
dim = pdl->schema->dims[i];
|
||||
stats.min = pc_value_scale_offset(stats.min, dim);
|
||||
stats.max = pc_value_scale_offset(stats.max, dim);
|
||||
stats.sum = pc_value_scale_offset(stats.sum, dim);
|
||||
/* Save the X/Y stats for use in bounds later */
|
||||
if (dim == pdl->schema->xdim)
|
||||
{
|
||||
fpdl->bounds.xmin = stats.min;
|
||||
fpdl->bounds.xmax = stats.max;
|
||||
}
|
||||
else if (dim == pdl->schema->ydim)
|
||||
{
|
||||
fpdl->bounds.ymin = stats.min;
|
||||
fpdl->bounds.ymax = stats.max;
|
||||
}
|
||||
|
||||
/* Save the X/Y stats for use in bounds later */
|
||||
if ( dim == pdl->schema->xdim )
|
||||
{
|
||||
fpdl->bounds.xmin = stats.min;
|
||||
fpdl->bounds.xmax = stats.max;
|
||||
}
|
||||
else if ( dim == pdl->schema->ydim )
|
||||
{
|
||||
fpdl->bounds.ymin = stats.min;
|
||||
fpdl->bounds.ymax = stats.max;
|
||||
}
|
||||
pc_point_set_double_by_index(&(fpdl->stats->min), i, stats.min);
|
||||
pc_point_set_double_by_index(&(fpdl->stats->max), i, stats.max);
|
||||
pc_point_set_double_by_index(&(fpdl->stats->avg), i,
|
||||
stats.sum / fpdl->npoints);
|
||||
}
|
||||
|
||||
pc_point_set_double_by_index(&(fpdl->stats->min), i, stats.min);
|
||||
pc_point_set_double_by_index(&(fpdl->stats->max), i, stats.max);
|
||||
pc_point_set_double_by_index(&(fpdl->stats->avg), i, stats.sum/fpdl->npoints);
|
||||
}
|
||||
|
||||
return fpdl;
|
||||
return fpdl;
|
||||
}
|
||||
|
||||
/* See if it's possible for the filter to have any results, given the stats */
|
||||
static int
|
||||
pc_patch_filter_has_results(const PCSTATS *stats, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2)
|
||||
static int pc_patch_filter_has_results(const PCSTATS *stats, uint32_t dimnum,
|
||||
PC_FILTERTYPE filter, double val1,
|
||||
double val2)
|
||||
{
|
||||
double min, max;
|
||||
pc_point_get_double_by_index(&(stats->min), dimnum, &min);
|
||||
pc_point_get_double_by_index(&(stats->max), dimnum, &max);
|
||||
switch ( filter )
|
||||
{
|
||||
case PC_GT:
|
||||
{
|
||||
if ( max < val1 ) return PC_FALSE;
|
||||
break;
|
||||
}
|
||||
case PC_LT:
|
||||
{
|
||||
if ( min > val1 ) return PC_FALSE;
|
||||
break;
|
||||
}
|
||||
case PC_EQUAL:
|
||||
{
|
||||
if ( min > val1 || max < val1 ) return PC_FALSE;
|
||||
break;
|
||||
}
|
||||
case PC_BETWEEN:
|
||||
{
|
||||
if ( min > val2 || max < val1 ) return PC_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return PC_TRUE;
|
||||
double min, max;
|
||||
pc_point_get_double_by_index(&(stats->min), dimnum, &min);
|
||||
pc_point_get_double_by_index(&(stats->max), dimnum, &max);
|
||||
switch (filter)
|
||||
{
|
||||
case PC_GT:
|
||||
{
|
||||
if (max < val1)
|
||||
return PC_FALSE;
|
||||
break;
|
||||
}
|
||||
case PC_LT:
|
||||
{
|
||||
if (min > val1)
|
||||
return PC_FALSE;
|
||||
break;
|
||||
}
|
||||
case PC_EQUAL:
|
||||
{
|
||||
if (min > val1 || max < val1)
|
||||
return PC_FALSE;
|
||||
break;
|
||||
}
|
||||
case PC_BETWEEN:
|
||||
{
|
||||
if (min > val2 || max < val1)
|
||||
return PC_FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return PC_TRUE;
|
||||
}
|
||||
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_filter(const PCPATCH *pa, uint32_t dimnum, PC_FILTERTYPE filter, double val1, double val2)
|
||||
PCPATCH *pc_patch_filter(const PCPATCH *pa, uint32_t dimnum,
|
||||
PC_FILTERTYPE filter, double val1, double val2)
|
||||
{
|
||||
if ( ! pa ) return NULL;
|
||||
PCPATCH *paout;
|
||||
if (!pa)
|
||||
return NULL;
|
||||
PCPATCH *paout;
|
||||
|
||||
/* If the stats say this filter returns an empty result, do that */
|
||||
if ( pa->stats && ! pc_patch_filter_has_results(pa->stats, dimnum, filter, val1, val2) )
|
||||
{
|
||||
/* Empty uncompressed patch to return */
|
||||
paout = (PCPATCH*)pc_patch_uncompressed_make(pa->schema, 0);
|
||||
return paout;
|
||||
}
|
||||
/* If the stats say this filter returns an empty result, do that */
|
||||
if (pa->stats &&
|
||||
!pc_patch_filter_has_results(pa->stats, dimnum, filter, val1, val2))
|
||||
{
|
||||
/* Empty uncompressed patch to return */
|
||||
paout = (PCPATCH *)pc_patch_uncompressed_make(pa->schema, 0);
|
||||
return paout;
|
||||
}
|
||||
|
||||
switch ( pa->type )
|
||||
{
|
||||
case PC_NONE:
|
||||
{
|
||||
PCBITMAP *map = pc_patch_uncompressed_bitmap((PCPATCH_UNCOMPRESSED*)pa, dimnum, filter, val1, val2);
|
||||
PCPATCH_UNCOMPRESSED *pu;
|
||||
if ( map->nset == 0 )
|
||||
{
|
||||
pc_bitmap_free(map);
|
||||
return (PCPATCH*)pc_patch_uncompressed_make(pa->schema, 0);
|
||||
}
|
||||
pu = pc_patch_uncompressed_filter((PCPATCH_UNCOMPRESSED*)pa, map);
|
||||
pc_bitmap_free(map);
|
||||
/* pc_patch_uncompressed_filter computes stats and bounds, so we're ready to return here */
|
||||
/* TODO, it could/should compute bounds and stats while filtering the points */
|
||||
paout = (PCPATCH*)pu;
|
||||
break;
|
||||
}
|
||||
case PC_DIMENSIONAL:
|
||||
{
|
||||
PCBITMAP *map = pc_patch_dimensional_bitmap((PCPATCH_DIMENSIONAL*)pa, dimnum, filter, val1, val2);
|
||||
PCPATCH_DIMENSIONAL *pdl;
|
||||
if ( map->nset == 0 )
|
||||
{
|
||||
pc_bitmap_free(map);
|
||||
return (PCPATCH*)pc_patch_uncompressed_make(pa->schema, 0);
|
||||
}
|
||||
pdl = pc_patch_dimensional_filter((PCPATCH_DIMENSIONAL*)pa, map);
|
||||
pc_bitmap_free(map);
|
||||
/* pc_patch_dimensional_filter computes both stats and bounds, so we're done*/
|
||||
paout = (PCPATCH*)pdl;
|
||||
break;
|
||||
}
|
||||
case PC_LAZPERF:
|
||||
{
|
||||
PCBITMAP *map;
|
||||
PCPATCH_UNCOMPRESSED *pu;
|
||||
PCPATCH_UNCOMPRESSED *pau;
|
||||
switch (pa->type)
|
||||
{
|
||||
case PC_NONE:
|
||||
{
|
||||
PCBITMAP *map = pc_patch_uncompressed_bitmap((PCPATCH_UNCOMPRESSED *)pa,
|
||||
dimnum, filter, val1, val2);
|
||||
PCPATCH_UNCOMPRESSED *pu;
|
||||
if (map->nset == 0)
|
||||
{
|
||||
pc_bitmap_free(map);
|
||||
return (PCPATCH *)pc_patch_uncompressed_make(pa->schema, 0);
|
||||
}
|
||||
pu = pc_patch_uncompressed_filter((PCPATCH_UNCOMPRESSED *)pa, map);
|
||||
pc_bitmap_free(map);
|
||||
/* pc_patch_uncompressed_filter computes stats and bounds, so we're
|
||||
* ready to return here */
|
||||
/* TODO, it could/should compute bounds and stats while filtering the
|
||||
* points
|
||||
*/
|
||||
paout = (PCPATCH *)pu;
|
||||
break;
|
||||
}
|
||||
case PC_DIMENSIONAL:
|
||||
{
|
||||
PCBITMAP *map = pc_patch_dimensional_bitmap((PCPATCH_DIMENSIONAL *)pa,
|
||||
dimnum, filter, val1, val2);
|
||||
PCPATCH_DIMENSIONAL *pdl;
|
||||
if (map->nset == 0)
|
||||
{
|
||||
pc_bitmap_free(map);
|
||||
return (PCPATCH *)pc_patch_uncompressed_make(pa->schema, 0);
|
||||
}
|
||||
pdl = pc_patch_dimensional_filter((PCPATCH_DIMENSIONAL *)pa, map);
|
||||
pc_bitmap_free(map);
|
||||
/* pc_patch_dimensional_filter computes both stats and bounds, so we're
|
||||
* done*/
|
||||
paout = (PCPATCH *)pdl;
|
||||
break;
|
||||
}
|
||||
case PC_LAZPERF:
|
||||
{
|
||||
PCBITMAP *map;
|
||||
PCPATCH_UNCOMPRESSED *pu;
|
||||
PCPATCH_UNCOMPRESSED *pau;
|
||||
|
||||
pau = pc_patch_uncompressed_from_lazperf( (PCPATCH_LAZPERF*) pa );
|
||||
map = pc_patch_uncompressed_bitmap(pau, dimnum, filter, val1, val2);
|
||||
if ( map->nset == 0 )
|
||||
{
|
||||
pc_bitmap_free(map);
|
||||
pc_patch_free((PCPATCH*) pau);
|
||||
return (PCPATCH*)pc_patch_uncompressed_make(pa->schema, 0);
|
||||
}
|
||||
pau = pc_patch_uncompressed_from_lazperf((PCPATCH_LAZPERF *)pa);
|
||||
map = pc_patch_uncompressed_bitmap(pau, dimnum, filter, val1, val2);
|
||||
if (map->nset == 0)
|
||||
{
|
||||
pc_bitmap_free(map);
|
||||
pc_patch_free((PCPATCH *)pau);
|
||||
return (PCPATCH *)pc_patch_uncompressed_make(pa->schema, 0);
|
||||
}
|
||||
|
||||
pu = pc_patch_uncompressed_filter(pau, map);
|
||||
pc_bitmap_free(map);
|
||||
pc_patch_free((PCPATCH*) pau);
|
||||
/* pc_patch_uncompressed_filter computes stats and bounds, so we're ready to return here */
|
||||
/* TODO, it could/should compute bounds and stats while filtering the points */
|
||||
paout = (PCPATCH*)pu;
|
||||
pu = pc_patch_uncompressed_filter(pau, map);
|
||||
pc_bitmap_free(map);
|
||||
pc_patch_free((PCPATCH *)pau);
|
||||
/* pc_patch_uncompressed_filter computes stats and bounds, so we're
|
||||
* ready to return here */
|
||||
/* TODO, it could/should compute bounds and stats while filtering the
|
||||
* points
|
||||
*/
|
||||
paout = (PCPATCH *)pu;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
pcerror("%s: failure", __func__);
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
pcerror("%s: failure", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return paout;
|
||||
return paout;
|
||||
}
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_filter_lt_by_name(const PCPATCH *pa, const char *name, double val)
|
||||
PCPATCH *pc_patch_filter_lt_by_name(const PCPATCH *pa, const char *name,
|
||||
double val)
|
||||
{
|
||||
/* Error out if we can't find the name */
|
||||
PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name);
|
||||
if ( ! d ) return NULL;
|
||||
/* Error out if we can't find the name */
|
||||
PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name);
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
return pc_patch_filter(pa, d->position, PC_LT, val, val);
|
||||
return pc_patch_filter(pa, d->position, PC_LT, val, val);
|
||||
}
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_filter_gt_by_name(const PCPATCH *pa, const char *name, double val)
|
||||
PCPATCH *pc_patch_filter_gt_by_name(const PCPATCH *pa, const char *name,
|
||||
double val)
|
||||
{
|
||||
/* Error out if we can't find the name */
|
||||
PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name);
|
||||
if ( ! d ) return NULL;
|
||||
/* Error out if we can't find the name */
|
||||
PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name);
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
return pc_patch_filter(pa, d->position, PC_GT, val, val);
|
||||
return pc_patch_filter(pa, d->position, PC_GT, val, val);
|
||||
}
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_filter_equal_by_name(const PCPATCH *pa, const char *name, double val)
|
||||
PCPATCH *pc_patch_filter_equal_by_name(const PCPATCH *pa, const char *name,
|
||||
double val)
|
||||
{
|
||||
/* Error out if we can't find the name */
|
||||
PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name);
|
||||
if ( ! d ) return NULL;
|
||||
/* Error out if we can't find the name */
|
||||
PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name);
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
return pc_patch_filter(pa, d->position, PC_EQUAL, val, val);
|
||||
return pc_patch_filter(pa, d->position, PC_EQUAL, val, val);
|
||||
}
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_filter_between_by_name(const PCPATCH *pa, const char *name, double val1, double val2)
|
||||
PCPATCH *pc_patch_filter_between_by_name(const PCPATCH *pa, const char *name,
|
||||
double val1, double val2)
|
||||
{
|
||||
/* Ensure val1 < val2 always */
|
||||
if ( val1 > val2 )
|
||||
{
|
||||
double tmp = val1;
|
||||
val1 = val2;
|
||||
val2 = tmp;
|
||||
}
|
||||
/* Error out if we can't find the name */
|
||||
PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name);
|
||||
if ( ! d ) return NULL;
|
||||
/* Ensure val1 < val2 always */
|
||||
if (val1 > val2)
|
||||
{
|
||||
double tmp = val1;
|
||||
val1 = val2;
|
||||
val2 = tmp;
|
||||
}
|
||||
/* Error out if we can't find the name */
|
||||
PCDIMENSION *d = pc_schema_get_dimension_by_name(pa->schema, name);
|
||||
if (!d)
|
||||
return NULL;
|
||||
|
||||
return pc_patch_filter(pa, d->position, PC_BETWEEN, val1, val2);
|
||||
return pc_patch_filter(pa, d->position, PC_BETWEEN, val1, val2);
|
||||
}
|
||||
|
||||
226
lib/pc_mem.c
226
lib/pc_mem.c
@ -1,174 +1,156 @@
|
||||
/***********************************************************************
|
||||
* pc_mem.c
|
||||
*
|
||||
* Memory and message management routines.
|
||||
* Allow this library to be used both inside and outside a
|
||||
* PgSQL backend.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_mem.c
|
||||
*
|
||||
* Memory and message management routines.
|
||||
* Allow this library to be used both inside and outside a
|
||||
* PgSQL backend.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include "pc_api_internal.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
struct pc_context_t
|
||||
{
|
||||
pc_allocator alloc;
|
||||
pc_reallocator realloc;
|
||||
pc_deallocator free;
|
||||
pc_message_handler err;
|
||||
pc_message_handler warn;
|
||||
pc_message_handler info;
|
||||
pc_allocator alloc;
|
||||
pc_reallocator realloc;
|
||||
pc_deallocator free;
|
||||
pc_message_handler err;
|
||||
pc_message_handler warn;
|
||||
pc_message_handler info;
|
||||
};
|
||||
|
||||
static struct pc_context_t pc_context;
|
||||
|
||||
/*
|
||||
* Default allocators
|
||||
*
|
||||
* We include some default allocators that use malloc/free/realloc
|
||||
* along with stdout/stderr since this is the most common use case
|
||||
*
|
||||
*/
|
||||
* Default allocators
|
||||
*
|
||||
* We include some default allocators that use malloc/free/realloc
|
||||
* along with stdout/stderr since this is the most common use case
|
||||
*
|
||||
*/
|
||||
|
||||
static void *
|
||||
default_allocator(size_t size)
|
||||
static void *default_allocator(size_t size) { return malloc(size); }
|
||||
|
||||
static void default_freeor(void *mem) { free(mem); }
|
||||
|
||||
static void *default_reallocator(void *mem, size_t size)
|
||||
{
|
||||
return malloc(size);
|
||||
return realloc(mem, size);
|
||||
}
|
||||
|
||||
static void
|
||||
default_freeor(void *mem)
|
||||
static void default_msg_handler(const char *label, const char *fmt, va_list ap)
|
||||
{
|
||||
free(mem);
|
||||
char newfmt[1024] = {0};
|
||||
snprintf(newfmt, 1024, "%s%s\n", label, fmt);
|
||||
newfmt[1023] = '\0';
|
||||
vprintf(newfmt, ap);
|
||||
}
|
||||
|
||||
static void *
|
||||
default_reallocator(void *mem, size_t size)
|
||||
static void default_info_handler(const char *fmt, va_list ap)
|
||||
{
|
||||
return realloc(mem, size);
|
||||
default_msg_handler("INFO: ", fmt, ap);
|
||||
}
|
||||
|
||||
static void
|
||||
default_msg_handler(const char *label, const char *fmt, va_list ap)
|
||||
static void default_warn_handler(const char *fmt, va_list ap)
|
||||
{
|
||||
char newfmt[1024] = {0};
|
||||
snprintf(newfmt, 1024, "%s%s\n", label, fmt);
|
||||
newfmt[1023] = '\0';
|
||||
vprintf(newfmt, ap);
|
||||
default_msg_handler("WARNING: ", fmt, ap);
|
||||
}
|
||||
|
||||
static void
|
||||
default_info_handler(const char *fmt, va_list ap)
|
||||
static void default_error_handler(const char *fmt, va_list ap)
|
||||
{
|
||||
default_msg_handler("INFO: ", fmt, ap);
|
||||
default_msg_handler("ERROR: ", fmt, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
default_warn_handler(const char *fmt, va_list ap)
|
||||
{
|
||||
default_msg_handler("WARNING: ", fmt, ap);
|
||||
}
|
||||
|
||||
static void
|
||||
default_error_handler(const char *fmt, va_list ap)
|
||||
{
|
||||
default_msg_handler("ERROR: ", fmt, ap);
|
||||
va_end(ap);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
void pc_install_default_handlers(void)
|
||||
{
|
||||
pc_context.alloc = default_allocator;
|
||||
pc_context.realloc = default_reallocator;
|
||||
pc_context.free = default_freeor;
|
||||
pc_context.err = default_error_handler;
|
||||
pc_context.info = default_info_handler;
|
||||
pc_context.warn = default_warn_handler;
|
||||
pc_context.alloc = default_allocator;
|
||||
pc_context.realloc = default_reallocator;
|
||||
pc_context.free = default_freeor;
|
||||
pc_context.err = default_error_handler;
|
||||
pc_context.info = default_info_handler;
|
||||
pc_context.warn = default_warn_handler;
|
||||
}
|
||||
|
||||
void pc_set_handlers(
|
||||
pc_allocator allocator, pc_reallocator reallocator,
|
||||
pc_deallocator deallocator, pc_message_handler error_handler,
|
||||
pc_message_handler info_handler, pc_message_handler warn_handler)
|
||||
void pc_set_handlers(pc_allocator allocator, pc_reallocator reallocator,
|
||||
pc_deallocator deallocator,
|
||||
pc_message_handler error_handler,
|
||||
pc_message_handler info_handler,
|
||||
pc_message_handler warn_handler)
|
||||
{
|
||||
if ( ! allocator ) allocator = pc_context.alloc;
|
||||
if ( ! reallocator ) reallocator = pc_context.realloc;
|
||||
if ( ! deallocator ) deallocator = pc_context.free;
|
||||
if ( ! error_handler ) error_handler = pc_context.err;
|
||||
if ( ! warn_handler ) warn_handler = pc_context.warn;
|
||||
if ( ! info_handler ) info_handler = pc_context.info;
|
||||
if (!allocator)
|
||||
allocator = pc_context.alloc;
|
||||
if (!reallocator)
|
||||
reallocator = pc_context.realloc;
|
||||
if (!deallocator)
|
||||
deallocator = pc_context.free;
|
||||
if (!error_handler)
|
||||
error_handler = pc_context.err;
|
||||
if (!warn_handler)
|
||||
warn_handler = pc_context.warn;
|
||||
if (!info_handler)
|
||||
info_handler = pc_context.info;
|
||||
|
||||
pc_context.alloc = allocator;
|
||||
pc_context.realloc = reallocator;
|
||||
pc_context.free = deallocator;
|
||||
pc_context.err = error_handler;
|
||||
pc_context.warn = warn_handler;
|
||||
pc_context.info = info_handler;
|
||||
return;
|
||||
pc_context.alloc = allocator;
|
||||
pc_context.realloc = reallocator;
|
||||
pc_context.free = deallocator;
|
||||
pc_context.err = error_handler;
|
||||
pc_context.warn = warn_handler;
|
||||
pc_context.info = info_handler;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
pcalloc(size_t size)
|
||||
void *pcalloc(size_t size)
|
||||
{
|
||||
void *mem;
|
||||
if ( ! size ) return NULL;
|
||||
mem = pc_context.alloc(size);
|
||||
memset(mem, 0, size); /* Always clean memory */
|
||||
return mem;
|
||||
void *mem;
|
||||
if (!size)
|
||||
return NULL;
|
||||
mem = pc_context.alloc(size);
|
||||
memset(mem, 0, size); /* Always clean memory */
|
||||
return mem;
|
||||
}
|
||||
|
||||
char *
|
||||
pcstrdup(const char *str)
|
||||
char *pcstrdup(const char *str)
|
||||
{
|
||||
size_t len = strlen(str);
|
||||
char *newstr = pcalloc(len + 1);
|
||||
memcpy(newstr, str, len + 1);
|
||||
return newstr;
|
||||
size_t len = strlen(str);
|
||||
char *newstr = pcalloc(len + 1);
|
||||
memcpy(newstr, str, len + 1);
|
||||
return newstr;
|
||||
}
|
||||
|
||||
void *
|
||||
pcrealloc(void * mem, size_t size)
|
||||
void *pcrealloc(void *mem, size_t size)
|
||||
{
|
||||
return pc_context.realloc(mem, size);
|
||||
return pc_context.realloc(mem, size);
|
||||
}
|
||||
|
||||
void
|
||||
pcfree(void * mem)
|
||||
void pcfree(void *mem) { pc_context.free(mem); }
|
||||
|
||||
void pcerror(const char *fmt, ...)
|
||||
{
|
||||
pc_context.free(mem);
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
(*pc_context.err)(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
pcerror(const char *fmt, ...)
|
||||
void pcinfo(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
(*pc_context.err)(fmt, ap);
|
||||
va_end(ap);
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
(*pc_context.info)(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
pcinfo(const char *fmt, ...)
|
||||
void pcwarn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
(*pc_context.info)(fmt, ap);
|
||||
va_end(ap);
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
(*pc_context.warn)(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void
|
||||
pcwarn(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
(*pc_context.warn)(fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
|
||||
1187
lib/pc_patch.c
1187
lib/pc_patch.c
File diff suppressed because it is too large
Load Diff
@ -1,329 +1,332 @@
|
||||
/***********************************************************************
|
||||
* pc_patch_dimensional.c
|
||||
*
|
||||
* Pointclound patch handling. Create, get and set values from the
|
||||
* dimensional PCPATCH structure.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_patch_dimensional.c
|
||||
*
|
||||
* Pointclound patch handling. Create, get and set values from the
|
||||
* dimensional PCPATCH structure.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include <math.h>
|
||||
#include <assert.h>
|
||||
#include "pc_api_internal.h"
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/*
|
||||
typedef struct
|
||||
{
|
||||
int type;
|
||||
int8_t readonly;
|
||||
const PCSCHEMA *schema;
|
||||
uint32_t npoints;
|
||||
double xmin, xmax, ymin, ymax;
|
||||
PCSTATS *stats;
|
||||
PCBYTES *bytes;
|
||||
int type;
|
||||
int8_t readonly;
|
||||
const PCSCHEMA *schema;
|
||||
uint32_t npoints;
|
||||
double xmin, xmax, ymin, ymax;
|
||||
PCSTATS *stats;
|
||||
PCBYTES *bytes;
|
||||
} PCPATCH_DIMENSIONAL;
|
||||
*/
|
||||
|
||||
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_clone(const PCPATCH_DIMENSIONAL *patch)
|
||||
{
|
||||
PCPATCH_DIMENSIONAL *pdl = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
memcpy(pdl, patch, sizeof(PCPATCH_DIMENSIONAL));
|
||||
pdl->bytes = pcalloc(patch->schema->ndims * sizeof(PCBYTES));
|
||||
pdl->npoints = 0;
|
||||
pdl->stats = NULL;
|
||||
return pdl;
|
||||
PCPATCH_DIMENSIONAL *pdl = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
memcpy(pdl, patch, sizeof(PCPATCH_DIMENSIONAL));
|
||||
pdl->bytes = pcalloc(patch->schema->ndims * sizeof(PCBYTES));
|
||||
pdl->npoints = 0;
|
||||
pdl->stats = NULL;
|
||||
return pdl;
|
||||
}
|
||||
|
||||
size_t
|
||||
pc_patch_dimensional_serialized_size(const PCPATCH_DIMENSIONAL *patch)
|
||||
size_t pc_patch_dimensional_serialized_size(const PCPATCH_DIMENSIONAL *patch)
|
||||
{
|
||||
PCPATCH_DIMENSIONAL *p = (PCPATCH_DIMENSIONAL*)patch;
|
||||
int i;
|
||||
size_t size = 0;
|
||||
for ( i = 0; i < p->schema->ndims; i++ )
|
||||
{
|
||||
size += pc_bytes_serialized_size(&(p->bytes[i]));
|
||||
}
|
||||
return size;
|
||||
PCPATCH_DIMENSIONAL *p = (PCPATCH_DIMENSIONAL *)patch;
|
||||
int i;
|
||||
size_t size = 0;
|
||||
for (i = 0; i < p->schema->ndims; i++)
|
||||
{
|
||||
size += pc_bytes_serialized_size(&(p->bytes[i]));
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
pc_patch_dimensional_to_string(const PCPATCH_DIMENSIONAL *pa)
|
||||
char *pc_patch_dimensional_to_string(const PCPATCH_DIMENSIONAL *pa)
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *patch = pc_patch_uncompressed_from_dimensional(pa);
|
||||
char *str = pc_patch_uncompressed_to_string(patch);
|
||||
pc_patch_free((PCPATCH*)patch);
|
||||
return str;
|
||||
PCPATCH_UNCOMPRESSED *patch = pc_patch_uncompressed_from_dimensional(pa);
|
||||
char *str = pc_patch_uncompressed_to_string(patch);
|
||||
pc_patch_free((PCPATCH *)patch);
|
||||
return str;
|
||||
}
|
||||
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa)
|
||||
{
|
||||
PCPATCH_DIMENSIONAL *pdl;
|
||||
const PCSCHEMA *schema;
|
||||
int i, j, ndims, npoints;
|
||||
PCPATCH_DIMENSIONAL *pdl;
|
||||
const PCSCHEMA *schema;
|
||||
int i, j, ndims, npoints;
|
||||
|
||||
assert(pa);
|
||||
npoints = pa->npoints;
|
||||
schema = pa->schema;
|
||||
ndims = schema->ndims;
|
||||
assert(pa);
|
||||
npoints = pa->npoints;
|
||||
schema = pa->schema;
|
||||
ndims = schema->ndims;
|
||||
|
||||
/* Cannot handle empty patches */
|
||||
if ( npoints == 0 ) return NULL;
|
||||
/* Cannot handle empty patches */
|
||||
if (npoints == 0)
|
||||
return NULL;
|
||||
|
||||
/* Initialize dimensional */
|
||||
pdl = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
pdl->type = PC_DIMENSIONAL;
|
||||
pdl->readonly = PC_FALSE;
|
||||
pdl->schema = schema;
|
||||
pdl->npoints = npoints;
|
||||
pdl->bounds = pa->bounds;
|
||||
pdl->stats = pc_stats_clone(pa->stats);
|
||||
pdl->bytes = pcalloc(ndims * sizeof(PCBYTES));
|
||||
/* Initialize dimensional */
|
||||
pdl = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
pdl->type = PC_DIMENSIONAL;
|
||||
pdl->readonly = PC_FALSE;
|
||||
pdl->schema = schema;
|
||||
pdl->npoints = npoints;
|
||||
pdl->bounds = pa->bounds;
|
||||
pdl->stats = pc_stats_clone(pa->stats);
|
||||
pdl->bytes = pcalloc(ndims * sizeof(PCBYTES));
|
||||
|
||||
for ( i = 0; i < ndims; i++ )
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(schema, i);
|
||||
pdl->bytes[i] = pc_bytes_make(dim, npoints);
|
||||
for ( j = 0; j < npoints; j++ )
|
||||
{
|
||||
uint8_t *to = pdl->bytes[i].bytes + dim->size * j;
|
||||
uint8_t *from = pa->data + schema->size * j + dim->byteoffset;
|
||||
memcpy(to, from, dim->size);
|
||||
}
|
||||
}
|
||||
return pdl;
|
||||
for (i = 0; i < ndims; i++)
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(schema, i);
|
||||
pdl->bytes[i] = pc_bytes_make(dim, npoints);
|
||||
for (j = 0; j < npoints; j++)
|
||||
{
|
||||
uint8_t *to = pdl->bytes[i].bytes + dim->size * j;
|
||||
uint8_t *from = pa->data + schema->size * j + dim->byteoffset;
|
||||
memcpy(to, from, dim->size);
|
||||
}
|
||||
}
|
||||
return pdl;
|
||||
}
|
||||
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_compress(const PCPATCH_DIMENSIONAL *pdl, PCDIMSTATS *pds_in)
|
||||
pc_patch_dimensional_compress(const PCPATCH_DIMENSIONAL *pdl,
|
||||
PCDIMSTATS *pds_in)
|
||||
{
|
||||
int i;
|
||||
int ndims = pdl->schema->ndims;
|
||||
PCPATCH_DIMENSIONAL *pdl_compressed;
|
||||
PCDIMSTATS *pds = pds_in;
|
||||
int i;
|
||||
int ndims = pdl->schema->ndims;
|
||||
PCPATCH_DIMENSIONAL *pdl_compressed;
|
||||
PCDIMSTATS *pds = pds_in;
|
||||
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
|
||||
if ( ! pds )
|
||||
pds = pc_dimstats_make(pdl->schema);
|
||||
if (!pds)
|
||||
pds = pc_dimstats_make(pdl->schema);
|
||||
|
||||
/* Still sampling, update stats */
|
||||
if ( pds->total_points < PCDIMSTATS_MIN_SAMPLE )
|
||||
pc_dimstats_update(pds, pdl);
|
||||
/* Still sampling, update stats */
|
||||
if (pds->total_points < PCDIMSTATS_MIN_SAMPLE)
|
||||
pc_dimstats_update(pds, pdl);
|
||||
|
||||
pdl_compressed = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
memcpy(pdl_compressed, pdl, sizeof(PCPATCH_DIMENSIONAL));
|
||||
pdl_compressed->bytes = pcalloc(ndims*sizeof(PCBYTES));
|
||||
pdl_compressed->stats = pc_stats_clone(pdl->stats);
|
||||
pdl_compressed = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
memcpy(pdl_compressed, pdl, sizeof(PCPATCH_DIMENSIONAL));
|
||||
pdl_compressed->bytes = pcalloc(ndims * sizeof(PCBYTES));
|
||||
pdl_compressed->stats = pc_stats_clone(pdl->stats);
|
||||
|
||||
/* Compress each dimension as dictated by stats */
|
||||
for ( i = 0; i < ndims; i++ )
|
||||
{
|
||||
pdl_compressed->bytes[i] = pc_bytes_encode(pdl->bytes[i], pds->stats[i].recommended_compression);
|
||||
}
|
||||
/* Compress each dimension as dictated by stats */
|
||||
for (i = 0; i < ndims; i++)
|
||||
{
|
||||
pdl_compressed->bytes[i] =
|
||||
pc_bytes_encode(pdl->bytes[i], pds->stats[i].recommended_compression);
|
||||
}
|
||||
|
||||
if ( pds != pds_in ) pc_dimstats_free(pds);
|
||||
if (pds != pds_in)
|
||||
pc_dimstats_free(pds);
|
||||
|
||||
return pdl_compressed;
|
||||
return pdl_compressed;
|
||||
}
|
||||
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_decompress(const PCPATCH_DIMENSIONAL *pdl)
|
||||
{
|
||||
int i;
|
||||
int ndims = pdl->schema->ndims;
|
||||
PCPATCH_DIMENSIONAL *pdl_decompressed;
|
||||
int i;
|
||||
int ndims = pdl->schema->ndims;
|
||||
PCPATCH_DIMENSIONAL *pdl_decompressed;
|
||||
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
|
||||
pdl_decompressed = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
memcpy(pdl_decompressed, pdl, sizeof(PCPATCH_DIMENSIONAL));
|
||||
pdl_decompressed->bytes = pcalloc(ndims*sizeof(PCBYTES));
|
||||
pdl_decompressed->stats = pc_stats_clone(pdl->stats);
|
||||
pdl_decompressed = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
memcpy(pdl_decompressed, pdl, sizeof(PCPATCH_DIMENSIONAL));
|
||||
pdl_decompressed->bytes = pcalloc(ndims * sizeof(PCBYTES));
|
||||
pdl_decompressed->stats = pc_stats_clone(pdl->stats);
|
||||
|
||||
/* Compress each dimension as dictated by stats */
|
||||
for ( i = 0; i < ndims; i++ )
|
||||
{
|
||||
pdl_decompressed->bytes[i] = pc_bytes_decode(pdl->bytes[i]);
|
||||
}
|
||||
/* Compress each dimension as dictated by stats */
|
||||
for (i = 0; i < ndims; i++)
|
||||
{
|
||||
pdl_decompressed->bytes[i] = pc_bytes_decode(pdl->bytes[i]);
|
||||
}
|
||||
|
||||
return pdl_decompressed;
|
||||
return pdl_decompressed;
|
||||
}
|
||||
|
||||
void
|
||||
pc_patch_dimensional_free(PCPATCH_DIMENSIONAL *pdl)
|
||||
void pc_patch_dimensional_free(PCPATCH_DIMENSIONAL *pdl)
|
||||
{
|
||||
int i;
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
int i;
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
|
||||
pc_patch_free_stats((PCPATCH*) pdl);
|
||||
pc_patch_free_stats((PCPATCH *)pdl);
|
||||
|
||||
if ( pdl->bytes )
|
||||
{
|
||||
for ( i = 0; i < pdl->schema->ndims; i++ )
|
||||
pc_bytes_free(pdl->bytes[i]);
|
||||
if (pdl->bytes)
|
||||
{
|
||||
for (i = 0; i < pdl->schema->ndims; i++)
|
||||
pc_bytes_free(pdl->bytes[i]);
|
||||
|
||||
pcfree(pdl->bytes);
|
||||
}
|
||||
pcfree(pdl->bytes);
|
||||
}
|
||||
|
||||
pcfree(pdl);
|
||||
pcfree(pdl);
|
||||
}
|
||||
|
||||
int
|
||||
pc_patch_dimensional_compute_extent(PCPATCH_DIMENSIONAL *pdl)
|
||||
int pc_patch_dimensional_compute_extent(PCPATCH_DIMENSIONAL *pdl)
|
||||
{
|
||||
double xmin, xmax, ymin, ymax, xavg, yavg;
|
||||
int rv;
|
||||
PCBYTES *pcb;
|
||||
double xmin, xmax, ymin, ymax, xavg, yavg;
|
||||
int rv;
|
||||
PCBYTES *pcb;
|
||||
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
assert(pdl->schema->xdim);
|
||||
assert(pdl->schema->ydim);
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
assert(pdl->schema->xdim);
|
||||
assert(pdl->schema->ydim);
|
||||
|
||||
/* Get x extremes */
|
||||
pcb = &(pdl->bytes[pdl->schema->xdim->position]);
|
||||
rv = pc_bytes_minmax(pcb, &xmin, &xmax, &xavg);
|
||||
if ( PC_FAILURE == rv ) return PC_FAILURE;
|
||||
xmin = pc_value_scale_offset(xmin, pdl->schema->xdim);
|
||||
xmax = pc_value_scale_offset(xmax, pdl->schema->xdim);
|
||||
pdl->bounds.xmin = xmin;
|
||||
pdl->bounds.xmax = xmax;
|
||||
/* Get x extremes */
|
||||
pcb = &(pdl->bytes[pdl->schema->xdim->position]);
|
||||
rv = pc_bytes_minmax(pcb, &xmin, &xmax, &xavg);
|
||||
if (PC_FAILURE == rv)
|
||||
return PC_FAILURE;
|
||||
xmin = pc_value_scale_offset(xmin, pdl->schema->xdim);
|
||||
xmax = pc_value_scale_offset(xmax, pdl->schema->xdim);
|
||||
pdl->bounds.xmin = xmin;
|
||||
pdl->bounds.xmax = xmax;
|
||||
|
||||
/* Get y extremes */
|
||||
pcb = &(pdl->bytes[pdl->schema->ydim->position]);
|
||||
rv = pc_bytes_minmax(pcb, &ymin, &ymax, &yavg);
|
||||
if ( PC_FAILURE == rv ) return PC_FAILURE;
|
||||
ymin = pc_value_scale_offset(ymin, pdl->schema->ydim);
|
||||
ymax = pc_value_scale_offset(ymax, pdl->schema->ydim);
|
||||
pdl->bounds.ymin = ymin;
|
||||
pdl->bounds.ymax = ymax;
|
||||
/* Get y extremes */
|
||||
pcb = &(pdl->bytes[pdl->schema->ydim->position]);
|
||||
rv = pc_bytes_minmax(pcb, &ymin, &ymax, &yavg);
|
||||
if (PC_FAILURE == rv)
|
||||
return PC_FAILURE;
|
||||
ymin = pc_value_scale_offset(ymin, pdl->schema->ydim);
|
||||
ymax = pc_value_scale_offset(ymax, pdl->schema->ydim);
|
||||
pdl->bounds.ymin = ymin;
|
||||
pdl->bounds.ymax = ymax;
|
||||
|
||||
return PC_SUCCESS;
|
||||
return PC_SUCCESS;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
pc_patch_dimensional_to_wkb(const PCPATCH_DIMENSIONAL *patch, size_t *wkbsize)
|
||||
uint8_t *pc_patch_dimensional_to_wkb(const PCPATCH_DIMENSIONAL *patch,
|
||||
size_t *wkbsize)
|
||||
{
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
dimensions[]: pcbytes (interpret relative to pcid and compressions)
|
||||
*/
|
||||
int ndims = patch->schema->ndims;
|
||||
int i;
|
||||
uint8_t *buf;
|
||||
char endian = machine_endian();
|
||||
/* endian + pcid + compression + npoints + datasize */
|
||||
size_t size = 1 + 4 + 4 + 4 + pc_patch_dimensional_serialized_size(patch);
|
||||
uint8_t *wkb = pcalloc(size);
|
||||
uint32_t compression = patch->type;
|
||||
uint32_t npoints = patch->npoints;
|
||||
uint32_t pcid = patch->schema->pcid;
|
||||
wkb[0] = endian; /* Write endian flag */
|
||||
memcpy(wkb + 1, &pcid, 4); /* Write PCID */
|
||||
memcpy(wkb + 5, &compression, 4); /* Write compression */
|
||||
memcpy(wkb + 9, &npoints, 4); /* Write npoints */
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
dimensions[]: pcbytes (interpret relative to pcid and compressions)
|
||||
*/
|
||||
int ndims = patch->schema->ndims;
|
||||
int i;
|
||||
uint8_t *buf;
|
||||
char endian = machine_endian();
|
||||
/* endian + pcid + compression + npoints + datasize */
|
||||
size_t size = 1 + 4 + 4 + 4 + pc_patch_dimensional_serialized_size(patch);
|
||||
uint8_t *wkb = pcalloc(size);
|
||||
uint32_t compression = patch->type;
|
||||
uint32_t npoints = patch->npoints;
|
||||
uint32_t pcid = patch->schema->pcid;
|
||||
wkb[0] = endian; /* Write endian flag */
|
||||
memcpy(wkb + 1, &pcid, 4); /* Write PCID */
|
||||
memcpy(wkb + 5, &compression, 4); /* Write compression */
|
||||
memcpy(wkb + 9, &npoints, 4); /* Write npoints */
|
||||
|
||||
buf = wkb + 13;
|
||||
for ( i = 0; i < ndims; i++ )
|
||||
{
|
||||
size_t bsz;
|
||||
PCBYTES *pcb = &(patch->bytes[i]);
|
||||
// XXX printf("pcb->(size=%d, interp=%d, npoints=%d, compression=%d, readonly=%d)\n",pcb->size, pcb->interpretation, pcb->npoints, pcb->compression, pcb->readonly);
|
||||
buf = wkb + 13;
|
||||
for (i = 0; i < ndims; i++)
|
||||
{
|
||||
size_t bsz;
|
||||
PCBYTES *pcb = &(patch->bytes[i]);
|
||||
// XXX printf("pcb->(size=%d, interp=%d, npoints=%d,
|
||||
// compression=%d, readonly=%d)\n",pcb->size, pcb->interpretation,
|
||||
// pcb->npoints, pcb->compression, pcb->readonly);
|
||||
|
||||
pc_bytes_serialize(pcb, buf, &bsz);
|
||||
buf += bsz;
|
||||
}
|
||||
pc_bytes_serialize(pcb, buf, &bsz);
|
||||
buf += bsz;
|
||||
}
|
||||
|
||||
if ( wkbsize ) *wkbsize = size;
|
||||
return wkb;
|
||||
if (wkbsize)
|
||||
*wkbsize = size;
|
||||
return wkb;
|
||||
}
|
||||
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_dimensional_from_wkb(const PCSCHEMA *schema, const uint8_t *wkb, size_t wkbsize)
|
||||
PCPATCH *pc_patch_dimensional_from_wkb(const PCSCHEMA *schema,
|
||||
const uint8_t *wkb, size_t wkbsize)
|
||||
{
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
dimensions[]: dims (interpret relative to pcid and compressions)
|
||||
*/
|
||||
static size_t hdrsz = 1+4+4+4; /* endian + pcid + compression + npoints */
|
||||
PCPATCH_DIMENSIONAL *patch;
|
||||
uint8_t swap_endian = (wkb[0] != machine_endian());
|
||||
uint32_t npoints, ndims;
|
||||
const uint8_t *buf;
|
||||
int i;
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
dimensions[]: dims (interpret relative to pcid and compressions)
|
||||
*/
|
||||
static size_t hdrsz =
|
||||
1 + 4 + 4 + 4; /* endian + pcid + compression + npoints */
|
||||
PCPATCH_DIMENSIONAL *patch;
|
||||
uint8_t swap_endian = (wkb[0] != machine_endian());
|
||||
uint32_t npoints, ndims;
|
||||
const uint8_t *buf;
|
||||
int i;
|
||||
|
||||
if ( wkb_get_compression(wkb) != PC_DIMENSIONAL )
|
||||
{
|
||||
pcerror("%s: call with wkb that is not dimensionally compressed", __func__);
|
||||
return NULL;
|
||||
}
|
||||
if (wkb_get_compression(wkb) != PC_DIMENSIONAL)
|
||||
{
|
||||
pcerror("%s: call with wkb that is not dimensionally compressed", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
npoints = wkb_get_npoints(wkb);
|
||||
ndims = schema->ndims;
|
||||
npoints = wkb_get_npoints(wkb);
|
||||
ndims = schema->ndims;
|
||||
|
||||
patch = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
patch->type = PC_DIMENSIONAL;
|
||||
patch->readonly = PC_FALSE;
|
||||
patch->schema = schema;
|
||||
patch->npoints = npoints;
|
||||
patch->bytes = pcalloc(ndims*sizeof(PCBYTES));
|
||||
patch->stats = NULL;
|
||||
patch = pcalloc(sizeof(PCPATCH_DIMENSIONAL));
|
||||
patch->type = PC_DIMENSIONAL;
|
||||
patch->readonly = PC_FALSE;
|
||||
patch->schema = schema;
|
||||
patch->npoints = npoints;
|
||||
patch->bytes = pcalloc(ndims * sizeof(PCBYTES));
|
||||
patch->stats = NULL;
|
||||
|
||||
buf = wkb+hdrsz;
|
||||
for ( i = 0; i < ndims; i++ )
|
||||
{
|
||||
PCBYTES *pcb = &(patch->bytes[i]);
|
||||
PCDIMENSION *dim = schema->dims[i];
|
||||
pc_bytes_deserialize(buf, dim, pcb, PC_FALSE /*readonly*/, swap_endian);
|
||||
pcb->npoints = npoints;
|
||||
buf += pc_bytes_serialized_size(pcb);
|
||||
}
|
||||
buf = wkb + hdrsz;
|
||||
for (i = 0; i < ndims; i++)
|
||||
{
|
||||
PCBYTES *pcb = &(patch->bytes[i]);
|
||||
PCDIMENSION *dim = schema->dims[i];
|
||||
pc_bytes_deserialize(buf, dim, pcb, PC_FALSE /*readonly*/, swap_endian);
|
||||
pcb->npoints = npoints;
|
||||
buf += pc_bytes_serialized_size(pcb);
|
||||
}
|
||||
|
||||
return (PCPATCH*)patch;
|
||||
return (PCPATCH *)patch;
|
||||
}
|
||||
|
||||
PCPATCH_DIMENSIONAL *
|
||||
pc_patch_dimensional_from_pointlist(const PCPOINTLIST *pdl)
|
||||
PCPATCH_DIMENSIONAL *pc_patch_dimensional_from_pointlist(const PCPOINTLIST *pdl)
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *patch = pc_patch_uncompressed_from_pointlist(pdl);
|
||||
if ( ! patch ) return NULL;
|
||||
PCPATCH_DIMENSIONAL *dimpatch = pc_patch_dimensional_from_uncompressed(patch);
|
||||
pc_patch_free((PCPATCH*)patch);
|
||||
return dimpatch;
|
||||
PCPATCH_UNCOMPRESSED *patch = pc_patch_uncompressed_from_pointlist(pdl);
|
||||
if (!patch)
|
||||
return NULL;
|
||||
PCPATCH_DIMENSIONAL *dimpatch = pc_patch_dimensional_from_uncompressed(patch);
|
||||
pc_patch_free((PCPATCH *)patch);
|
||||
return dimpatch;
|
||||
}
|
||||
|
||||
/** get point n, 0-based, positive */
|
||||
PCPOINT *pc_patch_dimensional_pointn(const PCPATCH_DIMENSIONAL *pdl, int n)
|
||||
{
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
int i;
|
||||
int ndims = pdl->schema->ndims;
|
||||
PCPOINT *pt = pc_point_make(pdl->schema);
|
||||
uint8_t *buf = pt->data;
|
||||
for ( i = 0; i < ndims; i++ )
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(pdl->schema, i);
|
||||
pc_bytes_to_ptr(buf+dim->byteoffset,pdl->bytes[i], n);
|
||||
}
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
int i;
|
||||
int ndims = pdl->schema->ndims;
|
||||
PCPOINT *pt = pc_point_make(pdl->schema);
|
||||
uint8_t *buf = pt->data;
|
||||
for (i = 0; i < ndims; i++)
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(pdl->schema, i);
|
||||
pc_bytes_to_ptr(buf + dim->byteoffset, pdl->bytes[i], n);
|
||||
}
|
||||
|
||||
return pt;
|
||||
return pt;
|
||||
}
|
||||
|
||||
@ -1,256 +1,251 @@
|
||||
/***********************************************************************
|
||||
* pc_patch_lazperf.c
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
*
|
||||
* Copyright (c) 2016 Paul Blottiere, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_patch_lazperf.c
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
*
|
||||
* Copyright (c) 2016 Paul Blottiere, Oslandia
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "pc_api_internal.h"
|
||||
#include "lazperf_adapter.h"
|
||||
#include <assert.h>
|
||||
|
||||
void
|
||||
pc_patch_lazperf_free(PCPATCH_LAZPERF *pal)
|
||||
#include "lazperf_adapter.h"
|
||||
#include "pc_api_internal.h"
|
||||
|
||||
void pc_patch_lazperf_free(PCPATCH_LAZPERF *pal)
|
||||
{
|
||||
assert(pal);
|
||||
assert(pal->schema);
|
||||
pc_patch_free_stats((PCPATCH*) pal);
|
||||
pcfree(pal->lazperf);
|
||||
pcfree(pal);
|
||||
assert(pal);
|
||||
assert(pal->schema);
|
||||
pc_patch_free_stats((PCPATCH *)pal);
|
||||
pcfree(pal->lazperf);
|
||||
pcfree(pal);
|
||||
}
|
||||
|
||||
PCPATCH_LAZPERF *pc_patch_lazperf_from_pointlist(const PCPOINTLIST *pdl)
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *patch = pc_patch_uncompressed_from_pointlist(pdl);
|
||||
PCPATCH_LAZPERF *lazperfpatch = pc_patch_lazperf_from_uncompressed(patch);
|
||||
pc_patch_free((PCPATCH *)patch);
|
||||
|
||||
return lazperfpatch;
|
||||
}
|
||||
|
||||
PCPATCH_LAZPERF *
|
||||
pc_patch_lazperf_from_pointlist(const PCPOINTLIST *pdl)
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *patch = pc_patch_uncompressed_from_pointlist(pdl);
|
||||
PCPATCH_LAZPERF *lazperfpatch = pc_patch_lazperf_from_uncompressed(patch);
|
||||
pc_patch_free((PCPATCH*) patch);
|
||||
|
||||
return lazperfpatch;
|
||||
}
|
||||
|
||||
PCPATCH_LAZPERF*
|
||||
pc_patch_lazperf_from_uncompressed(const PCPATCH_UNCOMPRESSED *pa)
|
||||
{
|
||||
#ifndef HAVE_LAZPERF
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
PCPATCH_LAZPERF *palaz = NULL;
|
||||
uint8_t *compressed;
|
||||
PCPATCH_LAZPERF *palaz = NULL;
|
||||
uint8_t *compressed;
|
||||
|
||||
// cpp call to get compressed data from pcpatch
|
||||
size_t compressSize = lazperf_compress_from_uncompressed(pa, &compressed);
|
||||
// cpp call to get compressed data from pcpatch
|
||||
size_t compressSize = lazperf_compress_from_uncompressed(pa, &compressed);
|
||||
|
||||
if (compressSize != -1)
|
||||
{
|
||||
palaz = pcalloc(sizeof(PCPATCH_LAZPERF));
|
||||
palaz->type = PC_LAZPERF;
|
||||
palaz->readonly = PC_FALSE;
|
||||
palaz->schema = pa->schema;
|
||||
if (compressSize != -1)
|
||||
{
|
||||
palaz = pcalloc(sizeof(PCPATCH_LAZPERF));
|
||||
palaz->type = PC_LAZPERF;
|
||||
palaz->readonly = PC_FALSE;
|
||||
palaz->schema = pa->schema;
|
||||
|
||||
// not optimal but we have to pass by the context manager otherwise
|
||||
// a segfault happenned (sometimes) during a pcfree of lazperf field
|
||||
palaz->lazperf = (uint8_t*) pcalloc(compressSize);
|
||||
memcpy(palaz->lazperf, compressed, compressSize);
|
||||
free(compressed);
|
||||
// not optimal but we have to pass by the context manager otherwise
|
||||
// a segfault happenned (sometimes) during a pcfree of lazperf field
|
||||
palaz->lazperf = (uint8_t *)pcalloc(compressSize);
|
||||
memcpy(palaz->lazperf, compressed, compressSize);
|
||||
free(compressed);
|
||||
|
||||
palaz->npoints = pa->npoints;
|
||||
palaz->bounds = pa->bounds;
|
||||
palaz->stats = pc_stats_clone(pa->stats);
|
||||
palaz->lazperfsize = compressSize;
|
||||
}
|
||||
else
|
||||
pcerror("%s: LAZ compressionf failed", __func__);
|
||||
palaz->npoints = pa->npoints;
|
||||
palaz->bounds = pa->bounds;
|
||||
palaz->stats = pc_stats_clone(pa->stats);
|
||||
palaz->lazperfsize = compressSize;
|
||||
}
|
||||
else
|
||||
pcerror("%s: LAZ compressionf failed", __func__);
|
||||
|
||||
return palaz;
|
||||
return palaz;
|
||||
}
|
||||
|
||||
PCPOINTLIST *
|
||||
pc_pointlist_from_lazperf(const PCPATCH_LAZPERF *palaz)
|
||||
PCPOINTLIST *pc_pointlist_from_lazperf(const PCPATCH_LAZPERF *palaz)
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *pu = NULL;
|
||||
pu = pc_patch_uncompressed_from_lazperf(palaz);
|
||||
PCPOINTLIST *pl = pc_pointlist_from_uncompressed(pu);
|
||||
pl->mem = pc_patch_uncompressed_readonly(pu);
|
||||
pc_patch_free((PCPATCH *)pu);
|
||||
return pl;
|
||||
PCPATCH_UNCOMPRESSED *pu = NULL;
|
||||
pu = pc_patch_uncompressed_from_lazperf(palaz);
|
||||
PCPOINTLIST *pl = pc_pointlist_from_uncompressed(pu);
|
||||
pl->mem = pc_patch_uncompressed_readonly(pu);
|
||||
pc_patch_free((PCPATCH *)pu);
|
||||
return pl;
|
||||
}
|
||||
|
||||
PCPATCH_UNCOMPRESSED*
|
||||
PCPATCH_UNCOMPRESSED *
|
||||
pc_patch_uncompressed_from_lazperf(const PCPATCH_LAZPERF *palaz)
|
||||
{
|
||||
#ifndef HAVE_LAZPERF
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
PCPATCH_UNCOMPRESSED *pcu = NULL;
|
||||
uint8_t *decompressed;
|
||||
PCPATCH_UNCOMPRESSED *pcu = NULL;
|
||||
uint8_t *decompressed;
|
||||
|
||||
// cpp call to uncompressed data
|
||||
size_t size = lazperf_uncompress_from_compressed(palaz, &decompressed);
|
||||
// cpp call to uncompressed data
|
||||
size_t size = lazperf_uncompress_from_compressed(palaz, &decompressed);
|
||||
|
||||
if (size != -1)
|
||||
{
|
||||
size_t datasize;
|
||||
pcu = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
pcu->type = PC_NONE;
|
||||
pcu->readonly = PC_FALSE;
|
||||
pcu->schema = palaz->schema;
|
||||
pcu->npoints = palaz->npoints;
|
||||
pcu->bounds = palaz->bounds;
|
||||
pcu->stats = pc_stats_clone(palaz->stats);
|
||||
if (size != -1)
|
||||
{
|
||||
size_t datasize;
|
||||
pcu = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
pcu->type = PC_NONE;
|
||||
pcu->readonly = PC_FALSE;
|
||||
pcu->schema = palaz->schema;
|
||||
pcu->npoints = palaz->npoints;
|
||||
pcu->bounds = palaz->bounds;
|
||||
pcu->stats = pc_stats_clone(palaz->stats);
|
||||
|
||||
// not optimal but we have to pass by the context manager otherwise
|
||||
// a segfault happenned (sometimes) during a pcfree of lazperf field
|
||||
datasize = palaz->schema->size * palaz->npoints;
|
||||
pcu->data = (uint8_t*) pcalloc(datasize);
|
||||
memcpy(pcu->data, decompressed, datasize);
|
||||
free(decompressed);
|
||||
// not optimal but we have to pass by the context manager otherwise
|
||||
// a segfault happenned (sometimes) during a pcfree of lazperf field
|
||||
datasize = palaz->schema->size * palaz->npoints;
|
||||
pcu->data = (uint8_t *)pcalloc(datasize);
|
||||
memcpy(pcu->data, decompressed, datasize);
|
||||
free(decompressed);
|
||||
|
||||
pcu->datasize = datasize;
|
||||
pcu->maxpoints = palaz->npoints;
|
||||
}
|
||||
else
|
||||
pcerror("%s: lazperf uncompression failed", __func__);
|
||||
pcu->datasize = datasize;
|
||||
pcu->maxpoints = palaz->npoints;
|
||||
}
|
||||
else
|
||||
pcerror("%s: lazperf uncompression failed", __func__);
|
||||
|
||||
return pcu;
|
||||
return pcu;
|
||||
}
|
||||
|
||||
char *
|
||||
pc_patch_lazperf_to_string(const PCPATCH_LAZPERF *pa)
|
||||
char *pc_patch_lazperf_to_string(const PCPATCH_LAZPERF *pa)
|
||||
{
|
||||
#ifndef HAVE_LAZPERF
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
#endif
|
||||
PCPATCH_UNCOMPRESSED *patch = pc_patch_uncompressed_from_lazperf(pa);
|
||||
char *str = pc_patch_uncompressed_to_string(patch);
|
||||
pc_patch_free((PCPATCH*) patch);
|
||||
return str;
|
||||
PCPATCH_UNCOMPRESSED *patch = pc_patch_uncompressed_from_lazperf(pa);
|
||||
char *str = pc_patch_uncompressed_to_string(patch);
|
||||
pc_patch_free((PCPATCH *)patch);
|
||||
return str;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
pc_patch_lazperf_to_wkb(const PCPATCH_LAZPERF *patch, size_t *wkbsize)
|
||||
uint8_t *pc_patch_lazperf_to_wkb(const PCPATCH_LAZPERF *patch, size_t *wkbsize)
|
||||
{
|
||||
#ifndef HAVE_LAZPERF
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
#else
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression
|
||||
uint32: npoints
|
||||
uint32: lazperfsize
|
||||
uint8[]: lazperfbuffer
|
||||
*/
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression
|
||||
uint32: npoints
|
||||
uint32: lazperfsize
|
||||
uint8[]: lazperfbuffer
|
||||
*/
|
||||
|
||||
uint8_t *buf;
|
||||
char endian = machine_endian();
|
||||
/* endian + pcid + compression + npoints + lazperfsize + lazperf */
|
||||
size_t size = 1 + 4 + 4 + 4 + 4 + patch->lazperfsize;
|
||||
uint8_t *buf;
|
||||
char endian = machine_endian();
|
||||
/* endian + pcid + compression + npoints + lazperfsize + lazperf */
|
||||
size_t size = 1 + 4 + 4 + 4 + 4 + patch->lazperfsize;
|
||||
|
||||
uint8_t *wkb = pcalloc(size);
|
||||
uint32_t compression = patch->type;
|
||||
uint32_t npoints = patch->npoints;
|
||||
uint32_t pcid = patch->schema->pcid;
|
||||
uint32_t lazperfsize = patch->lazperfsize;
|
||||
wkb[0] = endian; /* Write endian flag */
|
||||
memcpy(wkb + 1, &pcid, 4); /* Write PCID */
|
||||
memcpy(wkb + 5, &compression, 4); /* Write compression */
|
||||
memcpy(wkb + 9, &npoints, 4); /* Write npoints */
|
||||
memcpy(wkb + 13, &lazperfsize, 4); /* Write lazperf buffer size */
|
||||
uint8_t *wkb = pcalloc(size);
|
||||
uint32_t compression = patch->type;
|
||||
uint32_t npoints = patch->npoints;
|
||||
uint32_t pcid = patch->schema->pcid;
|
||||
uint32_t lazperfsize = patch->lazperfsize;
|
||||
wkb[0] = endian; /* Write endian flag */
|
||||
memcpy(wkb + 1, &pcid, 4); /* Write PCID */
|
||||
memcpy(wkb + 5, &compression, 4); /* Write compression */
|
||||
memcpy(wkb + 9, &npoints, 4); /* Write npoints */
|
||||
memcpy(wkb + 13, &lazperfsize, 4); /* Write lazperf buffer size */
|
||||
|
||||
buf = wkb + 17;
|
||||
memcpy(buf, patch->lazperf, patch->lazperfsize);
|
||||
if (wkbsize)
|
||||
*wkbsize = size;
|
||||
buf = wkb + 17;
|
||||
memcpy(buf, patch->lazperf, patch->lazperfsize);
|
||||
if (wkbsize)
|
||||
*wkbsize = size;
|
||||
|
||||
return wkb;
|
||||
return wkb;
|
||||
#endif
|
||||
}
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_lazperf_from_wkb(const PCSCHEMA *schema, const uint8_t *wkb, size_t wkbsize)
|
||||
PCPATCH *pc_patch_lazperf_from_wkb(const PCSCHEMA *schema, const uint8_t *wkb,
|
||||
size_t wkbsize)
|
||||
{
|
||||
#ifndef HAVE_LAZPERF
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
#else
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
uint32: lazperfsize
|
||||
uint8[]: lazerperfbuffer
|
||||
*/
|
||||
static size_t hdrsz = 1+4+4+4; /* endian + pcid + compression + npoints */
|
||||
PCPATCH_LAZPERF *patch;
|
||||
uint8_t swap_endian = (wkb[0] != machine_endian());
|
||||
uint32_t npoints;
|
||||
size_t lazperfsize;
|
||||
const uint8_t *buf;
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
uint32: lazperfsize
|
||||
uint8[]: lazerperfbuffer
|
||||
*/
|
||||
static size_t hdrsz =
|
||||
1 + 4 + 4 + 4; /* endian + pcid + compression + npoints */
|
||||
PCPATCH_LAZPERF *patch;
|
||||
uint8_t swap_endian = (wkb[0] != machine_endian());
|
||||
uint32_t npoints;
|
||||
size_t lazperfsize;
|
||||
const uint8_t *buf;
|
||||
|
||||
if (wkb_get_compression(wkb) != PC_LAZPERF)
|
||||
{
|
||||
pcerror("%s: call with wkb that is not LAZPERF compressed", __func__);
|
||||
return NULL;
|
||||
}
|
||||
if (wkb_get_compression(wkb) != PC_LAZPERF)
|
||||
{
|
||||
pcerror("%s: call with wkb that is not LAZPERF compressed", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
npoints = wkb_get_npoints(wkb);
|
||||
npoints = wkb_get_npoints(wkb);
|
||||
|
||||
patch = pcalloc(sizeof(PCPATCH_LAZPERF));
|
||||
patch->type = PC_LAZPERF;
|
||||
patch->readonly = PC_FALSE;
|
||||
patch->schema = schema;
|
||||
patch->npoints = npoints;
|
||||
patch->stats = NULL;
|
||||
patch = pcalloc(sizeof(PCPATCH_LAZPERF));
|
||||
patch->type = PC_LAZPERF;
|
||||
patch->readonly = PC_FALSE;
|
||||
patch->schema = schema;
|
||||
patch->npoints = npoints;
|
||||
patch->stats = NULL;
|
||||
|
||||
/* Start on the LAZPERF */
|
||||
buf = wkb+hdrsz;
|
||||
lazperfsize = wkb_get_int32(buf, swap_endian);
|
||||
buf += 4;
|
||||
/* Start on the LAZPERF */
|
||||
buf = wkb + hdrsz;
|
||||
lazperfsize = wkb_get_int32(buf, swap_endian);
|
||||
buf += 4;
|
||||
|
||||
/* Copy in the tree buffer */
|
||||
patch->lazperfsize = lazperfsize;
|
||||
patch->lazperf = pcalloc(lazperfsize);
|
||||
memcpy(patch->lazperf, buf, lazperfsize);
|
||||
/* Copy in the tree buffer */
|
||||
patch->lazperfsize = lazperfsize;
|
||||
patch->lazperf = pcalloc(lazperfsize);
|
||||
memcpy(patch->lazperf, buf, lazperfsize);
|
||||
|
||||
return (PCPATCH*)patch;
|
||||
return (PCPATCH *)patch;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
pc_patch_lazperf_compute_extent(PCPATCH_LAZPERF *patch)
|
||||
int pc_patch_lazperf_compute_extent(PCPATCH_LAZPERF *patch)
|
||||
{
|
||||
#ifndef HAVE_LAZPERF
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return PC_FAILURE;
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return PC_FAILURE;
|
||||
#endif
|
||||
|
||||
PCPATCH_UNCOMPRESSED *pau = pc_patch_uncompressed_from_lazperf(patch);
|
||||
return pc_patch_uncompressed_compute_extent(pau);
|
||||
PCPATCH_UNCOMPRESSED *pau = pc_patch_uncompressed_from_lazperf(patch);
|
||||
return pc_patch_uncompressed_compute_extent(pau);
|
||||
}
|
||||
|
||||
PCPOINT *
|
||||
pc_patch_lazperf_pointn(const PCPATCH_LAZPERF *patch, int n)
|
||||
PCPOINT *pc_patch_lazperf_pointn(const PCPATCH_LAZPERF *patch, int n)
|
||||
{
|
||||
#ifndef HAVE_LAZPERF
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
pcerror("%s: lazperf support is not enabled", __func__);
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
PCPOINT *pt = pc_point_make(patch->schema);
|
||||
PCPATCH_UNCOMPRESSED *pau = pc_patch_uncompressed_from_lazperf(patch);
|
||||
size_t size = patch->schema->size;
|
||||
memcpy(pt->data, pau->data + n * size, size);
|
||||
pc_patch_free((PCPATCH*) pau);
|
||||
return pt;
|
||||
PCPOINT *pt = pc_point_make(patch->schema);
|
||||
PCPATCH_UNCOMPRESSED *pau = pc_patch_uncompressed_from_lazperf(patch);
|
||||
size_t size = patch->schema->size;
|
||||
memcpy(pt->data, pau->data + n * size, size);
|
||||
pc_patch_free((PCPATCH *)pau);
|
||||
return pt;
|
||||
}
|
||||
|
||||
@ -1,443 +1,452 @@
|
||||
/***********************************************************************
|
||||
* pc_patch_uncompressed.c
|
||||
*
|
||||
* Pointclound patch handling. Create, get and set values from the
|
||||
* uncompressed PCPATCH structure.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_patch_uncompressed.c
|
||||
*
|
||||
* Pointclound patch handling. Create, get and set values from the
|
||||
* uncompressed PCPATCH structure.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include <assert.h>
|
||||
#include "pc_api_internal.h"
|
||||
#include "stringbuffer.h"
|
||||
#include <assert.h>
|
||||
|
||||
/* TODO: expose to API ? Would require also exposing stringbuffer
|
||||
* See https://github.com/pgpointcloud/pointcloud/issues/74
|
||||
*/
|
||||
* See https://github.com/pgpointcloud/pointcloud/issues/74
|
||||
*/
|
||||
static int
|
||||
pc_patch_uncompressed_to_stringbuffer(const PCPATCH_UNCOMPRESSED *patch, stringbuffer_t *sb)
|
||||
pc_patch_uncompressed_to_stringbuffer(const PCPATCH_UNCOMPRESSED *patch,
|
||||
stringbuffer_t *sb)
|
||||
{
|
||||
PCPOINTLIST *pl;
|
||||
int i, j;
|
||||
PCPOINTLIST *pl;
|
||||
int i, j;
|
||||
|
||||
/* { "pcid":1, "points":[[<dim1>, <dim2>, <dim3>, <dim4>],[<dim1>, <dim2>, <dim3>, <dim4>]] }*/
|
||||
/* { "pcid":1, "points":[[<dim1>, <dim2>, <dim3>, <dim4>],[<dim1>, <dim2>,
|
||||
* <dim3>, <dim4>]] }*/
|
||||
|
||||
/* TODO: reserve space in buffer ? */
|
||||
/* TODO: reserve space in buffer ? */
|
||||
|
||||
pl = pc_pointlist_from_uncompressed(patch);
|
||||
stringbuffer_aprintf(sb, "{\"pcid\":%d,\"pts\":[", patch->schema->pcid);
|
||||
for ( i = 0; i < pl->npoints; i++ )
|
||||
{
|
||||
PCPOINT *pt = pc_pointlist_get_point(pl, i);
|
||||
if ( i ) stringbuffer_append(sb, ",[");
|
||||
else stringbuffer_append(sb, "[");
|
||||
for ( j = 0; j < pt->schema->ndims; j++ )
|
||||
{
|
||||
double d;
|
||||
if ( ! pc_point_get_double_by_index(pt, j, &d))
|
||||
{
|
||||
pcerror("%s: unable to read double at index %d", __func__, j);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
if ( j ) stringbuffer_aprintf(sb, ",%g", d);
|
||||
else stringbuffer_aprintf(sb, "%g", d);
|
||||
}
|
||||
stringbuffer_append(sb, "]");
|
||||
}
|
||||
stringbuffer_append(sb, "]}");
|
||||
pl = pc_pointlist_from_uncompressed(patch);
|
||||
stringbuffer_aprintf(sb, "{\"pcid\":%d,\"pts\":[", patch->schema->pcid);
|
||||
for (i = 0; i < pl->npoints; i++)
|
||||
{
|
||||
PCPOINT *pt = pc_pointlist_get_point(pl, i);
|
||||
if (i)
|
||||
stringbuffer_append(sb, ",[");
|
||||
else
|
||||
stringbuffer_append(sb, "[");
|
||||
for (j = 0; j < pt->schema->ndims; j++)
|
||||
{
|
||||
double d;
|
||||
if (!pc_point_get_double_by_index(pt, j, &d))
|
||||
{
|
||||
pcerror("%s: unable to read double at index %d", __func__, j);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
if (j)
|
||||
stringbuffer_aprintf(sb, ",%g", d);
|
||||
else
|
||||
stringbuffer_aprintf(sb, "%g", d);
|
||||
}
|
||||
stringbuffer_append(sb, "]");
|
||||
}
|
||||
stringbuffer_append(sb, "]}");
|
||||
|
||||
/* All done, copy and clean up */
|
||||
pc_pointlist_free(pl);
|
||||
/* All done, copy and clean up */
|
||||
pc_pointlist_free(pl);
|
||||
|
||||
return PC_SUCCESS;
|
||||
return PC_SUCCESS;
|
||||
}
|
||||
|
||||
char *
|
||||
pc_patch_uncompressed_to_string(const PCPATCH_UNCOMPRESSED *patch)
|
||||
char *pc_patch_uncompressed_to_string(const PCPATCH_UNCOMPRESSED *patch)
|
||||
{
|
||||
stringbuffer_t *sb = stringbuffer_create();
|
||||
char *str;
|
||||
if ( PC_FAILURE == pc_patch_uncompressed_to_stringbuffer(patch, sb) )
|
||||
return NULL;
|
||||
str = stringbuffer_release_string(sb);
|
||||
stringbuffer_destroy(sb);
|
||||
return str;
|
||||
stringbuffer_t *sb = stringbuffer_create();
|
||||
char *str;
|
||||
if (PC_FAILURE == pc_patch_uncompressed_to_stringbuffer(patch, sb))
|
||||
return NULL;
|
||||
str = stringbuffer_release_string(sb);
|
||||
stringbuffer_destroy(sb);
|
||||
return str;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
pc_patch_uncompressed_to_wkb(const PCPATCH_UNCOMPRESSED *patch, size_t *wkbsize)
|
||||
uint8_t *pc_patch_uncompressed_to_wkb(const PCPATCH_UNCOMPRESSED *patch,
|
||||
size_t *wkbsize)
|
||||
{
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
uchar[]: data (interpret relative to pcid)
|
||||
*/
|
||||
char endian = machine_endian();
|
||||
/* endian + pcid + compression + npoints + datasize */
|
||||
size_t size = 1 + 4 + 4 + 4 + patch->datasize;
|
||||
uint8_t *wkb = pcalloc(size);
|
||||
uint32_t compression = patch->type;
|
||||
uint32_t npoints = patch->npoints;
|
||||
uint32_t pcid = patch->schema->pcid;
|
||||
wkb[0] = endian; /* Write endian flag */
|
||||
memcpy(wkb + 1, &pcid, 4); /* Write PCID */
|
||||
memcpy(wkb + 5, &compression, 4); /* Write compression */
|
||||
memcpy(wkb + 9, &npoints, 4); /* Write npoints */
|
||||
memcpy(wkb + 13, patch->data, patch->datasize); /* Write data */
|
||||
if ( wkbsize ) *wkbsize = size;
|
||||
return wkb;
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
uchar[]: data (interpret relative to pcid)
|
||||
*/
|
||||
char endian = machine_endian();
|
||||
/* endian + pcid + compression + npoints + datasize */
|
||||
size_t size = 1 + 4 + 4 + 4 + patch->datasize;
|
||||
uint8_t *wkb = pcalloc(size);
|
||||
uint32_t compression = patch->type;
|
||||
uint32_t npoints = patch->npoints;
|
||||
uint32_t pcid = patch->schema->pcid;
|
||||
wkb[0] = endian; /* Write endian flag */
|
||||
memcpy(wkb + 1, &pcid, 4); /* Write PCID */
|
||||
memcpy(wkb + 5, &compression, 4); /* Write compression */
|
||||
memcpy(wkb + 9, &npoints, 4); /* Write npoints */
|
||||
memcpy(wkb + 13, patch->data, patch->datasize); /* Write data */
|
||||
if (wkbsize)
|
||||
*wkbsize = size;
|
||||
return wkb;
|
||||
}
|
||||
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_uncompressed_from_wkb(const PCSCHEMA *s, const uint8_t *wkb, size_t wkbsize)
|
||||
PCPATCH *pc_patch_uncompressed_from_wkb(const PCSCHEMA *s, const uint8_t *wkb,
|
||||
size_t wkbsize)
|
||||
{
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
pcpoint[]: data (interpret relative to pcid)
|
||||
*/
|
||||
static size_t hdrsz = 1+4+4+4; /* endian + pcid + compression + npoints */
|
||||
PCPATCH_UNCOMPRESSED *patch;
|
||||
uint8_t *data;
|
||||
uint8_t swap_endian = (wkb[0] != machine_endian());
|
||||
uint32_t npoints;
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uint32: compression (0 = no compression, 1 = dimensional, 2 = lazperf)
|
||||
uint32: npoints
|
||||
pcpoint[]: data (interpret relative to pcid)
|
||||
*/
|
||||
static size_t hdrsz =
|
||||
1 + 4 + 4 + 4; /* endian + pcid + compression + npoints */
|
||||
PCPATCH_UNCOMPRESSED *patch;
|
||||
uint8_t *data;
|
||||
uint8_t swap_endian = (wkb[0] != machine_endian());
|
||||
uint32_t npoints;
|
||||
|
||||
if ( wkb_get_compression(wkb) != PC_NONE )
|
||||
{
|
||||
pcerror("%s: call with wkb that is not uncompressed", __func__);
|
||||
return NULL;
|
||||
}
|
||||
if (wkb_get_compression(wkb) != PC_NONE)
|
||||
{
|
||||
pcerror("%s: call with wkb that is not uncompressed", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
npoints = wkb_get_npoints(wkb);
|
||||
if ( (wkbsize - hdrsz) != (s->size * npoints) )
|
||||
{
|
||||
pcerror("%s: wkb size and expected data size do not match", __func__);
|
||||
return NULL;
|
||||
}
|
||||
npoints = wkb_get_npoints(wkb);
|
||||
if ((wkbsize - hdrsz) != (s->size * npoints))
|
||||
{
|
||||
pcerror("%s: wkb size and expected data size do not match", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( swap_endian )
|
||||
{
|
||||
data = uncompressed_bytes_flip_endian(wkb+hdrsz, s, npoints);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = pcalloc(npoints * s->size);
|
||||
memcpy(data, wkb+hdrsz, npoints*s->size);
|
||||
}
|
||||
if (swap_endian)
|
||||
{
|
||||
data = uncompressed_bytes_flip_endian(wkb + hdrsz, s, npoints);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = pcalloc(npoints * s->size);
|
||||
memcpy(data, wkb + hdrsz, npoints * s->size);
|
||||
}
|
||||
|
||||
patch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
patch->type = PC_NONE;
|
||||
patch->readonly = PC_FALSE;
|
||||
patch->schema = s;
|
||||
patch->npoints = npoints;
|
||||
patch->maxpoints = npoints;
|
||||
patch->datasize = (wkbsize - hdrsz);
|
||||
patch->data = data;
|
||||
patch->stats = NULL;
|
||||
patch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
patch->type = PC_NONE;
|
||||
patch->readonly = PC_FALSE;
|
||||
patch->schema = s;
|
||||
patch->npoints = npoints;
|
||||
patch->maxpoints = npoints;
|
||||
patch->datasize = (wkbsize - hdrsz);
|
||||
patch->data = data;
|
||||
patch->stats = NULL;
|
||||
|
||||
return (PCPATCH*)patch;
|
||||
return (PCPATCH *)patch;
|
||||
}
|
||||
|
||||
PCPATCH_UNCOMPRESSED *
|
||||
pc_patch_uncompressed_make(const PCSCHEMA *s, uint32_t maxpoints)
|
||||
PCPATCH_UNCOMPRESSED *pc_patch_uncompressed_make(const PCSCHEMA *s,
|
||||
uint32_t maxpoints)
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *pch;
|
||||
size_t datasize;
|
||||
PCPATCH_UNCOMPRESSED *pch;
|
||||
size_t datasize;
|
||||
|
||||
if ( ! s )
|
||||
{
|
||||
pcerror("%s: null schema passed in", __func__);
|
||||
return NULL;
|
||||
}
|
||||
if (!s)
|
||||
{
|
||||
pcerror("%s: null schema passed in", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Width of the data area */
|
||||
if ( ! s->size )
|
||||
{
|
||||
pcerror("%s, invalid size calculation", __func__);
|
||||
return NULL;
|
||||
}
|
||||
/* Width of the data area */
|
||||
if (!s->size)
|
||||
{
|
||||
pcerror("%s, invalid size calculation", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Set up basic info */
|
||||
pch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
pch->type = PC_NONE;
|
||||
pch->readonly = PC_FALSE;
|
||||
pch->schema = s;
|
||||
pch->npoints = 0;
|
||||
pch->stats = NULL;
|
||||
pch->maxpoints = maxpoints;
|
||||
/* Set up basic info */
|
||||
pch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
pch->type = PC_NONE;
|
||||
pch->readonly = PC_FALSE;
|
||||
pch->schema = s;
|
||||
pch->npoints = 0;
|
||||
pch->stats = NULL;
|
||||
pch->maxpoints = maxpoints;
|
||||
|
||||
/* Make our own data area */
|
||||
datasize = s->size * maxpoints;
|
||||
pch->datasize = datasize;
|
||||
pch->data = NULL;
|
||||
if ( datasize )
|
||||
{
|
||||
pch->data = pcalloc(datasize);
|
||||
}
|
||||
pc_bounds_init(&(pch->bounds));
|
||||
/* Make our own data area */
|
||||
datasize = s->size * maxpoints;
|
||||
pch->datasize = datasize;
|
||||
pch->data = NULL;
|
||||
if (datasize)
|
||||
{
|
||||
pch->data = pcalloc(datasize);
|
||||
}
|
||||
pc_bounds_init(&(pch->bounds));
|
||||
|
||||
return pch;
|
||||
return pch;
|
||||
}
|
||||
|
||||
int
|
||||
pc_patch_uncompressed_compute_extent(PCPATCH_UNCOMPRESSED *patch)
|
||||
int pc_patch_uncompressed_compute_extent(PCPATCH_UNCOMPRESSED *patch)
|
||||
{
|
||||
int i;
|
||||
PCPOINT *pt = pc_point_from_data(patch->schema, patch->data);
|
||||
PCBOUNDS b;
|
||||
double x, y;
|
||||
int i;
|
||||
PCPOINT *pt = pc_point_from_data(patch->schema, patch->data);
|
||||
PCBOUNDS b;
|
||||
double x, y;
|
||||
|
||||
/* Calculate bounds */
|
||||
pc_bounds_init(&b);
|
||||
for ( i = 0; i < patch->npoints; i++ )
|
||||
{
|
||||
/* Just push the data buffer forward by one point at a time */
|
||||
pt->data = patch->data + i * patch->schema->size;
|
||||
pc_point_get_x(pt, &x);
|
||||
pc_point_get_y(pt, &y);
|
||||
if ( b.xmin > x ) b.xmin = x;
|
||||
if ( b.ymin > y ) b.ymin = y;
|
||||
if ( b.xmax < x ) b.xmax = x;
|
||||
if ( b.ymax < y ) b.ymax = y;
|
||||
}
|
||||
/* Calculate bounds */
|
||||
pc_bounds_init(&b);
|
||||
for (i = 0; i < patch->npoints; i++)
|
||||
{
|
||||
/* Just push the data buffer forward by one point at a time */
|
||||
pt->data = patch->data + i * patch->schema->size;
|
||||
pc_point_get_x(pt, &x);
|
||||
pc_point_get_y(pt, &y);
|
||||
if (b.xmin > x)
|
||||
b.xmin = x;
|
||||
if (b.ymin > y)
|
||||
b.ymin = y;
|
||||
if (b.xmax < x)
|
||||
b.xmax = x;
|
||||
if (b.ymax < y)
|
||||
b.ymax = y;
|
||||
}
|
||||
|
||||
patch->bounds = b;
|
||||
pcfree(pt);
|
||||
return PC_SUCCESS;
|
||||
patch->bounds = b;
|
||||
pcfree(pt);
|
||||
return PC_SUCCESS;
|
||||
}
|
||||
|
||||
void
|
||||
pc_patch_uncompressed_free(PCPATCH_UNCOMPRESSED *patch)
|
||||
void pc_patch_uncompressed_free(PCPATCH_UNCOMPRESSED *patch)
|
||||
{
|
||||
assert(patch);
|
||||
assert(patch->schema);
|
||||
assert(patch);
|
||||
assert(patch->schema);
|
||||
|
||||
pc_patch_free_stats((PCPATCH*) patch);
|
||||
pc_patch_free_stats((PCPATCH *)patch);
|
||||
|
||||
if ( patch->data && ! patch->readonly )
|
||||
{
|
||||
pcfree(patch->data);
|
||||
}
|
||||
pcfree(patch);
|
||||
if (patch->data && !patch->readonly)
|
||||
{
|
||||
pcfree(patch->data);
|
||||
}
|
||||
pcfree(patch);
|
||||
}
|
||||
|
||||
// Make the patch readonly. Return the memory segment
|
||||
// owned by the patch, if any, to enable transfer of ownership
|
||||
uint8_t *
|
||||
pc_patch_uncompressed_readonly(PCPATCH_UNCOMPRESSED *patch)
|
||||
uint8_t *pc_patch_uncompressed_readonly(PCPATCH_UNCOMPRESSED *patch)
|
||||
{
|
||||
uint8_t *data = patch->readonly ? NULL : patch->data;
|
||||
patch->readonly = PC_TRUE;
|
||||
return data;
|
||||
uint8_t *data = patch->readonly ? NULL : patch->data;
|
||||
patch->readonly = PC_TRUE;
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
PCPATCH_UNCOMPRESSED *
|
||||
pc_patch_uncompressed_from_pointlist(const PCPOINTLIST *pl)
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *pch;
|
||||
const PCSCHEMA *s;
|
||||
PCPOINT *pt;
|
||||
uint8_t *ptr;
|
||||
int i;
|
||||
uint32_t numpts;
|
||||
PCPATCH_UNCOMPRESSED *pch;
|
||||
const PCSCHEMA *s;
|
||||
PCPOINT *pt;
|
||||
uint8_t *ptr;
|
||||
int i;
|
||||
uint32_t numpts;
|
||||
|
||||
if ( ! pl )
|
||||
{
|
||||
pcerror("%s: null PCPOINTLIST passed in", __func__);
|
||||
return NULL;
|
||||
}
|
||||
if (!pl)
|
||||
{
|
||||
pcerror("%s: null PCPOINTLIST passed in", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
numpts = pl->npoints;
|
||||
if ( ! numpts )
|
||||
{
|
||||
pcerror("%s: zero size PCPOINTLIST passed in", __func__);
|
||||
return NULL;
|
||||
}
|
||||
numpts = pl->npoints;
|
||||
if (!numpts)
|
||||
{
|
||||
pcerror("%s: zero size PCPOINTLIST passed in", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Assume the first PCSCHEMA is the same as the rest for now */
|
||||
/* We will check this as we go along */
|
||||
pt = pc_pointlist_get_point(pl, 0);
|
||||
s = pt->schema;
|
||||
/* Assume the first PCSCHEMA is the same as the rest for now */
|
||||
/* We will check this as we go along */
|
||||
pt = pc_pointlist_get_point(pl, 0);
|
||||
s = pt->schema;
|
||||
|
||||
/* Confirm we have a schema pointer */
|
||||
if ( ! s )
|
||||
{
|
||||
pcerror("%s: null schema encountered", __func__);
|
||||
return NULL;
|
||||
}
|
||||
/* Confirm we have a schema pointer */
|
||||
if (!s)
|
||||
{
|
||||
pcerror("%s: null schema encountered", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Confirm width of a point data buffer */
|
||||
if ( ! s->size )
|
||||
{
|
||||
pcerror("%s: invalid point size", __func__);
|
||||
return NULL;
|
||||
}
|
||||
/* Confirm width of a point data buffer */
|
||||
if (!s->size)
|
||||
{
|
||||
pcerror("%s: invalid point size", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make our own data area */
|
||||
pch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
pch->datasize = s->size * numpts;
|
||||
pch->data = pcalloc(pch->datasize);
|
||||
pch->stats = NULL;
|
||||
ptr = pch->data;
|
||||
/* Make our own data area */
|
||||
pch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
pch->datasize = s->size * numpts;
|
||||
pch->data = pcalloc(pch->datasize);
|
||||
pch->stats = NULL;
|
||||
ptr = pch->data;
|
||||
|
||||
/* Initialize bounds */
|
||||
pc_bounds_init(&(pch->bounds));
|
||||
/* Initialize bounds */
|
||||
pc_bounds_init(&(pch->bounds));
|
||||
|
||||
/* Set up basic info */
|
||||
pch->readonly = PC_FALSE;
|
||||
pch->maxpoints = numpts;
|
||||
pch->type = PC_NONE;
|
||||
pch->schema = s;
|
||||
pch->npoints = 0;
|
||||
/* Set up basic info */
|
||||
pch->readonly = PC_FALSE;
|
||||
pch->maxpoints = numpts;
|
||||
pch->type = PC_NONE;
|
||||
pch->schema = s;
|
||||
pch->npoints = 0;
|
||||
|
||||
for ( i = 0; i < numpts; i++ )
|
||||
{
|
||||
pt = pc_pointlist_get_point(pl, i);
|
||||
if ( pt )
|
||||
{
|
||||
if ( pt->schema->pcid != s->pcid )
|
||||
{
|
||||
pcerror("%s: points do not share a schema", __func__);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ptr, pt->data, s->size);
|
||||
pch->npoints++;
|
||||
ptr += s->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcwarn("%s: encountered null point", __func__);
|
||||
}
|
||||
}
|
||||
for (i = 0; i < numpts; i++)
|
||||
{
|
||||
pt = pc_pointlist_get_point(pl, i);
|
||||
if (pt)
|
||||
{
|
||||
if (pt->schema->pcid != s->pcid)
|
||||
{
|
||||
pcerror("%s: points do not share a schema", __func__);
|
||||
return NULL;
|
||||
}
|
||||
memcpy(ptr, pt->data, s->size);
|
||||
pch->npoints++;
|
||||
ptr += s->size;
|
||||
}
|
||||
else
|
||||
{
|
||||
pcwarn("%s: encountered null point", __func__);
|
||||
}
|
||||
}
|
||||
|
||||
if ( PC_FAILURE == pc_patch_uncompressed_compute_extent(pch) )
|
||||
{
|
||||
pcerror("%s: failed to compute patch extent", __func__);
|
||||
return NULL;
|
||||
}
|
||||
if (PC_FAILURE == pc_patch_uncompressed_compute_extent(pch))
|
||||
{
|
||||
pcerror("%s: failed to compute patch extent", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( PC_FAILURE == pc_patch_uncompressed_compute_stats(pch) )
|
||||
{
|
||||
pcerror("%s: failed to compute patch stats", __func__);
|
||||
return NULL;
|
||||
}
|
||||
if (PC_FAILURE == pc_patch_uncompressed_compute_stats(pch))
|
||||
{
|
||||
pcerror("%s: failed to compute patch stats", __func__);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return pch;
|
||||
return pch;
|
||||
}
|
||||
|
||||
|
||||
PCPATCH_UNCOMPRESSED *
|
||||
pc_patch_uncompressed_from_dimensional(const PCPATCH_DIMENSIONAL *pdl)
|
||||
{
|
||||
int i, j, npoints;
|
||||
PCPATCH_UNCOMPRESSED *patch;
|
||||
PCPATCH_DIMENSIONAL *pdl_uncompressed;
|
||||
const PCSCHEMA *schema;
|
||||
uint8_t *buf;
|
||||
int i, j, npoints;
|
||||
PCPATCH_UNCOMPRESSED *patch;
|
||||
PCPATCH_DIMENSIONAL *pdl_uncompressed;
|
||||
const PCSCHEMA *schema;
|
||||
uint8_t *buf;
|
||||
|
||||
npoints = pdl->npoints;
|
||||
schema = pdl->schema;
|
||||
patch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
patch->type = PC_NONE;
|
||||
patch->readonly = PC_FALSE;
|
||||
patch->schema = schema;
|
||||
patch->npoints = npoints;
|
||||
patch->maxpoints = npoints;
|
||||
patch->bounds = pdl->bounds;
|
||||
patch->stats = pc_stats_clone(pdl->stats);
|
||||
patch->datasize = schema->size * pdl->npoints;
|
||||
patch->data = pcalloc(patch->datasize);
|
||||
buf = patch->data;
|
||||
npoints = pdl->npoints;
|
||||
schema = pdl->schema;
|
||||
patch = pcalloc(sizeof(PCPATCH_UNCOMPRESSED));
|
||||
patch->type = PC_NONE;
|
||||
patch->readonly = PC_FALSE;
|
||||
patch->schema = schema;
|
||||
patch->npoints = npoints;
|
||||
patch->maxpoints = npoints;
|
||||
patch->bounds = pdl->bounds;
|
||||
patch->stats = pc_stats_clone(pdl->stats);
|
||||
patch->datasize = schema->size * pdl->npoints;
|
||||
patch->data = pcalloc(patch->datasize);
|
||||
buf = patch->data;
|
||||
|
||||
/* Can only read from uncompressed dimensions */
|
||||
pdl_uncompressed = pc_patch_dimensional_decompress(pdl);
|
||||
/* Can only read from uncompressed dimensions */
|
||||
pdl_uncompressed = pc_patch_dimensional_decompress(pdl);
|
||||
|
||||
for ( i = 0; i < npoints; i++ )
|
||||
{
|
||||
for ( j = 0; j < schema->ndims; j++ )
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(schema, j);
|
||||
uint8_t *in = pdl_uncompressed->bytes[j].bytes + dim->size * i;
|
||||
uint8_t *out = buf + dim->byteoffset;
|
||||
memcpy(out, in, dim->size);
|
||||
}
|
||||
buf += schema->size;
|
||||
}
|
||||
for (i = 0; i < npoints; i++)
|
||||
{
|
||||
for (j = 0; j < schema->ndims; j++)
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(schema, j);
|
||||
uint8_t *in = pdl_uncompressed->bytes[j].bytes + dim->size * i;
|
||||
uint8_t *out = buf + dim->byteoffset;
|
||||
memcpy(out, in, dim->size);
|
||||
}
|
||||
buf += schema->size;
|
||||
}
|
||||
|
||||
pc_patch_dimensional_free(pdl_uncompressed);
|
||||
pc_patch_dimensional_free(pdl_uncompressed);
|
||||
|
||||
return patch;
|
||||
return patch;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pc_patch_uncompressed_add_point(PCPATCH_UNCOMPRESSED *c, const PCPOINT *p)
|
||||
int pc_patch_uncompressed_add_point(PCPATCH_UNCOMPRESSED *c, const PCPOINT *p)
|
||||
{
|
||||
size_t sz;
|
||||
uint8_t *ptr;
|
||||
double x, y;
|
||||
size_t sz;
|
||||
uint8_t *ptr;
|
||||
double x, y;
|
||||
|
||||
if ( ! ( c && p ) )
|
||||
{
|
||||
pcerror("%s: null point or patch argument", __func__);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
if (!(c && p))
|
||||
{
|
||||
pcerror("%s: null point or patch argument", __func__);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
|
||||
if ( c->schema->pcid != p->schema->pcid )
|
||||
{
|
||||
pcerror("%s: pcids of point (%d) and patch (%d) not equal", __func__, c->schema->pcid, p->schema->pcid);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
if (c->schema->pcid != p->schema->pcid)
|
||||
{
|
||||
pcerror("%s: pcids of point (%d) and patch (%d) not equal", __func__,
|
||||
c->schema->pcid, p->schema->pcid);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
|
||||
if ( c->readonly )
|
||||
{
|
||||
pcerror("%s: cannot add point to readonly patch", __func__);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
if (c->readonly)
|
||||
{
|
||||
pcerror("%s: cannot add point to readonly patch", __func__);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
|
||||
if ( c->type != PC_NONE )
|
||||
{
|
||||
pcerror("%s: cannot add point to compressed patch", __func__);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
if (c->type != PC_NONE)
|
||||
{
|
||||
pcerror("%s: cannot add point to compressed patch", __func__);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
|
||||
sz = c->schema->size;
|
||||
sz = c->schema->size;
|
||||
|
||||
/* Double the data buffer if it's already full */
|
||||
if ( c->npoints == c->maxpoints )
|
||||
{
|
||||
c->maxpoints *= 2;
|
||||
c->datasize = c->maxpoints * sz;
|
||||
c->data = pcrealloc(c->data, c->datasize);
|
||||
}
|
||||
/* Double the data buffer if it's already full */
|
||||
if (c->npoints == c->maxpoints)
|
||||
{
|
||||
c->maxpoints *= 2;
|
||||
c->datasize = c->maxpoints * sz;
|
||||
c->data = pcrealloc(c->data, c->datasize);
|
||||
}
|
||||
|
||||
/* Copy the data buffer from point to patch */
|
||||
ptr = c->data + sz * c->npoints;
|
||||
memcpy(ptr, p->data, sz);
|
||||
c->npoints += 1;
|
||||
/* Copy the data buffer from point to patch */
|
||||
ptr = c->data + sz * c->npoints;
|
||||
memcpy(ptr, p->data, sz);
|
||||
c->npoints += 1;
|
||||
|
||||
/* Update bounding box */
|
||||
pc_point_get_x(p, &x);
|
||||
pc_point_get_y(p, &y);
|
||||
if ( c->bounds.xmin > x ) c->bounds.xmin = x;
|
||||
if ( c->bounds.ymin > y ) c->bounds.ymin = y;
|
||||
if ( c->bounds.xmax < x ) c->bounds.xmax = x;
|
||||
if ( c->bounds.ymax < y ) c->bounds.ymax = y;
|
||||
/* Update bounding box */
|
||||
pc_point_get_x(p, &x);
|
||||
pc_point_get_y(p, &y);
|
||||
if (c->bounds.xmin > x)
|
||||
c->bounds.xmin = x;
|
||||
if (c->bounds.ymin > y)
|
||||
c->bounds.ymin = y;
|
||||
if (c->bounds.xmax < x)
|
||||
c->bounds.xmax = x;
|
||||
if (c->bounds.ymax < y)
|
||||
c->bounds.ymax = y;
|
||||
|
||||
return PC_SUCCESS;
|
||||
return PC_SUCCESS;
|
||||
}
|
||||
|
||||
/** get point n, 0-based, positive */
|
||||
PCPOINT *pc_patch_uncompressed_pointn(const PCPATCH_UNCOMPRESSED *patch, int n)
|
||||
{
|
||||
return pc_point_from_data(patch->schema, patch->data+n*patch->schema->size);
|
||||
return pc_point_from_data(patch->schema,
|
||||
patch->data + n * patch->schema->size);
|
||||
}
|
||||
|
||||
581
lib/pc_point.c
581
lib/pc_point.c
@ -1,414 +1,395 @@
|
||||
/***********************************************************************
|
||||
* pc_point.c
|
||||
*
|
||||
* Pointclound point handling. Create, get and set values from the
|
||||
* basic PCPOINT structure.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_point.c
|
||||
*
|
||||
* Pointclound point handling. Create, get and set values from the
|
||||
* basic PCPOINT structure.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "pc_api_internal.h"
|
||||
#include "stringbuffer.h"
|
||||
|
||||
PCPOINT *
|
||||
pc_point_make(const PCSCHEMA *s)
|
||||
PCPOINT *pc_point_make(const PCSCHEMA *s)
|
||||
{
|
||||
size_t sz;
|
||||
PCPOINT *pt;
|
||||
size_t sz;
|
||||
PCPOINT *pt;
|
||||
|
||||
if ( ! s )
|
||||
{
|
||||
pcerror("null schema passed into pc_point_make");
|
||||
return NULL;
|
||||
}
|
||||
if (!s)
|
||||
{
|
||||
pcerror("null schema passed into pc_point_make");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Width of the data area */
|
||||
sz = s->size;
|
||||
if ( ! sz )
|
||||
{
|
||||
pcerror("invalid size calculation in pc_point_make");
|
||||
return NULL;
|
||||
}
|
||||
/* Width of the data area */
|
||||
sz = s->size;
|
||||
if (!sz)
|
||||
{
|
||||
pcerror("invalid size calculation in pc_point_make");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make our own data area */
|
||||
pt = pcalloc(sizeof(PCPOINT));
|
||||
pt->data = pcalloc(sz);
|
||||
/* Make our own data area */
|
||||
pt = pcalloc(sizeof(PCPOINT));
|
||||
pt->data = pcalloc(sz);
|
||||
|
||||
/* Set up basic info */
|
||||
pt->schema = s;
|
||||
pt->readonly = PC_FALSE;
|
||||
return pt;
|
||||
/* Set up basic info */
|
||||
pt->schema = s;
|
||||
pt->readonly = PC_FALSE;
|
||||
return pt;
|
||||
};
|
||||
|
||||
PCPOINT *
|
||||
pc_point_from_data(const PCSCHEMA *s, const uint8_t *data)
|
||||
PCPOINT *pc_point_from_data(const PCSCHEMA *s, const uint8_t *data)
|
||||
{
|
||||
PCPOINT *pt;
|
||||
PCPOINT *pt;
|
||||
|
||||
if ( ! s )
|
||||
{
|
||||
pcerror("null schema passed into pc_point_from_data");
|
||||
return NULL;
|
||||
}
|
||||
if (!s)
|
||||
{
|
||||
pcerror("null schema passed into pc_point_from_data");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Reference the external data */
|
||||
pt = pcalloc(sizeof(PCPOINT));
|
||||
pt->data = (uint8_t*)data;
|
||||
/* Reference the external data */
|
||||
pt = pcalloc(sizeof(PCPOINT));
|
||||
pt->data = (uint8_t *)data;
|
||||
|
||||
/* Set up basic info */
|
||||
pt->schema = s;
|
||||
pt->readonly = PC_TRUE;
|
||||
return pt;
|
||||
/* Set up basic info */
|
||||
pt->schema = s;
|
||||
pt->readonly = PC_TRUE;
|
||||
return pt;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
pc_point_free(PCPOINT *pt)
|
||||
void pc_point_free(PCPOINT *pt)
|
||||
{
|
||||
if ( ! pt->readonly )
|
||||
{
|
||||
pcfree(pt->data);
|
||||
}
|
||||
pcfree(pt);
|
||||
if (!pt->readonly)
|
||||
{
|
||||
pcfree(pt->data);
|
||||
}
|
||||
pcfree(pt);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_get_double(const PCPOINT *pt, const PCDIMENSION *dim, double *val)
|
||||
int pc_point_get_double(const PCPOINT *pt, const PCDIMENSION *dim, double *val)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
double d;
|
||||
uint8_t *ptr;
|
||||
double d;
|
||||
|
||||
if ( ! dim ) return PC_FAILURE;
|
||||
if (!dim)
|
||||
return PC_FAILURE;
|
||||
|
||||
/* Read raw value from byte buffer */
|
||||
ptr = pt->data + dim->byteoffset;
|
||||
d = pc_double_from_ptr(ptr, dim->interpretation);
|
||||
d = pc_value_scale_offset(d, dim);
|
||||
/* Read raw value from byte buffer */
|
||||
ptr = pt->data + dim->byteoffset;
|
||||
d = pc_double_from_ptr(ptr, dim->interpretation);
|
||||
d = pc_value_scale_offset(d, dim);
|
||||
|
||||
*val = d;
|
||||
return PC_SUCCESS;
|
||||
*val = d;
|
||||
return PC_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_get_double_by_name(const PCPOINT *pt, const char *name, double *val)
|
||||
int pc_point_get_double_by_name(const PCPOINT *pt, const char *name,
|
||||
double *val)
|
||||
{
|
||||
PCDIMENSION *dim;
|
||||
dim = pc_schema_get_dimension_by_name(pt->schema, name);
|
||||
return pc_point_get_double(pt, dim, val);
|
||||
PCDIMENSION *dim;
|
||||
dim = pc_schema_get_dimension_by_name(pt->schema, name);
|
||||
return pc_point_get_double(pt, dim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_get_double_by_index(const PCPOINT *pt, uint32_t idx, double *val)
|
||||
int pc_point_get_double_by_index(const PCPOINT *pt, uint32_t idx, double *val)
|
||||
{
|
||||
PCDIMENSION *dim;
|
||||
dim = pc_schema_get_dimension(pt->schema, idx);
|
||||
return pc_point_get_double(pt, dim, val);
|
||||
PCDIMENSION *dim;
|
||||
dim = pc_schema_get_dimension(pt->schema, idx);
|
||||
return pc_point_get_double(pt, dim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_set_double(PCPOINT *pt, const PCDIMENSION *dim, double val)
|
||||
int pc_point_set_double(PCPOINT *pt, const PCDIMENSION *dim, double val)
|
||||
{
|
||||
uint8_t *ptr;
|
||||
uint8_t *ptr;
|
||||
|
||||
if ( ! dim ) return PC_FAILURE;
|
||||
if (!dim)
|
||||
return PC_FAILURE;
|
||||
|
||||
/* Remove scale and offsets */
|
||||
val = pc_value_unscale_unoffset(val, dim);
|
||||
/* Remove scale and offsets */
|
||||
val = pc_value_unscale_unoffset(val, dim);
|
||||
|
||||
/* Get pointer into byte buffer */
|
||||
ptr = pt->data + dim->byteoffset;
|
||||
/* Get pointer into byte buffer */
|
||||
ptr = pt->data + dim->byteoffset;
|
||||
|
||||
return pc_double_to_ptr(ptr, dim->interpretation, val);
|
||||
return pc_double_to_ptr(ptr, dim->interpretation, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_set_double_by_index(PCPOINT *pt, uint32_t idx, double val)
|
||||
int pc_point_set_double_by_index(PCPOINT *pt, uint32_t idx, double val)
|
||||
{
|
||||
PCDIMENSION *dim;
|
||||
dim = pc_schema_get_dimension(pt->schema, idx);
|
||||
return pc_point_set_double(pt, dim, val);
|
||||
PCDIMENSION *dim;
|
||||
dim = pc_schema_get_dimension(pt->schema, idx);
|
||||
return pc_point_set_double(pt, dim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_set_double_by_name(PCPOINT *pt, const char *name, double val)
|
||||
int pc_point_set_double_by_name(PCPOINT *pt, const char *name, double val)
|
||||
{
|
||||
PCDIMENSION *dim;
|
||||
dim = pc_schema_get_dimension_by_name(pt->schema, name);
|
||||
return pc_point_set_double(pt, dim, val);
|
||||
PCDIMENSION *dim;
|
||||
dim = pc_schema_get_dimension_by_name(pt->schema, name);
|
||||
return pc_point_set_double(pt, dim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_get_x(const PCPOINT *pt, double *val)
|
||||
int pc_point_get_x(const PCPOINT *pt, double *val)
|
||||
{
|
||||
return pc_point_get_double(pt, pt->schema->xdim, val);
|
||||
return pc_point_get_double(pt, pt->schema->xdim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_get_y(const PCPOINT *pt, double *val)
|
||||
int pc_point_get_y(const PCPOINT *pt, double *val)
|
||||
{
|
||||
return pc_point_get_double(pt, pt->schema->ydim, val);
|
||||
return pc_point_get_double(pt, pt->schema->ydim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_get_z(const PCPOINT *pt, double *val)
|
||||
int pc_point_get_z(const PCPOINT *pt, double *val)
|
||||
{
|
||||
return pc_point_get_double(pt, pt->schema->zdim, val);
|
||||
return pc_point_get_double(pt, pt->schema->zdim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_get_m(const PCPOINT *pt, double *val)
|
||||
int pc_point_get_m(const PCPOINT *pt, double *val)
|
||||
{
|
||||
return pc_point_get_double(pt, pt->schema->mdim, val);
|
||||
return pc_point_get_double(pt, pt->schema->mdim, val);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
pc_point_set_x(PCPOINT *pt, double val)
|
||||
int pc_point_set_x(PCPOINT *pt, double val)
|
||||
{
|
||||
return pc_point_set_double(pt, pt->schema->xdim, val);
|
||||
return pc_point_set_double(pt, pt->schema->xdim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_set_y(PCPOINT *pt, double val)
|
||||
int pc_point_set_y(PCPOINT *pt, double val)
|
||||
{
|
||||
return pc_point_set_double(pt, pt->schema->ydim, val);
|
||||
return pc_point_set_double(pt, pt->schema->ydim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_set_z(PCPOINT *pt, double val)
|
||||
int pc_point_set_z(PCPOINT *pt, double val)
|
||||
{
|
||||
return pc_point_set_double(pt, pt->schema->zdim, val);
|
||||
return pc_point_set_double(pt, pt->schema->zdim, val);
|
||||
}
|
||||
|
||||
int
|
||||
pc_point_set_m(PCPOINT *pt, double val)
|
||||
int pc_point_set_m(PCPOINT *pt, double val)
|
||||
{
|
||||
return pc_point_set_double(pt, pt->schema->mdim, val);
|
||||
return pc_point_set_double(pt, pt->schema->mdim, val);
|
||||
}
|
||||
|
||||
char *
|
||||
pc_point_to_string(const PCPOINT *pt)
|
||||
char *pc_point_to_string(const PCPOINT *pt)
|
||||
{
|
||||
/* { "pcid":1, "values":[<dim1>, <dim2>, <dim3>, <dim4>] }*/
|
||||
stringbuffer_t *sb = stringbuffer_create();
|
||||
char *str;
|
||||
int i;
|
||||
/* { "pcid":1, "values":[<dim1>, <dim2>, <dim3>, <dim4>] }*/
|
||||
stringbuffer_t *sb = stringbuffer_create();
|
||||
char *str;
|
||||
int i;
|
||||
|
||||
stringbuffer_aprintf(sb, "{\"pcid\":%d,\"pt\":[", pt->schema->pcid);
|
||||
for ( i = 0; i < pt->schema->ndims; i++ )
|
||||
{
|
||||
double d;
|
||||
if ( ! pc_point_get_double_by_index(pt, i, &d) )
|
||||
{
|
||||
pcerror("pc_point_to_string: unable to read double at position %d", i);
|
||||
}
|
||||
if ( i )
|
||||
{
|
||||
stringbuffer_append(sb, ",");
|
||||
}
|
||||
stringbuffer_aprintf(sb, "%g", d);
|
||||
}
|
||||
stringbuffer_append(sb, "]}");
|
||||
str = stringbuffer_getstringcopy(sb);
|
||||
stringbuffer_destroy(sb);
|
||||
return str;
|
||||
stringbuffer_aprintf(sb, "{\"pcid\":%d,\"pt\":[", pt->schema->pcid);
|
||||
for (i = 0; i < pt->schema->ndims; i++)
|
||||
{
|
||||
double d;
|
||||
if (!pc_point_get_double_by_index(pt, i, &d))
|
||||
{
|
||||
pcerror("pc_point_to_string: unable to read double at position %d", i);
|
||||
}
|
||||
if (i)
|
||||
{
|
||||
stringbuffer_append(sb, ",");
|
||||
}
|
||||
stringbuffer_aprintf(sb, "%g", d);
|
||||
}
|
||||
stringbuffer_append(sb, "]}");
|
||||
str = stringbuffer_getstringcopy(sb);
|
||||
stringbuffer_destroy(sb);
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
PCPOINT *
|
||||
pc_point_from_double_array(const PCSCHEMA *s, double *array, uint32_t offset, uint32_t stride)
|
||||
PCPOINT *pc_point_from_double_array(const PCSCHEMA *s, double *array,
|
||||
uint32_t offset, uint32_t stride)
|
||||
{
|
||||
int i;
|
||||
PCPOINT *pt;
|
||||
int i;
|
||||
PCPOINT *pt;
|
||||
|
||||
if ( ! s )
|
||||
{
|
||||
pcerror("null schema passed into pc_point_from_double_array");
|
||||
return NULL;
|
||||
}
|
||||
if (!s)
|
||||
{
|
||||
pcerror("null schema passed into pc_point_from_double_array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( stride != s->ndims )
|
||||
{
|
||||
pcerror("number of elements in schema and array do not match in pc_point_from_double_array");
|
||||
return NULL;
|
||||
}
|
||||
if (stride != s->ndims)
|
||||
{
|
||||
pcerror("number of elements in schema and array do not match in "
|
||||
"pc_point_from_double_array");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Reference the external data */
|
||||
pt = pcalloc(sizeof(PCPOINT));
|
||||
pt->data = pcalloc(s->size);
|
||||
pt->schema = s;
|
||||
pt->readonly = PC_FALSE;
|
||||
/* Reference the external data */
|
||||
pt = pcalloc(sizeof(PCPOINT));
|
||||
pt->data = pcalloc(s->size);
|
||||
pt->schema = s;
|
||||
pt->readonly = PC_FALSE;
|
||||
|
||||
for ( i = 0; i < stride; 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;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < stride; 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;
|
||||
}
|
||||
}
|
||||
|
||||
return pt;
|
||||
return pt;
|
||||
}
|
||||
|
||||
PCPOINT *
|
||||
pc_point_from_wkb(const PCSCHEMA *schema, uint8_t *wkb, size_t wkblen)
|
||||
PCPOINT *pc_point_from_wkb(const PCSCHEMA *schema, uint8_t *wkb, size_t wkblen)
|
||||
{
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uchar[]: data (interpret relative to pcid)
|
||||
*/
|
||||
const size_t hdrsz = 1+4; /* endian + pcid */
|
||||
uint8_t wkb_endian;
|
||||
uint8_t *data;
|
||||
PCPOINT *pt;
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uchar[]: data (interpret relative to pcid)
|
||||
*/
|
||||
const size_t hdrsz = 1 + 4; /* endian + pcid */
|
||||
uint8_t wkb_endian;
|
||||
uint8_t *data;
|
||||
PCPOINT *pt;
|
||||
|
||||
if ( ! wkblen )
|
||||
{
|
||||
pcerror("pc_point_from_wkb: zero length wkb");
|
||||
}
|
||||
if (!wkblen)
|
||||
{
|
||||
pcerror("pc_point_from_wkb: zero length wkb");
|
||||
}
|
||||
|
||||
wkb_endian = wkb[0];
|
||||
wkb_endian = wkb[0];
|
||||
|
||||
if ( (wkblen-hdrsz) != schema->size )
|
||||
{
|
||||
pcerror("pc_point_from_wkb: wkb size inconsistent with schema size");
|
||||
}
|
||||
if ((wkblen - hdrsz) != schema->size)
|
||||
{
|
||||
pcerror("pc_point_from_wkb: wkb size inconsistent with schema size");
|
||||
}
|
||||
|
||||
if ( wkb_endian != machine_endian() )
|
||||
{
|
||||
/* uncompressed_bytes_flip_endian creates a flipped copy */
|
||||
data = uncompressed_bytes_flip_endian(wkb+hdrsz, schema, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = pcalloc(schema->size);
|
||||
memcpy(data, wkb+hdrsz, wkblen-hdrsz);
|
||||
}
|
||||
if (wkb_endian != machine_endian())
|
||||
{
|
||||
/* uncompressed_bytes_flip_endian creates a flipped copy */
|
||||
data = uncompressed_bytes_flip_endian(wkb + hdrsz, schema, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
data = pcalloc(schema->size);
|
||||
memcpy(data, wkb + hdrsz, wkblen - hdrsz);
|
||||
}
|
||||
|
||||
pt = pc_point_from_data(schema, data);
|
||||
pt->readonly = PC_FALSE;
|
||||
return pt;
|
||||
pt = pc_point_from_data(schema, data);
|
||||
pt->readonly = PC_FALSE;
|
||||
return pt;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
pc_point_to_wkb(const PCPOINT *pt, size_t *wkbsize)
|
||||
uint8_t *pc_point_to_wkb(const PCPOINT *pt, size_t *wkbsize)
|
||||
{
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uchar[]: data (interpret relative to pcid)
|
||||
*/
|
||||
char endian = machine_endian();
|
||||
size_t size = 1 + 4 + pt->schema->size;
|
||||
uint8_t *wkb = pcalloc(size);
|
||||
wkb[0] = endian; /* Write endian flag */
|
||||
memcpy(wkb + 1, &(pt->schema->pcid), 4); /* Write PCID */
|
||||
memcpy(wkb + 5, pt->data, pt->schema->size); /* Write data */
|
||||
if ( wkbsize ) *wkbsize = size;
|
||||
return wkb;
|
||||
/*
|
||||
byte: endianness (1 = NDR, 0 = XDR)
|
||||
uint32: pcid (key to POINTCLOUD_SCHEMAS)
|
||||
uchar[]: data (interpret relative to pcid)
|
||||
*/
|
||||
char endian = machine_endian();
|
||||
size_t size = 1 + 4 + pt->schema->size;
|
||||
uint8_t *wkb = pcalloc(size);
|
||||
wkb[0] = endian; /* Write endian flag */
|
||||
memcpy(wkb + 1, &(pt->schema->pcid), 4); /* Write PCID */
|
||||
memcpy(wkb + 5, pt->data, pt->schema->size); /* Write data */
|
||||
if (wkbsize)
|
||||
*wkbsize = size;
|
||||
return wkb;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
pc_point_to_geometry_wkb(const PCPOINT *pt, size_t *wkbsize)
|
||||
uint8_t *pc_point_to_geometry_wkb(const PCPOINT *pt, size_t *wkbsize)
|
||||
{
|
||||
static uint32_t srid_mask = 0x20000000;
|
||||
static uint32_t m_mask = 0x40000000;
|
||||
static uint32_t z_mask = 0x80000000;
|
||||
uint32_t wkbtype = 1; /* WKB POINT */
|
||||
size_t size = 1 + 4 + 8 + 8; /* endian + type + dblX, + dblY */
|
||||
uint8_t *wkb, *ptr;
|
||||
uint32_t srid = pt->schema->srid;
|
||||
double x, y, z, m;
|
||||
int has_x = pc_point_get_x(pt, &x) == PC_SUCCESS;
|
||||
int has_y = pc_point_get_y(pt, &y) == PC_SUCCESS;
|
||||
int has_z = pc_point_get_z(pt, &z) == PC_SUCCESS;
|
||||
int has_m = pc_point_get_m(pt, &m) == PC_SUCCESS;
|
||||
static uint32_t srid_mask = 0x20000000;
|
||||
static uint32_t m_mask = 0x40000000;
|
||||
static uint32_t z_mask = 0x80000000;
|
||||
uint32_t wkbtype = 1; /* WKB POINT */
|
||||
size_t size = 1 + 4 + 8 + 8; /* endian + type + dblX, + dblY */
|
||||
uint8_t *wkb, *ptr;
|
||||
uint32_t srid = pt->schema->srid;
|
||||
double x, y, z, m;
|
||||
int has_x = pc_point_get_x(pt, &x) == PC_SUCCESS;
|
||||
int has_y = pc_point_get_y(pt, &y) == PC_SUCCESS;
|
||||
int has_z = pc_point_get_z(pt, &z) == PC_SUCCESS;
|
||||
int has_m = pc_point_get_m(pt, &m) == PC_SUCCESS;
|
||||
|
||||
if ( ! ( has_x && has_y ) )
|
||||
return NULL;
|
||||
if (!(has_x && has_y))
|
||||
return NULL;
|
||||
|
||||
if ( srid )
|
||||
{
|
||||
wkbtype |= srid_mask;
|
||||
size += 4;
|
||||
}
|
||||
if (srid)
|
||||
{
|
||||
wkbtype |= srid_mask;
|
||||
size += 4;
|
||||
}
|
||||
|
||||
if ( has_z )
|
||||
{
|
||||
wkbtype |= z_mask;
|
||||
size += 8;
|
||||
}
|
||||
if (has_z)
|
||||
{
|
||||
wkbtype |= z_mask;
|
||||
size += 8;
|
||||
}
|
||||
|
||||
if ( has_m )
|
||||
{
|
||||
wkbtype |= m_mask;
|
||||
size += 8;
|
||||
}
|
||||
if (has_m)
|
||||
{
|
||||
wkbtype |= m_mask;
|
||||
size += 8;
|
||||
}
|
||||
|
||||
wkb = pcalloc(size);
|
||||
ptr = wkb;
|
||||
wkb = pcalloc(size);
|
||||
ptr = wkb;
|
||||
|
||||
ptr[0] = machine_endian(); /* Endian flag */
|
||||
ptr += 1;
|
||||
ptr[0] = machine_endian(); /* Endian flag */
|
||||
ptr += 1;
|
||||
|
||||
memcpy(ptr, &wkbtype, 4); /* WKB type */
|
||||
ptr += 4;
|
||||
memcpy(ptr, &wkbtype, 4); /* WKB type */
|
||||
ptr += 4;
|
||||
|
||||
if ( srid != 0 )
|
||||
{
|
||||
memcpy(ptr, &srid, 4); /* SRID */
|
||||
ptr += 4;
|
||||
}
|
||||
if (srid != 0)
|
||||
{
|
||||
memcpy(ptr, &srid, 4); /* SRID */
|
||||
ptr += 4;
|
||||
}
|
||||
|
||||
memcpy(ptr, &x, 8); /* X */
|
||||
ptr += 8;
|
||||
memcpy(ptr, &x, 8); /* X */
|
||||
ptr += 8;
|
||||
|
||||
memcpy(ptr, &y, 8); /* Y */
|
||||
ptr += 8;
|
||||
memcpy(ptr, &y, 8); /* Y */
|
||||
ptr += 8;
|
||||
|
||||
if ( has_z )
|
||||
{
|
||||
memcpy(ptr, &z, 8); /* Z */
|
||||
ptr += 8;
|
||||
}
|
||||
if (has_z)
|
||||
{
|
||||
memcpy(ptr, &z, 8); /* Z */
|
||||
ptr += 8;
|
||||
}
|
||||
|
||||
if ( has_m )
|
||||
{
|
||||
memcpy(ptr, &m, 8); /* M */
|
||||
ptr += 8;
|
||||
}
|
||||
if (has_m)
|
||||
{
|
||||
memcpy(ptr, &m, 8); /* M */
|
||||
ptr += 8;
|
||||
}
|
||||
|
||||
if ( wkbsize ) *wkbsize = size;
|
||||
return wkb;
|
||||
if (wkbsize)
|
||||
*wkbsize = size;
|
||||
return wkb;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief this function convert a PCPOINT to an array of double containing
|
||||
* all the dimension values of this point
|
||||
*
|
||||
* @param a pointer to the point to convert to double
|
||||
*
|
||||
* @return a pointer to an array of double containing all the dimensions
|
||||
* of the point expressed as double precision
|
||||
*
|
||||
*/
|
||||
double * pc_point_to_double_array(const PCPOINT *p)
|
||||
* @brief this function convert a PCPOINT to an array of double containing
|
||||
* all the dimension values of this point
|
||||
*
|
||||
* @param a pointer to the point to convert to double
|
||||
*
|
||||
* @return a pointer to an array of double containing all the dimensions
|
||||
* of the point expressed as double precision
|
||||
*
|
||||
*/
|
||||
double *pc_point_to_double_array(const PCPOINT *p)
|
||||
{
|
||||
int i;
|
||||
double *a = (double *) pcalloc( p->schema->ndims * sizeof(double) );
|
||||
int i;
|
||||
double *a = (double *)pcalloc(p->schema->ndims * sizeof(double));
|
||||
|
||||
for(i=0; i<p->schema->ndims; ++i)
|
||||
{
|
||||
pc_point_get_double_by_index(p, i, &(a[i]));
|
||||
}
|
||||
for (i = 0; i < p->schema->ndims; ++i)
|
||||
{
|
||||
pc_point_get_double_by_index(p, i, &(a[i]));
|
||||
}
|
||||
|
||||
return a;
|
||||
return a;
|
||||
}
|
||||
|
||||
@ -1,137 +1,133 @@
|
||||
/***********************************************************************
|
||||
* pc_pointlist.c
|
||||
*
|
||||
* Point list handling. Create, get and set values from the
|
||||
* basic PCPOINTLIST structure.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_pointlist.c
|
||||
*
|
||||
* Point list handling. Create, get and set values from the
|
||||
* basic PCPOINTLIST structure.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "pc_api_internal.h"
|
||||
#include <assert.h>
|
||||
|
||||
PCPOINTLIST *
|
||||
pc_pointlist_make(uint32_t npoints)
|
||||
PCPOINTLIST *pc_pointlist_make(uint32_t npoints)
|
||||
{
|
||||
PCPOINTLIST *pl = pcalloc(sizeof(PCPOINTLIST));
|
||||
pl->points = pcalloc(sizeof(PCPOINT*) * npoints);
|
||||
pl->maxpoints = npoints;
|
||||
pl->npoints = 0;
|
||||
pl->mem = NULL;
|
||||
return pl;
|
||||
PCPOINTLIST *pl = pcalloc(sizeof(PCPOINTLIST));
|
||||
pl->points = pcalloc(sizeof(PCPOINT *) * npoints);
|
||||
pl->maxpoints = npoints;
|
||||
pl->npoints = 0;
|
||||
pl->mem = NULL;
|
||||
return pl;
|
||||
}
|
||||
|
||||
void
|
||||
pc_pointlist_free(PCPOINTLIST *pl)
|
||||
void pc_pointlist_free(PCPOINTLIST *pl)
|
||||
{
|
||||
int i;
|
||||
for ( i = 0; i < pl->npoints; i++ )
|
||||
{
|
||||
pc_point_free(pl->points[i]);
|
||||
}
|
||||
if ( pl->mem )
|
||||
pcfree(pl->mem);
|
||||
pcfree(pl->points);
|
||||
pcfree(pl);
|
||||
return;
|
||||
int i;
|
||||
for (i = 0; i < pl->npoints; i++)
|
||||
{
|
||||
pc_point_free(pl->points[i]);
|
||||
}
|
||||
if (pl->mem)
|
||||
pcfree(pl->mem);
|
||||
pcfree(pl->points);
|
||||
pcfree(pl);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
pc_pointlist_add_point(PCPOINTLIST *pl, PCPOINT *pt)
|
||||
void pc_pointlist_add_point(PCPOINTLIST *pl, PCPOINT *pt)
|
||||
{
|
||||
if ( pl->npoints >= pl->maxpoints )
|
||||
{
|
||||
if ( pl->maxpoints < 1 ) pl->maxpoints = 1;
|
||||
pl->maxpoints *= 2;
|
||||
pl->points = pcrealloc(pl->points, pl->maxpoints * sizeof(PCPOINT*));
|
||||
}
|
||||
if (pl->npoints >= pl->maxpoints)
|
||||
{
|
||||
if (pl->maxpoints < 1)
|
||||
pl->maxpoints = 1;
|
||||
pl->maxpoints *= 2;
|
||||
pl->points = pcrealloc(pl->points, pl->maxpoints * sizeof(PCPOINT *));
|
||||
}
|
||||
|
||||
pl->points[pl->npoints] = pt;
|
||||
pl->npoints += 1;
|
||||
return;
|
||||
pl->points[pl->npoints] = pt;
|
||||
pl->npoints += 1;
|
||||
return;
|
||||
}
|
||||
|
||||
PCPOINT *
|
||||
pc_pointlist_get_point(const PCPOINTLIST *pl, int i)
|
||||
PCPOINT *pc_pointlist_get_point(const PCPOINTLIST *pl, int i)
|
||||
{
|
||||
return pl->points[i];
|
||||
return pl->points[i];
|
||||
}
|
||||
|
||||
PCPOINTLIST *
|
||||
pc_pointlist_from_dimensional(const PCPATCH_DIMENSIONAL *pdl)
|
||||
PCPOINTLIST *pc_pointlist_from_dimensional(const PCPATCH_DIMENSIONAL *pdl)
|
||||
{
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_DIMENSIONAL *pdl_uncompressed;
|
||||
const PCSCHEMA *schema = pdl->schema;
|
||||
int i, j, ndims, npoints;
|
||||
uint8_t *data;
|
||||
assert(pdl);
|
||||
PCPOINTLIST *pl;
|
||||
PCPATCH_DIMENSIONAL *pdl_uncompressed;
|
||||
const PCSCHEMA *schema = pdl->schema;
|
||||
int i, j, ndims, npoints;
|
||||
uint8_t *data;
|
||||
assert(pdl);
|
||||
|
||||
pdl_uncompressed = pc_patch_dimensional_decompress(pdl);
|
||||
pdl_uncompressed = pc_patch_dimensional_decompress(pdl);
|
||||
|
||||
ndims = schema->ndims;
|
||||
npoints = pdl->npoints;
|
||||
pl = pc_pointlist_make(npoints);
|
||||
pl->mem = data = pcalloc(npoints * schema->size);
|
||||
ndims = schema->ndims;
|
||||
npoints = pdl->npoints;
|
||||
pl = pc_pointlist_make(npoints);
|
||||
pl->mem = data = pcalloc(npoints * schema->size);
|
||||
|
||||
for ( i = 0; i < npoints; i++ )
|
||||
{
|
||||
PCPOINT *pt = pc_point_from_data(schema,data);
|
||||
for ( j = 0; j < ndims; j++ )
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(schema, j);
|
||||
for (i = 0; i < npoints; i++)
|
||||
{
|
||||
PCPOINT *pt = pc_point_from_data(schema, data);
|
||||
for (j = 0; j < ndims; j++)
|
||||
{
|
||||
PCDIMENSION *dim = pc_schema_get_dimension(schema, j);
|
||||
|
||||
uint8_t *in = pdl_uncompressed->bytes[j].bytes + dim->size * i;
|
||||
uint8_t *out = data + dim->byteoffset;
|
||||
memcpy(out, in, dim->size);
|
||||
}
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
data += schema->size;
|
||||
}
|
||||
pc_patch_dimensional_free(pdl_uncompressed);
|
||||
uint8_t *in = pdl_uncompressed->bytes[j].bytes + dim->size * i;
|
||||
uint8_t *out = data + dim->byteoffset;
|
||||
memcpy(out, in, dim->size);
|
||||
}
|
||||
pc_pointlist_add_point(pl, pt);
|
||||
data += schema->size;
|
||||
}
|
||||
pc_patch_dimensional_free(pdl_uncompressed);
|
||||
|
||||
return pl;
|
||||
return pl;
|
||||
}
|
||||
|
||||
PCPOINTLIST *
|
||||
pc_pointlist_from_uncompressed(const PCPATCH_UNCOMPRESSED *patch)
|
||||
PCPOINTLIST *pc_pointlist_from_uncompressed(const PCPATCH_UNCOMPRESSED *patch)
|
||||
{
|
||||
int i;
|
||||
PCPOINTLIST *pl;
|
||||
size_t pt_size = patch->schema->size;
|
||||
uint32_t npoints = patch->npoints;
|
||||
int i;
|
||||
PCPOINTLIST *pl;
|
||||
size_t pt_size = patch->schema->size;
|
||||
uint32_t npoints = patch->npoints;
|
||||
|
||||
pl = pc_pointlist_make(npoints);
|
||||
for ( i = 0; i < npoints; i++ )
|
||||
{
|
||||
pc_pointlist_add_point(pl, pc_point_from_data(patch->schema, patch->data + i*pt_size));
|
||||
}
|
||||
return pl;
|
||||
pl = pc_pointlist_make(npoints);
|
||||
for (i = 0; i < npoints; i++)
|
||||
{
|
||||
pc_pointlist_add_point(
|
||||
pl, pc_point_from_data(patch->schema, patch->data + i * pt_size));
|
||||
}
|
||||
return pl;
|
||||
}
|
||||
|
||||
PCPOINTLIST *
|
||||
pc_pointlist_from_patch(const PCPATCH *patch)
|
||||
PCPOINTLIST *pc_pointlist_from_patch(const PCPATCH *patch)
|
||||
{
|
||||
switch ( patch->type )
|
||||
{
|
||||
case PC_NONE:
|
||||
{
|
||||
return pc_pointlist_from_uncompressed((PCPATCH_UNCOMPRESSED*)patch);
|
||||
}
|
||||
case PC_DIMENSIONAL:
|
||||
{
|
||||
return pc_pointlist_from_dimensional((PCPATCH_DIMENSIONAL*)patch);
|
||||
}
|
||||
case PC_LAZPERF:
|
||||
{
|
||||
return pc_pointlist_from_lazperf((PCPATCH_LAZPERF*)patch);
|
||||
}
|
||||
}
|
||||
switch (patch->type)
|
||||
{
|
||||
case PC_NONE:
|
||||
{
|
||||
return pc_pointlist_from_uncompressed((PCPATCH_UNCOMPRESSED *)patch);
|
||||
}
|
||||
case PC_DIMENSIONAL:
|
||||
{
|
||||
return pc_pointlist_from_dimensional((PCPATCH_DIMENSIONAL *)patch);
|
||||
}
|
||||
case PC_LAZPERF:
|
||||
{
|
||||
return pc_pointlist_from_lazperf((PCPATCH_LAZPERF *)patch);
|
||||
}
|
||||
}
|
||||
|
||||
/* Don't get here */
|
||||
pcerror("pc_pointlist_from_patch: unsupported compression type %d", patch->type);
|
||||
return NULL;
|
||||
/* Don't get here */
|
||||
pcerror("pc_pointlist_from_patch: unsupported compression type %d",
|
||||
patch->type);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
1079
lib/pc_schema.c
1079
lib/pc_schema.c
File diff suppressed because it is too large
Load Diff
414
lib/pc_sort.c
414
lib/pc_sort.c
@ -1,264 +1,264 @@
|
||||
/***********************************************************************
|
||||
* pc_sort.c
|
||||
*
|
||||
* Pointclound patch sorting.
|
||||
*
|
||||
* Copyright (c) 2016 IGN
|
||||
*
|
||||
* Author: M. Brédif
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_sort.c
|
||||
*
|
||||
* Pointclound patch sorting.
|
||||
*
|
||||
* Copyright (c) 2016 IGN
|
||||
*
|
||||
* Author: M. Brédif
|
||||
*
|
||||
***********************************************************************/
|
||||
#include "pc_api_internal.h"
|
||||
#include <assert.h>
|
||||
#include "sort_r/sort_r.h"
|
||||
#include <assert.h>
|
||||
|
||||
// NULL terminated array of PCDIMENSION pointers
|
||||
typedef PCDIMENSION ** PCDIMENSION_LIST;
|
||||
typedef PCDIMENSION **PCDIMENSION_LIST;
|
||||
|
||||
/**
|
||||
* Comparators
|
||||
*/
|
||||
* Comparators
|
||||
*/
|
||||
|
||||
int
|
||||
pc_compare_dim (const void *a, const void *b, void *arg)
|
||||
int pc_compare_dim(const void *a, const void *b, void *arg)
|
||||
{
|
||||
PCDIMENSION_LIST dim = (PCDIMENSION_LIST)arg;
|
||||
uint32_t byteoffset = dim[0]->byteoffset;
|
||||
uint32_t interpretation = dim[0]->interpretation;
|
||||
double da = pc_double_from_ptr(a+byteoffset,interpretation);
|
||||
double db = pc_double_from_ptr(b+byteoffset,interpretation);
|
||||
int cmp = ((da > db) - (da < db));
|
||||
return ( cmp == 0 && dim[1]) ? pc_compare_dim(a,b,dim+1) : cmp;
|
||||
PCDIMENSION_LIST dim = (PCDIMENSION_LIST)arg;
|
||||
uint32_t byteoffset = dim[0]->byteoffset;
|
||||
uint32_t interpretation = dim[0]->interpretation;
|
||||
double da = pc_double_from_ptr(a + byteoffset, interpretation);
|
||||
double db = pc_double_from_ptr(b + byteoffset, interpretation);
|
||||
int cmp = ((da > db) - (da < db));
|
||||
return (cmp == 0 && dim[1]) ? pc_compare_dim(a, b, dim + 1) : cmp;
|
||||
}
|
||||
|
||||
int
|
||||
pc_compare_pcb (const void *a, const void *b, const void *arg)
|
||||
int pc_compare_pcb(const void *a, const void *b, const void *arg)
|
||||
{
|
||||
PCBYTES *pcb = (PCBYTES *)arg;
|
||||
double da = pc_double_from_ptr(a,pcb->interpretation);
|
||||
double db = pc_double_from_ptr(b,pcb->interpretation);
|
||||
return ((da > db) - (da < db));
|
||||
PCBYTES *pcb = (PCBYTES *)arg;
|
||||
double da = pc_double_from_ptr(a, pcb->interpretation);
|
||||
double db = pc_double_from_ptr(b, pcb->interpretation);
|
||||
return ((da > db) - (da < db));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sort
|
||||
*/
|
||||
* Sort
|
||||
*/
|
||||
|
||||
PCPATCH_UNCOMPRESSED *
|
||||
pc_patch_uncompressed_sort(const PCPATCH_UNCOMPRESSED *pu, PCDIMENSION_LIST dim)
|
||||
PCPATCH_UNCOMPRESSED *pc_patch_uncompressed_sort(const PCPATCH_UNCOMPRESSED *pu,
|
||||
PCDIMENSION_LIST dim)
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *spu = pc_patch_uncompressed_make(pu->schema, pu->npoints);
|
||||
PCPATCH_UNCOMPRESSED *spu =
|
||||
pc_patch_uncompressed_make(pu->schema, pu->npoints);
|
||||
|
||||
memcpy(spu->data, pu->data, pu->datasize);
|
||||
spu->npoints = pu->npoints;
|
||||
spu->bounds = pu->bounds;
|
||||
spu->stats = pc_stats_clone(pu->stats);
|
||||
memcpy(spu->data, pu->data, pu->datasize);
|
||||
spu->npoints = pu->npoints;
|
||||
spu->bounds = pu->bounds;
|
||||
spu->stats = pc_stats_clone(pu->stats);
|
||||
|
||||
sort_r(spu->data, spu->npoints, pu->schema->size, pc_compare_dim, dim);
|
||||
sort_r(spu->data, spu->npoints, pu->schema->size, pc_compare_dim, dim);
|
||||
|
||||
return spu;
|
||||
return spu;
|
||||
}
|
||||
|
||||
PCDIMENSION_LIST pc_schema_get_dimensions_by_name(const PCSCHEMA *schema, const char ** name, int ndims)
|
||||
PCDIMENSION_LIST pc_schema_get_dimensions_by_name(const PCSCHEMA *schema,
|
||||
const char **name, int ndims)
|
||||
{
|
||||
PCDIMENSION_LIST dim = pcalloc( (ndims+1) * sizeof(PCDIMENSION *));
|
||||
int i;
|
||||
for(i=0; i<ndims; ++i)
|
||||
{
|
||||
dim[i] = pc_schema_get_dimension_by_name(schema, name[i]);
|
||||
if ( ! dim[i] ) {
|
||||
pcerror("dimension \"%s\" does not exist", name[i]);
|
||||
return NULL;
|
||||
}
|
||||
assert(dim[i]->scale>0);
|
||||
}
|
||||
dim[ndims] = NULL;
|
||||
return dim;
|
||||
PCDIMENSION_LIST dim = pcalloc((ndims + 1) * sizeof(PCDIMENSION *));
|
||||
int i;
|
||||
for (i = 0; i < ndims; ++i)
|
||||
{
|
||||
dim[i] = pc_schema_get_dimension_by_name(schema, name[i]);
|
||||
if (!dim[i])
|
||||
{
|
||||
pcerror("dimension \"%s\" does not exist", name[i]);
|
||||
return NULL;
|
||||
}
|
||||
assert(dim[i]->scale > 0);
|
||||
}
|
||||
dim[ndims] = NULL;
|
||||
return dim;
|
||||
}
|
||||
|
||||
PCPATCH *
|
||||
pc_patch_sort(const PCPATCH *pa, const char ** name, int ndims)
|
||||
PCPATCH *pc_patch_sort(const PCPATCH *pa, const char **name, int ndims)
|
||||
{
|
||||
PCDIMENSION_LIST dim = pc_schema_get_dimensions_by_name(pa->schema, name, ndims);
|
||||
PCPATCH *pu = pc_patch_uncompress(pa);
|
||||
if ( !pu ) {
|
||||
pcfree(dim);
|
||||
pcerror("Patch uncompression failed");
|
||||
return NULL;
|
||||
}
|
||||
PCPATCH_UNCOMPRESSED *ps = pc_patch_uncompressed_sort((PCPATCH_UNCOMPRESSED *)pu, dim);
|
||||
PCDIMENSION_LIST dim =
|
||||
pc_schema_get_dimensions_by_name(pa->schema, name, ndims);
|
||||
PCPATCH *pu = pc_patch_uncompress(pa);
|
||||
if (!pu)
|
||||
{
|
||||
pcfree(dim);
|
||||
pcerror("Patch uncompression failed");
|
||||
return NULL;
|
||||
}
|
||||
PCPATCH_UNCOMPRESSED *ps =
|
||||
pc_patch_uncompressed_sort((PCPATCH_UNCOMPRESSED *)pu, dim);
|
||||
|
||||
pcfree(dim);
|
||||
if ( pu != pa )
|
||||
pc_patch_free(pu);
|
||||
return (PCPATCH *) ps;
|
||||
pcfree(dim);
|
||||
if (pu != pa)
|
||||
pc_patch_free(pu);
|
||||
return (PCPATCH *)ps;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* IsSorted
|
||||
*/
|
||||
* IsSorted
|
||||
*/
|
||||
|
||||
uint32_t
|
||||
pc_patch_uncompressed_is_sorted(const PCPATCH_UNCOMPRESSED *pu, PCDIMENSION_LIST dim, char strict)
|
||||
uint32_t pc_patch_uncompressed_is_sorted(const PCPATCH_UNCOMPRESSED *pu,
|
||||
PCDIMENSION_LIST dim, char strict)
|
||||
{
|
||||
size_t size = pu->schema->size;
|
||||
uint8_t *buf = pu->data, *last = pu->data+pu->datasize-size;
|
||||
while ( buf < last )
|
||||
{
|
||||
if( pc_compare_dim(buf,buf+size,dim) >= strict )
|
||||
return PC_FALSE;
|
||||
buf += size;
|
||||
}
|
||||
return PC_TRUE;
|
||||
size_t size = pu->schema->size;
|
||||
uint8_t *buf = pu->data, *last = pu->data + pu->datasize - size;
|
||||
while (buf < last)
|
||||
{
|
||||
if (pc_compare_dim(buf, buf + size, dim) >= strict)
|
||||
return PC_FALSE;
|
||||
buf += size;
|
||||
}
|
||||
return PC_TRUE;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
pc_bytes_uncompressed_is_sorted(const PCBYTES *pcb, char strict)
|
||||
uint32_t pc_bytes_uncompressed_is_sorted(const PCBYTES *pcb, char strict)
|
||||
{
|
||||
assert(pcb->compression == PC_DIM_NONE);
|
||||
size_t size = pc_interpretation_size(pcb->interpretation);
|
||||
uint8_t *buf = pcb->bytes;
|
||||
uint8_t *last = buf+pcb->size-size;
|
||||
while ( buf < last )
|
||||
{
|
||||
if( pc_compare_pcb(buf,buf+size,pcb) >= strict )
|
||||
return PC_FALSE;
|
||||
buf += size;
|
||||
}
|
||||
return PC_TRUE;
|
||||
assert(pcb->compression == PC_DIM_NONE);
|
||||
size_t size = pc_interpretation_size(pcb->interpretation);
|
||||
uint8_t *buf = pcb->bytes;
|
||||
uint8_t *last = buf + pcb->size - size;
|
||||
while (buf < last)
|
||||
{
|
||||
if (pc_compare_pcb(buf, buf + size, pcb) >= strict)
|
||||
return PC_FALSE;
|
||||
buf += size;
|
||||
}
|
||||
return PC_TRUE;
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
pc_bytes_sigbits_is_sorted(const PCBYTES *pcb, char strict)
|
||||
uint32_t pc_bytes_sigbits_is_sorted(const PCBYTES *pcb, char strict)
|
||||
{
|
||||
assert(pcb->compression == PC_DIM_SIGBITS);
|
||||
pcinfo("%s not implemented, decoding",__func__);
|
||||
PCBYTES dpcb = pc_bytes_decode(*pcb);
|
||||
uint32_t is_sorted = pc_bytes_uncompressed_is_sorted(&dpcb,strict);
|
||||
pc_bytes_free(dpcb);
|
||||
return is_sorted;
|
||||
assert(pcb->compression == PC_DIM_SIGBITS);
|
||||
pcinfo("%s not implemented, decoding", __func__);
|
||||
PCBYTES dpcb = pc_bytes_decode(*pcb);
|
||||
uint32_t is_sorted = pc_bytes_uncompressed_is_sorted(&dpcb, strict);
|
||||
pc_bytes_free(dpcb);
|
||||
return is_sorted;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
pc_bytes_zlib_is_sorted(const PCBYTES *pcb, char strict)
|
||||
uint32_t pc_bytes_zlib_is_sorted(const PCBYTES *pcb, char strict)
|
||||
{
|
||||
assert(pcb->compression == PC_DIM_ZLIB);
|
||||
pcinfo("%s not implemented, decoding",__func__);
|
||||
PCBYTES dpcb = pc_bytes_decode(*pcb);
|
||||
uint32_t is_sorted = pc_bytes_uncompressed_is_sorted(&dpcb,strict);
|
||||
pc_bytes_free(dpcb);
|
||||
return is_sorted;
|
||||
assert(pcb->compression == PC_DIM_ZLIB);
|
||||
pcinfo("%s not implemented, decoding", __func__);
|
||||
PCBYTES dpcb = pc_bytes_decode(*pcb);
|
||||
uint32_t is_sorted = pc_bytes_uncompressed_is_sorted(&dpcb, strict);
|
||||
pc_bytes_free(dpcb);
|
||||
return is_sorted;
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
pc_bytes_run_length_is_sorted(const PCBYTES *pcb, char strict)
|
||||
uint32_t pc_bytes_run_length_is_sorted(const PCBYTES *pcb, char strict)
|
||||
{
|
||||
assert(pcb->compression == PC_DIM_RLE);
|
||||
uint8_t run;
|
||||
size_t size = pc_interpretation_size(pcb->interpretation);
|
||||
const uint8_t *bytes_rle_curr_val = pcb->bytes + 1;
|
||||
const uint8_t *bytes_rle_next_val = pcb->bytes + 2 + size;
|
||||
const uint8_t *bytes_rle_end_val = pcb->bytes + pcb->size - size;
|
||||
while( bytes_rle_next_val < bytes_rle_end_val )
|
||||
{
|
||||
run = bytes_rle_curr_val[-1];
|
||||
assert(run>0);
|
||||
if( pc_compare_pcb(bytes_rle_curr_val,bytes_rle_next_val,pcb) >= strict // value comparison
|
||||
|| (strict && run > 1) ) // run_length should be 1 if strict
|
||||
return PC_FALSE;
|
||||
bytes_rle_curr_val = bytes_rle_next_val;
|
||||
bytes_rle_next_val += 1 + size;
|
||||
}
|
||||
return PC_TRUE;
|
||||
assert(pcb->compression == PC_DIM_RLE);
|
||||
uint8_t run;
|
||||
size_t size = pc_interpretation_size(pcb->interpretation);
|
||||
const uint8_t *bytes_rle_curr_val = pcb->bytes + 1;
|
||||
const uint8_t *bytes_rle_next_val = pcb->bytes + 2 + size;
|
||||
const uint8_t *bytes_rle_end_val = pcb->bytes + pcb->size - size;
|
||||
while (bytes_rle_next_val < bytes_rle_end_val)
|
||||
{
|
||||
run = bytes_rle_curr_val[-1];
|
||||
assert(run > 0);
|
||||
if (pc_compare_pcb(bytes_rle_curr_val, bytes_rle_next_val, pcb) >=
|
||||
strict // value comparison
|
||||
|| (strict && run > 1)) // run_length should be 1 if strict
|
||||
return PC_FALSE;
|
||||
bytes_rle_curr_val = bytes_rle_next_val;
|
||||
bytes_rle_next_val += 1 + size;
|
||||
}
|
||||
return PC_TRUE;
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
pc_patch_dimensional_is_sorted(const PCPATCH_DIMENSIONAL *pdl, PCDIMENSION_LIST dim, char strict)
|
||||
uint32_t pc_patch_dimensional_is_sorted(const PCPATCH_DIMENSIONAL *pdl,
|
||||
PCDIMENSION_LIST dim, char strict)
|
||||
{
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
assert(pdl);
|
||||
assert(pdl->schema);
|
||||
|
||||
// uncompress when checking multiple dimensions
|
||||
if(dim[1])
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *pu = pc_patch_uncompressed_from_dimensional(pdl);
|
||||
if ( !pu ) {
|
||||
pcerror("Patch uncompression failed");
|
||||
return PC_FAILURE - 1; // aliasing issue : PC_FALSE == PC_FAILURE...
|
||||
}
|
||||
uint32_t is_sorted = pc_patch_uncompressed_is_sorted(pu,dim,strict);
|
||||
pc_patch_free((PCPATCH *)pu);
|
||||
return is_sorted;
|
||||
}
|
||||
// uncompress when checking multiple dimensions
|
||||
if (dim[1])
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *pu = pc_patch_uncompressed_from_dimensional(pdl);
|
||||
if (!pu)
|
||||
{
|
||||
pcerror("Patch uncompression failed");
|
||||
return PC_FAILURE - 1; // aliasing issue : PC_FALSE == PC_FAILURE...
|
||||
}
|
||||
uint32_t is_sorted = pc_patch_uncompressed_is_sorted(pu, dim, strict);
|
||||
pc_patch_free((PCPATCH *)pu);
|
||||
return is_sorted;
|
||||
}
|
||||
|
||||
PCBYTES *pcb = pdl->bytes + dim[0]->position;
|
||||
switch ( pcb->compression )
|
||||
{
|
||||
case PC_DIM_RLE:
|
||||
{
|
||||
return pc_bytes_run_length_is_sorted(pcb,strict);
|
||||
}
|
||||
case PC_DIM_SIGBITS:
|
||||
{
|
||||
return pc_bytes_sigbits_is_sorted(pcb,strict);
|
||||
}
|
||||
case PC_DIM_ZLIB:
|
||||
{
|
||||
return pc_bytes_zlib_is_sorted(pcb,strict);
|
||||
}
|
||||
case PC_DIM_NONE:
|
||||
{
|
||||
return pc_bytes_uncompressed_is_sorted(pcb,strict);
|
||||
}
|
||||
default:
|
||||
{
|
||||
pcerror("%s: Uh oh", __func__);
|
||||
}
|
||||
}
|
||||
return PC_FAILURE - 1; // aliasing issue : PC_FALSE == PC_FAILURE...
|
||||
PCBYTES *pcb = pdl->bytes + dim[0]->position;
|
||||
switch (pcb->compression)
|
||||
{
|
||||
case PC_DIM_RLE:
|
||||
{
|
||||
return pc_bytes_run_length_is_sorted(pcb, strict);
|
||||
}
|
||||
case PC_DIM_SIGBITS:
|
||||
{
|
||||
return pc_bytes_sigbits_is_sorted(pcb, strict);
|
||||
}
|
||||
case PC_DIM_ZLIB:
|
||||
{
|
||||
return pc_bytes_zlib_is_sorted(pcb, strict);
|
||||
}
|
||||
case PC_DIM_NONE:
|
||||
{
|
||||
return pc_bytes_uncompressed_is_sorted(pcb, strict);
|
||||
}
|
||||
default:
|
||||
{
|
||||
pcerror("%s: Uh oh", __func__);
|
||||
}
|
||||
}
|
||||
return PC_FAILURE - 1; // aliasing issue : PC_FALSE == PC_FAILURE...
|
||||
}
|
||||
|
||||
|
||||
uint32_t
|
||||
pc_patch_lazperf_is_sorted(const PCPATCH_LAZPERF *pa, PCDIMENSION_LIST dim, char strict)
|
||||
uint32_t pc_patch_lazperf_is_sorted(const PCPATCH_LAZPERF *pa,
|
||||
PCDIMENSION_LIST dim, char strict)
|
||||
{
|
||||
PCPATCH_UNCOMPRESSED *pu = pc_patch_uncompressed_from_lazperf(pa);
|
||||
if ( !pu ) {
|
||||
pcerror("Patch uncompression failed");
|
||||
return PC_FAILURE - 1; // aliasing issue : PC_FALSE == PC_FAILURE...
|
||||
}
|
||||
uint32_t is_sorted = pc_patch_uncompressed_is_sorted(pu,dim,strict);
|
||||
pc_patch_free((PCPATCH*) pu);
|
||||
return is_sorted;
|
||||
PCPATCH_UNCOMPRESSED *pu = pc_patch_uncompressed_from_lazperf(pa);
|
||||
if (!pu)
|
||||
{
|
||||
pcerror("Patch uncompression failed");
|
||||
return PC_FAILURE - 1; // aliasing issue : PC_FALSE == PC_FAILURE...
|
||||
}
|
||||
uint32_t is_sorted = pc_patch_uncompressed_is_sorted(pu, dim, strict);
|
||||
pc_patch_free((PCPATCH *)pu);
|
||||
return is_sorted;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
pc_patch_is_sorted(const PCPATCH *pa, const char **name, int ndims, char strict)
|
||||
uint32_t pc_patch_is_sorted(const PCPATCH *pa, const char **name, int ndims,
|
||||
char strict)
|
||||
{
|
||||
int is_sorted = PC_FAILURE -1; // aliasing issue : PC_FALSE == PC_FAILURE...
|
||||
PCDIMENSION_LIST dim = pc_schema_get_dimensions_by_name(pa->schema, name, ndims);
|
||||
if ( ! dim ) return is_sorted;
|
||||
strict = (strict > 0); // ensure 0-1 value
|
||||
int is_sorted = PC_FAILURE - 1; // aliasing issue : PC_FALSE == PC_FAILURE...
|
||||
PCDIMENSION_LIST dim =
|
||||
pc_schema_get_dimensions_by_name(pa->schema, name, ndims);
|
||||
if (!dim)
|
||||
return is_sorted;
|
||||
strict = (strict > 0); // ensure 0-1 value
|
||||
|
||||
switch( pa->type )
|
||||
{
|
||||
case PC_NONE:
|
||||
is_sorted = pc_patch_uncompressed_is_sorted((PCPATCH_UNCOMPRESSED*)pa,dim,strict);
|
||||
break;
|
||||
case PC_DIMENSIONAL:
|
||||
is_sorted = pc_patch_dimensional_is_sorted((PCPATCH_DIMENSIONAL*)pa,dim,strict);
|
||||
break;
|
||||
case PC_LAZPERF:
|
||||
is_sorted = pc_patch_lazperf_is_sorted((PCPATCH_LAZPERF*)pa,dim,strict);
|
||||
break;
|
||||
default:
|
||||
pcerror("%s: unsupported compression %d requested", __func__, pa->type);
|
||||
}
|
||||
pcfree(dim);
|
||||
return is_sorted;
|
||||
switch (pa->type)
|
||||
{
|
||||
case PC_NONE:
|
||||
is_sorted = pc_patch_uncompressed_is_sorted((PCPATCH_UNCOMPRESSED *)pa, dim,
|
||||
strict);
|
||||
break;
|
||||
case PC_DIMENSIONAL:
|
||||
is_sorted =
|
||||
pc_patch_dimensional_is_sorted((PCPATCH_DIMENSIONAL *)pa, dim, strict);
|
||||
break;
|
||||
case PC_LAZPERF:
|
||||
is_sorted = pc_patch_lazperf_is_sorted((PCPATCH_LAZPERF *)pa, dim, strict);
|
||||
break;
|
||||
default:
|
||||
pcerror("%s: unsupported compression %d requested", __func__, pa->type);
|
||||
}
|
||||
pcfree(dim);
|
||||
return is_sorted;
|
||||
}
|
||||
|
||||
299
lib/pc_stats.c
299
lib/pc_stats.c
@ -1,197 +1,188 @@
|
||||
/***********************************************************************
|
||||
* pc_stats.c
|
||||
*
|
||||
* Pointclound patch statistics generation.
|
||||
*
|
||||
* Copyright (c) 2013 OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_stats.c
|
||||
*
|
||||
* Pointclound patch statistics generation.
|
||||
*
|
||||
* Copyright (c) 2013 OpenGeo
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "pc_api_internal.h"
|
||||
#include <float.h>
|
||||
|
||||
/*
|
||||
* Instantiate a new PCDOUBLESTATS for calculation, and set up
|
||||
* initial values for min/max/sum
|
||||
*/
|
||||
static PCDOUBLESTATS *
|
||||
pc_dstats_new(int ndims)
|
||||
* Instantiate a new PCDOUBLESTATS for calculation, and set up
|
||||
* initial values for min/max/sum
|
||||
*/
|
||||
static PCDOUBLESTATS *pc_dstats_new(int ndims)
|
||||
{
|
||||
int i;
|
||||
PCDOUBLESTATS *stats = pcalloc(sizeof(PCDOUBLESTATS));
|
||||
stats->dims = pcalloc(sizeof(PCDOUBLESTAT)*ndims);
|
||||
for ( i = 0; i < ndims; i++ )
|
||||
{
|
||||
stats->dims[i].min = DBL_MAX;
|
||||
stats->dims[i].max = -1 * DBL_MAX;
|
||||
stats->dims[i].sum = 0;
|
||||
}
|
||||
stats->npoints = 0;
|
||||
return stats;
|
||||
int i;
|
||||
PCDOUBLESTATS *stats = pcalloc(sizeof(PCDOUBLESTATS));
|
||||
stats->dims = pcalloc(sizeof(PCDOUBLESTAT) * ndims);
|
||||
for (i = 0; i < ndims; i++)
|
||||
{
|
||||
stats->dims[i].min = DBL_MAX;
|
||||
stats->dims[i].max = -1 * DBL_MAX;
|
||||
stats->dims[i].sum = 0;
|
||||
}
|
||||
stats->npoints = 0;
|
||||
return stats;
|
||||
}
|
||||
|
||||
static void
|
||||
pc_dstats_free(PCDOUBLESTATS *stats)
|
||||
static void pc_dstats_free(PCDOUBLESTATS *stats)
|
||||
{
|
||||
if ( ! stats) return;
|
||||
if ( stats->dims ) pcfree(stats->dims);
|
||||
pcfree(stats);
|
||||
return;
|
||||
if (!stats)
|
||||
return;
|
||||
if (stats->dims)
|
||||
pcfree(stats->dims);
|
||||
pcfree(stats);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the standard stats object for in memory patches
|
||||
*/
|
||||
void
|
||||
pc_stats_free(PCSTATS *stats)
|
||||
* Free the standard stats object for in memory patches
|
||||
*/
|
||||
void pc_stats_free(PCSTATS *stats)
|
||||
{
|
||||
if ( stats->min.readonly != PC_TRUE )
|
||||
pcfree(stats->min.data);
|
||||
if (stats->min.readonly != PC_TRUE)
|
||||
pcfree(stats->min.data);
|
||||
|
||||
if ( stats->max.readonly != PC_TRUE )
|
||||
pcfree(stats->max.data);
|
||||
if (stats->max.readonly != PC_TRUE)
|
||||
pcfree(stats->max.data);
|
||||
|
||||
if ( stats->avg.readonly != PC_TRUE )
|
||||
pcfree(stats->avg.data);
|
||||
if (stats->avg.readonly != PC_TRUE)
|
||||
pcfree(stats->avg.data);
|
||||
|
||||
pcfree(stats);
|
||||
return;
|
||||
pcfree(stats);
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a standard stats object on top of a serialization, allocate just the
|
||||
* point shells and set the pointers to look into the data area of the
|
||||
* serialization.
|
||||
*/
|
||||
PCSTATS *
|
||||
pc_stats_new_from_data(const PCSCHEMA *schema, const uint8_t *mindata, const uint8_t *maxdata, const uint8_t *avgdata)
|
||||
* Build a standard stats object on top of a serialization, allocate just the
|
||||
* point shells and set the pointers to look into the data area of the
|
||||
* serialization.
|
||||
*/
|
||||
PCSTATS *pc_stats_new_from_data(const PCSCHEMA *schema, const uint8_t *mindata,
|
||||
const uint8_t *maxdata, const uint8_t *avgdata)
|
||||
{
|
||||
/*size_t sz = schema->size;*/
|
||||
PCSTATS *stats = pcalloc(sizeof(PCSTATS));
|
||||
/* All share the schema with the patch */
|
||||
stats->min.schema = schema;
|
||||
stats->max.schema = schema;
|
||||
stats->avg.schema = schema;
|
||||
/* Data points into serialization */
|
||||
stats->min.data = (uint8_t*)mindata;
|
||||
stats->max.data = (uint8_t*)maxdata;
|
||||
stats->avg.data = (uint8_t*)avgdata;
|
||||
/* Can't modify external data */
|
||||
stats->min.readonly = PC_TRUE;
|
||||
stats->max.readonly = PC_TRUE;
|
||||
stats->avg.readonly = PC_TRUE;
|
||||
/* Done */
|
||||
return stats;
|
||||
/*size_t sz = schema->size;*/
|
||||
PCSTATS *stats = pcalloc(sizeof(PCSTATS));
|
||||
/* All share the schema with the patch */
|
||||
stats->min.schema = schema;
|
||||
stats->max.schema = schema;
|
||||
stats->avg.schema = schema;
|
||||
/* Data points into serialization */
|
||||
stats->min.data = (uint8_t *)mindata;
|
||||
stats->max.data = (uint8_t *)maxdata;
|
||||
stats->avg.data = (uint8_t *)avgdata;
|
||||
/* Can't modify external data */
|
||||
stats->min.readonly = PC_TRUE;
|
||||
stats->max.readonly = PC_TRUE;
|
||||
stats->avg.readonly = PC_TRUE;
|
||||
/* Done */
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a standard stats object with read/write memory, allocate the
|
||||
* point shells and the data areas underneath. Used for initial calcution
|
||||
* of patch stats, when objects first created.
|
||||
*/
|
||||
PCSTATS *
|
||||
pc_stats_new(const PCSCHEMA *schema)
|
||||
* Build a standard stats object with read/write memory, allocate the
|
||||
* point shells and the data areas underneath. Used for initial calcution
|
||||
* of patch stats, when objects first created.
|
||||
*/
|
||||
PCSTATS *pc_stats_new(const PCSCHEMA *schema)
|
||||
{
|
||||
/*size_t sz = schema->size;*/
|
||||
PCSTATS *stats = pcalloc(sizeof(PCSTATS));
|
||||
stats->min.schema = schema;
|
||||
stats->max.schema = schema;
|
||||
stats->avg.schema = schema;
|
||||
stats->min.readonly = PC_FALSE;
|
||||
stats->max.readonly = PC_FALSE;
|
||||
stats->avg.readonly = PC_FALSE;
|
||||
stats->min.data = pcalloc(schema->size);
|
||||
stats->max.data = pcalloc(schema->size);
|
||||
stats->avg.data = pcalloc(schema->size);
|
||||
return stats;
|
||||
/*size_t sz = schema->size;*/
|
||||
PCSTATS *stats = pcalloc(sizeof(PCSTATS));
|
||||
stats->min.schema = schema;
|
||||
stats->max.schema = schema;
|
||||
stats->avg.schema = schema;
|
||||
stats->min.readonly = PC_FALSE;
|
||||
stats->max.readonly = PC_FALSE;
|
||||
stats->avg.readonly = PC_FALSE;
|
||||
stats->min.data = pcalloc(schema->size);
|
||||
stats->max.data = pcalloc(schema->size);
|
||||
stats->avg.data = pcalloc(schema->size);
|
||||
return stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate and populate a new PCSTATS from the raw data in
|
||||
* a PCDOUBLESTATS
|
||||
*/
|
||||
static PCSTATS *
|
||||
pc_stats_new_from_dstats(const PCSCHEMA *schema, const PCDOUBLESTATS *dstats)
|
||||
* Allocate and populate a new PCSTATS from the raw data in
|
||||
* a PCDOUBLESTATS
|
||||
*/
|
||||
static PCSTATS *pc_stats_new_from_dstats(const PCSCHEMA *schema,
|
||||
const PCDOUBLESTATS *dstats)
|
||||
{
|
||||
int i;
|
||||
PCSTATS *stats = pc_stats_new(schema);
|
||||
int i;
|
||||
PCSTATS *stats = pc_stats_new(schema);
|
||||
|
||||
for ( i = 0; i < schema->ndims; i++ )
|
||||
{
|
||||
pc_point_set_double(&(stats->min), schema->dims[i], dstats->dims[i].min);
|
||||
pc_point_set_double(&(stats->max), schema->dims[i], dstats->dims[i].max);
|
||||
pc_point_set_double(&(stats->avg), schema->dims[i], dstats->dims[i].sum / dstats->npoints);
|
||||
}
|
||||
return stats;
|
||||
for (i = 0; i < schema->ndims; i++)
|
||||
{
|
||||
pc_point_set_double(&(stats->min), schema->dims[i], dstats->dims[i].min);
|
||||
pc_point_set_double(&(stats->max), schema->dims[i], dstats->dims[i].max);
|
||||
pc_point_set_double(&(stats->avg), schema->dims[i],
|
||||
dstats->dims[i].sum / dstats->npoints);
|
||||
}
|
||||
return stats;
|
||||
}
|
||||
|
||||
PCSTATS *
|
||||
pc_stats_clone(const PCSTATS *stats)
|
||||
PCSTATS *pc_stats_clone(const PCSTATS *stats)
|
||||
{
|
||||
PCSTATS *s;
|
||||
if ( ! stats ) return NULL;
|
||||
s = pcalloc(sizeof(PCSTATS));
|
||||
s->min.readonly = s->max.readonly = s->avg.readonly = PC_FALSE;
|
||||
s->min.schema = stats->min.schema;
|
||||
s->max.schema = stats->max.schema;
|
||||
s->avg.schema = stats->avg.schema;
|
||||
s->min.data = pcalloc(stats->min.schema->size);
|
||||
s->max.data = pcalloc(stats->max.schema->size);
|
||||
s->avg.data = pcalloc(stats->avg.schema->size);
|
||||
memcpy(s->min.data, stats->min.data, stats->min.schema->size);
|
||||
memcpy(s->max.data, stats->max.data, stats->max.schema->size);
|
||||
memcpy(s->avg.data, stats->avg.data, stats->avg.schema->size);
|
||||
return s;
|
||||
PCSTATS *s;
|
||||
if (!stats)
|
||||
return NULL;
|
||||
s = pcalloc(sizeof(PCSTATS));
|
||||
s->min.readonly = s->max.readonly = s->avg.readonly = PC_FALSE;
|
||||
s->min.schema = stats->min.schema;
|
||||
s->max.schema = stats->max.schema;
|
||||
s->avg.schema = stats->avg.schema;
|
||||
s->min.data = pcalloc(stats->min.schema->size);
|
||||
s->max.data = pcalloc(stats->max.schema->size);
|
||||
s->avg.data = pcalloc(stats->avg.schema->size);
|
||||
memcpy(s->min.data, stats->min.data, stats->min.schema->size);
|
||||
memcpy(s->max.data, stats->max.data, stats->max.schema->size);
|
||||
memcpy(s->avg.data, stats->avg.data, stats->avg.schema->size);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
pc_patch_uncompressed_compute_stats(PCPATCH_UNCOMPRESSED *pa)
|
||||
int pc_patch_uncompressed_compute_stats(PCPATCH_UNCOMPRESSED *pa)
|
||||
{
|
||||
int i, j;
|
||||
const PCSCHEMA *schema = pa->schema;
|
||||
double val;
|
||||
PCDOUBLESTATS *dstats = pc_dstats_new(pa->schema->ndims);
|
||||
int i, j;
|
||||
const PCSCHEMA *schema = pa->schema;
|
||||
double val;
|
||||
PCDOUBLESTATS *dstats = pc_dstats_new(pa->schema->ndims);
|
||||
|
||||
if ( pa->stats )
|
||||
pc_stats_free(pa->stats);
|
||||
if (pa->stats)
|
||||
pc_stats_free(pa->stats);
|
||||
|
||||
/* Point on stack for fast access to values in patch */
|
||||
PCPOINT pt;
|
||||
pt.readonly = PC_TRUE;
|
||||
pt.schema = schema;
|
||||
pt.data = pa->data;
|
||||
/* Point on stack for fast access to values in patch */
|
||||
PCPOINT pt;
|
||||
pt.readonly = PC_TRUE;
|
||||
pt.schema = schema;
|
||||
pt.data = pa->data;
|
||||
|
||||
/* We know npoints right away */
|
||||
dstats->npoints = pa->npoints;
|
||||
/* We know npoints right away */
|
||||
dstats->npoints = pa->npoints;
|
||||
|
||||
for ( i = 0; i < pa->npoints; i++ )
|
||||
{
|
||||
for ( j = 0; j < schema->ndims; j++ )
|
||||
{
|
||||
pc_point_get_double(&pt, schema->dims[j], &val);
|
||||
/* Check minimum */
|
||||
if ( val < dstats->dims[j].min )
|
||||
dstats->dims[j].min = val;
|
||||
/* Check maximum */
|
||||
if ( val > dstats->dims[j].max )
|
||||
dstats->dims[j].max = val;
|
||||
/* Add to sum */
|
||||
dstats->dims[j].sum += val;
|
||||
}
|
||||
/* Advance to next point */
|
||||
pt.data += schema->size;
|
||||
}
|
||||
for (i = 0; i < pa->npoints; i++)
|
||||
{
|
||||
for (j = 0; j < schema->ndims; j++)
|
||||
{
|
||||
pc_point_get_double(&pt, schema->dims[j], &val);
|
||||
/* Check minimum */
|
||||
if (val < dstats->dims[j].min)
|
||||
dstats->dims[j].min = val;
|
||||
/* Check maximum */
|
||||
if (val > dstats->dims[j].max)
|
||||
dstats->dims[j].max = val;
|
||||
/* Add to sum */
|
||||
dstats->dims[j].sum += val;
|
||||
}
|
||||
/* Advance to next point */
|
||||
pt.data += schema->size;
|
||||
}
|
||||
|
||||
pa->stats = pc_stats_new_from_dstats(pa->schema, dstats);
|
||||
pc_dstats_free(dstats);
|
||||
return PC_SUCCESS;
|
||||
pa->stats = pc_stats_new_from_dstats(pa->schema, dstats);
|
||||
pc_dstats_free(dstats);
|
||||
return PC_SUCCESS;
|
||||
}
|
||||
|
||||
size_t
|
||||
pc_stats_size(const PCSCHEMA *schema)
|
||||
{
|
||||
return 3*schema->size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
size_t pc_stats_size(const PCSCHEMA *schema) { return 3 * schema->size; }
|
||||
|
||||
615
lib/pc_util.c
615
lib/pc_util.c
@ -1,417 +1,402 @@
|
||||
/***********************************************************************
|
||||
* pc_util.c
|
||||
*
|
||||
* Handy functions used by the library.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_util.c
|
||||
*
|
||||
* Handy functions used by the library.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "pc_api_internal.h"
|
||||
#include <float.h>
|
||||
|
||||
/**********************************************************************************
|
||||
* WKB AND ENDIANESS UTILITIES
|
||||
*/
|
||||
* WKB AND ENDIANESS UTILITIES
|
||||
*/
|
||||
|
||||
/* Our static character->number map. Anything > 15 is invalid */
|
||||
static uint8_t hex2char[256] =
|
||||
static uint8_t hex2char[256] = {
|
||||
/* not Hex characters */
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
/* 0-9 */
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 20, 20, 20, 20, 20, 20,
|
||||
/* A-F */
|
||||
20, 10, 11, 12, 13, 14, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
/* not Hex characters */
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
/* a-f */
|
||||
20, 10, 11, 12, 13, 14, 15, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
/* not Hex characters (upper 128 characters) */
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
|
||||
20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20};
|
||||
|
||||
uint8_t *pc_bytes_from_hexbytes(const char *hexbuf, size_t hexsize)
|
||||
{
|
||||
/* not Hex characters */
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
/* 0-9 */
|
||||
0,1,2,3,4,5,6,7,8,9,20,20,20,20,20,20,
|
||||
/* A-F */
|
||||
20,10,11,12,13,14,15,20,20,20,20,20,20,20,20,20,
|
||||
/* not Hex characters */
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
/* a-f */
|
||||
20,10,11,12,13,14,15,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
/* not Hex characters (upper 128 characters) */
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,
|
||||
20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20
|
||||
};
|
||||
uint8_t *buf = NULL;
|
||||
register uint8_t h1, h2;
|
||||
int i;
|
||||
|
||||
if (hexsize % 2)
|
||||
pcerror("Invalid hex string, length (%d) has to be a multiple of two!",
|
||||
hexsize);
|
||||
|
||||
uint8_t*
|
||||
pc_bytes_from_hexbytes(const char *hexbuf, size_t hexsize)
|
||||
{
|
||||
uint8_t *buf = NULL;
|
||||
register uint8_t h1, h2;
|
||||
int i;
|
||||
buf = pcalloc(hexsize / 2);
|
||||
|
||||
if( hexsize % 2 )
|
||||
pcerror("Invalid hex string, length (%d) has to be a multiple of two!", hexsize);
|
||||
if (!buf)
|
||||
pcerror("Unable to allocate memory buffer.");
|
||||
|
||||
buf = pcalloc(hexsize/2);
|
||||
|
||||
if( ! buf )
|
||||
pcerror("Unable to allocate memory buffer.");
|
||||
|
||||
for( i = 0; i < hexsize/2; i++ )
|
||||
{
|
||||
h1 = hex2char[(int)hexbuf[2*i]];
|
||||
h2 = hex2char[(int)hexbuf[2*i+1]];
|
||||
if( h1 > 15 )
|
||||
pcerror("Invalid hex character (%c) encountered", hexbuf[2*i]);
|
||||
if( h2 > 15 )
|
||||
pcerror("Invalid hex character (%c) encountered", hexbuf[2*i+1]);
|
||||
/* First character is high bits, second is low bits */
|
||||
buf[i] = ((h1 & 0x0F) << 4) | (h2 & 0x0F);
|
||||
}
|
||||
return buf;
|
||||
for (i = 0; i < hexsize / 2; i++)
|
||||
{
|
||||
h1 = hex2char[(int)hexbuf[2 * i]];
|
||||
h2 = hex2char[(int)hexbuf[2 * i + 1]];
|
||||
if (h1 > 15)
|
||||
pcerror("Invalid hex character (%c) encountered", hexbuf[2 * i]);
|
||||
if (h2 > 15)
|
||||
pcerror("Invalid hex character (%c) encountered", hexbuf[2 * i + 1]);
|
||||
/* First character is high bits, second is low bits */
|
||||
buf[i] = ((h1 & 0x0F) << 4) | (h2 & 0x0F);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
static char *hexchr = "0123456789ABCDEF";
|
||||
|
||||
char*
|
||||
pc_hexbytes_from_bytes(const uint8_t *bytebuf, size_t bytesize)
|
||||
char *pc_hexbytes_from_bytes(const uint8_t *bytebuf, size_t bytesize)
|
||||
{
|
||||
char *buf = pcalloc(2*bytesize + 1); /* 2 chars per byte + null terminator */
|
||||
int i;
|
||||
buf[2*bytesize] = '\0';
|
||||
for ( i = 0; i < bytesize; i++ )
|
||||
{
|
||||
/* Top four bits to 0-F */
|
||||
buf[2*i] = hexchr[bytebuf[i] >> 4];
|
||||
/* Bottom four bits to 0-F */
|
||||
buf[2*i+1] = hexchr[bytebuf[i] & 0x0F];
|
||||
}
|
||||
char *buf =
|
||||
pcalloc(2 * bytesize + 1); /* 2 chars per byte + null terminator */
|
||||
int i;
|
||||
buf[2 * bytesize] = '\0';
|
||||
for (i = 0; i < bytesize; i++)
|
||||
{
|
||||
/* Top four bits to 0-F */
|
||||
buf[2 * i] = hexchr[bytebuf[i] >> 4];
|
||||
/* Bottom four bits to 0-F */
|
||||
buf[2 * i + 1] = hexchr[bytebuf[i] & 0x0F];
|
||||
}
|
||||
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
|
||||
/* 0 = xdr | big endian */
|
||||
/* 1 = ndr | little endian */
|
||||
char
|
||||
machine_endian(void)
|
||||
char machine_endian(void)
|
||||
{
|
||||
static int check_int = 1; /* dont modify this!!! */
|
||||
return *((char *) &check_int);
|
||||
static int check_int = 1; /* dont modify this!!! */
|
||||
return *((char *)&check_int);
|
||||
}
|
||||
|
||||
int32_t
|
||||
int32_flip_endian(int32_t val)
|
||||
int32_t int32_flip_endian(int32_t val)
|
||||
{
|
||||
int i;
|
||||
uint8_t tmp;
|
||||
uint8_t b[4];
|
||||
memcpy(b, &val, 4);
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
tmp = b[i];
|
||||
b[i] = b[3-i];
|
||||
b[3-i] = tmp;
|
||||
}
|
||||
memcpy(&val, b, 4);
|
||||
return val;
|
||||
int i;
|
||||
uint8_t tmp;
|
||||
uint8_t b[4];
|
||||
memcpy(b, &val, 4);
|
||||
for (i = 0; i < 2; i++)
|
||||
{
|
||||
tmp = b[i];
|
||||
b[i] = b[3 - i];
|
||||
b[3 - i] = tmp;
|
||||
}
|
||||
memcpy(&val, b, 4);
|
||||
return val;
|
||||
}
|
||||
|
||||
int16_t
|
||||
int16_flip_endian(int16_t val)
|
||||
int16_t int16_flip_endian(int16_t val)
|
||||
{
|
||||
uint8_t tmp;
|
||||
uint8_t b[2];
|
||||
memcpy(b, &val, 2);
|
||||
tmp = b[0];
|
||||
b[0] = b[1];
|
||||
b[1] = tmp;
|
||||
memcpy(&val, b, 2);
|
||||
return val;
|
||||
uint8_t tmp;
|
||||
uint8_t b[2];
|
||||
memcpy(b, &val, 2);
|
||||
tmp = b[0];
|
||||
b[0] = b[1];
|
||||
b[1] = tmp;
|
||||
memcpy(&val, b, 2);
|
||||
return val;
|
||||
}
|
||||
|
||||
int32_t
|
||||
wkb_get_int32(const uint8_t *wkb, int flip_endian)
|
||||
int32_t wkb_get_int32(const uint8_t *wkb, int flip_endian)
|
||||
{
|
||||
int32_t i;
|
||||
memcpy(&i, wkb, 4);
|
||||
if ( flip_endian )
|
||||
return int32_flip_endian(i);
|
||||
else
|
||||
return i;
|
||||
int32_t i;
|
||||
memcpy(&i, wkb, 4);
|
||||
if (flip_endian)
|
||||
return int32_flip_endian(i);
|
||||
else
|
||||
return i;
|
||||
}
|
||||
|
||||
int16_t
|
||||
wkb_get_int16(const uint8_t *wkb, int flip_endian)
|
||||
int16_t wkb_get_int16(const uint8_t *wkb, int flip_endian)
|
||||
{
|
||||
int16_t i;
|
||||
memcpy(&i, wkb, 2);
|
||||
if ( flip_endian )
|
||||
return int16_flip_endian(i);
|
||||
else
|
||||
return i;
|
||||
int16_t i;
|
||||
memcpy(&i, wkb, 2);
|
||||
if (flip_endian)
|
||||
return int16_flip_endian(i);
|
||||
else
|
||||
return i;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
wkb_set_double(uint8_t *wkb, double d)
|
||||
uint8_t *wkb_set_double(uint8_t *wkb, double d)
|
||||
{
|
||||
memcpy(wkb, &d, 8);
|
||||
wkb += 8;
|
||||
return wkb;
|
||||
memcpy(wkb, &d, 8);
|
||||
wkb += 8;
|
||||
return wkb;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
wkb_set_uint32(uint8_t *wkb, uint32_t i)
|
||||
uint8_t *wkb_set_uint32(uint8_t *wkb, uint32_t i)
|
||||
{
|
||||
memcpy(wkb, &i, 4);
|
||||
wkb += 4;
|
||||
return wkb;
|
||||
memcpy(wkb, &i, 4);
|
||||
wkb += 4;
|
||||
return wkb;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
wkb_set_char(uint8_t *wkb, char c)
|
||||
uint8_t *wkb_set_char(uint8_t *wkb, char c)
|
||||
{
|
||||
memcpy(wkb, &c, 1);
|
||||
wkb += 1;
|
||||
return wkb;
|
||||
memcpy(wkb, &c, 1);
|
||||
wkb += 1;
|
||||
return wkb;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
pc_wkb_get_pcid(const uint8_t *wkb)
|
||||
uint32_t pc_wkb_get_pcid(const uint8_t *wkb)
|
||||
{
|
||||
/* We expect the bytes to be in WKB format for PCPOINT/PCPATCH */
|
||||
/* byte 0: endian */
|
||||
/* byte 1-4: pcid */
|
||||
/* ...data... */
|
||||
uint32_t pcid;
|
||||
memcpy(&pcid, wkb + 1, 4);
|
||||
if ( wkb[0] != machine_endian() )
|
||||
{
|
||||
pcid = int32_flip_endian(pcid);
|
||||
}
|
||||
return pcid;
|
||||
/* We expect the bytes to be in WKB format for PCPOINT/PCPATCH */
|
||||
/* byte 0: endian */
|
||||
/* byte 1-4: pcid */
|
||||
/* ...data... */
|
||||
uint32_t pcid;
|
||||
memcpy(&pcid, wkb + 1, 4);
|
||||
if (wkb[0] != machine_endian())
|
||||
{
|
||||
pcid = int32_flip_endian(pcid);
|
||||
}
|
||||
return pcid;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wkb_get_compression(const uint8_t *wkb)
|
||||
uint32_t wkb_get_compression(const uint8_t *wkb)
|
||||
{
|
||||
/* We expect the bytes to be in WKB format for PCPATCH */
|
||||
/* byte 0: endian */
|
||||
/* byte 1-4: pcid */
|
||||
/* byte 5-8: compression */
|
||||
/* ...data... */
|
||||
uint32_t compression;
|
||||
memcpy(&compression, wkb+1+4, 4);
|
||||
if ( wkb[0] != machine_endian() )
|
||||
{
|
||||
compression = int32_flip_endian(compression);
|
||||
}
|
||||
return compression;
|
||||
/* We expect the bytes to be in WKB format for PCPATCH */
|
||||
/* byte 0: endian */
|
||||
/* byte 1-4: pcid */
|
||||
/* byte 5-8: compression */
|
||||
/* ...data... */
|
||||
uint32_t compression;
|
||||
memcpy(&compression, wkb + 1 + 4, 4);
|
||||
if (wkb[0] != machine_endian())
|
||||
{
|
||||
compression = int32_flip_endian(compression);
|
||||
}
|
||||
return compression;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
wkb_get_npoints(const uint8_t *wkb)
|
||||
uint32_t wkb_get_npoints(const uint8_t *wkb)
|
||||
{
|
||||
/* We expect the bytes to be in WKB format for PCPATCH */
|
||||
/* byte 0: endian */
|
||||
/* byte 1-4: pcid */
|
||||
/* byte 5-8: compression */
|
||||
/* byte 9-12: npoints */
|
||||
/* ...data... */
|
||||
uint32_t npoints;
|
||||
memcpy(&npoints, wkb+1+4+4, 4);
|
||||
if ( wkb[0] != machine_endian() )
|
||||
{
|
||||
npoints = int32_flip_endian(npoints);
|
||||
}
|
||||
return npoints;
|
||||
/* We expect the bytes to be in WKB format for PCPATCH */
|
||||
/* byte 0: endian */
|
||||
/* byte 1-4: pcid */
|
||||
/* byte 5-8: compression */
|
||||
/* byte 9-12: npoints */
|
||||
/* ...data... */
|
||||
uint32_t npoints;
|
||||
memcpy(&npoints, wkb + 1 + 4 + 4, 4);
|
||||
if (wkb[0] != machine_endian())
|
||||
{
|
||||
npoints = int32_flip_endian(npoints);
|
||||
}
|
||||
return npoints;
|
||||
}
|
||||
|
||||
uint8_t*
|
||||
uncompressed_bytes_flip_endian(const uint8_t *bytebuf, const PCSCHEMA *schema, uint32_t npoints)
|
||||
uint8_t *uncompressed_bytes_flip_endian(const uint8_t *bytebuf,
|
||||
const PCSCHEMA *schema,
|
||||
uint32_t npoints)
|
||||
{
|
||||
int i, j, k;
|
||||
size_t bufsize = schema->size * npoints;
|
||||
uint8_t *buf = pcalloc(bufsize);
|
||||
int i, j, k;
|
||||
size_t bufsize = schema->size * npoints;
|
||||
uint8_t *buf = pcalloc(bufsize);
|
||||
|
||||
memcpy(buf, bytebuf, bufsize);
|
||||
memcpy(buf, bytebuf, bufsize);
|
||||
|
||||
for ( i = 0; i < npoints ; i++ )
|
||||
{
|
||||
for ( j = 0; j < schema->ndims; j++ )
|
||||
{
|
||||
PCDIMENSION *dimension = schema->dims[j];
|
||||
uint8_t *ptr = buf + i * schema->size + dimension->byteoffset;
|
||||
for (i = 0; i < npoints; i++)
|
||||
{
|
||||
for (j = 0; j < schema->ndims; j++)
|
||||
{
|
||||
PCDIMENSION *dimension = schema->dims[j];
|
||||
uint8_t *ptr = buf + i * schema->size + dimension->byteoffset;
|
||||
|
||||
for ( k = 0; k < ((dimension->size)/2); k++ )
|
||||
{
|
||||
int l = dimension->size - k - 1;
|
||||
uint8_t tmp = ptr[k];
|
||||
ptr[k] = ptr[l];
|
||||
ptr[l] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (k = 0; k < ((dimension->size) / 2); k++)
|
||||
{
|
||||
int l = dimension->size - k - 1;
|
||||
uint8_t tmp = ptr[k];
|
||||
ptr[k] = ptr[l];
|
||||
ptr[l] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int
|
||||
pc_bounds_intersects(const PCBOUNDS *b1, const PCBOUNDS *b2)
|
||||
int pc_bounds_intersects(const PCBOUNDS *b1, const PCBOUNDS *b2)
|
||||
{
|
||||
if ( b1->xmin > b2->xmax ||
|
||||
b1->xmax < b2->xmin ||
|
||||
b1->ymin > b2->ymax ||
|
||||
b1->ymax < b2->ymin )
|
||||
{
|
||||
return PC_FALSE;
|
||||
}
|
||||
return PC_TRUE;
|
||||
if (b1->xmin > b2->xmax || b1->xmax < b2->xmin || b1->ymin > b2->ymax ||
|
||||
b1->ymax < b2->ymin)
|
||||
{
|
||||
return PC_FALSE;
|
||||
}
|
||||
return PC_TRUE;
|
||||
}
|
||||
|
||||
void
|
||||
pc_bounds_init(PCBOUNDS *b)
|
||||
void pc_bounds_init(PCBOUNDS *b)
|
||||
{
|
||||
b->xmin = b->ymin = DBL_MAX;
|
||||
b->xmax = b->ymax = -1*DBL_MAX;
|
||||
b->xmin = b->ymin = DBL_MAX;
|
||||
b->xmax = b->ymax = -1 * DBL_MAX;
|
||||
}
|
||||
|
||||
void pc_bounds_merge(PCBOUNDS *b1, const PCBOUNDS *b2)
|
||||
{
|
||||
if ( b2->xmin < b1->xmin ) b1->xmin = b2->xmin;
|
||||
if ( b2->ymin < b1->ymin ) b1->ymin = b2->ymin;
|
||||
if ( b2->xmax > b1->xmax ) b1->xmax = b2->xmax;
|
||||
if ( b2->ymax > b1->ymax ) b1->ymax = b2->ymax;
|
||||
if (b2->xmin < b1->xmin)
|
||||
b1->xmin = b2->xmin;
|
||||
if (b2->ymin < b1->ymin)
|
||||
b1->ymin = b2->ymin;
|
||||
if (b2->xmax > b1->xmax)
|
||||
b1->xmax = b2->xmax;
|
||||
if (b2->ymax > b1->ymax)
|
||||
b1->ymax = b2->ymax;
|
||||
}
|
||||
|
||||
static uint32_t srid_mask = 0x20000000;
|
||||
static uint32_t m_mask = 0x40000000;
|
||||
static uint32_t z_mask = 0x80000000;
|
||||
|
||||
uint8_t *
|
||||
pc_bounding_diagonal_wkb_from_bounds(
|
||||
const PCBOUNDS *bounds, const PCSCHEMA *schema, size_t *wkbsize)
|
||||
uint8_t *pc_bounding_diagonal_wkb_from_bounds(const PCBOUNDS *bounds,
|
||||
const PCSCHEMA *schema,
|
||||
size_t *wkbsize)
|
||||
{
|
||||
uint8_t *wkb, *ptr;
|
||||
uint32_t wkbtype;
|
||||
size_t size;
|
||||
uint8_t *wkb, *ptr;
|
||||
uint32_t wkbtype;
|
||||
size_t size;
|
||||
|
||||
wkbtype = 2; /* WKB LINESTRING */
|
||||
size = 1 + 4 + 4 + (2 * 2 * 8); /* endian + type + npoints + 2 dbl pts */
|
||||
wkbtype = 2; /* WKB LINESTRING */
|
||||
size = 1 + 4 + 4 + (2 * 2 * 8); /* endian + type + npoints + 2 dbl pts */
|
||||
|
||||
if ( schema->srid != 0 )
|
||||
{
|
||||
wkbtype |= srid_mask;
|
||||
size += 4;
|
||||
}
|
||||
if (schema->srid != 0)
|
||||
{
|
||||
wkbtype |= srid_mask;
|
||||
size += 4;
|
||||
}
|
||||
|
||||
wkb = pcalloc(size);
|
||||
ptr = wkb;
|
||||
wkb = pcalloc(size);
|
||||
ptr = wkb;
|
||||
|
||||
ptr = wkb_set_char(ptr, machine_endian()); /* Endian flag */
|
||||
ptr = wkb_set_uint32(ptr, wkbtype); /* Geometry type */
|
||||
ptr = wkb_set_char(ptr, machine_endian()); /* Endian flag */
|
||||
ptr = wkb_set_uint32(ptr, wkbtype); /* Geometry type */
|
||||
|
||||
if ( schema->srid != 0 )
|
||||
{
|
||||
ptr = wkb_set_uint32(ptr, schema->srid); /* SRID */
|
||||
}
|
||||
if (schema->srid != 0)
|
||||
{
|
||||
ptr = wkb_set_uint32(ptr, schema->srid); /* SRID */
|
||||
}
|
||||
|
||||
ptr = wkb_set_uint32(ptr, 2); /* NPOINTS = 2 */
|
||||
ptr = wkb_set_uint32(ptr, 2); /* NPOINTS = 2 */
|
||||
|
||||
// point 1
|
||||
ptr = wkb_set_double(ptr, bounds->xmin);
|
||||
ptr = wkb_set_double(ptr, bounds->ymin);
|
||||
// point 1
|
||||
ptr = wkb_set_double(ptr, bounds->xmin);
|
||||
ptr = wkb_set_double(ptr, bounds->ymin);
|
||||
|
||||
// point 2
|
||||
ptr = wkb_set_double(ptr, bounds->xmax);
|
||||
ptr = wkb_set_double(ptr, bounds->ymax);
|
||||
// point 2
|
||||
ptr = wkb_set_double(ptr, bounds->xmax);
|
||||
ptr = wkb_set_double(ptr, bounds->ymax);
|
||||
|
||||
if ( wkbsize )
|
||||
*wkbsize = size;
|
||||
if (wkbsize)
|
||||
*wkbsize = size;
|
||||
|
||||
return wkb;
|
||||
return wkb;
|
||||
}
|
||||
|
||||
uint8_t *
|
||||
pc_bounding_diagonal_wkb_from_stats(const PCSTATS *stats, size_t *wkbsize)
|
||||
uint8_t *pc_bounding_diagonal_wkb_from_stats(const PCSTATS *stats,
|
||||
size_t *wkbsize)
|
||||
{
|
||||
const PCSCHEMA *schema = stats->min.schema;
|
||||
const PCPOINT *stat;
|
||||
uint8_t *wkb, *ptr;
|
||||
uint32_t wkbtype;
|
||||
size_t size;
|
||||
double val;
|
||||
const PCSCHEMA *schema = stats->min.schema;
|
||||
const PCPOINT *stat;
|
||||
uint8_t *wkb, *ptr;
|
||||
uint32_t wkbtype;
|
||||
size_t size;
|
||||
double val;
|
||||
|
||||
wkbtype = 2; /* WKB LINESTRING */
|
||||
size = 1 + 4 + 4 + (2 * 2 * 8); /* endian + type + npoints + 2 dbl pts */
|
||||
wkbtype = 2; /* WKB LINESTRING */
|
||||
size = 1 + 4 + 4 + (2 * 2 * 8); /* endian + type + npoints + 2 dbl pts */
|
||||
|
||||
if ( schema->srid != 0 )
|
||||
{
|
||||
wkbtype |= srid_mask;
|
||||
size += 4;
|
||||
}
|
||||
if ( schema->zdim )
|
||||
{
|
||||
wkbtype |= z_mask;
|
||||
size += 2 * 8;
|
||||
}
|
||||
if ( schema->mdim )
|
||||
{
|
||||
wkbtype |= m_mask;
|
||||
size += 2 * 8;
|
||||
}
|
||||
if (schema->srid != 0)
|
||||
{
|
||||
wkbtype |= srid_mask;
|
||||
size += 4;
|
||||
}
|
||||
if (schema->zdim)
|
||||
{
|
||||
wkbtype |= z_mask;
|
||||
size += 2 * 8;
|
||||
}
|
||||
if (schema->mdim)
|
||||
{
|
||||
wkbtype |= m_mask;
|
||||
size += 2 * 8;
|
||||
}
|
||||
|
||||
wkb = pcalloc(size);
|
||||
ptr = wkb;
|
||||
wkb = pcalloc(size);
|
||||
ptr = wkb;
|
||||
|
||||
ptr = wkb_set_char(ptr, machine_endian()); /* Endian flag */
|
||||
ptr = wkb_set_uint32(ptr, wkbtype); /* Geometry type */
|
||||
ptr = wkb_set_char(ptr, machine_endian()); /* Endian flag */
|
||||
ptr = wkb_set_uint32(ptr, wkbtype); /* Geometry type */
|
||||
|
||||
if ( schema->srid != 0 )
|
||||
{
|
||||
ptr = wkb_set_uint32(ptr, schema->srid); /* SRID */
|
||||
}
|
||||
if (schema->srid != 0)
|
||||
{
|
||||
ptr = wkb_set_uint32(ptr, schema->srid); /* SRID */
|
||||
}
|
||||
|
||||
ptr = wkb_set_uint32(ptr, 2); /* NPOINTS = 2 */
|
||||
ptr = wkb_set_uint32(ptr, 2); /* NPOINTS = 2 */
|
||||
|
||||
// point 1
|
||||
stat = &stats->min;
|
||||
pc_point_get_x(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
pc_point_get_y(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
if ( schema->zdim )
|
||||
{
|
||||
pc_point_get_z(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
}
|
||||
if ( schema->mdim )
|
||||
{
|
||||
pc_point_get_m(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
}
|
||||
// point 1
|
||||
stat = &stats->min;
|
||||
pc_point_get_x(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
pc_point_get_y(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
if (schema->zdim)
|
||||
{
|
||||
pc_point_get_z(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
}
|
||||
if (schema->mdim)
|
||||
{
|
||||
pc_point_get_m(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
}
|
||||
|
||||
// point 2
|
||||
stat = &stats->max;
|
||||
pc_point_get_x(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
pc_point_get_y(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
if ( schema->zdim )
|
||||
{
|
||||
pc_point_get_z(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
}
|
||||
if ( schema->mdim )
|
||||
{
|
||||
pc_point_get_m(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
}
|
||||
// point 2
|
||||
stat = &stats->max;
|
||||
pc_point_get_x(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
pc_point_get_y(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
if (schema->zdim)
|
||||
{
|
||||
pc_point_get_z(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
}
|
||||
if (schema->mdim)
|
||||
{
|
||||
pc_point_get_m(stat, &val);
|
||||
ptr = wkb_set_double(ptr, val);
|
||||
}
|
||||
|
||||
if ( wkbsize )
|
||||
*wkbsize = size;
|
||||
if (wkbsize)
|
||||
*wkbsize = size;
|
||||
|
||||
return wkb;
|
||||
return wkb;
|
||||
}
|
||||
|
||||
394
lib/pc_val.c
394
lib/pc_val.c
@ -1,223 +1,225 @@
|
||||
/***********************************************************************
|
||||
* pc_val.c
|
||||
*
|
||||
* Pointclound value handling. Create, get and set values.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
* pc_val.c
|
||||
*
|
||||
* Pointclound value handling. Create, get and set values.
|
||||
*
|
||||
* PgSQL Pointcloud is free and open source software provided
|
||||
* by the Government of Canada
|
||||
* Copyright (c) 2013 Natural Resources Canada
|
||||
*
|
||||
***********************************************************************/
|
||||
|
||||
#include "pc_api_internal.h"
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
#include "pc_api_internal.h"
|
||||
|
||||
|
||||
double pc_value_unscale_unoffset(double val, const PCDIMENSION *dim)
|
||||
{
|
||||
/* Offset value */
|
||||
if ( dim->offset )
|
||||
val -= dim->offset;
|
||||
/* Offset value */
|
||||
if (dim->offset)
|
||||
val -= dim->offset;
|
||||
|
||||
/* Scale value */
|
||||
if ( dim->scale != 1 )
|
||||
val /= dim->scale;
|
||||
/* Scale value */
|
||||
if (dim->scale != 1)
|
||||
val /= dim->scale;
|
||||
|
||||
return val;
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
double pc_value_scale_offset(double val, const PCDIMENSION *dim)
|
||||
{
|
||||
/* Scale value */
|
||||
if ( dim->scale != 1 )
|
||||
val *= dim->scale;
|
||||
/* Scale value */
|
||||
if (dim->scale != 1)
|
||||
val *= dim->scale;
|
||||
|
||||
/* Offset value */
|
||||
if ( dim->offset )
|
||||
val += dim->offset;
|
||||
/* Offset value */
|
||||
if (dim->offset)
|
||||
val += dim->offset;
|
||||
|
||||
return val;
|
||||
return val;
|
||||
}
|
||||
|
||||
double
|
||||
pc_value_from_ptr(const uint8_t *ptr, const PCDIMENSION *dim)
|
||||
double pc_value_from_ptr(const uint8_t *ptr, const PCDIMENSION *dim)
|
||||
{
|
||||
double val = pc_double_from_ptr(ptr, dim->interpretation);
|
||||
return pc_value_scale_offset(val, dim);
|
||||
double val = pc_double_from_ptr(ptr, dim->interpretation);
|
||||
return pc_value_scale_offset(val, dim);
|
||||
}
|
||||
|
||||
double
|
||||
pc_double_from_ptr(const uint8_t *ptr, uint32_t interpretation)
|
||||
double pc_double_from_ptr(const uint8_t *ptr, uint32_t interpretation)
|
||||
{
|
||||
switch( interpretation )
|
||||
{
|
||||
case PC_UINT8:
|
||||
{
|
||||
uint8_t v;
|
||||
memcpy(&(v), ptr, sizeof(uint8_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_UINT16:
|
||||
{
|
||||
uint16_t v;
|
||||
memcpy(&(v), ptr, sizeof(uint16_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_UINT32:
|
||||
{
|
||||
uint32_t v;
|
||||
memcpy(&(v), ptr, sizeof(uint32_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_UINT64:
|
||||
{
|
||||
uint64_t v;
|
||||
memcpy(&(v), ptr, sizeof(uint64_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_INT8:
|
||||
{
|
||||
int8_t v;
|
||||
memcpy(&(v), ptr, sizeof(int8_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_INT16:
|
||||
{
|
||||
int16_t v;
|
||||
memcpy(&(v), ptr, sizeof(int16_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_INT32:
|
||||
{
|
||||
int32_t v;
|
||||
memcpy(&(v), ptr, sizeof(int32_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_INT64:
|
||||
{
|
||||
int64_t v;
|
||||
memcpy(&(v), ptr, sizeof(int64_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_FLOAT:
|
||||
{
|
||||
float v;
|
||||
memcpy(&(v), ptr, sizeof(float));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_DOUBLE:
|
||||
{
|
||||
double v;
|
||||
memcpy(&(v), ptr, sizeof(double));
|
||||
return v;
|
||||
}
|
||||
default:
|
||||
{
|
||||
pcerror("unknown interpretation type %d encountered in pc_double_from_ptr", interpretation);
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
switch (interpretation)
|
||||
{
|
||||
case PC_UINT8:
|
||||
{
|
||||
uint8_t v;
|
||||
memcpy(&(v), ptr, sizeof(uint8_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_UINT16:
|
||||
{
|
||||
uint16_t v;
|
||||
memcpy(&(v), ptr, sizeof(uint16_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_UINT32:
|
||||
{
|
||||
uint32_t v;
|
||||
memcpy(&(v), ptr, sizeof(uint32_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_UINT64:
|
||||
{
|
||||
uint64_t v;
|
||||
memcpy(&(v), ptr, sizeof(uint64_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_INT8:
|
||||
{
|
||||
int8_t v;
|
||||
memcpy(&(v), ptr, sizeof(int8_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_INT16:
|
||||
{
|
||||
int16_t v;
|
||||
memcpy(&(v), ptr, sizeof(int16_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_INT32:
|
||||
{
|
||||
int32_t v;
|
||||
memcpy(&(v), ptr, sizeof(int32_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_INT64:
|
||||
{
|
||||
int64_t v;
|
||||
memcpy(&(v), ptr, sizeof(int64_t));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_FLOAT:
|
||||
{
|
||||
float v;
|
||||
memcpy(&(v), ptr, sizeof(float));
|
||||
return (double)v;
|
||||
}
|
||||
case PC_DOUBLE:
|
||||
{
|
||||
double v;
|
||||
memcpy(&(v), ptr, sizeof(double));
|
||||
return v;
|
||||
}
|
||||
default:
|
||||
{
|
||||
pcerror("unknown interpretation type %d encountered in pc_double_from_ptr",
|
||||
interpretation);
|
||||
}
|
||||
}
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
#define CLAMP(v,min,max,t,format) do { \
|
||||
if ( v > max ) { \
|
||||
pcwarn("Value %g truncated to "format" to fit in "t, v, max); \
|
||||
v = max; \
|
||||
} else if ( v < min ) { \
|
||||
pcwarn("Value %g truncated to "format" to fit in "t, v, min); \
|
||||
v = min; \
|
||||
} \
|
||||
} while(0)
|
||||
#define CLAMP(v, min, max, t, format) \
|
||||
do \
|
||||
{ \
|
||||
if (v > max) \
|
||||
{ \
|
||||
pcwarn("Value %g truncated to " format " to fit in " t, v, max); \
|
||||
v = max; \
|
||||
} \
|
||||
else if (v < min) \
|
||||
{ \
|
||||
pcwarn("Value %g truncated to " format " to fit in " t, v, min); \
|
||||
v = min; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
int
|
||||
pc_double_to_ptr(uint8_t *ptr, uint32_t interpretation, double val)
|
||||
int pc_double_to_ptr(uint8_t *ptr, uint32_t interpretation, double val)
|
||||
{
|
||||
switch( interpretation )
|
||||
{
|
||||
case PC_UINT8:
|
||||
{
|
||||
uint8_t v;
|
||||
CLAMP(val, 0, UINT8_MAX, "uint8_t","%u");
|
||||
v = (uint8_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(uint8_t));
|
||||
break;
|
||||
}
|
||||
case PC_UINT16:
|
||||
{
|
||||
uint16_t v;
|
||||
CLAMP(val, 0, UINT16_MAX, "uint16_t","%u");
|
||||
v = (uint16_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(uint16_t));
|
||||
break;
|
||||
}
|
||||
case PC_UINT32:
|
||||
{
|
||||
uint32_t v;
|
||||
CLAMP(val, 0, UINT32_MAX, "uint32","%u");
|
||||
v = (uint32_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(uint32_t));
|
||||
break;
|
||||
}
|
||||
case PC_UINT64:
|
||||
{
|
||||
uint64_t v;
|
||||
CLAMP(val, 0, UINT64_MAX, "uint64","%u");
|
||||
v = (uint64_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(uint64_t));
|
||||
break;
|
||||
}
|
||||
case PC_INT8:
|
||||
{
|
||||
int8_t v;
|
||||
CLAMP(val, INT8_MIN, INT8_MAX, "int8","%d");
|
||||
v = (int8_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(int8_t));
|
||||
break;
|
||||
}
|
||||
case PC_INT16:
|
||||
{
|
||||
int16_t v;
|
||||
CLAMP(val, INT16_MIN, INT16_MAX, "int16","%d");
|
||||
v = (int16_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(int16_t));
|
||||
break;
|
||||
}
|
||||
case PC_INT32:
|
||||
{
|
||||
int32_t v;
|
||||
CLAMP(val, INT32_MIN, INT32_MAX, "int32","%d");
|
||||
v = (int32_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(int32_t));
|
||||
break;
|
||||
}
|
||||
case PC_INT64:
|
||||
{
|
||||
int64_t v;
|
||||
CLAMP(val, INT64_MIN, INT64_MAX, "int64","%d");
|
||||
v = (int64_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(int64_t));
|
||||
break;
|
||||
}
|
||||
case PC_FLOAT:
|
||||
{
|
||||
float v = (float)val;
|
||||
memcpy(ptr, &(v), sizeof(float));
|
||||
break;
|
||||
}
|
||||
case PC_DOUBLE:
|
||||
{
|
||||
double v = val;
|
||||
memcpy(ptr, &(v), sizeof(double));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
pcerror("unknown interpretation type %d encountered in pc_double_to_ptr", interpretation);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
}
|
||||
switch (interpretation)
|
||||
{
|
||||
case PC_UINT8:
|
||||
{
|
||||
uint8_t v;
|
||||
CLAMP(val, 0, UINT8_MAX, "uint8_t", "%u");
|
||||
v = (uint8_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(uint8_t));
|
||||
break;
|
||||
}
|
||||
case PC_UINT16:
|
||||
{
|
||||
uint16_t v;
|
||||
CLAMP(val, 0, UINT16_MAX, "uint16_t", "%u");
|
||||
v = (uint16_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(uint16_t));
|
||||
break;
|
||||
}
|
||||
case PC_UINT32:
|
||||
{
|
||||
uint32_t v;
|
||||
CLAMP(val, 0, UINT32_MAX, "uint32", "%u");
|
||||
v = (uint32_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(uint32_t));
|
||||
break;
|
||||
}
|
||||
case PC_UINT64:
|
||||
{
|
||||
uint64_t v;
|
||||
CLAMP(val, 0, UINT64_MAX, "uint64", "%u");
|
||||
v = (uint64_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(uint64_t));
|
||||
break;
|
||||
}
|
||||
case PC_INT8:
|
||||
{
|
||||
int8_t v;
|
||||
CLAMP(val, INT8_MIN, INT8_MAX, "int8", "%d");
|
||||
v = (int8_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(int8_t));
|
||||
break;
|
||||
}
|
||||
case PC_INT16:
|
||||
{
|
||||
int16_t v;
|
||||
CLAMP(val, INT16_MIN, INT16_MAX, "int16", "%d");
|
||||
v = (int16_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(int16_t));
|
||||
break;
|
||||
}
|
||||
case PC_INT32:
|
||||
{
|
||||
int32_t v;
|
||||
CLAMP(val, INT32_MIN, INT32_MAX, "int32", "%d");
|
||||
v = (int32_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(int32_t));
|
||||
break;
|
||||
}
|
||||
case PC_INT64:
|
||||
{
|
||||
int64_t v;
|
||||
CLAMP(val, INT64_MIN, INT64_MAX, "int64", "%d");
|
||||
v = (int64_t)lround(val);
|
||||
memcpy(ptr, &(v), sizeof(int64_t));
|
||||
break;
|
||||
}
|
||||
case PC_FLOAT:
|
||||
{
|
||||
float v = (float)val;
|
||||
memcpy(ptr, &(v), sizeof(float));
|
||||
break;
|
||||
}
|
||||
case PC_DOUBLE:
|
||||
{
|
||||
double v = val;
|
||||
memcpy(ptr, &(v), sizeof(double));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
pcerror("unknown interpretation type %d encountered in pc_double_to_ptr",
|
||||
interpretation);
|
||||
return PC_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
return PC_SUCCESS;
|
||||
return PC_SUCCESS;
|
||||
}
|
||||
|
||||
@ -1,369 +1,356 @@
|
||||
/**********************************************************************
|
||||
* stringbuffer.c
|
||||
*
|
||||
* Copyright 2002 Thamer Alharbash
|
||||
* Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
|
||||
* Copyright 2015 Sandro Santilli <strk@keybit.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**********************************************************************/
|
||||
* stringbuffer.c
|
||||
*
|
||||
* Copyright 2002 Thamer Alharbash
|
||||
* Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
|
||||
* Copyright 2015 Sandro Santilli <strk@keybit.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#include "stringbuffer.h"
|
||||
|
||||
/**
|
||||
* Allocate a new stringbuffer_t. Use stringbuffer_destroy to free.
|
||||
*/
|
||||
stringbuffer_t*
|
||||
stringbuffer_create(void)
|
||||
* Allocate a new stringbuffer_t. Use stringbuffer_destroy to free.
|
||||
*/
|
||||
stringbuffer_t *stringbuffer_create(void)
|
||||
{
|
||||
return stringbuffer_create_with_size(STRINGBUFFER_STARTSIZE);
|
||||
return stringbuffer_create_with_size(STRINGBUFFER_STARTSIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allocate a new stringbuffer_t. Use stringbuffer_destroy to free.
|
||||
*/
|
||||
stringbuffer_t*
|
||||
stringbuffer_create_with_size(size_t size)
|
||||
* Allocate a new stringbuffer_t. Use stringbuffer_destroy to free.
|
||||
*/
|
||||
stringbuffer_t *stringbuffer_create_with_size(size_t size)
|
||||
{
|
||||
stringbuffer_t *s;
|
||||
stringbuffer_t *s;
|
||||
|
||||
s = malloc(sizeof(stringbuffer_t));
|
||||
s->str_start = malloc(size);
|
||||
s->str_end = s->str_start;
|
||||
s->capacity = size;
|
||||
memset(s->str_start,0,size);
|
||||
return s;
|
||||
s = malloc(sizeof(stringbuffer_t));
|
||||
s->str_start = malloc(size);
|
||||
s->str_end = s->str_start;
|
||||
s->capacity = size;
|
||||
memset(s->str_start, 0, size);
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the stringbuffer_t and all memory managed within it.
|
||||
*/
|
||||
void
|
||||
stringbuffer_destroy(stringbuffer_t *s)
|
||||
* Free the stringbuffer_t and all memory managed within it.
|
||||
*/
|
||||
void stringbuffer_destroy(stringbuffer_t *s)
|
||||
{
|
||||
if ( s->str_start ) free(s->str_start);
|
||||
if ( s ) free(s);
|
||||
if (s->str_start)
|
||||
free(s->str_start);
|
||||
if (s)
|
||||
free(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the stringbuffer_t. Useful for starting a fresh string
|
||||
* without the expense of freeing and re-allocating a new
|
||||
* stringbuffer_t.
|
||||
*/
|
||||
void
|
||||
stringbuffer_clear(stringbuffer_t *s)
|
||||
* Reset the stringbuffer_t. Useful for starting a fresh string
|
||||
* without the expense of freeing and re-allocating a new
|
||||
* stringbuffer_t.
|
||||
*/
|
||||
void stringbuffer_clear(stringbuffer_t *s)
|
||||
{
|
||||
s->str_start[0] = '\0';
|
||||
s->str_end = s->str_start;
|
||||
s->str_start[0] = '\0';
|
||||
s->str_end = s->str_start;
|
||||
}
|
||||
|
||||
/**
|
||||
* If necessary, expand the stringbuffer_t internal buffer to accomodate the
|
||||
* specified additional size.
|
||||
*/
|
||||
static inline void
|
||||
stringbuffer_makeroom(stringbuffer_t *s, size_t size_to_add)
|
||||
* If necessary, expand the stringbuffer_t internal buffer to accomodate the
|
||||
* specified additional size.
|
||||
*/
|
||||
static inline void stringbuffer_makeroom(stringbuffer_t *s, size_t size_to_add)
|
||||
{
|
||||
size_t current_size = (s->str_end - s->str_start);
|
||||
size_t capacity = s->capacity;
|
||||
size_t required_size = current_size + size_to_add;
|
||||
size_t current_size = (s->str_end - s->str_start);
|
||||
size_t capacity = s->capacity;
|
||||
size_t required_size = current_size + size_to_add;
|
||||
|
||||
if ( ! capacity ) capacity = STRINGBUFFER_STARTSIZE;
|
||||
else while (capacity < required_size) capacity *= 2;
|
||||
if (!capacity)
|
||||
capacity = STRINGBUFFER_STARTSIZE;
|
||||
else
|
||||
while (capacity < required_size)
|
||||
capacity *= 2;
|
||||
|
||||
if ( capacity > s->capacity )
|
||||
{
|
||||
s->str_start = realloc(s->str_start, capacity);
|
||||
s->capacity = capacity;
|
||||
s->str_end = s->str_start + current_size;
|
||||
}
|
||||
if (capacity > s->capacity)
|
||||
{
|
||||
s->str_start = realloc(s->str_start, capacity);
|
||||
s->capacity = capacity;
|
||||
s->str_end = s->str_start + current_size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the last character in the buffer.
|
||||
*/
|
||||
char
|
||||
stringbuffer_lastchar(stringbuffer_t *s)
|
||||
* Return the last character in the buffer.
|
||||
*/
|
||||
char stringbuffer_lastchar(stringbuffer_t *s)
|
||||
{
|
||||
if( s->str_end == s->str_start )
|
||||
return 0;
|
||||
if (s->str_end == s->str_start)
|
||||
return 0;
|
||||
|
||||
return *(s->str_end - 1);
|
||||
return *(s->str_end - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Append the specified string to the stringbuffer_t.
|
||||
*/
|
||||
void
|
||||
stringbuffer_append(stringbuffer_t *s, const char *a)
|
||||
* Append the specified string to the stringbuffer_t.
|
||||
*/
|
||||
void stringbuffer_append(stringbuffer_t *s, const char *a)
|
||||
{
|
||||
int alen = strlen(a); /* Length of string to append */
|
||||
int alen0 = alen + 1; /* Length including null terminator */
|
||||
stringbuffer_makeroom(s, alen0);
|
||||
memcpy(s->str_end, a, alen0);
|
||||
s->str_end += alen;
|
||||
int alen = strlen(a); /* Length of string to append */
|
||||
int alen0 = alen + 1; /* Length including null terminator */
|
||||
stringbuffer_makeroom(s, alen0);
|
||||
memcpy(s->str_end, a, alen0);
|
||||
s->str_end += alen;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a reference to the internal string being managed by
|
||||
* the stringbuffer. The current string will be null-terminated
|
||||
* within the internal string.
|
||||
*/
|
||||
const char*
|
||||
stringbuffer_getstring(stringbuffer_t *s)
|
||||
* Returns a reference to the internal string being managed by
|
||||
* the stringbuffer. The current string will be null-terminated
|
||||
* within the internal string.
|
||||
*/
|
||||
const char *stringbuffer_getstring(stringbuffer_t *s) { return s->str_start; }
|
||||
|
||||
/**
|
||||
* Transfer ownership of the internal string to caller,
|
||||
* turning this buffer into an empty one
|
||||
*/
|
||||
char *stringbuffer_release_string(stringbuffer_t *s)
|
||||
{
|
||||
return s->str_start;
|
||||
char *ret = s->str_start;
|
||||
s->str_start = s->str_end = NULL;
|
||||
s->capacity = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer ownership of the internal string to caller,
|
||||
* turning this buffer into an empty one
|
||||
*/
|
||||
char*
|
||||
stringbuffer_release_string(stringbuffer_t *s)
|
||||
* Returns a newly allocated string large enough to contain the
|
||||
* current state of the string. Caller is responsible for
|
||||
* freeing the return value.
|
||||
*/
|
||||
char *stringbuffer_getstringcopy(stringbuffer_t *s)
|
||||
{
|
||||
char *ret = s->str_start;
|
||||
s->str_start = s->str_end = NULL;
|
||||
s->capacity = 0;
|
||||
return ret;
|
||||
size_t size = (s->str_end - s->str_start) + 1;
|
||||
char *str = malloc(size);
|
||||
memcpy(str, s->str_start, size - 1);
|
||||
str[size - 1] = '\0';
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a newly allocated string large enough to contain the
|
||||
* current state of the string. Caller is responsible for
|
||||
* freeing the return value.
|
||||
*/
|
||||
char*
|
||||
stringbuffer_getstringcopy(stringbuffer_t *s)
|
||||
* Returns the length of the current string, not including the
|
||||
* null terminator (same behavior as strlen()).
|
||||
*/
|
||||
int stringbuffer_getlength(stringbuffer_t *s)
|
||||
{
|
||||
size_t size = (s->str_end - s->str_start) + 1;
|
||||
char *str = malloc(size);
|
||||
memcpy(str, s->str_start, size-1);
|
||||
str[size-1] = '\0';
|
||||
return str;
|
||||
return (s->str_end - s->str_start);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of the current string, not including the
|
||||
* null terminator (same behavior as strlen()).
|
||||
*/
|
||||
int
|
||||
stringbuffer_getlength(stringbuffer_t *s)
|
||||
* Clear the stringbuffer_t and re-start it with the specified string.
|
||||
*/
|
||||
void stringbuffer_set(stringbuffer_t *s, const char *str)
|
||||
{
|
||||
return (s->str_end - s->str_start);
|
||||
stringbuffer_clear(s);
|
||||
stringbuffer_append(s, str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear the stringbuffer_t and re-start it with the specified string.
|
||||
*/
|
||||
void
|
||||
stringbuffer_set(stringbuffer_t *s, const char *str)
|
||||
* Copy the contents of src into dst.
|
||||
*/
|
||||
void stringbuffer_copy(stringbuffer_t *dst, stringbuffer_t *src)
|
||||
{
|
||||
stringbuffer_clear(s);
|
||||
stringbuffer_append(s, str);
|
||||
stringbuffer_set(dst, stringbuffer_getstring(src));
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the contents of src into dst.
|
||||
*/
|
||||
void
|
||||
stringbuffer_copy(stringbuffer_t *dst, stringbuffer_t *src)
|
||||
* Appends a formatted string to the current string buffer,
|
||||
* using the format and argument list provided. Returns -1 on error,
|
||||
* check errno for reasons, documented in the printf man page.
|
||||
*/
|
||||
static int stringbuffer_avprintf(stringbuffer_t *s, const char *fmt, va_list ap)
|
||||
{
|
||||
stringbuffer_set(dst, stringbuffer_getstring(src));
|
||||
}
|
||||
int maxlen = (s->capacity - (s->str_end - s->str_start));
|
||||
int len = 0; /* Length of the output */
|
||||
va_list ap2;
|
||||
|
||||
/**
|
||||
* Appends a formatted string to the current string buffer,
|
||||
* using the format and argument list provided. Returns -1 on error,
|
||||
* check errno for reasons, documented in the printf man page.
|
||||
*/
|
||||
static int
|
||||
stringbuffer_avprintf(stringbuffer_t *s, const char *fmt, va_list ap)
|
||||
{
|
||||
int maxlen = (s->capacity - (s->str_end - s->str_start));
|
||||
int len = 0; /* Length of the output */
|
||||
va_list ap2;
|
||||
/* Make a copy of the variadic arguments, in case we need to print twice */
|
||||
/* Print to our buffer */
|
||||
va_copy(ap2, ap);
|
||||
len = vsnprintf(s->str_end, maxlen, fmt, ap2);
|
||||
va_end(ap2);
|
||||
|
||||
/* Make a copy of the variadic arguments, in case we need to print twice */
|
||||
/* Print to our buffer */
|
||||
va_copy(ap2, ap);
|
||||
len = vsnprintf(s->str_end, maxlen, fmt, ap2);
|
||||
va_end(ap2);
|
||||
|
||||
/* Propogate errors up */
|
||||
if ( len < 0 )
|
||||
{
|
||||
/* Propogate errors up */
|
||||
if (len < 0)
|
||||
{
|
||||
#if defined(__MINGW64_VERSION_MAJOR)
|
||||
/* Assume windows flaky vsnprintf that returns -1 if */
|
||||
/* initial buffer too small and add more space */
|
||||
len = _vscprintf(fmt, ap2);
|
||||
/* Assume windows flaky vsnprintf that returns -1 if */
|
||||
/* initial buffer too small and add more space */
|
||||
len = _vscprintf(fmt, ap2);
|
||||
#else
|
||||
return len;
|
||||
return len;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* We didn't have enough space! */
|
||||
/* Either Unix vsnprint returned write length larger than our buffer */
|
||||
/* or Windows vsnprintf returned an error code. */
|
||||
if ( len >= maxlen )
|
||||
{
|
||||
stringbuffer_makeroom(s, len + 1);
|
||||
maxlen = (s->capacity - (s->str_end - s->str_start));
|
||||
/* We didn't have enough space! */
|
||||
/* Either Unix vsnprint returned write length larger than our buffer */
|
||||
/* or Windows vsnprintf returned an error code. */
|
||||
if (len >= maxlen)
|
||||
{
|
||||
stringbuffer_makeroom(s, len + 1);
|
||||
maxlen = (s->capacity - (s->str_end - s->str_start));
|
||||
|
||||
/* Try to print a second time */
|
||||
len = vsnprintf(s->str_end, maxlen, fmt, ap);
|
||||
/* Try to print a second time */
|
||||
len = vsnprintf(s->str_end, maxlen, fmt, ap);
|
||||
|
||||
/* Printing error? Error! */
|
||||
if ( len < 0 ) return len;
|
||||
/* Too long still? Error! */
|
||||
if ( len >= maxlen ) return -1;
|
||||
}
|
||||
/* Printing error? Error! */
|
||||
if (len < 0)
|
||||
return len;
|
||||
/* Too long still? Error! */
|
||||
if (len >= maxlen)
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Move end pointer forward and return. */
|
||||
s->str_end += len;
|
||||
return len;
|
||||
/* Move end pointer forward and return. */
|
||||
s->str_end += len;
|
||||
return len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends a formatted string to the current string buffer,
|
||||
* using the format and argument list provided.
|
||||
* Returns -1 on error, check errno for reasons,
|
||||
* as documented in the printf man page.
|
||||
*/
|
||||
int
|
||||
stringbuffer_aprintf(stringbuffer_t *s, const char *fmt, ...)
|
||||
* Appends a formatted string to the current string buffer,
|
||||
* using the format and argument list provided.
|
||||
* Returns -1 on error, check errno for reasons,
|
||||
* as documented in the printf man page.
|
||||
*/
|
||||
int stringbuffer_aprintf(stringbuffer_t *s, const char *fmt, ...)
|
||||
{
|
||||
int r;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
r = stringbuffer_avprintf(s, fmt, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
int r;
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
r = stringbuffer_avprintf(s, fmt, ap);
|
||||
va_end(ap);
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims whitespace off the end of the stringbuffer. Returns
|
||||
* the number of characters trimmed.
|
||||
*/
|
||||
int
|
||||
stringbuffer_trim_trailing_white(stringbuffer_t *s)
|
||||
* Trims whitespace off the end of the stringbuffer. Returns
|
||||
* the number of characters trimmed.
|
||||
*/
|
||||
int stringbuffer_trim_trailing_white(stringbuffer_t *s)
|
||||
{
|
||||
char *ptr = s->str_end;
|
||||
int dist = 0;
|
||||
char *ptr = s->str_end;
|
||||
int dist = 0;
|
||||
|
||||
/* Roll backwards until we hit a non-space. */
|
||||
while( ptr > s->str_start )
|
||||
{
|
||||
ptr--;
|
||||
if( (*ptr == ' ') || (*ptr == '\t') )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr++;
|
||||
dist = s->str_end - ptr;
|
||||
*ptr = '\0';
|
||||
s->str_end = ptr;
|
||||
return dist;
|
||||
}
|
||||
}
|
||||
return dist;
|
||||
/* Roll backwards until we hit a non-space. */
|
||||
while (ptr > s->str_start)
|
||||
{
|
||||
ptr--;
|
||||
if ((*ptr == ' ') || (*ptr == '\t'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
ptr++;
|
||||
dist = s->str_end - ptr;
|
||||
*ptr = '\0';
|
||||
s->str_end = ptr;
|
||||
return dist;
|
||||
}
|
||||
}
|
||||
return dist;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trims zeroes off the end of the last number in the stringbuffer.
|
||||
* The number has to be the very last thing in the buffer. Only the
|
||||
* last number will be trimmed. Returns the number of characters
|
||||
* trimmed.
|
||||
*
|
||||
* eg: 1.22000 -> 1.22
|
||||
* 1.0 -> 1
|
||||
* 0.0 -> 0
|
||||
*/
|
||||
int
|
||||
stringbuffer_trim_trailing_zeroes(stringbuffer_t *s)
|
||||
* Trims zeroes off the end of the last number in the stringbuffer.
|
||||
* The number has to be the very last thing in the buffer. Only the
|
||||
* last number will be trimmed. Returns the number of characters
|
||||
* trimmed.
|
||||
*
|
||||
* eg: 1.22000 -> 1.22
|
||||
* 1.0 -> 1
|
||||
* 0.0 -> 0
|
||||
*/
|
||||
int stringbuffer_trim_trailing_zeroes(stringbuffer_t *s)
|
||||
{
|
||||
char *ptr = s->str_end;
|
||||
char *decimal_ptr = NULL;
|
||||
int dist;
|
||||
char *ptr = s->str_end;
|
||||
char *decimal_ptr = NULL;
|
||||
int dist;
|
||||
|
||||
if ( s->str_end - s->str_start < 2)
|
||||
return 0;
|
||||
if (s->str_end - s->str_start < 2)
|
||||
return 0;
|
||||
|
||||
/* Roll backwards to find the decimal for this number */
|
||||
while( ptr > s->str_start )
|
||||
{
|
||||
ptr--;
|
||||
if ( *ptr == '.' )
|
||||
{
|
||||
decimal_ptr = ptr;
|
||||
break;
|
||||
}
|
||||
if ( (*ptr >= '0') && (*ptr <= '9' ) )
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* Roll backwards to find the decimal for this number */
|
||||
while (ptr > s->str_start)
|
||||
{
|
||||
ptr--;
|
||||
if (*ptr == '.')
|
||||
{
|
||||
decimal_ptr = ptr;
|
||||
break;
|
||||
}
|
||||
if ((*ptr >= '0') && (*ptr <= '9'))
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* No decimal? Nothing to trim! */
|
||||
if ( ! decimal_ptr )
|
||||
return 0;
|
||||
/* No decimal? Nothing to trim! */
|
||||
if (!decimal_ptr)
|
||||
return 0;
|
||||
|
||||
ptr = s->str_end;
|
||||
ptr = s->str_end;
|
||||
|
||||
/* Roll backwards again, with the decimal as stop point, trimming contiguous zeroes */
|
||||
while( ptr >= decimal_ptr )
|
||||
{
|
||||
ptr--;
|
||||
if ( *ptr == '0' )
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
/* Roll backwards again, with the decimal as stop point, trimming contiguous
|
||||
* zeroes */
|
||||
while (ptr >= decimal_ptr)
|
||||
{
|
||||
ptr--;
|
||||
if (*ptr == '0')
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* Huh, we get anywhere. Must not have trimmed anything. */
|
||||
if ( ptr == s->str_end )
|
||||
return 0;
|
||||
/* Huh, we get anywhere. Must not have trimmed anything. */
|
||||
if (ptr == s->str_end)
|
||||
return 0;
|
||||
|
||||
/* If we stopped at the decimal, we want to null that out.
|
||||
It we stopped on a numeral, we want to preserve that, so push the
|
||||
pointer forward one space. */
|
||||
if ( *ptr != '.' )
|
||||
ptr++;
|
||||
/* If we stopped at the decimal, we want to null that out.
|
||||
It we stopped on a numeral, we want to preserve that, so push the
|
||||
pointer forward one space. */
|
||||
if (*ptr != '.')
|
||||
ptr++;
|
||||
|
||||
/* Add null terminator re-set the end of the stringbuffer. */
|
||||
*ptr = '\0';
|
||||
dist = s->str_end - ptr;
|
||||
s->str_end = ptr;
|
||||
return dist;
|
||||
/* Add null terminator re-set the end of the stringbuffer. */
|
||||
*ptr = '\0';
|
||||
dist = s->str_end - ptr;
|
||||
s->str_end = ptr;
|
||||
return dist;
|
||||
}
|
||||
|
||||
|
||||
@ -1,48 +1,48 @@
|
||||
/**********************************************************************
|
||||
* stringbuffer.h
|
||||
*
|
||||
* Copyright 2002 Thamer Alharbash
|
||||
* Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
|
||||
* Copyright 2015 Sandro Santilli <strk@keybit.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**********************************************************************/
|
||||
* stringbuffer.h
|
||||
*
|
||||
* Copyright 2002 Thamer Alharbash
|
||||
* Copyright 2009 Paul Ramsey <pramsey@cleverelephant.ca>
|
||||
* Copyright 2015 Sandro Santilli <strk@keybit.net>
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or
|
||||
* without modification, are permitted provided that the following
|
||||
* conditions are met:
|
||||
*
|
||||
* Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* Redistributions in binary form must reproduce the above
|
||||
* copyright notice, this list of conditions and the following
|
||||
* disclaimer in the documentation and/or other materials provided
|
||||
* with the distribution.
|
||||
*
|
||||
* The name of the author may not be used to endorse or promote
|
||||
* products derived from this software without specific prior
|
||||
* written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR
|
||||
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
||||
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef _STRINGBUFFER_H
|
||||
#define _STRINGBUFFER_H 1
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Use appropriate allocators for this deployment */
|
||||
#define malloc pcalloc
|
||||
@ -55,11 +55,10 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
size_t capacity;
|
||||
char *str_end;
|
||||
char *str_start;
|
||||
}
|
||||
stringbuffer_t;
|
||||
size_t capacity;
|
||||
char *str_end;
|
||||
char *str_start;
|
||||
} stringbuffer_t;
|
||||
|
||||
extern stringbuffer_t *stringbuffer_create_with_size(size_t size);
|
||||
extern stringbuffer_t *stringbuffer_create(void);
|
||||
@ -78,4 +77,3 @@ extern int stringbuffer_trim_trailing_white(stringbuffer_t *s);
|
||||
extern int stringbuffer_trim_trailing_zeroes(stringbuffer_t *s);
|
||||
|
||||
#endif /* _STRINGBUFFER_H */
|
||||
|
||||
|
||||
3
tools/code_layout.sh
Normal file
3
tools/code_layout.sh
Normal file
@ -0,0 +1,3 @@
|
||||
#! /bin/bash
|
||||
|
||||
clang-format -i -style=file lib/*.c lib/*.h lib/cunit/*.c lib/*.cpp lib/*.hpp lib/cunit/*.h
|
||||
Loading…
x
Reference in New Issue
Block a user