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
This commit is contained in:
Pasukhin Dmitry
2026-02-15 09:26:56 +00:00
committed by GitHub
parent c9bdc4b9f1
commit 13d6dfc2e7
38 changed files with 3046 additions and 150 deletions
@@ -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
@@ -28,6 +28,8 @@
#include <BSplCLib.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include "Geom2d_EvalRepCurveDesc.hxx"
#include "Geom2d_EvalRepUtils.pxx"
#include <Geom2d_Geometry.hxx>
#include <Geom2d_UndefinedDerivative.hxx>
#include <gp.hxx>
@@ -39,12 +41,22 @@
#include <Standard_NoSuchObject.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_OutOfRange.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_Type.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Geom2d_BSplineCurve, Geom2d_BoundedCurve)
//=================================================================================================
void Geom2d_BSplineCurve::SetEvalRepresentation(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc)
{
Geom2d_EvalRepUtils::ValidateCurveDesc(theDesc, this);
myEvalRep = theDesc;
}
//=================================================================================================
static void CheckCurveData(const NCollection_Array1<gp_Pnt2d>& CPoles,
const NCollection_Array1<double>& CKnots,
const NCollection_Array1<int>& 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),
@@ -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<Geom2d_EvalRepCurveDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& 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<gp_Pnt2d> myPoles;
NCollection_Array1<double> myWeights;
NCollection_Array1<double> myKnots;
NCollection_Array1<double> myFlatKnots;
NCollection_Array1<int> 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<gp_Pnt2d> myPoles;
NCollection_Array1<double> myWeights;
NCollection_Array1<double> myKnots;
NCollection_Array1<double> myFlatKnots;
NCollection_Array1<int> myMults;
occ::handle<Geom2d_EvalRepCurveDesc::Base> 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
@@ -16,6 +16,8 @@
#include <BSplCLib.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include "Geom2d_EvalRepCurveDesc.hxx"
#include "Geom2d_EvalRepUtils.pxx"
#include <Geom2d_UndefinedDerivative.hxx>
#include <gp.hxx>
#include <gp_Pnt2d.hxx>
@@ -160,6 +162,13 @@ int Geom2d_BSplineCurve::Degree() const
std::optional<gp_Pnt2d> Geom2d_BSplineCurve::EvalD0(const double U) const
{
if (const std::optional<gp_Pnt2d> 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<gp_Pnt2d> Geom2d_BSplineCurve::EvalD0(const double U) const
std::optional<Geom2d_Curve::ResD1> Geom2d_BSplineCurve::EvalD1(const double U) const
{
if (const std::optional<Geom2d_Curve::ResD1> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD1(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD1> aResult{std::in_place};
int aSpanIndex = 0;
double aNewU(U);
@@ -201,6 +217,13 @@ std::optional<Geom2d_Curve::ResD1> Geom2d_BSplineCurve::EvalD1(const double U) c
std::optional<Geom2d_Curve::ResD2> Geom2d_BSplineCurve::EvalD2(const double U) const
{
if (const std::optional<Geom2d_Curve::ResD2> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD2(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD2> aResult{std::in_place};
int aSpanIndex = 0;
double aNewU(U);
@@ -227,6 +250,13 @@ std::optional<Geom2d_Curve::ResD2> Geom2d_BSplineCurve::EvalD2(const double U) c
std::optional<Geom2d_Curve::ResD3> Geom2d_BSplineCurve::EvalD3(const double U) const
{
if (const std::optional<Geom2d_Curve::ResD3> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD3(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD3> aResult{std::in_place};
int aSpanIndex = 0;
double aNewU(U);
@@ -256,6 +286,14 @@ std::optional<gp_Vec2d> Geom2d_BSplineCurve::EvalDN(const double U, const int N)
{
if (N < 1)
return std::nullopt;
if (const std::optional<gp_Vec2d> 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;
@@ -24,6 +24,8 @@
// Suppressed Swaps, added Init, removed typedefs
#include <Geom2d_BezierCurve.hxx>
#include "Geom2d_EvalRepCurveDesc.hxx"
#include "Geom2d_EvalRepUtils.pxx"
#include <Geom2d_Geometry.hxx>
#include <gp.hxx>
#include <gp_Pnt2d.hxx>
@@ -33,6 +35,7 @@
#include <Standard_ConstructionError.hxx>
#include <Standard_DimensionError.hxx>
#include <Standard_OutOfRange.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_RangeError.hxx>
#include <Standard_Type.hxx>
#include <Standard_Integer.hxx>
@@ -43,6 +46,15 @@ IMPLEMENT_STANDARD_RTTIEXT(Geom2d_BezierCurve, Geom2d_BoundedCurve)
//=================================================================================================
void Geom2d_BezierCurve::SetEvalRepresentation(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc)
{
Geom2d_EvalRepUtils::ValidateCurveDesc(theDesc, this);
myEvalRep = theDesc;
}
//=================================================================================================
static bool Rational(const NCollection_Array1<double>& 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<double>(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<gp_Pnt2d> Geom2d_BezierCurve::EvalD0(const double U) const
{
if (const std::optional<gp_Pnt2d> 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<gp_Pnt2d> Geom2d_BezierCurve::EvalD0(const double U) const
std::optional<Geom2d_Curve::ResD1> Geom2d_BezierCurve::EvalD1(const double U) const
{
if (const std::optional<Geom2d_Curve::ResD1> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD1(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD1> aResult{std::in_place};
BSplCLib::D1(U, Poles(), Weights(), aResult->Point, aResult->D1);
return aResult;
@@ -464,6 +491,13 @@ std::optional<Geom2d_Curve::ResD1> Geom2d_BezierCurve::EvalD1(const double U) co
std::optional<Geom2d_Curve::ResD2> Geom2d_BezierCurve::EvalD2(const double U) const
{
if (const std::optional<Geom2d_Curve::ResD2> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD2(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD2> aResult{std::in_place};
BSplCLib::D2(U, Poles(), Weights(), aResult->Point, aResult->D1, aResult->D2);
return aResult;
@@ -473,6 +507,13 @@ std::optional<Geom2d_Curve::ResD2> Geom2d_BezierCurve::EvalD2(const double U) co
std::optional<Geom2d_Curve::ResD3> Geom2d_BezierCurve::EvalD3(const double U) const
{
if (const std::optional<Geom2d_Curve::ResD3> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD3(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD3> 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<gp_Vec2d> Geom2d_BezierCurve::EvalDN(const double U, const int N)
{
if (N < 1)
return std::nullopt;
if (const std::optional<gp_Vec2d> 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<gp_Pnt2d>& thePoles,
myMaxDerivInv = 0.0;
myMaxDerivInvOk = false;
ClearEvalRepresentation();
}
//=================================================================================================
@@ -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<Geom2d_EvalRepCurveDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc);
//! Removes the evaluation representation.
void ClearEvalRepresentation() { myEvalRep.Nullify(); }
//! Increases the degree of a bezier curve. Degree is the new
//! degree of <me>.
//! raises ConstructionError if Degree is greater than MaxDegree or lower than 2
@@ -321,12 +340,13 @@ protected:
const NCollection_Array1<double>* theWeights);
private:
NCollection_Array1<gp_Pnt2d> myPoles;
NCollection_Array1<double> myWeights;
bool myRational = false;
bool myClosed = false;
double myMaxDerivInv = 0.0;
bool myMaxDerivInvOk = false;
NCollection_Array1<gp_Pnt2d> myPoles;
NCollection_Array1<double> myWeights;
occ::handle<Geom2d_EvalRepCurveDesc::Base> myEvalRep;
bool myRational = false;
bool myClosed = false;
double myMaxDerivInv = 0.0;
bool myMaxDerivInvOk = false;
};
#endif // _Geom2d_BezierCurve_HeaderFile
@@ -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 <Geom2d_Curve.hxx>
#include <Precision.hxx>
#include <Standard_Transient.hxx>
#include <cmath>
#include <cstddef>
#include <optional>
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<Geom2d_Curve> 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<Domain1d> 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
@@ -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 <Geom2d_Curve.hxx>
#include <Standard_ProgramError.hxx>
#include <cmath>
#include <optional>
namespace Geom2d_EvalRepUtils
{
occ::handle<Geom2d_EvalRepCurveDesc::Base> CloneCurveDesc(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc);
std::optional<gp_Pnt2d> TryEvalCurveD0(const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc,
const double theU);
std::optional<Geom2d_Curve::ResD1> TryEvalCurveD1(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc,
const double theU);
std::optional<Geom2d_Curve::ResD2> TryEvalCurveD2(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc,
const double theU);
std::optional<Geom2d_Curve::ResD3> TryEvalCurveD3(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc,
const double theU);
std::optional<gp_Vec2d> TryEvalCurveDN(const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc,
const double theU,
const int theN);
std::optional<gp_Pnt2d> TryEvalCurveD0Mapped(const Geom2d_EvalRepCurveDesc::Mapped& theDesc,
const double theU);
std::optional<Geom2d_Curve::ResD1> TryEvalCurveD1Mapped(
const Geom2d_EvalRepCurveDesc::Mapped& theDesc,
const double theU);
std::optional<Geom2d_Curve::ResD2> TryEvalCurveD2Mapped(
const Geom2d_EvalRepCurveDesc::Mapped& theDesc,
const double theU);
std::optional<Geom2d_Curve::ResD3> TryEvalCurveD3Mapped(
const Geom2d_EvalRepCurveDesc::Mapped& theDesc,
const double theU);
std::optional<gp_Vec2d> TryEvalCurveDNMapped(const Geom2d_EvalRepCurveDesc::Mapped& theDesc,
const double theU,
const int theN);
void ValidateCurveDesc(const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc,
const Geom2d_Curve* theOwner);
} // namespace Geom2d_EvalRepUtils
//==================================================================================================
inline void Geom2d_EvalRepUtils::ValidateCurveDesc(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& 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<const Geom2d_EvalRepCurveDesc::Mapped*>(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_EvalRepCurveDesc::Base> Geom2d_EvalRepUtils::CloneCurveDesc(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc)
{
if (theDesc.IsNull() || theDesc->Representation.IsNull())
{
return occ::handle<Geom2d_EvalRepCurveDesc::Base>();
}
const occ::handle<Geom2d_Curve> aRepCopy =
occ::down_cast<Geom2d_Curve>(theDesc->Representation->Copy());
if (aRepCopy.IsNull())
{
return occ::handle<Geom2d_EvalRepCurveDesc::Base>();
}
switch (theDesc->GetKind())
{
case Geom2d_EvalRepCurveDesc::Base::Kind::Full: {
occ::handle<Geom2d_EvalRepCurveDesc::Full> aClone = new Geom2d_EvalRepCurveDesc::Full();
aClone->Representation = aRepCopy;
return aClone;
}
case Geom2d_EvalRepCurveDesc::Base::Kind::DerivBounded: {
const auto* aSrc = static_cast<const Geom2d_EvalRepCurveDesc::DerivBounded*>(theDesc.get());
occ::handle<Geom2d_EvalRepCurveDesc::DerivBounded> 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<const Geom2d_EvalRepCurveDesc::Mapped*>(theDesc.get());
occ::handle<Geom2d_EvalRepCurveDesc::Mapped> 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<Geom2d_EvalRepCurveDesc::Base>();
}
//==================================================================================================
inline std::optional<gp_Pnt2d> Geom2d_EvalRepUtils::TryEvalCurveD0(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& 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<const Geom2d_EvalRepCurveDesc::Mapped*>(theDesc.get()),
theU);
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<Geom2d_Curve::ResD1> Geom2d_EvalRepUtils::TryEvalCurveD1(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& 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<const Geom2d_EvalRepCurveDesc::DerivBounded*>(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<const Geom2d_EvalRepCurveDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < 1)
return std::nullopt;
return TryEvalCurveD1Mapped(*aMapped, theU);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<Geom2d_Curve::ResD2> Geom2d_EvalRepUtils::TryEvalCurveD2(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& 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<const Geom2d_EvalRepCurveDesc::DerivBounded*>(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<const Geom2d_EvalRepCurveDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < 2)
return std::nullopt;
return TryEvalCurveD2Mapped(*aMapped, theU);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<Geom2d_Curve::ResD3> Geom2d_EvalRepUtils::TryEvalCurveD3(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& 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<const Geom2d_EvalRepCurveDesc::DerivBounded*>(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<const Geom2d_EvalRepCurveDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < 3)
return std::nullopt;
return TryEvalCurveD3Mapped(*aMapped, theU);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<gp_Vec2d> Geom2d_EvalRepUtils::TryEvalCurveDN(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& 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<const Geom2d_EvalRepCurveDesc::DerivBounded*>(theDesc.get());
if (aBounded->MaxDerivOrder < static_cast<std::size_t>(theN))
return std::nullopt;
return theDesc->Representation->EvalDN(theU, theN);
}
case Geom2d_EvalRepCurveDesc::Base::Kind::Mapped: {
const auto* aMapped = static_cast<const Geom2d_EvalRepCurveDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < static_cast<std::size_t>(theN))
return std::nullopt;
return TryEvalCurveDNMapped(*aMapped, theU, theN);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<gp_Pnt2d> 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_Curve::ResD1> 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<Geom2d_Curve::ResD1> 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_Curve::ResD2> 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<Geom2d_Curve::ResD2> 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_Curve::ResD3> 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<Geom2d_Curve::ResD3> 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<gp_Vec2d> 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<gp_Vec2d> 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
@@ -19,6 +19,8 @@
#include <Geom2d_BezierCurve.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Curve.hxx>
#include "Geom2d_EvalRepCurveDesc.hxx"
#include "Geom2d_EvalRepUtils.pxx"
#include <Geom2d_Geometry.hxx>
#include <Geom2d_OffsetCurve.hxx>
#include <Geom2d_OffsetCurveUtils.pxx>
@@ -33,6 +35,7 @@
#include <Precision.hxx>
#include <Standard_ConstructionError.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_RangeError.hxx>
#include <Standard_Type.hxx>
@@ -42,6 +45,15 @@ static const double MyAngularToleranceForG1 = Precision::Angular();
//==================================================================================================
void Geom2d_OffsetCurve::SetEvalRepresentation(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc)
{
Geom2d_EvalRepUtils::ValidateCurveDesc(theDesc, this);
myEvalRep = theDesc;
}
//==================================================================================================
occ::handle<Geom2d_Geometry> Geom2d_OffsetCurve::Copy() const
{
return new Geom2d_OffsetCurve(*this);
@@ -64,17 +76,19 @@ Geom2d_OffsetCurve::Geom2d_OffsetCurve(const occ::handle<Geom2d_Curve>& theCurve
//==================================================================================================
Geom2d_OffsetCurve::Geom2d_OffsetCurve(const Geom2d_OffsetCurve& theOther)
: offsetValue(theOther.offsetValue),
: basisCurve(occ::down_cast<Geom2d_Curve>(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<Geom2d_Curve>(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<Geom2d_Curve>& C, const bool isNotCheckC0)
{
ClearEvalRepresentation();
const double aUf = C->FirstParameter(), aUl = C->LastParameter();
occ::handle<Geom2d_Curve> aCheckingCurve = C;
bool isTrimmed = false;
@@ -149,6 +164,7 @@ void Geom2d_OffsetCurve::SetBasisCurve(const occ::handle<Geom2d_Curve>& C, const
void Geom2d_OffsetCurve::SetOffsetValue(const double D)
{
ClearEvalRepresentation();
offsetValue = D;
}
@@ -196,6 +212,13 @@ GeomAbs_Shape Geom2d_OffsetCurve::Continuity() const
std::optional<gp_Pnt2d> Geom2d_OffsetCurve::EvalD0(const double theU) const
{
if (const std::optional<gp_Pnt2d> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD0(myEvalRep, theU);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD1> aBasisD1 = basisCurve->EvalD1(theU);
if (!aBasisD1)
return std::nullopt;
@@ -209,6 +232,13 @@ std::optional<gp_Pnt2d> Geom2d_OffsetCurve::EvalD0(const double theU) const
std::optional<Geom2d_Curve::ResD1> Geom2d_OffsetCurve::EvalD1(const double theU) const
{
if (const std::optional<Geom2d_Curve::ResD1> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD1(myEvalRep, theU);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD2> aBasisD2 = basisCurve->EvalD2(theU);
if (!aBasisD2)
return std::nullopt;
@@ -223,6 +253,13 @@ std::optional<Geom2d_Curve::ResD1> Geom2d_OffsetCurve::EvalD1(const double theU)
std::optional<Geom2d_Curve::ResD2> Geom2d_OffsetCurve::EvalD2(const double theU) const
{
if (const std::optional<Geom2d_Curve::ResD2> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD2(myEvalRep, theU);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD3> aBasisD3 = basisCurve->EvalD3(theU);
if (!aBasisD3)
return std::nullopt;
@@ -251,6 +288,13 @@ std::optional<Geom2d_Curve::ResD2> Geom2d_OffsetCurve::EvalD2(const double theU)
std::optional<Geom2d_Curve::ResD3> Geom2d_OffsetCurve::EvalD3(const double theU) const
{
if (const std::optional<Geom2d_Curve::ResD3> aEvalRepResult =
Geom2d_EvalRepUtils::TryEvalCurveD3(myEvalRep, theU);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom2d_Curve::ResD3> aBasisD3 = basisCurve->EvalD3(theU);
if (!aBasisD3)
return std::nullopt;
@@ -290,6 +334,12 @@ std::optional<gp_Vec2d> Geom2d_OffsetCurve::EvalDN(const double U, const int N)
{
if (N < 1)
return std::nullopt;
if (const std::optional<gp_Vec2d> 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());
}
@@ -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<Geom2d_EvalRepCurveDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom2d_EvalRepCurveDesc::Base>& theDesc);
//! Removes the evaluation representation.
void ClearEvalRepresentation() { myEvalRep.Nullify(); }
//! Changes the direction of parametrization of <me>.
//! As a result:
//! - the basis curve is reversed,
@@ -275,9 +294,10 @@ public:
DEFINE_STANDARD_RTTIEXT(Geom2d_OffsetCurve, Geom2d_Curve)
private:
occ::handle<Geom2d_Curve> basisCurve;
double offsetValue;
GeomAbs_Shape myBasisCurveContinuity;
occ::handle<Geom2d_Curve> basisCurve;
occ::handle<Geom2d_EvalRepCurveDesc::Base> myEvalRep;
double offsetValue;
GeomAbs_Shape myBasisCurveContinuity;
};
#endif // _Geom2d_OffsetCurve_HeaderFile
@@ -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<Geom2dAdaptor_Curve::BezierData>(&theData))
{
return !aBezierData->EvalRep.IsNull();
}
if (const Geom2dAdaptor_Curve::BSplineData* aBSplineData =
std::get_if<Geom2dAdaptor_Curve::BSplineData>(&theData))
{
return !aBSplineData->EvalRep.IsNull();
}
if (const Geom2dAdaptor_Curve::OffsetData* anOffsetData =
std::get_if<Geom2dAdaptor_Curve::OffsetData>(&theData))
{
return !anOffsetData->EvalRep.IsNull();
}
return false;
}
} // namespace
//=================================================================================================
occ::handle<Adaptor2d_Curve2d> Geom2dAdaptor_Curve::ShallowCopy() const
@@ -82,17 +105,24 @@ occ::handle<Adaptor2d_Curve2d> Geom2dAdaptor_Curve::ShallowCopy() const
occ::down_cast<Geom2dAdaptor_Curve>(anOffsetData->BasisAdaptor->ShallowCopy());
}
aNewData.Offset = anOffsetData->Offset;
aNewData.EvalRep = anOffsetData->EvalRep;
aCopy->myCurveData = std::move(aNewData);
}
else if (const auto* aBSplineData = std::get_if<BSplineData>(&myCurveData))
{
BSplineData aNewData;
aNewData.Curve = aBSplineData->Curve;
aNewData.EvalRep = aBSplineData->EvalRep;
aCopy->myCurveData = std::move(aNewData);
}
else if (std::holds_alternative<BezierData>(myCurveData))
{
aCopy->myCurveData = BezierData{};
const BezierData& aBezierData = std::get<BezierData>(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<Geom2d_Curve>& C,
else if (TheType == STANDARD_TYPE(Geom2d_BezierCurve))
{
myTypeCurve = GeomAbs_BezierCurve;
myCurveData = BezierData{};
BezierData aBezierData;
aBezierData.Curve = occ::down_cast<Geom2d_BezierCurve>(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<Geom2d_BSplineCurve>(myCurve);
myCurveData = std::move(aBSplineData);
aBSplineData.Curve = occ::down_cast<Geom2d_BSplineCurve>(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<Geom2d_Curve>& 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<gp_Pnt2d> Geom2dAdaptor_Curve::EvalD0(double U) const
return P;
case GeomAbs_BezierCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD0(U);
}
auto& aBezierData = std::get<BezierData>(myCurveData);
if (aBezierData.Cache.IsNull())
RebuildCache(U);
@@ -690,6 +729,10 @@ std::optional<gp_Pnt2d> 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<BSplineData>(myCurveData);
if (IsBoundary(U, aStart, aFinish))
@@ -706,6 +749,10 @@ std::optional<gp_Pnt2d> Geom2dAdaptor_Curve::EvalD0(double U) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD0(U);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
if (!Geom2d_OffsetCurveUtils::EvaluateD0(U,
anOffsetData.BasisAdaptor.get(),
@@ -761,6 +808,10 @@ std::optional<Geom2d_Curve::ResD1> Geom2dAdaptor_Curve::EvalD1(double U) const
return aResult;
case GeomAbs_BezierCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD1(U);
}
auto& aBezierData = std::get<BezierData>(myCurveData);
if (aBezierData.Cache.IsNull())
RebuildCache(U);
@@ -769,6 +820,10 @@ std::optional<Geom2d_Curve::ResD1> 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<BSplineData>(myCurveData);
if (IsBoundary(U, aStart, aFinish))
@@ -785,6 +840,10 @@ std::optional<Geom2d_Curve::ResD1> Geom2dAdaptor_Curve::EvalD1(double U) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD1(U);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
if (!Geom2d_OffsetCurveUtils::EvaluateD1(U,
anOffsetData.BasisAdaptor.get(),
@@ -843,6 +902,10 @@ std::optional<Geom2d_Curve::ResD2> Geom2dAdaptor_Curve::EvalD2(double U) const
return aResult;
case GeomAbs_BezierCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD2(U);
}
auto& aBezierData = std::get<BezierData>(myCurveData);
if (aBezierData.Cache.IsNull())
RebuildCache(U);
@@ -851,6 +914,10 @@ std::optional<Geom2d_Curve::ResD2> 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<BSplineData>(myCurveData);
if (IsBoundary(U, aStart, aFinish))
@@ -867,6 +934,10 @@ std::optional<Geom2d_Curve::ResD2> Geom2dAdaptor_Curve::EvalD2(double U) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD2(U);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
if (!Geom2d_OffsetCurveUtils::EvaluateD2(U,
anOffsetData.BasisAdaptor.get(),
@@ -948,6 +1019,10 @@ std::optional<Geom2d_Curve::ResD3> Geom2dAdaptor_Curve::EvalD3(double U) const
return aResult;
case GeomAbs_BezierCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD3(U);
}
auto& aBezierData = std::get<BezierData>(myCurveData);
if (aBezierData.Cache.IsNull())
RebuildCache(U);
@@ -956,6 +1031,10 @@ std::optional<Geom2d_Curve::ResD3> 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<BSplineData>(myCurveData);
if (IsBoundary(U, aStart, aFinish))
@@ -973,6 +1052,10 @@ std::optional<Geom2d_Curve::ResD3> Geom2dAdaptor_Curve::EvalD3(double U) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD3(U);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
if (!Geom2d_OffsetCurveUtils::EvaluateD3(U,
anOffsetData.BasisAdaptor.get(),
@@ -1027,6 +1110,10 @@ std::optional<gp_Vec2d> 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<gp_Vec2d> Geom2dAdaptor_Curve::EvalDN(double U, int N) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalDN(U, N);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
gp_Vec2d aDN;
if (!Geom2d_OffsetCurveUtils::EvaluateDN(U,
@@ -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<Geom2dAdaptor_Curve> BasisAdaptor; //!< Adaptor for basis curve
double Offset = 0.0; //!< Offset distance
occ::handle<Geom2dAdaptor_Curve> BasisAdaptor; //!< Adaptor for basis curve
double Offset = 0.0; //!< Offset distance
occ::handle<Geom2d_EvalRepCurveDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Internal structure for Bezier curve evaluation data.
struct BezierData
{
mutable occ::handle<BSplCLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom2d_BezierCurve> Curve; //!< Bezier curve to prevent downcasts
mutable occ::handle<BSplCLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom2d_EvalRepCurveDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Internal structure for BSpline curve evaluation data.
struct BSplineData
{
occ::handle<Geom2d_BSplineCurve> Curve; //!< BSpline curve to prevent downcasts
mutable occ::handle<BSplCLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom2d_BSplineCurve> Curve; //!< BSpline curve to prevent downcasts
mutable occ::handle<BSplCLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom2d_EvalRepCurveDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Variant type for 2D curve-specific evaluation data.
+3
View File
@@ -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
@@ -30,6 +30,8 @@
#include <BSplCLib.hxx>
#include <ElCLib.hxx>
#include <Geom_BSplineCurve.hxx>
#include "Geom_EvalRepCurveDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include <Geom_Geometry.hxx>
#include <Geom_UndefinedDerivative.hxx>
#include <gp.hxx>
@@ -41,6 +43,7 @@
#include <Standard_NoSuchObject.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_OutOfRange.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_Real.hxx>
#include <Standard_Type.hxx>
@@ -48,6 +51,15 @@ IMPLEMENT_STANDARD_RTTIEXT(Geom_BSplineCurve, Geom_BoundedCurve)
//=================================================================================================
void Geom_BSplineCurve::SetEvalRepresentation(
const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc)
{
Geom_EvalRepUtils::ValidateCurveDesc(theDesc, this);
myEvalRep = theDesc;
}
//=================================================================================================
static void CheckCurveData(const NCollection_Array1<gp_Pnt>& CPoles,
const NCollection_Array1<double>& CKnots,
const NCollection_Array1<int>& 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<double>& Knots,
if (nbpoles == myPoles.Length())
return;
ClearEvalRepresentation();
NCollection_Array1<gp_Pnt> npoles(1, nbpoles);
NCollection_Array1<double> nknots(1, nbknots);
NCollection_Array1<int> 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<double>& 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;
}
@@ -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<Geom_EvalRepCurveDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom_EvalRepCurveDesc::Base>& 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<gp_Pnt> myPoles;
NCollection_Array1<double> myWeights;
NCollection_Array1<double> myKnots;
NCollection_Array1<double> myFlatKnots;
NCollection_Array1<int> 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<gp_Pnt> myPoles;
NCollection_Array1<double> myWeights;
NCollection_Array1<double> myKnots;
NCollection_Array1<double> myFlatKnots;
NCollection_Array1<int> myMults;
occ::handle<Geom_EvalRepCurveDesc::Base> 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
@@ -16,6 +16,8 @@
#include <BSplCLib.hxx>
#include <Geom_BSplineCurve.hxx>
#include "Geom_EvalRepCurveDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include <Geom_UndefinedDerivative.hxx>
#include <gp.hxx>
#include <gp_Pnt.hxx>
@@ -160,6 +162,12 @@ int Geom_BSplineCurve::Degree() const
std::optional<gp_Pnt> Geom_BSplineCurve::EvalD0(const double U) const
{
if (const std::optional<gp_Pnt> 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<gp_Pnt> Geom_BSplineCurve::EvalD0(const double U) const
std::optional<Geom_Curve::ResD1> Geom_BSplineCurve::EvalD1(const double U) const
{
if (const std::optional<Geom_Curve::ResD1> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD1(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD1> aResult{std::in_place};
int aSpanIndex = 0;
double aNewU(U);
@@ -201,6 +216,13 @@ std::optional<Geom_Curve::ResD1> Geom_BSplineCurve::EvalD1(const double U) const
std::optional<Geom_Curve::ResD2> Geom_BSplineCurve::EvalD2(const double U) const
{
if (const std::optional<Geom_Curve::ResD2> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD2(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD2> aResult{std::in_place};
int aSpanIndex = 0;
double aNewU(U);
@@ -227,6 +249,13 @@ std::optional<Geom_Curve::ResD2> Geom_BSplineCurve::EvalD2(const double U) const
std::optional<Geom_Curve::ResD3> Geom_BSplineCurve::EvalD3(const double U) const
{
if (const std::optional<Geom_Curve::ResD3> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD3(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD3> aResult{std::in_place};
int aSpanIndex = 0;
double aNewU(U);
@@ -256,6 +285,14 @@ std::optional<gp_Vec> Geom_BSplineCurve::EvalDN(const double U, const int N) con
{
if (N < 1)
return std::nullopt;
if (const std::optional<gp_Vec> 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;
@@ -24,6 +24,8 @@
#include <BSplCLib.hxx>
#include <BSplSLib.hxx>
#include <Geom_BSplineSurface.hxx>
#include "Geom_EvalRepSurfaceDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include <Geom_Geometry.hxx>
#include <Geom_UndefinedDerivative.hxx>
#include <gp.hxx>
@@ -34,12 +36,22 @@
#include <Standard_DomainError.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_OutOfRange.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_Type.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Geom_BSplineSurface, Geom_BoundedSurface)
//=================================================================================================
void Geom_BSplineSurface::SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc)
{
Geom_EvalRepUtils::ValidateSurfaceDesc(theDesc, this);
myEvalRep = theDesc;
}
//=================================================================================================
static void CheckSurfaceData(const NCollection_Array2<gp_Pnt>& SPoles,
const NCollection_Array1<double>& SUKnots,
const NCollection_Array1<double>& 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<gp_Pnt>& 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<double>& 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<double>& 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.
@@ -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<Geom_EvalRepSurfaceDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<gp_Pnt> myPoles;
NCollection_Array2<double> myWeights;
NCollection_Array1<double> myUKnots;
NCollection_Array1<double> myVKnots;
NCollection_Array1<double> myUFlatKnots;
NCollection_Array1<double> myVFlatKnots;
NCollection_Array1<int> myUMults;
NCollection_Array1<int> 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<gp_Pnt> myPoles;
NCollection_Array2<double> myWeights;
NCollection_Array1<double> myUKnots;
NCollection_Array1<double> myVKnots;
NCollection_Array1<double> myUFlatKnots;
NCollection_Array1<double> myVFlatKnots;
NCollection_Array1<int> myUMults;
NCollection_Array1<int> myVMults;
occ::handle<Geom_EvalRepSurfaceDesc::Base> 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
@@ -28,6 +28,8 @@
#include <Geom_BSplineCurve.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_Curve.hxx>
#include "Geom_EvalRepSurfaceDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include <Geom_UndefinedDerivative.hxx>
#include <gp_Pnt.hxx>
#include <gp_Trsf.hxx>
@@ -108,6 +110,13 @@ bool Geom_BSplineSurface::IsCNv(const int N) const
std::optional<gp_Pnt> Geom_BSplineSurface::EvalD0(const double U, const double V) const
{
if (const std::optional<gp_Pnt> 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<gp_Pnt> Geom_BSplineSurface::EvalD0(const double U, const double V
std::optional<Geom_Surface::ResD1> Geom_BSplineSurface::EvalD1(const double U, const double V) const
{
if (const std::optional<Geom_Surface::ResD1> 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_Surface::ResD1> Geom_BSplineSurface::EvalD1(const double U, c
std::optional<Geom_Surface::ResD2> Geom_BSplineSurface::EvalD2(const double U, const double V) const
{
if (const std::optional<Geom_Surface::ResD2> 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_Surface::ResD2> Geom_BSplineSurface::EvalD2(const double U, c
std::optional<Geom_Surface::ResD3> Geom_BSplineSurface::EvalD3(const double U, const double V) const
{
if (const std::optional<Geom_Surface::ResD3> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD3(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Surface::ResD3> aResult{std::in_place};
BSplSLib::D3(U,
V,
@@ -257,6 +287,14 @@ std::optional<gp_Vec> Geom_BSplineSurface::EvalDN(const double U,
{
if (Nu + Nv < 1 || Nu < 0 || Nv < 0)
return std::nullopt;
if (const std::optional<gp_Vec> 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<double>* 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<double>& Knots,
if (nbpoles == myPoles.ColLength())
return;
ClearEvalRepresentation();
NCollection_Array2<gp_Pnt> npoles(1, nbpoles, 1, myPoles.RowLength());
NCollection_Array1<double> nknots(1, nbknots);
NCollection_Array1<int> nmults(1, nbknots);
@@ -1853,6 +1908,8 @@ void Geom_BSplineSurface::InsertVKnots(const NCollection_Array1<double>& Knots,
if (nbpoles == myPoles.RowLength())
return;
ClearEvalRepresentation();
NCollection_Array2<gp_Pnt> npoles(1, myPoles.ColLength(), 1, nbpoles);
NCollection_Array1<double> nknots(1, nbknots);
NCollection_Array1<int> 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;
@@ -24,6 +24,8 @@
// Suppressed Swaps, added Init, removed typedefs
#include <Geom_BezierCurve.hxx>
#include "Geom_EvalRepCurveDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include <Geom_Geometry.hxx>
#include <gp.hxx>
#include <gp_Pnt.hxx>
@@ -35,6 +37,7 @@
#include <Standard_ConstructionError.hxx>
#include <Standard_DimensionError.hxx>
#include <Standard_OutOfRange.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_RangeError.hxx>
#include <Standard_Type.hxx>
#include <NCollection_Array1.hxx>
@@ -45,6 +48,15 @@ IMPLEMENT_STANDARD_RTTIEXT(Geom_BezierCurve, Geom_BoundedCurve)
//=================================================================================================
void Geom_BezierCurve::SetEvalRepresentation(
const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc)
{
Geom_EvalRepUtils::ValidateCurveDesc(theDesc, this);
myEvalRep = theDesc;
}
//=================================================================================================
static bool Rational(const NCollection_Array1<double>& 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<double>(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<gp_Pnt> Geom_BezierCurve::EvalD0(const double U) const
{
if (const std::optional<gp_Pnt> 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<gp_Pnt> Geom_BezierCurve::EvalD0(const double U) const
std::optional<Geom_Curve::ResD1> Geom_BezierCurve::EvalD1(const double U) const
{
if (const std::optional<Geom_Curve::ResD1> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD1(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD1> aResult{std::in_place};
BSplCLib::D1(U, Poles(), Weights(), aResult->Point, aResult->D1);
return aResult;
@@ -491,6 +517,13 @@ std::optional<Geom_Curve::ResD1> Geom_BezierCurve::EvalD1(const double U) const
std::optional<Geom_Curve::ResD2> Geom_BezierCurve::EvalD2(const double U) const
{
if (const std::optional<Geom_Curve::ResD2> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD2(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD2> aResult{std::in_place};
BSplCLib::D2(U, Poles(), Weights(), aResult->Point, aResult->D1, aResult->D2);
return aResult;
@@ -500,6 +533,13 @@ std::optional<Geom_Curve::ResD2> Geom_BezierCurve::EvalD2(const double U) const
std::optional<Geom_Curve::ResD3> Geom_BezierCurve::EvalD3(const double U) const
{
if (const std::optional<Geom_Curve::ResD3> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD3(myEvalRep, U);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD3> 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<gp_Vec> Geom_BezierCurve::EvalDN(const double U, const int N) cons
{
if (N < 1)
return std::nullopt;
if (const std::optional<gp_Vec> 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<gp_Pnt>& thePoles,
myMaxDerivInv = 0.0;
myMaxDerivInvOk = false;
ClearEvalRepresentation();
}
//=================================================================================================
@@ -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<Geom_EvalRepCurveDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc);
//! Removes the evaluation representation.
void ClearEvalRepresentation() { myEvalRep.Nullify(); }
//! Increases the degree of a bezier curve. Degree is the new
//! degree of <me>. Raises ConstructionError
//! if Degree is greater than MaxDegree or lower than 2
@@ -338,12 +357,13 @@ protected:
const NCollection_Array1<double>* theWeights);
private:
NCollection_Array1<gp_Pnt> myPoles;
NCollection_Array1<double> myWeights;
bool myRational = false;
bool myClosed = false;
double myMaxDerivInv = 0.0;
bool myMaxDerivInvOk = false;
NCollection_Array1<gp_Pnt> myPoles;
NCollection_Array1<double> myWeights;
occ::handle<Geom_EvalRepCurveDesc::Base> myEvalRep;
bool myRational = false;
bool myClosed = false;
double myMaxDerivInv = 0.0;
bool myMaxDerivInvOk = false;
};
#endif // _Geom_BezierCurve_HeaderFile
@@ -28,6 +28,8 @@
#include <BSplCLib.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_BezierSurface.hxx>
#include "Geom_EvalRepSurfaceDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include <Geom_Curve.hxx>
#include <Geom_Geometry.hxx>
#include <gp.hxx>
@@ -40,6 +42,7 @@
#include <Standard_ConstructionError.hxx>
#include <Standard_DimensionError.hxx>
#include <Standard_OutOfRange.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_RangeError.hxx>
#include <Standard_Type.hxx>
#include <Standard_Integer.hxx>
@@ -47,6 +50,15 @@
IMPLEMENT_STANDARD_RTTIEXT(Geom_BezierSurface, Geom_BoundedSurface)
//=================================================================================================
void Geom_BezierSurface::SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<double>(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<gp_Pnt> Geom_BezierSurface::EvalD0(const double U, const double V) const
{
if (const std::optional<gp_Pnt> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD0(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
gp_Pnt P;
if (myURational || myVRational)
{
@@ -1378,6 +1400,13 @@ std::optional<gp_Pnt> Geom_BezierSurface::EvalD0(const double U, const double V)
std::optional<Geom_Surface::ResD1> Geom_BezierSurface::EvalD1(const double U, const double V) const
{
if (const std::optional<Geom_Surface::ResD1> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD1(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Surface::ResD1> aResult{std::in_place};
if (myURational || myVRational)
{
@@ -1430,6 +1459,13 @@ std::optional<Geom_Surface::ResD1> Geom_BezierSurface::EvalD1(const double U, co
std::optional<Geom_Surface::ResD2> Geom_BezierSurface::EvalD2(const double U, const double V) const
{
if (const std::optional<Geom_Surface::ResD2> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD2(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Surface::ResD2> aResult{std::in_place};
if (myURational || myVRational)
{
@@ -1490,6 +1526,13 @@ std::optional<Geom_Surface::ResD2> Geom_BezierSurface::EvalD2(const double U, co
std::optional<Geom_Surface::ResD3> Geom_BezierSurface::EvalD3(const double U, const double V) const
{
if (const std::optional<Geom_Surface::ResD3> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD3(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Surface::ResD3> aResult{std::in_place};
if (myURational || myVRational)
{
@@ -1559,6 +1602,13 @@ std::optional<gp_Vec> Geom_BezierSurface::EvalDN(const double U,
const int Nu,
const int Nv) const
{
if (const std::optional<gp_Vec> 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<gp_Pnt>& thePoles,
}
myMaxDerivInvOk = false;
ClearEvalRepresentation();
}
//=================================================================================================
@@ -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<Geom_EvalRepSurfaceDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<double>* theWeights);
private:
NCollection_Array2<gp_Pnt> myPoles;
NCollection_Array2<double> myWeights;
bool myURational = false;
bool myVRational = false;
double myUMaxDerivInv = 0.0;
double myVMaxDerivInv = 0.0;
bool myMaxDerivInvOk = false;
NCollection_Array2<gp_Pnt> myPoles;
NCollection_Array2<double> myWeights;
occ::handle<Geom_EvalRepSurfaceDesc::Base> myEvalRep;
bool myURational = false;
bool myVRational = false;
double myUMaxDerivInv = 0.0;
double myVMaxDerivInv = 0.0;
bool myMaxDerivInvOk = false;
};
#endif // _Geom_BezierSurface_HeaderFile
@@ -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 <Geom_Curve.hxx>
#include <Precision.hxx>
#include <Standard_Transient.hxx>
#include <cmath>
#include <cstddef>
#include <optional>
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<Geom_Curve> 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<Domain1d> 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
@@ -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 <Geom_Surface.hxx>
#include <Precision.hxx>
#include <Standard_Transient.hxx>
#include <cmath>
#include <cstddef>
#include <optional>
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<Geom_Surface> 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<Domain2d> 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
@@ -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 <Geom_Curve.hxx>
#include <Geom_Surface.hxx>
#include <Standard_ProgramError.hxx>
#include <cmath>
#include <optional>
//! Internal helper namespace for EvalRep dispatch and validation.
namespace Geom_EvalRepUtils
{
occ::handle<Geom_EvalRepCurveDesc::Base> CloneCurveDesc(
const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc);
occ::handle<Geom_EvalRepSurfaceDesc::Base> CloneSurfaceDesc(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc);
std::optional<gp_Pnt> TryEvalCurveD0(const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc,
const double theU);
std::optional<Geom_Curve::ResD1> TryEvalCurveD1(
const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc,
const double theU);
std::optional<Geom_Curve::ResD2> TryEvalCurveD2(
const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc,
const double theU);
std::optional<Geom_Curve::ResD3> TryEvalCurveD3(
const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc,
const double theU);
std::optional<gp_Vec> TryEvalCurveDN(const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc,
const double theU,
const int theN);
std::optional<gp_Pnt> TryEvalSurfaceD0(const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc,
const double theU,
const double theV);
std::optional<Geom_Surface::ResD1> TryEvalSurfaceD1(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc,
const double theU,
const double theV);
std::optional<Geom_Surface::ResD2> TryEvalSurfaceD2(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc,
const double theU,
const double theV);
std::optional<Geom_Surface::ResD3> TryEvalSurfaceD3(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc,
const double theU,
const double theV);
std::optional<gp_Vec> TryEvalSurfaceDN(const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc,
const double theU,
const double theV,
const int theNu,
const int theNv);
std::optional<gp_Pnt> TryEvalCurveD0Mapped(const Geom_EvalRepCurveDesc::Mapped& theDesc,
const double theU);
std::optional<Geom_Curve::ResD1> TryEvalCurveD1Mapped(const Geom_EvalRepCurveDesc::Mapped& theDesc,
const double theU);
std::optional<Geom_Curve::ResD2> TryEvalCurveD2Mapped(const Geom_EvalRepCurveDesc::Mapped& theDesc,
const double theU);
std::optional<Geom_Curve::ResD3> TryEvalCurveD3Mapped(const Geom_EvalRepCurveDesc::Mapped& theDesc,
const double theU);
std::optional<gp_Vec> TryEvalCurveDNMapped(const Geom_EvalRepCurveDesc::Mapped& theDesc,
const double theU,
const int theN);
std::optional<gp_Pnt> TryEvalSurfaceD0Mapped(const Geom_EvalRepSurfaceDesc::Mapped& theDesc,
const double theU,
const double theV);
std::optional<Geom_Surface::ResD1> TryEvalSurfaceD1Mapped(
const Geom_EvalRepSurfaceDesc::Mapped& theDesc,
const double theU,
const double theV);
std::optional<Geom_Surface::ResD2> TryEvalSurfaceD2Mapped(
const Geom_EvalRepSurfaceDesc::Mapped& theDesc,
const double theU,
const double theV);
std::optional<Geom_Surface::ResD3> TryEvalSurfaceD3Mapped(
const Geom_EvalRepSurfaceDesc::Mapped& theDesc,
const double theU,
const double theV);
std::optional<gp_Vec> TryEvalSurfaceDNMapped(const Geom_EvalRepSurfaceDesc::Mapped& theDesc,
const double theU,
const double theV,
const int theNu,
const int theNv);
void ValidateCurveDesc(const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc,
const Geom_Curve* theOwner);
void ValidateSurfaceDesc(const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc,
const Geom_Surface* theOwner);
} // namespace Geom_EvalRepUtils
//==================================================================================================
inline void Geom_EvalRepUtils::ValidateCurveDesc(
const occ::handle<Geom_EvalRepCurveDesc::Base>& 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<const Geom_EvalRepCurveDesc::Mapped*>(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<Geom_EvalRepSurfaceDesc::Base>& 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<const Geom_EvalRepSurfaceDesc::Mapped*>(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_EvalRepCurveDesc::Base> Geom_EvalRepUtils::CloneCurveDesc(
const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc)
{
if (theDesc.IsNull() || theDesc->Representation.IsNull())
{
return occ::handle<Geom_EvalRepCurveDesc::Base>();
}
const occ::handle<Geom_Curve> aRepCopy =
occ::down_cast<Geom_Curve>(theDesc->Representation->Copy());
if (aRepCopy.IsNull())
{
return occ::handle<Geom_EvalRepCurveDesc::Base>();
}
switch (theDesc->GetKind())
{
case Geom_EvalRepCurveDesc::Base::Kind::Full: {
occ::handle<Geom_EvalRepCurveDesc::Full> aClone = new Geom_EvalRepCurveDesc::Full();
aClone->Representation = aRepCopy;
return aClone;
}
case Geom_EvalRepCurveDesc::Base::Kind::DerivBounded: {
const auto* aSrc = static_cast<const Geom_EvalRepCurveDesc::DerivBounded*>(theDesc.get());
occ::handle<Geom_EvalRepCurveDesc::DerivBounded> 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<const Geom_EvalRepCurveDesc::Mapped*>(theDesc.get());
occ::handle<Geom_EvalRepCurveDesc::Mapped> 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<Geom_EvalRepCurveDesc::Base>();
}
//==================================================================================================
inline occ::handle<Geom_EvalRepSurfaceDesc::Base> Geom_EvalRepUtils::CloneSurfaceDesc(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc)
{
if (theDesc.IsNull() || theDesc->Representation.IsNull())
{
return occ::handle<Geom_EvalRepSurfaceDesc::Base>();
}
const occ::handle<Geom_Surface> aRepCopy =
occ::down_cast<Geom_Surface>(theDesc->Representation->Copy());
if (aRepCopy.IsNull())
{
return occ::handle<Geom_EvalRepSurfaceDesc::Base>();
}
switch (theDesc->GetKind())
{
case Geom_EvalRepSurfaceDesc::Base::Kind::Full: {
occ::handle<Geom_EvalRepSurfaceDesc::Full> aClone = new Geom_EvalRepSurfaceDesc::Full();
aClone->Representation = aRepCopy;
return aClone;
}
case Geom_EvalRepSurfaceDesc::Base::Kind::DerivBounded: {
const auto* aSrc = static_cast<const Geom_EvalRepSurfaceDesc::DerivBounded*>(theDesc.get());
occ::handle<Geom_EvalRepSurfaceDesc::DerivBounded> 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<const Geom_EvalRepSurfaceDesc::Mapped*>(theDesc.get());
occ::handle<Geom_EvalRepSurfaceDesc::Mapped> 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<Geom_EvalRepSurfaceDesc::Base>();
}
//==================================================================================================
inline std::optional<gp_Pnt> Geom_EvalRepUtils::TryEvalCurveD0(
const occ::handle<Geom_EvalRepCurveDesc::Base>& 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<const Geom_EvalRepCurveDesc::Mapped*>(theDesc.get()),
theU);
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<Geom_Curve::ResD1> Geom_EvalRepUtils::TryEvalCurveD1(
const occ::handle<Geom_EvalRepCurveDesc::Base>& 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<const Geom_EvalRepCurveDesc::DerivBounded*>(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<const Geom_EvalRepCurveDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < 1)
return std::nullopt;
return TryEvalCurveD1Mapped(*aMapped, theU);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<Geom_Curve::ResD2> Geom_EvalRepUtils::TryEvalCurveD2(
const occ::handle<Geom_EvalRepCurveDesc::Base>& 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<const Geom_EvalRepCurveDesc::DerivBounded*>(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<const Geom_EvalRepCurveDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < 2)
return std::nullopt;
return TryEvalCurveD2Mapped(*aMapped, theU);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<Geom_Curve::ResD3> Geom_EvalRepUtils::TryEvalCurveD3(
const occ::handle<Geom_EvalRepCurveDesc::Base>& 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<const Geom_EvalRepCurveDesc::DerivBounded*>(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<const Geom_EvalRepCurveDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < 3)
return std::nullopt;
return TryEvalCurveD3Mapped(*aMapped, theU);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<gp_Vec> Geom_EvalRepUtils::TryEvalCurveDN(
const occ::handle<Geom_EvalRepCurveDesc::Base>& 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<const Geom_EvalRepCurveDesc::DerivBounded*>(theDesc.get());
if (aBounded->MaxDerivOrder < static_cast<std::size_t>(theN))
return std::nullopt;
return theDesc->Representation->EvalDN(theU, theN);
}
case Geom_EvalRepCurveDesc::Base::Kind::Mapped: {
const auto* aMapped = static_cast<const Geom_EvalRepCurveDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < static_cast<std::size_t>(theN))
return std::nullopt;
return TryEvalCurveDNMapped(*aMapped, theU, theN);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<gp_Pnt> Geom_EvalRepUtils::TryEvalSurfaceD0(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<const Geom_EvalRepSurfaceDesc::Mapped*>(theDesc.get()),
theU,
theV);
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<Geom_Surface::ResD1> Geom_EvalRepUtils::TryEvalSurfaceD1(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<const Geom_EvalRepSurfaceDesc::DerivBounded*>(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<const Geom_EvalRepSurfaceDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < 1)
return std::nullopt;
return TryEvalSurfaceD1Mapped(*aMapped, theU, theV);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<Geom_Surface::ResD2> Geom_EvalRepUtils::TryEvalSurfaceD2(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<const Geom_EvalRepSurfaceDesc::DerivBounded*>(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<const Geom_EvalRepSurfaceDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < 2)
return std::nullopt;
return TryEvalSurfaceD2Mapped(*aMapped, theU, theV);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<Geom_Surface::ResD3> Geom_EvalRepUtils::TryEvalSurfaceD3(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<const Geom_EvalRepSurfaceDesc::DerivBounded*>(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<const Geom_EvalRepSurfaceDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < 3)
return std::nullopt;
return TryEvalSurfaceD3Mapped(*aMapped, theU, theV);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<gp_Vec> Geom_EvalRepUtils::TryEvalSurfaceDN(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<const Geom_EvalRepSurfaceDesc::DerivBounded*>(theDesc.get());
if (aBounded->MaxDerivOrder < static_cast<std::size_t>(aTotalOrder))
return std::nullopt;
return theDesc->Representation->EvalDN(theU, theV, theNu, theNv);
}
case Geom_EvalRepSurfaceDesc::Base::Kind::Mapped: {
const auto* aMapped = static_cast<const Geom_EvalRepSurfaceDesc::Mapped*>(theDesc.get());
if (aMapped->MaxDerivOrder < static_cast<std::size_t>(aTotalOrder))
return std::nullopt;
return TryEvalSurfaceDNMapped(*aMapped, theU, theV, theNu, theNv);
}
}
return std::nullopt;
}
//==================================================================================================
inline std::optional<gp_Pnt> 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_Curve::ResD1> 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<Geom_Curve::ResD1> 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_Curve::ResD2> 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<Geom_Curve::ResD2> 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_Curve::ResD3> 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<Geom_Curve::ResD3> 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<gp_Vec> 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<gp_Vec> 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<gp_Pnt> 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_Surface::ResD1> 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<Geom_Surface::ResD1> 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_Surface::ResD2> 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<Geom_Surface::ResD2> 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_Surface::ResD3> 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<Geom_Surface::ResD3> 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<gp_Vec> 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<gp_Vec> 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
@@ -21,6 +21,8 @@
#include <Geom_BezierCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <Geom_Curve.hxx>
#include "Geom_EvalRepCurveDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include <Geom_Geometry.hxx>
#include <Geom_OffsetCurve.hxx>
#include <Geom_OffsetCurveUtils.pxx>
@@ -35,6 +37,7 @@
#include <Precision.hxx>
#include <Standard_ConstructionError.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_RangeError.hxx>
#include <Standard_Type.hxx>
@@ -44,6 +47,15 @@ static const double MyAngularToleranceForG1 = Precision::Angular();
//==================================================================================================
void Geom_OffsetCurve::SetEvalRepresentation(
const occ::handle<Geom_EvalRepCurveDesc::Base>& theDesc)
{
Geom_EvalRepUtils::ValidateCurveDesc(theDesc, this);
myEvalRep = theDesc;
}
//==================================================================================================
occ::handle<Geom_Geometry> Geom_OffsetCurve::Copy() const
{
return new Geom_OffsetCurve(*this);
@@ -57,6 +69,7 @@ occ::handle<Geom_Geometry> Geom_OffsetCurve::Copy() const
Geom_OffsetCurve::Geom_OffsetCurve(const Geom_OffsetCurve& theOther)
: basisCurve(occ::down_cast<Geom_Curve>(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<Geom_Curve>& 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<Geom_Curve>& C, const bool isNotCheckC0)
{
ClearEvalRepresentation();
const double aUf = C->FirstParameter(), aUl = C->LastParameter();
occ::handle<Geom_Curve> aCheckingCurve = occ::down_cast<Geom_Curve>(C->Copy());
bool isTrimmed = false;
@@ -242,6 +259,13 @@ GeomAbs_Shape Geom_OffsetCurve::Continuity() const
std::optional<gp_Pnt> Geom_OffsetCurve::EvalD0(const double theU) const
{
if (const std::optional<gp_Pnt> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD0(myEvalRep, theU);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD1> aBasisD1 = basisCurve->EvalD1(theU);
if (!aBasisD1)
return std::nullopt;
@@ -255,6 +279,13 @@ std::optional<gp_Pnt> Geom_OffsetCurve::EvalD0(const double theU) const
std::optional<Geom_Curve::ResD1> Geom_OffsetCurve::EvalD1(const double theU) const
{
if (const std::optional<Geom_Curve::ResD1> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD1(myEvalRep, theU);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD2> aBasisD2 = basisCurve->EvalD2(theU);
if (!aBasisD2)
return std::nullopt;
@@ -269,6 +300,13 @@ std::optional<Geom_Curve::ResD1> Geom_OffsetCurve::EvalD1(const double theU) con
std::optional<Geom_Curve::ResD2> Geom_OffsetCurve::EvalD2(const double theU) const
{
if (const std::optional<Geom_Curve::ResD2> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD2(myEvalRep, theU);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD3> aBasisD3 = basisCurve->EvalD3(theU);
if (!aBasisD3)
return std::nullopt;
@@ -303,6 +341,13 @@ std::optional<Geom_Curve::ResD2> Geom_OffsetCurve::EvalD2(const double theU) con
std::optional<Geom_Curve::ResD3> Geom_OffsetCurve::EvalD3(const double theU) const
{
if (const std::optional<Geom_Curve::ResD3> aEvalRepResult =
Geom_EvalRepUtils::TryEvalCurveD3(myEvalRep, theU);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD3> aBasisD3 = basisCurve->EvalD3(theU);
if (!aBasisD3)
return std::nullopt;
@@ -343,6 +388,12 @@ std::optional<gp_Vec> Geom_OffsetCurve::EvalDN(const double U, const int N) cons
{
if (N < 1)
return std::nullopt;
if (const std::optional<gp_Vec> 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();
@@ -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<Geom_EvalRepCurveDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom_EvalRepCurveDesc::Base>& 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<Geom_Curve> basisCurve;
gp_Dir direction;
double offsetValue;
GeomAbs_Shape myBasisCurveContinuity;
occ::handle<Geom_Curve> basisCurve;
occ::handle<Geom_EvalRepCurveDesc::Base> myEvalRep;
gp_Dir direction;
double offsetValue;
GeomAbs_Shape myBasisCurveContinuity;
};
#endif // _Geom_OffsetCurve_HeaderFile
@@ -25,6 +25,8 @@
#include <Geom_Curve.hxx>
#include <Geom_CylindricalSurface.hxx>
#include <Geom_ElementarySurface.hxx>
#include "Geom_EvalRepSurfaceDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include <Geom_Ellipse.hxx>
#include <Geom_Geometry.hxx>
#include <Geom_OffsetCurve.hxx>
@@ -53,6 +55,7 @@
#include <Standard_ConstructionError.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_NumericError.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_RangeError.hxx>
#include <Standard_Type.hxx>
#include <NCollection_Array1.hxx>
@@ -64,6 +67,44 @@ IMPLEMENT_STANDARD_RTTIEXT(Geom_OffsetSurface, Geom_Surface)
static const double MyAngularToleranceForG1 = Precision::Angular();
namespace
{
occ::handle<Geom_EvalRepSurfaceDesc::Base> makeFullSurfaceRep(
const occ::handle<Geom_Surface>& theSurface)
{
if (theSurface.IsNull())
{
return occ::handle<Geom_EvalRepSurfaceDesc::Base>();
}
occ::handle<Geom_EvalRepSurfaceDesc::Full> aDesc = new Geom_EvalRepSurfaceDesc::Full();
aDesc->Representation = theSurface;
return aDesc;
}
occ::handle<Geom_Surface> directRepSurface(const Geom_OffsetSurface& theSurface)
{
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& aDesc = theSurface.EvalRepresentation();
if (aDesc.IsNull())
{
return occ::handle<Geom_Surface>();
}
if (aDesc->GetKind() != Geom_EvalRepSurfaceDesc::Base::Kind::Full)
{
return occ::handle<Geom_Surface>();
}
return aDesc->Representation;
}
} // namespace
//=================================================================================================
void Geom_OffsetSurface::SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc)
{
Geom_EvalRepUtils::ValidateSurfaceDesc(theDesc, this);
myEvalRep = theDesc;
}
//=================================================================================================
occ::handle<Geom_Geometry> Geom_OffsetSurface::Copy() const
@@ -79,15 +120,13 @@ occ::handle<Geom_Geometry> Geom_OffsetSurface::Copy() const
Geom_OffsetSurface::Geom_OffsetSurface(const Geom_OffsetSurface& theOther)
: basisSurf(occ::down_cast<Geom_Surface>(theOther.basisSurf->Copy())),
equivSurf(theOther.equivSurf.IsNull()
? occ::handle<Geom_Surface>()
: occ::down_cast<Geom_Surface>(theOther.equivSurf->Copy())),
myEvalRep(Geom_EvalRepUtils::CloneSurfaceDesc(theOther.myEvalRep)),
offsetValue(theOther.offsetValue),
myOscSurf(theOther.myOscSurf ? std::make_unique<Geom_OsculatingSurface>(*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<Geom_Surface>& theSurf,
void Geom_OffsetSurface::SetBasisSurface(const occ::handle<Geom_Surface>& 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<Geom_Surface>& S,
basisSurf = aCheckingSurf;
}
equivSurf = Surface();
const occ::handle<Geom_Surface> 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<Geom_Surface>& 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<gp_Pnt> Geom_OffsetSurface::EvalD0(const double U, const double V)
return std::nullopt;
}
#endif
if (!equivSurf.IsNull())
if (const std::optional<gp_Pnt> 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_Surface::ResD1> Geom_OffsetSurface::EvalD1(const double U, co
return std::nullopt;
}
#endif
if (!equivSurf.IsNull())
if (const std::optional<Geom_Surface::ResD1> 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_Surface::ResD2> Geom_OffsetSurface::EvalD2(const double U, co
return std::nullopt;
}
#endif
if (!equivSurf.IsNull())
if (const std::optional<Geom_Surface::ResD2> 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_Surface::ResD3> Geom_OffsetSurface::EvalD3(const double U, co
return std::nullopt;
}
#endif
if (!equivSurf.IsNull())
if (const std::optional<Geom_Surface::ResD3> 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<gp_Vec> Geom_OffsetSurface::EvalDN(const double U,
return std::nullopt;
}
#endif
if (!equivSurf.IsNull())
if (const std::optional<gp_Vec> 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_Curve> Geom_OffsetSurface::UIso(const double UU) const
{
if (equivSurf.IsNull())
const occ::handle<Geom_Surface> anEquivSurface = directRepSurface(*this);
if (anEquivSurface.IsNull())
{
GeomAdaptor_Surface aGAsurf(basisSurf);
if (aGAsurf.GetType() == GeomAbs_SurfaceOfExtrusion)
@@ -608,15 +659,15 @@ occ::handle<Geom_Curve> Geom_OffsetSurface::UIso(const double UU) const
occ::handle<Geom_BSplineCurve> C = new Geom_BSplineCurve(Poles, Knots, Mults, Approx.Degree());
return C;
}
else
return equivSurf->UIso(UU);
return anEquivSurface->UIso(UU);
}
//=================================================================================================
occ::handle<Geom_Curve> Geom_OffsetSurface::VIso(const double VV) const
{
if (equivSurf.IsNull())
const occ::handle<Geom_Surface> anEquivSurface = directRepSurface(*this);
if (anEquivSurface.IsNull())
{
const int Num1 = 0, Num2 = 0, Num3 = 1;
occ::handle<NCollection_HArray1<double>> T1, T2, T3 = new NCollection_HArray1<double>(1, Num3);
@@ -644,8 +695,7 @@ occ::handle<Geom_Curve> Geom_OffsetSurface::VIso(const double VV) const
occ::handle<Geom_BSplineCurve> 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<Geom_Surface> 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<Geom_Surface> 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)
@@ -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<Geom_EvalRepSurfaceDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<Geom_Surface> basisSurf;
occ::handle<Geom_Surface> equivSurf;
double offsetValue;
std::unique_ptr<Geom_OsculatingSurface> myOscSurf;
GeomAbs_Shape myBasisSurfContinuity;
occ::handle<Geom_Surface> basisSurf;
occ::handle<Geom_EvalRepSurfaceDesc::Base> myEvalRep;
double offsetValue;
std::unique_ptr<Geom_OsculatingSurface> myOscSurf;
GeomAbs_Shape myBasisSurfContinuity;
};
#endif // _Geom_OffsetSurface_HeaderFile
@@ -18,6 +18,8 @@
#include <BSplSLib.hxx>
#include <Geom_BezierCurve.hxx>
#include <Geom_Curve.hxx>
#include "Geom_EvalRepSurfaceDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include "Geom_ExtrusionUtils.pxx"
#include <Geom_Geometry.hxx>
#include <Geom_Line.hxx>
@@ -32,6 +34,7 @@
#include <gp_Vec.hxx>
#include <gp_XYZ.hxx>
#include <Precision.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_RangeError.hxx>
#include <Standard_Type.hxx>
@@ -55,12 +58,21 @@ typedef gp_XYZ XYZ;
//=================================================================================================
void Geom_SurfaceOfLinearExtrusion::SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc)
{
Geom_EvalRepUtils::ValidateSurfaceDesc(theDesc, this);
myEvalRep = theDesc;
}
//=================================================================================================
occ::handle<Geom_Geometry> Geom_SurfaceOfLinearExtrusion::Copy() const
{
occ::handle<Geom_SurfaceOfLinearExtrusion> Sr;
Sr = new SurfaceOfLinearExtrusion(basisCurve, direction);
return Sr;
occ::handle<Geom_SurfaceOfLinearExtrusion> aCopy =
new SurfaceOfLinearExtrusion(basisCurve, direction);
aCopy->myEvalRep = Geom_EvalRepUtils::CloneSurfaceDesc(myEvalRep);
return aCopy;
}
//=================================================================================================
@@ -77,7 +89,7 @@ Geom_SurfaceOfLinearExtrusion::Geom_SurfaceOfLinearExtrusion(const occ::handle<G
void Geom_SurfaceOfLinearExtrusion::UReverse()
{
ClearEvalRepresentation();
basisCurve->Reverse();
}
@@ -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<Geom_Curve>& C)
{
ClearEvalRepresentation();
smooth = C->Continuity();
basisCurve = occ::down_cast<Geom_Curve>(C->Copy());
}
@@ -134,6 +149,13 @@ void Geom_SurfaceOfLinearExtrusion::Bounds(double& U1, double& U2, double& V1, d
std::optional<gp_Pnt> Geom_SurfaceOfLinearExtrusion::EvalD0(const double U, const double V) const
{
if (const std::optional<gp_Pnt> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD0(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<gp_Pnt> aBasisD0 = basisCurve->EvalD0(U);
if (!aBasisD0)
return std::nullopt;
@@ -147,6 +169,13 @@ std::optional<gp_Pnt> Geom_SurfaceOfLinearExtrusion::EvalD0(const double U, cons
std::optional<Geom_Surface::ResD1> Geom_SurfaceOfLinearExtrusion::EvalD1(const double U,
const double V) const
{
if (const std::optional<Geom_Surface::ResD1> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD1(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD1> aBasisD1 = basisCurve->EvalD1(U);
if (!aBasisD1)
return std::nullopt;
@@ -166,6 +195,13 @@ std::optional<Geom_Surface::ResD1> Geom_SurfaceOfLinearExtrusion::EvalD1(const d
std::optional<Geom_Surface::ResD2> Geom_SurfaceOfLinearExtrusion::EvalD2(const double U,
const double V) const
{
if (const std::optional<Geom_Surface::ResD2> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD2(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD2> aBasisD2 = basisCurve->EvalD2(U);
if (!aBasisD2)
return std::nullopt;
@@ -189,6 +225,13 @@ std::optional<Geom_Surface::ResD2> Geom_SurfaceOfLinearExtrusion::EvalD2(const d
std::optional<Geom_Surface::ResD3> Geom_SurfaceOfLinearExtrusion::EvalD3(const double U,
const double V) const
{
if (const std::optional<Geom_Surface::ResD3> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD3(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD3> aBasisD3 = basisCurve->EvalD3(U);
if (!aBasisD3)
return std::nullopt;
@@ -215,12 +258,20 @@ std::optional<Geom_Surface::ResD3> Geom_SurfaceOfLinearExtrusion::EvalD3(const d
//=================================================================================================
std::optional<gp_Vec> 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<gp_Vec> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceDN(myEvalRep, U, V, Nu, Nv);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
if (Nv == 0)
{
std::optional<gp_Vec> 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);
}
@@ -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<Geom_Curve>& 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<Geom_EvalRepSurfaceDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<Geom_EvalRepSurfaceDesc::Base> myEvalRep;
};
#endif // _Geom_SurfaceOfLinearExtrusion_HeaderFile
@@ -19,6 +19,8 @@
#include <Geom_BSplineCurve.hxx>
#include <Geom_Circle.hxx>
#include <Geom_Curve.hxx>
#include "Geom_EvalRepSurfaceDesc.hxx"
#include "Geom_EvalRepUtils.pxx"
#include <Geom_Geometry.hxx>
#include "Geom_RevolutionUtils.pxx"
#include <Geom_SurfaceOfRevolution.hxx>
@@ -36,6 +38,7 @@
#include <gp_XYZ.hxx>
#include <Precision.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_ProgramError.hxx>
#include <Standard_RangeError.hxx>
#include <Standard_Type.hxx>
@@ -62,10 +65,20 @@ typedef gp_XYZ XYZ;
//=================================================================================================
void Geom_SurfaceOfRevolution::SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& theDesc)
{
Geom_EvalRepUtils::ValidateSurfaceDesc(theDesc, this);
myEvalRep = theDesc;
}
//=================================================================================================
occ::handle<Geom_Geometry> Geom_SurfaceOfRevolution::Copy() const
{
return new Geom_SurfaceOfRevolution(basisCurve, Axis());
occ::handle<Geom_SurfaceOfRevolution> 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<Geom_Curve>
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<Geom_Curve>& C)
{
ClearEvalRepresentation();
basisCurve = occ::down_cast<Geom_Curve>(C->Copy());
smooth = C->Continuity();
}
@@ -199,6 +216,7 @@ void Geom_SurfaceOfRevolution::SetBasisCurve(const occ::handle<Geom_Curve>& 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<gp_Pnt> Geom_SurfaceOfRevolution::EvalD0(const double U, const double V) const
{
if (const std::optional<gp_Pnt> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD0(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<gp_Pnt> aBasisD0 = basisCurve->EvalD0(V);
if (!aBasisD0)
return std::nullopt;
@@ -230,6 +255,13 @@ std::optional<gp_Pnt> Geom_SurfaceOfRevolution::EvalD0(const double U, const dou
std::optional<Geom_Surface::ResD1> Geom_SurfaceOfRevolution::EvalD1(const double U,
const double V) const
{
if (const std::optional<Geom_Surface::ResD1> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD1(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD1> aBasisD1 = basisCurve->EvalD1(V);
if (!aBasisD1)
return std::nullopt;
@@ -249,6 +281,13 @@ std::optional<Geom_Surface::ResD1> Geom_SurfaceOfRevolution::EvalD1(const double
std::optional<Geom_Surface::ResD2> Geom_SurfaceOfRevolution::EvalD2(const double U,
const double V) const
{
if (const std::optional<Geom_Surface::ResD2> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD2(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD2> aBasisD2 = basisCurve->EvalD2(V);
if (!aBasisD2)
return std::nullopt;
@@ -272,6 +311,13 @@ std::optional<Geom_Surface::ResD2> Geom_SurfaceOfRevolution::EvalD2(const double
std::optional<Geom_Surface::ResD3> Geom_SurfaceOfRevolution::EvalD3(const double U,
const double V) const
{
if (const std::optional<Geom_Surface::ResD3> aEvalRepResult =
Geom_EvalRepUtils::TryEvalSurfaceD3(myEvalRep, U, V);
aEvalRepResult.has_value())
{
return aEvalRepResult;
}
std::optional<Geom_Curve::ResD3> aBasisD3 = basisCurve->EvalD3(V);
if (!aBasisD3)
return std::nullopt;
@@ -304,6 +350,12 @@ std::optional<gp_Vec> Geom_SurfaceOfRevolution::EvalDN(const double U,
{
if (Nu + Nv < 1 || Nu < 0 || Nv < 0)
return std::nullopt;
if (const std::optional<gp_Vec> 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_Curve> Geom_SurfaceOfRevolution::VIso(const double V) const
void Geom_SurfaceOfRevolution::Transform(const Trsf& T)
{
ClearEvalRepresentation();
loc.Transform(T);
direction.Transform(T);
basisCurve->Transform(T);
@@ -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<Geom_Curve>& 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<Geom_EvalRepSurfaceDesc::Base>& EvalRepresentation() const { return myEvalRep; }
//! Sets a new evaluation representation.
//! Validates descriptor data and ensures no circular references.
Standard_EXPORT void SetEvalRepresentation(
const occ::handle<Geom_EvalRepSurfaceDesc::Base>& 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<Geom_EvalRepSurfaceDesc::Base> myEvalRep;
gp_Pnt loc;
};
#endif // _Geom_SurfaceOfRevolution_HeaderFile
@@ -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<GeomAdaptor_Curve::BezierData>(&theData))
{
return !aBezierData->EvalRep.IsNull();
}
if (const GeomAdaptor_Curve::BSplineData* aBSplineData =
std::get_if<GeomAdaptor_Curve::BSplineData>(&theData))
{
return !aBSplineData->EvalRep.IsNull();
}
if (const GeomAdaptor_Curve::OffsetData* anOffsetData =
std::get_if<GeomAdaptor_Curve::OffsetData>(&theData))
{
return !anOffsetData->EvalRep.IsNull();
}
return false;
}
} // namespace
//=================================================================================================
occ::handle<Adaptor3d_Curve> GeomAdaptor_Curve::ShallowCopy() const
@@ -80,17 +103,24 @@ occ::handle<Adaptor3d_Curve> GeomAdaptor_Curve::ShallowCopy() const
occ::down_cast<GeomAdaptor_Curve>(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<BSplineData>(&myCurveData))
{
BSplineData aCopyData;
aCopyData.Curve = aBSplineData->Curve;
aCopyData.EvalRep = aBSplineData->EvalRep;
aCopy->myCurveData = std::move(aCopyData);
}
else if (std::holds_alternative<BezierData>(myCurveData))
{
aCopy->myCurveData = BezierData{};
const BezierData& aBezierData = std::get<BezierData>(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<Geom_Curve>& C,
else if (TheType == STANDARD_TYPE(Geom_BezierCurve))
{
myTypeCurve = GeomAbs_BezierCurve;
myCurveData = BezierData{};
BezierData aBezierData;
aBezierData.Curve = occ::down_cast<Geom_BezierCurve>(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<Geom_BSplineCurve>(C);
myCurveData = std::move(aBSplineData);
aBSplineData.Curve = occ::down_cast<Geom_BSplineCurve>(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<Geom_Curve>& 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<gp_Pnt> GeomAdaptor_Curve::EvalD0(double U) const
return P;
case GeomAbs_BezierCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD0(U);
}
auto& aCache = std::get<BezierData>(myCurveData).Cache;
if (aCache.IsNull())
RebuildCache(U);
@@ -664,6 +703,10 @@ std::optional<gp_Pnt> 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<BSplineData>(myCurveData);
if (IsBoundary(U, aStart, aFinish))
@@ -680,6 +723,10 @@ std::optional<gp_Pnt> GeomAdaptor_Curve::EvalD0(double U) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD0(U);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
if (!Geom_OffsetCurveUtils::EvaluateD0(U,
anOffsetData.BasisAdaptor.get(),
@@ -736,6 +783,10 @@ std::optional<Geom_Curve::ResD1> GeomAdaptor_Curve::EvalD1(double U) const
return aResult;
case GeomAbs_BezierCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD1(U);
}
auto& aCache = std::get<BezierData>(myCurveData).Cache;
if (aCache.IsNull())
RebuildCache(U);
@@ -744,6 +795,10 @@ std::optional<Geom_Curve::ResD1> 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<BSplineData>(myCurveData);
if (IsBoundary(U, aStart, aFinish))
@@ -760,6 +815,10 @@ std::optional<Geom_Curve::ResD1> GeomAdaptor_Curve::EvalD1(double U) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD1(U);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
if (!Geom_OffsetCurveUtils::EvaluateD1(U,
anOffsetData.BasisAdaptor.get(),
@@ -819,6 +878,10 @@ std::optional<Geom_Curve::ResD2> GeomAdaptor_Curve::EvalD2(double U) const
return aResult;
case GeomAbs_BezierCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD2(U);
}
auto& aCache = std::get<BezierData>(myCurveData).Cache;
if (aCache.IsNull())
RebuildCache(U);
@@ -827,6 +890,10 @@ std::optional<Geom_Curve::ResD2> 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<BSplineData>(myCurveData);
if (IsBoundary(U, aStart, aFinish))
@@ -843,6 +910,10 @@ std::optional<Geom_Curve::ResD2> GeomAdaptor_Curve::EvalD2(double U) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD2(U);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
if (!Geom_OffsetCurveUtils::EvaluateD2(U,
anOffsetData.BasisAdaptor.get(),
@@ -921,6 +992,10 @@ std::optional<Geom_Curve::ResD3> GeomAdaptor_Curve::EvalD3(double U) const
return aResult;
case GeomAbs_BezierCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD3(U);
}
auto& aCache = std::get<BezierData>(myCurveData).Cache;
if (aCache.IsNull())
RebuildCache(U);
@@ -929,6 +1004,10 @@ std::optional<Geom_Curve::ResD3> 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<BSplineData>(myCurveData);
if (IsBoundary(U, aStart, aFinish))
@@ -946,6 +1025,10 @@ std::optional<Geom_Curve::ResD3> GeomAdaptor_Curve::EvalD3(double U) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalD3(U);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
if (!Geom_OffsetCurveUtils::EvaluateD3(U,
anOffsetData.BasisAdaptor.get(),
@@ -1001,6 +1084,10 @@ std::optional<gp_Vec> 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<gp_Vec> GeomAdaptor_Curve::EvalDN(double U, int N) const
}
case GeomAbs_OffsetCurve: {
if (hasEvalRep(myCurveData))
{
return myCurve->EvalDN(U, N);
}
const auto& anOffsetData = std::get<OffsetData>(myCurveData);
gp_Vec aDN;
if (!Geom_OffsetCurveUtils::EvaluateDN(U,
@@ -34,6 +34,12 @@
#include <variant>
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<GeomAdaptor_Curve> BasisAdaptor; //!< Adaptor for basis curve
double Offset = 0.0; //!< Offset distance
gp_Dir Direction; //!< Offset direction
occ::handle<GeomAdaptor_Curve> BasisAdaptor; //!< Adaptor for basis curve
double Offset = 0.0; //!< Offset distance
gp_Dir Direction; //!< Offset direction
occ::handle<Geom_EvalRepCurveDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Internal structure for Bezier curve cache data.
struct BezierData
{
mutable occ::handle<BSplCLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom_BezierCurve> Curve; //!< Bezier curve to prevent downcasts
mutable occ::handle<BSplCLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom_EvalRepCurveDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Internal structure for BSpline curve cache data.
struct BSplineData
{
occ::handle<Geom_BSplineCurve> Curve; //!< BSpline curve to prevent downcasts
mutable occ::handle<BSplCLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom_BSplineCurve> Curve; //!< BSpline curve to prevent downcasts
mutable occ::handle<BSplCLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom_EvalRepCurveDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Variant type for curve-specific evaluation data.
@@ -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<GeomAdaptor_Surface::BezierData>(&theData))
{
return !aBezierData->EvalRep.IsNull();
}
if (const GeomAdaptor_Surface::BSplineData* aBSplineData =
std::get_if<GeomAdaptor_Surface::BSplineData>(&theData))
{
return !aBSplineData->EvalRep.IsNull();
}
if (const GeomAdaptor_Surface::ExtrusionData* anExtrusionData =
std::get_if<GeomAdaptor_Surface::ExtrusionData>(&theData))
{
return !anExtrusionData->EvalRep.IsNull();
}
if (const GeomAdaptor_Surface::RevolutionData* aRevolutionData =
std::get_if<GeomAdaptor_Surface::RevolutionData>(&theData))
{
return !aRevolutionData->EvalRep.IsNull();
}
if (const GeomAdaptor_Surface::OffsetData* anOffsetData =
std::get_if<GeomAdaptor_Surface::OffsetData>(&theData))
{
return !anOffsetData->EvalRep.IsNull();
}
return false;
}
//=================================================================================================
@@ -320,6 +349,7 @@ occ::handle<Adaptor3d_Surface> 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<GeomAdaptor_Surface::RevolutionData>(&mySurfaceData))
@@ -327,6 +357,7 @@ occ::handle<Adaptor3d_Surface> 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<GeomAdaptor_Surface::OffsetData>(&mySurfaceData))
@@ -341,15 +372,24 @@ occ::handle<Adaptor3d_Surface> 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<GeomAdaptor_Surface::BSplineData>(&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<GeomAdaptor_Surface::BezierData>(&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<Geom_Surface>& 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<Geom_Surface>& 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<Geom_BezierSurface>(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<Geom_BSplineSurface>(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<Geom_Surface>& S,
myTolV);
anOffsetData.OffsetSurface = anOffSurf;
anOffsetData.Offset = anOffSurf->Offset();
anOffsetData.EvalRep = anOffSurf->EvalRepresentation();
// Check if equivalent canonical surface exists for faster evaluation
occ::handle<Geom_Surface> anEquivSurf = anOffSurf->Surface();
if (!anEquivSurf.IsNull())
@@ -1015,6 +1062,10 @@ std::optional<gp_Pnt> 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<BezierData>(mySurfaceData).Cache;
if (aCache.IsNull())
RebuildCache(U, V);
@@ -1022,6 +1073,10 @@ std::optional<gp_Pnt> 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<BSplineData>(mySurfaceData).Cache;
if (aCache.IsNull() || !aCache->IsCacheValid(U, V))
RebuildCache(U, V);
@@ -1030,6 +1085,10 @@ std::optional<gp_Pnt> GeomAdaptor_Surface::EvalD0(double U, double V) const
}
case GeomAbs_SurfaceOfExtrusion: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD0(U, V);
}
const auto& anExtData = std::get<GeomAdaptor_Surface::ExtrusionData>(mySurfaceData);
if (!Geom_ExtrusionUtils::D0(U, V, *anExtData.BasisCurve, anExtData.Direction, P))
return std::nullopt;
@@ -1037,6 +1096,10 @@ std::optional<gp_Pnt> GeomAdaptor_Surface::EvalD0(double U, double V) const
}
case GeomAbs_SurfaceOfRevolution: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD0(U, V);
}
const auto& aRevData = std::get<GeomAdaptor_Surface::RevolutionData>(mySurfaceData);
if (!Geom_RevolutionUtils::D0(U, V, *aRevData.BasisCurve, aRevData.Axis, P))
return std::nullopt;
@@ -1044,6 +1107,10 @@ std::optional<gp_Pnt> GeomAdaptor_Surface::EvalD0(double U, double V) const
}
case GeomAbs_OffsetSurface: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD0(U, V);
}
const auto& anOffData = std::get<GeomAdaptor_Surface::OffsetData>(mySurfaceData);
if (!offsetD0(U, V, anOffData, P))
return std::nullopt;
@@ -1123,6 +1190,10 @@ std::optional<Geom_Surface::ResD1> GeomAdaptor_Surface::EvalD1(double U, double
return aResult;
case GeomAbs_BezierSurface: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD1(U, V);
}
auto& aCache = std::get<BezierData>(mySurfaceData).Cache;
if (aCache.IsNull())
RebuildCache(U, V);
@@ -1130,6 +1201,10 @@ std::optional<Geom_Surface::ResD1> GeomAdaptor_Surface::EvalD1(double U, double
return aResult;
}
case GeomAbs_BSplineSurface: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD1(U, V);
}
auto& aBSplData = std::get<BSplineData>(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<Geom_Surface::ResD1> GeomAdaptor_Surface::EvalD1(double U, double
}
case GeomAbs_SurfaceOfExtrusion: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD1(U, V);
}
const auto& anExtData = std::get<GeomAdaptor_Surface::ExtrusionData>(mySurfaceData);
if (!Geom_ExtrusionUtils::D1(u,
v,
@@ -1157,6 +1236,10 @@ std::optional<Geom_Surface::ResD1> GeomAdaptor_Surface::EvalD1(double U, double
}
case GeomAbs_SurfaceOfRevolution: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD1(U, V);
}
const auto& aRevData = std::get<GeomAdaptor_Surface::RevolutionData>(mySurfaceData);
if (!Geom_RevolutionUtils::D1(u,
v,
@@ -1170,6 +1253,10 @@ std::optional<Geom_Surface::ResD1> GeomAdaptor_Surface::EvalD1(double U, double
}
case GeomAbs_OffsetSurface: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD1(U, V);
}
const auto& anOffData = std::get<GeomAdaptor_Surface::OffsetData>(mySurfaceData);
if (!offsetD1(u, v, anOffData, aResult.Point, aResult.D1U, aResult.D1V))
return std::nullopt;
@@ -1285,6 +1372,10 @@ std::optional<Geom_Surface::ResD2> GeomAdaptor_Surface::EvalD2(double U, double
return aResult;
case GeomAbs_BezierSurface: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD2(U, V);
}
auto& aCache = std::get<BezierData>(mySurfaceData).Cache;
if (aCache.IsNull())
RebuildCache(U, V);
@@ -1293,6 +1384,10 @@ std::optional<Geom_Surface::ResD2> GeomAdaptor_Surface::EvalD2(double U, double
return aResult;
}
case GeomAbs_BSplineSurface: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD2(U, V);
}
auto& aBSplData = std::get<BSplineData>(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<Geom_Surface::ResD2> GeomAdaptor_Surface::EvalD2(double U, double
}
case GeomAbs_SurfaceOfExtrusion: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD2(U, V);
}
const auto& anExtData = std::get<GeomAdaptor_Surface::ExtrusionData>(mySurfaceData);
if (!Geom_ExtrusionUtils::D2(u,
v,
@@ -1341,6 +1440,10 @@ std::optional<Geom_Surface::ResD2> GeomAdaptor_Surface::EvalD2(double U, double
}
case GeomAbs_SurfaceOfRevolution: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD2(U, V);
}
const auto& aRevData = std::get<GeomAdaptor_Surface::RevolutionData>(mySurfaceData);
if (!Geom_RevolutionUtils::D2(u,
v,
@@ -1357,6 +1460,10 @@ std::optional<Geom_Surface::ResD2> GeomAdaptor_Surface::EvalD2(double U, double
}
case GeomAbs_OffsetSurface: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD2(U, V);
}
const auto& anOffData = std::get<GeomAdaptor_Surface::OffsetData>(mySurfaceData);
if (!offsetD2(u,
v,
@@ -1508,6 +1615,10 @@ std::optional<Geom_Surface::ResD3> GeomAdaptor_Surface::EvalD3(double U, double
return aResult;
case GeomAbs_BSplineSurface: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD3(U, V);
}
const auto& aBSpl = std::get<BSplineData>(mySurfaceData).Surface;
if ((USide == 0) && (VSide == 0))
{
@@ -1547,6 +1658,10 @@ std::optional<Geom_Surface::ResD3> GeomAdaptor_Surface::EvalD3(double U, double
}
case GeomAbs_SurfaceOfExtrusion: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD3(U, V);
}
const auto& anExtData = std::get<GeomAdaptor_Surface::ExtrusionData>(mySurfaceData);
if (!Geom_ExtrusionUtils::D3(u,
v,
@@ -1567,6 +1682,10 @@ std::optional<Geom_Surface::ResD3> GeomAdaptor_Surface::EvalD3(double U, double
}
case GeomAbs_SurfaceOfRevolution: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD3(U, V);
}
const auto& aRevData = std::get<GeomAdaptor_Surface::RevolutionData>(mySurfaceData);
if (!Geom_RevolutionUtils::D3(u,
v,
@@ -1587,6 +1706,10 @@ std::optional<Geom_Surface::ResD3> GeomAdaptor_Surface::EvalD3(double U, double
}
case GeomAbs_OffsetSurface: {
if (hasEvalRep(mySurfaceData))
{
return mySurface->EvalD3(U, V);
}
const auto& anOffData = std::get<GeomAdaptor_Surface::OffsetData>(mySurfaceData);
if (!offsetD3(u,
v,
@@ -1650,6 +1773,10 @@ std::optional<gp_Vec> 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<BSplineData>(mySurfaceData).Surface;
if ((USide == 0) && (VSide == 0))
return aBSpl->EvalDN(u, v, Nu, Nv);
@@ -1663,6 +1790,10 @@ std::optional<gp_Vec> 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<GeomAdaptor_Surface::ExtrusionData>(mySurfaceData);
gp_Vec aDN;
if (!Geom_ExtrusionUtils::DN(u, *anExtData.BasisCurve, anExtData.Direction, Nu, Nv, aDN))
@@ -1671,6 +1802,10 @@ std::optional<gp_Vec> 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<GeomAdaptor_Surface::RevolutionData>(mySurfaceData);
gp_Vec aDN;
if (!Geom_RevolutionUtils::DN(u, v, *aRevData.BasisCurve, aRevData.Axis, Nu, Nv, aDN))
@@ -1679,6 +1814,10 @@ std::optional<gp_Vec> 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<GeomAdaptor_Surface::OffsetData>(mySurfaceData);
gp_Vec aDN;
if (!offsetDN(u, v, anOffData, Nu, Nv, aDN))
@@ -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<Adaptor3d_Curve> BasisCurve; //!< Adaptor for basis curve
gp_XYZ Direction; //!< Extrusion direction XYZ (normalized)
occ::handle<Adaptor3d_Curve> BasisCurve; //!< Adaptor for basis curve
gp_XYZ Direction; //!< Extrusion direction XYZ (normalized)
occ::handle<Geom_EvalRepSurfaceDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Internal structure for revolution surface evaluation data.
struct RevolutionData
{
occ::handle<Adaptor3d_Curve> BasisCurve; //!< Adaptor for basis curve
gp_Ax1 Axis; //!< Revolution axis
occ::handle<Adaptor3d_Curve> BasisCurve; //!< Adaptor for basis curve
gp_Ax1 Axis; //!< Revolution axis
occ::handle<Geom_EvalRepSurfaceDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Internal structure for offset surface evaluation data.
@@ -73,19 +81,23 @@ public:
occ::handle<Geom_OffsetSurface>
OffsetSurface; //!< Original offset surface for osculating queries
double Offset = 0.0; //!< Offset distance
occ::handle<Geom_EvalRepSurfaceDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Internal structure for Bezier surface cache data.
struct BezierData
{
mutable occ::handle<BSplSLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom_BezierSurface> Surface; //!< Bezier surface to prevent downcasts
mutable occ::handle<BSplSLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom_EvalRepSurfaceDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Internal structure for BSpline surface cache data.
struct BSplineData
{
occ::handle<Geom_BSplineSurface> Surface; //!< BSpline surface to prevent downcasts
mutable occ::handle<BSplSLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom_BSplineSurface> Surface; //!< BSpline surface to prevent downcasts
mutable occ::handle<BSplSLib_Cache> Cache; //!< Cached data for evaluation
occ::handle<Geom_EvalRepSurfaceDesc::Base> EvalRep; //!< Eval representation descriptor
};
//! Variant type for surface-specific evaluation data.