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:
Paul Blottiere 2022-02-08 09:19:18 +01:00 committed by GitHub
commit ecbc19741c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 9354 additions and 9525 deletions

2
.clang-format Normal file
View File

@ -0,0 +1,2 @@
BasedOnStyle: llvm
BreakBeforeBraces: Allman

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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};

View File

@ -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};

View File

@ -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};

View File

@ -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};

View File

@ -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};

View File

@ -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;
}

View File

@ -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);

View File

@ -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.
*/

View File

@ -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.
*/

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 */

View File

@ -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 */

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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;
}

File diff suppressed because it is too large Load Diff

View File

@ -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;
}

View File

@ -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; }

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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
View 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