1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-09 13:22:24 +03:00
Files
occt/src/ModelingData/TKG2d/Geom2d/Geom2d_BezierCurve.cxx
Pasukhin Dmitry 0eb86fb05a Coding - Geom package Copy optimisation (#645)
- Adds copy constructors for 9 geometry classes (Bezier/BSpline curves and surfaces, offset curves and surfaces in both 2D and 3D)
- Updates Copy() methods to use the new copy constructors instead of recreating objects through standard constructors
- Includes comprehensive test coverage for all new copy constructors
2025-07-26 17:38:46 +01:00

729 lines
22 KiB
C++

// Created on: 1993-03-25
// Created by: JCV
// Copyright (c) 1993-1999 Matra Datavision
// Copyright (c) 1999-2014 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.
// Passage en classe persistante - 23/01/91
// Modif suite a la deuxieme revue de projet toolkit Geometry -23/01/91
// Infos :
// Actuellement pour les champs de la courbe le tableau des poles est
// declare de 1 a NbPoles et le tableau des poids est declare de 1 a NbPoles
// Revised RLE Aug 19 1993
// Suppressed Swaps, added Init, removed typedefs
#define No_Standard_OutOfRange
#define No_Standard_DimensionError
#include <Geom2d_BezierCurve.hxx>
#include <Geom2d_Geometry.hxx>
#include <gp.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Trsf2d.hxx>
#include <gp_Vec2d.hxx>
#include <PLib.hxx>
#include <Standard_ConstructionError.hxx>
#include <Standard_DimensionError.hxx>
#include <Standard_OutOfRange.hxx>
#include <Standard_RangeError.hxx>
#include <Standard_Type.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColStd_Array1OfReal.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Geom2d_BezierCurve, Geom2d_BoundedCurve)
//=======================================================================
// function : Rational
// purpose : check rationality of an array of weights
//=======================================================================
static Standard_Boolean Rational(const TColStd_Array1OfReal& W)
{
Standard_Integer i, n = W.Length();
Standard_Boolean rat = Standard_False;
for (i = 1; i < n; i++)
{
rat = Abs(W(i) - W(i + 1)) > gp::Resolution();
if (rat)
break;
}
return rat;
}
//=================================================================================================
Geom2d_BezierCurve::Geom2d_BezierCurve(const TColgp_Array1OfPnt2d& Poles)
{
// copy the poles
Handle(TColgp_HArray1OfPnt2d) npoles = new TColgp_HArray1OfPnt2d(1, Poles.Length());
npoles->ChangeArray1() = Poles;
// Init non rational
Init(npoles, Handle(TColStd_HArray1OfReal)());
}
//=================================================================================================
Geom2d_BezierCurve::Geom2d_BezierCurve(const TColgp_Array1OfPnt2d& Poles,
const TColStd_Array1OfReal& Weights)
{
// copy the poles
Handle(TColgp_HArray1OfPnt2d) npoles = new TColgp_HArray1OfPnt2d(1, Poles.Length());
npoles->ChangeArray1() = Poles;
// check the weights
Standard_Integer nbpoles = Poles.Length();
if (Weights.Length() != nbpoles)
throw Standard_ConstructionError();
Standard_Integer i;
for (i = 1; i <= nbpoles; i++)
{
if (Weights(i) <= gp::Resolution())
{
throw Standard_ConstructionError();
}
}
// check really rational
Standard_Boolean rat = Rational(Weights);
// copy the weights
Handle(TColStd_HArray1OfReal) nweights;
if (rat)
{
nweights = new TColStd_HArray1OfReal(1, nbpoles);
nweights->ChangeArray1() = Weights;
}
// Init
Init(npoles, nweights);
}
//=================================================================================================
Geom2d_BezierCurve::Geom2d_BezierCurve(const Geom2d_BezierCurve& theOther)
: rational(theOther.rational),
closed(theOther.closed),
maxderivinv(theOther.maxderivinv),
maxderivinvok(Standard_False)
{
// Deep copy all data arrays without validation
poles = new TColgp_HArray1OfPnt2d(theOther.poles->Lower(), theOther.poles->Upper());
poles->ChangeArray1() = theOther.poles->Array1();
if (!theOther.weights.IsNull())
{
weights = new TColStd_HArray1OfReal(theOther.weights->Lower(), theOther.weights->Upper());
weights->ChangeArray1() = theOther.weights->Array1();
}
}
//=================================================================================================
void Geom2d_BezierCurve::Increase(const Standard_Integer Deg)
{
if (Deg == Degree())
return;
Standard_ConstructionError_Raise_if(Deg < Degree() || Deg > Geom2d_BezierCurve::MaxDegree(),
"Geom2d_BezierCurve::Increase");
Handle(TColgp_HArray1OfPnt2d) npoles = new TColgp_HArray1OfPnt2d(1, Deg + 1);
Handle(TColStd_HArray1OfReal) nweights;
TColStd_Array1OfReal bidknots(1, 2);
bidknots(1) = 0.;
bidknots(2) = 1.;
TColStd_Array1OfInteger bidmults(1, 2);
bidmults.Init(Degree() + 1);
if (IsRational())
{
nweights = new TColStd_HArray1OfReal(1, Deg + 1);
BSplCLib::IncreaseDegree(Degree(),
Deg,
0,
poles->Array1(),
&weights->Array1(),
bidknots,
bidmults,
npoles->ChangeArray1(),
&nweights->ChangeArray1(),
bidknots,
bidmults);
}
else
{
BSplCLib::IncreaseDegree(Degree(),
Deg,
0,
poles->Array1(),
BSplCLib::NoWeights(),
bidknots,
bidmults,
npoles->ChangeArray1(),
BSplCLib::NoWeights(),
bidknots,
bidmults);
}
Init(npoles, nweights);
}
//=================================================================================================
Standard_Integer Geom2d_BezierCurve::MaxDegree()
{
return BSplCLib::MaxDegree();
}
//=================================================================================================
void Geom2d_BezierCurve::InsertPoleAfter(const Standard_Integer Index,
const gp_Pnt2d& P,
const Standard_Real Weight)
{
Standard_Integer nbpoles = NbPoles();
Standard_ConstructionError_Raise_if(nbpoles >= Geom2d_BezierCurve::MaxDegree()
|| Weight <= gp::Resolution(),
"Geom2d_BezierCurve::InsertPoleAfter");
Standard_OutOfRange_Raise_if(Index < 0 || Index > nbpoles, "Geom2d_BezierCurve::InsertPoleAfter");
Standard_Integer i;
// Insert the pole
Handle(TColgp_HArray1OfPnt2d) npoles = new TColgp_HArray1OfPnt2d(1, nbpoles + 1);
TColgp_Array1OfPnt2d& newpoles = npoles->ChangeArray1();
const TColgp_Array1OfPnt2d& oldpoles = poles->Array1();
for (i = 1; i <= Index; i++)
newpoles(i) = oldpoles(i);
newpoles(Index + 1) = P;
for (i = Index + 1; i <= nbpoles; i++)
newpoles(i + 1) = oldpoles(i);
// Insert the weight
Handle(TColStd_HArray1OfReal) nweights;
Standard_Boolean rat = IsRational() || Abs(Weight - 1.) > gp::Resolution();
if (rat)
{
nweights = new TColStd_HArray1OfReal(1, nbpoles + 1);
TColStd_Array1OfReal& newweights = nweights->ChangeArray1();
for (i = 1; i <= Index; i++)
if (IsRational())
newweights(i) = weights->Value(i);
else
newweights(i) = 1.;
newweights(Index + 1) = Weight;
for (i = Index + 1; i <= nbpoles; i++)
if (IsRational())
newweights(i + 1) = weights->Value(i);
else
newweights(i + 1) = 1.;
}
Init(npoles, nweights);
}
//=================================================================================================
void Geom2d_BezierCurve::InsertPoleBefore(const Standard_Integer Index,
const gp_Pnt2d& P,
const Standard_Real Weight)
{
InsertPoleAfter(Index - 1, P, Weight);
}
//=================================================================================================
void Geom2d_BezierCurve::RemovePole(const Standard_Integer Index)
{
Standard_Integer nbpoles = NbPoles();
Standard_ConstructionError_Raise_if(nbpoles <= 2, "Geom2d_BezierCurve::RemovePole");
Standard_OutOfRange_Raise_if(Index < 1 || Index > nbpoles, "Geom2d_BezierCurve::RemovePole");
Standard_Integer i;
// Remove the pole
Handle(TColgp_HArray1OfPnt2d) npoles = new TColgp_HArray1OfPnt2d(1, nbpoles - 1);
TColgp_Array1OfPnt2d& newpoles = npoles->ChangeArray1();
const TColgp_Array1OfPnt2d& oldpoles = poles->Array1();
for (i = 1; i < Index; i++)
newpoles(i) = oldpoles(i);
for (i = Index + 1; i <= nbpoles; i++)
newpoles(i - 1) = oldpoles(i);
// Remove the weight
Handle(TColStd_HArray1OfReal) nweights;
if (IsRational())
{
nweights = new TColStd_HArray1OfReal(1, nbpoles - 1);
TColStd_Array1OfReal& newweights = nweights->ChangeArray1();
const TColStd_Array1OfReal& oldweights = weights->Array1();
for (i = 1; i < Index; i++)
newweights(i) = oldweights(i);
for (i = Index + 1; i <= nbpoles; i++)
newweights(i - 1) = oldweights(i);
}
Init(npoles, nweights);
}
//=================================================================================================
void Geom2d_BezierCurve::Reverse()
{
gp_Pnt2d P;
Standard_Integer i, nbpoles = NbPoles();
TColgp_Array1OfPnt2d& cpoles = poles->ChangeArray1();
// reverse poles
for (i = 1; i <= nbpoles / 2; i++)
{
P = cpoles(i);
cpoles(i) = cpoles(nbpoles - i + 1);
cpoles(nbpoles - i + 1) = P;
}
// reverse weights
if (IsRational())
{
TColStd_Array1OfReal& cweights = weights->ChangeArray1();
Standard_Real w;
for (i = 1; i <= nbpoles / 2; i++)
{
w = cweights(i);
cweights(i) = cweights(nbpoles - i + 1);
cweights(nbpoles - i + 1) = w;
}
}
}
//=================================================================================================
Standard_Real Geom2d_BezierCurve::ReversedParameter(const Standard_Real U) const
{
return (1. - U);
}
//=================================================================================================
void Geom2d_BezierCurve::Segment(const Standard_Real U1, const Standard_Real U2)
{
closed = (Abs(Value(U1).Distance(Value(U2))) <= gp::Resolution());
//
// WARNING : when calling trimming be careful that the cache
// is computed regarding 0.0e0 and not 1.0e0
//
TColStd_Array1OfReal bidflatknots(BSplCLib::FlatBezierKnots(Degree()), 1, 2 * (Degree() + 1));
TColgp_Array1OfPnt2d coeffs(1, poles->Size());
if (IsRational())
{
TColStd_Array1OfReal wcoeffs(1, poles->Size());
BSplCLib::BuildCache(0.0,
1.0,
0,
Degree(),
bidflatknots,
poles->Array1(),
&weights->Array1(),
coeffs,
&wcoeffs);
PLib::Trimming(U1, U2, coeffs, &wcoeffs);
PLib::CoefficientsPoles(coeffs, &wcoeffs, poles->ChangeArray1(), &weights->ChangeArray1());
}
else
{
BSplCLib::BuildCache(0.0,
1.0,
0,
Degree(),
bidflatknots,
poles->Array1(),
BSplCLib::NoWeights(),
coeffs,
BSplCLib::NoWeights());
PLib::Trimming(U1, U2, coeffs, PLib::NoWeights());
PLib::CoefficientsPoles(coeffs, PLib::NoWeights(), poles->ChangeArray1(), PLib::NoWeights());
}
}
//=================================================================================================
void Geom2d_BezierCurve::SetPole(const Standard_Integer Index, const gp_Pnt2d& P)
{
Standard_OutOfRange_Raise_if(Index < 1 || Index > NbPoles(), "Geom2d_BezierCurve::SetPole");
TColgp_Array1OfPnt2d& cpoles = poles->ChangeArray1();
cpoles(Index) = P;
if (Index == 1 || Index == cpoles.Length())
{
closed = (cpoles(1).Distance(cpoles(NbPoles())) <= gp::Resolution());
}
}
//=================================================================================================
void Geom2d_BezierCurve::SetPole(const Standard_Integer Index,
const gp_Pnt2d& P,
const Standard_Real Weight)
{
SetPole(Index, P);
SetWeight(Index, Weight);
}
//=================================================================================================
void Geom2d_BezierCurve::SetWeight(const Standard_Integer Index, const Standard_Real Weight)
{
Standard_Integer nbpoles = NbPoles();
Standard_OutOfRange_Raise_if(Index < 1 || Index > nbpoles, "Geom2d_BezierCurve::SetWeight");
Standard_ConstructionError_Raise_if(Weight <= gp::Resolution(), "Geom2d_BezierCurve::SetWeight");
// compute new rationality
Standard_Boolean wasrat = IsRational();
if (!wasrat)
{
// a weight of 1. does not turn to rational
if (Abs(Weight - 1.) <= gp::Resolution())
return;
// set weights of 1.
weights = new TColStd_HArray1OfReal(1, nbpoles);
weights->Init(1.);
}
TColStd_Array1OfReal& cweights = weights->ChangeArray1();
cweights(Index) = Weight;
// is it turning into non rational
if (wasrat && !Rational(cweights))
weights.Nullify();
}
//=================================================================================================
Standard_Boolean Geom2d_BezierCurve::IsClosed() const
{
return closed;
}
//=================================================================================================
Standard_Boolean Geom2d_BezierCurve::IsCN(const Standard_Integer) const
{
return Standard_True;
}
//=================================================================================================
Standard_Boolean Geom2d_BezierCurve::IsPeriodic() const
{
return Standard_False;
}
//=================================================================================================
Standard_Boolean Geom2d_BezierCurve::IsRational() const
{
return !weights.IsNull();
}
//=================================================================================================
GeomAbs_Shape Geom2d_BezierCurve::Continuity() const
{
return GeomAbs_CN;
}
//=================================================================================================
Standard_Integer Geom2d_BezierCurve::Degree() const
{
return poles->Length() - 1;
}
//=================================================================================================
void Geom2d_BezierCurve::D0(const Standard_Real U, gp_Pnt2d& P) const
{
BSplCLib::D0(U, Poles(), Weights(), P);
}
//=================================================================================================
void Geom2d_BezierCurve::D1(const Standard_Real U, gp_Pnt2d& P, gp_Vec2d& V1) const
{
BSplCLib::D1(U, Poles(), Weights(), P, V1);
}
//=================================================================================================
void Geom2d_BezierCurve::D2(const Standard_Real U, gp_Pnt2d& P, gp_Vec2d& V1, gp_Vec2d& V2) const
{
BSplCLib::D2(U, Poles(), Weights(), P, V1, V2);
}
//=================================================================================================
void Geom2d_BezierCurve::D3(const Standard_Real U,
gp_Pnt2d& P,
gp_Vec2d& V1,
gp_Vec2d& V2,
gp_Vec2d& V3) const
{
BSplCLib::D3(U, Poles(), Weights(), P, V1, V2, V3);
}
//=================================================================================================
gp_Vec2d Geom2d_BezierCurve::DN(const Standard_Real U, const Standard_Integer N) const
{
Standard_RangeError_Raise_if(N < 1, "Geom2d_BezierCurve::DN");
gp_Vec2d V;
TColStd_Array1OfReal bidknots(1, 2);
bidknots(1) = 0.;
bidknots(2) = 1.;
TColStd_Array1OfInteger bidmults(1, 2);
bidmults.Init(Degree() + 1);
if (IsRational())
BSplCLib::DN(U,
N,
0,
Degree(),
Standard_False,
poles->Array1(),
&weights->Array1(),
bidknots,
&bidmults,
V);
else
BSplCLib::DN(U,
N,
0,
Degree(),
Standard_False,
poles->Array1(),
BSplCLib::NoWeights(),
bidknots,
&bidmults,
V);
return V;
}
//=================================================================================================
gp_Pnt2d Geom2d_BezierCurve::EndPoint() const
{
return poles->Value(poles->Upper());
}
//=================================================================================================
Standard_Real Geom2d_BezierCurve::FirstParameter() const
{
return 0.0;
}
//=================================================================================================
Standard_Real Geom2d_BezierCurve::LastParameter() const
{
return 1.0;
}
//=================================================================================================
Standard_Integer Geom2d_BezierCurve::NbPoles() const
{
return poles->Length();
}
//=================================================================================================
const gp_Pnt2d& Geom2d_BezierCurve::Pole(const Standard_Integer Index) const
{
Standard_OutOfRange_Raise_if(Index < 1 || Index > poles->Length(), "Geom2d_BezierCurve::Pole");
return poles->Value(Index);
}
//=================================================================================================
void Geom2d_BezierCurve::Poles(TColgp_Array1OfPnt2d& P) const
{
Standard_DimensionError_Raise_if(P.Length() != poles->Length(), "Geom2d_BezierCurve::Poles");
P = poles->Array1();
}
//=================================================================================================
gp_Pnt2d Geom2d_BezierCurve::StartPoint() const
{
return poles->Value(1);
}
//=================================================================================================
Standard_Real Geom2d_BezierCurve::Weight(const Standard_Integer Index) const
{
Standard_OutOfRange_Raise_if(Index < 1 || Index > weights->Length(),
"Geom2d_BezierCurve::Weight");
if (IsRational())
return weights->Value(Index);
else
return 1.;
}
//=================================================================================================
void Geom2d_BezierCurve::Weights(TColStd_Array1OfReal& W) const
{
Standard_Integer nbpoles = NbPoles();
Standard_DimensionError_Raise_if(W.Length() != nbpoles, "Geom2d_BezierCurve::Weights");
if (IsRational())
W = weights->Array1();
else
{
Standard_Integer i;
for (i = 1; i <= nbpoles; i++)
W(i) = 1.;
}
}
//=================================================================================================
void Geom2d_BezierCurve::Transform(const gp_Trsf2d& T)
{
Standard_Integer nbpoles = NbPoles();
TColgp_Array1OfPnt2d& cpoles = poles->ChangeArray1();
for (Standard_Integer i = 1; i <= nbpoles; i++)
cpoles(i).Transform(T);
}
//=================================================================================================
void Geom2d_BezierCurve::Resolution(const Standard_Real ToleranceUV, Standard_Real& UTolerance)
{
if (!maxderivinvok)
{
TColStd_Array1OfReal bidflatknots(1, 2 * (Degree() + 1));
for (Standard_Integer i = 1; i <= Degree() + 1; i++)
{
bidflatknots(i) = 0.;
bidflatknots(i + Degree() + 1) = 1.;
}
if (IsRational())
{
BSplCLib::Resolution(poles->Array1(),
&weights->Array1(),
poles->Length(),
bidflatknots,
Degree(),
1.,
maxderivinv);
}
else
{
BSplCLib::Resolution(poles->Array1(),
BSplCLib::NoWeights(),
poles->Length(),
bidflatknots,
Degree(),
1.,
maxderivinv);
}
maxderivinvok = 1;
}
UTolerance = ToleranceUV * maxderivinv;
}
//=================================================================================================
Handle(Geom2d_Geometry) Geom2d_BezierCurve::Copy() const
{
return new Geom2d_BezierCurve(*this);
}
//=================================================================================================
void Geom2d_BezierCurve::Init(const Handle(TColgp_HArray1OfPnt2d)& Poles,
const Handle(TColStd_HArray1OfReal)& Weights)
{
Standard_Integer nbpoles = Poles->Length();
// closed ?
const TColgp_Array1OfPnt2d& cpoles = Poles->Array1();
closed = cpoles(1).Distance(cpoles(nbpoles)) <= gp::Resolution();
// rational
rational = !Weights.IsNull();
// set fields
poles = Poles;
if (rational)
weights = Weights;
else
weights.Nullify();
}
//=================================================================================================
void Geom2d_BezierCurve::DumpJson(Standard_OStream& theOStream, Standard_Integer theDepth) const
{
OCCT_DUMP_TRANSIENT_CLASS_BEGIN(theOStream)
OCCT_DUMP_BASE_CLASS(theOStream, theDepth, Geom2d_BoundedCurve)
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, rational)
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, closed)
if (!poles.IsNull())
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, poles->Size())
if (!weights.IsNull())
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, weights->Size())
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, maxderivinv)
OCCT_DUMP_FIELD_VALUE_NUMERICAL(theOStream, maxderivinvok)
}