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_CacheDerivedState_HeaderFile
0015 #define _BRepGraph_CacheDerivedState_HeaderFile
0016 
0017 #include <BRepGraph_Cache.hxx>
0018 #include <BRepGraph_NodeId.hxx>
0019 #include <NCollection_DynamicArray.hxx>
0020 #include <Standard_DefineAlloc.hxx>
0021 #include <Standard_GUID.hxx>
0022 
0023 #include <atomic>
0024 #include <mutex>
0025 
0026 class BRepGraphInc_Storage;
0027 
0028 //! @brief Cache for derived edge, wire, and shell properties.
0029 //!
0030 //! Each query is independent and caches only its own result.
0031 //! Callers request specific values (IsDegenerated, SameParameter, etc.)
0032 //! and the cache computes + stores only what is needed.
0033 class BRepGraph_CacheDerivedState : public BRepGraph_Cache
0034 {
0035 public:
0036   //! Returns the unique cache service GUID.
0037   [[nodiscard]] Standard_EXPORT static const Standard_GUID& GetID();
0038 
0039   //! Returns the unique cache service GUID.
0040   [[nodiscard]] Standard_EXPORT const Standard_GUID& ID() const override;
0041 
0042   //! Returns the cache service display name.
0043   [[nodiscard]] Standard_EXPORT const TCollection_AsciiString& Name() const override;
0044 
0045   //! Clears all cached entries.
0046   Standard_EXPORT void Clear() noexcept override;
0047 
0048   //! Copy fresh, remappable derived-state entries into the target graph.
0049   Standard_EXPORT void CopyFreshTo(const BRepGraph_CopyRemap& theCopy) const override;
0050 
0051   //! @brief Test if an edge is degenerate (no 3D curve and vertex collapse).
0052   //! Computes and caches only Status - does NOT compute SameParameter/SameRange.
0053   //! @param[in] theEdge edge definition identifier
0054   //! @return true if the edge is degenerate
0055   [[nodiscard]] Standard_EXPORT bool IsDegenerated(BRepGraph_EdgeId theEdge);
0056 
0057   //! @brief Test if a single coedge has SameParameter.
0058   //! @param[in] theCoEdge coedge definition identifier
0059   //! @return true if the coedge has SameParameter
0060   [[nodiscard]] Standard_EXPORT bool SameParameter(BRepGraph_CoEdgeId theCoEdge);
0061 
0062   //! @brief Test if a single coedge has SameRange.
0063   //! @param[in] theCoEdge coedge definition identifier
0064   //! @return true if the coedge has SameRange
0065   [[nodiscard]] Standard_EXPORT bool SameRange(BRepGraph_CoEdgeId theCoEdge);
0066 
0067   //! @brief Test if an edge is closed (start vertex == end vertex).
0068   //! Computes and caches only IsClosed.
0069   //! @param[in] theEdge edge definition identifier
0070   //! @return true if the edge is closed
0071   [[nodiscard]] Standard_EXPORT bool IsClosed(BRepGraph_EdgeId theEdge);
0072 
0073   //! @brief Return wire closure, computing and storing a fresh entry.
0074   //! @param[in]  theWire   wire definition identifier
0075   //! @param[out] theClosed filled with the fresh derived value
0076   //! @return true if computation succeeded
0077   [[nodiscard]] Standard_EXPORT bool GetWireIsClosed(BRepGraph_WireId theWire, bool& theClosed);
0078 
0079   //! @brief Store a pre-computed wire closure value.
0080   //! @param[in] theWire   wire definition identifier
0081   //! @param[in] theClosed pre-computed closure value
0082   Standard_EXPORT void SetWireIsClosed(BRepGraph_WireId theWire, bool theClosed);
0083 
0084   //! @brief Test if a shell is closed.
0085   //! @param[in] theShell shell definition identifier
0086   //! @return true if the shell is closed
0087   [[nodiscard]] Standard_EXPORT bool IsShellClosed(BRepGraph_ShellId theShell);
0088 
0089   //! Compute edge-own derived state (Status, IsClosed).
0090   //! SameRange/SameParameter are per-CoEdge - use the per-CoEdge cache directly.
0091   //! @param[in]  theGraph source graph
0092   //! @param[in]  theEdge  edge definition identifier
0093   //! @param[out] theIsDegenerated true if edge is degenerate
0094   //! @param[out] theIsClosed      true if edge is closed
0095   //! @return true if computation succeeded
0096   [[nodiscard]] Standard_EXPORT static bool ComputeEdgeProperties(const BRepGraph& theGraph,
0097                                                                   BRepGraph_EdgeId theEdge,
0098                                                                   bool&            theIsDegenerated,
0099                                                                   bool&            theIsClosed);
0100 
0101   //! Compute shell closure directly from a BRepGraph without caching.
0102   //! @param[in] theGraph source graph
0103   //! @param[in] theShell shell definition identifier
0104   //! @return true if the shell is closed
0105   [[nodiscard]] Standard_EXPORT static bool ComputeShellIsClosed(const BRepGraph&  theGraph,
0106                                                                  BRepGraph_ShellId theShell);
0107 
0108   //! Compute wire closure directly from a BRepGraph without caching.
0109   //! @param[in] theGraph source graph
0110   //! @param[in] theWire  wire definition identifier
0111   //! @return true if the wire is closed
0112   [[nodiscard]] Standard_EXPORT static bool ComputeWireIsClosed(const BRepGraph& theGraph,
0113                                                                 BRepGraph_WireId theWire);
0114 
0115   DEFINE_STANDARD_RTTIEXT(BRepGraph_CacheDerivedState, BRepGraph_Cache)
0116 
0117 private:
0118   //! Edge-own derived state: Status (HasCurve3D/Degenerate/Missing), IsClosed.
0119   //! Depends only on Edge OwnGen (vertices, 3D curve).
0120   //! Packed into a single atomic byte for lock-free reads.
0121   struct EdgeEntry : public NodeEntry
0122   {
0123     enum class GeomStatus : uint8_t
0124     {
0125       HasCurve3D,
0126       DegenerateOnSurface,
0127       MissingCurve3D,
0128       Invalid
0129     };
0130 
0131     enum Flags : uint8_t
0132     {
0133       FlagNone     = 0,
0134       StatusMask   = 0x07,
0135       FlagClosed   = 1 << 3,
0136       FlagComputed = 1 << 4,
0137     };
0138 
0139     std::atomic<uint8_t> Packed{FlagNone};
0140 
0141     EdgeEntry() = default;
0142 
0143     EdgeEntry(const EdgeEntry& theOther)
0144         : NodeEntry(theOther),
0145           Packed(theOther.Packed.load(std::memory_order_relaxed))
0146     {
0147     }
0148 
0149     EdgeEntry& operator=(const EdgeEntry& theOther)
0150     {
0151       NodeEntry::operator=(theOther);
0152       Packed.store(theOther.Packed.load(std::memory_order_relaxed), std::memory_order_relaxed);
0153       return *this;
0154     }
0155 
0156     [[nodiscard]] GeomStatus GetStatus() const
0157     {
0158       return static_cast<GeomStatus>(Packed.load(std::memory_order_acquire) & StatusMask);
0159     }
0160 
0161     [[nodiscard]] bool IsClosed() const
0162     {
0163       return (Packed.load(std::memory_order_acquire) & FlagClosed) != 0;
0164     }
0165 
0166     [[nodiscard]] bool IsComputed() const
0167     {
0168       return (Packed.load(std::memory_order_acquire) & FlagComputed) != 0;
0169     }
0170 
0171     void Set(GeomStatus theStatus, bool theClosed)
0172     {
0173       uint8_t aFlags = FlagComputed | static_cast<uint8_t>(theStatus);
0174       if (theClosed)
0175       {
0176         aFlags |= FlagClosed;
0177       }
0178       Packed.store(aFlags, std::memory_order_release);
0179     }
0180   };
0181 
0182   //! Per-CoEdge entry for SameRange/SameParameter.
0183   //! Bound to CoEdge OwnGen - invalidates automatically when PCurve changes.
0184   //! Packed into a single atomic byte for lock-free reads.
0185   struct CoEdgeSameRangeEntry : public NodeEntry
0186   {
0187     enum Flags : uint8_t
0188     {
0189       FlagNone          = 0,
0190       ComputedSameRange = 1 << 0,
0191       ComputedSameParam = 1 << 1,
0192       FlagSameRange     = 1 << 2,
0193       FlagSameParameter = 1 << 3,
0194     };
0195 
0196     std::atomic<uint8_t> Packed{FlagNone};
0197 
0198     CoEdgeSameRangeEntry() = default;
0199 
0200     CoEdgeSameRangeEntry(const CoEdgeSameRangeEntry& theOther)
0201         : NodeEntry(theOther),
0202           Packed(theOther.Packed.load(std::memory_order_relaxed))
0203     {
0204     }
0205 
0206     CoEdgeSameRangeEntry& operator=(const CoEdgeSameRangeEntry& theOther)
0207     {
0208       NodeEntry::operator=(theOther);
0209       Packed.store(theOther.Packed.load(std::memory_order_relaxed), std::memory_order_relaxed);
0210       return *this;
0211     }
0212 
0213     [[nodiscard]] bool SameRange() const
0214     {
0215       return (Packed.load(std::memory_order_acquire) & FlagSameRange) != 0;
0216     }
0217 
0218     [[nodiscard]] bool SameParameter() const
0219     {
0220       return (Packed.load(std::memory_order_acquire) & FlagSameParameter) != 0;
0221     }
0222 
0223     [[nodiscard]] uint8_t Computed() const { return Packed.load(std::memory_order_acquire); }
0224 
0225     void SetSameRange(bool theVal)
0226     {
0227       uint8_t aFlags = ComputedSameRange;
0228       if (theVal)
0229       {
0230         aFlags |= FlagSameRange;
0231       }
0232       Packed.fetch_or(aFlags, std::memory_order_release);
0233     }
0234 
0235     void SetSameParameter(bool theVal)
0236     {
0237       uint8_t aFlags = ComputedSameParam;
0238       if (theVal)
0239       {
0240         aFlags |= FlagSameParameter;
0241       }
0242       Packed.fetch_or(aFlags, std::memory_order_release);
0243     }
0244   };
0245 
0246   struct WireEntry : public NodeEntry
0247   {
0248     enum Flags : uint8_t
0249     {
0250       FlagNone     = 0,
0251       FlagClosed   = 1 << 0,
0252       FlagComputed = 1 << 1,
0253     };
0254 
0255     std::atomic<uint8_t> Packed{FlagNone};
0256 
0257     WireEntry() = default;
0258 
0259     WireEntry(const WireEntry& theOther)
0260         : NodeEntry(theOther),
0261           Packed(theOther.Packed.load(std::memory_order_relaxed))
0262     {
0263     }
0264 
0265     WireEntry& operator=(const WireEntry& theOther)
0266     {
0267       NodeEntry::operator=(theOther);
0268       Packed.store(theOther.Packed.load(std::memory_order_relaxed), std::memory_order_relaxed);
0269       return *this;
0270     }
0271 
0272     [[nodiscard]] bool IsClosed() const
0273     {
0274       return (Packed.load(std::memory_order_acquire) & FlagClosed) != 0;
0275     }
0276 
0277     [[nodiscard]] bool IsComputed() const
0278     {
0279       return (Packed.load(std::memory_order_acquire) & FlagComputed) != 0;
0280     }
0281 
0282     void SetClosed(bool theVal)
0283     {
0284       uint8_t aFlags = FlagComputed;
0285       if (theVal)
0286       {
0287         aFlags |= FlagClosed;
0288       }
0289       Packed.store(aFlags, std::memory_order_release);
0290     }
0291   };
0292 
0293   struct ShellEntry : public NodeEntry
0294   {
0295     enum class ClosureStatus : uint8_t
0296     {
0297       Empty,
0298       Open,
0299       Closed,
0300       NonManifold,
0301       Invalid
0302     };
0303 
0304     std::atomic<ClosureStatus> Status{ClosureStatus::Invalid};
0305 
0306     ShellEntry() = default;
0307 
0308     ShellEntry(const ShellEntry& theOther)
0309         : NodeEntry(theOther),
0310           Status(theOther.Status.load(std::memory_order_relaxed))
0311     {
0312     }
0313 
0314     ShellEntry& operator=(const ShellEntry& theOther)
0315     {
0316       NodeEntry::operator=(theOther);
0317       Status.store(theOther.Status.load(std::memory_order_relaxed), std::memory_order_relaxed);
0318       return *this;
0319     }
0320   };
0321 
0322   //! Ensure edge-own entry (Status, IsClosed) is fresh. Uses OwnGen only.
0323   bool ensureEdgeEntry(BRepGraph_EdgeId theEdge, EdgeEntry& theEntry);
0324 
0325   //! Ensure per-CoEdge entry is fresh. Bound to CoEdge OwnGen.
0326   bool ensureCoEdgeSameRangeEntry(BRepGraph_CoEdgeId    theCoEdge,
0327                                   uint8_t               theRequiredFlags,
0328                                   CoEdgeSameRangeEntry& theEntry);
0329 
0330   static void computeStatusOnly(const BRepGraph& theGraph,
0331                                 BRepGraph_EdgeId theEdge,
0332                                 EdgeEntry&       theEntry);
0333 
0334   static void computeSameRange(const BRepGraph&      theGraph,
0335                                BRepGraph_CoEdgeId    theCoEdge,
0336                                CoEdgeSameRangeEntry& theEntry);
0337 
0338   static void computeSameParameter(const BRepGraph&      theGraph,
0339                                    BRepGraph_CoEdgeId    theCoEdge,
0340                                    CoEdgeSameRangeEntry& theEntry);
0341 
0342   static ShellEntry::ClosureStatus computeShellClosure(const BRepGraph&  theGraph,
0343                                                        BRepGraph_ShellId theShell);
0344 
0345   mutable std::mutex myMutex;
0346 
0347   NCollection_DynamicArray<EdgeEntry>            myEdgeEntries;
0348   NCollection_DynamicArray<CoEdgeSameRangeEntry> myCoEdgeSameRangeEntries;
0349   NCollection_DynamicArray<WireEntry>            myWireEntries;
0350   NCollection_DynamicArray<ShellEntry>           myShellEntries;
0351 };
0352 
0353 #endif // _BRepGraph_CacheDerivedState_HeaderFile