File indexing completed on 2026-09-28 09:20:59
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014 #ifndef NCollection_KDTree_HeaderFile
0015 #define NCollection_KDTree_HeaderFile
0016
0017 #include <NCollection_Array1.hxx>
0018 #include <NCollection_DynamicArray.hxx>
0019
0020 #include <algorithm>
0021 #include <cmath>
0022 #include <cstddef>
0023 #include <limits>
0024 #include <type_traits>
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062 template <class ThePointType, int TheDimension, bool HasRadii = false>
0063 class NCollection_KDTree
0064 {
0065 public:
0066
0067 NCollection_KDTree()
0068 : mySize(0)
0069 {
0070 }
0071
0072
0073
0074
0075
0076 template <bool R = HasRadii, typename = std::enable_if_t<!R>>
0077 void Build(const ThePointType* thePoints, size_t theCount)
0078 {
0079 if (theCount == 0)
0080 {
0081 Clear();
0082 return;
0083 }
0084 mySize = theCount;
0085 myPoints.Resize(1, static_cast<int>(theCount), false);
0086 myIndices.Resize(1, static_cast<int>(theCount), false);
0087 for (size_t i = 0; i < theCount; ++i)
0088 {
0089 myPoints.SetValue(static_cast<int>(i + 1), thePoints[i]);
0090 myIndices.SetValue(static_cast<int>(i + 1), i + 1);
0091 }
0092 buildRecursive(1, static_cast<int>(mySize), 0);
0093 }
0094
0095
0096
0097
0098 template <bool R = HasRadii, typename = std::enable_if_t<!R>>
0099 void Build(const NCollection_Array1<ThePointType>& thePoints)
0100 {
0101 const int aCount = thePoints.Length();
0102 if (aCount == 0)
0103 {
0104 Clear();
0105 return;
0106 }
0107 mySize = static_cast<size_t>(aCount);
0108 myPoints.Resize(1, aCount, false);
0109 myIndices.Resize(1, aCount, false);
0110 for (int i = 0; i < aCount; ++i)
0111 {
0112 myPoints.SetValue(i + 1, thePoints.Value(thePoints.Lower() + i));
0113 myIndices.SetValue(i + 1, static_cast<size_t>(i + 1));
0114 }
0115 buildRecursive(1, static_cast<int>(mySize), 0);
0116 }
0117
0118
0119
0120
0121
0122
0123 template <bool R = HasRadii, typename = std::enable_if_t<R>>
0124 void Build(const ThePointType* thePoints, const double* theRadii, size_t theCount)
0125 {
0126 if (theCount == 0)
0127 {
0128 Clear();
0129 return;
0130 }
0131 mySize = theCount;
0132 const int aN = static_cast<int>(theCount);
0133 myPoints.Resize(1, aN, false);
0134 myIndices.Resize(1, aN, false);
0135 myRadii.Resize(1, aN, false);
0136 myMaxRadius.Resize(1, aN, false);
0137 for (size_t i = 0; i < theCount; ++i)
0138 {
0139 const int anI = static_cast<int>(i + 1);
0140 myPoints.SetValue(anI, thePoints[i]);
0141 myIndices.SetValue(anI, i + 1);
0142 myRadii.SetValue(anI, theRadii[i]);
0143 }
0144 buildRecursive(1, aN, 0);
0145 }
0146
0147
0148
0149
0150
0151 template <bool R = HasRadii, typename = std::enable_if_t<R>>
0152 void Build(const NCollection_Array1<ThePointType>& thePoints,
0153 const NCollection_Array1<double>& theRadii)
0154 {
0155 const int aCount = thePoints.Length();
0156 if (aCount == 0)
0157 {
0158 Clear();
0159 return;
0160 }
0161 mySize = static_cast<size_t>(aCount);
0162 myPoints.Resize(1, aCount, false);
0163 myIndices.Resize(1, aCount, false);
0164 myRadii.Resize(1, aCount, false);
0165 myMaxRadius.Resize(1, aCount, false);
0166 for (int i = 0; i < aCount; ++i)
0167 {
0168 myPoints.SetValue(i + 1, thePoints.Value(thePoints.Lower() + i));
0169 myIndices.SetValue(i + 1, static_cast<size_t>(i + 1));
0170 myRadii.SetValue(i + 1, theRadii.Value(theRadii.Lower() + i));
0171 }
0172 buildRecursive(1, static_cast<int>(mySize), 0);
0173 }
0174
0175
0176 bool IsEmpty() const { return mySize == 0; }
0177
0178
0179 size_t Size() const { return mySize; }
0180
0181
0182 void Clear()
0183 {
0184 mySize = 0;
0185 myPoints = NCollection_Array1<ThePointType>();
0186 myIndices = NCollection_Array1<size_t>();
0187 if constexpr (HasRadii)
0188 {
0189 myRadii = NCollection_Array1<double>();
0190 myMaxRadius = NCollection_Array1<double>();
0191 }
0192 }
0193
0194
0195
0196
0197 const ThePointType& Point(size_t theIndex) const
0198 {
0199 return myPoints.Value(static_cast<int>(theIndex));
0200 }
0201
0202
0203
0204
0205
0206 template <bool R = HasRadii, typename = std::enable_if_t<R>>
0207 double Radius(size_t theIndex) const
0208 {
0209 return myRadii.Value(static_cast<int>(theIndex));
0210 }
0211
0212
0213
0214
0215 size_t NearestPoint(const ThePointType& theQuery) const
0216 {
0217 double aDummy = 0.0;
0218 return NearestPoint(theQuery, aDummy);
0219 }
0220
0221
0222
0223
0224
0225 size_t NearestPoint(const ThePointType& theQuery, double& theSqDistance) const
0226 {
0227 if (IsEmpty())
0228 {
0229 theSqDistance = 0.0;
0230 return 0;
0231 }
0232 size_t aBestIndex = 0;
0233 double aBestSqDist = std::numeric_limits<double>::max();
0234 double aBoundsMin[TheDimension];
0235 double aBoundsMax[TheDimension];
0236 initBounds(aBoundsMin, aBoundsMax);
0237 nearestRecursive(theQuery,
0238 1,
0239 static_cast<int>(mySize),
0240 0,
0241 aBestIndex,
0242 aBestSqDist,
0243 aBoundsMin,
0244 aBoundsMax);
0245 theSqDistance = aBestSqDist;
0246 return aBestIndex;
0247 }
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257 NCollection_DynamicArray<size_t> NearestPoints(const ThePointType& theQuery,
0258 double theTolerance,
0259 double& theSqDistance) const
0260 {
0261 NCollection_DynamicArray<size_t> aResult;
0262 if (IsEmpty())
0263 {
0264 theSqDistance = 0.0;
0265 return aResult;
0266 }
0267
0268 size_t aBestIndex = 0;
0269 double aBestSqDist = std::numeric_limits<double>::max();
0270 double aBoundsMin[TheDimension];
0271 double aBoundsMax[TheDimension];
0272 initBounds(aBoundsMin, aBoundsMax);
0273 nearestRecursive(theQuery,
0274 1,
0275 static_cast<int>(mySize),
0276 0,
0277 aBestIndex,
0278 aBestSqDist,
0279 aBoundsMin,
0280 aBoundsMax);
0281 theSqDistance = aBestSqDist;
0282
0283 const double aBestDist = std::sqrt(aBestSqDist);
0284 const double aSearchRadius = aBestDist + theTolerance;
0285 const double aSearchRadiusSq = aSearchRadius * aSearchRadius;
0286 const double aMinSqDist = (aBestDist - theTolerance > 0.0)
0287 ? (aBestDist - theTolerance) * (aBestDist - theTolerance)
0288 : 0.0;
0289
0290 NCollection_DynamicArray<size_t> aCandidates;
0291 rangeSearchRecursive(theQuery, aSearchRadiusSq, 1, static_cast<int>(mySize), 0, aCandidates);
0292 for (size_t i = 0; i < aCandidates.Size(); ++i)
0293 {
0294 const size_t anIdx = aCandidates[i];
0295 const double aSqDist = squareDistance(theQuery, myPoints.Value(static_cast<int>(anIdx)));
0296 if (aSqDist >= aMinSqDist && aSqDist <= aSearchRadiusSq)
0297 {
0298 aResult.Append(anIdx);
0299 }
0300 }
0301 return aResult;
0302 }
0303
0304
0305
0306
0307
0308
0309
0310
0311 size_t KNearestPoints(const ThePointType& theQuery,
0312 size_t theK,
0313 NCollection_Array1<size_t>& theIndices,
0314 NCollection_Array1<double>& theSqDistances) const
0315 {
0316 if (IsEmpty() || theK == 0)
0317 {
0318 theIndices = NCollection_Array1<size_t>();
0319 theSqDistances = NCollection_Array1<double>();
0320 return 0;
0321 }
0322 const size_t anActualK = std::min(theK, mySize);
0323
0324 NCollection_Array1<std::pair<double, size_t>> aHeap(1, static_cast<int>(anActualK));
0325 size_t aHeapSize = 0;
0326 double aBoundsMin[TheDimension];
0327 double aBoundsMax[TheDimension];
0328 initBounds(aBoundsMin, aBoundsMax);
0329 kNearestRecursive(theQuery,
0330 1,
0331 static_cast<int>(mySize),
0332 0,
0333 aHeap,
0334 aHeapSize,
0335 anActualK,
0336 aBoundsMin,
0337 aBoundsMax);
0338
0339 const int aCount = static_cast<int>(aHeapSize);
0340 theIndices.Resize(1, aCount, false);
0341 theSqDistances.Resize(1, aCount, false);
0342
0343 for (int i = aCount; i >= 1; --i)
0344 {
0345 theIndices.SetValue(i, aHeap.Value(1).second);
0346 theSqDistances.SetValue(i, aHeap.Value(1).first);
0347
0348 aHeap.SetValue(1, aHeap.Value(static_cast<int>(aHeapSize)));
0349 --aHeapSize;
0350 heapSiftDown(aHeap, 1, static_cast<int>(aHeapSize));
0351 }
0352 return static_cast<size_t>(aCount);
0353 }
0354
0355
0356
0357
0358
0359 NCollection_DynamicArray<size_t> RangeSearch(const ThePointType& theQuery, double theRadius) const
0360 {
0361 NCollection_DynamicArray<size_t> aResult;
0362 if (IsEmpty() || theRadius < 0.0)
0363 {
0364 return aResult;
0365 }
0366 const double aRadiusSq = theRadius * theRadius;
0367 rangeSearchRecursive(theQuery, aRadiusSq, 1, static_cast<int>(mySize), 0, aResult);
0368 return aResult;
0369 }
0370
0371
0372
0373
0374
0375
0376
0377
0378 template <typename Functor>
0379 void ForEachInRange(const ThePointType& theQuery, double theRadius, Functor theFunctor) const
0380 {
0381 if (IsEmpty() || theRadius < 0.0)
0382 {
0383 return;
0384 }
0385 const double aRadiusSq = theRadius * theRadius;
0386 forEachInRangeRecursive(theQuery, aRadiusSq, 1, static_cast<int>(mySize), 0, theFunctor);
0387 }
0388
0389
0390
0391
0392
0393 NCollection_DynamicArray<size_t> BoxSearch(const ThePointType& theMin,
0394 const ThePointType& theMax) const
0395 {
0396 NCollection_DynamicArray<size_t> aResult;
0397 if (IsEmpty())
0398 {
0399 return aResult;
0400 }
0401 boxSearchRecursive(theMin, theMax, 1, static_cast<int>(mySize), 0, aResult);
0402 return aResult;
0403 }
0404
0405
0406
0407
0408
0409
0410 template <bool R = HasRadii, typename = std::enable_if_t<R>>
0411 NCollection_DynamicArray<size_t> ContainingSearch(const ThePointType& theQuery) const
0412 {
0413 NCollection_DynamicArray<size_t> aResult;
0414 if (IsEmpty())
0415 {
0416 return aResult;
0417 }
0418 double aBoundsMin[TheDimension];
0419 double aBoundsMax[TheDimension];
0420 initBounds(aBoundsMin, aBoundsMax);
0421 containingSearchRecursive(theQuery,
0422 1,
0423 static_cast<int>(mySize),
0424 0,
0425 aResult,
0426 aBoundsMin,
0427 aBoundsMax);
0428 return aResult;
0429 }
0430
0431
0432
0433
0434
0435
0436
0437 template <bool R = HasRadii, typename = std::enable_if_t<R>>
0438 size_t NearestWeighted(const ThePointType& theQuery) const
0439 {
0440 double aDummy = 0.0;
0441 return NearestWeighted(theQuery, aDummy);
0442 }
0443
0444
0445
0446
0447
0448
0449
0450
0451 template <bool R = HasRadii, typename = std::enable_if_t<R>>
0452 size_t NearestWeighted(const ThePointType& theQuery, double& theGapDistance) const
0453 {
0454 if (IsEmpty())
0455 {
0456 theGapDistance = 0.0;
0457 return 0;
0458 }
0459 size_t aBestIndex = 0;
0460 double aBestGap = std::numeric_limits<double>::max();
0461 double aBoundsMin[TheDimension];
0462 double aBoundsMax[TheDimension];
0463 initBounds(aBoundsMin, aBoundsMax);
0464 nearestWeightedRecursive(theQuery,
0465 1,
0466 static_cast<int>(mySize),
0467 0,
0468 aBestIndex,
0469 aBestGap,
0470 aBoundsMin,
0471 aBoundsMax);
0472 theGapDistance = aBestGap;
0473 return aBestIndex;
0474 }
0475
0476
0477 NCollection_KDTree(const NCollection_KDTree& theOther) = default;
0478
0479
0480 NCollection_KDTree(NCollection_KDTree&& theOther) noexcept
0481 : myPoints(std::move(theOther.myPoints)),
0482 myIndices(std::move(theOther.myIndices)),
0483 myRadii(std::move(theOther.myRadii)),
0484 myMaxRadius(std::move(theOther.myMaxRadius)),
0485 mySize(theOther.mySize)
0486 {
0487 theOther.mySize = 0;
0488 }
0489
0490
0491 NCollection_KDTree& operator=(const NCollection_KDTree& theOther)
0492 {
0493 if (this != &theOther)
0494 {
0495 myPoints = theOther.myPoints;
0496 myIndices = theOther.myIndices;
0497 myRadii = theOther.myRadii;
0498 myMaxRadius = theOther.myMaxRadius;
0499 mySize = theOther.mySize;
0500 }
0501 return *this;
0502 }
0503
0504
0505 NCollection_KDTree& operator=(NCollection_KDTree&& theOther) noexcept
0506 {
0507 if (this != &theOther)
0508 {
0509 myPoints = std::move(theOther.myPoints);
0510 myIndices = std::move(theOther.myIndices);
0511 myRadii = std::move(theOther.myRadii);
0512 myMaxRadius = std::move(theOther.myMaxRadius);
0513 mySize = theOther.mySize;
0514 theOther.mySize = 0;
0515 }
0516 return *this;
0517 }
0518
0519 private:
0520
0521 static double squareDistance(const ThePointType& theP1, const ThePointType& theP2)
0522 {
0523 double aSqDist = 0.0;
0524 for (int i = 1; i <= TheDimension; ++i)
0525 {
0526 const double aDiff = theP1.Coord(i) - theP2.Coord(i);
0527 aSqDist += aDiff * aDiff;
0528 }
0529 return aSqDist;
0530 }
0531
0532
0533 static bool isInsideBox(const ThePointType& thePoint,
0534 const ThePointType& theMin,
0535 const ThePointType& theMax)
0536 {
0537 for (int i = 1; i <= TheDimension; ++i)
0538 {
0539 const double aCoord = thePoint.Coord(i);
0540 if (aCoord < theMin.Coord(i) || aCoord > theMax.Coord(i))
0541 {
0542 return false;
0543 }
0544 }
0545 return true;
0546 }
0547
0548
0549
0550 static constexpr int THE_LEAF_SIZE = 32;
0551
0552
0553 static double sqDistToBox(const ThePointType& theQuery,
0554 const double theBoundsMin[],
0555 const double theBoundsMax[])
0556 {
0557 double aSqDist = 0.0;
0558 for (int i = 0; i < TheDimension; ++i)
0559 {
0560 const double aCoord = theQuery.Coord(i + 1);
0561 if (aCoord < theBoundsMin[i])
0562 {
0563 const double aDiff = theBoundsMin[i] - aCoord;
0564 aSqDist += aDiff * aDiff;
0565 }
0566 else if (aCoord > theBoundsMax[i])
0567 {
0568 const double aDiff = aCoord - theBoundsMax[i];
0569 aSqDist += aDiff * aDiff;
0570 }
0571 }
0572 return aSqDist;
0573 }
0574
0575
0576 static void initBounds(double theBoundsMin[], double theBoundsMax[])
0577 {
0578 for (int i = 0; i < TheDimension; ++i)
0579 {
0580 theBoundsMin[i] = -std::numeric_limits<double>::max();
0581 theBoundsMax[i] = std::numeric_limits<double>::max();
0582 }
0583 }
0584
0585
0586 static void heapSiftDown(NCollection_Array1<std::pair<double, size_t>>& theHeap,
0587 int theIdx,
0588 int theSize)
0589 {
0590 while (true)
0591 {
0592 int aLargest = theIdx;
0593 const int aLeft = 2 * theIdx;
0594 const int aRight = 2 * theIdx + 1;
0595 if (aLeft <= theSize && theHeap.Value(aLeft).first > theHeap.Value(aLargest).first)
0596 {
0597 aLargest = aLeft;
0598 }
0599 if (aRight <= theSize && theHeap.Value(aRight).first > theHeap.Value(aLargest).first)
0600 {
0601 aLargest = aRight;
0602 }
0603 if (aLargest == theIdx)
0604 {
0605 break;
0606 }
0607 std::swap(theHeap.ChangeValue(theIdx), theHeap.ChangeValue(aLargest));
0608 theIdx = aLargest;
0609 }
0610 }
0611
0612
0613 static void heapSiftUp(NCollection_Array1<std::pair<double, size_t>>& theHeap, int theIdx)
0614 {
0615 while (theIdx > 1)
0616 {
0617 const int aParent = theIdx / 2;
0618 if (theHeap.Value(theIdx).first <= theHeap.Value(aParent).first)
0619 {
0620 break;
0621 }
0622 std::swap(theHeap.ChangeValue(theIdx), theHeap.ChangeValue(aParent));
0623 theIdx = aParent;
0624 }
0625 }
0626
0627
0628
0629 double buildRecursive(int theLo, int theHi, int theDepth)
0630 {
0631 if (theLo > theHi)
0632 {
0633 return 0.0;
0634 }
0635 if (theLo == theHi)
0636 {
0637 if constexpr (HasRadii)
0638 {
0639 const double aR = myRadii.Value(static_cast<int>(myIndices.Value(theLo)));
0640 myMaxRadius.SetValue(theLo, aR);
0641 return aR;
0642 }
0643 return 0.0;
0644 }
0645 const int theAxis = theDepth % TheDimension;
0646 const int theMid = (theLo + theHi) / 2;
0647
0648 std::nth_element(&myIndices.ChangeValue(theLo),
0649 &myIndices.ChangeValue(theMid),
0650 &myIndices.ChangeValue(theHi) + 1,
0651 [this, theAxis](size_t a, size_t b) {
0652 return myPoints.Value(static_cast<int>(a)).Coord(theAxis + 1)
0653 < myPoints.Value(static_cast<int>(b)).Coord(theAxis + 1);
0654 });
0655 if constexpr (HasRadii)
0656 {
0657 const double aLeftMax = buildRecursive(theLo, theMid - 1, theDepth + 1);
0658 const double aRightMax = buildRecursive(theMid + 1, theHi, theDepth + 1);
0659 const double aNodeR = myRadii.Value(static_cast<int>(myIndices.Value(theMid)));
0660 const double aMaxR = std::max({aNodeR, aLeftMax, aRightMax});
0661 myMaxRadius.SetValue(theMid, aMaxR);
0662 return aMaxR;
0663 }
0664 else
0665 {
0666 buildRecursive(theLo, theMid - 1, theDepth + 1);
0667 buildRecursive(theMid + 1, theHi, theDepth + 1);
0668 return 0.0;
0669 }
0670 }
0671
0672
0673 void nearestRecursive(const ThePointType& theQuery,
0674 int theLo,
0675 int theHi,
0676 int theDepth,
0677 size_t& theBestIndex,
0678 double& theBestSqDist,
0679 double theBoundsMin[],
0680 double theBoundsMax[]) const
0681 {
0682 if (theLo > theHi)
0683 {
0684 return;
0685 }
0686
0687 if (sqDistToBox(theQuery, theBoundsMin, theBoundsMax) >= theBestSqDist)
0688 {
0689 return;
0690 }
0691
0692 if (theHi - theLo + 1 <= THE_LEAF_SIZE)
0693 {
0694 for (int i = theLo; i <= theHi; ++i)
0695 {
0696 const size_t anIdx = myIndices.Value(i);
0697 const double aSqDist = squareDistance(theQuery, myPoints.Value(static_cast<int>(anIdx)));
0698 if (aSqDist < theBestSqDist)
0699 {
0700 theBestSqDist = aSqDist;
0701 theBestIndex = anIdx;
0702 }
0703 }
0704 return;
0705 }
0706 const int theMid = (theLo + theHi) / 2;
0707 const size_t aNodeIndex = myIndices.Value(theMid);
0708 const ThePointType& aNodePoint = myPoints.Value(static_cast<int>(aNodeIndex));
0709 const double aSqDist = squareDistance(theQuery, aNodePoint);
0710 if (aSqDist < theBestSqDist)
0711 {
0712 theBestSqDist = aSqDist;
0713 theBestIndex = aNodeIndex;
0714 }
0715 const int theAxis = theDepth % TheDimension;
0716 const double aSplitVal = aNodePoint.Coord(theAxis + 1);
0717 const double aDiff = theQuery.Coord(theAxis + 1) - aSplitVal;
0718
0719
0720 if (aDiff <= 0.0)
0721 {
0722 const double aSavedMax = theBoundsMax[theAxis];
0723 theBoundsMax[theAxis] = aSplitVal;
0724 nearestRecursive(theQuery,
0725 theLo,
0726 theMid - 1,
0727 theDepth + 1,
0728 theBestIndex,
0729 theBestSqDist,
0730 theBoundsMin,
0731 theBoundsMax);
0732 theBoundsMax[theAxis] = aSavedMax;
0733 const double aSavedMin = theBoundsMin[theAxis];
0734 theBoundsMin[theAxis] = aSplitVal;
0735 nearestRecursive(theQuery,
0736 theMid + 1,
0737 theHi,
0738 theDepth + 1,
0739 theBestIndex,
0740 theBestSqDist,
0741 theBoundsMin,
0742 theBoundsMax);
0743 theBoundsMin[theAxis] = aSavedMin;
0744 }
0745 else
0746 {
0747 const double aSavedMin = theBoundsMin[theAxis];
0748 theBoundsMin[theAxis] = aSplitVal;
0749 nearestRecursive(theQuery,
0750 theMid + 1,
0751 theHi,
0752 theDepth + 1,
0753 theBestIndex,
0754 theBestSqDist,
0755 theBoundsMin,
0756 theBoundsMax);
0757 theBoundsMin[theAxis] = aSavedMin;
0758 const double aSavedMax = theBoundsMax[theAxis];
0759 theBoundsMax[theAxis] = aSplitVal;
0760 nearestRecursive(theQuery,
0761 theLo,
0762 theMid - 1,
0763 theDepth + 1,
0764 theBestIndex,
0765 theBestSqDist,
0766 theBoundsMin,
0767 theBoundsMax);
0768 theBoundsMax[theAxis] = aSavedMax;
0769 }
0770 }
0771
0772
0773 void kNearestRecursive(const ThePointType& theQuery,
0774 int theLo,
0775 int theHi,
0776 int theDepth,
0777 NCollection_Array1<std::pair<double, size_t>>& theHeap,
0778 size_t& theHeapSize,
0779 size_t theK,
0780 double theBoundsMin[],
0781 double theBoundsMax[]) const
0782 {
0783 if (theLo > theHi)
0784 {
0785 return;
0786 }
0787
0788 if (theHeapSize == theK
0789 && sqDistToBox(theQuery, theBoundsMin, theBoundsMax) >= theHeap.Value(1).first)
0790 {
0791 return;
0792 }
0793
0794 if (theHi - theLo + 1 <= THE_LEAF_SIZE)
0795 {
0796 for (int i = theLo; i <= theHi; ++i)
0797 {
0798 const size_t anIdx = myIndices.Value(i);
0799 const double aSqDist = squareDistance(theQuery, myPoints.Value(static_cast<int>(anIdx)));
0800 if (theHeapSize < theK)
0801 {
0802 ++theHeapSize;
0803 theHeap.SetValue(static_cast<int>(theHeapSize), {aSqDist, anIdx});
0804 heapSiftUp(theHeap, static_cast<int>(theHeapSize));
0805 }
0806 else if (aSqDist < theHeap.Value(1).first)
0807 {
0808 theHeap.SetValue(1, {aSqDist, anIdx});
0809 heapSiftDown(theHeap, 1, static_cast<int>(theHeapSize));
0810 }
0811 }
0812 return;
0813 }
0814 const int theMid = (theLo + theHi) / 2;
0815 const size_t aNodeIndex = myIndices.Value(theMid);
0816 const ThePointType& aNodePoint = myPoints.Value(static_cast<int>(aNodeIndex));
0817 const double aSqDist = squareDistance(theQuery, aNodePoint);
0818 if (theHeapSize < theK)
0819 {
0820 ++theHeapSize;
0821 theHeap.SetValue(static_cast<int>(theHeapSize), {aSqDist, aNodeIndex});
0822 heapSiftUp(theHeap, static_cast<int>(theHeapSize));
0823 }
0824 else if (aSqDist < theHeap.Value(1).first)
0825 {
0826 theHeap.SetValue(1, {aSqDist, aNodeIndex});
0827 heapSiftDown(theHeap, 1, static_cast<int>(theHeapSize));
0828 }
0829 const int theAxis = theDepth % TheDimension;
0830 const double aSplitVal = aNodePoint.Coord(theAxis + 1);
0831 const double aDiff = theQuery.Coord(theAxis + 1) - aSplitVal;
0832
0833 if (aDiff <= 0.0)
0834 {
0835 const double aSavedMax = theBoundsMax[theAxis];
0836 theBoundsMax[theAxis] = aSplitVal;
0837 kNearestRecursive(theQuery,
0838 theLo,
0839 theMid - 1,
0840 theDepth + 1,
0841 theHeap,
0842 theHeapSize,
0843 theK,
0844 theBoundsMin,
0845 theBoundsMax);
0846 theBoundsMax[theAxis] = aSavedMax;
0847 const double aSavedMin = theBoundsMin[theAxis];
0848 theBoundsMin[theAxis] = aSplitVal;
0849 kNearestRecursive(theQuery,
0850 theMid + 1,
0851 theHi,
0852 theDepth + 1,
0853 theHeap,
0854 theHeapSize,
0855 theK,
0856 theBoundsMin,
0857 theBoundsMax);
0858 theBoundsMin[theAxis] = aSavedMin;
0859 }
0860 else
0861 {
0862 const double aSavedMin = theBoundsMin[theAxis];
0863 theBoundsMin[theAxis] = aSplitVal;
0864 kNearestRecursive(theQuery,
0865 theMid + 1,
0866 theHi,
0867 theDepth + 1,
0868 theHeap,
0869 theHeapSize,
0870 theK,
0871 theBoundsMin,
0872 theBoundsMax);
0873 theBoundsMin[theAxis] = aSavedMin;
0874 const double aSavedMax = theBoundsMax[theAxis];
0875 theBoundsMax[theAxis] = aSplitVal;
0876 kNearestRecursive(theQuery,
0877 theLo,
0878 theMid - 1,
0879 theDepth + 1,
0880 theHeap,
0881 theHeapSize,
0882 theK,
0883 theBoundsMin,
0884 theBoundsMax);
0885 theBoundsMax[theAxis] = aSavedMax;
0886 }
0887 }
0888
0889
0890 void rangeSearchRecursive(const ThePointType& theQuery,
0891 double theRadiusSq,
0892 int theLo,
0893 int theHi,
0894 int theDepth,
0895 NCollection_DynamicArray<size_t>& theIndices) const
0896 {
0897 if (theLo > theHi)
0898 {
0899 return;
0900 }
0901
0902 if (theHi - theLo + 1 <= THE_LEAF_SIZE)
0903 {
0904 for (int i = theLo; i <= theHi; ++i)
0905 {
0906 const size_t anIdx = myIndices.Value(i);
0907 const double aSqDist = squareDistance(theQuery, myPoints.Value(static_cast<int>(anIdx)));
0908 if (aSqDist <= theRadiusSq)
0909 {
0910 theIndices.Append(anIdx);
0911 }
0912 }
0913 return;
0914 }
0915 const int theMid = (theLo + theHi) / 2;
0916 const size_t aNodeIndex = myIndices.Value(theMid);
0917 const ThePointType& aNodePoint = myPoints.Value(static_cast<int>(aNodeIndex));
0918 const double aSqDist = squareDistance(theQuery, aNodePoint);
0919 if (aSqDist <= theRadiusSq)
0920 {
0921 theIndices.Append(aNodeIndex);
0922 }
0923 if (theLo == theHi)
0924 {
0925 return;
0926 }
0927 const int theAxis = theDepth % TheDimension;
0928 const double aDiff = theQuery.Coord(theAxis + 1) - aNodePoint.Coord(theAxis + 1);
0929
0930 if (aDiff <= 0.0)
0931 {
0932 rangeSearchRecursive(theQuery, theRadiusSq, theLo, theMid - 1, theDepth + 1, theIndices);
0933 if (aDiff * aDiff <= theRadiusSq)
0934 {
0935 rangeSearchRecursive(theQuery, theRadiusSq, theMid + 1, theHi, theDepth + 1, theIndices);
0936 }
0937 }
0938 else
0939 {
0940 rangeSearchRecursive(theQuery, theRadiusSq, theMid + 1, theHi, theDepth + 1, theIndices);
0941 if (aDiff * aDiff <= theRadiusSq)
0942 {
0943 rangeSearchRecursive(theQuery, theRadiusSq, theLo, theMid - 1, theDepth + 1, theIndices);
0944 }
0945 }
0946 }
0947
0948
0949 template <typename Functor>
0950 void forEachInRangeRecursive(const ThePointType& theQuery,
0951 double theRadiusSq,
0952 int theLo,
0953 int theHi,
0954 int theDepth,
0955 Functor& theFunctor) const
0956 {
0957 if (theLo > theHi)
0958 {
0959 return;
0960 }
0961 if (theHi - theLo + 1 <= THE_LEAF_SIZE)
0962 {
0963 for (int i = theLo; i <= theHi; ++i)
0964 {
0965 const size_t anIdx = myIndices.Value(i);
0966 const double aSqDist = squareDistance(theQuery, myPoints.Value(static_cast<int>(anIdx)));
0967 if (aSqDist <= theRadiusSq)
0968 {
0969 theFunctor(anIdx);
0970 }
0971 }
0972 return;
0973 }
0974 const int aMid = (theLo + theHi) / 2;
0975 const size_t aNodeIndex = myIndices.Value(aMid);
0976 const ThePointType& aNodePoint = myPoints.Value(static_cast<int>(aNodeIndex));
0977 const double aSqDist = squareDistance(theQuery, aNodePoint);
0978 if (aSqDist <= theRadiusSq)
0979 {
0980 theFunctor(aNodeIndex);
0981 }
0982 if (theLo == theHi)
0983 {
0984 return;
0985 }
0986 const int aAxis = theDepth % TheDimension;
0987 const double aDiff = theQuery.Coord(aAxis + 1) - aNodePoint.Coord(aAxis + 1);
0988 if (aDiff <= 0.0)
0989 {
0990 forEachInRangeRecursive(theQuery, theRadiusSq, theLo, aMid - 1, theDepth + 1, theFunctor);
0991 if (aDiff * aDiff <= theRadiusSq)
0992 {
0993 forEachInRangeRecursive(theQuery, theRadiusSq, aMid + 1, theHi, theDepth + 1, theFunctor);
0994 }
0995 }
0996 else
0997 {
0998 forEachInRangeRecursive(theQuery, theRadiusSq, aMid + 1, theHi, theDepth + 1, theFunctor);
0999 if (aDiff * aDiff <= theRadiusSq)
1000 {
1001 forEachInRangeRecursive(theQuery, theRadiusSq, theLo, aMid - 1, theDepth + 1, theFunctor);
1002 }
1003 }
1004 }
1005
1006
1007 void boxSearchRecursive(const ThePointType& theMin,
1008 const ThePointType& theMax,
1009 int theLo,
1010 int theHi,
1011 int theDepth,
1012 NCollection_DynamicArray<size_t>& theIndices) const
1013 {
1014 if (theLo > theHi)
1015 {
1016 return;
1017 }
1018
1019 if (theHi - theLo + 1 <= THE_LEAF_SIZE)
1020 {
1021 for (int i = theLo; i <= theHi; ++i)
1022 {
1023 const size_t anIdx = myIndices.Value(i);
1024 if (isInsideBox(myPoints.Value(static_cast<int>(anIdx)), theMin, theMax))
1025 {
1026 theIndices.Append(anIdx);
1027 }
1028 }
1029 return;
1030 }
1031 const int theMid = (theLo + theHi) / 2;
1032 const size_t aNodeIndex = myIndices.Value(theMid);
1033 const ThePointType& aNodePoint = myPoints.Value(static_cast<int>(aNodeIndex));
1034 if (isInsideBox(aNodePoint, theMin, theMax))
1035 {
1036 theIndices.Append(aNodeIndex);
1037 }
1038 if (theLo == theHi)
1039 {
1040 return;
1041 }
1042 const int theAxis = theDepth % TheDimension;
1043 const double aCoord = aNodePoint.Coord(theAxis + 1);
1044 if (aCoord >= theMin.Coord(theAxis + 1))
1045 {
1046 boxSearchRecursive(theMin, theMax, theLo, theMid - 1, theDepth + 1, theIndices);
1047 }
1048 if (aCoord <= theMax.Coord(theAxis + 1))
1049 {
1050 boxSearchRecursive(theMin, theMax, theMid + 1, theHi, theDepth + 1, theIndices);
1051 }
1052 }
1053
1054
1055
1056 void containingSearchRecursive(const ThePointType& theQuery,
1057 int theLo,
1058 int theHi,
1059 int theDepth,
1060 NCollection_DynamicArray<size_t>& theIndices,
1061 double theBoundsMin[],
1062 double theBoundsMax[]) const
1063 {
1064 if (theLo > theHi)
1065 {
1066 return;
1067 }
1068
1069 const int theMid = (theLo + theHi) / 2;
1070 const double aMaxR = myMaxRadius.Value(theMid);
1071 if (sqDistToBox(theQuery, theBoundsMin, theBoundsMax) > aMaxR * aMaxR)
1072 {
1073 return;
1074 }
1075
1076 if (theHi - theLo + 1 <= THE_LEAF_SIZE)
1077 {
1078 for (int i = theLo; i <= theHi; ++i)
1079 {
1080 const size_t anIdx = myIndices.Value(i);
1081 const double aR = myRadii.Value(static_cast<int>(anIdx));
1082 const double aSqDist = squareDistance(theQuery, myPoints.Value(static_cast<int>(anIdx)));
1083 if (aSqDist <= aR * aR)
1084 {
1085 theIndices.Append(anIdx);
1086 }
1087 }
1088 return;
1089 }
1090
1091 const size_t aNodeIndex = myIndices.Value(theMid);
1092 const ThePointType& aNodePoint = myPoints.Value(static_cast<int>(aNodeIndex));
1093 const double aNodeR = myRadii.Value(static_cast<int>(aNodeIndex));
1094 if (squareDistance(theQuery, aNodePoint) <= aNodeR * aNodeR)
1095 {
1096 theIndices.Append(aNodeIndex);
1097 }
1098
1099 const int theAxis = theDepth % TheDimension;
1100 const double aSplitVal = aNodePoint.Coord(theAxis + 1);
1101 const double aSavedMax = theBoundsMax[theAxis];
1102 theBoundsMax[theAxis] = aSplitVal;
1103 containingSearchRecursive(theQuery,
1104 theLo,
1105 theMid - 1,
1106 theDepth + 1,
1107 theIndices,
1108 theBoundsMin,
1109 theBoundsMax);
1110 theBoundsMax[theAxis] = aSavedMax;
1111 const double aSavedMin = theBoundsMin[theAxis];
1112 theBoundsMin[theAxis] = aSplitVal;
1113 containingSearchRecursive(theQuery,
1114 theMid + 1,
1115 theHi,
1116 theDepth + 1,
1117 theIndices,
1118 theBoundsMin,
1119 theBoundsMax);
1120 theBoundsMin[theAxis] = aSavedMin;
1121 }
1122
1123
1124
1125 void nearestWeightedRecursive(const ThePointType& theQuery,
1126 int theLo,
1127 int theHi,
1128 int theDepth,
1129 size_t& theBestIndex,
1130 double& theBestGap,
1131 double theBoundsMin[],
1132 double theBoundsMax[]) const
1133 {
1134 if (theLo > theHi)
1135 {
1136 return;
1137 }
1138
1139
1140 const int theMid = (theLo + theHi) / 2;
1141 const double aMaxR = myMaxRadius.Value(theMid);
1142 const double aSqDistToBox = sqDistToBox(theQuery, theBoundsMin, theBoundsMax);
1143 const double aPruneThreshold = theBestGap + aMaxR;
1144 if (aPruneThreshold >= 0.0 && aSqDistToBox >= aPruneThreshold * aPruneThreshold)
1145 {
1146 return;
1147 }
1148
1149 if (theHi - theLo + 1 <= THE_LEAF_SIZE)
1150 {
1151 for (int i = theLo; i <= theHi; ++i)
1152 {
1153 const size_t anIdx = myIndices.Value(i);
1154 const double aDist =
1155 std::sqrt(squareDistance(theQuery, myPoints.Value(static_cast<int>(anIdx))));
1156 const double aGap = aDist - myRadii.Value(static_cast<int>(anIdx));
1157 if (aGap < theBestGap)
1158 {
1159 theBestGap = aGap;
1160 theBestIndex = anIdx;
1161 }
1162 }
1163 return;
1164 }
1165
1166 const size_t aNodeIndex = myIndices.Value(theMid);
1167 const ThePointType& aNodePoint = myPoints.Value(static_cast<int>(aNodeIndex));
1168 const double aDist = std::sqrt(squareDistance(theQuery, aNodePoint));
1169 const double aGap = aDist - myRadii.Value(static_cast<int>(aNodeIndex));
1170 if (aGap < theBestGap)
1171 {
1172 theBestGap = aGap;
1173 theBestIndex = aNodeIndex;
1174 }
1175
1176 const int theAxis = theDepth % TheDimension;
1177 const double aSplitVal = aNodePoint.Coord(theAxis + 1);
1178 const double aDiff = theQuery.Coord(theAxis + 1) - aSplitVal;
1179 if (aDiff <= 0.0)
1180 {
1181 const double aSavedMax = theBoundsMax[theAxis];
1182 theBoundsMax[theAxis] = aSplitVal;
1183 nearestWeightedRecursive(theQuery,
1184 theLo,
1185 theMid - 1,
1186 theDepth + 1,
1187 theBestIndex,
1188 theBestGap,
1189 theBoundsMin,
1190 theBoundsMax);
1191 theBoundsMax[theAxis] = aSavedMax;
1192 const double aSavedMin = theBoundsMin[theAxis];
1193 theBoundsMin[theAxis] = aSplitVal;
1194 nearestWeightedRecursive(theQuery,
1195 theMid + 1,
1196 theHi,
1197 theDepth + 1,
1198 theBestIndex,
1199 theBestGap,
1200 theBoundsMin,
1201 theBoundsMax);
1202 theBoundsMin[theAxis] = aSavedMin;
1203 }
1204 else
1205 {
1206 const double aSavedMin = theBoundsMin[theAxis];
1207 theBoundsMin[theAxis] = aSplitVal;
1208 nearestWeightedRecursive(theQuery,
1209 theMid + 1,
1210 theHi,
1211 theDepth + 1,
1212 theBestIndex,
1213 theBestGap,
1214 theBoundsMin,
1215 theBoundsMax);
1216 theBoundsMin[theAxis] = aSavedMin;
1217 const double aSavedMax = theBoundsMax[theAxis];
1218 theBoundsMax[theAxis] = aSplitVal;
1219 nearestWeightedRecursive(theQuery,
1220 theLo,
1221 theMid - 1,
1222 theDepth + 1,
1223 theBestIndex,
1224 theBestGap,
1225 theBoundsMin,
1226 theBoundsMax);
1227 theBoundsMax[theAxis] = aSavedMax;
1228 }
1229 }
1230
1231 private:
1232 NCollection_Array1<ThePointType> myPoints;
1233 NCollection_Array1<size_t> myIndices;
1234 NCollection_Array1<double> myRadii;
1235 NCollection_Array1<double>
1236 myMaxRadius;
1237 size_t mySize;
1238 };
1239
1240 #endif