1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-05 18:16:23 +03:00
occt/src/Geom2d/Geom2d_BSplineCurve.cxx

1250 lines
38 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.
//Avril 1991 : constructeurs + methodes de lecture.
//Mai 1991 : revue des specifs + debut de realisation des classes tool =>
// implementation des methodes Set et calcul du point courant.
//Juillet 1991 : voir egalement File Geom2d_BSplineCurve_1.cxx
//Juin 1992 : mise a plat des valeurs nodales - amelioration des
// performances sur calcul du point courant
//RLE Aug 1993 Remove Swaps, Init methods, Remove typedefs
// 14-Mar-96 : xab implemented MovePointAndTangent
//SAMTECH Jan 2002 : add text to Raise()
#define No_Standard_OutOfRange
#include <BSplCLib.hxx>
#include <Geom2d_BSplineCurve.hxx>
#include <Geom2d_Geometry.hxx>
#include <Geom2d_UndefinedDerivative.hxx>
#include <gp.hxx>
#include <gp_Pnt2d.hxx>
#include <gp_Vec2d.hxx>
#include <Precision.hxx>
#include <Standard_ConstructionError.hxx>
#include <Standard_DomainError.hxx>
#include <Standard_NoSuchObject.hxx>
#include <Standard_NotImplemented.hxx>
#include <Standard_OutOfRange.hxx>
#include <Standard_Type.hxx>
IMPLEMENT_STANDARD_RTTIEXT(Geom2d_BSplineCurve,Geom2d_BoundedCurve)
//=======================================================================
//function : CheckCurveData
//purpose : Internal use only
//=======================================================================
static void CheckCurveData
(const TColgp_Array1OfPnt2d& CPoles,
const TColStd_Array1OfReal& CKnots,
const TColStd_Array1OfInteger& CMults,
const Standard_Integer Degree,
const Standard_Boolean Periodic)
{
if (Degree < 1 || Degree > Geom2d_BSplineCurve::MaxDegree()) {
throw Standard_ConstructionError("BSpline curve: invalid degree");
}
if (CPoles.Length() < 2) throw Standard_ConstructionError("BSpline curve: at least 2 poles required");
if (CKnots.Length() != CMults.Length()) throw Standard_ConstructionError("BSpline curve: Knot and Mult array size mismatch");
for (Standard_Integer I = CKnots.Lower(); I < CKnots.Upper(); I++) {
if (CKnots (I+1) - CKnots (I) <= Epsilon (Abs(CKnots (I)))) {
throw Standard_ConstructionError("BSpline curve: Knots interval values too close");
}
}
if (CPoles.Length() != BSplCLib::NbPoles(Degree,Periodic,CMults))
throw Standard_ConstructionError("BSpline curve: # Poles and degree mismatch");
}
//! Check rationality of an array of weights
static Standard_Boolean Rational (const TColStd_Array1OfReal& theWeights)
{
for (Standard_Integer i = theWeights.Lower(); i < theWeights.Upper(); i++)
{
if (Abs (theWeights[i] - theWeights[i + 1]) > gp::Resolution())
{
return Standard_True;
}
}
return Standard_False;
}
//=======================================================================
//function : Copy
//purpose :
//=======================================================================
Handle(Geom2d_Geometry) Geom2d_BSplineCurve::Copy() const
{
Handle(Geom2d_BSplineCurve) C;
if (IsRational())
C = new Geom2d_BSplineCurve(poles->Array1(),
weights->Array1(),
knots->Array1(),
mults->Array1(),
deg,periodic);
else
C = new Geom2d_BSplineCurve(poles->Array1(),
knots->Array1(),
mults->Array1(),
deg,periodic);
return C;
}
//=======================================================================
//function : Geom2d_BSplineCurve
//purpose :
//=======================================================================
Geom2d_BSplineCurve::Geom2d_BSplineCurve
(const TColgp_Array1OfPnt2d& Poles,
const TColStd_Array1OfReal& Knots,
const TColStd_Array1OfInteger& Mults,
const Standard_Integer Degree,
const Standard_Boolean Periodic) :
rational(Standard_False),
periodic(Periodic),
deg(Degree),
maxderivinvok(Standard_False)
{
// check
CheckCurveData(Poles,
Knots,
Mults,
Degree,
Periodic);
// copy arrays
poles = new TColgp_HArray1OfPnt2d(1,Poles.Length());
poles->ChangeArray1() = Poles;
knots = new TColStd_HArray1OfReal(1,Knots.Length());
knots->ChangeArray1() = Knots;
mults = new TColStd_HArray1OfInteger(1,Mults.Length());
mults->ChangeArray1() = Mults;
UpdateKnots();
}
//=======================================================================
//function : Geom2d_BSplineCurve
//purpose :
//=======================================================================
Geom2d_BSplineCurve::Geom2d_BSplineCurve
(const TColgp_Array1OfPnt2d& Poles,
const TColStd_Array1OfReal& Weights,
const TColStd_Array1OfReal& Knots,
const TColStd_Array1OfInteger& Mults,
const Standard_Integer Degree,
const Standard_Boolean Periodic) :
rational(Standard_True),
periodic(Periodic),
deg(Degree),
maxderivinvok(Standard_False)
{
// check
CheckCurveData(Poles,
Knots,
Mults,
Degree,
Periodic);
if (Weights.Length() != Poles.Length())
throw Standard_ConstructionError("Geom2d_BSplineCurve: Weights and Poles array size mismatch");
Standard_Integer i;
for (i = Weights.Lower(); i <= Weights.Upper(); i++) {
if (Weights(i) <= gp::Resolution()) {
throw Standard_ConstructionError("Geom2d_BSplineCurve: Weights values too small");
}
}
// check really rational
rational = Rational(Weights);
// copy arrays
poles = new TColgp_HArray1OfPnt2d(1,Poles.Length());
poles->ChangeArray1() = Poles;
if (rational) {
weights = new TColStd_HArray1OfReal(1,Weights.Length());
weights->ChangeArray1() = Weights;
}
knots = new TColStd_HArray1OfReal(1,Knots.Length());
knots->ChangeArray1() = Knots;
mults = new TColStd_HArray1OfInteger(1,Mults.Length());
mults->ChangeArray1() = Mults;
UpdateKnots();
}
//=======================================================================
//function : MaxDegree
//purpose :
//=======================================================================
Standard_Integer Geom2d_BSplineCurve::MaxDegree ()
{
return BSplCLib::MaxDegree();
}
//=======================================================================
//function : IncreaseDegree
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::IncreaseDegree
(const Standard_Integer Degree)
{
if (Degree == deg) return;
if (Degree < deg || Degree > Geom2d_BSplineCurve::MaxDegree()) {
throw Standard_ConstructionError("BSpline curve: IncreaseDegree: bad degree value");
}
Standard_Integer FromK1 = FirstUKnotIndex ();
Standard_Integer ToK2 = LastUKnotIndex ();
Standard_Integer Step = Degree - deg;
Handle(TColgp_HArray1OfPnt2d) npoles = new
TColgp_HArray1OfPnt2d(1,poles->Length() + Step * (ToK2-FromK1));
Standard_Integer nbknots = BSplCLib::IncreaseDegreeCountKnots
(deg,Degree,periodic,mults->Array1());
Handle(TColStd_HArray1OfReal) nknots =
new TColStd_HArray1OfReal(1,nbknots);
Handle(TColStd_HArray1OfInteger) nmults =
new TColStd_HArray1OfInteger(1,nbknots);
Handle(TColStd_HArray1OfReal) nweights;
if (IsRational()) {
nweights = new TColStd_HArray1OfReal(1,npoles->Upper());
}
BSplCLib::IncreaseDegree (deg, Degree, periodic,
poles->Array1(), !nweights.IsNull() ? &weights->Array1() : BSplCLib::NoWeights(),
knots->Array1(), mults->Array1(),
npoles->ChangeArray1(), !nweights.IsNull() ? &nweights->ChangeArray1() : BSplCLib::NoWeights(),
nknots->ChangeArray1(), nmults->ChangeArray1());
deg = Degree;
poles = npoles;
weights = nweights;
knots = nknots;
mults = nmults;
UpdateKnots();
}
//=======================================================================
//function : IncreaseMultiplicity
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::IncreaseMultiplicity
(const Standard_Integer Index,
const Standard_Integer M)
{
TColStd_Array1OfReal k(1,1);
k(1) = knots->Value(Index);
TColStd_Array1OfInteger m(1,1);
m(1) = M - mults->Value(Index);
InsertKnots(k,m,Epsilon(1.),Standard_True);
}
//=======================================================================
//function : IncreaseMultiplicity
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::IncreaseMultiplicity
(const Standard_Integer I1,
const Standard_Integer I2,
const Standard_Integer M)
{
Handle(TColStd_HArray1OfReal) tk = knots;
TColStd_Array1OfReal k((knots->Array1())(I1),I1,I2);
TColStd_Array1OfInteger m(I1,I2);
Standard_Integer i;
for (i = I1; i <= I2; i++)
m(i) = M - mults->Value(i);
InsertKnots(k,m,Epsilon(1.),Standard_True);
}
//=======================================================================
//function : IncrementMultiplicity
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::IncrementMultiplicity
(const Standard_Integer I1,
const Standard_Integer I2,
const Standard_Integer Step)
{
Handle(TColStd_HArray1OfReal) tk = knots;
TColStd_Array1OfReal k((knots->Array1())(I1),I1,I2);
TColStd_Array1OfInteger m(I1,I2);
m.Init(Step);
InsertKnots(k,m,Epsilon(1.),Standard_True);
}
//=======================================================================
//function : InsertKnot
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::InsertKnot
(const Standard_Real U,
const Standard_Integer M,
const Standard_Real ParametricTolerance)
{
TColStd_Array1OfReal k(1,1);
k(1) = U;
TColStd_Array1OfInteger m(1,1);
m(1) = M;
InsertKnots(k,m,ParametricTolerance);
}
//=======================================================================
//function : InsertKnots
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::InsertKnots(const TColStd_Array1OfReal& Knots,
const TColStd_Array1OfInteger& Mults,
const Standard_Real Epsilon,
const Standard_Boolean Add)
{
// Check and compute new sizes
Standard_Integer nbpoles,nbknots;
if (!BSplCLib::PrepareInsertKnots(deg,periodic,
knots->Array1(),mults->Array1(),
Knots,&Mults,nbpoles,nbknots,Epsilon,Add))
throw Standard_ConstructionError("Geom2d_BSplineCurve::InsertKnots");
if (nbpoles == poles->Length()) return;
Handle(TColgp_HArray1OfPnt2d) npoles = new TColgp_HArray1OfPnt2d(1,nbpoles);
Handle(TColStd_HArray1OfReal) nknots = knots;
Handle(TColStd_HArray1OfInteger) nmults = mults;
if (nbknots != knots->Length()) {
nknots = new TColStd_HArray1OfReal(1,nbknots);
nmults = new TColStd_HArray1OfInteger(1,nbknots);
}
Handle(TColStd_HArray1OfReal) nweights;
if (rational)
{
nweights = new TColStd_HArray1OfReal (1, nbpoles);
}
BSplCLib::InsertKnots (deg, periodic,
poles->Array1(), !nweights.IsNull() ? &weights->Array1() : BSplCLib::NoWeights(),
knots->Array1(), mults->Array1(),
Knots, &Mults,
npoles->ChangeArray1(), !nweights.IsNull() ? &nweights->ChangeArray1() : BSplCLib::NoWeights(),
nknots->ChangeArray1(), nmults->ChangeArray1(),
Epsilon, Add);
weights = nweights;
poles = npoles;
knots = nknots;
mults = nmults;
UpdateKnots();
}
//=======================================================================
//function : RemoveKnot
//purpose :
//=======================================================================
Standard_Boolean Geom2d_BSplineCurve::RemoveKnot
(const Standard_Integer Index,
const Standard_Integer M,
const Standard_Real Tolerance)
{
if (M < 0) return Standard_True;
Standard_Integer I1 = FirstUKnotIndex ();
Standard_Integer I2 = LastUKnotIndex ();
if (Index < I1 || Index > I2) {
throw Standard_OutOfRange("BSpline curve: RemoveKnot: index out of range");
}
const TColgp_Array1OfPnt2d & oldpoles = poles->Array1();
Standard_Integer step = mults->Value(Index) - M;
if (step <= 0) return Standard_True;
Handle(TColgp_HArray1OfPnt2d) npoles =
new TColgp_HArray1OfPnt2d(1,oldpoles.Length()-step);
Handle(TColStd_HArray1OfReal) nknots = knots;
Handle(TColStd_HArray1OfInteger) nmults = mults;
if (M == 0) {
nknots = new TColStd_HArray1OfReal(1,knots->Length()-1);
nmults = new TColStd_HArray1OfInteger(1,knots->Length()-1);
}
Handle(TColStd_HArray1OfReal) nweights;
if (IsRational())
{
nweights = new TColStd_HArray1OfReal(1,npoles->Length());
}
if (!BSplCLib::RemoveKnot (Index, M, deg, periodic,
poles->Array1(), !nweights.IsNull() ? &weights->Array1() : BSplCLib::NoWeights(),
knots->Array1(),mults->Array1(),
npoles->ChangeArray1(), !nweights.IsNull() ? &nweights->ChangeArray1() : BSplCLib::NoWeights(),
nknots->ChangeArray1(),nmults->ChangeArray1(),
Tolerance))
{
return Standard_False;
}
weights = nweights;
poles = npoles;
knots = nknots;
mults = nmults;
UpdateKnots();
maxderivinvok = 0;
return Standard_True;
}
//=======================================================================
//function : InsertPoleAfter
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::InsertPoleAfter
(const Standard_Integer Index,
const gp_Pnt2d& P,
const Standard_Real Weight)
{
if (Index < 0 || Index > poles->Length()) throw Standard_OutOfRange("BSpline curve: InsertPoleAfter: Index and #pole mismatch");
if (Weight <= gp::Resolution()) throw Standard_ConstructionError("BSpline curve: InsertPoleAfter: Weight too small");
if (knotSet == GeomAbs_NonUniform || knotSet == GeomAbs_PiecewiseBezier) {
throw Standard_ConstructionError("BSpline curve: InsertPoleAfter: bad knotSet type");
}
const TColStd_Array1OfReal& cknots = knots->Array1();
Standard_Integer nbknots = cknots.Length();
Handle(TColStd_HArray1OfReal) nknots =
new TColStd_HArray1OfReal(1,nbknots+1);
TColStd_Array1OfReal& newknots = nknots->ChangeArray1();
Standard_Integer i;
for (i = 1; i < nbknots; i++) {
newknots (i) = cknots(i);
}
newknots (nbknots+1) = 2 * newknots (nbknots) - newknots(nbknots-1);
Handle(TColStd_HArray1OfInteger) nmults =
new TColStd_HArray1OfInteger(1,nbknots+1);
TColStd_Array1OfInteger& newmults = nmults->ChangeArray1();
const TColStd_Array1OfInteger& cmults = mults->Array1();
for (i = 2; i <= nbknots; i++) newmults (i) = 1;
newmults (1) = cmults(1);
newmults (nbknots+1) = cmults(nbknots+1);
const TColgp_Array1OfPnt2d& cpoles = poles->Array1();
Standard_Integer nbpoles = cpoles.Length();
Handle(TColgp_HArray1OfPnt2d) npoles =
new TColgp_HArray1OfPnt2d(1, nbpoles+1);
TColgp_Array1OfPnt2d& newpoles = npoles->ChangeArray1();
// insert the pole
for (i = 1; i <= Index; i++)
newpoles(i) = cpoles(i);
newpoles(Index+1) = P;
for (i = Index+1; i <= nbpoles; i++)
newpoles(i+1) = cpoles(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.;
}
poles = npoles;
weights = nweights;
knots = nknots;
mults = nmults;
maxderivinvok = 0;
UpdateKnots();
}
//=======================================================================
//function : InsertPoleBefore
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::InsertPoleBefore
(const Standard_Integer Index,
const gp_Pnt2d& P,
const Standard_Real Weight)
{
InsertPoleAfter(Index-1,P,Weight);
}
//=======================================================================
//function : RemovePole
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::RemovePole
(const Standard_Integer Index)
{
if (Index < 1 || Index > poles->Length()) throw Standard_OutOfRange("BSpline curve: RemovePole: Index and #pole mismatch");
if (poles->Length() <= 2) throw Standard_ConstructionError("BSpline curve: RemovePole: #pole is already minimum");
if (knotSet == GeomAbs_NonUniform || knotSet == GeomAbs_PiecewiseBezier)
throw Standard_ConstructionError("BSpline curve: RemovePole: bad knotSet type");
Standard_Integer i;
Handle(TColStd_HArray1OfReal) nknots =
new TColStd_HArray1OfReal(1,knots->Length()-1);
TColStd_Array1OfReal& newknots = nknots->ChangeArray1();
Handle(TColStd_HArray1OfInteger) nmults =
new TColStd_HArray1OfInteger(1,mults->Length()-1);
TColStd_Array1OfInteger& newmults = nmults->ChangeArray1();
for (i = 1; i < newknots.Length(); i++) {
newknots (i) = knots->Value (i);
newmults (i) = 1;
}
newmults(1) = mults->Value(1);
newknots(newknots.Upper()) = knots->Value (knots->Upper());
newmults(newmults.Upper()) = mults->Value (mults->Upper());
Handle(TColgp_HArray1OfPnt2d) npoles =
new TColgp_HArray1OfPnt2d(1, poles->Upper()-1);
TColgp_Array1OfPnt2d& newpoles = npoles->ChangeArray1();
for (i = 1; i < Index; i++)
newpoles(i) = poles->Value(i);
for (i = Index; i < newpoles.Length(); i++)
newpoles(i) = poles->Value(i+1);
Handle(TColStd_HArray1OfReal) nweights;
if (IsRational()) {
nweights = new TColStd_HArray1OfReal(1,newpoles.Length());
TColStd_Array1OfReal& newweights = nweights->ChangeArray1();
for (i = 1; i < Index; i++)
newweights(i) = weights->Value(i);
for (i = Index; i < newweights.Length(); i++)
newweights(i) = weights->Value(i+1);
}
poles = npoles;
weights = nweights;
knots = nknots;
mults = nmults;
UpdateKnots();
}
//=======================================================================
//function : Reverse
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::Reverse ()
{
BSplCLib::Reverse(knots->ChangeArray1());
BSplCLib::Reverse(mults->ChangeArray1());
Standard_Integer last;
if (periodic)
last = flatknots->Upper() - deg - 1;
else
last = poles->Upper();
BSplCLib::Reverse(poles->ChangeArray1(),last);
if (rational)
BSplCLib::Reverse(weights->ChangeArray1(),last);
UpdateKnots();
}
//=======================================================================
//function : ReversedParameter
//purpose :
//=======================================================================
Standard_Real Geom2d_BSplineCurve::ReversedParameter( const Standard_Real U) const
{
return (FirstParameter() + LastParameter() - U);
}
//=======================================================================
//function : Segment
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::Segment(const Standard_Real aU1,
const Standard_Real aU2,
const Standard_Real theTolerance)
{
if (aU2 < aU1)
throw Standard_DomainError("Geom2d_BSplineCurve::Segment");
//
Standard_Real AbsUMax = Max(Abs(FirstParameter()),Abs(LastParameter()));
Standard_Real Eps = Max (Epsilon(AbsUMax), theTolerance);
Standard_Real NewU1, NewU2;
Standard_Real U, DU=0;
Standard_Integer i, k, index;
//
//f
Standard_Real U1 = aU1, U2 = aU2;
//
// Henceforward we use U1, U2 as bounds of the segment
//t
//
TColStd_Array1OfReal Knots(1,2);
TColStd_Array1OfInteger Mults(1,2);
//
// define param distance to keep (eap, Apr 18 2002, occ311)
if (periodic) {
Standard_Real Period = LastParameter() - FirstParameter();
DU = U2 - U1;
if (DU - Period > Precision::PConfusion())
throw Standard_DomainError("Geom2d_BSplineCurve::Segment");
if (DU > Period)
DU = Period;
}
//
index = 0;
BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
U1,periodic,knots->Lower(),knots->Upper(),
index,NewU1);
index = 0;
BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
U2,periodic,knots->Lower(),knots->Upper(),
index,NewU2);
Knots(1) = Min( NewU1, NewU2);
Knots(2) = Max( NewU1, NewU2);
Mults(1) = Mults( 2) = deg;
InsertKnots(Knots, Mults, Eps);
if (periodic) { // set the origine at NewU1
index = 0;
BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
U1,periodic,knots->Lower(),knots->Upper(),
index,U);
// Eps = Epsilon(knots->Value(index+1));
if ( Abs(knots->Value(index+1)-U) <= Eps) {
index++;
}
SetOrigin(index);
SetNotPeriodic();
NewU2 = NewU1 + DU;
}
// compute index1 and index2 to set the new knots and mults
Standard_Integer index1 = 0, index2 = 0;
Standard_Integer FromU1 = knots->Lower();
Standard_Integer ToU2 = knots->Upper();
BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
NewU1,periodic,FromU1,ToU2,index1,U);
if (Abs(knots->Value(index1 + 1) - U) <= Eps){
index1++;
}
BSplCLib::LocateParameter(deg,knots->Array1(),mults->Array1(),
NewU2,periodic,FromU1,ToU2,index2,U);
// Eps = Epsilon(knots->Value(index2+1));
if ( Abs(knots->Value(index2+1)-U) <= Eps || index2 == index1){
index2++;
}
Standard_Integer nbknots = index2 - index1 + 1;
Handle(TColStd_HArray1OfReal)
nknots = new TColStd_HArray1OfReal(1,nbknots);
Handle(TColStd_HArray1OfInteger)
nmults = new TColStd_HArray1OfInteger(1,nbknots);
// to restore changed U1
if (DU > 0) {// if was periodic
DU = NewU1 - U1;
}
//
k = 1;
//
for ( i = index1; i<= index2; i++) {
nknots->SetValue(k, knots->Value(i) - DU);
nmults->SetValue(k, mults->Value(i));
k++;
}
nmults->SetValue( 1, deg + 1);
nmults->SetValue(nbknots, deg + 1);
// compute index1 and index2 to set the new poles and weights
Standard_Integer pindex1
= BSplCLib::PoleIndex(deg,index1,periodic,mults->Array1());
Standard_Integer pindex2
= BSplCLib::PoleIndex(deg,index2,periodic,mults->Array1());
pindex1++;
pindex2 = Min( pindex2+1, poles->Length());
Standard_Integer nbpoles = pindex2 - pindex1 + 1;
Handle(TColStd_HArray1OfReal)
nweights = new TColStd_HArray1OfReal(1,nbpoles);
Handle(TColgp_HArray1OfPnt2d)
npoles = new TColgp_HArray1OfPnt2d(1,nbpoles);
k = 1;
if ( rational) {
nweights = new TColStd_HArray1OfReal( 1, nbpoles);
for ( i = pindex1; i <= pindex2; i++) {
npoles->SetValue(k, poles->Value(i));
nweights->SetValue(k, weights->Value(i));
k++;
}
}
else {
for ( i = pindex1; i <= pindex2; i++) {
npoles->SetValue(k, poles->Value(i));
k++;
}
}
knots = nknots;
mults = nmults;
poles = npoles;
if (rational){
weights = nweights;
}
UpdateKnots();
}
//=======================================================================
//function : SetKnot
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::SetKnot
(const Standard_Integer Index,
const Standard_Real K)
{
if (Index < 1 || Index > knots->Length()) throw Standard_OutOfRange("BSpline curve: SetKnot: Index and #knots mismatch");
Standard_Real DK = Abs(Epsilon (K));
if (Index == 1) {
if (K >= knots->Value(2) - DK) throw Standard_ConstructionError("BSpline curve: SetKnot: K out of range");
}
else if (Index == knots->Length()) {
if (K <= knots->Value (knots->Length()-1) + DK) {
throw Standard_ConstructionError("BSpline curve: SetKnot: K out of range");
}
}
else {
if (K <= knots->Value(Index-1) + DK ||
K >= knots->Value(Index+1) - DK ) {
throw Standard_ConstructionError("BSpline curve: SetKnot: K out of range");
}
}
if (K != knots->Value (Index)) {
knots->SetValue (Index, K);
maxderivinvok = 0;
UpdateKnots();
}
}
//=======================================================================
//function : SetKnots
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::SetKnots
(const TColStd_Array1OfReal& K)
{
CheckCurveData(poles->Array1(),K,mults->Array1(),deg,periodic);
knots->ChangeArray1() = K;
maxderivinvok = 0;
UpdateKnots();
}
//=======================================================================
//function : SetKnot
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::SetKnot
(const Standard_Integer Index,
const Standard_Real K,
const Standard_Integer M)
{
IncreaseMultiplicity (Index, M);
SetKnot (Index, K);
}
//=======================================================================
//function : SetPeriodic
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::SetPeriodic ()
{
Standard_Integer first = FirstUKnotIndex();
Standard_Integer last = LastUKnotIndex();
Handle(TColStd_HArray1OfReal) tk = knots;
TColStd_Array1OfReal cknots((knots->Array1())(first),first,last);
knots = new TColStd_HArray1OfReal(1,cknots.Length());
knots->ChangeArray1() = cknots;
Handle(TColStd_HArray1OfInteger) tm = mults;
TColStd_Array1OfInteger cmults((mults->Array1())(first),first,last);
cmults(first) = cmults(last) = Min(deg, Max( cmults(first), cmults(last)));
mults = new TColStd_HArray1OfInteger(1,cmults.Length());
mults->ChangeArray1() = cmults;
// compute new number of poles;
Standard_Integer nbp = BSplCLib::NbPoles(deg,Standard_True,cmults);
Handle(TColgp_HArray1OfPnt2d) tp = poles;
TColgp_Array1OfPnt2d cpoles((poles->Array1())(1),1,nbp);
poles = new TColgp_HArray1OfPnt2d(1,nbp);
poles->ChangeArray1() = cpoles;
if (rational) {
Handle(TColStd_HArray1OfReal) tw = weights;
TColStd_Array1OfReal cweights((weights->Array1())(1),1,nbp);
weights = new TColStd_HArray1OfReal(1,nbp);
weights->ChangeArray1() = cweights;
}
periodic = Standard_True;
maxderivinvok = 0;
UpdateKnots();
}
//=======================================================================
//function : SetOrigin
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::SetOrigin(const Standard_Integer Index)
{
if (!periodic)
throw Standard_NoSuchObject("Geom2d_BSplineCurve::SetOrigin");
Standard_Integer i,k;
Standard_Integer first = FirstUKnotIndex();
Standard_Integer last = LastUKnotIndex();
if ((Index < first) || (Index > last))
throw Standard_DomainError("Geom2d_BSplineCurve::SetOrigin");
Standard_Integer nbknots = knots->Length();
Standard_Integer nbpoles = poles->Length();
Handle(TColStd_HArray1OfReal) nknots =
new TColStd_HArray1OfReal(1,nbknots);
TColStd_Array1OfReal& newknots = nknots->ChangeArray1();
Handle(TColStd_HArray1OfInteger) nmults =
new TColStd_HArray1OfInteger(1,nbknots);
TColStd_Array1OfInteger& newmults = nmults->ChangeArray1();
// set the knots and mults
Standard_Real period = knots->Value(last) - knots->Value(first);
k = 1;
for ( i = Index; i <= last ; i++) {
newknots(k) = knots->Value(i);
newmults(k) = mults->Value(i);
k++;
}
for ( i = first+1; i <= Index; i++) {
newknots(k) = knots->Value(i) + period;
newmults(k) = mults->Value(i);
k++;
}
Standard_Integer index = 1;
for (i = first+1; i <= Index; i++)
index += mults->Value(i);
// set the poles and weights
Handle(TColgp_HArray1OfPnt2d) npoles =
new TColgp_HArray1OfPnt2d(1,nbpoles);
Handle(TColStd_HArray1OfReal) nweights =
new TColStd_HArray1OfReal(1,nbpoles);
TColgp_Array1OfPnt2d & newpoles = npoles->ChangeArray1();
TColStd_Array1OfReal & newweights = nweights->ChangeArray1();
first = poles->Lower();
last = poles->Upper();
if ( rational) {
k = 1;
for ( i = index; i <= last; i++) {
newpoles(k) = poles->Value(i);
newweights(k) = weights->Value(i);
k++;
}
for ( i = first; i < index; i++) {
newpoles(k) = poles->Value(i);
newweights(k) = weights->Value(i);
k++;
}
}
else {
k = 1;
for ( i = index; i <= last; i++) {
newpoles(k) = poles->Value(i);
k++;
}
for ( i = first; i < index; i++) {
newpoles(k) = poles->Value(i);
k++;
}
}
poles = npoles;
knots = nknots;
mults = nmults;
if (rational)
weights = nweights;
maxderivinvok = 0;
UpdateKnots();
}
//=======================================================================
//function : SetNotPeriodic
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::SetNotPeriodic ()
{
if (periodic) {
Standard_Integer NbKnots, NbPoles;
BSplCLib::PrepareUnperiodize( deg, mults->Array1(),NbKnots,NbPoles);
Handle(TColgp_HArray1OfPnt2d) npoles
= new TColgp_HArray1OfPnt2d(1,NbPoles);
Handle(TColStd_HArray1OfReal) nknots
= new TColStd_HArray1OfReal(1,NbKnots);
Handle(TColStd_HArray1OfInteger) nmults
= new TColStd_HArray1OfInteger(1,NbKnots);
Handle(TColStd_HArray1OfReal) nweights;
if (IsRational()) {
nweights = new TColStd_HArray1OfReal(1,NbPoles);
}
BSplCLib::Unperiodize (deg,
mults->Array1(), knots->Array1(), poles->Array1(),
!nweights.IsNull() ? &weights->Array1() : BSplCLib::NoWeights(),
nmults->ChangeArray1(), nknots->ChangeArray1(), npoles->ChangeArray1(),
!nweights.IsNull() ? &nweights->ChangeArray1() : BSplCLib::NoWeights());
poles = npoles;
weights = nweights;
mults = nmults;
knots = nknots;
periodic = Standard_False;
maxderivinvok = 0;
UpdateKnots();
}
}
//=======================================================================
//function : SetPole
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::SetPole
(const Standard_Integer Index,
const gp_Pnt2d& P)
{
if (Index < 1 || Index > poles->Length()) throw Standard_OutOfRange("BSpline curve: SetPole: index and #pole mismatch");
poles->SetValue (Index, P);
maxderivinvok = 0;
}
//=======================================================================
//function : SetPole
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::SetPole
(const Standard_Integer Index,
const gp_Pnt2d& P,
const Standard_Real W)
{
SetPole(Index,P);
SetWeight(Index,W);
}
//=======================================================================
//function : SetWeight
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::SetWeight
(const Standard_Integer Index,
const Standard_Real W)
{
if (Index < 1 || Index > poles->Length()) throw Standard_OutOfRange("BSpline curve: SetWeight: Index and #pole mismatch");
if (W <= gp::Resolution ()) throw Standard_ConstructionError("BSpline curve: SetWeight: Weight too small");
Standard_Boolean rat = IsRational() || (Abs(W - 1.) > gp::Resolution());
if ( rat) {
if (rat && !IsRational()) {
weights = new TColStd_HArray1OfReal(1,poles->Length());
weights->Init(1.);
}
weights->SetValue (Index, W);
if (IsRational()) {
rat = Rational(weights->Array1());
if (!rat) weights.Nullify();
}
rational = !weights.IsNull();
}
maxderivinvok = 0;
}
//=======================================================================
//function : MovePoint
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::MovePoint(const Standard_Real U,
const gp_Pnt2d& P,
const Standard_Integer Index1,
const Standard_Integer Index2,
Standard_Integer& FirstModifiedPole,
Standard_Integer& LastmodifiedPole)
{
if (Index1 < 1 || Index1 > poles->Length() ||
Index2 < 1 || Index2 > poles->Length() || Index1 > Index2) {
throw Standard_OutOfRange("BSpline curve: MovePoint: Index and #pole mismatch");
}
TColgp_Array1OfPnt2d npoles(1, poles->Length());
gp_Pnt2d P0;
D0(U, P0);
gp_Vec2d Displ(P0, P);
BSplCLib::MovePoint (U, Displ, Index1, Index2, deg, poles->Array1(),
rational ? &weights->Array1() : BSplCLib::NoWeights(), flatknots->Array1(),
FirstModifiedPole, LastmodifiedPole, npoles);
if (FirstModifiedPole) {
poles->ChangeArray1() = npoles;
maxderivinvok = 0;
}
}
//=======================================================================
//function : MovePointAndTangent
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::
MovePointAndTangent(const Standard_Real U,
const gp_Pnt2d& P,
const gp_Vec2d& Tangent,
const Standard_Real Tolerance,
const Standard_Integer StartingCondition,
const Standard_Integer EndingCondition,
Standard_Integer& ErrorStatus)
{
Standard_Integer ii ;
if (IsPeriodic()) {
//
// for the time being do not deal with periodic curves
//
SetNotPeriodic() ;
}
TColgp_Array1OfPnt2d new_poles(1, poles->Length());
gp_Pnt2d P0;
gp_Vec2d delta_derivative;
D1(U, P0,
delta_derivative) ;
gp_Vec2d delta(P0, P);
for (ii = 1 ; ii <= 2 ; ii++) {
delta_derivative.SetCoord(ii,
Tangent.Coord(ii)- delta_derivative.Coord(ii)) ;
}
BSplCLib::MovePointAndTangent (U,
delta,
delta_derivative,
Tolerance,
deg,
StartingCondition,
EndingCondition,
poles->Array1(),
rational ? &weights->Array1() : BSplCLib::NoWeights(),
flatknots->Array1(),
new_poles,
ErrorStatus);
if (!ErrorStatus) {
poles->ChangeArray1() = new_poles;
maxderivinvok = 0;
}
}
//=======================================================================
//function : UpdateKnots
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::UpdateKnots()
{
rational = !weights.IsNull();
Standard_Integer MaxKnotMult = 0;
BSplCLib::KnotAnalysis (deg,
periodic,
knots->Array1(),
mults->Array1(),
knotSet, MaxKnotMult);
if (knotSet == GeomAbs_Uniform && !periodic) {
flatknots = knots;
}
else {
flatknots = new TColStd_HArray1OfReal
(1, BSplCLib::KnotSequenceLength(mults->Array1(),deg,periodic));
BSplCLib::KnotSequence (knots->Array1(),
mults->Array1(),
deg,periodic,
flatknots->ChangeArray1());
}
if (MaxKnotMult == 0) smooth = GeomAbs_CN;
else {
switch (deg - MaxKnotMult) {
case 0 : smooth = GeomAbs_C0; break;
case 1 : smooth = GeomAbs_C1; break;
case 2 : smooth = GeomAbs_C2; break;
case 3 : smooth = GeomAbs_C3; break;
default : smooth = GeomAbs_C3; break;
}
}
}
//=======================================================================
//function : Normalizes the parameters if the curve is periodic
//purpose : that is compute the cache so that it is valid
//=======================================================================
void Geom2d_BSplineCurve::PeriodicNormalization(Standard_Real& Parameter) const
{
Standard_Real Period ;
if (periodic) {
Period = flatknots->Value(flatknots->Upper() - deg) - flatknots->Value (deg + 1) ;
while (Parameter > flatknots->Value(flatknots->Upper()-deg)) {
Parameter -= Period ;
}
while (Parameter < flatknots->Value((deg + 1))) {
Parameter += Period ;
}
}
}
//=======================================================================
//function : DumpJson
//purpose :
//=======================================================================
void Geom2d_BSplineCurve::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, periodic)
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, knotSet)
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, smooth)
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, deg)
if (!poles.IsNull())
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, poles->Size())
if (!weights.IsNull())
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, weights->Size())
if (!flatknots.IsNull())
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, flatknots->Size())
if (!knots.IsNull())
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, knots->Size())
if (!mults.IsNull())
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, mults->Size())
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, maxderivinv)
OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, maxderivinvok)
}