bool KdTree::CalcBestSplit( double totalObjectCosts, double costToBeat,
const ExtentTripleArrayInfo& extents,
double minOnAxis, double maxOnAxis,
double secondAxisLen, double thirdAxisLen,
double* retNewBestCost, double* retSplitValue,
long* retNumTriplesToLeft, long* retNumObjectsToLeft, long* retNumObjectsToRight,
double* retCostObjectsToLeft, double* retCostObjectsToRight )
{
if ( minOnAxis>=maxOnAxis ) {
return false; // We do not support splitting a zero length axis.
}
InitSplitCostFunction( minOnAxis, maxOnAxis, secondAxisLen, thirdAxisLen,
costToBeat, totalObjectCosts );
bool foundBetter = false;
double bestCost = costToBeat; // Cost to beat
long numTriplesLeft = 0; // number of triples processed so far
long numTriples = extents.NumTriples(); // total number of triples
long numObjectsLeft = 0; // number of ojects on the left during the scan
long numObjectsRight = extents.NumObjects(); // number of objects on the right during the scan
double costLeft = 0.0; // cost of objects on the left during the scan
double costRight = totalObjectCosts; // total cost of objects still on the right side during scan
ExtentTriple* etPtr = extents.TripleArray;
bool inFirstHalf = true; // If still scanning first half, measured in distance along axis
double midPoint = 0.5*(minOnAxis+maxOnAxis);
while ( numTriplesLeft<numTriples ) {
// The split can occur either right before or right after the split value.
double thisSplitValue = etPtr->ExtentValue;
bool sameSplitValue = true;
ExtentTriple::TripleType thisType = etPtr->ExtentType;
if ( inFirstHalf && thisSplitValue>midPoint ) {
inFirstHalf = false;
}
// Skip past all TT_MAX's, and TT_FLAT's in first half, with this split value
while ( numTriplesLeft<numTriples ) {
if ( !(
(( thisType==ExtentTriple::TT_MAX || (thisType==ExtentTriple::TT_FLAT && inFirstHalf) ))
&& sameSplitValue
)
)
{
break;
}
UpdateLeftRightCosts( *etPtr, &numObjectsLeft, &numObjectsRight, &costLeft, &costRight );
etPtr++;
numTriplesLeft++;
thisType = etPtr->ExtentType;
sameSplitValue = (etPtr->ExtentValue <= thisSplitValue);
}
// Ready to call the cost function
// If the cost function gives better value, save everything appropriately
if ( CalcSplitCost( thisSplitValue, costLeft, costRight, &bestCost ) ) {
foundBetter = true;
*retNewBestCost = bestCost;
*retSplitValue = thisSplitValue;
*retNumTriplesToLeft = numTriplesLeft;
*retNumObjectsToLeft = numObjectsLeft;
*retNumObjectsToRight = numObjectsRight;
*retCostObjectsToLeft = costLeft;
*retCostObjectsToRight = costRight;
}
// Skip past all TT_MIN's, and TT_FLAT's in second half, with this split value
while ( numTriplesLeft<numTriples ) {
if ( !( sameSplitValue &&
(thisType==ExtentTriple::TT_MIN
|| (thisType==ExtentTriple::TT_FLAT && !inFirstHalf)) ) )
{
break;
}
// Move rightward a triple
UpdateLeftRightCosts( *etPtr, &numObjectsLeft, &numObjectsRight, &costLeft, &costRight );
etPtr++;
numTriplesLeft++;
thisType = etPtr->ExtentType;
sameSplitValue = (etPtr->ExtentValue <= thisSplitValue);
}
}
return foundBetter;
const ExtentTripleArrayInfo& extents,
double minOnAxis, double maxOnAxis,
double secondAxisLen, double thirdAxisLen,
double* retNewBestCost, double* retSplitValue,
long* retNumTriplesToLeft, long* retNumObjectsToLeft, long* retNumObjectsToRight,
double* retCostObjectsToLeft, double* retCostObjectsToRight )
{
if ( minOnAxis>=maxOnAxis ) {
return false; // We do not support splitting a zero length axis.
}
InitSplitCostFunction( minOnAxis, maxOnAxis, secondAxisLen, thirdAxisLen,
costToBeat, totalObjectCosts );
bool foundBetter = false;
double bestCost = costToBeat; // Cost to beat
long numTriplesLeft = 0; // number of triples processed so far
long numTriples = extents.NumTriples(); // total number of triples
long numObjectsLeft = 0; // number of ojects on the left during the scan
long numObjectsRight = extents.NumObjects(); // number of objects on the right during the scan
double costLeft = 0.0; // cost of objects on the left during the scan
double costRight = totalObjectCosts; // total cost of objects still on the right side during scan
ExtentTriple* etPtr = extents.TripleArray;
bool inFirstHalf = true; // If still scanning first half, measured in distance along axis
double midPoint = 0.5*(minOnAxis+maxOnAxis);
while ( numTriplesLeft<numTriples ) {
// The split can occur either right before or right after the split value.
double thisSplitValue = etPtr->ExtentValue;
bool sameSplitValue = true;
ExtentTriple::TripleType thisType = etPtr->ExtentType;
if ( inFirstHalf && thisSplitValue>midPoint ) {
inFirstHalf = false;
}
// Skip past all TT_MAX's, and TT_FLAT's in first half, with this split value
while ( numTriplesLeft<numTriples ) {
if ( !(
(( thisType==ExtentTriple::TT_MAX || (thisType==ExtentTriple::TT_FLAT && inFirstHalf) ))
&& sameSplitValue
)
)
{
break;
}
UpdateLeftRightCosts( *etPtr, &numObjectsLeft, &numObjectsRight, &costLeft, &costRight );
etPtr++;
numTriplesLeft++;
thisType = etPtr->ExtentType;
sameSplitValue = (etPtr->ExtentValue <= thisSplitValue);
}
// Ready to call the cost function
// If the cost function gives better value, save everything appropriately
if ( CalcSplitCost( thisSplitValue, costLeft, costRight, &bestCost ) ) {
foundBetter = true;
*retNewBestCost = bestCost;
*retSplitValue = thisSplitValue;
*retNumTriplesToLeft = numTriplesLeft;
*retNumObjectsToLeft = numObjectsLeft;
*retNumObjectsToRight = numObjectsRight;
*retCostObjectsToLeft = costLeft;
*retCostObjectsToRight = costRight;
}
// Skip past all TT_MIN's, and TT_FLAT's in second half, with this split value
while ( numTriplesLeft<numTriples ) {
if ( !( sameSplitValue &&
(thisType==ExtentTriple::TT_MIN
|| (thisType==ExtentTriple::TT_FLAT && !inFirstHalf)) ) )
{
break;
}
// Move rightward a triple
UpdateLeftRightCosts( *etPtr, &numObjectsLeft, &numObjectsRight, &costLeft, &costRight );
etPtr++;
numTriplesLeft++;
thisType = etPtr->ExtentType;
sameSplitValue = (etPtr->ExtentValue <= thisSplitValue);
}
}
return foundBetter;
}
凸体的三角面元的点集合 ,其一个点是某一个面元的TT_MIN ,也是另外某个三角面元的TT_MAX. 若是TT_FLAT 则就是自己不与其他面元公用:
所以以midPoint为界限,在前半部分只要找所有的TT_MIN为候选split,在后半部分找所有的TT_MAX为候选的split 。
sameSplitValue 变量的存在,因为有些三角面元的TT_MIN和TT_MAX 在投影坐标上是重合的,因此就忽略。