1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-06 18:26:22 +03:00
occt/src/IntPatch/IntPatch_ALineToWLine.cxx
gelin 492b09dcae 0032850: Modeling Algorithms - Surface Surface Intersect Lost one line
IntStart_SearchOnBoundaries.gxx - improving tangent criteria
2022-10-31 18:09:15 +03:00

1076 lines
34 KiB
C++

// Created on: 1993-11-26
// Created by: Modelistation
// 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 <IntPatch_ALineToWLine.hxx>
#include <Adaptor3d_Surface.hxx>
#include <ElSLib.hxx>
#include <IntPatch_ALine.hxx>
#include <IntPatch_Point.hxx>
#include <IntPatch_SpecialPoints.hxx>
#include <IntPatch_WLine.hxx>
#include <IntSurf.hxx>
#include <IntSurf_LineOn2S.hxx>
//=======================================================================
//function : AddPointIntoLine
//purpose :
//=======================================================================
static inline void AddPointIntoLine(Handle(IntSurf_LineOn2S)& theLine,
const Standard_Real* const theArrPeriods,
IntSurf_PntOn2S &thePoint,
IntPatch_Point* theVertex = 0)
{
if(theLine->NbPoints() > 0)
{
if(thePoint.IsSame(theLine->Value(theLine->NbPoints()), Precision::Confusion()))
return;
IntPatch_SpecialPoints::AdjustPointAndVertex(theLine->Value(theLine->NbPoints()),
theArrPeriods, thePoint, theVertex);
}
theLine->Add(thePoint);
}
//=======================================================================
//function : AddVertexPoint
//purpose : Extracts IntSurf_PntOn2S from theVertex and adds result in theLine.
//=======================================================================
static void AddVertexPoint(Handle(IntSurf_LineOn2S)& theLine,
IntPatch_Point &theVertex,
const Standard_Real* const theArrPeriods)
{
IntSurf_PntOn2S anApexPoint = theVertex.PntOn2S();
AddPointIntoLine(theLine, theArrPeriods, anApexPoint, &theVertex);
}
//=======================================================================
//function : IsPoleOrSeam
//purpose : Processes theVertex depending on its type
// (pole/apex/point on boundary etc.) and adds it in theLine.
// thePIsoRef is the reference point using in case when the
// value of correspond parameter cannot be precise.
// theSingularSurfaceID contains the ID of surface with
// special point (0 - none, 1 - theS1, 2 - theS2)
//=======================================================================
static IntPatch_SpecPntType IsPoleOrSeam(const Handle(Adaptor3d_Surface)& theS1,
const Handle(Adaptor3d_Surface)& theS2,
const IntSurf_PntOn2S& thePIsoRef,
Handle(IntSurf_LineOn2S)& theLine,
IntPatch_Point &theVertex,
const Standard_Real theArrPeriods[4],
const Standard_Real theTol3d,
Standard_Integer& theSingularSurfaceID)
{
theSingularSurfaceID = 0;
for(Standard_Integer i = 0; i < 2; i++)
{
const Standard_Boolean isReversed = (i > 0);
const GeomAbs_SurfaceType aType = isReversed? theS2->GetType() : theS1->GetType();
IntPatch_SpecPntType anAddedPType = IntPatch_SPntNone;
IntSurf_PntOn2S anApexPoint;
switch(aType)
{
case GeomAbs_Sphere:
case GeomAbs_Cone:
{
if(IntPatch_SpecialPoints::
AddSingularPole((isReversed? theS2 : theS1), (isReversed? theS1 : theS2),
thePIsoRef, theVertex, anApexPoint,
isReversed, Standard_True))
{
anAddedPType = IntPatch_SPntPole;
break;
}
}
Standard_FALLTHROUGH
case GeomAbs_Torus:
if(aType == GeomAbs_Torus)
{
if(IntPatch_SpecialPoints::
AddCrossUVIsoPoint((isReversed? theS2 : theS1), (isReversed? theS1 : theS2),
thePIsoRef, theTol3d,
anApexPoint, isReversed))
{
anAddedPType = IntPatch_SPntSeamUV;
break;
}
}
Standard_FALLTHROUGH
case GeomAbs_Cylinder:
theSingularSurfaceID = i + 1;
AddVertexPoint(theLine, theVertex, theArrPeriods);
return IntPatch_SPntSeamU;
default:
break;
}
if(anAddedPType != IntPatch_SPntNone)
{
theSingularSurfaceID = i + 1;
AddPointIntoLine(theLine, theArrPeriods, anApexPoint, &theVertex);
return anAddedPType;
}
}
return IntPatch_SPntNone;
}
//=======================================================================
//function : IntPatch_ALineToWLine
//purpose :
//=======================================================================
IntPatch_ALineToWLine::IntPatch_ALineToWLine(const Handle(Adaptor3d_Surface)& theS1,
const Handle(Adaptor3d_Surface)& theS2,
const Standard_Integer theNbPoints) :
myS1(theS1),
myS2(theS2),
myNbPointsInWline(theNbPoints),
myTolOpenDomain(1.e-9),
myTolTransition(1.e-8),
myTol3D(Precision::Confusion())
{
const GeomAbs_SurfaceType aTyps1 = theS1->GetType();
const GeomAbs_SurfaceType aTyps2 = theS2->GetType();
switch(aTyps1)
{
case GeomAbs_Plane:
myQuad1.SetValue(theS1->Plane());
break;
case GeomAbs_Cylinder:
myQuad1.SetValue(theS1->Cylinder());
break;
case GeomAbs_Sphere:
myQuad1.SetValue(theS1->Sphere());
break;
case GeomAbs_Cone:
myQuad1.SetValue(theS1->Cone());
break;
case GeomAbs_Torus:
myQuad1.SetValue(theS1->Torus());
break;
default:
break;
}
switch(aTyps2)
{
case GeomAbs_Plane:
myQuad2.SetValue(theS2->Plane());
break;
case GeomAbs_Cylinder:
myQuad2.SetValue(theS2->Cylinder());
break;
case GeomAbs_Sphere:
myQuad2.SetValue(theS2->Sphere());
break;
case GeomAbs_Cone:
myQuad2.SetValue(theS2->Cone());
break;
case GeomAbs_Torus:
myQuad2.SetValue(theS2->Torus());
break;
default:
break;
}
}
//=======================================================================
//function : SetTol3D
//purpose :
//=======================================================================
void IntPatch_ALineToWLine::SetTol3D(const Standard_Real aTol)
{
myTol3D = aTol;
}
//=======================================================================
//function : Tol3D
//purpose :
//=======================================================================
Standard_Real IntPatch_ALineToWLine::Tol3D()const
{
return myTol3D;
}
//=======================================================================
//function : SetTolTransition
//purpose :
//=======================================================================
void IntPatch_ALineToWLine::SetTolTransition(const Standard_Real aTol)
{
myTolTransition = aTol;
}
//=======================================================================
//function : TolTransition
//purpose :
//=======================================================================
Standard_Real IntPatch_ALineToWLine::TolTransition()const
{
return myTolTransition;
}
//=======================================================================
//function : SetTolOpenDomain
//purpose :
//=======================================================================
void IntPatch_ALineToWLine::SetTolOpenDomain(const Standard_Real aTol)
{
myTolOpenDomain = aTol;
}
//=======================================================================
//function : TolOpenDomain
//purpose :
//=======================================================================
Standard_Real IntPatch_ALineToWLine::TolOpenDomain()const
{
return myTolOpenDomain;
}
//=======================================================================
//function : CorrectEndPoint
//purpose :
//=======================================================================
void IntPatch_ALineToWLine::CorrectEndPoint(Handle(IntSurf_LineOn2S)& theLine,
const Standard_Integer theIndex) const
{
const Standard_Real aTol = 1.e-5;
const Standard_Real aSqTol = 1.e-10;
//Perform linear extrapolation from two previous points
Standard_Integer anIndFirst, anIndSecond;
if (theIndex == 1)
{
anIndFirst = 3;
anIndSecond = 2;
}
else
{
anIndFirst = theIndex - 2;
anIndSecond = theIndex - 1;
}
IntSurf_PntOn2S aPntOn2S = theLine->Value(theIndex);
for (Standard_Integer ii = 1; ii <= 2; ii++)
{
Standard_Boolean anIsOnFirst = (ii == 1);
const IntSurf_Quadric& aQuad = (ii == 1)? myQuad1 : myQuad2;
if (aQuad.TypeQuadric() == GeomAbs_Cone)
{
const gp_Cone aCone = aQuad.Cone();
const gp_Pnt anApex = aCone.Apex();
if (anApex.SquareDistance (aPntOn2S.Value()) > aSqTol)
continue;
}
else if (aQuad.TypeQuadric() == GeomAbs_Sphere)
{
Standard_Real aU, aV;
aPntOn2S.ParametersOnSurface(anIsOnFirst, aU, aV);
if (Abs(aV - M_PI/2) > aTol &&
Abs(aV + M_PI/2) > aTol)
continue;
}
else
continue;
gp_Pnt2d PrevPrevP2d = theLine->Value(anIndFirst).ValueOnSurface(anIsOnFirst);
gp_Pnt2d PrevP2d = theLine->Value (anIndSecond).ValueOnSurface(anIsOnFirst);
gp_Dir2d aDir = gp_Vec2d(PrevPrevP2d, PrevP2d);
Standard_Real aX0 = PrevPrevP2d.X(), aY0 = PrevPrevP2d.Y();
Standard_Real aXend, aYend;
aPntOn2S.ParametersOnSurface(anIsOnFirst, aXend, aYend);
if (Abs(aDir.Y()) < gp::Resolution())
continue;
Standard_Real aNewXend = aDir.X()/aDir.Y() * (aYend - aY0) + aX0;
theLine->SetUV (theIndex, anIsOnFirst, aNewXend, aYend);
}
}
//=======================================================================
//function : GetSectionRadius
//purpose :
//=======================================================================
Standard_Real IntPatch_ALineToWLine::GetSectionRadius(const gp_Pnt& thePnt3d) const
{
Standard_Real aRetVal = RealLast();
for (Standard_Integer i = 0; i < 2; i++)
{
const IntSurf_Quadric& aQuad = i ? myQuad2 : myQuad1;
if (aQuad.TypeQuadric() == GeomAbs_Cone)
{
const gp_Cone aCone = aQuad.Cone();
const gp_XYZ aRVec = thePnt3d.XYZ() - aCone.Apex().XYZ();
const gp_XYZ &aDir = aCone.Axis().Direction().XYZ();
aRetVal = Min(aRetVal, Abs(aRVec.Dot(aDir)*Tan(aCone.SemiAngle())));
}
else if (aQuad.TypeQuadric() == GeomAbs_Sphere)
{
const gp_Sphere aSphere = aQuad.Sphere();
const gp_XYZ aRVec = thePnt3d.XYZ() - aSphere.Location().XYZ();
const gp_XYZ &aDir = aSphere.Position().Direction().XYZ();
const Standard_Real aR = aSphere.Radius();
const Standard_Real aD = aRVec.Dot(aDir);
const Standard_Real aDelta = aR*aR - aD*aD;
if (aDelta <= 0.0)
{
aRetVal = 0.0;
break;
}
else
{
aRetVal = Min(aRetVal, Sqrt(aDelta));
}
}
}
return aRetVal;
}
//=======================================================================
//function : MakeWLine
//purpose :
//=======================================================================
void IntPatch_ALineToWLine::MakeWLine(const Handle(IntPatch_ALine)& theAline,
IntPatch_SequenceOfLine& theLines) const
{
Standard_Boolean included;
Standard_Real f = theAline->FirstParameter(included);
if(!included) {
f+=myTolOpenDomain;
}
Standard_Real l = theAline->LastParameter(included);
if(!included) {
l-=myTolOpenDomain;
}
MakeWLine(theAline, f, l, theLines);
}
//=======================================================================
//function : MakeWLine
//purpose :
//=======================================================================
void IntPatch_ALineToWLine::MakeWLine(const Handle(IntPatch_ALine)& theALine,
const Standard_Real theFPar,
const Standard_Real theLPar,
IntPatch_SequenceOfLine& theLines) const
{
const Standard_Integer aNbVert = theALine->NbVertex();
if (aNbVert == 0)
{
return;
}
#if 0
//To draw ALine as a wire DRAW-object use the following code.
{
static int ind = 0;
ind++;
bool flShow = true;
if (flShow)
{
std::cout << " +++ DUMP ALine (begin) +++++" << std::endl;
const Standard_Integer NbSamples = 20;
const Standard_Real aStep = (theLPar - theFPar) / NbSamples;
char* name = new char[100];
for (Standard_Integer ii = 0; ii <= NbSamples; ii++)
{
Standard_Real aPrm = theFPar + ii * aStep;
const gp_Pnt aPP(theALine->Value(aPrm));
std::cout << "vertex v" << ii << " " << aPP.X() << " " << aPP.Y() << " " << aPP.Z() << std::endl;
sprintf(name, "p%d_%d", ii, ind);
Draw::Set(name, aPP);
}
std::cout << " --- DUMP ALine (end) -----" << std::endl;
}
}
//Copy all output information and apply it as a TCL-code in DRAW.
//After that, use TCL-script below:
/* ********************************* Script (begin)
shape ww w
copy v1 vprev
for {set i 2} {$i <= 10000} {incr i} {
distmini dd vprev v$i;
if { [dval dd_val] > 1.0e-7} {
edge ee vprev v$i;
add ee ww;
copy v$i vprev;
}
}
********************************** Script (end) */
#endif
//The same points can be marked by different vertices.
//The code below unifies tolerances of all vertices
//marking the same points.
for (Standard_Integer i = 1; i < aNbVert; i++)
{
IntPatch_Point &aCurVert = theALine->ChangeVertex(i);
const IntSurf_PntOn2S &aCurrPt = aCurVert.PntOn2S();
const Standard_Real aCurToler = aCurVert.Tolerance();
for (Standard_Integer j = i + 1; j <= aNbVert; j++)
{
IntPatch_Point &aVert = theALine->ChangeVertex(j);
const IntSurf_PntOn2S &aNewPt = aVert.PntOn2S();
const Standard_Real aToler = aVert.Tolerance();
const Standard_Real aSumTol = aCurToler + aToler;
if (aCurrPt.IsSame(aNewPt, aSumTol))
{
aCurVert.SetTolerance(aSumTol);
aVert.SetTolerance(aSumTol);
}
}
}
const Standard_Real aTol = 2.0*myTol3D+Precision::Confusion();
const Standard_Real aPrmTol = Max(1.0e-4*(theLPar - theFPar), Precision::PConfusion());
IntPatch_SpecPntType aPrePointExist = IntPatch_SPntNone;
NCollection_Array1<Standard_Real> aVertexParams(1, aNbVert);
NCollection_Array1<IntPatch_Point> aSeqVertex(1, aNbVert);
//It is possible to have several vertices with equal parameters.
NCollection_Array1<Standard_Boolean> hasVertexBeenChecked(1, aNbVert);
Handle(IntSurf_LineOn2S) aLinOn2S;
Standard_Real aParameter = theFPar;
for(Standard_Integer i = aVertexParams.Lower(); i <= aVertexParams.Upper(); i++)
{
const IntPatch_Point& aVert = theALine->Vertex(i);
const Standard_Real aPar = aVert.ParameterOnLine();
aVertexParams(i) = aPar;
hasVertexBeenChecked(i) = Standard_False;
}
Standard_Integer aSingularSurfaceID = 0;
Standard_Real anArrPeriods[] = { 0.0, //U1
0.0, //V1
0.0, //U2
0.0}; //V2
IntSurf::SetPeriod(myS1, myS2, anArrPeriods);
IntSurf_PntOn2S aPrevLPoint;
while(aParameter < theLPar)
{
Standard_Real aStep = (theLPar - aParameter) / (Standard_Real)(myNbPointsInWline - 1);
if(aStep < Epsilon(theLPar))
break;
Standard_Boolean isStepReduced = Standard_False;
Standard_Real aLPar = theLPar;
for (Standard_Integer i = aVertexParams.Lower(); i <= aVertexParams.Upper(); i++)
{
if (hasVertexBeenChecked(i))
continue;
aLPar = aVertexParams(i);
if (Abs(aLPar - aParameter) < aPrmTol)
continue;
break;
}
if ((aStep - (aLPar - aParameter) > aPrmTol) &&
(Abs(aLPar - aParameter) > aPrmTol))
{
aStep = Max((aLPar - aParameter) / 5, 1.e-5);
isStepReduced = Standard_True;
}
Standard_Integer aNewVertID = 0;
aLinOn2S = new IntSurf_LineOn2S;
Standard_Boolean anIsFirstDegenerated = Standard_False,
anIsLastDegenerated = Standard_False;
Standard_Real aStepMin = 0.1 * aStep, aStepMax = 10.0 * aStep;
Standard_Boolean isLast = Standard_False;
Standard_Real aPrevParam = aParameter;
for(; !isLast; aParameter += aStep)
{
IntSurf_PntOn2S aPOn2S;
if(theLPar <= aParameter)
{
isLast = Standard_True;
if(aPrePointExist != IntPatch_SPntNone)
{
break;
}
else
{
aParameter = theLPar;
}
}
Standard_Boolean isPointValid = Standard_False;
Standard_Real aTgMagn = 0.0;
{
gp_Pnt aPnt3d;
gp_Vec aTg;
theALine->D1(aParameter, aPnt3d, aTg);
if (GetSectionRadius(aPnt3d) < 5.0e-6)
{
// We cannot compute 2D-parameters of
// aPOn2S correctly.
if (anIsLastDegenerated) //the current last point is wrong
aLinOn2S->RemovePoint (aLinOn2S->NbPoints());
isPointValid = Standard_False;
}
else
{
isPointValid = Standard_True;
}
aTgMagn = aTg.Magnitude();
Standard_Real u1 = 0.0, v1 = 0.0, u2 = 0.0, v2 = 0.0;
myQuad1.Parameters(aPnt3d, u1, v1);
myQuad2.Parameters(aPnt3d, u2, v2);
aPOn2S.SetValue(aPnt3d, u1, v1, u2, v2);
}
if(aPrePointExist != IntPatch_SPntNone)
{
const Standard_Real aURes = Max(myS1->UResolution(myTol3D),
myS2->UResolution(myTol3D)),
aVRes = Max(myS1->VResolution(myTol3D),
myS2->VResolution(myTol3D));
const Standard_Real aTol2d = (aPrePointExist == IntPatch_SPntPole) ? -1.0 :
(aPrePointExist == IntPatch_SPntSeamV)? aVRes :
(aPrePointExist == IntPatch_SPntSeamUV)? Max(aURes, aVRes) : aURes;
IntSurf_PntOn2S aRPT = aPOn2S;
if (aPrePointExist == IntPatch_SPntPole)
{
Standard_Real aPrt = 0.5*(aPrevParam + theLPar);
for (Standard_Integer i = aVertexParams.Lower();
i <= aVertexParams.Upper(); i++)
{
const Standard_Real aParam = aVertexParams(i);
if (aParam <= aPrevParam)
continue;
if ((aParam - aPrevParam) < aPrmTol)
{
const gp_Pnt aPnt3d(theALine->Value(aParam));
if (aPOn2S.Value().SquareDistance(aPnt3d) < Precision::SquareConfusion())
{
// i-th vertex is the same as a Pole/Apex.
// So, it should be ignored.
continue;
}
}
aPrt = 0.5*(aParam + aPrevParam);
break;
}
const gp_Pnt aPnt3d(theALine->Value(aPrt));
Standard_Real u1, v1, u2, v2;
myQuad1.Parameters(aPnt3d, u1, v1);
myQuad2.Parameters(aPnt3d, u2, v2);
aRPT.SetValue(aPnt3d, u1, v1, u2, v2);
if (aPOn2S.IsSame(aPrevLPoint, Max(Precision::Approximation(), aTol)))
{
//Set V-parameter as precise value found on the previous step.
if (aSingularSurfaceID == 1)
{
aPOn2S.ParametersOnS1(u2, v2);
aPOn2S.SetValue(Standard_True, u1, v2);
}
else //if (aSingularSurfaceID == 2)
{
aPOn2S.ParametersOnS2(u1, v1);
aPOn2S.SetValue(Standard_False, u2, v1);
}
}
}
if(IntPatch_SpecialPoints::
ContinueAfterSpecialPoint(myS1, myS2, aRPT,
aPrePointExist, aTol2d,
aPrevLPoint, Standard_False))
{
AddPointIntoLine(aLinOn2S, anArrPeriods, aPrevLPoint);
}
else if(aParameter == theLPar)
{// Strictly equal!!!
break;
}
}
aPrePointExist = IntPatch_SPntNone;
Standard_Integer aVertexNumber = -1;
for(Standard_Integer i = aVertexParams.Lower(); i <= aVertexParams.Upper(); i++)
{
if(hasVertexBeenChecked(i))
continue;
const IntPatch_Point &aVP = theALine->Vertex(i);
const Standard_Real aParam = aVertexParams(i);
if( ((aPrevParam < aParam) && (aParam <= aParameter)) ||
((aPrevParam == aParameter) && (aParam == aParameter))||
(aPOn2S.IsSame(aVP.PntOn2S(), aVP.Tolerance()) &&
(Abs(aVP.ParameterOnLine() - aParameter) < aPrmTol)))
{
//We have either jumped over the vertex or "fell" on the vertex.
//However, ALine can be self-interfered. Therefore, we need to check
//vertex parameter and 3D-distance together.
aVertexNumber = i;
break;
}
}
aPrevParam = aParameter;
if(aVertexNumber < 0)
{
if (isPointValid)
{
if (!isStepReduced)
{
StepComputing(theALine, aPOn2S, theLPar, aParameter, aTgMagn,
aStepMin, aStepMax, myTol3D, aStep);
}
AddPointIntoLine(aLinOn2S, anArrPeriods, aPOn2S);
aPrevLPoint = aPOn2S;
}
else
{
//add point, set correxponding status: to be corrected later
Standard_Boolean ToAdd = Standard_False;
if (aLinOn2S->NbPoints() == 0)
{
anIsFirstDegenerated = Standard_True;
ToAdd = Standard_True;
}
else if (aLinOn2S->NbPoints() > 1)
{
anIsLastDegenerated = Standard_True;
ToAdd = Standard_True;
}
if (ToAdd)
{
AddPointIntoLine(aLinOn2S, anArrPeriods, aPOn2S);
aPrevLPoint = aPOn2S;
}
}
continue;
}
IntPatch_Point aVtx = theALine->Vertex(aVertexNumber);
Standard_Real aNewVertexParam = aLinOn2S->NbPoints() + 1;
Standard_Integer aNbPointsPrev = aLinOn2S->NbPoints();
//ATTENTION!!!
// IsPoleOrSeam inserts new point in aLinOn2S if aVtx respects
//to some special point. Otherwise, aLinOn2S is not changed.
// Find a point for reference parameter. It will be used
// if real parameter value cannot be precise (see comment to
// IsPoleOrSeam(...) function).
IntSurf_PntOn2S aPrefIso = aVtx.PntOn2S();
if (aLinOn2S->NbPoints() < 1)
{
for (Standard_Integer i = aVertexNumber + 1; i <= aVertexParams.Upper(); i++)
{
const Standard_Real aParam = aVertexParams(i);
if ((aParam - aVertexParams(aVertexNumber)) > Precision::PConfusion())
{
const Standard_Real aPrm = 0.5*(aParam + aVertexParams(aVertexNumber));
const gp_Pnt aPnt3d(theALine->Value(aPrm));
Standard_Real u1 = 0.0, v1 = 0.0, u2 = 0.0, v2 = 0.0;
myQuad1.Parameters(aPnt3d, u1, v1);
myQuad2.Parameters(aPnt3d, u2, v2);
aPrefIso.SetValue(aPnt3d, u1, v1, u2, v2);
break;
}
}
}
else
{
aPrefIso = aLinOn2S->Value(aLinOn2S->NbPoints());
}
aPrePointExist = IsPoleOrSeam(myS1, myS2, aPrefIso, aLinOn2S, aVtx,
anArrPeriods, aTol, aSingularSurfaceID);
if (aPrePointExist == IntPatch_SPntPole ||
aPrePointExist == IntPatch_SPntPoleSeamU)
{
//set correxponding status: to be corrected later
if (aLinOn2S->NbPoints() == 1)
anIsFirstDegenerated = Standard_True;
else
anIsLastDegenerated = Standard_True;
}
const Standard_Real aCurVertParam = aVtx.ParameterOnLine();
if(aPrePointExist != IntPatch_SPntNone)
{
if (aNbPointsPrev == aLinOn2S->NbPoints())
{
//Vertex coinsides any point of line and was not added into line
aNewVertexParam = aNbPointsPrev;
}
aPrevParam = aParameter = aCurVertParam;
}
else
{
if (!isPointValid)
{
//Take a farther point of ALine (with greater parameter)
continue;
}
if(aVtx.Tolerance() > aTol)
{
aVtx.SetValue(aPOn2S);
AddPointIntoLine(aLinOn2S, anArrPeriods, aPOn2S);
}
else
{
AddVertexPoint(aLinOn2S, aVtx, anArrPeriods);
}
}
aPrevLPoint = aPOn2S = aLinOn2S->Value(aLinOn2S->NbPoints());
{
Standard_Boolean isFound = Standard_False;
const Standard_Real aSqTol = aTol*aTol;
const gp_Pnt aP1(theALine->Value(aCurVertParam));
const IntSurf_PntOn2S& aVertP2S = aVtx.PntOn2S();
const Standard_Real aVertToler = aVtx.Tolerance();
for(Standard_Integer i = aVertexParams.Lower(); i <= aVertexParams.Upper(); i++)
{
if(hasVertexBeenChecked(i))
continue;
const gp_Pnt aP2(theALine->Value(aVertexParams(i)));
if(aP1.SquareDistance(aP2) < aSqTol)
{
IntPatch_Point aLVtx = theALine->Vertex(i);
aLVtx.SetValue(aVertP2S);
aLVtx.SetTolerance(aVertToler);
Standard_Real aParam = aLVtx.ParameterOnLine();
if (Abs(aParam - theLPar) <= Precision::PConfusion()) //in the case of closed curve,
aLVtx.SetParameter(-1); //we don't know yet the number of points in the curve
else
aLVtx.SetParameter(aNewVertexParam);
aSeqVertex(++aNewVertID) = aLVtx;
hasVertexBeenChecked(i) = Standard_True;
isFound = Standard_True;
}
else if(isFound)
{
break;
}
}
}
if ((aPrePointExist != IntPatch_SPntNone) && (aLinOn2S->NbPoints() > 1))
break;
if (isStepReduced)
{
isStepReduced = Standard_False;
aStep = (theLPar - aParameter) / (Standard_Real)(myNbPointsInWline - 1);
if(aStep < Epsilon(theLPar))
break;
aLPar = aVertexParams(aNbVert);
for (Standard_Integer i = aVertexParams.Lower(); i <= aVertexParams.Upper(); i++)
{
if (hasVertexBeenChecked(i))
continue;
aLPar = aVertexParams(i);
if (Abs(aLPar - aParameter) < aPrmTol)
continue;
break;
}
if ((aStep - (aLPar - aParameter) > aPrmTol) &&
(Abs(aLPar - aParameter) > aPrmTol))
{
aStep = Max((aLPar - aParameter) / 5, 1.e-5);
isStepReduced = Standard_True;
}
aStepMin = 0.1 * aStep;
aStepMax = 10.0 * aStep;
}
}//for(; !isLast; aParameter += aStep)
if(aLinOn2S->NbPoints() < 2)
{
aParameter += aStep;
continue;
}
//Correct first and last points if needed
if (aLinOn2S->NbPoints() >= 3)
{
if (anIsFirstDegenerated)
CorrectEndPoint (aLinOn2S, 1);
if (anIsLastDegenerated)
CorrectEndPoint (aLinOn2S, aLinOn2S->NbPoints());
}
//-----------------------------------------------------------------
//-- W L i n e c r e a t i o n ---
//-----------------------------------------------------------------
Handle(IntPatch_WLine) aWLine;
//
if(theALine->TransitionOnS1() == IntSurf_Touch)
{
aWLine = new IntPatch_WLine(aLinOn2S,
theALine->IsTangent(),
theALine->SituationS1(),
theALine->SituationS2());
aWLine->SetCreatingWayInfo(IntPatch_WLine::IntPatch_WLImpImp);
}
else if(theALine->TransitionOnS1() == IntSurf_Undecided)
{
aWLine = new IntPatch_WLine(aLinOn2S, theALine->IsTangent());
aWLine->SetCreatingWayInfo(IntPatch_WLine::IntPatch_WLImpImp);
}
else
{
//Computation of transitions of the line on two surfaces ---
const Standard_Integer indice1 = Max(aLinOn2S->NbPoints() / 3, 2);
const gp_Pnt &aPP0 = aLinOn2S->Value(indice1 - 1).Value(),
&aPP1 = aLinOn2S->Value(indice1).Value();
const gp_Vec tgvalid(aPP0, aPP1);
const gp_Vec aNQ1(myQuad1.Normale(aPP0)), aNQ2(myQuad2.Normale(aPP0));
const Standard_Real dotcross = tgvalid.DotCross(aNQ2, aNQ1);
IntSurf_TypeTrans trans1 = IntSurf_Undecided,
trans2 = IntSurf_Undecided;
if (dotcross > myTolTransition)
{
trans1 = IntSurf_Out;
trans2 = IntSurf_In;
}
else if (dotcross < -myTolTransition)
{
trans1 = IntSurf_In;
trans2 = IntSurf_Out;
}
aWLine = new IntPatch_WLine(aLinOn2S, theALine->IsTangent(),
trans1, trans2);
aWLine->SetCreatingWayInfo(IntPatch_WLine::IntPatch_WLImpImp);
}
for(Standard_Integer i = aSeqVertex.Lower(); i <= aNewVertID; i++)
{
IntPatch_Point aVtx = aSeqVertex(i);
if (aVtx.ParameterOnLine() == -1) //in the case of closed curve,
aVtx.SetParameter (aWLine->NbPnts()); //we set the last parameter
aWLine->AddVertex(aVtx);
}
aWLine->SetPeriod(anArrPeriods[0],anArrPeriods[1],anArrPeriods[2],anArrPeriods[3]);
//the method ComputeVertexParameters can reduce the number of points in <aWLine>
aWLine->ComputeVertexParameters(myTol3D);
if (aWLine->NbPnts() > 1)
{
aWLine->EnablePurging(Standard_False);
#ifdef INTPATCH_ALINETOWLINE_DEBUG
aWLine->Dump(0);
#endif
theLines.Append(aWLine);
}
}//while(aParameter < theLPar)
}
//=======================================================================
//function : CheckDeflection
//purpose : Returns:
// -1 - step is too small
// 0 - step is normal
// +1 - step is too big
//=======================================================================
Standard_Integer IntPatch_ALineToWLine::CheckDeflection(const gp_XYZ& theMidPt,
const Standard_Real theMaxDeflection) const
{
Standard_Real aDist = Abs(myQuad1.Distance(theMidPt));
if(aDist > theMaxDeflection)
return 1;
aDist = Max(Abs(myQuad2.Distance(theMidPt)), aDist);
if(aDist > theMaxDeflection)
return 1;
if((aDist + aDist) < theMaxDeflection)
return -1;
return 0;
}
//=======================================================================
//function : StepComputing
//purpose :
//=======================================================================
Standard_Boolean IntPatch_ALineToWLine::
StepComputing(const Handle(IntPatch_ALine)& theALine,
const IntSurf_PntOn2S& thePOn2S,
const Standard_Real theLastParOfAline,
const Standard_Real theCurParam,
const Standard_Real theTgMagnitude,
const Standard_Real theStepMin,
const Standard_Real theStepMax,
const Standard_Real theMaxDeflection,
Standard_Real& theStep) const
{
if(theTgMagnitude < Precision::Confusion())
return Standard_False;
const Standard_Real anEps = myTol3D;
//Indeed, 1.0e+15 < 2^50 < 1.0e+16. Therefore,
//if we apply bisection method to the range with length
//1.0e+6 then we will be able to find solution with max error ~1.0e-9.
const Standard_Integer aNbIterMax = 50;
const Standard_Real aNotFilledRange = theLastParOfAline - theCurParam;
Standard_Real aMinStep = theStepMin, aMaxStep = Min(theStepMax, aNotFilledRange);
if(aMinStep > aMaxStep)
{
theStep = aMaxStep;
return Standard_True;
}
const Standard_Real aR = IntPatch_PointLine::
CurvatureRadiusOfIntersLine(myS1, myS2, thePOn2S);
#if 0
{
static int zzz = 0;
zzz++;
std::cout << "*** R" << zzz << " (begin)" << std::endl;
Standard_Real aU1, aV1, aU2, aV2;
thePOn2S.Parameters(aU1, aV1, aU2, aV2);
std::cout << "Prms: " << aU1 << ", " << aV1 << ", " << aU2 << ", " << aV2 << std::endl;
std::cout << "Radius = " << aR << std::endl;
std::cout << "*** R" << zzz << " (end)" << std::endl;
}
#endif
if(aR < 0.0)
{
return Standard_False;
}
else
{
//The 3D-step is defined as length of the tangent to the osculating circle
//by the condition that the distance from end point of the tangent to the
//circle is no greater than anEps. theStep is the step in
//parameter space of intersection curve (must be converted from 3D-step).
theStep = Min(sqrt(anEps*(2.0*aR + anEps))/theTgMagnitude, aMaxStep);
theStep = Max(theStep, aMinStep);
}
//The step value has been computed for osculating circle.
//Now it should be checked for real intersection curve
//and is made more precise in case of necessity.
Standard_Integer aNbIter = 0;
do
{
aNbIter++;
const gp_XYZ& aP1 = thePOn2S.Value().XYZ();
const gp_XYZ aP2(theALine->Value(theCurParam + theStep).XYZ());
const Standard_Integer aStatus = CheckDeflection(0.5*(aP1 + aP2), theMaxDeflection);
if(aStatus == 0)
break;
if(aStatus < 0)
{
aMinStep = theStep;
}
else //if(aStatus > 0)
{
aMaxStep = theStep;
}
theStep = 0.5*(aMinStep + aMaxStep);
}
while(((aMaxStep - aMinStep) > Precision::PConfusion()) && (aNbIter <= aNbIterMax));
if(aNbIter > aNbIterMax)
return Standard_False;
return Standard_True;
}