/*********************************************************************** * pc_sort.c * * Pointclound patch sorting. * * Copyright (c) 2016 IGN * * Author: M. Brédif * ***********************************************************************/ #include "pc_api_internal.h" #include #include "sort_r/sort_r.h" // NULL terminated array of PCDIMENSION pointers typedef PCDIMENSION ** PCDIMENSION_LIST; /** * Comparators */ 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; } 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)); } /** * Sort */ PCPATCH_UNCOMPRESSED * pc_patch_uncompressed_sort(const PCPATCH_UNCOMPRESSED *pu, PCDIMENSION_LIST dim) { 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); sort_r(spu->data, spu->npoints, pu->schema->size, pc_compare_dim, dim); return spu; } 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; iscale>0); } dim[ndims] = NULL; return dim; } 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); pcfree(dim); if ( pu != pa ) pc_patch_free(pu); return (PCPATCH *) ps; } /** * IsSorted */ 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; } 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; } 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; } 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; } 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; } uint32_t pc_patch_dimensional_is_sorted(const PCPATCH_DIMENSIONAL *pdl, PCDIMENSION_LIST dim, char strict) { 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; } 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) { 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) { 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; }