Warning, /include/opencascade/BVH_Traverse.lxx is written in an unsupported language. File is not indexed.
0001 // Created by: Eugeny MALTCHIKOV
0002 // Created on: 2019-04-17
0003 // Copyright (c) 2019 OPEN CASCADE SAS
0004 //
0005 // This file is part of Open CASCADE Technology software library.
0006 //
0007 // This library is free software; you can redistribute it and/or modify it under
0008 // the terms of the GNU Lesser General Public License version 2.1 as published
0009 // by the Free Software Foundation, with special exception defined in the file
0010 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0011 // distribution for complete text of the license and disclaimer of any warranty.
0012 //
0013 // Alternatively, this file may be used under the terms of Open CASCADE
0014 // commercial license or contractual agreement.
0015
0016 namespace
0017 {
0018 //! Auxiliary structure for keeping the nodes to process
0019 template <class MetricType>
0020 struct BVH_NodeInStack
0021 {
0022 //! Constructor
0023 BVH_NodeInStack(const Standard_Integer theNodeID = 0, const MetricType& theMetric = MetricType())
0024 : NodeID(theNodeID),
0025 Metric(theMetric)
0026 {
0027 }
0028
0029 // Fields
0030 Standard_Integer NodeID; //!< Id of the node in the BVH tree
0031 MetricType Metric; //!< Metric computed for the node
0032 };
0033 } // namespace
0034
0035 // =======================================================================
0036 // function : BVH_Traverse::Select
0037 // purpose :
0038 // =======================================================================
0039 template <class NumType, int Dimension, class BVHSetType, class MetricType>
0040 Standard_Integer BVH_Traverse<NumType, Dimension, BVHSetType, MetricType>::Select(
0041 const opencascade::handle<BVH_Tree<NumType, Dimension>>& theBVH)
0042 {
0043 if (theBVH.IsNull())
0044 return 0;
0045
0046 if (theBVH->NodeInfoBuffer().empty())
0047 return 0;
0048
0049 // Create stack
0050 BVH_NodeInStack<MetricType> aStack[BVH_Constants_MaxTreeDepth];
0051
0052 // clang-format off
0053 BVH_NodeInStack<MetricType> aNode (0); // Currently processed node, starting with the root node
0054 // clang-format on
0055 BVH_NodeInStack<MetricType> aPrevNode = aNode; // Previously processed node
0056
0057 Standard_Integer aHead = -1; // End of the stack
0058 Standard_Integer aNbAccepted = 0; // Counter for accepted elements
0059
0060 for (;;)
0061 {
0062 const BVH_Vec4i& aData = theBVH->NodeInfoBuffer()[aNode.NodeID];
0063
0064 if (aData.x() == 0)
0065 {
0066 // Inner node:
0067 // - check the metric of the node
0068 // - test the children of the node
0069
0070 if (!this->AcceptMetric(aNode.Metric))
0071 {
0072 // Test the left branch
0073 MetricType aMetricLft;
0074 Standard_Boolean isGoodLft =
0075 !RejectNode(theBVH->MinPoint(aData.y()), theBVH->MaxPoint(aData.y()), aMetricLft);
0076 if (this->Stop())
0077 return aNbAccepted;
0078
0079 // Test the right branch
0080 MetricType aMetricRgh;
0081 Standard_Boolean isGoodRgh =
0082 !RejectNode(theBVH->MinPoint(aData.z()), theBVH->MaxPoint(aData.z()), aMetricRgh);
0083 if (this->Stop())
0084 return aNbAccepted;
0085
0086 if (isGoodLft && isGoodRgh)
0087 {
0088 // Chose the branch with the best metric to be processed next,
0089 // put the other branch in the stack
0090 if (this->IsMetricBetter(aMetricLft, aMetricRgh))
0091 {
0092 aNode = BVH_NodeInStack<MetricType>(aData.y(), aMetricLft);
0093 aStack[++aHead] = BVH_NodeInStack<MetricType>(aData.z(), aMetricRgh);
0094 }
0095 else
0096 {
0097 aNode = BVH_NodeInStack<MetricType>(aData.z(), aMetricRgh);
0098 aStack[++aHead] = BVH_NodeInStack<MetricType>(aData.y(), aMetricLft);
0099 }
0100 }
0101 else if (isGoodLft || isGoodRgh)
0102 {
0103 aNode = isGoodLft ? BVH_NodeInStack<MetricType>(aData.y(), aMetricLft)
0104 : BVH_NodeInStack<MetricType>(aData.z(), aMetricRgh);
0105 }
0106 }
0107 else
0108 {
0109 // Both children will be accepted
0110 // Take one for processing, put the other into stack
0111 aNode = BVH_NodeInStack<MetricType>(aData.y(), aNode.Metric);
0112 aStack[++aHead] = BVH_NodeInStack<MetricType>(aData.z(), aNode.Metric);
0113 }
0114 }
0115 else
0116 {
0117 // Leaf node - apply the leaf node operation to each element
0118 for (Standard_Integer iN = aData.y(); iN <= aData.z(); ++iN)
0119 {
0120 if (Accept(iN, aNode.Metric))
0121 ++aNbAccepted;
0122
0123 if (this->Stop())
0124 return aNbAccepted;
0125 }
0126 }
0127
0128 if (aNode.NodeID == aPrevNode.NodeID)
0129 {
0130 if (aHead < 0)
0131 return aNbAccepted;
0132
0133 // Remove the nodes with bad metric from the stack
0134 aNode = aStack[aHead--];
0135 while (this->RejectMetric(aNode.Metric))
0136 {
0137 if (aHead < 0)
0138 return aNbAccepted;
0139 aNode = aStack[aHead--];
0140 }
0141 }
0142
0143 aPrevNode = aNode;
0144 }
0145 }
0146
0147 namespace
0148 {
0149 //! Auxiliary structure for keeping the pair of nodes to process
0150 template <class MetricType>
0151 struct BVH_PairNodesInStack
0152 {
0153 //! Constructor
0154 BVH_PairNodesInStack(const Standard_Integer theNodeID1 = 0,
0155 const Standard_Integer theNodeID2 = 0,
0156 const MetricType& theMetric = MetricType())
0157 : NodeID1(theNodeID1),
0158 NodeID2(theNodeID2),
0159 Metric(theMetric)
0160 {
0161 }
0162
0163 // Fields
0164 Standard_Integer NodeID1; //!< Id of the node in the first BVH tree
0165 Standard_Integer NodeID2; //!< Id of the node in the second BVH tree
0166 MetricType Metric; //!< Metric computed for the pair of nodes
0167 };
0168 } // namespace
0169
0170 // =======================================================================
0171 // function : BVH_PairTraverse::Select
0172 // purpose :
0173 // =======================================================================
0174 template <class NumType, int Dimension, class BVHSetType, class MetricType>
0175 Standard_Integer BVH_PairTraverse<NumType, Dimension, BVHSetType, MetricType>::Select(
0176 const opencascade::handle<BVH_Tree<NumType, Dimension>>& theBVH1,
0177 const opencascade::handle<BVH_Tree<NumType, Dimension>>& theBVH2)
0178 {
0179 if (theBVH1.IsNull() || theBVH2.IsNull())
0180 return 0;
0181
0182 const BVH_Array4i& aBVHNodes1 = theBVH1->NodeInfoBuffer();
0183 const BVH_Array4i& aBVHNodes2 = theBVH2->NodeInfoBuffer();
0184 if (aBVHNodes1.empty() || aBVHNodes2.empty())
0185 return 0;
0186
0187 // On each iteration we can add max four new pairs of nodes to process.
0188 // One of these pairs goes directly to processing, while others
0189 // are put in the stack. So the max number of pairs in the stack is
0190 // the max tree depth multiplied by 3.
0191 const Standard_Integer aMaxNbPairsInStack = 3 * BVH_Constants_MaxTreeDepth;
0192
0193 // Stack of pairs of nodes to process
0194 BVH_PairNodesInStack<MetricType> aStack[aMaxNbPairsInStack];
0195
0196 // Currently processed pair, starting with the root nodes
0197 BVH_PairNodesInStack<MetricType> aNode(0, 0);
0198 // Previously processed pair
0199 BVH_PairNodesInStack<MetricType> aPrevNode = aNode;
0200 // End of the stack
0201 Standard_Integer aHead = -1;
0202 // Counter for accepted elements
0203 Standard_Integer aNbAccepted = 0;
0204
0205 for (;;)
0206 {
0207 const BVH_Vec4i& aData1 = aBVHNodes1[aNode.NodeID1];
0208 const BVH_Vec4i& aData2 = aBVHNodes2[aNode.NodeID2];
0209
0210 if (aData1.x() != 0 && aData2.x() != 0)
0211 {
0212 // Outer/Outer
0213 for (Standard_Integer iN1 = aData1.y(); iN1 <= aData1.z(); ++iN1)
0214 {
0215 for (Standard_Integer iN2 = aData2.y(); iN2 <= aData2.z(); ++iN2)
0216 {
0217 if (Accept(iN1, iN2))
0218 ++aNbAccepted;
0219
0220 if (this->Stop())
0221 return aNbAccepted;
0222 }
0223 }
0224 }
0225 else
0226 {
0227 BVH_PairNodesInStack<MetricType> aPairs[4];
0228 Standard_Integer aNbPairs = 0;
0229
0230 if (aData1.x() == 0 && aData2.x() == 0)
0231 {
0232 // Inner/Inner
0233 aPairs[aNbPairs++] = BVH_PairNodesInStack<MetricType>(aData1.y(), aData2.y());
0234 aPairs[aNbPairs++] = BVH_PairNodesInStack<MetricType>(aData1.y(), aData2.z());
0235 aPairs[aNbPairs++] = BVH_PairNodesInStack<MetricType>(aData1.z(), aData2.y());
0236 aPairs[aNbPairs++] = BVH_PairNodesInStack<MetricType>(aData1.z(), aData2.z());
0237 }
0238 else if (aData1.x() == 0)
0239 {
0240 // Inner/Outer
0241 aPairs[aNbPairs++] = BVH_PairNodesInStack<MetricType>(aData1.y(), aNode.NodeID2);
0242 aPairs[aNbPairs++] = BVH_PairNodesInStack<MetricType>(aData1.z(), aNode.NodeID2);
0243 }
0244 else if (aData2.x() == 0)
0245 {
0246 // Outer/Inner
0247 aPairs[aNbPairs++] = BVH_PairNodesInStack<MetricType>(aNode.NodeID1, aData2.y());
0248 aPairs[aNbPairs++] = BVH_PairNodesInStack<MetricType>(aNode.NodeID1, aData2.z());
0249 }
0250
0251 BVH_PairNodesInStack<MetricType> aKeptPairs[4];
0252 Standard_Integer aNbKept = 0;
0253 // Compute metrics for the nodes
0254 for (Standard_Integer iPair = 0; iPair < aNbPairs; ++iPair)
0255 {
0256 const Standard_Boolean isPairRejected = RejectNode(theBVH1->MinPoint(aPairs[iPair].NodeID1),
0257 theBVH1->MaxPoint(aPairs[iPair].NodeID1),
0258 theBVH2->MinPoint(aPairs[iPair].NodeID2),
0259 theBVH2->MaxPoint(aPairs[iPair].NodeID2),
0260 aPairs[iPair].Metric);
0261 if (!isPairRejected)
0262 {
0263 // Put the item into the sorted array of pairs
0264 Standard_Integer iSort = aNbKept;
0265 while (iSort > 0
0266 && this->IsMetricBetter(aPairs[iPair].Metric, aKeptPairs[iSort - 1].Metric))
0267 {
0268 aKeptPairs[iSort] = aKeptPairs[iSort - 1];
0269 --iSort;
0270 }
0271 aKeptPairs[iSort] = aPairs[iPair];
0272 aNbKept++;
0273 }
0274 }
0275
0276 if (aNbKept > 0)
0277 {
0278 aNode = aKeptPairs[0];
0279
0280 for (Standard_Integer iPair = 1; iPair < aNbKept; ++iPair)
0281 {
0282 aStack[++aHead] = aKeptPairs[iPair];
0283 }
0284 }
0285 }
0286
0287 if (aNode.NodeID1 == aPrevNode.NodeID1 && aNode.NodeID2 == aPrevNode.NodeID2)
0288 {
0289 // No pairs to add
0290 if (aHead < 0)
0291 return aNbAccepted;
0292
0293 // Remove the pairs of nodes with bad metric from the stack
0294 aNode = aStack[aHead--];
0295 while (this->RejectMetric(aNode.Metric))
0296 {
0297 if (aHead < 0)
0298 return aNbAccepted;
0299 aNode = aStack[aHead--];
0300 }
0301 }
0302
0303 aPrevNode = aNode;
0304 }
0305 }