Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
c5f20409cThis file is pinned to the selected release. Download the original to open it in your design tool.
// Created on: 1993-03-30
// Created by: Laurent BUCHARD
// 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.
#include <AppParCurves_Constraint.hxx>
#include <ApproxInt_KnotTools.hxx>
#include <GeomAbs_SurfaceType.hxx>
#include <IntSurf_PntOn2S.hxx>
#include <IntSurf_Quadric.hxx>
#include <Precision.hxx>
#include <gp_Trsf.hxx>
#include <gp_Trsf2d.hxx>
// If quantity of points is less than aMinNbPointsForApprox
// then interpolation is used.
const Standard_Integer aMinNbPointsForApprox = 5;
// This constant should be removed in the future.
const Standard_Real RatioTol = 1.5;
//=================================================================================================
static void ComputeTrsf3d(const Handle(TheWLine)& theline,
Standard_Real& theXo,
Standard_Real& theYo,
Standard_Real& theZo)
{
const Standard_Integer aNbPnts = theline->NbPnts();
Standard_Real aXmin = RealLast(), aYmin = RealLast(), aZmin = RealLast();
for (Standard_Integer i = 1; i <= aNbPnts; i++)
{
const gp_Pnt P = theline->Point(i).Value();
aXmin = Min(P.X(), aXmin);
aYmin = Min(P.Y(), aYmin);
aZmin = Min(P.Z(), aZmin);
}
theXo = -aXmin;
theYo = -aYmin;
theZo = -aZmin;
}
//=================================================================================================
static void ComputeTrsf2d(const Handle(TheWLine)& theline,
const Standard_Boolean onFirst,
Standard_Real& theUo,
Standard_Real& theVo)
{
const Standard_Integer aNbPnts = theline->NbPnts();
Standard_Real aUmin = RealLast(), aVmin = RealLast();
// pointer to a member-function
void (IntSurf_PntOn2S::*pfunc)(Standard_Real&, Standard_Real&) const;
if (onFirst)
pfunc = &IntSurf_PntOn2S::ParametersOnS1;
else
pfunc = &IntSurf_PntOn2S::ParametersOnS2;
for (Standard_Integer i = 1; i <= aNbPnts; i++)
{
const IntSurf_PntOn2S POn2S = theline->Point(i);
Standard_Real U, V;
(POn2S.*pfunc)(U, V);
aUmin = Min(U, aUmin);
aVmin = Min(V, aVmin);
}
theUo = -aUmin;
theVo = -aVmin;
}
//=================================================================================================
void ApproxInt_Approx::Parameters(const ApproxInt_TheMultiLine& Line,
const Standard_Integer firstP,
const Standard_Integer lastP,
const Approx_ParametrizationType Par,
math_Vector& TheParameters)
{
Standard_Integer i, j, nbP2d, nbP3d;
Standard_Real dist;
if (Par == Approx_ChordLength || Par == Approx_Centripetal)
{
nbP3d = ApproxInt_TheMultiLineTool::NbP3d(Line);
nbP2d = ApproxInt_TheMultiLineTool::NbP2d(Line);
Standard_Integer mynbP3d = nbP3d, mynbP2d = nbP2d;
if (nbP3d == 0)
mynbP3d = 1;
if (nbP2d == 0)
mynbP2d = 1;
TheParameters(firstP) = 0.0;
dist = 0.0;
TColgp_Array1OfPnt tabP(1, mynbP3d);
TColgp_Array1OfPnt tabPP(1, mynbP3d);
TColgp_Array1OfPnt2d tabP2d(1, mynbP2d);
TColgp_Array1OfPnt2d tabPP2d(1, mynbP2d);
for (i = firstP + 1; i <= lastP; i++)
{
if (nbP3d != 0 && nbP2d != 0)
ApproxInt_TheMultiLineTool::Value(Line, i - 1, tabP, tabP2d);
else if (nbP2d != 0)
ApproxInt_TheMultiLineTool::Value(Line, i - 1, tabP2d);
else if (nbP3d != 0)
ApproxInt_TheMultiLineTool::Value(Line, i - 1, tabP);
if (nbP3d != 0 && nbP2d != 0)
ApproxInt_TheMultiLineTool::Value(Line, i, tabPP, tabPP2d);
else if (nbP2d != 0)
ApproxInt_TheMultiLineTool::Value(Line, i, tabPP2d);
else if (nbP3d != 0)
ApproxInt_TheMultiLineTool::Value(Line, i, tabPP);
dist = 0;
for (j = 1; j <= nbP3d; j++)
{
const gp_Pnt &aP1 = tabP(j), &aP2 = tabPP(j);
dist += aP2.SquareDistance(aP1);
}
for (j = 1; j <= nbP2d; j++)
{
const gp_Pnt2d &aP12d = tabP2d(j), &aP22d = tabPP2d(j);
dist += aP22d.SquareDistance(aP12d);
}
dist = Sqrt(dist);
if (Par == Approx_ChordLength)
{
TheParameters(i) = TheParameters(i - 1) + dist;
}
else
{ // Par == Approx_Centripetal
TheParameters(i) = TheParameters(i - 1) + Sqrt(dist);
}
}
for (i = firstP; i <= lastP; i++)
TheParameters(i) /= TheParameters(lastP);
}
else
{
for (i = firstP; i <= lastP; i++)
{
TheParameters(i) =
(Standard_Real(i) - firstP) / (Standard_Real(lastP) - Standard_Real(firstP));
}
}
}
//=================================================================================================
ApproxInt_Approx::ApproxInt_Approx() :
myComputeLine(4, 8, 0.001, 0.001, 5),
myComputeLineBezier(4, 8, 0.001, 0.001, 5),
myWithTangency(Standard_True),
myTol3d(0.001),
myTol2d(0.001),
myDegMin(4),
myDegMax(8),
myNbIterMax(5),
myTolReached3d(0.0),
myTolReached2d(0.0)
{
myComputeLine.SetContinuity(2);
// myComputeLineBezier.SetContinuity(2);
}
//=================================================================================================
void ApproxInt_Approx::Perform(const Handle(TheWLine)& theline,
const Standard_Boolean ApproxXYZ,
const Standard_Boolean ApproxU1V1,
const Standard_Boolean ApproxU2V2,
const Standard_Integer indicemin,
const Standard_Integer indicemax)
{
// Prepare DS.
prepareDS(ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax);
const Standard_Integer nbpntbez = myData.indicemax - myData.indicemin;
if (nbpntbez < aMinNbPointsForApprox)
myData.myBezierApprox = Standard_False;
else
myData.myBezierApprox = Standard_True;
// Fill data structure.
fillData(theline);
// Build knots.
buildKnots(theline, NULL);
if (myKnots.Length() == 2 && indicemax - indicemin > 2 * myData.myNbPntMax)
{
// At least 3 knots for BrepApprox.
myKnots.ChangeLast() = (indicemax - indicemin) / 2;
myKnots.Append(indicemax);
}
myComputeLine
.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, myData.parametrization);
myComputeLineBezier
.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, myData.parametrization);
buildCurve(theline, NULL);
}
//=================================================================================================
// function : Perform
// purpose : Definition of next steps according to surface types
// (i.e. coordination algorithm).
//=================================================================================================
void ApproxInt_Approx::Perform(const ThePSurface& Surf1,
const ThePSurface& Surf2,
const Handle(TheWLine)& theline,
const Standard_Boolean ApproxXYZ,
const Standard_Boolean ApproxU1V1,
const Standard_Boolean ApproxU2V2,
const Standard_Integer indicemin,
const Standard_Integer indicemax)
{
myTolReached3d = myTolReached2d = 0.;
const GeomAbs_SurfaceType typeS1 = ThePSurfaceTool::GetType(Surf1);
const GeomAbs_SurfaceType typeS2 = ThePSurfaceTool::GetType(Surf2);
const Standard_Boolean isQuadric =
((typeS1 == GeomAbs_Plane) || (typeS1 == GeomAbs_Cylinder) || (typeS1 == GeomAbs_Sphere) ||
(typeS1 == GeomAbs_Cone) || (typeS2 == GeomAbs_Plane) || (typeS2 == GeomAbs_Cylinder) ||
(typeS2 == GeomAbs_Sphere) || (typeS2 == GeomAbs_Cone));
if (isQuadric)
{
IntSurf_Quadric Quad;
Standard_Boolean SecondIsImplicit = Standard_False;
switch (typeS1)
{
case GeomAbs_Plane:
Quad.SetValue(ThePSurfaceTool::Plane(Surf1));
break;
case GeomAbs_Cylinder:
Quad.SetValue(ThePSurfaceTool::Cylinder(Surf1));
break;
case GeomAbs_Sphere:
Quad.SetValue(ThePSurfaceTool::Sphere(Surf1));
break;
case GeomAbs_Cone:
Quad.SetValue(ThePSurfaceTool::Cone(Surf1));
break;
default: {
SecondIsImplicit = Standard_True;
switch (typeS2)
{
case GeomAbs_Plane:
Quad.SetValue(ThePSurfaceTool::Plane(Surf2));
break;
case GeomAbs_Cylinder:
Quad.SetValue(ThePSurfaceTool::Cylinder(Surf2));
break;
case GeomAbs_Sphere:
Quad.SetValue(ThePSurfaceTool::Sphere(Surf2));
break;
case GeomAbs_Cone:
Quad.SetValue(ThePSurfaceTool::Cone(Surf2));
break;
default:
break;
} // switch (typeS2)
}
break;
} // switch (typeS1)
Perform(Quad,
(SecondIsImplicit ? Surf1 : Surf2),
theline,
ApproxXYZ,
ApproxU1V1,
ApproxU2V2,
indicemin,
indicemax,
!SecondIsImplicit);
return;
}
// Here, isQuadric == FALSE.
// Prepare DS.
prepareDS(ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax);
// Non-analytical case: Param-Param perform.
ApproxInt_ThePrmPrmSvSurfaces myPrmPrmSvSurfaces(Surf1, Surf2);
Standard_Integer nbpntbez = indicemax - indicemin;
if (nbpntbez < aMinNbPointsForApprox)
{
myData.myBezierApprox = Standard_False;
}
else
{
myData.myBezierApprox = Standard_True;
}
// Fill data structure.
fillData(theline);
const Standard_Boolean cut = myData.myBezierApprox;
const Standard_Address ptrsvsurf = &myPrmPrmSvSurfaces;
// Build knots.
buildKnots(theline, ptrsvsurf);
myComputeLine
.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, cut, myData.parametrization);
myComputeLineBezier
.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, cut, myData.parametrization);
buildCurve(theline, ptrsvsurf);
}
//=================================================================================================
// function : Perform
// purpose : Analytic-Param perform.
//=================================================================================================
void ApproxInt_Approx::Perform(const TheISurface& ISurf,
const ThePSurface& PSurf,
const Handle(TheWLine)& theline,
const Standard_Boolean ApproxXYZ,
const Standard_Boolean ApproxU1V1,
const Standard_Boolean ApproxU2V2,
const Standard_Integer indicemin,
const Standard_Integer indicemax,
const Standard_Boolean isTheQuadFirst)
{
// Prepare DS.
prepareDS(ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax);
// Non-analytical case: Analytic-Param perform.
ApproxInt_TheImpPrmSvSurfaces myImpPrmSvSurfaces =
isTheQuadFirst ? ApproxInt_TheImpPrmSvSurfaces(ISurf, PSurf)
: ApproxInt_TheImpPrmSvSurfaces(PSurf, ISurf);
myImpPrmSvSurfaces.SetUseSolver(Standard_False);
const Standard_Integer nbpntbez = indicemax - indicemin;
if (nbpntbez < aMinNbPointsForApprox)
{
myData.myBezierApprox = Standard_False;
}
else
{
myData.myBezierApprox = Standard_True;
}
const Standard_Boolean cut = myData.myBezierApprox;
const Standard_Address ptrsvsurf = &myImpPrmSvSurfaces;
// Fill data structure.
fillData(theline);
// Build knots.
buildKnots(theline, ptrsvsurf);
myComputeLine
.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, cut, myData.parametrization);
myComputeLineBezier
.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, cut, myData.parametrization);
buildCurve(theline, ptrsvsurf);
}
//=================================================================================================
void ApproxInt_Approx::SetParameters(const Standard_Real Tol3d,
const Standard_Real Tol2d,
const Standard_Integer DegMin,
const Standard_Integer DegMax,
const Standard_Integer NbIterMax,
const Standard_Integer NbPntMax,
const Standard_Boolean ApproxWithTangency,
const Approx_ParametrizationType Parametrization)
{
myData.myNbPntMax = NbPntMax;
myWithTangency = ApproxWithTangency;
myTol3d = Tol3d / RatioTol;
myTol2d = Tol2d / RatioTol;
myDegMin = DegMin;
myDegMax = DegMax;
myNbIterMax = NbIterMax;
myComputeLine
.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, Parametrization);
myComputeLineBezier
.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, Parametrization);
if (!ApproxWithTangency)
{
myComputeLine.SetConstraints(AppParCurves_PassPoint, AppParCurves_PassPoint);
myComputeLineBezier.SetConstraints(AppParCurves_PassPoint, AppParCurves_PassPoint);
}
myData.myBezierApprox = Standard_True;
}
//=================================================================================================
Standard_Integer ApproxInt_Approx::NbMultiCurves() const
{
return 1;
}
//=================================================================================================
void ApproxInt_Approx::UpdateTolReached()
{
if (myData.myBezierApprox)
{
const Standard_Integer NbCurves = myComputeLineBezier.NbMultiCurves();
for (Standard_Integer ICur = 1; ICur <= NbCurves; ICur++)
{
Standard_Real Tol3D, Tol2D;
myComputeLineBezier.Error(ICur, Tol3D, Tol2D);
myTolReached3d = Max(myTolReached3d, Tol3D);
myTolReached2d = Max(myTolReached2d, Tol2D);
}
}
else
{
myComputeLine.Error(myTolReached3d, myTolReached2d);
}
}
//=================================================================================================
Standard_Real ApproxInt_Approx::TolReached3d() const
{
return myTolReached3d * RatioTol;
}
//=================================================================================================
Standard_Real ApproxInt_Approx::TolReached2d() const
{
return myTolReached2d * RatioTol;
}
//=================================================================================================
Standard_Boolean ApproxInt_Approx::IsDone() const
{
if (myData.myBezierApprox)
{
return (myComputeLineBezier.NbMultiCurves() > 0);
}
else
{
return (myComputeLine.IsToleranceReached());
}
}
//=================================================================================================
const AppParCurves_MultiBSpCurve& ApproxInt_Approx::Value(const Standard_Integer) const
{
if (myData.myBezierApprox)
{
return (myBezToBSpl.Value());
}
else
{
return (myComputeLine.Value());
}
}
//=================================================================================================
void ApproxInt_Approx::fillData(const Handle(TheWLine)& theline)
{
if (myData.ApproxXYZ)
ComputeTrsf3d(theline, myData.Xo, myData.Yo, myData.Zo);
else
myData.Xo = myData.Yo = myData.Zo = 0.0;
if (myData.ApproxU1V1)
ComputeTrsf2d(theline, Standard_True, myData.U1o, myData.V1o);
else
myData.U1o = myData.V1o = 0.0;
if (myData.ApproxU2V2)
ComputeTrsf2d(theline, Standard_False, myData.U2o, myData.V2o);
else
myData.U2o = myData.V2o = 0.0;
}
//=================================================================================================
void ApproxInt_Approx::prepareDS(const Standard_Boolean theApproxXYZ,
const Standard_Boolean theApproxU1V1,
const Standard_Boolean theApproxU2V2,
const Standard_Integer theIndicemin,
const Standard_Integer theIndicemax)
{
myTolReached3d = myTolReached2d = 0.0;
myData.ApproxU1V1 = theApproxU1V1;
myData.ApproxU2V2 = theApproxU2V2;
myData.ApproxXYZ = theApproxXYZ;
myData.indicemin = theIndicemin;
myData.indicemax = theIndicemax;
myData.parametrization = myComputeLineBezier.Parametrization();
}
//=================================================================================================
void ApproxInt_Approx::buildKnots(const Handle(TheWLine)& theline,
const Standard_Address thePtrSVSurf)
{
myKnots.Clear();
if (!myData.myBezierApprox)
{
myKnots.Append(myData.indicemin);
myKnots.Append(myData.indicemax);
return;
}
const ApproxInt_TheMultiLine aTestLine(theline,
thePtrSVSurf,
((myData.ApproxXYZ) ? 1 : 0),
((myData.ApproxU1V1) ? 1 : 0) +
((myData.ApproxU2V2) ? 1 : 0),
myData.ApproxU1V1,
myData.ApproxU2V2,
myData.Xo,
myData.Yo,
myData.Zo,
myData.U1o,
myData.V1o,
myData.U2o,
myData.V2o,
myData.ApproxU1V1,
myData.indicemin,
myData.indicemax);
const Standard_Integer nbp3d = aTestLine.NbP3d(), nbp2d = aTestLine.NbP2d();
TColgp_Array1OfPnt aTabPnt3d(1, Max(1, nbp3d));
TColgp_Array1OfPnt2d aTabPnt2d(1, Max(1, nbp2d));
TColgp_Array1OfPnt aPntXYZ(myData.indicemin, myData.indicemax);
TColgp_Array1OfPnt2d aPntU1V1(myData.indicemin, myData.indicemax);
TColgp_Array1OfPnt2d aPntU2V2(myData.indicemin, myData.indicemax);
for (Standard_Integer i = myData.indicemin; i <= myData.indicemax; ++i)
{
if (nbp3d != 0 && nbp2d != 0)
aTestLine.Value(i, aTabPnt3d, aTabPnt2d);
else if (nbp2d != 0)
aTestLine.Value(i, aTabPnt2d);
else if (nbp3d != 0)
aTestLine.Value(i, aTabPnt3d);
//
if (nbp3d > 0)
{
aPntXYZ(i) = aTabPnt3d(1);
}
if (nbp2d > 1)
{
aPntU1V1(i) = aTabPnt2d(1);
aPntU2V2(i) = aTabPnt2d(2);
}
else if (nbp2d > 0)
{
if (myData.ApproxU1V1)
{
aPntU1V1(i) = aTabPnt2d(1);
}
else
{
aPntU2V2(i) = aTabPnt2d(1);
}
}
}
Standard_Integer aMinNbPnts = myData.myNbPntMax;
// Expected parametrization.
math_Vector aPars(myData.indicemin, myData.indicemax);
Parameters(aTestLine, myData.indicemin, myData.indicemax, myData.parametrization, aPars);
ApproxInt_KnotTools::BuildKnots(aPntXYZ,
aPntU1V1,
aPntU2V2,
aPars,
myData.ApproxXYZ,
myData.ApproxU1V1,
myData.ApproxU2V2,
aMinNbPnts,
myKnots);
}
//=================================================================================================
void ApproxInt_Approx::buildCurve(const Handle(TheWLine)& theline,
const Standard_Address thePtrSVSurf)
{
if (myData.myBezierApprox)
{
myBezToBSpl.Reset();
}
Standard_Integer kind = myKnots.Lower();
Standard_Integer imin = 0, imax = 0;
Standard_Boolean OtherInter = Standard_False;
do
{
// Base cycle: iterate over knots.
imin = myKnots(kind);
imax = myKnots(kind + 1);
ApproxInt_TheMultiLine myMultiLine(theline,
thePtrSVSurf,
((myData.ApproxXYZ) ? 1 : 0),
((myData.ApproxU1V1) ? 1 : 0) +
((myData.ApproxU2V2) ? 1 : 0),
myData.ApproxU1V1,
myData.ApproxU2V2,
myData.Xo,
myData.Yo,
myData.Zo,
myData.U1o,
myData.V1o,
myData.U2o,
myData.V2o,
myData.ApproxU1V1,
imin,
imax);
if (myData.myBezierApprox)
{
myComputeLineBezier.Perform(myMultiLine);
if (myComputeLineBezier.NbMultiCurves() == 0)
return;
}
else
{
myComputeLine.Perform(myMultiLine);
}
UpdateTolReached();
Standard_Integer indice3d = 1, indice2d1 = 2, indice2d2 = 3;
if (!myData.ApproxXYZ)
{
indice2d1--;
indice2d2--;
}
if (!myData.ApproxU1V1)
{
indice2d2--;
}
if (myData.ApproxXYZ)
{
if (myData.myBezierApprox)
{
for (Standard_Integer nbmc = myComputeLineBezier.NbMultiCurves(); nbmc >= 1; nbmc--)
{
myComputeLineBezier.ChangeValue(nbmc)
.Transform(indice3d, -myData.Xo, 1.0, -myData.Yo, 1.0, -myData.Zo, 1.0);
}
}
else
{
myComputeLine.ChangeValue()
.Transform(indice3d, -myData.Xo, 1.0, -myData.Yo, 1.0, -myData.Zo, 1.0);
}
}
if (myData.ApproxU1V1)
{
if (myData.myBezierApprox)
{
for (Standard_Integer nbmc = myComputeLineBezier.NbMultiCurves(); nbmc >= 1; nbmc--)
{
myComputeLineBezier.ChangeValue(nbmc).Transform2d(indice2d1,
-myData.U1o,
1.0,
-myData.V1o,
1.0);
}
}
else
{
myComputeLine.ChangeValue().Transform2d(indice2d1, -myData.U1o, 1.0, -myData.V1o, 1.0);
}
}
if (myData.ApproxU2V2)
{
if (myData.myBezierApprox)
{
for (Standard_Integer nbmc = myComputeLineBezier.NbMultiCurves(); nbmc >= 1; nbmc--)
{
myComputeLineBezier.ChangeValue(nbmc).Transform2d(indice2d2,
-myData.U2o,
1.0,
-myData.V2o,
1.0);
}
}
else
{
myComputeLine.ChangeValue().Transform2d(indice2d2, -myData.U2o, 1.0, -myData.V2o, 1.0);
}
}
OtherInter = Standard_False;
if (myData.myBezierApprox)
{
for (Standard_Integer nbmc = 1; nbmc <= myComputeLineBezier.NbMultiCurves(); nbmc++)
{
myBezToBSpl.Append(myComputeLineBezier.Value(nbmc));
}
kind++;
if (kind < myKnots.Upper())
{
OtherInter = Standard_True;
}
}
} while (OtherInter);
if (myData.myBezierApprox)
{
myBezToBSpl.Perform();
}
}