From 13d6dfc2e7604c1c19b464daa91b5ba67016441e Mon Sep 17 00:00:00 2001 From: Pasukhin Dmitry Date: Sun, 15 Feb 2026 09:26:56 +0000 Subject: [PATCH] Modeling Data - Integrate EvalRep descriptors and dispatch for Geom/Geom2d (#1089) Introduce EvalRep descriptors for selected Geom and Geom2d curve/surface classes and add inline EvalRep utilities for evaluation dispatch with fallback to native paths. - add per-class Set/Get/Clear EvalRepresentation API and storage - support full, derivative-bounded and mapped descriptors - validate mapped parameter transforms in SetEvalRepresentation() - migrate Geom_OffsetSurface equivalent-surface path to EvalRep - clone EvalRep descriptors in copy constructors and Copy() paths - update adaptors to use EvalRep in supported branches - keep EvalRep invalidation in geometry mutators and fix regressions --- src/ModelingData/TKG2d/Geom2d/FILES.cmake | 2 + .../TKG2d/Geom2d/Geom2d_BSplineCurve.cxx | 13 + .../TKG2d/Geom2d/Geom2d_BSplineCurve.hxx | 44 +- .../TKG2d/Geom2d/Geom2d_BSplineCurve_1.cxx | 38 + .../TKG2d/Geom2d/Geom2d_BezierCurve.cxx | 51 + .../TKG2d/Geom2d/Geom2d_BezierCurve.hxx | 32 +- .../TKG2d/Geom2d/Geom2d_EvalRepCurveDesc.hxx | 116 +++ .../TKG2d/Geom2d/Geom2d_EvalRepUtils.pxx | 417 ++++++++ .../TKG2d/Geom2d/Geom2d_OffsetCurve.cxx | 55 +- .../TKG2d/Geom2d/Geom2d_OffsetCurve.hxx | 26 +- .../Geom2dAdaptor/Geom2dAdaptor_Curve.cxx | 99 +- .../Geom2dAdaptor/Geom2dAdaptor_Curve.hxx | 19 +- src/ModelingData/TKG3d/Geom/FILES.cmake | 3 + .../TKG3d/Geom/Geom_BSplineCurve.cxx | 34 + .../TKG3d/Geom/Geom_BSplineCurve.hxx | 44 +- .../TKG3d/Geom/Geom_BSplineCurve_1.cxx | 38 + .../TKG3d/Geom/Geom_BSplineSurface.cxx | 26 + .../TKG3d/Geom/Geom_BSplineSurface.hxx | 62 +- .../TKG3d/Geom/Geom_BSplineSurface_1.cxx | 66 +- .../TKG3d/Geom/Geom_BezierCurve.cxx | 50 + .../TKG3d/Geom/Geom_BezierCurve.hxx | 32 +- .../TKG3d/Geom/Geom_BezierSurface.cxx | 52 + .../TKG3d/Geom/Geom_BezierSurface.hxx | 34 +- .../TKG3d/Geom/Geom_EvalRepCurveDesc.hxx | 117 +++ .../TKG3d/Geom/Geom_EvalRepSurfaceDesc.hxx | 143 +++ .../TKG3d/Geom/Geom_EvalRepUtils.pxx | 900 ++++++++++++++++++ .../TKG3d/Geom/Geom_OffsetCurve.cxx | 52 + .../TKG3d/Geom/Geom_OffsetCurve.hxx | 28 +- .../TKG3d/Geom/Geom_OffsetSurface.cxx | 115 ++- .../TKG3d/Geom/Geom_OffsetSurface.hxx | 29 +- .../Geom/Geom_SurfaceOfLinearExtrusion.cxx | 68 +- .../Geom/Geom_SurfaceOfLinearExtrusion.hxx | 22 + .../TKG3d/Geom/Geom_SurfaceOfRevolution.cxx | 59 +- .../TKG3d/Geom/Geom_SurfaceOfRevolution.hxx | 22 +- .../TKG3d/GeomAdaptor/GeomAdaptor_Curve.cxx | 99 +- .../TKG3d/GeomAdaptor/GeomAdaptor_Curve.hxx | 22 +- .../TKG3d/GeomAdaptor/GeomAdaptor_Surface.cxx | 141 ++- .../TKG3d/GeomAdaptor/GeomAdaptor_Surface.hxx | 26 +- 38 files changed, 3046 insertions(+), 150 deletions(-) create mode 100644 src/ModelingData/TKG2d/Geom2d/Geom2d_EvalRepCurveDesc.hxx create mode 100644 src/ModelingData/TKG2d/Geom2d/Geom2d_EvalRepUtils.pxx create mode 100644 src/ModelingData/TKG3d/Geom/Geom_EvalRepCurveDesc.hxx create mode 100644 src/ModelingData/TKG3d/Geom/Geom_EvalRepSurfaceDesc.hxx create mode 100644 src/ModelingData/TKG3d/Geom/Geom_EvalRepUtils.pxx diff --git a/src/ModelingData/TKG2d/Geom2d/FILES.cmake b/src/ModelingData/TKG2d/Geom2d/FILES.cmake index c8767be16e..8d1ff18693 100644 --- a/src/ModelingData/TKG2d/Geom2d/FILES.cmake +++ b/src/ModelingData/TKG2d/Geom2d/FILES.cmake @@ -23,6 +23,8 @@ set(OCCT_Geom2d_FILES Geom2d_Direction.hxx Geom2d_Ellipse.cxx Geom2d_Ellipse.hxx + Geom2d_EvalRepCurveDesc.hxx + Geom2d_EvalRepUtils.pxx Geom2d_Geometry.cxx Geom2d_Geometry.hxx Geom2d_Hyperbola.cxx diff --git a/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve.cxx b/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve.cxx index 1220fcada5..b61c9b592d 100644 --- a/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve.cxx +++ b/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve.cxx @@ -28,6 +28,8 @@ #include #include +#include "Geom2d_EvalRepCurveDesc.hxx" +#include "Geom2d_EvalRepUtils.pxx" #include #include #include @@ -39,12 +41,22 @@ #include #include #include +#include #include IMPLEMENT_STANDARD_RTTIEXT(Geom2d_BSplineCurve, Geom2d_BoundedCurve) //================================================================================================= +void Geom2d_BSplineCurve::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom2d_EvalRepUtils::ValidateCurveDesc(theDesc, this); + myEvalRep = theDesc; +} + +//================================================================================================= + static void CheckCurveData(const NCollection_Array1& CPoles, const NCollection_Array1& CKnots, const NCollection_Array1& CMults, @@ -102,6 +114,7 @@ Geom2d_BSplineCurve::Geom2d_BSplineCurve(const Geom2d_BSplineCurve& theOther) myKnots(theOther.myKnots), myFlatKnots(theOther.myFlatKnots), myMults(theOther.myMults), + myEvalRep(Geom2d_EvalRepUtils::CloneCurveDesc(theOther.myEvalRep)), myDeg(theOther.myDeg), myPeriodic(theOther.myPeriodic), myRational(theOther.myRational), diff --git a/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve.hxx b/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve.hxx index 54d4db8bfd..06fc3ca917 100644 --- a/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve.hxx +++ b/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve.hxx @@ -29,6 +29,11 @@ class gp_Trsf2d; class Geom2d_Geometry; +namespace Geom2d_EvalRepCurveDesc +{ +class Base; +} + //! Describes a BSpline curve. //! A BSpline curve can be: //! - uniform or non-uniform, @@ -189,6 +194,20 @@ public: //! Copy constructor for optimized copying without validation. Standard_EXPORT Geom2d_BSplineCurve(const Geom2d_BSplineCurve& theOther); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Increases the degree of this BSpline curve to //! Degree. As a result, the poles, weights and //! multiplicities tables are modified; the knots table is @@ -848,18 +867,19 @@ protected: void updateKnots(); private: - NCollection_Array1 myPoles; - NCollection_Array1 myWeights; - NCollection_Array1 myKnots; - NCollection_Array1 myFlatKnots; - NCollection_Array1 myMults; - int myDeg = 0; - bool myPeriodic = false; - bool myRational = false; - GeomAbs_BSplKnotDistribution myKnotSet = GeomAbs_NonUniform; - GeomAbs_Shape mySmooth = GeomAbs_C0; - double myMaxDerivInv = 0.0; - bool myMaxDerivInvOk = false; + NCollection_Array1 myPoles; + NCollection_Array1 myWeights; + NCollection_Array1 myKnots; + NCollection_Array1 myFlatKnots; + NCollection_Array1 myMults; + occ::handle myEvalRep; + int myDeg = 0; + bool myPeriodic = false; + bool myRational = false; + GeomAbs_BSplKnotDistribution myKnotSet = GeomAbs_NonUniform; + GeomAbs_Shape mySmooth = GeomAbs_C0; + double myMaxDerivInv = 0.0; + bool myMaxDerivInvOk = false; }; #endif // _Geom2d_BSplineCurve_HeaderFile diff --git a/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve_1.cxx b/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve_1.cxx index 96e17cef4e..0c0e0def73 100644 --- a/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve_1.cxx +++ b/src/ModelingData/TKG2d/Geom2d/Geom2d_BSplineCurve_1.cxx @@ -16,6 +16,8 @@ #include #include +#include "Geom2d_EvalRepCurveDesc.hxx" +#include "Geom2d_EvalRepUtils.pxx" #include #include #include @@ -160,6 +162,13 @@ int Geom2d_BSplineCurve::Degree() const std::optional Geom2d_BSplineCurve::EvalD0(const double U) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD0(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Pnt2d P; int aSpanIndex = 0; double aNewU(U); @@ -176,6 +185,13 @@ std::optional Geom2d_BSplineCurve::EvalD0(const double U) const std::optional Geom2d_BSplineCurve::EvalD1(const double U) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD1(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; int aSpanIndex = 0; double aNewU(U); @@ -201,6 +217,13 @@ std::optional Geom2d_BSplineCurve::EvalD1(const double U) c std::optional Geom2d_BSplineCurve::EvalD2(const double U) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD2(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; int aSpanIndex = 0; double aNewU(U); @@ -227,6 +250,13 @@ std::optional Geom2d_BSplineCurve::EvalD2(const double U) c std::optional Geom2d_BSplineCurve::EvalD3(const double U) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD3(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; int aSpanIndex = 0; double aNewU(U); @@ -256,6 +286,14 @@ std::optional Geom2d_BSplineCurve::EvalDN(const double U, const int N) { if (N < 1) return std::nullopt; + + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveDN(myEvalRep, U, N); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Vec2d V; BSplCLib::DN(U, N, 0, myDeg, myPeriodic, myPoles, Weights(), myFlatKnots, BSplCLib::NoMults(), V); return V; diff --git a/src/ModelingData/TKG2d/Geom2d/Geom2d_BezierCurve.cxx b/src/ModelingData/TKG2d/Geom2d/Geom2d_BezierCurve.cxx index ada6cde609..8a441912c3 100644 --- a/src/ModelingData/TKG2d/Geom2d/Geom2d_BezierCurve.cxx +++ b/src/ModelingData/TKG2d/Geom2d/Geom2d_BezierCurve.cxx @@ -24,6 +24,8 @@ // Suppressed Swaps, added Init, removed typedefs #include +#include "Geom2d_EvalRepCurveDesc.hxx" +#include "Geom2d_EvalRepUtils.pxx" #include #include #include @@ -33,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +46,15 @@ IMPLEMENT_STANDARD_RTTIEXT(Geom2d_BezierCurve, Geom2d_BoundedCurve) //================================================================================================= +void Geom2d_BezierCurve::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom2d_EvalRepUtils::ValidateCurveDesc(theDesc, this); + myEvalRep = theDesc; +} + +//================================================================================================= + static bool Rational(const NCollection_Array1& W) { int i, n = W.Length(); @@ -105,6 +117,7 @@ Geom2d_BezierCurve::Geom2d_BezierCurve(const Geom2d_BezierCurve& theOther) : myPoles(theOther.myPoles), myWeights(theOther.myRational ? NCollection_Array1(theOther.myWeights) : BSplCLib::UnitWeights(theOther.myPoles.Length())), + myEvalRep(Geom2d_EvalRepUtils::CloneCurveDesc(theOther.myEvalRep)), myRational(theOther.myRational), myClosed(theOther.myClosed), myMaxDerivInvOk(false) @@ -446,6 +459,13 @@ int Geom2d_BezierCurve::Degree() const std::optional Geom2d_BezierCurve::EvalD0(const double U) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD0(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Pnt2d P; BSplCLib::D0(U, Poles(), Weights(), P); return P; @@ -455,6 +475,13 @@ std::optional Geom2d_BezierCurve::EvalD0(const double U) const std::optional Geom2d_BezierCurve::EvalD1(const double U) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD1(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; BSplCLib::D1(U, Poles(), Weights(), aResult->Point, aResult->D1); return aResult; @@ -464,6 +491,13 @@ std::optional Geom2d_BezierCurve::EvalD1(const double U) co std::optional Geom2d_BezierCurve::EvalD2(const double U) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD2(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; BSplCLib::D2(U, Poles(), Weights(), aResult->Point, aResult->D1, aResult->D2); return aResult; @@ -473,6 +507,13 @@ std::optional Geom2d_BezierCurve::EvalD2(const double U) co std::optional Geom2d_BezierCurve::EvalD3(const double U) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD3(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; BSplCLib::D3(U, Poles(), Weights(), aResult->Point, aResult->D1, aResult->D2, aResult->D3); return aResult; @@ -484,6 +525,14 @@ std::optional Geom2d_BezierCurve::EvalDN(const double U, const int N) { if (N < 1) return std::nullopt; + + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveDN(myEvalRep, U, N); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Vec2d V; BSplCLib::DN(U, N, 0, Degree(), false, myPoles, Weights(), Knots(), &Multiplicities(), V); @@ -576,6 +625,7 @@ void Geom2d_BezierCurve::Transform(const gp_Trsf2d& T) for (int i = 1; i <= nbpoles; i++) myPoles(i).Transform(T); + ClearEvalRepresentation(); myMaxDerivInvOk = false; } @@ -635,6 +685,7 @@ void Geom2d_BezierCurve::init(const NCollection_Array1& thePoles, myMaxDerivInv = 0.0; myMaxDerivInvOk = false; + ClearEvalRepresentation(); } //================================================================================================= diff --git a/src/ModelingData/TKG2d/Geom2d/Geom2d_BezierCurve.hxx b/src/ModelingData/TKG2d/Geom2d/Geom2d_BezierCurve.hxx index 01ce00b7e7..9b08469601 100644 --- a/src/ModelingData/TKG2d/Geom2d/Geom2d_BezierCurve.hxx +++ b/src/ModelingData/TKG2d/Geom2d/Geom2d_BezierCurve.hxx @@ -28,6 +28,11 @@ class gp_Trsf2d; class Geom2d_Geometry; +namespace Geom2d_EvalRepCurveDesc +{ +class Base; +} + //! Describes a rational or non-rational Bezier curve //! - a non-rational Bezier curve is defined by a table //! of poles (also called control points), @@ -104,6 +109,20 @@ public: //! Copy constructor for optimized copying without validation. Standard_EXPORT Geom2d_BezierCurve(const Geom2d_BezierCurve& theOther); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Increases the degree of a bezier curve. Degree is the new //! degree of . //! raises ConstructionError if Degree is greater than MaxDegree or lower than 2 @@ -321,12 +340,13 @@ protected: const NCollection_Array1* theWeights); private: - NCollection_Array1 myPoles; - NCollection_Array1 myWeights; - bool myRational = false; - bool myClosed = false; - double myMaxDerivInv = 0.0; - bool myMaxDerivInvOk = false; + NCollection_Array1 myPoles; + NCollection_Array1 myWeights; + occ::handle myEvalRep; + bool myRational = false; + bool myClosed = false; + double myMaxDerivInv = 0.0; + bool myMaxDerivInvOk = false; }; #endif // _Geom2d_BezierCurve_HeaderFile diff --git a/src/ModelingData/TKG2d/Geom2d/Geom2d_EvalRepCurveDesc.hxx b/src/ModelingData/TKG2d/Geom2d/Geom2d_EvalRepCurveDesc.hxx new file mode 100644 index 0000000000..9b07cfad0b --- /dev/null +++ b/src/ModelingData/TKG2d/Geom2d/Geom2d_EvalRepCurveDesc.hxx @@ -0,0 +1,116 @@ +// Copyright (c) 2025 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Geom2d_EvalRepCurveDesc_HeaderFile +#define _Geom2d_EvalRepCurveDesc_HeaderFile + +#include +#include +#include + +#include +#include +#include + +namespace Geom2d_EvalRepCurveDesc +{ +//! 1D affine parameter map: uRep = Scale * u + Offset. +struct Map1d +{ + double Scale = 1.0; + double Offset = 0.0; + + bool IsIdentity() const + { + return std::abs(Scale - 1.0) < Precision::Confusion() + && std::abs(Offset) < Precision::Confusion(); + } + + bool IsValid() const { return std::abs(Scale) > Precision::Confusion(); } + + double Map(const double theU) const { return Scale * theU + Offset; } +}; + +//! 1D parameter domain interval. +struct Domain1d +{ + double First = 0.0; + double Last = 1.0; + + bool Contains(const double theU) const + { + return (theU >= First - Precision::Confusion()) && (theU <= Last + Precision::Confusion()); + } +}; + +//! Abstract base descriptor for 2D curve evaluation representation. +//! Holds the representation handle and a Kind tag for switch-based dispatch. +class Base : public Standard_Transient +{ +public: + //! Descriptor kind for switch-based dispatch (no RTTI needed). + enum class Kind + { + Full, //!< fully equivalent, no derivative limit, no domain, no map + DerivBounded, //!< full domain + identity map, limited to MaxDerivOrder + Mapped //!< has MaxDerivOrder + optional Domain + ParamMap + }; + + occ::handle Representation; //!< geometry used for evaluation + + //! Returns the descriptor kind. + virtual Kind GetKind() const = 0; + + DEFINE_STANDARD_RTTI_INLINE(Base, Standard_Transient) + +protected: + Base() = default; +}; + +//! Fully equivalent descriptor: no derivative limit, no domain, no map. +//! Fastest evaluation path - direct delegation to Representation. +class Full : public Base +{ +public: + Kind GetKind() const override { return Kind::Full; } + + DEFINE_STANDARD_RTTI_INLINE(Full, Base) +}; + +//! Derivative-bounded descriptor: full domain, identity map, limited to MaxDerivOrder. +class DerivBounded : public Base +{ +public: + std::size_t MaxDerivOrder = 3; //!< max supported derivative order + + Kind GetKind() const override { return Kind::DerivBounded; } + + DEFINE_STANDARD_RTTI_INLINE(DerivBounded, Base) +}; + +//! Mapped descriptor for 2D curve evaluation representation. +//! Adds optional bounded domain and affine parameter map. +class Mapped : public Base +{ +public: + std::size_t MaxDerivOrder = 3; //!< max supported derivative order + std::optional Domain; //!< nullopt = full domain + Map1d ParamMap; //!< affine parameter transform + + Kind GetKind() const override { return Kind::Mapped; } + + DEFINE_STANDARD_RTTI_INLINE(Mapped, Base) +}; +} // namespace Geom2d_EvalRepCurveDesc + +#endif // _Geom2d_EvalRepCurveDesc_HeaderFile diff --git a/src/ModelingData/TKG2d/Geom2d/Geom2d_EvalRepUtils.pxx b/src/ModelingData/TKG2d/Geom2d/Geom2d_EvalRepUtils.pxx new file mode 100644 index 0000000000..603da36f6f --- /dev/null +++ b/src/ModelingData/TKG2d/Geom2d/Geom2d_EvalRepUtils.pxx @@ -0,0 +1,417 @@ +// Copyright (c) 2025 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Geom2d_EvalRepUtils_HeaderFile +#define _Geom2d_EvalRepUtils_HeaderFile + +#include "Geom2d_EvalRepCurveDesc.hxx" + +#include + +#include + +#include +#include + +namespace Geom2d_EvalRepUtils +{ +occ::handle CloneCurveDesc( + const occ::handle& theDesc); + +std::optional TryEvalCurveD0(const occ::handle& theDesc, + const double theU); +std::optional TryEvalCurveD1( + const occ::handle& theDesc, + const double theU); +std::optional TryEvalCurveD2( + const occ::handle& theDesc, + const double theU); +std::optional TryEvalCurveD3( + const occ::handle& theDesc, + const double theU); +std::optional TryEvalCurveDN(const occ::handle& theDesc, + const double theU, + const int theN); +std::optional TryEvalCurveD0Mapped(const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU); +std::optional TryEvalCurveD1Mapped( + const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU); +std::optional TryEvalCurveD2Mapped( + const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU); +std::optional TryEvalCurveD3Mapped( + const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU); +std::optional TryEvalCurveDNMapped(const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU, + const int theN); +void ValidateCurveDesc(const occ::handle& theDesc, + const Geom2d_Curve* theOwner); +} // namespace Geom2d_EvalRepUtils + +//================================================================================================== + +inline void Geom2d_EvalRepUtils::ValidateCurveDesc( + const occ::handle& theDesc, + const Geom2d_Curve* theOwner) +{ + if (theDesc.IsNull()) + { + return; + } + if (theDesc->Representation.IsNull()) + { + throw Standard_ProgramError("SetEvalRepresentation: null Representation"); + } + if (theDesc->GetKind() == Geom2d_EvalRepCurveDesc::Base::Kind::Mapped) + { + const auto* aMapped = static_cast(theDesc.get()); + if (!aMapped->ParamMap.IsValid()) + { + throw Standard_ProgramError("SetEvalRepresentation: invalid parameter map"); + } + } + // Only direct self-reference is detected here; indirect cycles (A->B->A) are not + // checked because EvalRepresentation() is not available on the Geom2d_Curve base class. + if (theDesc->Representation.get() == theOwner) + { + throw Standard_ProgramError("SetEvalRepresentation: invalid descriptor chain"); + } +} + +//================================================================================================== + +inline occ::handle Geom2d_EvalRepUtils::CloneCurveDesc( + const occ::handle& theDesc) +{ + if (theDesc.IsNull() || theDesc->Representation.IsNull()) + { + return occ::handle(); + } + + const occ::handle aRepCopy = + occ::down_cast(theDesc->Representation->Copy()); + if (aRepCopy.IsNull()) + { + return occ::handle(); + } + + switch (theDesc->GetKind()) + { + case Geom2d_EvalRepCurveDesc::Base::Kind::Full: { + occ::handle aClone = new Geom2d_EvalRepCurveDesc::Full(); + aClone->Representation = aRepCopy; + return aClone; + } + case Geom2d_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aSrc = static_cast(theDesc.get()); + occ::handle aClone = + new Geom2d_EvalRepCurveDesc::DerivBounded(); + aClone->Representation = aRepCopy; + aClone->MaxDerivOrder = aSrc->MaxDerivOrder; + return aClone; + } + case Geom2d_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aSrc = static_cast(theDesc.get()); + occ::handle aClone = new Geom2d_EvalRepCurveDesc::Mapped(); + aClone->Representation = aRepCopy; + aClone->MaxDerivOrder = aSrc->MaxDerivOrder; + aClone->Domain = aSrc->Domain; + aClone->ParamMap = aSrc->ParamMap; + return aClone; + } + } + return occ::handle(); +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveD0( + const occ::handle& theDesc, + const double theU) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom2d_EvalRepCurveDesc::Base::Kind::Full: + case Geom2d_EvalRepCurveDesc::Base::Kind::DerivBounded: + return theDesc->Representation->EvalD0(theU); + case Geom2d_EvalRepCurveDesc::Base::Kind::Mapped: + return TryEvalCurveD0Mapped( + *static_cast(theDesc.get()), + theU); + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveD1( + const occ::handle& theDesc, + const double theU) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom2d_EvalRepCurveDesc::Base::Kind::Full: + return theDesc->Representation->EvalD1(theU); + case Geom2d_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aBounded = + static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < 1) + return std::nullopt; + return theDesc->Representation->EvalD1(theU); + } + case Geom2d_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < 1) + return std::nullopt; + return TryEvalCurveD1Mapped(*aMapped, theU); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveD2( + const occ::handle& theDesc, + const double theU) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom2d_EvalRepCurveDesc::Base::Kind::Full: + return theDesc->Representation->EvalD2(theU); + case Geom2d_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aBounded = + static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < 2) + return std::nullopt; + return theDesc->Representation->EvalD2(theU); + } + case Geom2d_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < 2) + return std::nullopt; + return TryEvalCurveD2Mapped(*aMapped, theU); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveD3( + const occ::handle& theDesc, + const double theU) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom2d_EvalRepCurveDesc::Base::Kind::Full: + return theDesc->Representation->EvalD3(theU); + case Geom2d_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aBounded = + static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < 3) + return std::nullopt; + return theDesc->Representation->EvalD3(theU); + } + case Geom2d_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < 3) + return std::nullopt; + return TryEvalCurveD3Mapped(*aMapped, theU); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveDN( + const occ::handle& theDesc, + const double theU, + const int theN) +{ + if (theDesc.IsNull() || theN < 1) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom2d_EvalRepCurveDesc::Base::Kind::Full: + return theDesc->Representation->EvalDN(theU, theN); + case Geom2d_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aBounded = + static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < static_cast(theN)) + return std::nullopt; + return theDesc->Representation->EvalDN(theU, theN); + } + case Geom2d_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < static_cast(theN)) + return std::nullopt; + return TryEvalCurveDNMapped(*aMapped, theU, theN); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveD0Mapped( + const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + return theDesc.Representation->EvalD0(aURep); +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveD1Mapped( + const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + const std::optional aRepRes = theDesc.Representation->EvalD1(aURep); + if (!aRepRes) + { + return std::nullopt; + } + + const double aScale = theDesc.ParamMap.Scale; + Geom2d_Curve::ResD1 aRes; + aRes.Point = aRepRes->Point; + aRes.D1 = aRepRes->D1 * aScale; + return aRes; +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveD2Mapped( + const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + const std::optional aRepRes = theDesc.Representation->EvalD2(aURep); + if (!aRepRes) + { + return std::nullopt; + } + + const double aScale = theDesc.ParamMap.Scale; + const double aScale2 = aScale * aScale; + + Geom2d_Curve::ResD2 aRes; + aRes.Point = aRepRes->Point; + aRes.D1 = aRepRes->D1 * aScale; + aRes.D2 = aRepRes->D2 * aScale2; + return aRes; +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveD3Mapped( + const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + const std::optional aRepRes = theDesc.Representation->EvalD3(aURep); + if (!aRepRes) + { + return std::nullopt; + } + + const double aScale = theDesc.ParamMap.Scale; + const double aScale2 = aScale * aScale; + const double aScale3 = aScale2 * aScale; + + Geom2d_Curve::ResD3 aRes; + aRes.Point = aRepRes->Point; + aRes.D1 = aRepRes->D1 * aScale; + aRes.D2 = aRepRes->D2 * aScale2; + aRes.D3 = aRepRes->D3 * aScale3; + return aRes; +} + +//================================================================================================== + +inline std::optional Geom2d_EvalRepUtils::TryEvalCurveDNMapped( + const Geom2d_EvalRepCurveDesc::Mapped& theDesc, + const double theU, + const int theN) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + const std::optional aRepVec = theDesc.Representation->EvalDN(aURep, theN); + if (!aRepVec) + { + return std::nullopt; + } + + const double aScaleN = std::pow(theDesc.ParamMap.Scale, theN); + return (*aRepVec) * aScaleN; +} + +#endif // _Geom2d_EvalRepUtils_HeaderFile diff --git a/src/ModelingData/TKG2d/Geom2d/Geom2d_OffsetCurve.cxx b/src/ModelingData/TKG2d/Geom2d/Geom2d_OffsetCurve.cxx index 59876d9afa..5c7ee674a3 100644 --- a/src/ModelingData/TKG2d/Geom2d/Geom2d_OffsetCurve.cxx +++ b/src/ModelingData/TKG2d/Geom2d/Geom2d_OffsetCurve.cxx @@ -19,6 +19,8 @@ #include #include #include +#include "Geom2d_EvalRepCurveDesc.hxx" +#include "Geom2d_EvalRepUtils.pxx" #include #include #include @@ -33,6 +35,7 @@ #include #include #include +#include #include #include @@ -42,6 +45,15 @@ static const double MyAngularToleranceForG1 = Precision::Angular(); //================================================================================================== +void Geom2d_OffsetCurve::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom2d_EvalRepUtils::ValidateCurveDesc(theDesc, this); + myEvalRep = theDesc; +} + +//================================================================================================== + occ::handle Geom2d_OffsetCurve::Copy() const { return new Geom2d_OffsetCurve(*this); @@ -64,17 +76,19 @@ Geom2d_OffsetCurve::Geom2d_OffsetCurve(const occ::handle& theCurve //================================================================================================== Geom2d_OffsetCurve::Geom2d_OffsetCurve(const Geom2d_OffsetCurve& theOther) - : offsetValue(theOther.offsetValue), + : basisCurve(occ::down_cast(theOther.basisCurve->Copy())), + myEvalRep(Geom2d_EvalRepUtils::CloneCurveDesc(theOther.myEvalRep)), + offsetValue(theOther.offsetValue), myBasisCurveContinuity(theOther.myBasisCurveContinuity) { // Deep copy basis curve without validation - basisCurve = occ::down_cast(theOther.basisCurve->Copy()); } //================================================================================================== void Geom2d_OffsetCurve::Reverse() { + ClearEvalRepresentation(); basisCurve->Reverse(); offsetValue = -offsetValue; } @@ -90,6 +104,7 @@ double Geom2d_OffsetCurve::ReversedParameter(const double U) const void Geom2d_OffsetCurve::SetBasisCurve(const occ::handle& C, const bool isNotCheckC0) { + ClearEvalRepresentation(); const double aUf = C->FirstParameter(), aUl = C->LastParameter(); occ::handle aCheckingCurve = C; bool isTrimmed = false; @@ -149,6 +164,7 @@ void Geom2d_OffsetCurve::SetBasisCurve(const occ::handle& C, const void Geom2d_OffsetCurve::SetOffsetValue(const double D) { + ClearEvalRepresentation(); offsetValue = D; } @@ -196,6 +212,13 @@ GeomAbs_Shape Geom2d_OffsetCurve::Continuity() const std::optional Geom2d_OffsetCurve::EvalD0(const double theU) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD0(myEvalRep, theU); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD1 = basisCurve->EvalD1(theU); if (!aBasisD1) return std::nullopt; @@ -209,6 +232,13 @@ std::optional Geom2d_OffsetCurve::EvalD0(const double theU) const std::optional Geom2d_OffsetCurve::EvalD1(const double theU) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD1(myEvalRep, theU); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD2 = basisCurve->EvalD2(theU); if (!aBasisD2) return std::nullopt; @@ -223,6 +253,13 @@ std::optional Geom2d_OffsetCurve::EvalD1(const double theU) std::optional Geom2d_OffsetCurve::EvalD2(const double theU) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD2(myEvalRep, theU); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD3 = basisCurve->EvalD3(theU); if (!aBasisD3) return std::nullopt; @@ -251,6 +288,13 @@ std::optional Geom2d_OffsetCurve::EvalD2(const double theU) std::optional Geom2d_OffsetCurve::EvalD3(const double theU) const { + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveD3(myEvalRep, theU); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD3 = basisCurve->EvalD3(theU); if (!aBasisD3) return std::nullopt; @@ -290,6 +334,12 @@ std::optional Geom2d_OffsetCurve::EvalDN(const double U, const int N) { if (N < 1) return std::nullopt; + if (const std::optional aEvalRepResult = + Geom2d_EvalRepUtils::TryEvalCurveDN(myEvalRep, U, N); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } switch (N) { case 1: { @@ -366,6 +416,7 @@ double Geom2d_OffsetCurve::Period() const void Geom2d_OffsetCurve::Transform(const gp_Trsf2d& T) { + ClearEvalRepresentation(); basisCurve->Transform(T); offsetValue *= std::abs(T.ScaleFactor()); } diff --git a/src/ModelingData/TKG2d/Geom2d/Geom2d_OffsetCurve.hxx b/src/ModelingData/TKG2d/Geom2d/Geom2d_OffsetCurve.hxx index 2ef67e584e..8c71791181 100644 --- a/src/ModelingData/TKG2d/Geom2d/Geom2d_OffsetCurve.hxx +++ b/src/ModelingData/TKG2d/Geom2d/Geom2d_OffsetCurve.hxx @@ -26,6 +26,11 @@ class gp_Trsf2d; class Geom2d_Geometry; +namespace Geom2d_EvalRepCurveDesc +{ +class Base; +} + //! This class implements the basis services for the creation, //! edition, modification and evaluation of planar offset curve. //! The offset curve is obtained by offsetting by distance along @@ -94,6 +99,20 @@ public: //! Copy constructor for optimized copying without validation. Standard_EXPORT Geom2d_OffsetCurve(const Geom2d_OffsetCurve& theOther); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Changes the direction of parametrization of . //! As a result: //! - the basis curve is reversed, @@ -275,9 +294,10 @@ public: DEFINE_STANDARD_RTTIEXT(Geom2d_OffsetCurve, Geom2d_Curve) private: - occ::handle basisCurve; - double offsetValue; - GeomAbs_Shape myBasisCurveContinuity; + occ::handle basisCurve; + occ::handle myEvalRep; + double offsetValue; + GeomAbs_Shape myBasisCurveContinuity; }; #endif // _Geom2d_OffsetCurve_HeaderFile diff --git a/src/ModelingData/TKG2d/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx b/src/ModelingData/TKG2d/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx index 49dd08d724..276ac4b1bf 100644 --- a/src/ModelingData/TKG2d/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx +++ b/src/ModelingData/TKG2d/Geom2dAdaptor/Geom2dAdaptor_Curve.cxx @@ -61,6 +61,29 @@ static const double PosTol = Precision::PConfusion() / 2; IMPLEMENT_STANDARD_RTTIEXT(Geom2dAdaptor_Curve, Adaptor2d_Curve2d) +namespace +{ +bool hasEvalRep(const Geom2dAdaptor_Curve::CurveDataVariant& theData) +{ + if (const Geom2dAdaptor_Curve::BezierData* aBezierData = + std::get_if(&theData)) + { + return !aBezierData->EvalRep.IsNull(); + } + if (const Geom2dAdaptor_Curve::BSplineData* aBSplineData = + std::get_if(&theData)) + { + return !aBSplineData->EvalRep.IsNull(); + } + if (const Geom2dAdaptor_Curve::OffsetData* anOffsetData = + std::get_if(&theData)) + { + return !anOffsetData->EvalRep.IsNull(); + } + return false; +} +} // namespace + //================================================================================================= occ::handle Geom2dAdaptor_Curve::ShallowCopy() const @@ -82,17 +105,24 @@ occ::handle Geom2dAdaptor_Curve::ShallowCopy() const occ::down_cast(anOffsetData->BasisAdaptor->ShallowCopy()); } aNewData.Offset = anOffsetData->Offset; + aNewData.EvalRep = anOffsetData->EvalRep; aCopy->myCurveData = std::move(aNewData); } else if (const auto* aBSplineData = std::get_if(&myCurveData)) { BSplineData aNewData; aNewData.Curve = aBSplineData->Curve; + aNewData.EvalRep = aBSplineData->EvalRep; aCopy->myCurveData = std::move(aNewData); } else if (std::holds_alternative(myCurveData)) { - aCopy->myCurveData = BezierData{}; + const BezierData& aBezierData = std::get(myCurveData); + BezierData aNewData; + aNewData.Curve = aBezierData.Curve; + aNewData.EvalRep = aBezierData.EvalRep; + // Cache is not copied - will be rebuilt on demand. + aCopy->myCurveData = std::move(aNewData); } else { @@ -276,14 +306,18 @@ void Geom2dAdaptor_Curve::load(const occ::handle& C, else if (TheType == STANDARD_TYPE(Geom2d_BezierCurve)) { myTypeCurve = GeomAbs_BezierCurve; - myCurveData = BezierData{}; + BezierData aBezierData; + aBezierData.Curve = occ::down_cast(myCurve); + aBezierData.EvalRep = aBezierData.Curve->EvalRepresentation(); + myCurveData = std::move(aBezierData); } else if (TheType == STANDARD_TYPE(Geom2d_BSplineCurve)) { myTypeCurve = GeomAbs_BSplineCurve; BSplineData aBSplineData; - aBSplineData.Curve = occ::down_cast(myCurve); - myCurveData = std::move(aBSplineData); + aBSplineData.Curve = occ::down_cast(myCurve); + aBSplineData.EvalRep = aBSplineData.Curve->EvalRepresentation(); + myCurveData = std::move(aBSplineData); } else if (TheType == STANDARD_TYPE(Geom2d_OffsetCurve)) { @@ -295,6 +329,7 @@ void Geom2dAdaptor_Curve::load(const occ::handle& C, OffsetData anOffsetData; anOffsetData.BasisAdaptor = new Geom2dAdaptor_Curve(aBaseCurve, UFirst, ULast); anOffsetData.Offset = anOffsetCurve->Offset(); + anOffsetData.EvalRep = anOffsetCurve->EvalRepresentation(); myCurveData = std::move(anOffsetData); } else @@ -682,6 +717,10 @@ std::optional Geom2dAdaptor_Curve::EvalD0(double U) const return P; case GeomAbs_BezierCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD0(U); + } auto& aBezierData = std::get(myCurveData); if (aBezierData.Cache.IsNull()) RebuildCache(U); @@ -690,6 +729,10 @@ std::optional Geom2dAdaptor_Curve::EvalD0(double U) const } case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD0(U); + } int aStart = 0, aFinish = 0; const BSplineData& aBSplineData = std::get(myCurveData); if (IsBoundary(U, aStart, aFinish)) @@ -706,6 +749,10 @@ std::optional Geom2dAdaptor_Curve::EvalD0(double U) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD0(U); + } const auto& anOffsetData = std::get(myCurveData); if (!Geom2d_OffsetCurveUtils::EvaluateD0(U, anOffsetData.BasisAdaptor.get(), @@ -761,6 +808,10 @@ std::optional Geom2dAdaptor_Curve::EvalD1(double U) const return aResult; case GeomAbs_BezierCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD1(U); + } auto& aBezierData = std::get(myCurveData); if (aBezierData.Cache.IsNull()) RebuildCache(U); @@ -769,6 +820,10 @@ std::optional Geom2dAdaptor_Curve::EvalD1(double U) const } case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD1(U); + } int aStart = 0, aFinish = 0; const BSplineData& aBSplineData = std::get(myCurveData); if (IsBoundary(U, aStart, aFinish)) @@ -785,6 +840,10 @@ std::optional Geom2dAdaptor_Curve::EvalD1(double U) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD1(U); + } const auto& anOffsetData = std::get(myCurveData); if (!Geom2d_OffsetCurveUtils::EvaluateD1(U, anOffsetData.BasisAdaptor.get(), @@ -843,6 +902,10 @@ std::optional Geom2dAdaptor_Curve::EvalD2(double U) const return aResult; case GeomAbs_BezierCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD2(U); + } auto& aBezierData = std::get(myCurveData); if (aBezierData.Cache.IsNull()) RebuildCache(U); @@ -851,6 +914,10 @@ std::optional Geom2dAdaptor_Curve::EvalD2(double U) const } case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD2(U); + } int aStart = 0, aFinish = 0; const BSplineData& aBSplineData = std::get(myCurveData); if (IsBoundary(U, aStart, aFinish)) @@ -867,6 +934,10 @@ std::optional Geom2dAdaptor_Curve::EvalD2(double U) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD2(U); + } const auto& anOffsetData = std::get(myCurveData); if (!Geom2d_OffsetCurveUtils::EvaluateD2(U, anOffsetData.BasisAdaptor.get(), @@ -948,6 +1019,10 @@ std::optional Geom2dAdaptor_Curve::EvalD3(double U) const return aResult; case GeomAbs_BezierCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD3(U); + } auto& aBezierData = std::get(myCurveData); if (aBezierData.Cache.IsNull()) RebuildCache(U); @@ -956,6 +1031,10 @@ std::optional Geom2dAdaptor_Curve::EvalD3(double U) const } case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD3(U); + } int aStart = 0, aFinish = 0; const BSplineData& aBSplineData = std::get(myCurveData); if (IsBoundary(U, aStart, aFinish)) @@ -973,6 +1052,10 @@ std::optional Geom2dAdaptor_Curve::EvalD3(double U) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD3(U); + } const auto& anOffsetData = std::get(myCurveData); if (!Geom2d_OffsetCurveUtils::EvaluateD3(U, anOffsetData.BasisAdaptor.get(), @@ -1027,6 +1110,10 @@ std::optional Geom2dAdaptor_Curve::EvalDN(double U, int N) const return myCurve->EvalDN(U, N); case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalDN(U, N); + } int aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) { @@ -1037,6 +1124,10 @@ std::optional Geom2dAdaptor_Curve::EvalDN(double U, int N) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalDN(U, N); + } const auto& anOffsetData = std::get(myCurveData); gp_Vec2d aDN; if (!Geom2d_OffsetCurveUtils::EvaluateDN(U, diff --git a/src/ModelingData/TKG2d/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx b/src/ModelingData/TKG2d/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx index 80d3d327de..96f9ac89f3 100644 --- a/src/ModelingData/TKG2d/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx +++ b/src/ModelingData/TKG2d/Geom2dAdaptor/Geom2dAdaptor_Curve.hxx @@ -38,6 +38,11 @@ class gp_Vec2d; class Geom2d_BezierCurve; class Geom2d_BSplineCurve; +namespace Geom2d_EvalRepCurveDesc +{ +class Base; +} + //! An interface between the services provided by any //! curve from the package Geom2d and those required //! of the curve by algorithms which use it. @@ -52,21 +57,25 @@ public: //! Internal structure for 2D offset curve evaluation data. struct OffsetData { - occ::handle BasisAdaptor; //!< Adaptor for basis curve - double Offset = 0.0; //!< Offset distance + occ::handle BasisAdaptor; //!< Adaptor for basis curve + double Offset = 0.0; //!< Offset distance + occ::handle EvalRep; //!< Eval representation descriptor }; //! Internal structure for Bezier curve evaluation data. struct BezierData { - mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle Curve; //!< Bezier curve to prevent downcasts + mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle EvalRep; //!< Eval representation descriptor }; //! Internal structure for BSpline curve evaluation data. struct BSplineData { - occ::handle Curve; //!< BSpline curve to prevent downcasts - mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle Curve; //!< BSpline curve to prevent downcasts + mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle EvalRep; //!< Eval representation descriptor }; //! Variant type for 2D curve-specific evaluation data. diff --git a/src/ModelingData/TKG3d/Geom/FILES.cmake b/src/ModelingData/TKG3d/Geom/FILES.cmake index b7dd53210f..0d64554f94 100644 --- a/src/ModelingData/TKG3d/Geom/FILES.cmake +++ b/src/ModelingData/TKG3d/Geom/FILES.cmake @@ -41,6 +41,9 @@ set(OCCT_Geom_FILES Geom_ElementarySurface.hxx Geom_Ellipse.cxx Geom_Ellipse.hxx + Geom_EvalRepCurveDesc.hxx + Geom_EvalRepSurfaceDesc.hxx + Geom_EvalRepUtils.pxx Geom_Geometry.cxx Geom_Geometry.hxx diff --git a/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve.cxx b/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve.cxx index a37766ca9c..8708443d8f 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve.cxx @@ -30,6 +30,8 @@ #include #include #include +#include "Geom_EvalRepCurveDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include #include #include @@ -41,6 +43,7 @@ #include #include #include +#include #include #include @@ -48,6 +51,15 @@ IMPLEMENT_STANDARD_RTTIEXT(Geom_BSplineCurve, Geom_BoundedCurve) //================================================================================================= +void Geom_BSplineCurve::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom_EvalRepUtils::ValidateCurveDesc(theDesc, this); + myEvalRep = theDesc; +} + +//================================================================================================= + static void CheckCurveData(const NCollection_Array1& CPoles, const NCollection_Array1& CKnots, const NCollection_Array1& CMults, @@ -105,6 +117,7 @@ Geom_BSplineCurve::Geom_BSplineCurve(const Geom_BSplineCurve& theOther) myKnots(theOther.myKnots), myFlatKnots(theOther.myFlatKnots), myMults(theOther.myMults), + myEvalRep(Geom_EvalRepUtils::CloneCurveDesc(theOther.myEvalRep)), myDeg(theOther.myDeg), myPeriodic(theOther.myPeriodic), myRational(theOther.myRational), @@ -220,6 +233,8 @@ void Geom_BSplineCurve::IncreaseDegree(const int Degree) if (Degree == myDeg) return; + ClearEvalRepresentation(); + if (Degree < myDeg || Degree > Geom_BSplineCurve::MaxDegree()) { throw Standard_ConstructionError("BSpline curve: IncreaseDegree: bad degree value"); @@ -336,6 +351,8 @@ void Geom_BSplineCurve::InsertKnots(const NCollection_Array1& Knots, if (nbpoles == myPoles.Length()) return; + ClearEvalRepresentation(); + NCollection_Array1 npoles(1, nbpoles); NCollection_Array1 nknots(1, nbknots); NCollection_Array1 nmults(1, nbknots); @@ -423,6 +440,8 @@ bool Geom_BSplineCurve::RemoveKnot(const int Index, const int M, const double To return false; } + ClearEvalRepresentation(); + if (IsRational()) myWeights = std::move(nweights); else @@ -440,6 +459,7 @@ bool Geom_BSplineCurve::RemoveKnot(const int Index, const int M, const double To void Geom_BSplineCurve::Reverse() { + ClearEvalRepresentation(); BSplCLib::Reverse(myKnots); BSplCLib::Reverse(myMults); int last; @@ -467,6 +487,8 @@ void Geom_BSplineCurve::Segment(const double U1, const double U2, const double t if (U2 < U1) throw Standard_DomainError("Geom_BSplineCurve::Segment"); + ClearEvalRepresentation(); + double NewU1, NewU2; double U, DU = 0, aDDU = 0; int index; @@ -660,6 +682,7 @@ void Geom_BSplineCurve::SetKnot(const int Index, const double K) } if (K != myKnots.Value(Index)) { + ClearEvalRepresentation(); myKnots.SetValue(Index, K); myMaxDerivInvOk = false; updateKnots(); @@ -671,6 +694,7 @@ void Geom_BSplineCurve::SetKnot(const int Index, const double K) void Geom_BSplineCurve::SetKnots(const NCollection_Array1& K) { CheckCurveData(myPoles, K, myMults, myDeg, myPeriodic); + ClearEvalRepresentation(); myKnots = K; myMaxDerivInvOk = false; updateKnots(); @@ -688,6 +712,7 @@ void Geom_BSplineCurve::SetKnot(const int Index, const double K, const int M) void Geom_BSplineCurve::SetPeriodic() { + ClearEvalRepresentation(); int first = FirstUKnotIndex(); int last = LastUKnotIndex(); @@ -724,6 +749,8 @@ void Geom_BSplineCurve::SetOrigin(const int Index) if (!myPeriodic) throw Standard_NoSuchObject("Geom_BSplineCurve::SetOrigin"); + ClearEvalRepresentation(); + int i, k; int first = FirstUKnotIndex(); int last = LastUKnotIndex(); @@ -819,6 +846,7 @@ void Geom_BSplineCurve::SetOrigin(const double U, const double Tol) if (std::abs(U - u) > Tol) { // On reparametre la courbe + ClearEvalRepresentation(); double delta = U - u; uf += delta; ul += delta; @@ -859,6 +887,7 @@ void Geom_BSplineCurve::SetNotPeriodic() { if (myPeriodic) { + ClearEvalRepresentation(); int NbKnots, NbPoles; BSplCLib::PrepareUnperiodize(myDeg, myMults, NbKnots, NbPoles); @@ -903,6 +932,7 @@ void Geom_BSplineCurve::SetPole(const int Index, const gp_Pnt& P) { if (Index < 1 || Index > myPoles.Length()) throw Standard_OutOfRange("BSpline curve: SetPole: index and #pole mismatch"); + ClearEvalRepresentation(); myPoles.SetValue(Index, P); myMaxDerivInvOk = false; } @@ -925,6 +955,8 @@ void Geom_BSplineCurve::SetWeight(const int Index, const double W) if (W <= gp::Resolution()) throw Standard_ConstructionError("BSpline curve: SetWeight: Weight too small"); + ClearEvalRepresentation(); + bool rat = IsRational() || (std::abs(W - 1.) > gp::Resolution()); if (rat) @@ -980,6 +1012,7 @@ void Geom_BSplineCurve::MovePoint(const double U, npoles); if (FirstModifiedPole) { + ClearEvalRepresentation(); myPoles = std::move(npoles); myMaxDerivInvOk = false; } @@ -1027,6 +1060,7 @@ void Geom_BSplineCurve::MovePointAndTangent(const double U, ErrorStatus); if (!ErrorStatus) { + ClearEvalRepresentation(); myPoles = std::move(new_poles); myMaxDerivInvOk = false; } diff --git a/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve.hxx b/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve.hxx index 892de34b2b..a508198aa0 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve.hxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve.hxx @@ -29,6 +29,11 @@ class gp_Trsf; class Geom_Geometry; +namespace Geom_EvalRepCurveDesc +{ +class Base; +} + //! Definition of the B_spline curve. //! A B-spline curve can be //! Uniform or non-uniform @@ -166,6 +171,20 @@ public: //! @param[in] theOther the BSpline curve to copy from Standard_EXPORT Geom_BSplineCurve(const Geom_BSplineCurve& theOther); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Increases the degree of this BSpline curve to //! Degree. As a result, the poles, weights and //! multiplicities tables are modified; the knots table is @@ -817,18 +836,19 @@ protected: void updateKnots(); private: - NCollection_Array1 myPoles; - NCollection_Array1 myWeights; - NCollection_Array1 myKnots; - NCollection_Array1 myFlatKnots; - NCollection_Array1 myMults; - int myDeg = 0; - bool myPeriodic = false; - bool myRational = false; - GeomAbs_BSplKnotDistribution myKnotSet = GeomAbs_NonUniform; - GeomAbs_Shape mySmooth = GeomAbs_C0; - double myMaxDerivInv = 0.0; - bool myMaxDerivInvOk = false; + NCollection_Array1 myPoles; + NCollection_Array1 myWeights; + NCollection_Array1 myKnots; + NCollection_Array1 myFlatKnots; + NCollection_Array1 myMults; + occ::handle myEvalRep; + int myDeg = 0; + bool myPeriodic = false; + bool myRational = false; + GeomAbs_BSplKnotDistribution myKnotSet = GeomAbs_NonUniform; + GeomAbs_Shape mySmooth = GeomAbs_C0; + double myMaxDerivInv = 0.0; + bool myMaxDerivInvOk = false; }; #endif // _Geom_BSplineCurve_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve_1.cxx b/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve_1.cxx index e3e8ca29c2..2949c79afa 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve_1.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BSplineCurve_1.cxx @@ -16,6 +16,8 @@ #include #include +#include "Geom_EvalRepCurveDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include #include #include @@ -160,6 +162,12 @@ int Geom_BSplineCurve::Degree() const std::optional Geom_BSplineCurve::EvalD0(const double U) const { + if (const std::optional aEvalRepResult = Geom_EvalRepUtils::TryEvalCurveD0(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Pnt P; int aSpanIndex = 0; double aNewU(U); @@ -176,6 +184,13 @@ std::optional Geom_BSplineCurve::EvalD0(const double U) const std::optional Geom_BSplineCurve::EvalD1(const double U) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD1(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; int aSpanIndex = 0; double aNewU(U); @@ -201,6 +216,13 @@ std::optional Geom_BSplineCurve::EvalD1(const double U) const std::optional Geom_BSplineCurve::EvalD2(const double U) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD2(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; int aSpanIndex = 0; double aNewU(U); @@ -227,6 +249,13 @@ std::optional Geom_BSplineCurve::EvalD2(const double U) const std::optional Geom_BSplineCurve::EvalD3(const double U) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD3(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; int aSpanIndex = 0; double aNewU(U); @@ -256,6 +285,14 @@ std::optional Geom_BSplineCurve::EvalDN(const double U, const int N) con { if (N < 1) return std::nullopt; + + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveDN(myEvalRep, U, N); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Vec V; BSplCLib::DN(U, N, 0, myDeg, myPeriodic, myPoles, Weights(), myFlatKnots, BSplCLib::NoMults(), V); return V; @@ -605,6 +642,7 @@ bool Geom_BSplineCurve::IsRational() const void Geom_BSplineCurve::Transform(const gp_Trsf& T) { + ClearEvalRepresentation(); for (int I = 1; I <= myPoles.Length(); I++) myPoles.ChangeValue(I).Transform(T); myMaxDerivInvOk = false; diff --git a/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface.cxx b/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface.cxx index f206c25a14..87f9fa45bc 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface.cxx @@ -24,6 +24,8 @@ #include #include #include +#include "Geom_EvalRepSurfaceDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include #include #include @@ -34,12 +36,22 @@ #include #include #include +#include #include IMPLEMENT_STANDARD_RTTIEXT(Geom_BSplineSurface, Geom_BoundedSurface) //================================================================================================= +void Geom_BSplineSurface::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom_EvalRepUtils::ValidateSurfaceDesc(theDesc, this); + myEvalRep = theDesc; +} + +//================================================================================================= + static void CheckSurfaceData(const NCollection_Array2& SPoles, const NCollection_Array1& SUKnots, const NCollection_Array1& SVKnots, @@ -142,6 +154,7 @@ Geom_BSplineSurface::Geom_BSplineSurface(const Geom_BSplineSurface& theOther) myVFlatKnots(theOther.myVFlatKnots), myUMults(theOther.myUMults), myVMults(theOther.myVMults), + myEvalRep(Geom_EvalRepUtils::CloneSurfaceDesc(theOther.myEvalRep)), myUDeg(theOther.myUDeg), myVDeg(theOther.myVDeg), myUPeriodic(theOther.myUPeriodic), @@ -293,6 +306,7 @@ Geom_BSplineSurface::Geom_BSplineSurface(const NCollection_Array2& Poles void Geom_BSplineSurface::ExchangeUV() { + ClearEvalRepresentation(); int LC = myPoles.LowerCol(); int UC = myPoles.UpperCol(); int LR = myPoles.LowerRow(); @@ -345,6 +359,8 @@ void Geom_BSplineSurface::IncreaseDegree(const int UDegree, const int VDegree) if (UDegree < myUDeg || UDegree > Geom_BSplineSurface::MaxDegree()) throw Standard_ConstructionError("Geom_BSplineSurface::IncreaseDegree: bad U degree value"); + ClearEvalRepresentation(); + int FromK1 = FirstUKnotIndex(); int ToK2 = LastUKnotIndex(); @@ -406,6 +422,8 @@ void Geom_BSplineSurface::IncreaseDegree(const int UDegree, const int VDegree) if (VDegree < myVDeg || VDegree > Geom_BSplineSurface::MaxDegree()) throw Standard_ConstructionError("Geom_BSplineSurface::IncreaseDegree: bad V degree value"); + ClearEvalRepresentation(); + int FromK1 = FirstVKnotIndex(); int ToK2 = LastVKnotIndex(); @@ -518,6 +536,7 @@ void Geom_BSplineSurface::segment(const double U1, const bool SegmentInU, const bool SegmentInV) { + ClearEvalRepresentation(); double deltaU = U2 - U1; if (myUPeriodic) { @@ -876,6 +895,7 @@ void Geom_BSplineSurface::SetUKnot(const int UIndex, const double K) if (K != myUKnots.Value(NewIndex)) { + ClearEvalRepresentation(); myUKnots.SetValue(NewIndex, K); myMaxDerivInvOk = false; updateUKnots(); @@ -908,6 +928,7 @@ void Geom_BSplineSurface::SetUKnots(const NCollection_Array1& UK) } } double K1 = UK(Lower); + ClearEvalRepresentation(); for (int i = Lower; i <= Upper; i++) { myUKnots.SetValue(i, UK(i)); @@ -965,6 +986,7 @@ void Geom_BSplineSurface::SetVKnot(const int VIndex, const double K) if (K != myVKnots.Value(NewIndex)) { + ClearEvalRepresentation(); myVKnots.SetValue(NewIndex, K); myMaxDerivInvOk = false; updateVKnots(); @@ -997,6 +1019,7 @@ void Geom_BSplineSurface::SetVKnots(const NCollection_Array1& VK) } } double K1 = VK(Lower); + ClearEvalRepresentation(); for (int i = Lower; i <= Upper; i++) { myVKnots.SetValue(i, VK(i)); @@ -1226,6 +1249,7 @@ void Geom_BSplineSurface::SetWeight(const int UIndex, const int VIndex, const do { throw Standard_OutOfRange("Geom_BSplineSurface::SetWeight: Index and #pole mismatch"); } + ClearEvalRepresentation(); if (!myURational && !myVRational) { // Make an owned copy of the unit weights view before modifying. @@ -1252,6 +1276,7 @@ void Geom_BSplineSurface::SetWeightCol(const int VIndex, { throw Standard_ConstructionError("Geom_BSplineSurface::SetWeightCol: invalid array dimension"); } + ClearEvalRepresentation(); if (!myURational && !myVRational) { // Make an owned copy of the unit weights view before modifying. @@ -1289,6 +1314,7 @@ void Geom_BSplineSurface::SetWeightRow(const int UIndex, throw Standard_ConstructionError("Geom_BSplineSurface::SetWeightRow: invalid array dimension"); } + ClearEvalRepresentation(); if (!myURational && !myVRational) { // Make an owned copy of the unit weights view before modifying. diff --git a/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface.hxx b/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface.hxx index 71c159285f..56438c25b4 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface.hxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface.hxx @@ -31,6 +31,11 @@ class Geom_Curve; class gp_Trsf; class Geom_Geometry; +namespace Geom_EvalRepSurfaceDesc +{ +class Base; +} + //! Describes a BSpline surface. //! In each parametric direction, a BSpline surface can be: //! - uniform or non-uniform, @@ -220,6 +225,20 @@ public: //! @param[in] theOther the BSpline surface to copy from Standard_EXPORT Geom_BSplineSurface(const Geom_BSplineSurface& theOther); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Exchanges the u and v parametric directions on //! this BSpline surface. //! As a consequence: @@ -1280,27 +1299,28 @@ protected: void updateVKnots(); private: - NCollection_Array2 myPoles; - NCollection_Array2 myWeights; - NCollection_Array1 myUKnots; - NCollection_Array1 myVKnots; - NCollection_Array1 myUFlatKnots; - NCollection_Array1 myVFlatKnots; - NCollection_Array1 myUMults; - NCollection_Array1 myVMults; - int myUDeg = 0; - int myVDeg = 0; - bool myUPeriodic = false; - bool myVPeriodic = false; - bool myURational = false; - bool myVRational = false; - GeomAbs_BSplKnotDistribution myUKnotSet = GeomAbs_NonUniform; - GeomAbs_BSplKnotDistribution myVKnotSet = GeomAbs_NonUniform; - GeomAbs_Shape myUSmooth = GeomAbs_C0; - GeomAbs_Shape myVSmooth = GeomAbs_C0; - double myUMaxDerivInv = 0.0; - double myVMaxDerivInv = 0.0; - bool myMaxDerivInvOk = false; + NCollection_Array2 myPoles; + NCollection_Array2 myWeights; + NCollection_Array1 myUKnots; + NCollection_Array1 myVKnots; + NCollection_Array1 myUFlatKnots; + NCollection_Array1 myVFlatKnots; + NCollection_Array1 myUMults; + NCollection_Array1 myVMults; + occ::handle myEvalRep; + int myUDeg = 0; + int myVDeg = 0; + bool myUPeriodic = false; + bool myVPeriodic = false; + bool myURational = false; + bool myVRational = false; + GeomAbs_BSplKnotDistribution myUKnotSet = GeomAbs_NonUniform; + GeomAbs_BSplKnotDistribution myVKnotSet = GeomAbs_NonUniform; + GeomAbs_Shape myUSmooth = GeomAbs_C0; + GeomAbs_Shape myVSmooth = GeomAbs_C0; + double myUMaxDerivInv = 0.0; + double myVMaxDerivInv = 0.0; + bool myMaxDerivInvOk = false; }; #endif // _Geom_BSplineSurface_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface_1.cxx b/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface_1.cxx index d60447a671..7b2bcb471a 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface_1.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BSplineSurface_1.cxx @@ -28,6 +28,8 @@ #include #include #include +#include "Geom_EvalRepSurfaceDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include #include #include @@ -108,6 +110,13 @@ bool Geom_BSplineSurface::IsCNv(const int N) const std::optional Geom_BSplineSurface::EvalD0(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD0(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + double aNewU = U; double aNewV = V; PeriodicNormalization(aNewU, aNewV); @@ -137,6 +146,13 @@ std::optional Geom_BSplineSurface::EvalD0(const double U, const double V std::optional Geom_BSplineSurface::EvalD1(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD1(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + double aNewU = U; double aNewV = V; PeriodicNormalization(aNewU, aNewV); @@ -176,6 +192,13 @@ std::optional Geom_BSplineSurface::EvalD1(const double U, c std::optional Geom_BSplineSurface::EvalD2(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD2(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + double aNewU = U; double aNewV = V; PeriodicNormalization(aNewU, aNewV); @@ -218,6 +241,13 @@ std::optional Geom_BSplineSurface::EvalD2(const double U, c std::optional Geom_BSplineSurface::EvalD3(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD3(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; BSplSLib::D3(U, V, @@ -257,6 +287,14 @@ std::optional Geom_BSplineSurface::EvalDN(const double U, { if (Nu + Nv < 1 || Nu < 0 || Nv < 0) return std::nullopt; + + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceDN(myEvalRep, U, V, Nu, Nv); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Vec Vn; BSplSLib::DN(U, V, @@ -888,6 +926,7 @@ const NCollection_Array2* Geom_BSplineSurface::Weights() const void Geom_BSplineSurface::Transform(const gp_Trsf& T) { + ClearEvalRepresentation(); for (int j = myPoles.LowerCol(); j <= myPoles.UpperCol(); j++) { for (int i = myPoles.LowerRow(); i <= myPoles.UpperRow(); i++) @@ -902,6 +941,7 @@ void Geom_BSplineSurface::Transform(const gp_Trsf& T) void Geom_BSplineSurface::SetUPeriodic() { + ClearEvalRepresentation(); int first = FirstUKnotIndex(); int last = LastUKnotIndex(); @@ -940,6 +980,7 @@ void Geom_BSplineSurface::SetUPeriodic() void Geom_BSplineSurface::SetVPeriodic() { + ClearEvalRepresentation(); int first = FirstVKnotIndex(); int last = LastVKnotIndex(); @@ -981,6 +1022,8 @@ void Geom_BSplineSurface::SetUOrigin(const int Index) if (!myUPeriodic) throw Standard_NoSuchObject("Geom_BSplineSurface::SetUOrigin: surface is not U periodic"); + ClearEvalRepresentation(); + int i, j, k; int first = FirstUKnotIndex(); int last = LastUKnotIndex(); @@ -1079,6 +1122,8 @@ void Geom_BSplineSurface::SetVOrigin(const int Index) if (!myVPeriodic) throw Standard_NoSuchObject("Geom_BSplineSurface::SetVOrigin: surface is not V periodic"); + ClearEvalRepresentation(); + int i, j, k; int first = FirstVKnotIndex(); int last = LastVKnotIndex(); @@ -1176,6 +1221,7 @@ void Geom_BSplineSurface::SetUNotPeriodic() { if (myUPeriodic) { + ClearEvalRepresentation(); int NbKnots, NbPoles; BSplCLib::PrepareUnperiodize(myUDeg, myUMults, NbKnots, NbPoles); @@ -1231,6 +1277,7 @@ void Geom_BSplineSurface::SetVNotPeriodic() { if (myVPeriodic) { + ClearEvalRepresentation(); int NbKnots, NbPoles; BSplCLib::PrepareUnperiodize(myVDeg, myVMults, NbKnots, NbPoles); @@ -1482,6 +1529,7 @@ void Geom_BSplineSurface::LocateV(const double V, void Geom_BSplineSurface::UReverse() { + ClearEvalRepresentation(); BSplCLib::Reverse(myUMults); BSplCLib::Reverse(myUKnots); int last; @@ -1506,6 +1554,7 @@ double Geom_BSplineSurface::UReversedParameter(const double U) const void Geom_BSplineSurface::VReverse() { + ClearEvalRepresentation(); BSplCLib::Reverse(myVMults); BSplCLib::Reverse(myVKnots); int last; @@ -1540,6 +1589,7 @@ void Geom_BSplineSurface::SetPoleCol(const int VIndex, const NCollection_Array1< throw Standard_ConstructionError("Geom_BSplineSurface::SetPoleCol: invalid array dimension"); } + ClearEvalRepresentation(); for (int I = CPoles.Lower(); I <= CPoles.Upper(); I++) { myPoles(I + myPoles.LowerRow() - 1, VIndex + myPoles.LowerCol() - 1) = CPoles(I); @@ -1571,6 +1621,7 @@ void Geom_BSplineSurface::SetPoleRow(const int UIndex, const NCollection_Array1< throw Standard_ConstructionError("Geom_BSplineSurface::SetPoleRow: invalid array dimension"); } + ClearEvalRepresentation(); for (int I = CPoles.Lower(); I <= CPoles.Upper(); I++) { myPoles(UIndex + myPoles.LowerRow() - 1, I + myPoles.LowerCol() - 1) = CPoles(I); @@ -1592,6 +1643,7 @@ void Geom_BSplineSurface::SetPoleRow(const int UIndex, void Geom_BSplineSurface::SetPole(const int UIndex, const int VIndex, const gp_Pnt& P) { + ClearEvalRepresentation(); myPoles.SetValue(UIndex + myPoles.LowerRow() - 1, VIndex + myPoles.LowerCol() - 1, P); myMaxDerivInvOk = false; } @@ -1654,6 +1706,7 @@ void Geom_BSplineSurface::MovePoint(const double U, npoles); if (UFirstModifiedPole) { + ClearEvalRepresentation(); myPoles = std::move(npoles); } myMaxDerivInvOk = false; @@ -1778,6 +1831,8 @@ void Geom_BSplineSurface::InsertUKnots(const NCollection_Array1& Knots, if (nbpoles == myPoles.ColLength()) return; + ClearEvalRepresentation(); + NCollection_Array2 npoles(1, nbpoles, 1, myPoles.RowLength()); NCollection_Array1 nknots(1, nbknots); NCollection_Array1 nmults(1, nbknots); @@ -1853,6 +1908,8 @@ void Geom_BSplineSurface::InsertVKnots(const NCollection_Array1& Knots, if (nbpoles == myPoles.RowLength()) return; + ClearEvalRepresentation(); + NCollection_Array2 npoles(1, myPoles.ColLength(), 1, nbpoles); NCollection_Array1 nknots(1, nbknots); NCollection_Array1 nmults(1, nbknots); @@ -1970,6 +2027,7 @@ bool Geom_BSplineSurface::RemoveUKnot(const int Index, const int M, const double myWeights = BSplSLib::UnitWeights(npoles.ColLength(), npoles.RowLength()); } + ClearEvalRepresentation(); myPoles = std::move(npoles); myUKnots = std::move(nknots); myUMults = std::move(nmults); @@ -2046,9 +2104,11 @@ bool Geom_BSplineSurface::RemoveVKnot(const int Index, const int M, const double myWeights = BSplSLib::UnitWeights(npoles.ColLength(), npoles.RowLength()); } - myPoles = std::move(npoles); - myVKnots = std::move(nknots); - myVMults = std::move(nmults); + ClearEvalRepresentation(); + myPoles = std::move(npoles); + myVKnots = std::move(nknots); + myVMults = std::move(nmults); + myMaxDerivInvOk = false; updateVKnots(); return true; diff --git a/src/ModelingData/TKG3d/Geom/Geom_BezierCurve.cxx b/src/ModelingData/TKG3d/Geom/Geom_BezierCurve.cxx index 978e6ef4eb..c1d4d2a9ab 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BezierCurve.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BezierCurve.cxx @@ -24,6 +24,8 @@ // Suppressed Swaps, added Init, removed typedefs #include +#include "Geom_EvalRepCurveDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include #include #include @@ -35,6 +37,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +48,15 @@ IMPLEMENT_STANDARD_RTTIEXT(Geom_BezierCurve, Geom_BoundedCurve) //================================================================================================= +void Geom_BezierCurve::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom_EvalRepUtils::ValidateCurveDesc(theDesc, this); + myEvalRep = theDesc; +} + +//================================================================================================= + static bool Rational(const NCollection_Array1& W) { int i, n = W.Length(); @@ -64,6 +76,7 @@ Geom_BezierCurve::Geom_BezierCurve(const Geom_BezierCurve& theOther) : myPoles(theOther.myPoles), myWeights(theOther.myRational ? NCollection_Array1(theOther.myWeights) : BSplCLib::UnitWeights(theOther.myPoles.Length())), + myEvalRep(Geom_EvalRepUtils::CloneCurveDesc(theOther.myEvalRep)), myRational(theOther.myRational), myClosed(theOther.myClosed), myMaxDerivInvOk(false) @@ -473,6 +486,12 @@ int Geom_BezierCurve::Degree() const std::optional Geom_BezierCurve::EvalD0(const double U) const { + if (const std::optional aEvalRepResult = Geom_EvalRepUtils::TryEvalCurveD0(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Pnt P; BSplCLib::D0(U, Poles(), Weights(), P); return P; @@ -482,6 +501,13 @@ std::optional Geom_BezierCurve::EvalD0(const double U) const std::optional Geom_BezierCurve::EvalD1(const double U) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD1(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; BSplCLib::D1(U, Poles(), Weights(), aResult->Point, aResult->D1); return aResult; @@ -491,6 +517,13 @@ std::optional Geom_BezierCurve::EvalD1(const double U) const std::optional Geom_BezierCurve::EvalD2(const double U) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD2(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; BSplCLib::D2(U, Poles(), Weights(), aResult->Point, aResult->D1, aResult->D2); return aResult; @@ -500,6 +533,13 @@ std::optional Geom_BezierCurve::EvalD2(const double U) const std::optional Geom_BezierCurve::EvalD3(const double U) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD3(myEvalRep, U); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; BSplCLib::D3(U, Poles(), Weights(), aResult->Point, aResult->D1, aResult->D2, aResult->D3); return aResult; @@ -511,6 +551,14 @@ std::optional Geom_BezierCurve::EvalDN(const double U, const int N) cons { if (N < 1) return std::nullopt; + + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveDN(myEvalRep, U, N); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Vec V; const int aDeg = myPoles.Size() - 1; @@ -616,6 +664,7 @@ void Geom_BezierCurve::Transform(const gp_Trsf& T) for (int i = 1; i <= nbpoles; i++) myPoles(i).Transform(T); + ClearEvalRepresentation(); myMaxDerivInvOk = false; } @@ -677,6 +726,7 @@ void Geom_BezierCurve::init(const NCollection_Array1& thePoles, myMaxDerivInv = 0.0; myMaxDerivInvOk = false; + ClearEvalRepresentation(); } //================================================================================================= diff --git a/src/ModelingData/TKG3d/Geom/Geom_BezierCurve.hxx b/src/ModelingData/TKG3d/Geom/Geom_BezierCurve.hxx index d9c46ceb3a..b097bb4534 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BezierCurve.hxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BezierCurve.hxx @@ -28,6 +28,11 @@ class gp_Trsf; class Geom_Geometry; +namespace Geom_EvalRepCurveDesc +{ +class Base; +} + //! Describes a rational or non-rational Bezier curve //! - a non-rational Bezier curve is defined by a table of //! poles (also called control points), @@ -101,6 +106,20 @@ public: //! @param[in] theOther the Bezier curve to copy from Standard_EXPORT Geom_BezierCurve(const Geom_BezierCurve& theOther); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Increases the degree of a bezier curve. Degree is the new //! degree of . Raises ConstructionError //! if Degree is greater than MaxDegree or lower than 2 @@ -338,12 +357,13 @@ protected: const NCollection_Array1* theWeights); private: - NCollection_Array1 myPoles; - NCollection_Array1 myWeights; - bool myRational = false; - bool myClosed = false; - double myMaxDerivInv = 0.0; - bool myMaxDerivInvOk = false; + NCollection_Array1 myPoles; + NCollection_Array1 myWeights; + occ::handle myEvalRep; + bool myRational = false; + bool myClosed = false; + double myMaxDerivInv = 0.0; + bool myMaxDerivInvOk = false; }; #endif // _Geom_BezierCurve_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_BezierSurface.cxx b/src/ModelingData/TKG3d/Geom/Geom_BezierSurface.cxx index 21062538b0..dafca40763 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BezierSurface.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BezierSurface.cxx @@ -28,6 +28,8 @@ #include #include #include +#include "Geom_EvalRepSurfaceDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include #include #include @@ -40,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -47,6 +50,15 @@ IMPLEMENT_STANDARD_RTTIEXT(Geom_BezierSurface, Geom_BoundedSurface) +//================================================================================================= + +void Geom_BezierSurface::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom_EvalRepUtils::ValidateSurfaceDesc(theDesc, this); + myEvalRep = theDesc; +} + //======================================================================= // function : Rational // purpose : check rationality of an array of weights @@ -363,6 +375,7 @@ Geom_BezierSurface::Geom_BezierSurface(const Geom_BezierSurface& theOther) (theOther.myURational || theOther.myVRational) ? NCollection_Array2(theOther.myWeights) : BSplSLib::UnitWeights(theOther.myPoles.ColLength(), theOther.myPoles.RowLength())), + myEvalRep(Geom_EvalRepUtils::CloneSurfaceDesc(theOther.myEvalRep)), myURational(theOther.myURational), myVRational(theOther.myVRational), myUMaxDerivInv(theOther.myUMaxDerivInv), @@ -1253,6 +1266,7 @@ void Geom_BezierSurface::UReverse() } } } + ClearEvalRepresentation(); myMaxDerivInvOk = false; } @@ -1299,6 +1313,7 @@ void Geom_BezierSurface::VReverse() } } } + ClearEvalRepresentation(); myMaxDerivInvOk = false; } @@ -1330,6 +1345,13 @@ GeomAbs_Shape Geom_BezierSurface::Continuity() const std::optional Geom_BezierSurface::EvalD0(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD0(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + gp_Pnt P; if (myURational || myVRational) { @@ -1378,6 +1400,13 @@ std::optional Geom_BezierSurface::EvalD0(const double U, const double V) std::optional Geom_BezierSurface::EvalD1(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD1(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; if (myURational || myVRational) { @@ -1430,6 +1459,13 @@ std::optional Geom_BezierSurface::EvalD1(const double U, co std::optional Geom_BezierSurface::EvalD2(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD2(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; if (myURational || myVRational) { @@ -1490,6 +1526,13 @@ std::optional Geom_BezierSurface::EvalD2(const double U, co std::optional Geom_BezierSurface::EvalD3(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD3(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aResult{std::in_place}; if (myURational || myVRational) { @@ -1559,6 +1602,13 @@ std::optional Geom_BezierSurface::EvalDN(const double U, const int Nu, const int Nv) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceDN(myEvalRep, U, V, Nu, Nv); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + if (Nu + Nv < 1 || Nu < 0 || Nv < 0) return std::nullopt; gp_Vec Derivative; @@ -1805,6 +1855,7 @@ void Geom_BezierSurface::Transform(const gp_Trsf& T) myPoles(I, J).Transform(T); } } + ClearEvalRepresentation(); myMaxDerivInvOk = false; } @@ -1941,6 +1992,7 @@ void Geom_BezierSurface::init(const NCollection_Array2& thePoles, } myMaxDerivInvOk = false; + ClearEvalRepresentation(); } //================================================================================================= diff --git a/src/ModelingData/TKG3d/Geom/Geom_BezierSurface.hxx b/src/ModelingData/TKG3d/Geom/Geom_BezierSurface.hxx index e2a95bdc9c..1242b65303 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_BezierSurface.hxx +++ b/src/ModelingData/TKG3d/Geom/Geom_BezierSurface.hxx @@ -30,6 +30,11 @@ class Geom_Curve; class gp_Trsf; class Geom_Geometry; +namespace Geom_EvalRepSurfaceDesc +{ +class Base; +} + //! Describes a rational or non-rational Bezier surface. //! - A non-rational Bezier surface is defined by a table //! of poles (also known as control points). @@ -121,6 +126,20 @@ public: //! @param[in] theOther the Bezier surface to copy from Standard_EXPORT Geom_BezierSurface(const Geom_BezierSurface& theOther); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! ---Purpose //! Creates a rational Bezier surface with a set of poles and a //! set of weights. @@ -614,13 +633,14 @@ protected: const NCollection_Array2* theWeights); private: - NCollection_Array2 myPoles; - NCollection_Array2 myWeights; - bool myURational = false; - bool myVRational = false; - double myUMaxDerivInv = 0.0; - double myVMaxDerivInv = 0.0; - bool myMaxDerivInvOk = false; + NCollection_Array2 myPoles; + NCollection_Array2 myWeights; + occ::handle myEvalRep; + bool myURational = false; + bool myVRational = false; + double myUMaxDerivInv = 0.0; + double myVMaxDerivInv = 0.0; + bool myMaxDerivInvOk = false; }; #endif // _Geom_BezierSurface_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_EvalRepCurveDesc.hxx b/src/ModelingData/TKG3d/Geom/Geom_EvalRepCurveDesc.hxx new file mode 100644 index 0000000000..be78b70c55 --- /dev/null +++ b/src/ModelingData/TKG3d/Geom/Geom_EvalRepCurveDesc.hxx @@ -0,0 +1,117 @@ +// Copyright (c) 2025 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Geom_EvalRepCurveDesc_HeaderFile +#define _Geom_EvalRepCurveDesc_HeaderFile + +#include +#include +#include + +#include +#include +#include + +namespace Geom_EvalRepCurveDesc +{ +//! 1D affine parameter map: uRep = Scale * u + Offset. +struct Map1d +{ + double Scale = 1.0; + double Offset = 0.0; + + bool IsIdentity() const + { + return std::abs(Scale - 1.0) < Precision::Confusion() + && std::abs(Offset) < Precision::Confusion(); + } + + bool IsValid() const { return std::abs(Scale) > Precision::Confusion(); } + + double Map(const double theU) const { return Scale * theU + Offset; } +}; + +//! 1D parameter domain interval. +struct Domain1d +{ + double First = 0.0; + double Last = 1.0; + + bool Contains(const double theU) const + { + return (theU >= First - Precision::Confusion()) && (theU <= Last + Precision::Confusion()); + } +}; + +//! Abstract base descriptor for curve evaluation representation. +//! Holds the representation handle and a Kind tag for switch-based dispatch. +class Base : public Standard_Transient +{ +public: + //! Descriptor kind for switch-based dispatch (no RTTI needed). + enum class Kind + { + Full, //!< fully equivalent, no derivative limit, no domain, no map + DerivBounded, //!< full domain + identity map, limited to MaxDerivOrder + Mapped //!< has MaxDerivOrder + optional Domain + ParamMap + }; + + occ::handle Representation; //!< geometry used for evaluation + + //! Returns the descriptor kind. + virtual Kind GetKind() const = 0; + + DEFINE_STANDARD_RTTI_INLINE(Base, Standard_Transient) + +protected: + Base() = default; +}; + +//! Fully equivalent descriptor: no derivative limit, no domain, no map. +//! Fastest evaluation path - direct delegation to Representation. +class Full : public Base +{ +public: + Kind GetKind() const override { return Kind::Full; } + + DEFINE_STANDARD_RTTI_INLINE(Full, Base) +}; + +//! Derivative-bounded descriptor: full domain, identity map, limited to MaxDerivOrder. +class DerivBounded : public Base +{ +public: + std::size_t MaxDerivOrder = 3; //!< max supported derivative order + + Kind GetKind() const override { return Kind::DerivBounded; } + + DEFINE_STANDARD_RTTI_INLINE(DerivBounded, Base) +}; + +//! Mapped descriptor for curve evaluation representation. +//! Adds optional bounded domain and affine parameter map. +//! Evaluation requires: domain check -> map parameter -> evaluate -> scale derivatives. +class Mapped : public Base +{ +public: + std::size_t MaxDerivOrder = 3; //!< max supported derivative order + std::optional Domain; //!< nullopt = full domain + Map1d ParamMap; //!< affine parameter transform + + Kind GetKind() const override { return Kind::Mapped; } + + DEFINE_STANDARD_RTTI_INLINE(Mapped, Base) +}; +} // namespace Geom_EvalRepCurveDesc + +#endif // _Geom_EvalRepCurveDesc_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_EvalRepSurfaceDesc.hxx b/src/ModelingData/TKG3d/Geom/Geom_EvalRepSurfaceDesc.hxx new file mode 100644 index 0000000000..389cb739b8 --- /dev/null +++ b/src/ModelingData/TKG3d/Geom/Geom_EvalRepSurfaceDesc.hxx @@ -0,0 +1,143 @@ +// Copyright (c) 2025 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Geom_EvalRepSurfaceDesc_HeaderFile +#define _Geom_EvalRepSurfaceDesc_HeaderFile + +#include +#include +#include + +#include +#include +#include + +namespace Geom_EvalRepSurfaceDesc +{ +//! 2D diagonal affine parameter map with optional UV swap. +//! Without swap: uRep = ScaleU*u + OffsetU, vRep = ScaleV*v + OffsetV. +//! With swap: uRep = ScaleU*v + OffsetU, vRep = ScaleV*u + OffsetV. +struct Map2d +{ + double ScaleU = 1.0; + double OffsetU = 0.0; + double ScaleV = 1.0; + double OffsetV = 0.0; + bool SwapUV = false; + + bool IsIdentity() const + { + return std::abs(ScaleU - 1.0) < Precision::Confusion() + && std::abs(ScaleV - 1.0) < Precision::Confusion() + && std::abs(OffsetU) < Precision::Confusion() + && std::abs(OffsetV) < Precision::Confusion() && !SwapUV; + } + + bool IsValid() const + { + return std::abs(ScaleU) > Precision::Confusion() && std::abs(ScaleV) > Precision::Confusion(); + } + + void Map(const double theU, const double theV, double& theURep, double& theVRep) const + { + if (SwapUV) + { + theURep = ScaleU * theV + OffsetU; + theVRep = ScaleV * theU + OffsetV; + } + else + { + theURep = ScaleU * theU + OffsetU; + theVRep = ScaleV * theV + OffsetV; + } + } +}; + +//! 2D parameter domain. +struct Domain2d +{ + double UFirst = 0.0; + double ULast = 1.0; + double VFirst = 0.0; + double VLast = 1.0; + + bool Contains(const double theU, const double theV) const + { + return (theU >= UFirst - Precision::Confusion()) && (theU <= ULast + Precision::Confusion()) + && (theV >= VFirst - Precision::Confusion()) && (theV <= VLast + Precision::Confusion()); + } +}; + +//! Abstract base descriptor for surface evaluation representation. +//! Holds the representation handle and a Kind tag for switch-based dispatch. +class Base : public Standard_Transient +{ +public: + //! Descriptor kind for switch-based dispatch (no RTTI needed). + enum class Kind + { + Full, //!< fully equivalent, no derivative limit, no domain, no map + DerivBounded, //!< full domain + identity map, limited to MaxDerivOrder + Mapped //!< has MaxDerivOrder + optional Domain + ParamMap + }; + + occ::handle Representation; //!< geometry used for evaluation + + //! Returns the descriptor kind. + virtual Kind GetKind() const = 0; + + DEFINE_STANDARD_RTTI_INLINE(Base, Standard_Transient) + +protected: + Base() = default; +}; + +//! Fully equivalent descriptor: no derivative limit, no domain, no map. +//! Fastest evaluation path - direct delegation to Representation. +class Full : public Base +{ +public: + Kind GetKind() const override { return Kind::Full; } + + DEFINE_STANDARD_RTTI_INLINE(Full, Base) +}; + +//! Derivative-bounded descriptor: full domain, identity map, limited to MaxDerivOrder. +class DerivBounded : public Base +{ +public: + std::size_t MaxDerivOrder = 3; //!< max supported derivative order + + Kind GetKind() const override { return Kind::DerivBounded; } + + DEFINE_STANDARD_RTTI_INLINE(DerivBounded, Base) +}; + +//! Mapped descriptor for surface evaluation representation. +//! Adds optional bounded domain and diagonal affine parameter map with optional UV swap. +//! Evaluation requires: domain check -> map parameters -> evaluate -> scale derivatives. +//! Future subclasses can support multi-region descriptors with per-patch UV domains and maps. +class Mapped : public Base +{ +public: + std::size_t MaxDerivOrder = 3; //!< max supported derivative order + std::optional Domain; //!< nullopt = full domain + Map2d ParamMap; //!< affine parameter transform + + Kind GetKind() const override { return Kind::Mapped; } + + DEFINE_STANDARD_RTTI_INLINE(Mapped, Base) +}; +} // namespace Geom_EvalRepSurfaceDesc + +#endif // _Geom_EvalRepSurfaceDesc_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_EvalRepUtils.pxx b/src/ModelingData/TKG3d/Geom/Geom_EvalRepUtils.pxx new file mode 100644 index 0000000000..37b5701351 --- /dev/null +++ b/src/ModelingData/TKG3d/Geom/Geom_EvalRepUtils.pxx @@ -0,0 +1,900 @@ +// Copyright (c) 2025 OPEN CASCADE SAS +// +// This file is part of Open CASCADE Technology software library. +// +// This library is free software; you can redistribute it and/or modify it under +// the terms of the GNU Lesser General Public License version 2.1 as published +// by the Free Software Foundation, with special exception defined in the file +// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT +// distribution for complete text of the license and disclaimer of any warranty. +// +// Alternatively, this file may be used under the terms of Open CASCADE +// commercial license or contractual agreement. + +#ifndef _Geom_EvalRepUtils_HeaderFile +#define _Geom_EvalRepUtils_HeaderFile + +#include "Geom_EvalRepCurveDesc.hxx" +#include "Geom_EvalRepSurfaceDesc.hxx" + +#include +#include + +#include + +#include +#include + +//! Internal helper namespace for EvalRep dispatch and validation. +namespace Geom_EvalRepUtils +{ +occ::handle CloneCurveDesc( + const occ::handle& theDesc); +occ::handle CloneSurfaceDesc( + const occ::handle& theDesc); + +std::optional TryEvalCurveD0(const occ::handle& theDesc, + const double theU); +std::optional TryEvalCurveD1( + const occ::handle& theDesc, + const double theU); +std::optional TryEvalCurveD2( + const occ::handle& theDesc, + const double theU); +std::optional TryEvalCurveD3( + const occ::handle& theDesc, + const double theU); +std::optional TryEvalCurveDN(const occ::handle& theDesc, + const double theU, + const int theN); + +std::optional TryEvalSurfaceD0(const occ::handle& theDesc, + const double theU, + const double theV); +std::optional TryEvalSurfaceD1( + const occ::handle& theDesc, + const double theU, + const double theV); +std::optional TryEvalSurfaceD2( + const occ::handle& theDesc, + const double theU, + const double theV); +std::optional TryEvalSurfaceD3( + const occ::handle& theDesc, + const double theU, + const double theV); +std::optional TryEvalSurfaceDN(const occ::handle& theDesc, + const double theU, + const double theV, + const int theNu, + const int theNv); + +std::optional TryEvalCurveD0Mapped(const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU); +std::optional TryEvalCurveD1Mapped(const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU); +std::optional TryEvalCurveD2Mapped(const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU); +std::optional TryEvalCurveD3Mapped(const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU); +std::optional TryEvalCurveDNMapped(const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU, + const int theN); + +std::optional TryEvalSurfaceD0Mapped(const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV); +std::optional TryEvalSurfaceD1Mapped( + const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV); +std::optional TryEvalSurfaceD2Mapped( + const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV); +std::optional TryEvalSurfaceD3Mapped( + const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV); +std::optional TryEvalSurfaceDNMapped(const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV, + const int theNu, + const int theNv); +void ValidateCurveDesc(const occ::handle& theDesc, + const Geom_Curve* theOwner); +void ValidateSurfaceDesc(const occ::handle& theDesc, + const Geom_Surface* theOwner); +} // namespace Geom_EvalRepUtils + +//================================================================================================== + +inline void Geom_EvalRepUtils::ValidateCurveDesc( + const occ::handle& theDesc, + const Geom_Curve* theOwner) +{ + if (theDesc.IsNull()) + { + return; + } + if (theDesc->Representation.IsNull()) + { + throw Standard_ProgramError("SetEvalRepresentation: null Representation"); + } + if (theDesc->GetKind() == Geom_EvalRepCurveDesc::Base::Kind::Mapped) + { + const auto* aMapped = static_cast(theDesc.get()); + if (!aMapped->ParamMap.IsValid()) + { + throw Standard_ProgramError("SetEvalRepresentation: invalid parameter map"); + } + } + // Only direct self-reference is detected here; indirect cycles (A->B->A) are not + // checked because EvalRepresentation() is not available on the Geom_Curve base class. + if (theDesc->Representation.get() == theOwner) + { + throw Standard_ProgramError("SetEvalRepresentation: invalid descriptor chain"); + } +} + +//================================================================================================== + +inline void Geom_EvalRepUtils::ValidateSurfaceDesc( + const occ::handle& theDesc, + const Geom_Surface* theOwner) +{ + if (theDesc.IsNull()) + { + return; + } + if (theDesc->Representation.IsNull()) + { + throw Standard_ProgramError("SetEvalRepresentation: null Representation"); + } + if (theDesc->GetKind() == Geom_EvalRepSurfaceDesc::Base::Kind::Mapped) + { + const auto* aMapped = static_cast(theDesc.get()); + if (!aMapped->ParamMap.IsValid()) + { + throw Standard_ProgramError("SetEvalRepresentation: invalid parameter map"); + } + } + // Only direct self-reference is detected here; indirect cycles (A->B->A) are not + // checked because EvalRepresentation() is not available on the Geom_Surface base class. + if (theDesc->Representation.get() == theOwner) + { + throw Standard_ProgramError("SetEvalRepresentation: invalid descriptor chain"); + } +} + +//================================================================================================== + +inline occ::handle Geom_EvalRepUtils::CloneCurveDesc( + const occ::handle& theDesc) +{ + if (theDesc.IsNull() || theDesc->Representation.IsNull()) + { + return occ::handle(); + } + + const occ::handle aRepCopy = + occ::down_cast(theDesc->Representation->Copy()); + if (aRepCopy.IsNull()) + { + return occ::handle(); + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepCurveDesc::Base::Kind::Full: { + occ::handle aClone = new Geom_EvalRepCurveDesc::Full(); + aClone->Representation = aRepCopy; + return aClone; + } + case Geom_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aSrc = static_cast(theDesc.get()); + occ::handle aClone = + new Geom_EvalRepCurveDesc::DerivBounded(); + aClone->Representation = aRepCopy; + aClone->MaxDerivOrder = aSrc->MaxDerivOrder; + return aClone; + } + case Geom_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aSrc = static_cast(theDesc.get()); + occ::handle aClone = new Geom_EvalRepCurveDesc::Mapped(); + aClone->Representation = aRepCopy; + aClone->MaxDerivOrder = aSrc->MaxDerivOrder; + aClone->Domain = aSrc->Domain; + aClone->ParamMap = aSrc->ParamMap; + return aClone; + } + } + return occ::handle(); +} + +//================================================================================================== + +inline occ::handle Geom_EvalRepUtils::CloneSurfaceDesc( + const occ::handle& theDesc) +{ + if (theDesc.IsNull() || theDesc->Representation.IsNull()) + { + return occ::handle(); + } + + const occ::handle aRepCopy = + occ::down_cast(theDesc->Representation->Copy()); + if (aRepCopy.IsNull()) + { + return occ::handle(); + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepSurfaceDesc::Base::Kind::Full: { + occ::handle aClone = new Geom_EvalRepSurfaceDesc::Full(); + aClone->Representation = aRepCopy; + return aClone; + } + case Geom_EvalRepSurfaceDesc::Base::Kind::DerivBounded: { + const auto* aSrc = static_cast(theDesc.get()); + occ::handle aClone = + new Geom_EvalRepSurfaceDesc::DerivBounded(); + aClone->Representation = aRepCopy; + aClone->MaxDerivOrder = aSrc->MaxDerivOrder; + return aClone; + } + case Geom_EvalRepSurfaceDesc::Base::Kind::Mapped: { + const auto* aSrc = static_cast(theDesc.get()); + occ::handle aClone = new Geom_EvalRepSurfaceDesc::Mapped(); + aClone->Representation = aRepCopy; + aClone->MaxDerivOrder = aSrc->MaxDerivOrder; + aClone->Domain = aSrc->Domain; + aClone->ParamMap = aSrc->ParamMap; + return aClone; + } + } + return occ::handle(); +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveD0( + const occ::handle& theDesc, + const double theU) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepCurveDesc::Base::Kind::Full: + case Geom_EvalRepCurveDesc::Base::Kind::DerivBounded: + return theDesc->Representation->EvalD0(theU); + case Geom_EvalRepCurveDesc::Base::Kind::Mapped: + return TryEvalCurveD0Mapped(*static_cast(theDesc.get()), + theU); + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveD1( + const occ::handle& theDesc, + const double theU) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepCurveDesc::Base::Kind::Full: + return theDesc->Representation->EvalD1(theU); + case Geom_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aBounded = static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < 1) + return std::nullopt; + return theDesc->Representation->EvalD1(theU); + } + case Geom_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < 1) + return std::nullopt; + return TryEvalCurveD1Mapped(*aMapped, theU); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveD2( + const occ::handle& theDesc, + const double theU) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepCurveDesc::Base::Kind::Full: + return theDesc->Representation->EvalD2(theU); + case Geom_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aBounded = static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < 2) + return std::nullopt; + return theDesc->Representation->EvalD2(theU); + } + case Geom_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < 2) + return std::nullopt; + return TryEvalCurveD2Mapped(*aMapped, theU); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveD3( + const occ::handle& theDesc, + const double theU) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepCurveDesc::Base::Kind::Full: + return theDesc->Representation->EvalD3(theU); + case Geom_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aBounded = static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < 3) + return std::nullopt; + return theDesc->Representation->EvalD3(theU); + } + case Geom_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < 3) + return std::nullopt; + return TryEvalCurveD3Mapped(*aMapped, theU); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveDN( + const occ::handle& theDesc, + const double theU, + const int theN) +{ + if (theDesc.IsNull() || theN < 1) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepCurveDesc::Base::Kind::Full: + return theDesc->Representation->EvalDN(theU, theN); + case Geom_EvalRepCurveDesc::Base::Kind::DerivBounded: { + const auto* aBounded = static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < static_cast(theN)) + return std::nullopt; + return theDesc->Representation->EvalDN(theU, theN); + } + case Geom_EvalRepCurveDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < static_cast(theN)) + return std::nullopt; + return TryEvalCurveDNMapped(*aMapped, theU, theN); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceD0( + const occ::handle& theDesc, + const double theU, + const double theV) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepSurfaceDesc::Base::Kind::Full: + case Geom_EvalRepSurfaceDesc::Base::Kind::DerivBounded: + return theDesc->Representation->EvalD0(theU, theV); + case Geom_EvalRepSurfaceDesc::Base::Kind::Mapped: + return TryEvalSurfaceD0Mapped( + *static_cast(theDesc.get()), + theU, + theV); + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceD1( + const occ::handle& theDesc, + const double theU, + const double theV) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepSurfaceDesc::Base::Kind::Full: + return theDesc->Representation->EvalD1(theU, theV); + case Geom_EvalRepSurfaceDesc::Base::Kind::DerivBounded: { + const auto* aBounded = + static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < 1) + return std::nullopt; + return theDesc->Representation->EvalD1(theU, theV); + } + case Geom_EvalRepSurfaceDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < 1) + return std::nullopt; + return TryEvalSurfaceD1Mapped(*aMapped, theU, theV); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceD2( + const occ::handle& theDesc, + const double theU, + const double theV) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepSurfaceDesc::Base::Kind::Full: + return theDesc->Representation->EvalD2(theU, theV); + case Geom_EvalRepSurfaceDesc::Base::Kind::DerivBounded: { + const auto* aBounded = + static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < 2) + return std::nullopt; + return theDesc->Representation->EvalD2(theU, theV); + } + case Geom_EvalRepSurfaceDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < 2) + return std::nullopt; + return TryEvalSurfaceD2Mapped(*aMapped, theU, theV); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceD3( + const occ::handle& theDesc, + const double theU, + const double theV) +{ + if (theDesc.IsNull()) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepSurfaceDesc::Base::Kind::Full: + return theDesc->Representation->EvalD3(theU, theV); + case Geom_EvalRepSurfaceDesc::Base::Kind::DerivBounded: { + const auto* aBounded = + static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < 3) + return std::nullopt; + return theDesc->Representation->EvalD3(theU, theV); + } + case Geom_EvalRepSurfaceDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < 3) + return std::nullopt; + return TryEvalSurfaceD3Mapped(*aMapped, theU, theV); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceDN( + const occ::handle& theDesc, + const double theU, + const double theV, + const int theNu, + const int theNv) +{ + const int aTotalOrder = theNu + theNv; + if (theDesc.IsNull() || theNu < 0 || theNv < 0 || aTotalOrder < 1) + { + return std::nullopt; + } + + switch (theDesc->GetKind()) + { + case Geom_EvalRepSurfaceDesc::Base::Kind::Full: + return theDesc->Representation->EvalDN(theU, theV, theNu, theNv); + case Geom_EvalRepSurfaceDesc::Base::Kind::DerivBounded: { + const auto* aBounded = + static_cast(theDesc.get()); + if (aBounded->MaxDerivOrder < static_cast(aTotalOrder)) + return std::nullopt; + return theDesc->Representation->EvalDN(theU, theV, theNu, theNv); + } + case Geom_EvalRepSurfaceDesc::Base::Kind::Mapped: { + const auto* aMapped = static_cast(theDesc.get()); + if (aMapped->MaxDerivOrder < static_cast(aTotalOrder)) + return std::nullopt; + return TryEvalSurfaceDNMapped(*aMapped, theU, theV, theNu, theNv); + } + } + return std::nullopt; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveD0Mapped( + const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + return theDesc.Representation->EvalD0(aURep); +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveD1Mapped( + const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + const std::optional aRepRes = theDesc.Representation->EvalD1(aURep); + if (!aRepRes) + { + return std::nullopt; + } + + const double aScale = theDesc.ParamMap.Scale; + Geom_Curve::ResD1 aRes; + aRes.Point = aRepRes->Point; + aRes.D1 = aRepRes->D1 * aScale; + return aRes; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveD2Mapped( + const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + const std::optional aRepRes = theDesc.Representation->EvalD2(aURep); + if (!aRepRes) + { + return std::nullopt; + } + + const double aScale = theDesc.ParamMap.Scale; + const double aScale2 = aScale * aScale; + + Geom_Curve::ResD2 aRes; + aRes.Point = aRepRes->Point; + aRes.D1 = aRepRes->D1 * aScale; + aRes.D2 = aRepRes->D2 * aScale2; + return aRes; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveD3Mapped( + const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + const std::optional aRepRes = theDesc.Representation->EvalD3(aURep); + if (!aRepRes) + { + return std::nullopt; + } + + const double aScale = theDesc.ParamMap.Scale; + const double aScale2 = aScale * aScale; + const double aScale3 = aScale2 * aScale; + + Geom_Curve::ResD3 aRes; + aRes.Point = aRepRes->Point; + aRes.D1 = aRepRes->D1 * aScale; + aRes.D2 = aRepRes->D2 * aScale2; + aRes.D3 = aRepRes->D3 * aScale3; + return aRes; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalCurveDNMapped( + const Geom_EvalRepCurveDesc::Mapped& theDesc, + const double theU, + const int theN) +{ + const double aURep = theDesc.ParamMap.Map(theU); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep)) + { + return std::nullopt; + } + + const std::optional aRepVec = theDesc.Representation->EvalDN(aURep, theN); + if (!aRepVec) + { + return std::nullopt; + } + + const double aScaleN = std::pow(theDesc.ParamMap.Scale, theN); + return (*aRepVec) * aScaleN; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceD0Mapped( + const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV) +{ + double aURep = 0.0; + double aVRep = 0.0; + theDesc.ParamMap.Map(theU, theV, aURep, aVRep); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep, aVRep)) + { + return std::nullopt; + } + + return theDesc.Representation->EvalD0(aURep, aVRep); +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceD1Mapped( + const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV) +{ + double aURep = 0.0; + double aVRep = 0.0; + theDesc.ParamMap.Map(theU, theV, aURep, aVRep); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep, aVRep)) + { + return std::nullopt; + } + + const std::optional aRepRes = theDesc.Representation->EvalD1(aURep, aVRep); + if (!aRepRes) + { + return std::nullopt; + } + + Geom_Surface::ResD1 aRes; + aRes.Point = aRepRes->Point; + + if (theDesc.ParamMap.SwapUV) + { + aRes.D1U = aRepRes->D1V * theDesc.ParamMap.ScaleV; + aRes.D1V = aRepRes->D1U * theDesc.ParamMap.ScaleU; + } + else + { + aRes.D1U = aRepRes->D1U * theDesc.ParamMap.ScaleU; + aRes.D1V = aRepRes->D1V * theDesc.ParamMap.ScaleV; + } + + return aRes; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceD2Mapped( + const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV) +{ + double aURep = 0.0; + double aVRep = 0.0; + theDesc.ParamMap.Map(theU, theV, aURep, aVRep); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep, aVRep)) + { + return std::nullopt; + } + + const std::optional aRepRes = theDesc.Representation->EvalD2(aURep, aVRep); + if (!aRepRes) + { + return std::nullopt; + } + + Geom_Surface::ResD2 aRes; + aRes.Point = aRepRes->Point; + + const double aSu = theDesc.ParamMap.ScaleU; + const double aSv = theDesc.ParamMap.ScaleV; + const double aSu2 = aSu * aSu; + const double aSv2 = aSv * aSv; + const double aSuSv = aSu * aSv; + + if (theDesc.ParamMap.SwapUV) + { + aRes.D1U = aRepRes->D1V * aSv; + aRes.D1V = aRepRes->D1U * aSu; + aRes.D2U = aRepRes->D2V * aSv2; + aRes.D2V = aRepRes->D2U * aSu2; + aRes.D2UV = aRepRes->D2UV * aSuSv; + } + else + { + aRes.D1U = aRepRes->D1U * aSu; + aRes.D1V = aRepRes->D1V * aSv; + aRes.D2U = aRepRes->D2U * aSu2; + aRes.D2V = aRepRes->D2V * aSv2; + aRes.D2UV = aRepRes->D2UV * aSuSv; + } + + return aRes; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceD3Mapped( + const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV) +{ + double aURep = 0.0; + double aVRep = 0.0; + theDesc.ParamMap.Map(theU, theV, aURep, aVRep); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep, aVRep)) + { + return std::nullopt; + } + + const std::optional aRepRes = theDesc.Representation->EvalD3(aURep, aVRep); + if (!aRepRes) + { + return std::nullopt; + } + + Geom_Surface::ResD3 aRes; + aRes.Point = aRepRes->Point; + + const double aSu = theDesc.ParamMap.ScaleU; + const double aSv = theDesc.ParamMap.ScaleV; + + if (theDesc.ParamMap.SwapUV) + { + aRes.D1U = aRepRes->D1V * aSv; + aRes.D1V = aRepRes->D1U * aSu; + aRes.D2U = aRepRes->D2V * (aSv * aSv); + aRes.D2V = aRepRes->D2U * (aSu * aSu); + aRes.D2UV = aRepRes->D2UV * (aSu * aSv); + aRes.D3U = aRepRes->D3V * (aSv * aSv * aSv); + aRes.D3V = aRepRes->D3U * (aSu * aSu * aSu); + aRes.D3UUV = aRepRes->D3UVV * (aSv * aSv * aSu); + aRes.D3UVV = aRepRes->D3UUV * (aSu * aSu * aSv); + } + else + { + aRes.D1U = aRepRes->D1U * aSu; + aRes.D1V = aRepRes->D1V * aSv; + aRes.D2U = aRepRes->D2U * (aSu * aSu); + aRes.D2V = aRepRes->D2V * (aSv * aSv); + aRes.D2UV = aRepRes->D2UV * (aSu * aSv); + aRes.D3U = aRepRes->D3U * (aSu * aSu * aSu); + aRes.D3V = aRepRes->D3V * (aSv * aSv * aSv); + aRes.D3UUV = aRepRes->D3UUV * (aSu * aSu * aSv); + aRes.D3UVV = aRepRes->D3UVV * (aSu * aSv * aSv); + } + + return aRes; +} + +//================================================================================================== + +inline std::optional Geom_EvalRepUtils::TryEvalSurfaceDNMapped( + const Geom_EvalRepSurfaceDesc::Mapped& theDesc, + const double theU, + const double theV, + const int theNu, + const int theNv) +{ + double aURep = 0.0; + double aVRep = 0.0; + theDesc.ParamMap.Map(theU, theV, aURep, aVRep); + + if (theDesc.Domain.has_value() && !theDesc.Domain->Contains(aURep, aVRep)) + { + return std::nullopt; + } + + int aNuRep = theNu; + int aNvRep = theNv; + + if (theDesc.ParamMap.SwapUV) + { + aNuRep = theNv; + aNvRep = theNu; + } + + const std::optional aRepVec = + theDesc.Representation->EvalDN(aURep, aVRep, aNuRep, aNvRep); + if (!aRepVec) + { + return std::nullopt; + } + + const double aScale = + std::pow(theDesc.ParamMap.ScaleU, aNuRep) * std::pow(theDesc.ParamMap.ScaleV, aNvRep); + + return (*aRepVec) * aScale; +} + +#endif // _Geom_EvalRepUtils_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_OffsetCurve.cxx b/src/ModelingData/TKG3d/Geom/Geom_OffsetCurve.cxx index c4225b40e3..38741f329a 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_OffsetCurve.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_OffsetCurve.cxx @@ -21,6 +21,8 @@ #include #include #include +#include "Geom_EvalRepCurveDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include #include #include @@ -35,6 +37,7 @@ #include #include #include +#include #include #include @@ -44,6 +47,15 @@ static const double MyAngularToleranceForG1 = Precision::Angular(); //================================================================================================== +void Geom_OffsetCurve::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom_EvalRepUtils::ValidateCurveDesc(theDesc, this); + myEvalRep = theDesc; +} + +//================================================================================================== + occ::handle Geom_OffsetCurve::Copy() const { return new Geom_OffsetCurve(*this); @@ -57,6 +69,7 @@ occ::handle Geom_OffsetCurve::Copy() const Geom_OffsetCurve::Geom_OffsetCurve(const Geom_OffsetCurve& theOther) : basisCurve(occ::down_cast(theOther.basisCurve->Copy())), + myEvalRep(Geom_EvalRepUtils::CloneCurveDesc(theOther.myEvalRep)), direction(theOther.direction), offsetValue(theOther.offsetValue), myBasisCurveContinuity(theOther.myBasisCurveContinuity) @@ -80,6 +93,7 @@ Geom_OffsetCurve::Geom_OffsetCurve(const occ::handle& theCurve, void Geom_OffsetCurve::Reverse() { + ClearEvalRepresentation(); basisCurve->Reverse(); offsetValue = -offsetValue; } @@ -102,6 +116,7 @@ const gp_Dir& Geom_OffsetCurve::Direction() const void Geom_OffsetCurve::SetDirection(const gp_Dir& V) { + ClearEvalRepresentation(); direction = V; } @@ -109,6 +124,7 @@ void Geom_OffsetCurve::SetDirection(const gp_Dir& V) void Geom_OffsetCurve::SetOffsetValue(const double D) { + ClearEvalRepresentation(); offsetValue = D; } @@ -130,6 +146,7 @@ double Geom_OffsetCurve::Period() const void Geom_OffsetCurve::SetBasisCurve(const occ::handle& C, const bool isNotCheckC0) { + ClearEvalRepresentation(); const double aUf = C->FirstParameter(), aUl = C->LastParameter(); occ::handle aCheckingCurve = occ::down_cast(C->Copy()); bool isTrimmed = false; @@ -242,6 +259,13 @@ GeomAbs_Shape Geom_OffsetCurve::Continuity() const std::optional Geom_OffsetCurve::EvalD0(const double theU) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD0(myEvalRep, theU); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD1 = basisCurve->EvalD1(theU); if (!aBasisD1) return std::nullopt; @@ -255,6 +279,13 @@ std::optional Geom_OffsetCurve::EvalD0(const double theU) const std::optional Geom_OffsetCurve::EvalD1(const double theU) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD1(myEvalRep, theU); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD2 = basisCurve->EvalD2(theU); if (!aBasisD2) return std::nullopt; @@ -269,6 +300,13 @@ std::optional Geom_OffsetCurve::EvalD1(const double theU) con std::optional Geom_OffsetCurve::EvalD2(const double theU) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD2(myEvalRep, theU); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD3 = basisCurve->EvalD3(theU); if (!aBasisD3) return std::nullopt; @@ -303,6 +341,13 @@ std::optional Geom_OffsetCurve::EvalD2(const double theU) con std::optional Geom_OffsetCurve::EvalD3(const double theU) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveD3(myEvalRep, theU); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD3 = basisCurve->EvalD3(theU); if (!aBasisD3) return std::nullopt; @@ -343,6 +388,12 @@ std::optional Geom_OffsetCurve::EvalDN(const double U, const int N) cons { if (N < 1) return std::nullopt; + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalCurveDN(myEvalRep, U, N); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } switch (N) { case 1: { @@ -405,6 +456,7 @@ bool Geom_OffsetCurve::IsCN(const int N) const void Geom_OffsetCurve::Transform(const gp_Trsf& T) { + ClearEvalRepresentation(); basisCurve->Transform(T); direction.Transform(T); offsetValue *= T.ScaleFactor(); diff --git a/src/ModelingData/TKG3d/Geom/Geom_OffsetCurve.hxx b/src/ModelingData/TKG3d/Geom/Geom_OffsetCurve.hxx index d3582a0dda..5ab23d15dc 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_OffsetCurve.hxx +++ b/src/ModelingData/TKG3d/Geom/Geom_OffsetCurve.hxx @@ -27,6 +27,11 @@ class gp_Trsf; class Geom_Geometry; +namespace Geom_EvalRepCurveDesc +{ +class Base; +} + //! This class implements the basis services for an offset curve //! in 3D space. The Offset curve in this package can be a self //! intersecting curve even if the basis curve does not @@ -98,6 +103,20 @@ public: //! @param[in] theOther the offset curve to copy from Standard_EXPORT Geom_OffsetCurve(const Geom_OffsetCurve& theOther); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Changes the orientation of this offset curve. //! As a result: //! - the basis curve is reversed, @@ -273,10 +292,11 @@ public: DEFINE_STANDARD_RTTIEXT(Geom_OffsetCurve, Geom_Curve) private: - occ::handle basisCurve; - gp_Dir direction; - double offsetValue; - GeomAbs_Shape myBasisCurveContinuity; + occ::handle basisCurve; + occ::handle myEvalRep; + gp_Dir direction; + double offsetValue; + GeomAbs_Shape myBasisCurveContinuity; }; #endif // _Geom_OffsetCurve_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_OffsetSurface.cxx b/src/ModelingData/TKG3d/Geom/Geom_OffsetSurface.cxx index 5268e31001..0f20dae958 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_OffsetSurface.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_OffsetSurface.cxx @@ -25,6 +25,8 @@ #include #include #include +#include "Geom_EvalRepSurfaceDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include #include #include @@ -53,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -64,6 +67,44 @@ IMPLEMENT_STANDARD_RTTIEXT(Geom_OffsetSurface, Geom_Surface) static const double MyAngularToleranceForG1 = Precision::Angular(); +namespace +{ +occ::handle makeFullSurfaceRep( + const occ::handle& theSurface) +{ + if (theSurface.IsNull()) + { + return occ::handle(); + } + occ::handle aDesc = new Geom_EvalRepSurfaceDesc::Full(); + aDesc->Representation = theSurface; + return aDesc; +} + +occ::handle directRepSurface(const Geom_OffsetSurface& theSurface) +{ + const occ::handle& aDesc = theSurface.EvalRepresentation(); + if (aDesc.IsNull()) + { + return occ::handle(); + } + if (aDesc->GetKind() != Geom_EvalRepSurfaceDesc::Base::Kind::Full) + { + return occ::handle(); + } + return aDesc->Representation; +} +} // namespace + +//================================================================================================= + +void Geom_OffsetSurface::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom_EvalRepUtils::ValidateSurfaceDesc(theDesc, this); + myEvalRep = theDesc; +} + //================================================================================================= occ::handle Geom_OffsetSurface::Copy() const @@ -79,15 +120,13 @@ occ::handle Geom_OffsetSurface::Copy() const Geom_OffsetSurface::Geom_OffsetSurface(const Geom_OffsetSurface& theOther) : basisSurf(occ::down_cast(theOther.basisSurf->Copy())), - equivSurf(theOther.equivSurf.IsNull() - ? occ::handle() - : occ::down_cast(theOther.equivSurf->Copy())), + myEvalRep(Geom_EvalRepUtils::CloneSurfaceDesc(theOther.myEvalRep)), offsetValue(theOther.offsetValue), myOscSurf(theOther.myOscSurf ? std::make_unique(*theOther.myOscSurf) : nullptr), myBasisSurfContinuity(theOther.myBasisSurfContinuity) { - // Deep copy without validation - source surface is already validated + // Deep copy without validation - source surface is already validated. } //================================================================================================= @@ -109,6 +148,7 @@ Geom_OffsetSurface::Geom_OffsetSurface(const occ::handle& theSurf, void Geom_OffsetSurface::SetBasisSurface(const occ::handle& S, const bool isNotCheckC0) { + ClearEvalRepresentation(); double aUf, aUl, aVf, aVl; S->Bounds(aUf, aUl, aVf, aVl); @@ -215,7 +255,8 @@ void Geom_OffsetSurface::SetBasisSurface(const occ::handle& S, basisSurf = aCheckingSurf; } - equivSurf = Surface(); + const occ::handle aSurfaceRep = Surface(); + SetEvalRepresentation(makeFullSurfaceRep(aSurfaceRep)); if (aCheckingSurf->IsKind(STANDARD_TYPE(Geom_BSplineSurface)) || aCheckingSurf->IsKind(STANDARD_TYPE(Geom_BezierSurface))) @@ -233,18 +274,18 @@ void Geom_OffsetSurface::SetBasisSurface(const occ::handle& S, void Geom_OffsetSurface::SetOffsetValue(const double D) { + ClearEvalRepresentation(); offsetValue = D; - equivSurf = Surface(); + SetEvalRepresentation(makeFullSurfaceRep(Surface())); } //================================================================================================= void Geom_OffsetSurface::UReverse() { + ClearEvalRepresentation(); basisSurf->UReverse(); offsetValue = -offsetValue; - if (!equivSurf.IsNull()) - equivSurf->UReverse(); } //================================================================================================= @@ -258,10 +299,9 @@ double Geom_OffsetSurface::UReversedParameter(const double U) const void Geom_OffsetSurface::VReverse() { + ClearEvalRepresentation(); basisSurf->VReverse(); offsetValue = -offsetValue; - if (!equivSurf.IsNull()) - equivSurf->VReverse(); } //================================================================================================= @@ -306,9 +346,11 @@ std::optional Geom_OffsetSurface::EvalD0(const double U, const double V) return std::nullopt; } #endif - if (!equivSurf.IsNull()) + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD0(myEvalRep, U, V); + aEvalRepResult.has_value()) { - return equivSurf->EvalD0(U, V); + return aEvalRepResult; } gp_Pnt aP; @@ -329,9 +371,11 @@ std::optional Geom_OffsetSurface::EvalD1(const double U, co return std::nullopt; } #endif - if (!equivSurf.IsNull()) + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD1(myEvalRep, U, V); + aEvalRepResult.has_value()) { - return equivSurf->EvalD1(U, V); + return aEvalRepResult; } Geom_Surface::ResD1 aResult; @@ -360,9 +404,11 @@ std::optional Geom_OffsetSurface::EvalD2(const double U, co return std::nullopt; } #endif - if (!equivSurf.IsNull()) + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD2(myEvalRep, U, V); + aEvalRepResult.has_value()) { - return equivSurf->EvalD2(U, V); + return aEvalRepResult; } Geom_Surface::ResD2 aResult; @@ -393,9 +439,11 @@ std::optional Geom_OffsetSurface::EvalD3(const double U, co return std::nullopt; } #endif - if (!equivSurf.IsNull()) + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD3(myEvalRep, U, V); + aEvalRepResult.has_value()) { - return equivSurf->EvalD3(U, V); + return aEvalRepResult; } Geom_Surface::ResD3 aResult; @@ -435,9 +483,11 @@ std::optional Geom_OffsetSurface::EvalDN(const double U, return std::nullopt; } #endif - if (!equivSurf.IsNull()) + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceDN(myEvalRep, U, V, Nu, Nv); + aEvalRepResult.has_value()) { - return equivSurf->EvalDN(U, V, Nu, Nv); + return aEvalRepResult; } gp_Vec aResult; @@ -565,7 +615,8 @@ void Geom_OffsetSurface_VIsoEvaluator::Evaluate(int*, /*Dimension*/ occ::handle Geom_OffsetSurface::UIso(const double UU) const { - if (equivSurf.IsNull()) + const occ::handle anEquivSurface = directRepSurface(*this); + if (anEquivSurface.IsNull()) { GeomAdaptor_Surface aGAsurf(basisSurf); if (aGAsurf.GetType() == GeomAbs_SurfaceOfExtrusion) @@ -608,15 +659,15 @@ occ::handle Geom_OffsetSurface::UIso(const double UU) const occ::handle C = new Geom_BSplineCurve(Poles, Knots, Mults, Approx.Degree()); return C; } - else - return equivSurf->UIso(UU); + return anEquivSurface->UIso(UU); } //================================================================================================= occ::handle Geom_OffsetSurface::VIso(const double VV) const { - if (equivSurf.IsNull()) + const occ::handle anEquivSurface = directRepSurface(*this); + if (anEquivSurface.IsNull()) { const int Num1 = 0, Num2 = 0, Num3 = 1; occ::handle> T1, T2, T3 = new NCollection_HArray1(1, Num3); @@ -644,8 +695,7 @@ occ::handle Geom_OffsetSurface::VIso(const double VV) const occ::handle C = new Geom_BSplineCurve(Poles, Knots, Mults, Approx.Degree()); return C; } - else - return equivSurf->VIso(VV); + return anEquivSurface->VIso(VV); } //================================================================================================= @@ -799,9 +849,9 @@ bool Geom_OffsetSurface::IsVClosed() const void Geom_OffsetSurface::Transform(const gp_Trsf& T) { + ClearEvalRepresentation(); basisSurf->Transform(T); offsetValue *= T.ScaleFactor(); - equivSurf.Nullify(); } //================================================================================================= @@ -809,8 +859,11 @@ void Geom_OffsetSurface::Transform(const gp_Trsf& T) void Geom_OffsetSurface::TransformParameters(double& U, double& V, const gp_Trsf& T) const { basisSurf->TransformParameters(U, V, T); - if (!equivSurf.IsNull()) - equivSurf->TransformParameters(U, V, T); + const occ::handle anEquivSurface = directRepSurface(*this); + if (!anEquivSurface.IsNull()) + { + anEquivSurface->TransformParameters(U, V, T); + } } //================================================================================================= @@ -972,12 +1025,14 @@ bool Geom_OffsetSurface::VOsculatingSurface(const double U, void Geom_OffsetSurface::DumpJson(Standard_OStream& theOStream, int theDepth) const { + const occ::handle anEquivSurface = directRepSurface(*this); + OCCT_DUMP_TRANSIENT_CLASS_BEGIN(theOStream) OCCT_DUMP_BASE_CLASS(theOStream, theDepth, Geom_Surface) OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, basisSurf.get()) - OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, equivSurf.get()) + OCCT_DUMP_FIELD_VALUES_DUMPED(theOStream, theDepth, anEquivSurface.get()) OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, offsetValue) OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, myBasisSurfContinuity) diff --git a/src/ModelingData/TKG3d/Geom/Geom_OffsetSurface.hxx b/src/ModelingData/TKG3d/Geom/Geom_OffsetSurface.hxx index 0da8a9c230..5efbdf7ecf 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_OffsetSurface.hxx +++ b/src/ModelingData/TKG3d/Geom/Geom_OffsetSurface.hxx @@ -32,6 +32,11 @@ class gp_Trsf; class gp_GTrsf2d; class Geom_Geometry; +namespace Geom_EvalRepSurfaceDesc +{ +class Base; +} + //! Describes an offset surface in 3D space. //! An offset surface is defined by: //! - the basis surface to which it is parallel, and @@ -86,6 +91,20 @@ public: const double Offset, const bool isNotCheckC0 = false); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Raised if S is not at least C1. //! Warnings : //! No check is done to verify that a unique normal direction is @@ -354,11 +373,11 @@ public: DEFINE_STANDARD_RTTIEXT(Geom_OffsetSurface, Geom_Surface) private: - occ::handle basisSurf; - occ::handle equivSurf; - double offsetValue; - std::unique_ptr myOscSurf; - GeomAbs_Shape myBasisSurfContinuity; + occ::handle basisSurf; + occ::handle myEvalRep; + double offsetValue; + std::unique_ptr myOscSurf; + GeomAbs_Shape myBasisSurfContinuity; }; #endif // _Geom_OffsetSurface_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfLinearExtrusion.cxx b/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfLinearExtrusion.cxx index 46af0f3503..3f05edec79 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfLinearExtrusion.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfLinearExtrusion.cxx @@ -18,6 +18,8 @@ #include #include #include +#include "Geom_EvalRepSurfaceDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include "Geom_ExtrusionUtils.pxx" #include #include @@ -32,6 +34,7 @@ #include #include #include +#include #include #include @@ -55,12 +58,21 @@ typedef gp_XYZ XYZ; //================================================================================================= +void Geom_SurfaceOfLinearExtrusion::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom_EvalRepUtils::ValidateSurfaceDesc(theDesc, this); + myEvalRep = theDesc; +} + +//================================================================================================= + occ::handle Geom_SurfaceOfLinearExtrusion::Copy() const { - - occ::handle Sr; - Sr = new SurfaceOfLinearExtrusion(basisCurve, direction); - return Sr; + occ::handle aCopy = + new SurfaceOfLinearExtrusion(basisCurve, direction); + aCopy->myEvalRep = Geom_EvalRepUtils::CloneSurfaceDesc(myEvalRep); + return aCopy; } //================================================================================================= @@ -77,7 +89,7 @@ Geom_SurfaceOfLinearExtrusion::Geom_SurfaceOfLinearExtrusion(const occ::handleReverse(); } @@ -93,6 +105,7 @@ double Geom_SurfaceOfLinearExtrusion::UReversedParameter(const double U) const void Geom_SurfaceOfLinearExtrusion::VReverse() { + ClearEvalRepresentation(); direction.Reverse(); } @@ -108,6 +121,7 @@ double Geom_SurfaceOfLinearExtrusion::VReversedParameter(const double V) const void Geom_SurfaceOfLinearExtrusion::SetDirection(const Dir& V) { + ClearEvalRepresentation(); direction = V; } @@ -115,6 +129,7 @@ void Geom_SurfaceOfLinearExtrusion::SetDirection(const Dir& V) void Geom_SurfaceOfLinearExtrusion::SetBasisCurve(const occ::handle& C) { + ClearEvalRepresentation(); smooth = C->Continuity(); basisCurve = occ::down_cast(C->Copy()); } @@ -134,6 +149,13 @@ void Geom_SurfaceOfLinearExtrusion::Bounds(double& U1, double& U2, double& V1, d std::optional Geom_SurfaceOfLinearExtrusion::EvalD0(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD0(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD0 = basisCurve->EvalD0(U); if (!aBasisD0) return std::nullopt; @@ -147,6 +169,13 @@ std::optional Geom_SurfaceOfLinearExtrusion::EvalD0(const double U, cons std::optional Geom_SurfaceOfLinearExtrusion::EvalD1(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD1(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD1 = basisCurve->EvalD1(U); if (!aBasisD1) return std::nullopt; @@ -166,6 +195,13 @@ std::optional Geom_SurfaceOfLinearExtrusion::EvalD1(const d std::optional Geom_SurfaceOfLinearExtrusion::EvalD2(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD2(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD2 = basisCurve->EvalD2(U); if (!aBasisD2) return std::nullopt; @@ -189,6 +225,13 @@ std::optional Geom_SurfaceOfLinearExtrusion::EvalD2(const d std::optional Geom_SurfaceOfLinearExtrusion::EvalD3(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD3(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD3 = basisCurve->EvalD3(U); if (!aBasisD3) return std::nullopt; @@ -215,12 +258,20 @@ std::optional Geom_SurfaceOfLinearExtrusion::EvalD3(const d //================================================================================================= std::optional Geom_SurfaceOfLinearExtrusion::EvalDN(const double U, - const double, - const int Nu, - const int Nv) const + const double V, + const int Nu, + const int Nv) const { if (Nu + Nv < 1 || Nu < 0 || Nv < 0) return std::nullopt; + + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceDN(myEvalRep, U, V, Nu, Nv); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + if (Nv == 0) { std::optional aDN = basisCurve->EvalDN(U, Nu); @@ -278,6 +329,7 @@ bool Geom_SurfaceOfLinearExtrusion::IsCNv(const int) const void Geom_SurfaceOfLinearExtrusion::Transform(const Trsf& T) { + ClearEvalRepresentation(); direction.Transform(T); basisCurve->Transform(T); } diff --git a/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfLinearExtrusion.hxx b/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfLinearExtrusion.hxx index c85bdec373..6c3361172d 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfLinearExtrusion.hxx +++ b/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfLinearExtrusion.hxx @@ -27,6 +27,11 @@ class gp_Trsf; class gp_GTrsf2d; class Geom_Geometry; +namespace Geom_EvalRepSurfaceDesc +{ +class Base; +} + //! Describes a surface of linear extrusion ("extruded //! surface"), e.g. a generalized cylinder. Such a surface //! is obtained by sweeping a curve (called the "extruded @@ -72,6 +77,20 @@ public: //! line. Standard_EXPORT Geom_SurfaceOfLinearExtrusion(const occ::handle& C, const gp_Dir& V); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Assigns V as the "direction of extrusion" for this //! surface of linear extrusion. Standard_EXPORT void SetDirection(const gp_Dir& V); @@ -235,6 +254,9 @@ public: Standard_EXPORT void DumpJson(Standard_OStream& theOStream, int theDepth = -1) const final; DEFINE_STANDARD_RTTIEXT(Geom_SurfaceOfLinearExtrusion, Geom_SweptSurface) + +private: + occ::handle myEvalRep; }; #endif // _Geom_SurfaceOfLinearExtrusion_HeaderFile diff --git a/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfRevolution.cxx b/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfRevolution.cxx index f0c561b032..1ee5fac336 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfRevolution.cxx +++ b/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfRevolution.cxx @@ -19,6 +19,8 @@ #include #include #include +#include "Geom_EvalRepSurfaceDesc.hxx" +#include "Geom_EvalRepUtils.pxx" #include #include "Geom_RevolutionUtils.pxx" #include @@ -36,6 +38,7 @@ #include #include #include +#include #include #include @@ -62,10 +65,20 @@ typedef gp_XYZ XYZ; //================================================================================================= +void Geom_SurfaceOfRevolution::SetEvalRepresentation( + const occ::handle& theDesc) +{ + Geom_EvalRepUtils::ValidateSurfaceDesc(theDesc, this); + myEvalRep = theDesc; +} + +//================================================================================================= + occ::handle Geom_SurfaceOfRevolution::Copy() const { - - return new Geom_SurfaceOfRevolution(basisCurve, Axis()); + occ::handle aCopy = new Geom_SurfaceOfRevolution(basisCurve, Axis()); + aCopy->myEvalRep = Geom_EvalRepUtils::CloneSurfaceDesc(myEvalRep); + return aCopy; } //================================================================================================= @@ -81,6 +94,7 @@ Geom_SurfaceOfRevolution::Geom_SurfaceOfRevolution(const occ::handle void Geom_SurfaceOfRevolution::UReverse() { + ClearEvalRepresentation(); direction.Reverse(); } @@ -96,7 +110,7 @@ double Geom_SurfaceOfRevolution::UReversedParameter(const double U) const void Geom_SurfaceOfRevolution::VReverse() { - + ClearEvalRepresentation(); basisCurve->Reverse(); } @@ -176,6 +190,7 @@ bool Geom_SurfaceOfRevolution::IsVPeriodic() const void Geom_SurfaceOfRevolution::SetAxis(const Ax1& A1) { + ClearEvalRepresentation(); direction = A1.Direction(); loc = A1.Location(); } @@ -184,6 +199,7 @@ void Geom_SurfaceOfRevolution::SetAxis(const Ax1& A1) void Geom_SurfaceOfRevolution::SetDirection(const Dir& V) { + ClearEvalRepresentation(); direction = V; } @@ -191,6 +207,7 @@ void Geom_SurfaceOfRevolution::SetDirection(const Dir& V) void Geom_SurfaceOfRevolution::SetBasisCurve(const occ::handle& C) { + ClearEvalRepresentation(); basisCurve = occ::down_cast(C->Copy()); smooth = C->Continuity(); } @@ -199,6 +216,7 @@ void Geom_SurfaceOfRevolution::SetBasisCurve(const occ::handle& C) void Geom_SurfaceOfRevolution::SetLocation(const Pnt& P) { + ClearEvalRepresentation(); loc = P; } @@ -217,6 +235,13 @@ void Geom_SurfaceOfRevolution::Bounds(double& U1, double& U2, double& V1, double std::optional Geom_SurfaceOfRevolution::EvalD0(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD0(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD0 = basisCurve->EvalD0(V); if (!aBasisD0) return std::nullopt; @@ -230,6 +255,13 @@ std::optional Geom_SurfaceOfRevolution::EvalD0(const double U, const dou std::optional Geom_SurfaceOfRevolution::EvalD1(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD1(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD1 = basisCurve->EvalD1(V); if (!aBasisD1) return std::nullopt; @@ -249,6 +281,13 @@ std::optional Geom_SurfaceOfRevolution::EvalD1(const double std::optional Geom_SurfaceOfRevolution::EvalD2(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD2(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD2 = basisCurve->EvalD2(V); if (!aBasisD2) return std::nullopt; @@ -272,6 +311,13 @@ std::optional Geom_SurfaceOfRevolution::EvalD2(const double std::optional Geom_SurfaceOfRevolution::EvalD3(const double U, const double V) const { + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceD3(myEvalRep, U, V); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } + std::optional aBasisD3 = basisCurve->EvalD3(V); if (!aBasisD3) return std::nullopt; @@ -304,6 +350,12 @@ std::optional Geom_SurfaceOfRevolution::EvalDN(const double U, { if (Nu + Nv < 1 || Nu < 0 || Nv < 0) return std::nullopt; + if (const std::optional aEvalRepResult = + Geom_EvalRepUtils::TryEvalSurfaceDN(myEvalRep, U, V, Nu, Nv); + aEvalRepResult.has_value()) + { + return aEvalRepResult; + } gp_Vec aCurvePtOrDN; if (Nu == 0) { @@ -384,6 +436,7 @@ occ::handle Geom_SurfaceOfRevolution::VIso(const double V) const void Geom_SurfaceOfRevolution::Transform(const Trsf& T) { + ClearEvalRepresentation(); loc.Transform(T); direction.Transform(T); basisCurve->Transform(T); diff --git a/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfRevolution.hxx b/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfRevolution.hxx index ac2a833ced..b9c141c273 100644 --- a/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfRevolution.hxx +++ b/src/ModelingData/TKG3d/Geom/Geom_SurfaceOfRevolution.hxx @@ -30,6 +30,11 @@ class gp_Trsf; class gp_GTrsf2d; class Geom_Geometry; +namespace Geom_EvalRepSurfaceDesc +{ +class Base; +} + //! Describes a surface of revolution (revolved surface). //! Such a surface is obtained by rotating a curve (called //! the "meridian") through a complete revolution about @@ -91,6 +96,20 @@ public: //! self-intersects. Standard_EXPORT Geom_SurfaceOfRevolution(const occ::handle& C, const gp_Ax1& A1); + //! Returns true if an evaluation representation is attached. + bool HasEvalRepresentation() const { return !myEvalRep.IsNull(); } + + //! Returns the current evaluation representation descriptor (may be null). + const occ::handle& EvalRepresentation() const { return myEvalRep; } + + //! Sets a new evaluation representation. + //! Validates descriptor data and ensures no circular references. + Standard_EXPORT void SetEvalRepresentation( + const occ::handle& theDesc); + + //! Removes the evaluation representation. + void ClearEvalRepresentation() { myEvalRep.Nullify(); } + //! Changes the axis of revolution. //! Warnings : //! It is not checked that the axis is in the plane of the @@ -286,7 +305,8 @@ public: DEFINE_STANDARD_RTTIEXT(Geom_SurfaceOfRevolution, Geom_SweptSurface) private: - gp_Pnt loc; + occ::handle myEvalRep; + gp_Pnt loc; }; #endif // _Geom_SurfaceOfRevolution_HeaderFile diff --git a/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Curve.cxx b/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Curve.cxx index 6bbf476bb0..d860c03e7b 100644 --- a/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Curve.cxx +++ b/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Curve.cxx @@ -61,6 +61,29 @@ static const double PosTol = Precision::PConfusion() / 2; IMPLEMENT_STANDARD_RTTIEXT(GeomAdaptor_Curve, Adaptor3d_Curve) +namespace +{ +bool hasEvalRep(const GeomAdaptor_Curve::CurveDataVariant& theData) +{ + if (const GeomAdaptor_Curve::BezierData* aBezierData = + std::get_if(&theData)) + { + return !aBezierData->EvalRep.IsNull(); + } + if (const GeomAdaptor_Curve::BSplineData* aBSplineData = + std::get_if(&theData)) + { + return !aBSplineData->EvalRep.IsNull(); + } + if (const GeomAdaptor_Curve::OffsetData* anOffsetData = + std::get_if(&theData)) + { + return !anOffsetData->EvalRep.IsNull(); + } + return false; +} +} // namespace + //================================================================================================= occ::handle GeomAdaptor_Curve::ShallowCopy() const @@ -80,17 +103,24 @@ occ::handle GeomAdaptor_Curve::ShallowCopy() const occ::down_cast(anOffsetData->BasisAdaptor->ShallowCopy()); aCopyData.Offset = anOffsetData->Offset; aCopyData.Direction = anOffsetData->Direction; + aCopyData.EvalRep = anOffsetData->EvalRep; aCopy->myCurveData = std::move(aCopyData); } else if (const auto* aBSplineData = std::get_if(&myCurveData)) { BSplineData aCopyData; aCopyData.Curve = aBSplineData->Curve; + aCopyData.EvalRep = aBSplineData->EvalRep; aCopy->myCurveData = std::move(aCopyData); } else if (std::holds_alternative(myCurveData)) { - aCopy->myCurveData = BezierData{}; + const BezierData& aBezierData = std::get(myCurveData); + BezierData aCopyData; + aCopyData.Curve = aBezierData.Curve; + aCopyData.EvalRep = aBezierData.EvalRep; + // Cache is not copied - will be rebuilt on demand. + aCopy->myCurveData = std::move(aCopyData); } else { @@ -243,14 +273,18 @@ void GeomAdaptor_Curve::load(const occ::handle& C, else if (TheType == STANDARD_TYPE(Geom_BezierCurve)) { myTypeCurve = GeomAbs_BezierCurve; - myCurveData = BezierData{}; + BezierData aBezierData; + aBezierData.Curve = occ::down_cast(C); + aBezierData.EvalRep = aBezierData.Curve->EvalRepresentation(); + myCurveData = std::move(aBezierData); } else if (TheType == STANDARD_TYPE(Geom_BSplineCurve)) { myTypeCurve = GeomAbs_BSplineCurve; BSplineData aBSplineData; - aBSplineData.Curve = occ::down_cast(C); - myCurveData = std::move(aBSplineData); + aBSplineData.Curve = occ::down_cast(C); + aBSplineData.EvalRep = aBSplineData.Curve->EvalRepresentation(); + myCurveData = std::move(aBSplineData); } else if (TheType == STANDARD_TYPE(Geom_OffsetCurve)) { @@ -260,6 +294,7 @@ void GeomAdaptor_Curve::load(const occ::handle& C, anOffsetData.BasisAdaptor = new GeomAdaptor_Curve(anOffsetCurve->BasisCurve()); anOffsetData.Offset = anOffsetCurve->Offset(); anOffsetData.Direction = anOffsetCurve->Direction(); + anOffsetData.EvalRep = anOffsetCurve->EvalRepresentation(); myCurveData = std::move(anOffsetData); } else @@ -656,6 +691,10 @@ std::optional GeomAdaptor_Curve::EvalD0(double U) const return P; case GeomAbs_BezierCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD0(U); + } auto& aCache = std::get(myCurveData).Cache; if (aCache.IsNull()) RebuildCache(U); @@ -664,6 +703,10 @@ std::optional GeomAdaptor_Curve::EvalD0(double U) const } case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD0(U); + } int aStart = 0, aFinish = 0; auto& aBSplData = std::get(myCurveData); if (IsBoundary(U, aStart, aFinish)) @@ -680,6 +723,10 @@ std::optional GeomAdaptor_Curve::EvalD0(double U) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD0(U); + } const auto& anOffsetData = std::get(myCurveData); if (!Geom_OffsetCurveUtils::EvaluateD0(U, anOffsetData.BasisAdaptor.get(), @@ -736,6 +783,10 @@ std::optional GeomAdaptor_Curve::EvalD1(double U) const return aResult; case GeomAbs_BezierCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD1(U); + } auto& aCache = std::get(myCurveData).Cache; if (aCache.IsNull()) RebuildCache(U); @@ -744,6 +795,10 @@ std::optional GeomAdaptor_Curve::EvalD1(double U) const } case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD1(U); + } int aStart = 0, aFinish = 0; auto& aBSplData = std::get(myCurveData); if (IsBoundary(U, aStart, aFinish)) @@ -760,6 +815,10 @@ std::optional GeomAdaptor_Curve::EvalD1(double U) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD1(U); + } const auto& anOffsetData = std::get(myCurveData); if (!Geom_OffsetCurveUtils::EvaluateD1(U, anOffsetData.BasisAdaptor.get(), @@ -819,6 +878,10 @@ std::optional GeomAdaptor_Curve::EvalD2(double U) const return aResult; case GeomAbs_BezierCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD2(U); + } auto& aCache = std::get(myCurveData).Cache; if (aCache.IsNull()) RebuildCache(U); @@ -827,6 +890,10 @@ std::optional GeomAdaptor_Curve::EvalD2(double U) const } case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD2(U); + } int aStart = 0, aFinish = 0; auto& aBSplData = std::get(myCurveData); if (IsBoundary(U, aStart, aFinish)) @@ -843,6 +910,10 @@ std::optional GeomAdaptor_Curve::EvalD2(double U) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD2(U); + } const auto& anOffsetData = std::get(myCurveData); if (!Geom_OffsetCurveUtils::EvaluateD2(U, anOffsetData.BasisAdaptor.get(), @@ -921,6 +992,10 @@ std::optional GeomAdaptor_Curve::EvalD3(double U) const return aResult; case GeomAbs_BezierCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD3(U); + } auto& aCache = std::get(myCurveData).Cache; if (aCache.IsNull()) RebuildCache(U); @@ -929,6 +1004,10 @@ std::optional GeomAdaptor_Curve::EvalD3(double U) const } case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD3(U); + } int aStart = 0, aFinish = 0; auto& aBSplData = std::get(myCurveData); if (IsBoundary(U, aStart, aFinish)) @@ -946,6 +1025,10 @@ std::optional GeomAdaptor_Curve::EvalD3(double U) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalD3(U); + } const auto& anOffsetData = std::get(myCurveData); if (!Geom_OffsetCurveUtils::EvaluateD3(U, anOffsetData.BasisAdaptor.get(), @@ -1001,6 +1084,10 @@ std::optional GeomAdaptor_Curve::EvalDN(double U, int N) const return myCurve->EvalDN(U, N); case GeomAbs_BSplineCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalDN(U, N); + } int aStart = 0, aFinish = 0; if (IsBoundary(U, aStart, aFinish)) { @@ -1011,6 +1098,10 @@ std::optional GeomAdaptor_Curve::EvalDN(double U, int N) const } case GeomAbs_OffsetCurve: { + if (hasEvalRep(myCurveData)) + { + return myCurve->EvalDN(U, N); + } const auto& anOffsetData = std::get(myCurveData); gp_Vec aDN; if (!Geom_OffsetCurveUtils::EvaluateDN(U, diff --git a/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Curve.hxx b/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Curve.hxx index d3d4feaa8b..b7b26b4329 100644 --- a/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Curve.hxx +++ b/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Curve.hxx @@ -34,6 +34,12 @@ #include class Geom_BSplineCurve; +class Geom_BezierCurve; + +namespace Geom_EvalRepCurveDesc +{ +class Base; +} //! This class provides an interface between the services provided by any //! curve from the package Geom and those required of the curve by algorithms which use it. @@ -49,22 +55,26 @@ public: //! Internal structure for offset curve evaluation data. struct OffsetData { - occ::handle BasisAdaptor; //!< Adaptor for basis curve - double Offset = 0.0; //!< Offset distance - gp_Dir Direction; //!< Offset direction + occ::handle BasisAdaptor; //!< Adaptor for basis curve + double Offset = 0.0; //!< Offset distance + gp_Dir Direction; //!< Offset direction + occ::handle EvalRep; //!< Eval representation descriptor }; //! Internal structure for Bezier curve cache data. struct BezierData { - mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle Curve; //!< Bezier curve to prevent downcasts + mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle EvalRep; //!< Eval representation descriptor }; //! Internal structure for BSpline curve cache data. struct BSplineData { - occ::handle Curve; //!< BSpline curve to prevent downcasts - mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle Curve; //!< BSpline curve to prevent downcasts + mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle EvalRep; //!< Eval representation descriptor }; //! Variant type for curve-specific evaluation data. diff --git a/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Surface.cxx b/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Surface.cxx index ca4b752583..95c22bb1e8 100644 --- a/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Surface.cxx +++ b/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Surface.cxx @@ -75,6 +75,35 @@ IMPLEMENT_STANDARD_RTTIEXT(GeomAdaptor_Surface, Adaptor3d_Surface) namespace { +bool hasEvalRep(const GeomAdaptor_Surface::SurfaceDataVariant& theData) +{ + if (const GeomAdaptor_Surface::BezierData* aBezierData = + std::get_if(&theData)) + { + return !aBezierData->EvalRep.IsNull(); + } + if (const GeomAdaptor_Surface::BSplineData* aBSplineData = + std::get_if(&theData)) + { + return !aBSplineData->EvalRep.IsNull(); + } + if (const GeomAdaptor_Surface::ExtrusionData* anExtrusionData = + std::get_if(&theData)) + { + return !anExtrusionData->EvalRep.IsNull(); + } + if (const GeomAdaptor_Surface::RevolutionData* aRevolutionData = + std::get_if(&theData)) + { + return !aRevolutionData->EvalRep.IsNull(); + } + if (const GeomAdaptor_Surface::OffsetData* anOffsetData = + std::get_if(&theData)) + { + return !anOffsetData->EvalRep.IsNull(); + } + return false; +} //================================================================================================= @@ -320,6 +349,7 @@ occ::handle GeomAdaptor_Surface::ShallowCopy() const GeomAdaptor_Surface::ExtrusionData aNewData; aNewData.BasisCurve = anExtrusionData->BasisCurve->ShallowCopy(); aNewData.Direction = anExtrusionData->Direction; + aNewData.EvalRep = anExtrusionData->EvalRep; aCopy->mySurfaceData = aNewData; } else if (auto* aRevolutionData = std::get_if(&mySurfaceData)) @@ -327,6 +357,7 @@ occ::handle GeomAdaptor_Surface::ShallowCopy() const GeomAdaptor_Surface::RevolutionData aNewData; aNewData.BasisCurve = aRevolutionData->BasisCurve->ShallowCopy(); aNewData.Axis = aRevolutionData->Axis; + aNewData.EvalRep = aRevolutionData->EvalRep; aCopy->mySurfaceData = aNewData; } else if (auto* anOffsetData = std::get_if(&mySurfaceData)) @@ -341,15 +372,24 @@ occ::handle GeomAdaptor_Surface::ShallowCopy() const } aNewData.OffsetSurface = anOffsetData->OffsetSurface; // Shared handle to original surface aNewData.Offset = anOffsetData->Offset; + aNewData.EvalRep = anOffsetData->EvalRep; aCopy->mySurfaceData = std::move(aNewData); } else if (auto* aBSplineData = std::get_if(&mySurfaceData)) { GeomAdaptor_Surface::BSplineData aNewData; aNewData.Surface = aBSplineData->Surface; + aNewData.EvalRep = aBSplineData->EvalRep; // Cache is not copied - will be rebuilt on demand aCopy->mySurfaceData = aNewData; } + else if (auto* aBezierData = std::get_if(&mySurfaceData)) + { + GeomAdaptor_Surface::BezierData aNewData; + aNewData.Surface = aBezierData->Surface; + aNewData.EvalRep = aBezierData->EvalRep; + aCopy->mySurfaceData = aNewData; + } else { // Elementary surface types (gp_Pln, gp_Cylinder, etc.) are value types - direct copy @@ -424,6 +464,7 @@ void GeomAdaptor_Surface::load(const occ::handle& S, GeomAdaptor_Surface::RevolutionData aRevData; aRevData.BasisCurve = new GeomAdaptor_Curve(aRevSurf->BasisCurve()); aRevData.Axis = aRevSurf->Axis(); + aRevData.EvalRep = aRevSurf->EvalRepresentation(); mySurfaceData = aRevData; } else if (TheType == STANDARD_TYPE(Geom_SurfaceOfLinearExtrusion)) @@ -435,18 +476,23 @@ void GeomAdaptor_Surface::load(const occ::handle& S, GeomAdaptor_Surface::ExtrusionData anExtData; anExtData.BasisCurve = new GeomAdaptor_Curve(anExtSurf->BasisCurve()); anExtData.Direction = anExtSurf->Direction().XYZ(); + anExtData.EvalRep = anExtSurf->EvalRepresentation(); mySurfaceData = anExtData; } else if (TheType == STANDARD_TYPE(Geom_BezierSurface)) { mySurfaceType = GeomAbs_BezierSurface; - mySurfaceData = GeomAdaptor_Surface::BezierData{}; + GeomAdaptor_Surface::BezierData aBezierData; + aBezierData.Surface = occ::down_cast(mySurface); + aBezierData.EvalRep = aBezierData.Surface->EvalRepresentation(); + mySurfaceData = std::move(aBezierData); } else if (TheType == STANDARD_TYPE(Geom_BSplineSurface)) { mySurfaceType = GeomAbs_BSplineSurface; GeomAdaptor_Surface::BSplineData aBSplineData; aBSplineData.Surface = occ::down_cast(mySurface); + aBSplineData.EvalRep = aBSplineData.Surface->EvalRepresentation(); mySurfaceData = aBSplineData; } else if (TheType == STANDARD_TYPE(Geom_OffsetSurface)) @@ -464,6 +510,7 @@ void GeomAdaptor_Surface::load(const occ::handle& S, myTolV); anOffsetData.OffsetSurface = anOffSurf; anOffsetData.Offset = anOffSurf->Offset(); + anOffsetData.EvalRep = anOffSurf->EvalRepresentation(); // Check if equivalent canonical surface exists for faster evaluation occ::handle anEquivSurf = anOffSurf->Surface(); if (!anEquivSurf.IsNull()) @@ -1015,6 +1062,10 @@ std::optional GeomAdaptor_Surface::EvalD0(double U, double V) const return P; case GeomAbs_BezierSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD0(U, V); + } auto& aCache = std::get(mySurfaceData).Cache; if (aCache.IsNull()) RebuildCache(U, V); @@ -1022,6 +1073,10 @@ std::optional GeomAdaptor_Surface::EvalD0(double U, double V) const return P; } case GeomAbs_BSplineSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD0(U, V); + } auto& aCache = std::get(mySurfaceData).Cache; if (aCache.IsNull() || !aCache->IsCacheValid(U, V)) RebuildCache(U, V); @@ -1030,6 +1085,10 @@ std::optional GeomAdaptor_Surface::EvalD0(double U, double V) const } case GeomAbs_SurfaceOfExtrusion: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD0(U, V); + } const auto& anExtData = std::get(mySurfaceData); if (!Geom_ExtrusionUtils::D0(U, V, *anExtData.BasisCurve, anExtData.Direction, P)) return std::nullopt; @@ -1037,6 +1096,10 @@ std::optional GeomAdaptor_Surface::EvalD0(double U, double V) const } case GeomAbs_SurfaceOfRevolution: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD0(U, V); + } const auto& aRevData = std::get(mySurfaceData); if (!Geom_RevolutionUtils::D0(U, V, *aRevData.BasisCurve, aRevData.Axis, P)) return std::nullopt; @@ -1044,6 +1107,10 @@ std::optional GeomAdaptor_Surface::EvalD0(double U, double V) const } case GeomAbs_OffsetSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD0(U, V); + } const auto& anOffData = std::get(mySurfaceData); if (!offsetD0(U, V, anOffData, P)) return std::nullopt; @@ -1123,6 +1190,10 @@ std::optional GeomAdaptor_Surface::EvalD1(double U, double return aResult; case GeomAbs_BezierSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD1(U, V); + } auto& aCache = std::get(mySurfaceData).Cache; if (aCache.IsNull()) RebuildCache(U, V); @@ -1130,6 +1201,10 @@ std::optional GeomAdaptor_Surface::EvalD1(double U, double return aResult; } case GeomAbs_BSplineSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD1(U, V); + } auto& aBSplData = std::get(mySurfaceData); const auto& aBSpl = aBSplData.Surface; if ((USide != 0 || VSide != 0) && IfUVBound(u, v, Ideb, Ifin, IVdeb, IVfin, USide, VSide)) @@ -1144,6 +1219,10 @@ std::optional GeomAdaptor_Surface::EvalD1(double U, double } case GeomAbs_SurfaceOfExtrusion: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD1(U, V); + } const auto& anExtData = std::get(mySurfaceData); if (!Geom_ExtrusionUtils::D1(u, v, @@ -1157,6 +1236,10 @@ std::optional GeomAdaptor_Surface::EvalD1(double U, double } case GeomAbs_SurfaceOfRevolution: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD1(U, V); + } const auto& aRevData = std::get(mySurfaceData); if (!Geom_RevolutionUtils::D1(u, v, @@ -1170,6 +1253,10 @@ std::optional GeomAdaptor_Surface::EvalD1(double U, double } case GeomAbs_OffsetSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD1(U, V); + } const auto& anOffData = std::get(mySurfaceData); if (!offsetD1(u, v, anOffData, aResult.Point, aResult.D1U, aResult.D1V)) return std::nullopt; @@ -1285,6 +1372,10 @@ std::optional GeomAdaptor_Surface::EvalD2(double U, double return aResult; case GeomAbs_BezierSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD2(U, V); + } auto& aCache = std::get(mySurfaceData).Cache; if (aCache.IsNull()) RebuildCache(U, V); @@ -1293,6 +1384,10 @@ std::optional GeomAdaptor_Surface::EvalD2(double U, double return aResult; } case GeomAbs_BSplineSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD2(U, V); + } auto& aBSplData = std::get(mySurfaceData); const auto& aBSpl = aBSplData.Surface; if ((USide != 0 || VSide != 0) && IfUVBound(u, v, Ideb, Ifin, IVdeb, IVfin, USide, VSide)) @@ -1325,6 +1420,10 @@ std::optional GeomAdaptor_Surface::EvalD2(double U, double } case GeomAbs_SurfaceOfExtrusion: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD2(U, V); + } const auto& anExtData = std::get(mySurfaceData); if (!Geom_ExtrusionUtils::D2(u, v, @@ -1341,6 +1440,10 @@ std::optional GeomAdaptor_Surface::EvalD2(double U, double } case GeomAbs_SurfaceOfRevolution: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD2(U, V); + } const auto& aRevData = std::get(mySurfaceData); if (!Geom_RevolutionUtils::D2(u, v, @@ -1357,6 +1460,10 @@ std::optional GeomAdaptor_Surface::EvalD2(double U, double } case GeomAbs_OffsetSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD2(U, V); + } const auto& anOffData = std::get(mySurfaceData); if (!offsetD2(u, v, @@ -1508,6 +1615,10 @@ std::optional GeomAdaptor_Surface::EvalD3(double U, double return aResult; case GeomAbs_BSplineSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD3(U, V); + } const auto& aBSpl = std::get(mySurfaceData).Surface; if ((USide == 0) && (VSide == 0)) { @@ -1547,6 +1658,10 @@ std::optional GeomAdaptor_Surface::EvalD3(double U, double } case GeomAbs_SurfaceOfExtrusion: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD3(U, V); + } const auto& anExtData = std::get(mySurfaceData); if (!Geom_ExtrusionUtils::D3(u, v, @@ -1567,6 +1682,10 @@ std::optional GeomAdaptor_Surface::EvalD3(double U, double } case GeomAbs_SurfaceOfRevolution: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD3(U, V); + } const auto& aRevData = std::get(mySurfaceData); if (!Geom_RevolutionUtils::D3(u, v, @@ -1587,6 +1706,10 @@ std::optional GeomAdaptor_Surface::EvalD3(double U, double } case GeomAbs_OffsetSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalD3(U, V); + } const auto& anOffData = std::get(mySurfaceData); if (!offsetD3(u, v, @@ -1650,6 +1773,10 @@ std::optional GeomAdaptor_Surface::EvalDN(double U, double V, int Nu, in switch (mySurfaceType) { case GeomAbs_BSplineSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalDN(U, V, Nu, Nv); + } const auto& aBSpl = std::get(mySurfaceData).Surface; if ((USide == 0) && (VSide == 0)) return aBSpl->EvalDN(u, v, Nu, Nv); @@ -1663,6 +1790,10 @@ std::optional GeomAdaptor_Surface::EvalDN(double U, double V, int Nu, in } case GeomAbs_SurfaceOfExtrusion: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalDN(U, V, Nu, Nv); + } const auto& anExtData = std::get(mySurfaceData); gp_Vec aDN; if (!Geom_ExtrusionUtils::DN(u, *anExtData.BasisCurve, anExtData.Direction, Nu, Nv, aDN)) @@ -1671,6 +1802,10 @@ std::optional GeomAdaptor_Surface::EvalDN(double U, double V, int Nu, in } case GeomAbs_SurfaceOfRevolution: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalDN(U, V, Nu, Nv); + } const auto& aRevData = std::get(mySurfaceData); gp_Vec aDN; if (!Geom_RevolutionUtils::DN(u, v, *aRevData.BasisCurve, aRevData.Axis, Nu, Nv, aDN)) @@ -1679,6 +1814,10 @@ std::optional GeomAdaptor_Surface::EvalDN(double U, double V, int Nu, in } case GeomAbs_OffsetSurface: { + if (hasEvalRep(mySurfaceData)) + { + return mySurface->EvalDN(U, V, Nu, Nv); + } const auto& anOffData = std::get(mySurfaceData); gp_Vec aDN; if (!offsetDN(u, v, anOffData, Nu, Nv, aDN)) diff --git a/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Surface.hxx b/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Surface.hxx index 5799728f64..18f9341da9 100644 --- a/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Surface.hxx +++ b/src/ModelingData/TKG3d/GeomAdaptor/GeomAdaptor_Surface.hxx @@ -37,6 +37,12 @@ class GeomAdaptor_Curve; class Geom_OffsetSurface; +class Geom_BezierSurface; + +namespace Geom_EvalRepSurfaceDesc +{ +class Base; +} //! An interface between the services provided by any //! surface from the package Geom and those required @@ -53,15 +59,17 @@ public: //! Internal structure for extrusion surface evaluation data. struct ExtrusionData { - occ::handle BasisCurve; //!< Adaptor for basis curve - gp_XYZ Direction; //!< Extrusion direction XYZ (normalized) + occ::handle BasisCurve; //!< Adaptor for basis curve + gp_XYZ Direction; //!< Extrusion direction XYZ (normalized) + occ::handle EvalRep; //!< Eval representation descriptor }; //! Internal structure for revolution surface evaluation data. struct RevolutionData { - occ::handle BasisCurve; //!< Adaptor for basis curve - gp_Ax1 Axis; //!< Revolution axis + occ::handle BasisCurve; //!< Adaptor for basis curve + gp_Ax1 Axis; //!< Revolution axis + occ::handle EvalRep; //!< Eval representation descriptor }; //! Internal structure for offset surface evaluation data. @@ -73,19 +81,23 @@ public: occ::handle OffsetSurface; //!< Original offset surface for osculating queries double Offset = 0.0; //!< Offset distance + occ::handle EvalRep; //!< Eval representation descriptor }; //! Internal structure for Bezier surface cache data. struct BezierData { - mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle Surface; //!< Bezier surface to prevent downcasts + mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle EvalRep; //!< Eval representation descriptor }; //! Internal structure for BSpline surface cache data. struct BSplineData { - occ::handle Surface; //!< BSpline surface to prevent downcasts - mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle Surface; //!< BSpline surface to prevent downcasts + mutable occ::handle Cache; //!< Cached data for evaluation + occ::handle EvalRep; //!< Eval representation descriptor }; //! Variant type for surface-specific evaluation data.