1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00
occt/src/IntPatch/IntPatch_WLineTool.cxx
ifv 9f5ad42aae 0032569: Modeling Algorithm - Section not found
src/IntPatch/IntPatch_WLineTool.cxx - adding control of maximal ratio of distances between 3 sequential points.
2021-09-20 14:31:47 +03:00

1797 lines
63 KiB
C++

// 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_WLineTool.hxx>
#include <Adaptor3d_HSurface.hxx>
#include <Adaptor3d_TopolTool.hxx>
#include <Bnd_Range.hxx>
#include <ElCLib.hxx>
#include <ElSLib.hxx>
#include <IntPatch_SpecialPoints.hxx>
#include <NCollection_IncAllocator.hxx>
#include <TopAbs_State.hxx>
// It is pure empirical value.
const Standard_Real IntPatch_WLineTool::myMaxConcatAngle = M_PI/6;
//Bit-mask is used for information about
//the operation made in
//IntPatch_WLineTool::ExtendTwoWLines(...) method.
enum
{
IntPatchWT_EnAll = 0x00,
IntPatchWT_DisLastLast = 0x01,
IntPatchWT_DisLastFirst = 0x02,
IntPatchWT_DisFirstLast = 0x04,
IntPatchWT_DisFirstFirst = 0x08
};
enum IntPatchWT_WLsConnectionType
{
IntPatchWT_NotConnected,
IntPatchWT_Singular,
IntPatchWT_EachOther
};
//=======================================================================
//function : MinMax
//purpose : Replaces theParMIN = MIN(theParMIN, theParMAX),
// theParMAX = MAX(theParMIN, theParMAX).
//
// Static subfunction in IsSeamOrBound.
//=======================================================================
static inline void MinMax(Standard_Real& theParMIN, Standard_Real& theParMAX)
{
if(theParMIN > theParMAX)
{
const Standard_Real aTmp = theParMAX;
theParMAX = theParMIN;
theParMIN = aTmp;
}
}
//=========================================================================
// function : FillPointsHash
// purpose : Fill points hash by input data.
// Static subfunction in ComputePurgedWLine.
//=========================================================================
static void FillPointsHash(const Handle(IntPatch_WLine) &theWLine,
NCollection_Array1<Standard_Integer> &thePointsHash)
{
// 1 - Delete point.
// 0 - Store point.
// -1 - Vertex point (not delete).
Standard_Integer i, v;
for(i = 1; i <= theWLine->NbPnts(); i++)
thePointsHash.SetValue(i, 0);
for(v = 1; v <= theWLine->NbVertex(); v++)
{
IntPatch_Point aVertex = theWLine->Vertex(v);
Standard_Integer avertexindex = (Standard_Integer)aVertex.ParameterOnLine();
thePointsHash.SetValue(avertexindex, -1);
}
}
//=========================================================================
// function : MakeNewWLine
// purpose : Makes new walking line according to the points hash
// Static subfunction in ComputePurgedWLine and DeleteOuter.
//=========================================================================
static Handle(IntPatch_WLine) MakeNewWLine(const Handle(IntPatch_WLine) &theWLine,
NCollection_Array1<Standard_Integer> &thePointsHash,
const Standard_Boolean theIsOuter)
{
Standard_Integer i;
Handle(IntSurf_LineOn2S) aPurgedLineOn2S = new IntSurf_LineOn2S();
Handle(IntPatch_WLine) aLocalWLine = new IntPatch_WLine(aPurgedLineOn2S, Standard_False);
Standard_Integer anOldLineIdx = 1, aVertexIdx = 1, anIndexPrev = -1, anIdxOld = -1;
gp_Pnt aPPrev, aPOld;
for(i = 1; i <= thePointsHash.Upper(); i++)
{
if (thePointsHash(i) == 0)
{
// Point has to be added
const gp_Pnt aP = theWLine->Point(i).Value();
const Standard_Real aSqDistPrev = aPPrev.SquareDistance(aPOld);
const Standard_Real aSqDist = aPPrev.SquareDistance(aP);
const Standard_Real aRatio = (aSqDistPrev < gp::Resolution()) ? 0.0 : 9.0*aSqDist / aSqDistPrev;
if(theIsOuter ||
(aRatio < gp::Resolution()) ||
((1.0 < aRatio) && (aRatio < 81.0)) ||
(i - anIndexPrev <= 1) ||
(i - anIdxOld <= 1))
{
// difference in distances is satisfactory
// (1/9 < aSqDist/aSqDistPrev < 9)
// Store this point.
aPurgedLineOn2S->Add(theWLine->Point(i));
anOldLineIdx++;
aPOld = aPPrev;
aPPrev = aP;
anIdxOld = anIndexPrev;
anIndexPrev = i;
}
else if(aSqDist >= aSqDistPrev*9.0)
{
// current segment is much more longer
// (aSqDist/aSqDistPrev >= 9)
i = (i + anIndexPrev)/2;
thePointsHash(i) = 0;
i--;
}
else
{
//previous segment is much more longer
//(aSqDist/aSqDistPrev <= 1/9)
if(anIndexPrev - anIdxOld > 1)
{
//Delete aPPrev from WL
aPurgedLineOn2S->RemovePoint(aPurgedLineOn2S->NbPoints());
anOldLineIdx--;
// Insert point between aPOld and aPPrev
i = (anIdxOld + anIndexPrev) / 2;
thePointsHash(i) = 0;
aPPrev = aPOld;
anIndexPrev = anIdxOld;
}
else
{
aPOld = aPPrev;
anIdxOld = anIndexPrev;
}
//Next iterations will start from this inserted point.
i--;
}
}
else if (thePointsHash(i) == -1)
{
// Add vertex.
IntPatch_Point aVertex = theWLine->Vertex(aVertexIdx++);
aVertex.SetParameter(anOldLineIdx++);
aLocalWLine->AddVertex(aVertex);
aPurgedLineOn2S->Add(theWLine->Point(i));
aPPrev = aPOld = theWLine->Point(i).Value();
anIndexPrev = anIdxOld = i;
}
//Other points will be rejected by purger.
}
return aLocalWLine;
}
//=========================================================================
// function : MovePoint
// purpose : Move point into surface param space. No interpolation used
// because walking algorithm should care for closeness to the param space.
// Static subfunction in ComputePurgedWLine.
//=========================================================================
static void MovePoint(const Handle(Adaptor3d_HSurface) &theS1,
Standard_Real &U1, Standard_Real &V1)
{
if (U1 < theS1->FirstUParameter())
U1 = theS1->FirstUParameter();
if (U1 > theS1->LastUParameter())
U1 = theS1->LastUParameter();
if (V1 < theS1->FirstVParameter())
V1 = theS1->FirstVParameter();
if (V1 > theS1->LastVParameter())
V1 = theS1->LastVParameter();
}
//=========================================================================
// function : DeleteOuterPoints
// purpose : Check and delete out of bounds points on walking line.
// Static subfunction in ComputePurgedWLine.
//=========================================================================
static Handle(IntPatch_WLine)
DeleteOuterPoints(const Handle(IntPatch_WLine) &theWLine,
const Handle(Adaptor3d_HSurface) &theS1,
const Handle(Adaptor3d_HSurface) &theS2,
const Handle(Adaptor3d_TopolTool) &theDom1,
const Handle(Adaptor3d_TopolTool) &theDom2)
{
Standard_Integer i;
NCollection_Array1<Standard_Integer> aDelOuterPointsHash(1, theWLine->NbPnts());
FillPointsHash(theWLine, aDelOuterPointsHash);
if (theS1->IsUPeriodic() || theS1->IsVPeriodic() ||
theS2->IsUPeriodic() || theS2->IsVPeriodic() )
return theWLine;
gp_Pnt2d aPntOnF1, aPntOnF2;
Standard_Real aX1, aY1, aX2, aY2;
// Iterate over points in walking line and delete which are out of bounds.
// Forward.
Standard_Boolean isAllDeleted = Standard_True;
Standard_Boolean aChangedFirst = Standard_False;
Standard_Integer aFirstGeomIdx = 1;
for(i = 1; i <= theWLine->NbPnts(); i++)
{
theWLine->Point(i).Parameters(aX1, aY1, aX2, aY2);
aPntOnF1.SetCoord(aX1, aY1);
aPntOnF2.SetCoord(aX2, aY2);
TopAbs_State aState1 = theDom1->Classify(aPntOnF1, Precision::Confusion());
TopAbs_State aState2 = theDom2->Classify(aPntOnF2, Precision::Confusion());
if (aState1 == TopAbs_OUT ||
aState2 == TopAbs_OUT )
{
aDelOuterPointsHash(i) = 1;
aChangedFirst = Standard_True;
}
else
{
isAllDeleted = Standard_False;
aFirstGeomIdx = Max (i - 1, 1);
if (aDelOuterPointsHash(i) == -1)
aFirstGeomIdx = i; // Use data what lies in (i) point / vertex.
aDelOuterPointsHash(i) = -1;
break;
}
}
if (isAllDeleted)
{
// ALL points are out of bounds:
// case boolean bcut_complex F5 and similar.
return theWLine;
}
// Backward.
Standard_Boolean aChangedLast = Standard_False;
Standard_Integer aLastGeomIdx = theWLine->NbPnts();
for(i = theWLine->NbPnts(); i >= 1; i--)
{
theWLine->Point(i).Parameters(aX1, aY1, aX2, aY2);
aPntOnF1.SetCoord(aX1, aY1);
aPntOnF2.SetCoord(aX2, aY2);
TopAbs_State aState1 = theDom1->Classify(aPntOnF1, Precision::Confusion());
TopAbs_State aState2 = theDom2->Classify(aPntOnF2, Precision::Confusion());
if (aState1 == TopAbs_OUT ||
aState2 == TopAbs_OUT )
{
aDelOuterPointsHash(i) = 1;
aChangedLast = Standard_True; // Move vertex to first good point
}
else
{
aLastGeomIdx = Min (i + 1, theWLine->NbPnts());
if (aDelOuterPointsHash(i) == -1)
aLastGeomIdx = i; // Use data what lies in (i) point / vertex.
aDelOuterPointsHash(i) = -1;
break;
}
}
if (!aChangedFirst && !aChangedLast)
{
// Nothing is done, return input.
return theWLine;
}
// Build new line and modify geometry of necessary vertexes.
Handle(IntPatch_WLine) aLocalWLine = MakeNewWLine(theWLine, aDelOuterPointsHash, Standard_True);
if (aChangedFirst)
{
// Vertex geometry.
IntPatch_Point aVertex = aLocalWLine->Vertex(1);
aVertex.SetValue(theWLine->Point(aFirstGeomIdx).Value());
Standard_Real aU1, aU2, aV1, aV2;
theWLine->Point(aFirstGeomIdx).Parameters(aU1, aV1, aU2, aV2);
MovePoint(theS1, aU1, aV1);
MovePoint(theS2, aU2, aV2);
aVertex.SetParameters(aU1, aV1, aU2, aV2);
aLocalWLine->Replace(1, aVertex);
// Change point in walking line.
aLocalWLine->SetPoint(1, aVertex);
}
if (aChangedLast)
{
// Vertex geometry.
IntPatch_Point aVertex = aLocalWLine->Vertex(aLocalWLine->NbVertex());
aVertex.SetValue(theWLine->Point(aLastGeomIdx).Value());
Standard_Real aU1, aU2, aV1, aV2;
theWLine->Point(aLastGeomIdx).Parameters(aU1, aV1, aU2, aV2);
MovePoint(theS1, aU1, aV1);
MovePoint(theS2, aU2, aV2);
aVertex.SetParameters(aU1, aV1, aU2, aV2);
aLocalWLine->Replace(aLocalWLine->NbVertex(), aVertex);
// Change point in walking line.
aLocalWLine->SetPoint(aLocalWLine->NbPnts(), aVertex);
}
return aLocalWLine;
}
//=========================================================================
// function : IsInsideIn2d
// purpose : Check if aNextPnt lies inside of tube build on aBasePnt and aBaseVec.
// In 2d space. Static subfunction in DeleteByTube.
//=========================================================================
static Standard_Boolean IsInsideIn2d(const gp_Pnt2d& aBasePnt,
const gp_Vec2d& aBaseVec,
const gp_Pnt2d& aNextPnt,
const Standard_Real aSquareMaxDist)
{
gp_Vec2d aVec2d(aBasePnt, aNextPnt);
//d*d = (basevec^(nextpnt-basepnt))**2 / basevec**2
Standard_Real aCross = aVec2d.Crossed(aBaseVec);
Standard_Real aSquareDist = aCross * aCross
/ aBaseVec.SquareMagnitude();
return (aSquareDist <= aSquareMaxDist);
}
//=========================================================================
// function : IsInsideIn3d
// purpose : Check if aNextPnt lies inside of tube build on aBasePnt and aBaseVec.
// In 3d space. Static subfunction in DeleteByTube.
//=========================================================================
static Standard_Boolean IsInsideIn3d(const gp_Pnt& aBasePnt,
const gp_Vec& aBaseVec,
const gp_Pnt& aNextPnt,
const Standard_Real aSquareMaxDist)
{
gp_Vec aVec(aBasePnt, aNextPnt);
//d*d = (basevec^(nextpnt-basepnt))**2 / basevec**2
Standard_Real aSquareDist = aVec.CrossSquareMagnitude(aBaseVec)
/ aBaseVec.SquareMagnitude();
return (aSquareDist <= aSquareMaxDist);
}
static const Standard_Integer aMinNbBadDistr = 15;
static const Standard_Integer aNbSingleBezier = 30;
//=========================================================================
// function : DeleteByTube
// purpose : Check and delete points using tube criteria.
// Static subfunction in ComputePurgedWLine.
//=========================================================================
static Standard_Boolean IsSurfPlaneLike(const Handle(Adaptor3d_HSurface) &theS)
{
if (theS->GetType() == GeomAbs_Plane)
{
return Standard_True;
}
if (theS->GetType() == GeomAbs_BSplineSurface)
{
if (theS->UDegree() == 1 && theS->VDegree() == 1)
{
return Standard_True;
}
}
return Standard_False;
}
static Handle(IntPatch_WLine)
DeleteByTube(const Handle(IntPatch_WLine) &theWLine,
const Handle(Adaptor3d_HSurface) &theS1,
const Handle(Adaptor3d_HSurface) &theS2)
{
// III: Check points for tube criteria:
// Workaround to handle case of small amount points after purge.
// Test "boolean boptuc_complex B5" and similar.
Standard_Integer aNbPnt = 0 , i;
if (theWLine->NbPnts() <= 2)
return theWLine;
NCollection_Array1<Standard_Integer> aNewPointsHash(1, theWLine->NbPnts());
FillPointsHash(theWLine, aNewPointsHash);
// Inital computations.
Standard_Real UonS1[3], VonS1[3], UonS2[3], VonS2[3];
theWLine->Point(1).ParametersOnS1(UonS1[0], VonS1[0]);
theWLine->Point(2).ParametersOnS1(UonS1[1], VonS1[1]);
theWLine->Point(1).ParametersOnS2(UonS2[0], VonS2[0]);
theWLine->Point(2).ParametersOnS2(UonS2[1], VonS2[1]);
gp_Pnt2d aBase2dPnt1(UonS1[0], VonS1[0]);
gp_Pnt2d aBase2dPnt2(UonS2[0], VonS2[0]);
gp_Vec2d aBase2dVec1(UonS1[1] - UonS1[0], VonS1[1] - VonS1[0]);
gp_Vec2d aBase2dVec2(UonS2[1] - UonS2[0], VonS2[1] - VonS2[0]);
gp_Pnt aBase3dPnt = theWLine->Point(1).Value();
gp_Vec aBase3dVec(theWLine->Point(1).Value(), theWLine->Point(2).Value());
Standard_Real aPrevStep = aBase3dVec.SquareMagnitude();
// Choose base tolerance and scale it to pipe algorithm.
const Standard_Real aBaseTolerance = Precision::Approximation();
Standard_Real aResS1Tol = Min(theS1->UResolution(aBaseTolerance),
theS1->VResolution(aBaseTolerance));
Standard_Real aResS2Tol = Min(theS2->UResolution(aBaseTolerance),
theS2->VResolution(aBaseTolerance));
Standard_Real aTol1 = aResS1Tol * aResS1Tol;
Standard_Real aTol2 = aResS2Tol * aResS2Tol;
Standard_Real aTol3d = aBaseTolerance * aBaseTolerance;
const Standard_Real aLimitCoeff = 0.99 * 0.99;
const Standard_Real aMaxSqrRatio = 15. * 15.;
Standard_Boolean isPlanePlane = IsSurfPlaneLike(theS1) && IsSurfPlaneLike(theS2);
for(i = 3; i <= theWLine->NbPnts(); i++)
{
Standard_Boolean isDeleteState = Standard_False;
theWLine->Point(i).ParametersOnS1(UonS1[2], VonS1[2]);
theWLine->Point(i).ParametersOnS2(UonS2[2], VonS2[2]);
gp_Pnt2d aPnt2dOnS1(UonS1[2], VonS1[2]);
gp_Pnt2d aPnt2dOnS2(UonS2[2], VonS2[2]);
const gp_Pnt& aPnt3d = theWLine->Point(i).Value();
if (aNewPointsHash(i - 1) != - 1 &&
IsInsideIn2d(aBase2dPnt1, aBase2dVec1, aPnt2dOnS1, aTol1) &&
IsInsideIn2d(aBase2dPnt2, aBase2dVec2, aPnt2dOnS2, aTol2) &&
IsInsideIn3d(aBase3dPnt, aBase3dVec, aPnt3d, aTol3d) )
{
// Handle possible uneven parametrization on one of 2d subspaces.
// Delete point only when expected lengths are close to each other (aLimitCoeff).
// Example:
// c2d1 - line
// c3d - line
// c2d2 - geometrically line, but have uneven parametrization -> c2d2 is bspline.
gp_XY aPntOnS1[2]= { gp_XY(UonS1[1] - UonS1[0], VonS1[1] - VonS1[0])
, gp_XY(UonS1[2] - UonS1[1], VonS1[2] - VonS1[1])};
gp_XY aPntOnS2[2]= { gp_XY(UonS2[1] - UonS2[0], VonS2[1] - VonS2[0])
, gp_XY(UonS2[2] - UonS2[1], VonS2[2] - VonS2[1])};
Standard_Real aStepOnS1 = aPntOnS1[0].SquareModulus() / aPntOnS1[1].SquareModulus();
Standard_Real aStepOnS2 = aPntOnS2[0].SquareModulus() / aPntOnS2[1].SquareModulus();
// Check very rare case when wline fluctuates nearly one point and some of them may be equal.
// Middle point will be deleted when such situation occurs.
// bugs moddata_2 bug469.
if (Min(aStepOnS1, aStepOnS2) >= aLimitCoeff * Max(aStepOnS1, aStepOnS2))
{
// Set hash flag to "Delete" state.
Standard_Real aCurrStep = aBase3dPnt.SquareDistance(aPnt3d);
Standard_Real aSqrRatio = 0.;
if (!isPlanePlane)
{
aSqrRatio = aPrevStep / aCurrStep;
if (aSqrRatio < 1.)
{
aSqrRatio = 1. / aSqrRatio;
}
}
if (aSqrRatio < aMaxSqrRatio)
{
isDeleteState = Standard_True;
aNewPointsHash.SetValue(i - 1, 1);
// Change middle point.
UonS1[1] = UonS1[2];
UonS2[1] = UonS2[2];
VonS1[1] = VonS1[2];
VonS2[1] = VonS2[2];
}
}
}
if (!isDeleteState)
{
// Compute new pipe parameters.
UonS1[0] = UonS1[1];
VonS1[0] = VonS1[1];
UonS2[0] = UonS2[1];
VonS2[0] = VonS2[1];
UonS1[1] = UonS1[2];
VonS1[1] = VonS1[2];
UonS2[1] = UonS2[2];
VonS2[1] = VonS2[2];
aBase2dPnt1.SetCoord(UonS1[0], VonS1[0]);
aBase2dPnt2.SetCoord(UonS2[0], VonS2[0]);
aBase2dVec1.SetCoord(UonS1[1] - UonS1[0], VonS1[1] - VonS1[0]);
aBase2dVec2.SetCoord(UonS2[1] - UonS2[0], VonS2[1] - VonS2[0]);
aBase3dPnt = theWLine->Point(i - 1).Value();
aBase3dVec = gp_Vec(theWLine->Point(i - 1).Value(), theWLine->Point(i).Value());
aPrevStep = aBase3dVec.SquareMagnitude();
aNbPnt++;
}
}
// Workaround to handle case of small amount of points after purge.
// Test "boolean boptuc_complex B5" and similar.
// This is possible since there are at least two points.
if (aNewPointsHash(1) == -1 &&
aNewPointsHash(2) == -1 &&
aNbPnt <= 3)
{
// Delete first.
aNewPointsHash(1) = 1;
}
if (aNewPointsHash(theWLine->NbPnts() - 1) == -1 &&
aNewPointsHash(theWLine->NbPnts() ) == -1 &&
aNbPnt <= 3)
{
// Delete last.
aNewPointsHash(theWLine->NbPnts()) = 1;
}
// Purgre when too small amount of points left.
if (aNbPnt <= 2)
{
for(i = aNewPointsHash.Lower(); i <= aNewPointsHash.Upper(); i++)
{
if (aNewPointsHash(i) != -1)
{
aNewPointsHash(i) = 1;
}
}
}
// Handle possible bad distribution of points,
// which are will converted into one single bezier curve (less than 30 points).
// Make distribution more even:
// max step will be nearly to 0.1 of param distance.
if (aNbPnt + 2 > aMinNbBadDistr &&
aNbPnt + 2 < aNbSingleBezier )
{
for(Standard_Integer anIdx = 1; anIdx <= 8; anIdx++)
{
Standard_Integer aHashIdx =
Standard_Integer(anIdx * theWLine->NbPnts() / 9);
//Vertex must be stored as VERTEX (HASH = -1)
if (aNewPointsHash(aHashIdx) != -1)
aNewPointsHash(aHashIdx) = 0;
}
}
return MakeNewWLine(theWLine, aNewPointsHash, Standard_False);
}
//=======================================================================
//function : IsSeamOrBound
//purpose : Returns TRUE if segment [thePtf, thePtl] intersects "seam-edge"
// (if it exist) or surface boundaries and both thePtf and thePtl do
// not match "seam-edge" or boundaries.
// Point thePtmid lies in this segment (in both 3D and 2D-space).
// If thePtmid match "seam-edge" or boundaries strictly
// (without any tolerance) then the function will return TRUE.
// See comments in function body for detail information.
//
// Arrays theArrPeriods, theFBound and theLBound must be filled
// as follows:
// [0] - U-parameter of 1st surface;
// [1] - V-parameter of 1st surface;
// [2] - U-parameter of 2nd surface;
// [3] - V-parameter of 2nd surface.
//=======================================================================
static Standard_Boolean IsSeamOrBound(const IntSurf_PntOn2S& thePtf,
const IntSurf_PntOn2S& thePtl,
const IntSurf_PntOn2S& thePtmid,
const Standard_Real theArrPeriods[4],
const Standard_Real theFBound[4],
const Standard_Real theLBound[4])
{
Standard_Real aParF[4] = { 0.0, 0.0, 0.0, 0.0 };
Standard_Real aParL[4] = { 0.0, 0.0, 0.0, 0.0 };
thePtf.Parameters(aParF[0], aParF[1], aParF[2], aParF[3]);
thePtl.Parameters(aParL[0], aParL[1], aParL[2], aParL[3]);
Bnd_Range aBndR[4];
for (Standard_Integer i = 0; i < 4; i++)
{
aBndR[i].Add(aParF[i]);
aBndR[i].Add(aParL[i]);
if (aBndR[i].IsIntersected(theFBound[i], theArrPeriods[i]) == 1)
return Standard_True;
if (aBndR[i].IsIntersected(theLBound[i], theArrPeriods[i]) == 1)
return Standard_True;
}
for (Standard_Integer i = 0; i < 4; i++)
{
if (theArrPeriods[i] == 0.0)
{
//Strictly equal
continue;
}
const Standard_Real aDelta = Abs(aParL[i] - aParF[i]);
if (2.0*aDelta > theArrPeriods[i])
{
//Most likely, seam is intersected.
return Standard_True;
}
if (aBndR[i].IsIntersected(0.0, theArrPeriods[i]) == 1)
return Standard_True;
}
//The segment [thePtf, thePtl] does not intersect the boundaries and
//the seam-edge of the surfaces.
//Nevertheless, following situation is possible:
// seam or
// bound
// |
// thePtf * |
// |
// * thePtmid
// thePtl * |
// |
//This case must be processed, too.
Standard_Real aMPar[4] = { 0.0, 0.0, 0.0, 0.0 };
thePtmid.Parameters(aMPar[0], aMPar[1], aMPar[2], aMPar[3]);
for (Standard_Integer i = 0; i < 4; i++)
{
const Bnd_Range aBR(aMPar[i], aMPar[i]);
if (aBR.IsIntersected(theFBound[i], theArrPeriods[i]))
return Standard_True;
if (aBR.IsIntersected(theLBound[i], theArrPeriods[i]))
return Standard_True;
if (aBR.IsIntersected(0.0, theArrPeriods[i]))
return Standard_True;
}
return Standard_False;
}
//=======================================================================
//function : IsIntersectionPoint
//purpose : Returns True if thePmid is intersection point
// between theS1 and theS2 with given tolerance.
// In this case, parameters of thePmid on every quadric
// will be recomputed and returned.
//=======================================================================
static Standard_Boolean IsIntersectionPoint(const gp_Pnt& thePmid,
const Handle(Adaptor3d_HSurface)& theS1,
const Handle(Adaptor3d_HSurface)& theS2,
const IntSurf_PntOn2S& theRefPt,
const Standard_Real theTol,
const Standard_Real* const theArrPeriods,
IntSurf_PntOn2S& theNewPt)
{
Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
switch(theS1->GetType())
{
case GeomAbs_Plane:
ElSLib::Parameters(theS1->Plane(), thePmid, aU1, aV1);
break;
case GeomAbs_Cylinder:
ElSLib::Parameters(theS1->Cylinder(), thePmid, aU1, aV1);
break;
case GeomAbs_Sphere:
ElSLib::Parameters(theS1->Sphere(), thePmid, aU1, aV1);
break;
case GeomAbs_Cone:
ElSLib::Parameters(theS1->Cone(), thePmid, aU1, aV1);
break;
case GeomAbs_Torus:
ElSLib::Parameters(theS1->Torus(), thePmid, aU1, aV1);
break;
default:
return Standard_False;
}
switch(theS2->GetType())
{
case GeomAbs_Plane:
ElSLib::Parameters(theS2->Plane(), thePmid, aU2, aV2);
break;
case GeomAbs_Cylinder:
ElSLib::Parameters(theS2->Cylinder(), thePmid, aU2, aV2);
break;
case GeomAbs_Sphere:
ElSLib::Parameters(theS2->Sphere(), thePmid, aU2, aV2);
break;
case GeomAbs_Cone:
ElSLib::Parameters(theS2->Cone(), thePmid, aU2, aV2);
break;
case GeomAbs_Torus:
ElSLib::Parameters(theS2->Torus(), thePmid, aU2, aV2);
break;
default:
return Standard_False;
}
theNewPt.SetValue(thePmid, aU1, aV1, aU2, aV2);
IntPatch_SpecialPoints::AdjustPointAndVertex(theRefPt, theArrPeriods, theNewPt);
const gp_Pnt aP1(theS1->Value(aU1, aV1));
const gp_Pnt aP2(theS2->Value(aU2, aV2));
return (aP1.SquareDistance(aP2) <= theTol*theTol);
}
//=======================================================================
//function : ExtendFirst
//purpose : Adds thePOn2S to the begin of theWline
//=======================================================================
static void ExtendFirst(const Handle(IntPatch_WLine)& theWline,
const IntSurf_PntOn2S& theAddedPt)
{
Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
theAddedPt.Parameters(aU1, aV1, aU2, aV2);
if(theAddedPt.IsSame(theWline->Point(1), Precision::Confusion()))
{
theWline->Curve()->Value(1, theAddedPt);
for(Standard_Integer i = 1; i <= theWline->NbVertex(); i++)
{
IntPatch_Point &aVert = theWline->ChangeVertex(i);
if(aVert.ParameterOnLine() != 1)
break;
aVert.SetParameters(aU1, aV1, aU2, aV2);
aVert.SetValue(theAddedPt.Value());
}
return;
}
theWline->Curve()->InsertBefore(1, theAddedPt);
for(Standard_Integer i = 1; i <= theWline->NbVertex(); i++)
{
IntPatch_Point &aVert = theWline->ChangeVertex(i);
if(aVert.ParameterOnLine() == 1)
{
aVert.SetParameters(aU1, aV1, aU2, aV2);
aVert.SetValue(theAddedPt.Value());
}
else
{
aVert.SetParameter(aVert.ParameterOnLine()+1);
}
}
}
//=======================================================================
//function : ExtendLast
//purpose : Adds thePOn2S to the end of theWline
//=======================================================================
static void ExtendLast(const Handle(IntPatch_WLine)& theWline,
const IntSurf_PntOn2S& theAddedPt)
{
Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
theAddedPt.Parameters(aU1, aV1, aU2, aV2);
const Standard_Integer aNbPnts = theWline->NbPnts();
if(theAddedPt.IsSame(theWline->Point(aNbPnts), Precision::Confusion()))
{
theWline->Curve()->Value(aNbPnts, theAddedPt);
}
else
{
theWline->Curve()->Add(theAddedPt);
}
for(Standard_Integer i = theWline->NbVertex(); i >= 1; i--)
{
IntPatch_Point &aVert = theWline->ChangeVertex(i);
if(aVert.ParameterOnLine() != aNbPnts)
break;
aVert.SetParameters(aU1, aV1, aU2, aV2);
aVert.SetValue(theAddedPt.Value());
aVert.SetParameter(theWline->NbPnts());
}
}
//=========================================================================
// function: IsOutOfDomain
// purpose : Checks, if 2D-representation of thePOn2S is in surfaces domain,
// defined by bounding-boxes theBoxS1 and theBoxS2
//=========================================================================
static Standard_Boolean IsOutOfDomain(const Bnd_Box2d& theBoxS1,
const Bnd_Box2d& theBoxS2,
const IntSurf_PntOn2S &thePOn2S,
const Standard_Real* const theArrPeriods)
{
Standard_Real aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
Standard_Real aU1min = 0.0, aU1max = 0.0, aV1min = 0.0, aV1max = 0.0;
Standard_Real aU2min = 0.0, aU2max = 0.0, aV2min = 0.0, aV2max = 0.0;
thePOn2S.Parameters(aU1, aV1, aU2, aV2);
theBoxS1.Get(aU1min, aV1min, aU1max, aV1max);
theBoxS2.Get(aU2min, aV2min, aU2max, aV2max);
aU1 = ElCLib::InPeriod(aU1, aU1min, aU1min + theArrPeriods[0]);
aV1 = ElCLib::InPeriod(aV1, aV1min, aV1min + theArrPeriods[1]);
aU2 = ElCLib::InPeriod(aU2, aU2min, aU2min + theArrPeriods[2]);
aV2 = ElCLib::InPeriod(aV2, aV2min, aV2min + theArrPeriods[3]);
return (theBoxS1.IsOut(gp_Pnt2d(aU1, aV1)) ||
theBoxS2.IsOut(gp_Pnt2d(aU2, aV2)));
}
//=======================================================================
//function : CheckArgumentsToExtend
//purpose : Check if extending is possible
// (see IntPatch_WLineTool::ExtendTwoWLines)
//=======================================================================
static IntPatchWT_WLsConnectionType
CheckArgumentsToExtend(const Handle(Adaptor3d_HSurface)& theS1,
const Handle(Adaptor3d_HSurface)& theS2,
const IntSurf_PntOn2S& thePtWL1,
const IntSurf_PntOn2S& thePtWL2,
IntSurf_PntOn2S& theNewPoint,
const gp_Vec& theVec1,
const gp_Vec& theVec2,
const gp_Vec& theVec3,
const Bnd_Box2d& theBoxS1,
const Bnd_Box2d& theBoxS2,
const Standard_Real theToler3D,
const Standard_Real* const theArrPeriods)
{
const Standard_Real aSqToler = theToler3D*theToler3D;
if(theVec3.SquareMagnitude() <= aSqToler)
{
return IntPatchWT_NotConnected;
}
if((theVec1.Angle(theVec2) > IntPatch_WLineTool::myMaxConcatAngle) ||
(theVec1.Angle(theVec3) > IntPatch_WLineTool::myMaxConcatAngle) ||
(theVec2.Angle(theVec3) > IntPatch_WLineTool::myMaxConcatAngle))
{
return IntPatchWT_NotConnected;
}
const gp_Pnt aPmid(0.5*(thePtWL1.Value().XYZ()+thePtWL2.Value().XYZ()));
Standard_Real aNewPar[4] = {0.0, 0.0, 0.0, 0.0};
//Left-bottom corner
Standard_Real aParLBC[4] = {0.0, 0.0, 0.0, 0.0};
theBoxS1.Get(aParLBC[0], aParLBC[1], aNewPar[0], aNewPar[0]);
theBoxS2.Get(aParLBC[2], aParLBC[3], aNewPar[0], aNewPar[0]);
if(!IsIntersectionPoint(aPmid, theS1, theS2, thePtWL1, theToler3D,
theArrPeriods, theNewPoint))
{
return IntPatchWT_NotConnected;
}
if(IsOutOfDomain(theBoxS1, theBoxS2, theNewPoint, theArrPeriods))
{
return IntPatchWT_NotConnected;
}
Standard_Real aParWL1[4] = {0.0, 0.0, 0.0, 0.0},
aParWL2[4] = {0.0, 0.0, 0.0, 0.0};
thePtWL1.Parameters(aParWL1[0], aParWL1[1], aParWL1[2], aParWL1[3]);
thePtWL2.Parameters(aParWL2[0], aParWL2[1], aParWL2[2], aParWL2[3]);
theNewPoint.Parameters(aNewPar[0], aNewPar[1], aNewPar[2], aNewPar[3]);
Bnd_Range aR1, aR2;
Standard_Boolean isOnBoundary = Standard_False;
for(Standard_Integer i = 0; i < 4; i++)
{
if (theArrPeriods[i] == 0.0)
{
//Strictly equal
continue;
}
aR1.SetVoid();
aR1.Add(aParWL1[i]);
aR1.Add(aParWL2[i]);
if (aR1.IsIntersected(aParLBC[i],theArrPeriods[i]))
{
//Check, if we intersect surface boundary when we will extend Wline1 or Wline2
//to theNewPoint
MinMax(aParWL1[i], aParWL2[i]);
if(aNewPar[i] > aParWL2[i])
{
//Source situation:
//
//---*---------------*------------*-----
// aParWL1[i] aParWL2[i] aNewPar[i]
//
//After possible adjusting:
//
//---*---------------*------------*-----
// aParWL1[i] aNewPar[i] aParWL2[i]
//
//Now we will be able to extend every WLine to
//aNewPar[i] to make them close to each other.
//However, it is necessary to add check if we
//intersect boundary.
const Standard_Real aPar = aParWL1[i] +
theArrPeriods[i]*Ceiling((aNewPar[i]-aParWL1[i])/theArrPeriods[i]);
aParWL1[i] = aParWL2[i];
aParWL2[i] = aPar;
}
else if(aNewPar[i] < aParWL1[i])
{
//See comments to main "if".
//Source situation:
//
//---*---------------*------------*-----
// aNewPar[i] aParWL1[i] aParWL2[i]
//
//After possible adjusting:
//
//---*---------------*------------*-----
// aParWL1[i] aNewPar[i] aParWL2[i]
const Standard_Real aPar = aParWL2[i] -
theArrPeriods[i]*Ceiling((aParWL2[i]-aNewPar[i])/theArrPeriods[i]);
aParWL2[i] = aParWL1[i];
aParWL1[i] = aPar;
}
aR1.SetVoid();
aR2.SetVoid();
aR1.Add(aParWL1[i]);
aR1.Add(aNewPar[i]);
aR2.Add(aNewPar[i]);
aR2.Add(aParWL2[i]);
if (aR1.IsIntersected(aParLBC[i], theArrPeriods[i]) ||
aR2.IsIntersected(aParLBC[i], theArrPeriods[i]))
{
return IntPatchWT_NotConnected;
}
else
{
isOnBoundary = Standard_True;
}
}
}
if(isOnBoundary)
{
return IntPatchWT_Singular;
}
return IntPatchWT_EachOther;
}
//=======================================================================
//function : CheckArgumentsToJoin
//purpose : Check if joining is possible
// (see IntPatch_WLineTool::JoinWLines(...))
//=======================================================================
Standard_Boolean CheckArgumentsToJoin(const Handle(Adaptor3d_HSurface)& theS1,
const Handle(Adaptor3d_HSurface)& theS2,
const IntSurf_PntOn2S& thePnt,
const Standard_Real theMinRad)
{
const Standard_Real aRad =
IntPatch_PointLine::CurvatureRadiusOfIntersLine(theS1, theS2, thePnt);
return (aRad > theMinRad);
}
//=======================================================================
//function : ExtendTwoWLFirstFirst
//purpose : Performs extending theWLine1 and theWLine2 through their
// respecting start point.
//=======================================================================
static void ExtendTwoWLFirstFirst(const Handle(Adaptor3d_HSurface)& theS1,
const Handle(Adaptor3d_HSurface)& theS2,
const Handle(IntPatch_WLine)& theWLine1,
const Handle(IntPatch_WLine)& theWLine2,
const IntSurf_PntOn2S& thePtWL1,
const IntSurf_PntOn2S& thePtWL2,
const gp_Vec& theVec1,
const gp_Vec& theVec2,
const gp_Vec& theVec3,
const Bnd_Box2d& theBoxS1,
const Bnd_Box2d& theBoxS2,
const Standard_Real theToler3D,
const Standard_Real* const theArrPeriods,
unsigned int &theCheckResult,
Standard_Boolean &theHasBeenJoined)
{
IntSurf_PntOn2S aPOn2S;
const IntPatchWT_WLsConnectionType aCheckRes =
CheckArgumentsToExtend(theS1, theS2, thePtWL1, thePtWL2, aPOn2S,
theVec1, theVec2, theVec3,
theBoxS1, theBoxS2,
theToler3D, theArrPeriods);
if(aCheckRes != IntPatchWT_NotConnected)
theCheckResult |= (IntPatchWT_DisFirstLast | IntPatchWT_DisLastFirst);
else
return;
IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL1, theArrPeriods, aPOn2S);
ExtendFirst(theWLine1, aPOn2S);
IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL2, theArrPeriods, aPOn2S);
ExtendFirst(theWLine2, aPOn2S);
if(theHasBeenJoined || (aCheckRes == IntPatchWT_Singular))
return;
Standard_Real aPrm = theWLine1->Vertex(1).ParameterOnLine();
while(theWLine1->Vertex(1).ParameterOnLine() == aPrm)
theWLine1->RemoveVertex(1);
aPrm = theWLine2->Vertex(1).ParameterOnLine();
while(theWLine2->Vertex(1).ParameterOnLine() == aPrm)
theWLine2->RemoveVertex(1);
const Standard_Integer aNbPts = theWLine2->NbPnts();
for(Standard_Integer aNPt = 2; aNPt <= aNbPts; aNPt++)
{
const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
theWLine1->Curve()->InsertBefore(1, aPt);
}
for(Standard_Integer aNVtx = 1; aNVtx <= theWLine1->NbVertex(); aNVtx++)
{
IntPatch_Point &aVert = theWLine1->ChangeVertex(aNVtx);
const Standard_Real aCurParam = aVert.ParameterOnLine();
aVert.SetParameter(aNbPts+aCurParam-1);
}
for(Standard_Integer aNVtx = 1; aNVtx <= theWLine2->NbVertex(); aNVtx++)
{
IntPatch_Point &aVert = theWLine2->ChangeVertex(aNVtx);
const Standard_Real aCurParam = aVert.ParameterOnLine();
aVert.SetParameter(aNbPts-aCurParam+1);
theWLine1->AddVertex(aVert, Standard_True);
}
theHasBeenJoined = Standard_True;
}
//=======================================================================
//function : ExtendTwoWLFirstLast
//purpose : Performs extending theWLine1 through its start point and theWLine2
// through its end point.
//=======================================================================
static void ExtendTwoWLFirstLast(const Handle(Adaptor3d_HSurface)& theS1,
const Handle(Adaptor3d_HSurface)& theS2,
const Handle(IntPatch_WLine)& theWLine1,
const Handle(IntPatch_WLine)& theWLine2,
const IntSurf_PntOn2S& thePtWL1,
const IntSurf_PntOn2S& thePtWL2,
const gp_Vec& theVec1,
const gp_Vec& theVec2,
const gp_Vec& theVec3,
const Bnd_Box2d& theBoxS1,
const Bnd_Box2d& theBoxS2,
const Standard_Real theToler3D,
const Standard_Real* const theArrPeriods,
unsigned int &theCheckResult,
Standard_Boolean &theHasBeenJoined)
{
IntSurf_PntOn2S aPOn2S;
const IntPatchWT_WLsConnectionType aCheckRes =
CheckArgumentsToExtend(theS1, theS2, thePtWL1, thePtWL2, aPOn2S,
theVec1, theVec2, theVec3,
theBoxS1, theBoxS2,
theToler3D, theArrPeriods);
if(aCheckRes != IntPatchWT_NotConnected)
theCheckResult |= IntPatchWT_DisLastLast;
else
return;
IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL1, theArrPeriods, aPOn2S);
ExtendFirst(theWLine1, aPOn2S);
IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL2, theArrPeriods, aPOn2S);
ExtendLast (theWLine2, aPOn2S);
if(theHasBeenJoined || (aCheckRes == IntPatchWT_Singular))
return;
Standard_Real aPrm = theWLine1->Vertex(1).ParameterOnLine();
while(theWLine1->Vertex(1).ParameterOnLine() == aPrm)
theWLine1->RemoveVertex(1);
aPrm = theWLine2->Vertex(theWLine2->NbVertex()).ParameterOnLine();
while(theWLine2->Vertex(theWLine2->NbVertex()).ParameterOnLine() == aPrm)
theWLine2->RemoveVertex(theWLine2->NbVertex());
const Standard_Integer aNbPts = theWLine2->NbPnts();
for(Standard_Integer aNPt = aNbPts - 1; aNPt >= 1; aNPt--)
{
const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
theWLine1->Curve()->InsertBefore(1, aPt);
}
for(Standard_Integer aNVtx = 1; aNVtx <= theWLine1->NbVertex(); aNVtx++)
{
IntPatch_Point &aVert = theWLine1->ChangeVertex(aNVtx);
const Standard_Real aCurParam = aVert.ParameterOnLine();
aVert.SetParameter(aNbPts+aCurParam-1);
}
for(Standard_Integer aNVtx = theWLine2->NbVertex(); aNVtx >= 1; aNVtx--)
{
const IntPatch_Point &aVert = theWLine2->Vertex(aNVtx);
theWLine1->AddVertex(aVert, Standard_True);
}
theHasBeenJoined = Standard_True;
}
//=======================================================================
//function : ExtendTwoWLLastFirst
//purpose : Performs extending theWLine1 through its end point and theWLine2
// through its start point.
//=======================================================================
static void ExtendTwoWLLastFirst(const Handle(Adaptor3d_HSurface)& theS1,
const Handle(Adaptor3d_HSurface)& theS2,
const Handle(IntPatch_WLine)& theWLine1,
const Handle(IntPatch_WLine)& theWLine2,
const IntSurf_PntOn2S& thePtWL1,
const IntSurf_PntOn2S& thePtWL2,
const gp_Vec& theVec1,
const gp_Vec& theVec2,
const gp_Vec& theVec3,
const Bnd_Box2d& theBoxS1,
const Bnd_Box2d& theBoxS2,
const Standard_Real theToler3D,
const Standard_Real* const theArrPeriods,
unsigned int &theCheckResult,
Standard_Boolean &theHasBeenJoined)
{
IntSurf_PntOn2S aPOn2S;
const IntPatchWT_WLsConnectionType aCheckRes =
CheckArgumentsToExtend(theS1, theS2, thePtWL1, thePtWL2, aPOn2S,
theVec1, theVec2, theVec3,
theBoxS1, theBoxS2,
theToler3D, theArrPeriods);
if(aCheckRes != IntPatchWT_NotConnected)
theCheckResult |= IntPatchWT_DisLastLast;
else
return;
IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL1, theArrPeriods, aPOn2S);
ExtendLast (theWLine1, aPOn2S);
IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL2, theArrPeriods, aPOn2S);
ExtendFirst(theWLine2, aPOn2S);
if(theHasBeenJoined || (aCheckRes == IntPatchWT_Singular))
{
return;
}
Standard_Real aPrm = theWLine1->Vertex(theWLine1->NbVertex()).ParameterOnLine();
while(theWLine1->Vertex(theWLine1->NbVertex()).ParameterOnLine() == aPrm)
theWLine1->RemoveVertex(theWLine1->NbVertex());
aPrm = theWLine2->Vertex(1).ParameterOnLine();
while(theWLine2->Vertex(1).ParameterOnLine() == aPrm)
theWLine2->RemoveVertex(1);
const Standard_Integer aNbPts = theWLine1->NbPnts();
for(Standard_Integer aNPt = 2; aNPt <= theWLine2->NbPnts(); aNPt++)
{
const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
theWLine1->Curve()->Add(aPt);
}
for(Standard_Integer aNVtx = 1; aNVtx <= theWLine2->NbVertex(); aNVtx++)
{
IntPatch_Point &aVert = theWLine2->ChangeVertex(aNVtx);
const Standard_Real aCurParam = aVert.ParameterOnLine();
aVert.SetParameter(aNbPts+aCurParam-1);
theWLine1->AddVertex(aVert, Standard_False);
}
theHasBeenJoined = Standard_True;
}
//=======================================================================
//function : ExtendTwoWLLastLast
//purpose :
//=======================================================================
static void ExtendTwoWLLastLast(const Handle(Adaptor3d_HSurface)& theS1,
const Handle(Adaptor3d_HSurface)& theS2,
const Handle(IntPatch_WLine)& theWLine1,
const Handle(IntPatch_WLine)& theWLine2,
const IntSurf_PntOn2S& thePtWL1,
const IntSurf_PntOn2S& thePtWL2,
const gp_Vec& theVec1,
const gp_Vec& theVec2,
const gp_Vec& theVec3,
const Bnd_Box2d& theBoxS1,
const Bnd_Box2d& theBoxS2,
const Standard_Real theToler3D,
const Standard_Real* const theArrPeriods,
unsigned int &theCheckResult,
Standard_Boolean &theHasBeenJoined)
{
IntSurf_PntOn2S aPOn2S;
const IntPatchWT_WLsConnectionType aCheckRes =
CheckArgumentsToExtend(theS1, theS2, thePtWL1, thePtWL2, aPOn2S,
theVec1, theVec2, theVec3,
theBoxS1, theBoxS2,
theToler3D, theArrPeriods);
if(aCheckRes != IntPatchWT_NotConnected)
theCheckResult |= IntPatchWT_DisLastLast;
else
return;
IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL1, theArrPeriods, aPOn2S);
ExtendLast(theWLine1, aPOn2S);
IntPatch_SpecialPoints::AdjustPointAndVertex(thePtWL2, theArrPeriods, aPOn2S);
ExtendLast(theWLine2, aPOn2S);
if(theHasBeenJoined || (aCheckRes == IntPatchWT_Singular))
return;
Standard_Real aPrm = theWLine1->Vertex(theWLine1->NbVertex()).ParameterOnLine();
while(theWLine1->Vertex(theWLine1->NbVertex()).ParameterOnLine() == aPrm)
theWLine1->RemoveVertex(theWLine1->NbVertex());
aPrm = theWLine2->Vertex(theWLine2->NbVertex()).ParameterOnLine();
while(theWLine2->Vertex(theWLine2->NbVertex()).ParameterOnLine() == aPrm)
theWLine2->RemoveVertex(theWLine2->NbVertex());
const Standard_Integer aNbPts = theWLine1->NbPnts() + theWLine2->NbPnts();
for(Standard_Integer aNPt = theWLine2->NbPnts()-1; aNPt >= 1; aNPt--)
{
const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
theWLine1->Curve()->Add(aPt);
}
for(Standard_Integer aNVtx = theWLine2->NbVertex(); aNVtx >= 1; aNVtx--)
{
IntPatch_Point &aVert = theWLine2->ChangeVertex(aNVtx);
const Standard_Real aCurParam = aVert.ParameterOnLine();
aVert.SetParameter(aNbPts - aCurParam);
theWLine1->AddVertex(aVert, Standard_False);
}
theHasBeenJoined = Standard_True;
}
//=========================================================================
// function : ComputePurgedWLine
// purpose :
//=========================================================================
Handle(IntPatch_WLine) IntPatch_WLineTool::
ComputePurgedWLine(const Handle(IntPatch_WLine) &theWLine,
const Handle(Adaptor3d_HSurface) &theS1,
const Handle(Adaptor3d_HSurface) &theS2,
const Handle(Adaptor3d_TopolTool) &theDom1,
const Handle(Adaptor3d_TopolTool) &theDom2)
{
Standard_Integer i, k, v, nb, nbvtx;
Handle(IntPatch_WLine) aResult;
nbvtx = theWLine->NbVertex();
nb = theWLine->NbPnts();
if (nb==2)
{
const IntSurf_PntOn2S& p1 = theWLine->Point(1);
const IntSurf_PntOn2S& p2 = theWLine->Point(2);
if(p1.Value().IsEqual(p2.Value(), gp::Resolution()))
return aResult;
}
Handle(IntPatch_WLine) aLocalWLine;
Handle(IntPatch_WLine) aTmpWLine = theWLine;
Handle(IntSurf_LineOn2S) aLineOn2S = new IntSurf_LineOn2S();
aLocalWLine = new IntPatch_WLine(aLineOn2S, Standard_False);
for(i = 1; i <= nb; i++)
aLineOn2S->Add(theWLine->Point(i));
for(v = 1; v <= nbvtx; v++)
aLocalWLine->AddVertex(theWLine->Vertex(v));
// I: Delete equal points
for(i = 1; i <= aLineOn2S->NbPoints(); i++)
{
Standard_Integer aStartIndex = i + 1;
Standard_Integer anEndIndex = i + 5;
nb = aLineOn2S->NbPoints();
anEndIndex = (anEndIndex > nb) ? nb : anEndIndex;
if((aStartIndex > nb) || (anEndIndex <= 1))
continue;
k = aStartIndex;
while(k <= anEndIndex)
{
if(i != k)
{
IntSurf_PntOn2S p1 = aLineOn2S->Value(i);
IntSurf_PntOn2S p2 = aLineOn2S->Value(k);
Standard_Real UV[8];
p1.Parameters(UV[0], UV[1], UV[2], UV[3]);
p2.Parameters(UV[4], UV[5], UV[6], UV[7]);
Standard_Real aMax = Abs(UV[0]);
for(Standard_Integer anIdx = 1; anIdx < 8; anIdx++)
{
if (aMax < Abs(UV[anIdx]))
aMax = Abs(UV[anIdx]);
}
if(p1.Value().IsEqual(p2.Value(), gp::Resolution()) ||
Abs(UV[0] - UV[4]) + Abs(UV[1] - UV[5]) < 1.0e-16 * aMax ||
Abs(UV[2] - UV[6]) + Abs(UV[3] - UV[7]) < 1.0e-16 * aMax )
{
aTmpWLine = aLocalWLine;
aLocalWLine = new IntPatch_WLine(aLineOn2S, Standard_False);
for(v = 1; v <= aTmpWLine->NbVertex(); v++)
{
IntPatch_Point aVertex = aTmpWLine->Vertex(v);
Standard_Integer avertexindex = (Standard_Integer)aVertex.ParameterOnLine();
if(avertexindex >= k)
{
aVertex.SetParameter(aVertex.ParameterOnLine() - 1.);
}
aLocalWLine->AddVertex(aVertex);
}
aLineOn2S->RemovePoint(k);
anEndIndex--;
continue;
}
}
k++;
}
}
if (aLineOn2S->NbPoints() <= 2)
{
if (aLineOn2S->NbPoints() == 2)
return aLocalWLine;
else
return aResult;
}
// Avoid purge in case of C0 continuity:
// Intersection approximator may produce invalid curve after purge, example:
// bugs modalg_5 bug24731.
// Do not run purger when base number of points is too small.
if (theS1->UContinuity() == GeomAbs_C0 ||
theS1->VContinuity() == GeomAbs_C0 ||
theS2->UContinuity() == GeomAbs_C0 ||
theS2->VContinuity() == GeomAbs_C0 ||
nb < aNbSingleBezier)
{
return aLocalWLine;
}
// II: Delete out of borders points.
aLocalWLine = DeleteOuterPoints(aLocalWLine, theS1, theS2, theDom1, theDom2);
// III: Delete points by tube criteria.
Handle(IntPatch_WLine) aLocalWLineTube =
DeleteByTube(aLocalWLine, theS1, theS2);
if(aLocalWLineTube->NbPnts() > 1)
{
aResult = aLocalWLineTube;
}
return aResult;
}
//=======================================================================
//function : JoinWLines
//purpose :
//=======================================================================
void IntPatch_WLineTool::JoinWLines(IntPatch_SequenceOfLine& theSlin,
IntPatch_SequenceOfPoint& theSPnt,
Handle(Adaptor3d_HSurface) theS1,
Handle(Adaptor3d_HSurface) theS2,
const Standard_Real theTol3D)
{
if(theSlin.Length() == 0)
return;
// For two cylindrical surfaces only
const Standard_Real aMinRad = 1.0e-3*Min(theS1->Cylinder().Radius(),
theS2->Cylinder().Radius());
const Standard_Real anArrPeriods[4] = {theS1->IsUPeriodic() ? theS1->UPeriod() : 0.0,
theS1->IsVPeriodic() ? theS1->VPeriod() : 0.0,
theS2->IsUPeriodic() ? theS2->UPeriod() : 0.0,
theS2->IsVPeriodic() ? theS2->VPeriod() : 0.0};
const Standard_Real anArrFBonds[4] = {theS1->FirstUParameter(), theS1->FirstVParameter(),
theS2->FirstUParameter(), theS2->FirstVParameter()};
const Standard_Real anArrLBonds[4] = {theS1->LastUParameter(), theS1->LastVParameter(),
theS2->LastUParameter(), theS2->LastVParameter()};
Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator();
for(Standard_Integer aN1 = 1; aN1 <= theSlin.Length(); aN1++)
{
Handle(IntPatch_WLine) aWLine1(Handle(IntPatch_WLine)::DownCast(theSlin.Value(aN1)));
if(aWLine1.IsNull())
{//We must have failed to join not-point-lines
continue;
}
const Standard_Integer aNbPntsWL1 = aWLine1->NbPnts();
const IntSurf_PntOn2S& aPntFWL1 = aWLine1->Point(1);
const IntSurf_PntOn2S& aPntLWL1 = aWLine1->Point(aNbPntsWL1);
for(Standard_Integer aNPt = 1; aNPt <= theSPnt.Length(); aNPt++)
{
const IntSurf_PntOn2S aPntCur = theSPnt.Value(aNPt).PntOn2S();
if( aPntCur.IsSame(aPntFWL1, Precision::Confusion()) ||
aPntCur.IsSame(aPntLWL1, Precision::Confusion()))
{
theSPnt.Remove(aNPt);
aNPt--;
}
}
anAlloc->Reset();
NCollection_List<Standard_Integer> aListFC(anAlloc),
aListLC(anAlloc);
Standard_Boolean isFirstConnected = Standard_False, isLastConnected = Standard_False;
for (Standard_Integer aN2 = 1; aN2 <= theSlin.Length(); aN2++)
{
if (aN2 == aN1)
continue;
Handle(IntPatch_WLine) aWLine2(Handle(IntPatch_WLine)::DownCast(theSlin.Value(aN2)));
if (aWLine2.IsNull())
continue;
isFirstConnected = isLastConnected = Standard_False;
const Standard_Integer aNbPntsWL2 = aWLine2->NbPnts();
const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aNbPntsWL2);
Standard_Real aSqDistF = aPntFWL1.Value().SquareDistance(aPntFWL2.Value());
Standard_Real aSqDistL = aPntFWL1.Value().SquareDistance(aPntLWL2.Value());
const Standard_Real aSqMinFDist = Min(aSqDistF, aSqDistL);
if (aSqMinFDist < Precision::SquareConfusion())
{
if (CheckArgumentsToJoin(theS1, theS2, aPntFWL1, aMinRad))
{
const Standard_Boolean isFM = (aSqDistF < aSqDistL);
const IntSurf_PntOn2S& aPt1 = aWLine1->Point(2);
const IntSurf_PntOn2S& aPt2 = isFM ? aWLine2->Point(2) :
aWLine2->Point(aNbPntsWL2 - 1);
if (!IsSeamOrBound(aPt1, aPt2, aPntFWL1,
anArrPeriods, anArrFBonds, anArrLBonds))
{
isFirstConnected = Standard_True;
}
}
}
aSqDistF = aPntLWL1.Value().SquareDistance(aPntFWL2.Value());
aSqDistL = aPntLWL1.Value().SquareDistance(aPntLWL2.Value());
const Standard_Real aSqMinLDist = Min(aSqDistF, aSqDistL);
if (aSqMinLDist < Precision::SquareConfusion())
{
if (CheckArgumentsToJoin(theS1, theS2, aPntLWL1, aMinRad))
{
const Standard_Boolean isFM = (aSqDistF < aSqDistL);
const IntSurf_PntOn2S& aPt1 = aWLine1->Point(aNbPntsWL1 - 1);
const IntSurf_PntOn2S& aPt2 = isFM ? aWLine2->Point(2) :
aWLine2->Point(aNbPntsWL2 - 1);
if (!IsSeamOrBound(aPt1, aPt2, aPntLWL1,
anArrPeriods, anArrFBonds, anArrLBonds))
{
isLastConnected = Standard_True;
}
}
}
if (isFirstConnected && isLastConnected)
{
if (aSqMinFDist < aSqMinLDist)
{
aListFC.Append(aN2);
}
else
{
aListLC.Append(aN2);
}
}
else if (isFirstConnected)
{
aListFC.Append(aN2);
}
else if (isLastConnected)
{
aListLC.Append(aN2);
}
}
isFirstConnected = (aListFC.Extent() == 1);
isLastConnected = (aListLC.Extent() == 1);
if (!(isFirstConnected || isLastConnected))
{
continue;
}
const Standard_Integer anIndexWL2 = isFirstConnected ? aListFC.First() : aListLC.First();
Handle(IntPatch_WLine) aWLine2(Handle(IntPatch_WLine)::DownCast(theSlin.Value(anIndexWL2)));
const Standard_Integer aNbPntsWL2 = aWLine2->NbPnts();
const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
aWLine1->ClearVertexes();
if (isFirstConnected)
{
if (aPntFWL1.IsSame(aPntFWL2, Precision::Confusion()))
{
//First-First-connection
for (Standard_Integer aNPt = 1; aNPt <= aNbPntsWL2; aNPt++)
{
const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
aWLine1->Curve()->InsertBefore(1, aPt);
}
}
else
{
//First-Last-connection
for (Standard_Integer aNPt = aNbPntsWL2; aNPt >= 1; aNPt--)
{
const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
aWLine1->Curve()->InsertBefore(1, aPt);
}
}
}
else //if (isLastConnected)
{
if (aPntLWL1.IsSame(aPntFWL2, Precision::Confusion()))
{
//Last-First connection
for(Standard_Integer aNPt = 1; aNPt <= aNbPntsWL2; aNPt++)
{
const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
aWLine1->Curve()->Add(aPt);
}
}
else
{
//Last-Last connection
for (Standard_Integer aNPt = aNbPntsWL2; aNPt >= 1; aNPt--)
{
const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
aWLine1->Curve()->Add(aPt);
}
}
}
aWLine1->ComputeVertexParameters(theTol3D);
theSlin.Remove(anIndexWL2);
aN1--;
}
}
//=======================================================================
//function : ExtendTwoWLines
//purpose : Performs extending theWLine1 and theWLine2 through their
// respecting end point.
//=======================================================================
void IntPatch_WLineTool::ExtendTwoWLines(IntPatch_SequenceOfLine& theSlin,
const Handle(Adaptor3d_HSurface)& theS1,
const Handle(Adaptor3d_HSurface)& theS2,
const Standard_Real theToler3D,
const Standard_Real* const theArrPeriods,
const Bnd_Box2d& theBoxS1,
const Bnd_Box2d& theBoxS2)
{
if(theSlin.Length() < 2)
return;
gp_Vec aVec1, aVec2, aVec3;
for(Standard_Integer aNumOfLine1 = 1; aNumOfLine1 <= theSlin.Length(); aNumOfLine1++)
{
Handle(IntPatch_WLine) aWLine1 (Handle(IntPatch_WLine)::
DownCast(theSlin.Value(aNumOfLine1)));
if(aWLine1.IsNull())
{//We must have failed to join not-point-lines
continue;
}
const Standard_Integer aNbPntsWL1 = aWLine1->NbPnts();
if(aWLine1->Vertex(1).ParameterOnLine() != 1)
continue;
if(aWLine1->Vertex(aWLine1->NbVertex()).ParameterOnLine() != aWLine1->NbPnts())
continue;
const IntSurf_PntOn2S& aPntFWL1 = aWLine1->Point(1);
const IntSurf_PntOn2S& aPntFp1WL1 = aWLine1->Point(2);
const IntSurf_PntOn2S& aPntLWL1 = aWLine1->Point(aNbPntsWL1);
const IntSurf_PntOn2S& aPntLm1WL1 = aWLine1->Point(aNbPntsWL1-1);
//Enable/Disable of some ckeck. Bit-mask is used for it.
//E.g. if 1st point of aWLine1 matches with
//1st point of aWLine2 then we do not need in check
//1st point of aWLine1 and last point of aWLine2 etc.
unsigned int aCheckResult = IntPatchWT_EnAll;
//If aWLine1 is already connected with another Wline then
//there is no point in extending.
for(Standard_Integer aNumOfLine2 = aNumOfLine1 + 1;
aNumOfLine2 <= theSlin.Length(); aNumOfLine2++)
{
Handle(IntPatch_WLine) aWLine2 (Handle(IntPatch_WLine)::
DownCast(theSlin.Value(aNumOfLine2)));
if(aWLine2.IsNull())
continue;
const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aWLine2->NbPnts());
if( aPntFWL1.IsSame(aPntFWL2, theToler3D) ||
aPntFWL1.IsSame(aPntLWL2, theToler3D) )
{
aCheckResult |= IntPatchWT_DisFirstFirst | IntPatchWT_DisFirstLast;
}
if( aPntLWL1.IsSame(aPntFWL2, theToler3D) ||
aPntLWL1.IsSame(aPntFWL2, theToler3D))
{
aCheckResult |= IntPatchWT_DisLastFirst | IntPatchWT_DisLastLast;
}
}
if(aCheckResult == (IntPatchWT_DisFirstFirst | IntPatchWT_DisFirstLast |
IntPatchWT_DisLastFirst | IntPatchWT_DisLastLast))
continue;
for(Standard_Integer aNumOfLine2 = aNumOfLine1 + 1;
aNumOfLine2 <= theSlin.Length(); aNumOfLine2++)
{
Handle(IntPatch_WLine) aWLine2 (Handle(IntPatch_WLine)::
DownCast(theSlin.Value(aNumOfLine2)));
if(aWLine2.IsNull())
continue;
if(aWLine2->Vertex(1).ParameterOnLine() != 1)
continue;
if(aWLine2->Vertex(aWLine2->NbVertex()).ParameterOnLine() != aWLine2->NbPnts())
continue;
Standard_Boolean hasBeenJoined = Standard_False;
const Standard_Integer aNbPntsWL2 = aWLine2->NbPnts();
const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
const IntSurf_PntOn2S& aPntFp1WL2 = aWLine2->Point(2);
const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aNbPntsWL2);
const IntSurf_PntOn2S& aPntLm1WL2 = aWLine2->Point(aNbPntsWL2-1);
//if(!(aCheckResult & IntPatchWT_DisFirstFirst))
{// First/First
aVec1.SetXYZ(aPntFp1WL1.Value().XYZ() - aPntFWL1.Value().XYZ());
aVec2.SetXYZ(aPntFWL2.Value().XYZ() - aPntFp1WL2.Value().XYZ());
aVec3.SetXYZ(aPntFWL1.Value().XYZ() - aPntFWL2.Value().XYZ());
ExtendTwoWLFirstFirst(theS1, theS2, aWLine1, aWLine2, aPntFWL1, aPntFWL2,
aVec1, aVec2, aVec3, theBoxS1, theBoxS2, theToler3D,
theArrPeriods, aCheckResult, hasBeenJoined);
}
if(!(aCheckResult & IntPatchWT_DisFirstLast))
{// First/Last
aVec1.SetXYZ(aPntFp1WL1.Value().XYZ() - aPntFWL1.Value().XYZ());
aVec2.SetXYZ(aPntLWL2.Value().XYZ() - aPntLm1WL2.Value().XYZ());
aVec3.SetXYZ(aPntFWL1.Value().XYZ() - aPntLWL2.Value().XYZ());
ExtendTwoWLFirstLast(theS1, theS2, aWLine1, aWLine2, aPntFWL1, aPntLWL2,
aVec1, aVec2, aVec3, theBoxS1, theBoxS2, theToler3D,
theArrPeriods, aCheckResult, hasBeenJoined);
}
if(!(aCheckResult & IntPatchWT_DisLastFirst))
{// Last/First
aVec1.SetXYZ(aPntLWL1.Value().XYZ() - aPntLm1WL1.Value().XYZ());
aVec2.SetXYZ(aPntFp1WL2.Value().XYZ() - aPntFWL2.Value().XYZ());
aVec3.SetXYZ(aPntFWL2.Value().XYZ() - aPntLWL1.Value().XYZ());
ExtendTwoWLLastFirst(theS1, theS2, aWLine1, aWLine2, aPntLWL1, aPntFWL2,
aVec1, aVec2, aVec3, theBoxS1, theBoxS2, theToler3D,
theArrPeriods, aCheckResult, hasBeenJoined);
}
if(!(aCheckResult & IntPatchWT_DisLastLast))
{// Last/Last
aVec1.SetXYZ(aPntLWL1.Value().XYZ() - aPntLm1WL1.Value().XYZ());
aVec2.SetXYZ(aPntLm1WL2.Value().XYZ() - aPntLWL2.Value().XYZ());
aVec3.SetXYZ(aPntLWL2.Value().XYZ() - aPntLWL1.Value().XYZ());
ExtendTwoWLLastLast(theS1, theS2, aWLine1, aWLine2, aPntLWL1, aPntLWL2,
aVec1, aVec2, aVec3, theBoxS1, theBoxS2, theToler3D,
theArrPeriods, aCheckResult, hasBeenJoined);
}
if(hasBeenJoined)
{
theSlin.Remove(aNumOfLine2);
aNumOfLine2--;
}
}
}
}