Loading files
f2929057eThis file is pinned to the selected release. Download the original to open it in your design tool.
// Created on: 1996-09-23
// Created by: Philippe MANGIN
// Copyright (c) 1996-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.
// Modified: Fri Jul 10 11:23:35 1998
// JCT : Add WithRatio,MinM
#include <Geom_BoundedCurve.hxx>
#include <Geom_BSplineCurve.hxx>
#include <GeomConvert.hxx>
#include <GeomConvert_CompCurveToBSplineCurve.hxx>
#include <gp_Pnt.hxx>
#include <gp_Vec.hxx>
#include <Precision.hxx>
#include <NCollection_Array1.hxx>
#include <Standard_Integer.hxx>
//=================================================================================================
GeomConvert_CompCurveToBSplineCurve::GeomConvert_CompCurveToBSplineCurve(
const Convert_ParameterisationType theParameterisation)
: myTol(Precision::Confusion()),
myType(theParameterisation)
{
}
//=================================================================================================
GeomConvert_CompCurveToBSplineCurve::GeomConvert_CompCurveToBSplineCurve(
const occ::handle<Geom_BoundedCurve>& BasisCurve,
const Convert_ParameterisationType Parameterisation)
: myTol(Precision::Confusion()),
myType(Parameterisation)
{
occ::handle<Geom_BSplineCurve> Bs = occ::down_cast<Geom_BSplineCurve>(BasisCurve);
if (!Bs.IsNull())
{
myCurve = occ::down_cast<Geom_BSplineCurve>(BasisCurve->Copy());
}
else
{
myCurve = GeomConvert::CurveToBSplineCurve(BasisCurve, myType);
}
}
//=================================================================================================
bool GeomConvert_CompCurveToBSplineCurve::Add(const occ::handle<Geom_BoundedCurve>& NewCurve,
const double Tolerance,
const bool After,
const bool WithRatio,
const int MinM)
{
// conversion
occ::handle<Geom_BSplineCurve> Bs = occ::down_cast<Geom_BSplineCurve>(NewCurve);
if (!Bs.IsNull())
{
Bs = occ::down_cast<Geom_BSplineCurve>(NewCurve->Copy());
}
else
{
Bs = GeomConvert::CurveToBSplineCurve(NewCurve, myType);
}
if (myCurve.IsNull())
{
myCurve = Bs;
return true;
}
bool avant, apres;
myTol = Tolerance;
// Use actual curve endpoints instead of poles for proper G0 continuity check.
// G0 continuity (positional continuity) requires curves to share endpoints.
// For non-clamped or periodic B-splines, first/last poles may not coincide with endpoints.
const gp_Pnt aCurveStart = myCurve->StartPoint();
const gp_Pnt aCurveEnd = myCurve->EndPoint();
const gp_Pnt aBsStart = Bs->StartPoint();
const gp_Pnt aBsEnd = Bs->EndPoint();
avant = ((aCurveStart.Distance(aBsStart) < myTol) || (aCurveStart.Distance(aBsEnd) < myTol));
apres = ((aCurveEnd.Distance(aBsStart) < myTol) || (aCurveEnd.Distance(aBsEnd) < myTol));
// Will myCurve be (or become) closed?
if (avant && apres)
{ // Resolve the ambiguity
if (After)
{
avant = false;
}
else
{
apres = false;
}
}
// Append after?
if (apres)
{
if (aCurveEnd.Distance(aBsEnd) < myTol)
{
Bs->Reverse();
}
Add(myCurve, Bs, true, WithRatio, MinM);
return true;
}
// Prepend before?
else if (avant)
{
if (aCurveStart.Distance(aBsStart) < myTol)
{
Bs->Reverse();
}
Add(Bs, myCurve, false, WithRatio, MinM);
return true;
}
return false;
}
//=================================================================================================
void GeomConvert_CompCurveToBSplineCurve::Add(occ::handle<Geom_BSplineCurve>& FirstCurve,
occ::handle<Geom_BSplineCurve>& SecondCurve,
const bool After,
const bool WithRatio,
const int MinM)
{
// Harmonize the degrees.
int Deg = std::max(FirstCurve->Degree(), SecondCurve->Degree());
if (FirstCurve->Degree() < Deg)
{
FirstCurve->IncreaseDegree(Deg);
}
if (SecondCurve->Degree() < Deg)
{
SecondCurve->IncreaseDegree(Deg);
}
// Declarations
double L1, L2;
int ii, jj;
double Ratio = 1, Ratio1, Ratio2, Delta1, Delta2;
int NbP1 = FirstCurve->NbPoles(), NbP2 = SecondCurve->NbPoles();
int NbK1 = FirstCurve->NbKnots(), NbK2 = SecondCurve->NbKnots();
NCollection_Array1<double> Noeuds(1, NbK1 + NbK2 - 1);
NCollection_Array1<gp_Pnt> Poles(1, NbP1 + NbP2 - 1);
NCollection_Array1<double> Poids(1, NbP1 + NbP2 - 1);
NCollection_Array1<int> Mults(1, NbK1 + NbK2 - 1);
// Reparameterization ratio (C1 if possible)
if (WithRatio)
{
L1 = FirstCurve->DN(FirstCurve->LastParameter(), 1).Magnitude();
L2 = SecondCurve->DN(SecondCurve->FirstParameter(), 1).Magnitude();
if ((L1 > Precision::Confusion()) && (L2 > Precision::Confusion()))
{
Ratio = L1 / L2;
}
if ((Ratio < Precision::Confusion()) || (Ratio > 1 / Precision::Confusion()))
{
Ratio = 1;
}
}
if (After)
{
// Do not move the first curve
Ratio1 = 1;
Delta1 = 0;
Ratio2 = 1 / Ratio;
Delta2 = Ratio2 * SecondCurve->Knot(1) - FirstCurve->Knot(NbK1);
}
else
{
// Do not move the second curve
Ratio1 = Ratio;
Delta1 = Ratio1 * FirstCurve->Knot(NbK1) - SecondCurve->Knot(1);
Ratio2 = 1;
Delta2 = 0;
}
// The Knots
double eps;
for (ii = 1; ii <= NbK1; ii++)
{
Noeuds(ii) = Ratio1 * FirstCurve->Knot(ii) - Delta1;
if (ii > 1)
{
eps = Epsilon(std::abs(Noeuds(ii - 1)));
if (eps < 5.e-10)
{
eps = 5.e-10;
}
if (Noeuds(ii) - Noeuds(ii - 1) <= eps)
{
Noeuds(ii) += eps;
}
}
Mults(ii) = FirstCurve->Multiplicity(ii);
}
Mults(NbK1) = FirstCurve->Degree();
for (ii = 2, jj = NbK1 + 1; ii <= NbK2; ii++, jj++)
{
Noeuds(jj) = Ratio2 * SecondCurve->Knot(ii) - Delta2;
eps = Epsilon(std::abs(Noeuds(jj - 1)));
if (eps < 5.e-10)
{
eps = 5.e-10;
}
if (Noeuds(jj) - Noeuds(jj - 1) <= eps)
{
Noeuds(jj) += eps;
}
Mults(jj) = SecondCurve->Multiplicity(ii);
}
Ratio = FirstCurve->Weight(NbP1);
Ratio /= SecondCurve->Weight(1);
// The Poles and Weights
for (ii = 1; ii < NbP1; ii++)
{
Poles(ii) = FirstCurve->Pole(ii);
Poids(ii) = FirstCurve->Weight(ii);
}
for (ii = 1, jj = NbP1; ii <= NbP2; ii++, jj++)
{
Poles(jj) = SecondCurve->Pole(ii);
//
// Note: the weights may not necessarily connect with C0 continuity,
// hence the use of Ratio
//
Poids(jj) = Ratio * SecondCurve->Weight(ii);
}
// Create the BSpline
myCurve = new (Geom_BSplineCurve)(Poles, Poids, Noeuds, Mults, Deg);
// Optionally reduce multiplicity down to MinM
bool Ok = true;
int M = Mults(NbK1);
while ((M > MinM) && Ok)
{
M--;
Ok = myCurve->RemoveKnot(NbK1, M, myTol);
}
}
//=================================================================================================
occ::handle<Geom_BSplineCurve> GeomConvert_CompCurveToBSplineCurve::BSplineCurve() const
{
return myCurve;
}
//=================================================================================================
void GeomConvert_CompCurveToBSplineCurve::Clear()
{
myCurve.Nullify();
}