/*========================================================================= * * Copyright NumFOCUS * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://www.apache.org/licenses/LICENSE-2.0.txt * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *=========================================================================*/ #ifndef itkWeightedCentroidKdTreeGenerator_hxx #define itkWeightedCentroidKdTreeGenerator_hxx namespace itk { namespace Statistics { template void WeightedCentroidKdTreeGenerator::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); } template inline auto WeightedCentroidKdTreeGenerator::GenerateNonterminalNode(unsigned int beginIndex, unsigned int endIndex, MeasurementVectorType & lowerBound, MeasurementVectorType & upperBound, unsigned int level) -> KdTreeNodeType * { MeasurementType dimensionLowerBound; MeasurementType dimensionUpperBound; MeasurementType partitionValue; unsigned int partitionDimension = 0; unsigned int i; unsigned int j; MeasurementType spread; MeasurementType maxSpread; unsigned int medianIndex; SubsamplePointer subsample = this->GetSubsample(); // Sanity check. Verify that the subsample has measurement vectors of the // same length as the sample generated by the tree. if (this->GetMeasurementVectorSize() != subsample->GetMeasurementVectorSize()) { itkExceptionMacro("Measurement Vector Length mismatch"); } // calculates the weighted centroid which is the vector sum // of all the associated instances. typename KdTreeNodeType::CentroidType weightedCentroid; NumericTraits::SetLength(weightedCentroid, this->GetMeasurementVectorSize()); MeasurementVectorType tempVector; weightedCentroid.Fill(MeasurementType{}); for (i = beginIndex; i < endIndex; ++i) { tempVector = subsample->GetMeasurementVectorByIndex(i); for (j = 0; j < this->GetMeasurementVectorSize(); ++j) { weightedCentroid[j] += tempVector[j]; } } // find most widely spread dimension Algorithm::FindSampleBoundAndMean( this->GetSubsample(), beginIndex, endIndex, m_TempLowerBound, m_TempUpperBound, m_TempMean); maxSpread = NumericTraits::NonpositiveMin(); for (i = 0; i < this->GetMeasurementVectorSize(); ++i) { spread = m_TempUpperBound[i] - m_TempLowerBound[i]; if (spread >= maxSpread) { maxSpread = spread; partitionDimension = i; } } medianIndex = (endIndex - beginIndex) / 2; // // Find the medial element by using the NthElement function // based on the STL implementation of the QuickSelect algorithm. // partitionValue = Algorithm::NthElement(this->GetSubsample(), partitionDimension, beginIndex, endIndex, medianIndex); medianIndex += beginIndex; // save bounds for cutting dimension dimensionLowerBound = lowerBound[partitionDimension]; dimensionUpperBound = upperBound[partitionDimension]; upperBound[partitionDimension] = partitionValue; const unsigned int beginLeftIndex = beginIndex; const unsigned int endLeftIndex = medianIndex; KdTreeNodeType * left = this->GenerateTreeLoop(beginLeftIndex, endLeftIndex, lowerBound, upperBound, level + 1); upperBound[partitionDimension] = dimensionUpperBound; lowerBound[partitionDimension] = partitionValue; const unsigned int beginRightIndex = medianIndex + 1; const unsigned int endRighIndex = endIndex; KdTreeNodeType * right = this->GenerateTreeLoop(beginRightIndex, endRighIndex, lowerBound, upperBound, level + 1); lowerBound[partitionDimension] = dimensionLowerBound; using KdTreeNonterminalNodeType = KdTreeWeightedCentroidNonterminalNode; auto * nonTerminalNode = new KdTreeNonterminalNodeType( partitionDimension, partitionValue, left, right, weightedCentroid, endIndex - beginIndex); nonTerminalNode->AddInstanceIdentifier(subsample->GetInstanceIdentifier(medianIndex)); return nonTerminalNode; } } // end of namespace Statistics } // end of namespace itk #endif