129 #include "cpl_error.h"
150 #define SHP_SPLIT_RATIO 0.55
153 #define STATIC_CAST(type,x) static_cast<type>(x)
154 #define REINTERPRET_CAST(type,x) reinterpret_cast<type>(x)
155 #define CONST_CAST(type,x) const_cast<type>(x)
156 #define SHPLIB_NULLPTR nullptr
158 #define STATIC_CAST(type,x) ((type)(x))
159 #define REINTERPRET_CAST(type,x) ((type)(x))
160 #define CONST_CAST(type,x) ((type)(x))
161 #define SHPLIB_NULLPTR NULL
175 return malloc(nNewSize);
177 return realloc(pMem,nNewSize);
187 double * padfBoundsMax )
203 memcpy( psTreeNode->
adfBoundsMin, padfBoundsMin,
sizeof(
double) * 4 );
206 memcpy( psTreeNode->
adfBoundsMax, padfBoundsMax,
sizeof(
double) * 4 );
218 double *padfBoundsMin,
double *padfBoundsMax )
246 int nMaxNodeCount = 1;
250 while( nMaxNodeCount*4 < nShapeCount )
253 nMaxNodeCount = nMaxNodeCount * 2;
258 "Estimated spatial index tree depth: %d",
272 "Falling back to max number of allowed index tree levels (%d).",
305 int iShape, nShapeCount;
309 for( iShape = 0; iShape < nShapeCount; iShape++ )
336 for( i = 0; i < psTreeNode->
nSubNodes; i++ )
379 double * padfBox2Min,
double * padfBox2Max,
385 for( iDim = 0; iDim < nDimension; iDim++ )
387 if( padfBox2Max[iDim] < padfBox1Min[iDim] )
390 if( padfBox1Max[iDim] < padfBox2Min[iDim] )
404 double * padfBoundsMin,
double * padfBoundsMax )
407 if( psObject->
dfXMin < padfBoundsMin[0]
408 || psObject->
dfXMax > padfBoundsMax[0] )
411 if( psObject->
dfYMin < padfBoundsMin[1]
412 || psObject->
dfYMax > padfBoundsMax[1] )
415 if( nDimension == 2 )
418 if( psObject->
dfZMin < padfBoundsMin[2]
419 || psObject->
dfZMax > padfBoundsMax[2] )
422 if( nDimension == 3 )
425 if( psObject->
dfMMin < padfBoundsMin[3]
426 || psObject->
dfMMax > padfBoundsMax[3] )
441 double *padfBoundsMin1,
double * padfBoundsMax1,
442 double *padfBoundsMin2,
double * padfBoundsMax2 )
449 memcpy( padfBoundsMin1, padfBoundsMinIn,
sizeof(
double) * 4 );
450 memcpy( padfBoundsMax1, padfBoundsMaxIn,
sizeof(
double) * 4 );
451 memcpy( padfBoundsMin2, padfBoundsMinIn,
sizeof(
double) * 4 );
452 memcpy( padfBoundsMax2, padfBoundsMaxIn,
sizeof(
double) * 4 );
457 if( (padfBoundsMaxIn[0] - padfBoundsMinIn[0])
458 > (padfBoundsMaxIn[1] - padfBoundsMinIn[1]) )
460 double dfRange = padfBoundsMaxIn[0] - padfBoundsMinIn[0];
471 double dfRange = padfBoundsMaxIn[1] - padfBoundsMinIn[1];
484 int nMaxDepth,
int nDimension )
493 if( nMaxDepth > 1 && psTreeNode->
nSubNodes > 0 )
495 for( i = 0; i < psTreeNode->
nSubNodes; i++ )
502 psObject, nMaxDepth-1,
513 else if( nMaxDepth > 1 && psTreeNode->
nSubNodes == 0 )
515 double adfBoundsMinH1[4], adfBoundsMaxH1[4];
516 double adfBoundsMinH2[4], adfBoundsMaxH2[4];
517 double adfBoundsMin1[4], adfBoundsMax1[4];
518 double adfBoundsMin2[4], adfBoundsMax2[4];
519 double adfBoundsMin3[4], adfBoundsMax3[4];
520 double adfBoundsMin4[4], adfBoundsMax4[4];
524 adfBoundsMinH1, adfBoundsMaxH1,
525 adfBoundsMinH2, adfBoundsMaxH2 );
528 adfBoundsMin1, adfBoundsMax1,
529 adfBoundsMin2, adfBoundsMax2 );
532 adfBoundsMin3, adfBoundsMax3,
533 adfBoundsMin4, adfBoundsMax4 );
536 adfBoundsMin1, adfBoundsMax1)
538 adfBoundsMin2, adfBoundsMax2)
540 adfBoundsMin3, adfBoundsMax3)
542 adfBoundsMin4, adfBoundsMax4) )
556 nMaxDepth, nDimension ) );
566 else if( nMaxDepth > 1 && psTreeNode->
nSubNodes == 0 )
568 double adfBoundsMin1[4], adfBoundsMax1[4];
569 double adfBoundsMin2[4], adfBoundsMax2[4];
572 adfBoundsMin1, adfBoundsMax1,
573 adfBoundsMin2, adfBoundsMax2 );
576 adfBoundsMin1, adfBoundsMax1))
585 nMaxDepth - 1, nDimension ) );
588 adfBoundsMin2, adfBoundsMax2) )
597 nMaxDepth - 1, nDimension ) );
649 double * padfBoundsMin,
double * padfBoundsMax,
650 int * pnShapeCount,
int * pnMaxShapes,
651 int ** ppanShapeList )
670 if( *pnShapeCount + psTreeNode->
nShapeCount > *pnMaxShapes )
672 *pnMaxShapes = (*pnShapeCount + psTreeNode->
nShapeCount) * 2 + 20;
674 SfRealloc(*ppanShapeList,
sizeof(
int) * *pnMaxShapes));
682 (*ppanShapeList)[(*pnShapeCount)++] = psTreeNode->
panShapeIds[i];
688 for( i = 0; i < psTreeNode->
nSubNodes; i++ )
692 padfBoundsMin, padfBoundsMax,
693 pnShapeCount, pnMaxShapes,
717 double * padfBoundsMin,
double * padfBoundsMax,
729 padfBoundsMin, padfBoundsMax,
730 pnShapeCount, &nMaxShapes,
738 qsort(panShapeList, *pnShapeCount,
sizeof(
int),
compare_ints);
758 for( i = 0; i < psTreeNode->
nSubNodes; i++ )
791 for( i = 0; i < psSubNode->
nSubNodes; i++ )
828 for( i=0; i < length/2; i++ )
832 STATIC_CAST(
unsigned char*, wordP)[length-i-1] = temp;
888 int **ppanResultBuffer,
int *pnBufferMax,
889 int *pnResultCount,
int bNeedSwap,
int nRecLevel )
894 unsigned int numshapes, numsubnodes;
895 double adfNodeBoundsMin[2], adfNodeBoundsMax[2];
908 SwapWord( 8, adfNodeBoundsMin + 0 );
909 SwapWord( 8, adfNodeBoundsMin + 1 );
910 SwapWord( 8, adfNodeBoundsMax + 0 );
911 SwapWord( 8, adfNodeBoundsMax + 1 );
915 if ( bNeedSwap )
SwapWord ( 4, &numshapes );
918 if( nFReadAcc != 1 + 2 + 2 + 1 )
925 if(
offset > INT_MAX -
sizeof(
int) )
927 hDiskTree->
sHooks.
Error(
"Invalid value for offset");
931 if( numshapes > (INT_MAX -
offset -
sizeof(
int)) /
sizeof(
int) ||
932 numshapes > INT_MAX /
sizeof(
int) - *pnResultCount )
934 hDiskTree->
sHooks.
Error(
"Invalid value for numshapes");
943 padfBoundsMin, padfBoundsMax, 2 ) )
945 offset += numshapes*
sizeof(int) +
sizeof(
int);
955 if( *pnResultCount + numshapes >
STATIC_CAST(
unsigned int, *pnBufferMax) )
959 *pnBufferMax = (*pnResultCount + numshapes + 100) * 5 / 4;
961 if(
STATIC_CAST(
size_t, *pnBufferMax) > INT_MAX /
sizeof(int) )
962 *pnBufferMax = *pnResultCount + numshapes;
965 SfRealloc( *ppanResultBuffer, *pnBufferMax *
sizeof(
int) ));
973 *ppanResultBuffer = pNewBuffer;
976 if( hDiskTree->
sHooks.
FRead( *ppanResultBuffer + *pnResultCount,
977 sizeof(
int), numshapes, hDiskTree->
fpQIX ) != numshapes )
985 for( i=0; i<numshapes; i++ )
986 SwapWord( 4, *ppanResultBuffer + *pnResultCount + i );
989 *pnResultCount += numshapes;
1000 if ( bNeedSwap )
SwapWord ( 4, &numsubnodes );
1001 if( numsubnodes > 0 && nRecLevel == 32 )
1003 hDiskTree->
sHooks.
Error(
"Shape tree is too deep");
1007 for(i=0; i<numsubnodes; i++)
1010 ppanResultBuffer, pnBufferMax,
1011 pnResultCount, bNeedSwap, nRecLevel + 1 ) )
1049 double *padfBoundsMin,
double *padfBoundsMax,
1053 memset(&sDiskTree.
sHooks, 0,
sizeof(sDiskTree.
sHooks));
1071 double *padfBoundsMin,
double *padfBoundsMax,
1075 int i, bNeedSwap, nBufferMax = 0;
1076 unsigned char abyBuf[16];
1096 if( memcmp( abyBuf,
"SQT", 3 ) != 0 )
1109 &panResultBuffer, &nBufferMax,
1110 pnShapeCount, bNeedSwap, 0 ) )
1113 free( panResultBuffer );
1123 panResultBuffer =
STATIC_CAST(
int*, calloc(1,
sizeof(
int)));
1125 qsort(panResultBuffer, *pnShapeCount,
sizeof(
int),
compare_ints);
1128 return panResultBuffer;
1148 offset += 4*
sizeof(double)
1165 unsigned char *pabyRec;
1171 malloc(
sizeof(
double) * 4
1172 + (3 *
sizeof(
int)) + (node->
nShapeCount *
sizeof(
int)) ));
1176 CPLError( CE_Fatal, CPLE_OutOfMemory,
"Memory allocation failure");
1182 memcpy( pabyRec, &
offset, 4);
1185 memcpy( pabyRec+ 4, node->
adfBoundsMin+0,
sizeof(
double) );
1186 memcpy( pabyRec+12, node->
adfBoundsMin+1,
sizeof(
double) );
1187 memcpy( pabyRec+20, node->
adfBoundsMax+0,
sizeof(
double) );
1188 memcpy( pabyRec+28, node->
adfBoundsMax+1,
sizeof(
double) );
1194 memcpy( pabyRec+j+40, &node->
nSubNodes, 4);
1196 psHooks->
FWrite( pabyRec, 44+j, 1, fp );
1225 char signature[4] =
"SQT";
1258 memcpy( abyBuf+0, signature, 3 );
1270 psHooks->
FWrite( abyBuf, 8, 1, fp );
void SASetupDefaultHooks(SAHooks *psHooks)
void SHPDestroyObject(SHPObject *psObject)
#define SHP_CVSID(string)
#define MAX_DEFAULT_TREE_DEPTH
void SHPGetInfo(SHPHandle hSHP, int *pnEntities, int *pnShapeType, double *padfMinBound, double *padfMaxBound)
SHPObject * SHPReadObject(SHPHandle hSHP, int iShape)
int SHPCheckBoundsOverlap(double *padfBox1Min, double *padfBox1Max, double *padfBox2Min, double *padfBox2Max, int nDimension)
static int compare_ints(const void *a, const void *b)
static int SHPSearchDiskTreeNode(SHPTreeDiskHandle hDiskTree, double *padfBoundsMin, double *padfBoundsMax, int **ppanResultBuffer, int *pnBufferMax, int *pnResultCount, int bNeedSwap, int nRecLevel)
static SAOffset SHPTreeSeekLibc(SAFile file, SAOffset offset, int whence)
int SHPWriteTreeLL(SHPTree *tree, const char *filename, SAHooks *psHooks)
void SHPCloseDiskTree(SHPTreeDiskHandle hDiskTree)
int SHPTreeAddShapeId(SHPTree *psTree, SHPObject *psObject)
static SHPTreeNode * SHPTreeNodeCreate(double *padfBoundsMin, double *padfBoundsMax)
static SAOffset SHPTreeReadLibc(void *p, SAOffset size, SAOffset nmemb, SAFile file)
static void SHPDestroyTreeNode(SHPTreeNode *psTreeNode)
static void SwapWord(int length, void *wordP)
static int SHPGetSubNodeOffset(SHPTreeNode *node)
static int SHPTreeNodeAddShapeId(SHPTreeNode *psTreeNode, SHPObject *psObject, int nMaxDepth, int nDimension)
#define STATIC_CAST(type, x)
int SHPWriteTree(SHPTree *tree, const char *filename)
SHPTree * SHPCreateTree(SHPHandle hSHP, int nDimension, int nMaxDepth, double *padfBoundsMin, double *padfBoundsMax)
void SHPTreeTrimExtraNodes(SHPTree *hTree)
SHPTreeDiskHandle SHPOpenDiskTree(const char *pszQIXFilename, SAHooks *psHooks)
#define REINTERPRET_CAST(type, x)
static int SHPCheckObjectContained(SHPObject *psObject, int nDimension, double *padfBoundsMin, double *padfBoundsMax)
void SHPDestroyTree(SHPTree *psTree)
static void SHPTreeCollectShapeIds(SHPTree *hTree, SHPTreeNode *psTreeNode, double *padfBoundsMin, double *padfBoundsMax, int *pnShapeCount, int *pnMaxShapes, int **ppanShapeList)
int * SHPSearchDiskTree(FILE *fp, double *padfBoundsMin, double *padfBoundsMax, int *pnShapeCount)
static int SHPTreeNodeTrim(SHPTreeNode *psTreeNode)
int * SHPSearchDiskTreeEx(SHPTreeDiskHandle hDiskTree, double *padfBoundsMin, double *padfBoundsMax, int *pnShapeCount)
static void * SfRealloc(void *pMem, int nNewSize)
static void SHPTreeSplitBounds(double *padfBoundsMinIn, double *padfBoundsMaxIn, double *padfBoundsMin1, double *padfBoundsMax1, double *padfBoundsMin2, double *padfBoundsMax2)
int * SHPTreeFindLikelyShapes(SHPTree *hTree, double *padfBoundsMin, double *padfBoundsMax, int *pnShapeCount)
static void SHPWriteTreeNode(SAFile fp, SHPTreeNode *node, SAHooks *psHooks)
void(* Error)(const char *message)
SAFile(* FOpen)(const char *filename, const char *access)
SAOffset(* FWrite)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
int(* FClose)(SAFile file)
SAOffset(* FRead)(void *p, SAOffset size, SAOffset nmemb, SAFile file)
SAOffset(* FSeek)(SAFile file, SAOffset offset, int whence)
SHPObject ** papsShapeObj
struct shape_tree_node * apsSubNode[4]