Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-09-28 09:19:34

0001 // Copyright (c) 2026 OPEN CASCADE SAS
0002 //
0003 // This file is part of Open CASCADE Technology software library.
0004 //
0005 // This library is free software; you can redistribute it and/or modify it under
0006 // the terms of the GNU Lesser General Public License version 2.1 as published
0007 // by the Free Software Foundation, with special exception defined in the file
0008 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
0009 // distribution for complete text of the license and disclaimer of any warranty.
0010 //
0011 // Alternatively, this file may be used under the terms of Open CASCADE
0012 // commercial license or contractual agreement.
0013 
0014 #ifndef _BRepGraph_ChildExplorer_HeaderFile
0015 #define _BRepGraph_ChildExplorer_HeaderFile
0016 
0017 #include <BRepGraph.hxx>
0018 #include <BRepGraphInc_Definition.hxx>
0019 #include <BRepGraphInc_Instance.hxx>
0020 #include <BRepGraphInc_Reference.hxx>
0021 #include <BRepGraph_UsagePath.hxx>
0022 #include <NCollection_ForwardRange.hxx>
0023 #include <NCollection_LocalArray.hxx>
0024 #include <TopAbs_Orientation.hxx>
0025 #include <TopLoc_Location.hxx>
0026 
0027 #include <optional>
0028 
0029 //! @brief Stack-based lazy downward hierarchy walker for BRepGraph with inline
0030 //! location/orientation accumulation.
0031 //! @see BRepGraph class comment "Iterator guide" for choosing between iterator types.
0032 //!
0033 //! Walks the graph hierarchy from a root node down to entities of a target kind,
0034 //! yielding one occurrence at a time via a depth-first stack. Location and
0035 //! orientation are composed incrementally during the walk, making
0036 //! Current().Location and Current().Orientation O(1) per call.
0037 //!
0038 //! The traversal follows the actual graph structure transparently - every node
0039 //! kind is visited as a distinct entity (no hidden collapses):
0040 //!   Compound -> children,  CompSolid -> Solids,  Solid -> Shells,
0041 //!   Shell -> Faces,  Face -> Wires (+direct Vertices),  Wire -> CoEdges,
0042 //!   CoEdge -> Edge,  Edge -> Vertices,
0043 //!   Product -> Occurrences, Occurrence -> Product/topology-root.
0044 //!
0045 //! Unlike flat definition traversal by typed ids, BRepGraph_ChildExplorer visits
0046 //! each occurrence. If Edge[5] is reachable through Face[0] and Face[1],
0047 //! it is visited twice with different accumulated transforms.
0048 //!
0049 //! ## Traversal modes
0050 //! - **Recursive**: depth-first walk through the full subgraph.
0051 //!   Without target kind, all descendant nodes are emitted.
0052 //!   With target kind, only matching nodes are emitted but intermediate
0053 //!   levels are traversed to reach them.
0054 //! - **DirectChildren**: yields only the immediate children of the root.
0055 //!   No descent into grandchildren.  With target kind, only children
0056 //!   matching the kind are returned.
0057 class BRepGraph_ChildExplorer
0058 {
0059 public:
0060   DEFINE_STANDARD_ALLOC
0061 
0062   //! Relationship kind between Current() and CurrentParent().
0063   enum class LinkKind
0064   {
0065     None,       //!< No current incoming link (e.g. root/self match).
0066     Reference,  //!< Current() is reached through a parent-owned RefId.
0067     Structural, //!< Current() is reached through a structural non-ref link.
0068   };
0069 
0070   //! Downward traversal strategy.
0071   enum class TraversalMode
0072   {
0073     Recursive,      //!< Depth-first walk through the full subgraph.
0074     DirectChildren, //!< Yields only the immediate children of the root.
0075   };
0076 
0077   //! Consolidated configuration for the explorer.
0078   //!
0079   //! The `Config`-based constructor is the preferred idiom: new options can be
0080   //! added as fields without additional constructor overloads.
0081   //!
0082   //! @code
0083   //!   BRepGraph_ChildExplorer::Config aConfig;
0084   //!   aConfig.Mode        = BRepGraph_ChildExplorer::TraversalMode::DirectChildren;
0085   //!   aConfig.TargetKind  = BRepGraph_NodeId::Kind::Face;
0086   //!   aConfig.StartLoc    = aParentLocation;
0087   //!   aConfig.StartOri    = TopAbs_REVERSED;
0088   //!   for (auto [id, loc, ori] : BRepGraph_ChildExplorer(aGraph, aRoot, aConfig)) { ... }
0089   //! @endcode
0090   struct Config
0091   {
0092     TraversalMode Mode = TraversalMode::Recursive;
0093     std::optional<BRepGraph_NodeId::Kind>
0094       TargetKind;                                    //!< Emit only this kind (no value = emit all).
0095     std::optional<BRepGraph_NodeId::Kind> AvoidKind; //!< Do not descend into this kind.
0096     bool                                  EmitAvoidKind =
0097       false; //!< Emit matching avoid-kind nodes once before skipping their subtree.
0098     bool               AccumulateLocation    = true; //!< Compose Location down the walk.
0099     bool               AccumulateOrientation = true; //!< Compose Orientation down the walk.
0100     TopLoc_Location    StartLoc;                     //!< Initial accumulated location.
0101     TopAbs_Orientation StartOri = TopAbs_FORWARD;    //!< Initial accumulated orientation.
0102   };
0103 
0104   //! Preferred long-term constructor: all tuning knobs in `Config`.
0105   //! @param[in] theGraph graph to walk
0106   //! @param[in] theRoot  root node where the walk begins
0107   //! @param[in] theConfig traversal configuration (mode, target kind, avoid kind, etc.)
0108   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&       theGraph,
0109                                           const BRepGraph_NodeId theRoot,
0110                                           const Config&          theConfig);
0111 
0112   //! Explore all descendants of the root node using recursive traversal.
0113   //! @param[in] theGraph graph to walk
0114   //! @param[in] theRoot  root node where the walk begins
0115   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&       theGraph,
0116                                           const BRepGraph_NodeId theRoot);
0117 
0118   //! Explore descendants of the root node using the given traversal mode.
0119   //! @param[in] theGraph graph to walk
0120   //! @param[in] theRoot  root node where the walk begins
0121   //! @param[in] theMode  traversal strategy (recursive or direct children)
0122   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&       theGraph,
0123                                           const BRepGraph_NodeId theRoot,
0124                                           TraversalMode          theMode);
0125 
0126   //! Explore descendants while pruning branches at the avoid kind.
0127   //! @param[in] theGraph        graph to walk
0128   //! @param[in] theRoot         root node where the walk begins
0129   //! @param[in] theAvoidKind    node kind to avoid descending into
0130   //! @param[in] theEmitAvoidKind if true, emit matching avoid-kind nodes once before skipping
0131   //! @param[in] theMode         traversal strategy
0132   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&                             theGraph,
0133                                           const BRepGraph_NodeId                       theRoot,
0134                                           const std::optional<BRepGraph_NodeId::Kind>& theAvoidKind,
0135                                           bool          theEmitAvoidKind,
0136                                           TraversalMode theMode = TraversalMode::Recursive);
0137 
0138   //! Explore only descendants of the given target kind.
0139   //! @param[in] theGraph     graph to walk
0140   //! @param[in] theRoot      root node where the walk begins
0141   //! @param[in] theTargetKind kind of nodes to emit
0142   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&       theGraph,
0143                                           const BRepGraph_NodeId theRoot,
0144                                           BRepGraph_NodeId::Kind theTargetKind);
0145 
0146   //! Explore only descendants of the given target kind using the given traversal mode.
0147   //! @param[in] theGraph     graph to walk
0148   //! @param[in] theRoot      root node where the walk begins
0149   //! @param[in] theTargetKind kind of nodes to emit
0150   //! @param[in] theMode      traversal strategy
0151   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&       theGraph,
0152                                           const BRepGraph_NodeId theRoot,
0153                                           BRepGraph_NodeId::Kind theTargetKind,
0154                                           TraversalMode          theMode);
0155 
0156   //! Explore descendants of the given target kind while pruning branches at the avoid kind.
0157   //! @param[in] theGraph        graph to walk
0158   //! @param[in] theRoot         root node where the walk begins
0159   //! @param[in] theTargetKind   kind of nodes to emit
0160   //! @param[in] theAvoidKind    node kind to avoid descending into
0161   //! @param[in] theEmitAvoidKind if true, emit matching avoid-kind nodes once before skipping
0162   //! @param[in] theMode         traversal strategy
0163   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&       theGraph,
0164                                           const BRepGraph_NodeId theRoot,
0165                                           BRepGraph_NodeId::Kind theTargetKind,
0166                                           const std::optional<BRepGraph_NodeId::Kind>& theAvoidKind,
0167                                           bool          theEmitAvoidKind,
0168                                           TraversalMode theMode = TraversalMode::Recursive);
0169 
0170   //! Explore only descendants of the given target kind starting from a product.
0171   //! @param[in] theGraph     graph to walk
0172   //! @param[in] theProduct   product whose occurrences and topology are explored
0173   //! @param[in] theTargetKind kind of nodes to emit
0174   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&          theGraph,
0175                                           const BRepGraph_ProductId theProduct,
0176                                           BRepGraph_NodeId::Kind    theTargetKind);
0177 
0178   //! Disambiguates non-product typed ids from the ProductId-specific overload
0179   //! family above and keeps them on the generic NodeId traversal path.
0180   //! @param[in] theGraph     graph to walk
0181   //! @param[in] theRoot      typed root node where the walk begins
0182   //! @param[in] theTargetKind kind of nodes to emit
0183   template <BRepGraph_NodeId::Kind TheKind,
0184             typename std::enable_if_t<TheKind != BRepGraph_NodeId::Kind::Product, int> = 0>
0185   BRepGraph_ChildExplorer(const BRepGraph&                       theGraph,
0186                           const BRepGraph_NodeId::Typed<TheKind> theRoot,
0187                           BRepGraph_NodeId::Kind                 theTargetKind)
0188       : BRepGraph_ChildExplorer(theGraph, BRepGraph_NodeId(theRoot), theTargetKind)
0189   {
0190   }
0191 
0192   //! Explore only descendants of the given target kind starting from a product,
0193   //! using the given traversal mode.
0194   //! @param[in] theGraph     graph to walk
0195   //! @param[in] theProduct   product whose occurrences and topology are explored
0196   //! @param[in] theTargetKind kind of nodes to emit
0197   //! @param[in] theMode      traversal strategy
0198   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&          theGraph,
0199                                           const BRepGraph_ProductId theProduct,
0200                                           BRepGraph_NodeId::Kind    theTargetKind,
0201                                           TraversalMode             theMode);
0202 
0203   //! Disambiguates non-product typed ids from the ProductId-specific overload
0204   //! family above and keeps them on the generic NodeId traversal path.
0205   //! @param[in] theGraph     graph to walk
0206   //! @param[in] theRoot      typed root node where the walk begins
0207   //! @param[in] theTargetKind kind of nodes to emit
0208   //! @param[in] theMode      traversal strategy
0209   template <BRepGraph_NodeId::Kind TheKind,
0210             typename std::enable_if_t<TheKind != BRepGraph_NodeId::Kind::Product, int> = 0>
0211   BRepGraph_ChildExplorer(const BRepGraph&                       theGraph,
0212                           const BRepGraph_NodeId::Typed<TheKind> theRoot,
0213                           BRepGraph_NodeId::Kind                 theTargetKind,
0214                           TraversalMode                          theMode)
0215       : BRepGraph_ChildExplorer(theGraph, BRepGraph_NodeId(theRoot), theTargetKind, theMode)
0216   {
0217   }
0218 
0219   //! Explore only descendants of the given target kind with explicit location/orientation control.
0220   //! @param[in] theGraph     graph to walk
0221   //! @param[in] theRoot      root node where the walk begins
0222   //! @param[in] theTargetKind kind of nodes to emit
0223   //! @param[in] theCumLoc    if true, accumulate location down the walk
0224   //! @param[in] theCumOri    if true, accumulate orientation down the walk
0225   //! @param[in] theMode      traversal strategy
0226   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&       theGraph,
0227                                           const BRepGraph_NodeId theRoot,
0228                                           BRepGraph_NodeId::Kind theTargetKind,
0229                                           bool                   theCumLoc,
0230                                           bool                   theCumOri,
0231                                           TraversalMode theMode = TraversalMode::Recursive);
0232 
0233   //! Explore only descendants of the given target kind starting from a product,
0234   //! with explicit location/orientation control.
0235   //! @param[in] theGraph     graph to walk
0236   //! @param[in] theProduct   product whose occurrences and topology are explored
0237   //! @param[in] theTargetKind kind of nodes to emit
0238   //! @param[in] theCumLoc    if true, accumulate location down the walk
0239   //! @param[in] theCumOri    if true, accumulate orientation down the walk
0240   //! @param[in] theMode      traversal strategy
0241   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&          theGraph,
0242                                           const BRepGraph_ProductId theProduct,
0243                                           BRepGraph_NodeId::Kind    theTargetKind,
0244                                           bool                      theCumLoc,
0245                                           bool                      theCumOri,
0246                                           TraversalMode theMode = TraversalMode::Recursive);
0247 
0248   //! Disambiguates non-product typed ids from the ProductId-specific overload
0249   //! family above and keeps them on the generic NodeId traversal path.
0250   //! @param[in] theGraph     graph to walk
0251   //! @param[in] theRoot      typed root node where the walk begins
0252   //! @param[in] theTargetKind kind of nodes to emit
0253   //! @param[in] theCumLoc    if true, accumulate location down the walk
0254   //! @param[in] theCumOri    if true, accumulate orientation down the walk
0255   //! @param[in] theMode      traversal strategy
0256   template <BRepGraph_NodeId::Kind TheKind,
0257             typename std::enable_if_t<TheKind != BRepGraph_NodeId::Kind::Product, int> = 0>
0258   BRepGraph_ChildExplorer(const BRepGraph&                       theGraph,
0259                           const BRepGraph_NodeId::Typed<TheKind> theRoot,
0260                           BRepGraph_NodeId::Kind                 theTargetKind,
0261                           bool                                   theCumLoc,
0262                           bool                                   theCumOri,
0263                           TraversalMode                          theMode = TraversalMode::Recursive)
0264       : BRepGraph_ChildExplorer(theGraph,
0265                                 BRepGraph_NodeId(theRoot),
0266                                 theTargetKind,
0267                                 theCumLoc,
0268                                 theCumOri,
0269                                 theMode)
0270   {
0271   }
0272 
0273   //! Explore only descendants of the given target kind with an explicit initial transform.
0274   //! @param[in] theGraph     graph to walk
0275   //! @param[in] theRoot      root node where the walk begins
0276   //! @param[in] theTargetKind kind of nodes to emit
0277   //! @param[in] theStartLoc  initial accumulated location
0278   //! @param[in] theStartOri  initial accumulated orientation
0279   //! @param[in] theMode      traversal strategy
0280   Standard_EXPORT BRepGraph_ChildExplorer(const BRepGraph&       theGraph,
0281                                           const BRepGraph_NodeId theRoot,
0282                                           BRepGraph_NodeId::Kind theTargetKind,
0283                                           const TopLoc_Location& theStartLoc,
0284                                           TopAbs_Orientation     theStartOri,
0285                                           TraversalMode theMode = TraversalMode::DirectChildren);
0286 
0287   //! Returns the traversal configuration this explorer was constructed with.
0288   //! Read-only - configuration is fixed for the lifetime of the explorer.
0289   [[nodiscard]] const Config& GetConfig() const { return myConfig; }
0290 
0291   //! True if another matching descendant is available.
0292   [[nodiscard]] bool More() const { return myHasMore; }
0293 
0294   //! Advance to the next matching descendant.
0295   Standard_EXPORT void Next();
0296 
0297   //! Current matching descendant node with accumulated location and orientation.
0298   [[nodiscard]] BRepGraphInc::NodeInstance Current() const
0299   {
0300     return {myCurrent, myLocation, myOrientation};
0301   }
0302 
0303   //! Returns the immediate parent of Current() in the explored path.
0304   //! Returns invalid NodeId when Current() is the root/self match.
0305   [[nodiscard]] Standard_EXPORT BRepGraph_NodeId CurrentParent() const;
0306 
0307   //! Returns how Current() is linked from CurrentParent().
0308   [[nodiscard]] Standard_EXPORT LinkKind CurrentLinkKind() const;
0309 
0310   //! Returns the exact parent-owned RefId for Current(), when the current step
0311   //! is represented by a reference entry. Returns invalid RefId for structural
0312   //! links without a dedicated ref entry such as CoEdge->Edge,
0313   //! Occurrence->Product/topology-root.
0314   [[nodiscard]] Standard_EXPORT BRepGraph_RefId CurrentRef() const;
0315 
0316   //! Returns the explicit concrete traversal path from the explorer root to Current().
0317   [[nodiscard]] Standard_EXPORT BRepGraph_UsagePath CurrentUsagePath() const;
0318 
0319   //! Returns the accumulated location at the most recent ancestor of the given kind.
0320   //! @param[in] theKind node kind to search for in the ancestor chain
0321   //! @return accumulated location at the matching ancestor
0322   [[nodiscard]] Standard_EXPORT TopLoc_Location
0323     LocationOf(const BRepGraph_NodeId::Kind theKind) const;
0324 
0325   //! Returns the node id of the most recent ancestor of the given kind.
0326   //! @param[in] theKind node kind to search for in the ancestor chain
0327   //! @return node id of the matching ancestor
0328   [[nodiscard]] Standard_EXPORT BRepGraph_NodeId NodeOf(const BRepGraph_NodeId::Kind theKind) const;
0329 
0330   //! Returns the accumulated location at the given stack level.
0331   //! @param[in] theLevel zero-based stack depth (0 = root)
0332   //! @return accumulated location at the specified level
0333   [[nodiscard]] Standard_EXPORT TopLoc_Location LocationAt(const int theLevel) const;
0334 
0335   //! Returns the node id at the given stack level.
0336   //! @param[in] theLevel zero-based stack depth (0 = root)
0337   //! @return node id at the specified level
0338   [[nodiscard]] Standard_EXPORT BRepGraph_NodeId NodeAt(const int theLevel) const;
0339 
0340   //! Number of valid ancestor frames currently on the stack (excluding the
0341   //! sentinel below the root). O(1); avoids the O(depth^2) NodeAt(i) walk used
0342   //! to compute container priority in selection-mode building.
0343   [[nodiscard]] int Depth() const noexcept { return myStackTop < 0 ? 0 : myStackTop + 1; }
0344 
0345   //! Returns an STL-compatible iterator for range-based for loops.
0346   NCollection_ForwardRangeIterator<BRepGraph_ChildExplorer> begin()
0347   {
0348     return NCollection_ForwardRangeIterator<BRepGraph_ChildExplorer>(this);
0349   }
0350 
0351   //! Returns a sentinel marking the end of iteration.
0352   NCollection_ForwardRangeSentinel end() const { return NCollection_ForwardRangeSentinel{}; }
0353 
0354 private:
0355   struct StackFrame
0356   {
0357     BRepGraph_NodeId   Node;
0358     uint32_t           NextChildIdx   = 0;
0359     int                StepFromParent = -1;
0360     BRepGraph_RefId    Ref; //!< RefId resolved at push time (O(1) in CurrentRef)
0361     TopLoc_Location    AccLocation;
0362     TopAbs_Orientation AccOrientation = TopAbs_FORWARD;
0363   };
0364 
0365   Standard_EXPORT void advance();
0366 
0367   void startTraversal(const TopLoc_Location& theStartLoc, TopAbs_Orientation theStartOri);
0368 
0369   static std::optional<BRepGraph_NodeId::Kind> normalizeAvoidKind(
0370     const std::optional<BRepGraph_NodeId::Kind>& theAvoidKind,
0371     const std::optional<BRepGraph_NodeId::Kind>& theTargetKind);
0372 
0373   static bool canContainTarget(BRepGraph_NodeId::Kind theParentKind,
0374                                BRepGraph_NodeId::Kind theTargetKind);
0375 
0376   static bool canHaveChildren(BRepGraph_NodeId::Kind theNodeKind);
0377 
0378   void setCurrentFromFrame(const int theFrameIndex);
0379 
0380   [[nodiscard]] bool shouldDescendFromCurrent() const;
0381 
0382   [[nodiscard]] bool matchesTarget(const BRepGraph_NodeId theNode) const
0383   {
0384     return myConfig.TargetKind.has_value() && theNode.NodeKind == *myConfig.TargetKind;
0385   }
0386 
0387   [[nodiscard]] bool matchesAvoid(const BRepGraph_NodeId theNode) const
0388   {
0389     return myConfig.AvoidKind.has_value() && theNode.NodeKind == *myConfig.AvoidKind;
0390   }
0391 
0392   [[nodiscard]] bool shouldEmit(const BRepGraph_NodeId theNode) const
0393   {
0394     const bool isAvoid = matchesAvoid(theNode);
0395     const bool isFind =
0396       !myConfig.TargetKind.has_value() || theNode.NodeKind == *myConfig.TargetKind;
0397     return myConfig.EmitAvoidKind ? (isFind || isAvoid) : (isFind && !isAvoid);
0398   }
0399 
0400   void pushFrame(const StackFrame& theFrame);
0401 
0402   void popFrame();
0403 
0404   StackFrame& topFrame() { return myStack[myStackTop]; }
0405 
0406   const StackFrame& topFrame() const { return myStack[myStackTop]; }
0407 
0408   static constexpr int THE_INLINE_STACK_SIZE = 16;
0409 
0410   const BRepGraph* myGraph = nullptr;
0411   BRepGraph_NodeId myRoot;
0412   Config           myConfig; //!< Traversal configuration - single source of truth.
0413 
0414   NCollection_LocalArray<StackFrame, THE_INLINE_STACK_SIZE> myStack;
0415   int                                                       myStackTop     = -1;
0416   int                                                       myCurrentFrame = -1;
0417 
0418   BRepGraph_NodeId   myCurrent;
0419   TopLoc_Location    myLocation;
0420   TopAbs_Orientation myOrientation = TopAbs_FORWARD;
0421   bool               myHasMore     = false;
0422 };
0423 
0424 #endif // _BRepGraph_ChildExplorer_HeaderFile