mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-06-24 21:25:38 +08:00
Bug fixes: - Bnd_Box::Add(Bnd_Box) - fix unconditional bounds merge before open direction check - Bnd_Box::IsOut(gp_Pln) - use GetXMin()/GetXMax() accessors (include Gap) instead of raw fields - Bnd_Box::Distance() - add void box check to avoid invalid results - Bnd_Range::Common() - add missing return statement - Bnd_Sphere::SquareDistances() - fix radius comparison (was comparing distance vs radius instead of squared values) - Bnd_OBB: OBBTool::ProcessTriangle - add safety check for degenerate cross products before normalization - Bnd_OBB: OBBTool::ProcessDiTetrahedron - fix off-by-one in bounds check (use < instead of <=) Performance optimizations: - Bnd_Box::IsOut(Bnd_Box) - add early return fast path for non-open boxes - Bnd_Box2d::IsOut(Bnd_Box2d) - add early return fast path for non-open boxes API improvements: - Add Contains()/Intersects() semantic wrappers (inverse of IsOut) to Bnd_Box, Bnd_Box2d, Bnd_OBB, Bnd_Range - Add Center() returning std::optional to Bnd_Box, Bnd_Box2d, Bnd_Range - Add Min()/Max()/Get() returning std::optional to Bnd_Range - Add Bnd_Range::Bounds struct for C++17 structured bindings via Get() - Add Bnd_OBB::HalfSizes struct and GetHalfSizes() for structured bindings - Add Bnd_Box2d::Distance() method - Replace Bnd_Range::IsIntersected magic int returns with IntersectStatus enum Code modernization: - Add [[nodiscard]] and noexcept annotations across all Bnd classes - Migrate Bnd_Sphere inline methods from .lxx to header, delete Bnd_Sphere.lxx - Remove unused includes (iomanip, fstream, legacy Standard_*.hxx headers) - Fix Bnd_Box.hxx "Ymix" typo in IsOpenYmin() comment - Clean up DET-style comments in Bnd_Box.cxx - Update IntPatch_WLineTool.cxx to use IntersectStatus enum
2025 lines
72 KiB
C++
2025 lines
72 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_Surface.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 double 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_Common,
|
|
IntPatchWT_ReqExtend
|
|
};
|
|
|
|
//=======================================================================
|
|
// function : MinMax
|
|
// purpose : Replaces theParMIN = MIN(theParMIN, theParMAX),
|
|
// theParMAX = MAX(theParMIN, theParMAX).
|
|
//
|
|
// Static subfunction in IsSeamOrBound.
|
|
//=======================================================================
|
|
static inline void MinMax(double& theParMIN, double& theParMAX)
|
|
{
|
|
if (theParMIN > theParMAX)
|
|
{
|
|
const double aTmp = theParMAX;
|
|
theParMAX = theParMIN;
|
|
theParMIN = aTmp;
|
|
}
|
|
}
|
|
|
|
//=========================================================================
|
|
// function : FillPointsHash
|
|
// purpose : Fill points hash by input data.
|
|
// Static subfunction in ComputePurgedWLine.
|
|
//=========================================================================
|
|
static void FillPointsHash(const occ::handle<IntPatch_WLine>& theWLine,
|
|
NCollection_Array1<int>& thePointsHash)
|
|
{
|
|
// 1 - Delete point.
|
|
// 0 - Store point.
|
|
// -1 - Vertex point (not delete).
|
|
int 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);
|
|
int avertexindex = (int)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 occ::handle<IntPatch_WLine> MakeNewWLine(const occ::handle<IntPatch_WLine>& theWLine,
|
|
NCollection_Array1<int>& thePointsHash,
|
|
const bool theIsOuter)
|
|
{
|
|
int i;
|
|
|
|
occ::handle<IntSurf_LineOn2S> aPurgedLineOn2S = new IntSurf_LineOn2S();
|
|
occ::handle<IntPatch_WLine> aLocalWLine = new IntPatch_WLine(aPurgedLineOn2S, false);
|
|
aLocalWLine->SetCreatingWayInfo(theWLine->GetCreatingWay());
|
|
int 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 double aSqDistPrev = aPPrev.SquareDistance(aPOld);
|
|
const double aSqDist = aPPrev.SquareDistance(aP);
|
|
|
|
const double 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 occ::handle<Adaptor3d_Surface>& theS1, double& U1, double& 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 occ::handle<IntPatch_WLine> DeleteOuterPoints(
|
|
const occ::handle<IntPatch_WLine>& theWLine,
|
|
const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const occ::handle<Adaptor3d_TopolTool>& theDom1,
|
|
const occ::handle<Adaptor3d_TopolTool>& theDom2)
|
|
{
|
|
int i;
|
|
|
|
NCollection_Array1<int> aDelOuterPointsHash(1, theWLine->NbPnts());
|
|
FillPointsHash(theWLine, aDelOuterPointsHash);
|
|
|
|
if (theS1->IsUPeriodic() || theS1->IsVPeriodic() || theS2->IsUPeriodic() || theS2->IsVPeriodic())
|
|
return theWLine;
|
|
|
|
gp_Pnt2d aPntOnF1, aPntOnF2;
|
|
double aX1, aY1, aX2, aY2;
|
|
|
|
// Iterate over points in walking line and delete which are out of bounds.
|
|
// Forward.
|
|
bool isAllDeleted = true;
|
|
bool aChangedFirst = false;
|
|
int 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 = true;
|
|
}
|
|
else
|
|
{
|
|
isAllDeleted = false;
|
|
|
|
aFirstGeomIdx = std::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.
|
|
bool aChangedLast = false;
|
|
int 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 = true; // Move vertex to first good point
|
|
}
|
|
else
|
|
{
|
|
aLastGeomIdx = std::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 vertices.
|
|
occ::handle<IntPatch_WLine> aLocalWLine = MakeNewWLine(theWLine, aDelOuterPointsHash, true);
|
|
|
|
if (aChangedFirst)
|
|
{
|
|
// Vertex geometry.
|
|
IntPatch_Point aVertex = aLocalWLine->Vertex(1);
|
|
aVertex.SetValue(theWLine->Point(aFirstGeomIdx).Value());
|
|
double 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());
|
|
double 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 bool IsInsideIn2d(const gp_Pnt2d& aBasePnt,
|
|
const gp_Vec2d& aBaseVec,
|
|
const gp_Pnt2d& aNextPnt,
|
|
const double aSquareMaxDist)
|
|
{
|
|
gp_Vec2d aVec2d(aBasePnt, aNextPnt);
|
|
|
|
// d*d = (basevec^(nextpnt-basepnt))**2 / basevec**2
|
|
double aCross = aVec2d.Crossed(aBaseVec);
|
|
double 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 bool IsInsideIn3d(const gp_Pnt& aBasePnt,
|
|
const gp_Vec& aBaseVec,
|
|
const gp_Pnt& aNextPnt,
|
|
const double aSquareMaxDist)
|
|
{
|
|
gp_Vec aVec(aBasePnt, aNextPnt);
|
|
|
|
// d*d = (basevec^(nextpnt-basepnt))**2 / basevec**2
|
|
double aSquareDist = aVec.CrossSquareMagnitude(aBaseVec) / aBaseVec.SquareMagnitude();
|
|
|
|
return (aSquareDist <= aSquareMaxDist);
|
|
}
|
|
|
|
static const int aMinNbBadDistr = 15;
|
|
static const int aNbSingleBezier = 30;
|
|
|
|
//=========================================================================
|
|
// function : IsSurfPlaneLike
|
|
// purpose : Define is surface plane like or not.
|
|
// Static subfunction in DeleteByTube.
|
|
//=========================================================================
|
|
static bool IsSurfPlaneLike(const occ::handle<Adaptor3d_Surface>& theS)
|
|
{
|
|
if (theS->GetType() == GeomAbs_Plane)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if (theS->GetType() == GeomAbs_BSplineSurface)
|
|
{
|
|
if (theS->UDegree() == 1 && theS->VDegree() == 1)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//=========================================================================
|
|
// function : DeleteByTube
|
|
// purpose : Check and delete points using tube criteria.
|
|
// Static subfunction in ComputePurgedWLine.
|
|
//=========================================================================
|
|
|
|
static occ::handle<IntPatch_WLine> DeleteByTube(const occ::handle<IntPatch_WLine>& theWLine,
|
|
const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2)
|
|
{
|
|
// III: Check points for tube criteria:
|
|
// Workaround to handle case of small amount points after purge.
|
|
// Test "boolean boptuc_complex B5" and similar.
|
|
int aNbPnt = 0, i;
|
|
|
|
if (theWLine->NbPnts() <= 2)
|
|
return theWLine;
|
|
|
|
NCollection_Array1<int> aNewPointsHash(1, theWLine->NbPnts());
|
|
FillPointsHash(theWLine, aNewPointsHash);
|
|
|
|
// Initial computations.
|
|
double 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());
|
|
double aPrevStep = aBase3dVec.SquareMagnitude();
|
|
|
|
// Choose base tolerance and scale it to pipe algorithm.
|
|
constexpr double aBaseTolerance = Precision::Approximation();
|
|
double aResS1Tol =
|
|
std::min(theS1->UResolution(aBaseTolerance), theS1->VResolution(aBaseTolerance));
|
|
double aResS2Tol =
|
|
std::min(theS2->UResolution(aBaseTolerance), theS2->VResolution(aBaseTolerance));
|
|
double aTol1 = aResS1Tol * aResS1Tol;
|
|
double aTol2 = aResS2Tol * aResS2Tol;
|
|
double aTol3d = aBaseTolerance * aBaseTolerance;
|
|
|
|
const double aLimitCoeff = 0.99 * 0.99;
|
|
const double aMaxSqrRatio = 15. * 15.;
|
|
bool isPlanePlane = IsSurfPlaneLike(theS1) && IsSurfPlaneLike(theS2);
|
|
for (i = 3; i <= theWLine->NbPnts(); i++)
|
|
{
|
|
bool isDeleteState = 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])};
|
|
|
|
double aStepOnS1 = aPntOnS1[0].SquareModulus() / aPntOnS1[1].SquareModulus();
|
|
double 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 (std::min(aStepOnS1, aStepOnS2) >= aLimitCoeff * std::max(aStepOnS1, aStepOnS2))
|
|
{
|
|
// Set hash flag to "Delete" state.
|
|
double aCurrStep = aBase3dPnt.SquareDistance(aPnt3d);
|
|
double aSqrRatio = 0.;
|
|
if (!isPlanePlane)
|
|
{
|
|
aSqrRatio = aPrevStep / aCurrStep;
|
|
if (aSqrRatio < 1.)
|
|
{
|
|
aSqrRatio = 1. / aSqrRatio;
|
|
}
|
|
}
|
|
if (aSqrRatio < aMaxSqrRatio)
|
|
{
|
|
isDeleteState = 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 (int anIdx = 1; anIdx <= 8; anIdx++)
|
|
{
|
|
int aHashIdx = int(anIdx * theWLine->NbPnts() / 9);
|
|
|
|
// Vertex must be stored as VERTEX (HASH = -1)
|
|
if (aNewPointsHash(aHashIdx) != -1)
|
|
aNewPointsHash(aHashIdx) = 0;
|
|
}
|
|
}
|
|
|
|
return MakeNewWLine(theWLine, aNewPointsHash, 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 bool IsSeamOrBound(const IntSurf_PntOn2S& thePtf,
|
|
const IntSurf_PntOn2S& thePtl,
|
|
const IntSurf_PntOn2S& thePtmid,
|
|
const double theArrPeriods[4],
|
|
const double theFBound[4],
|
|
const double theLBound[4])
|
|
{
|
|
double aParF[4] = {0.0, 0.0, 0.0, 0.0};
|
|
double 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 (int i = 0; i < 4; i++)
|
|
{
|
|
aBndR[i].Add(aParF[i]);
|
|
aBndR[i].Add(aParL[i]);
|
|
|
|
if (aBndR[i].IsIntersected(theFBound[i], theArrPeriods[i]) == Bnd_Range::IntersectStatus_In)
|
|
return true;
|
|
|
|
if (aBndR[i].IsIntersected(theLBound[i], theArrPeriods[i]) == Bnd_Range::IntersectStatus_In)
|
|
return true;
|
|
}
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
if (theArrPeriods[i] == 0.0)
|
|
{
|
|
// Strictly equal
|
|
continue;
|
|
}
|
|
|
|
const double aDelta = std::abs(aParL[i] - aParF[i]);
|
|
if (2.0 * aDelta > theArrPeriods[i])
|
|
{
|
|
// Most likely, seam is intersected.
|
|
return true;
|
|
}
|
|
|
|
if (aBndR[i].IsIntersected(0.0, theArrPeriods[i]) == Bnd_Range::IntersectStatus_In)
|
|
return 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.
|
|
|
|
double aMPar[4] = {0.0, 0.0, 0.0, 0.0};
|
|
thePtmid.Parameters(aMPar[0], aMPar[1], aMPar[2], aMPar[3]);
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
const Bnd_Range aBR(aMPar[i], aMPar[i]);
|
|
if (aBR.IsIntersected(theFBound[i], theArrPeriods[i]))
|
|
return true;
|
|
|
|
if (aBR.IsIntersected(theLBound[i], theArrPeriods[i]))
|
|
return true;
|
|
|
|
if (aBR.IsIntersected(0.0, theArrPeriods[i]))
|
|
return true;
|
|
}
|
|
|
|
return 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 bool IsIntersectionPoint(const gp_Pnt& thePmid,
|
|
const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const IntSurf_PntOn2S& theRefPt,
|
|
const double theTol,
|
|
const double* const theArrPeriods,
|
|
IntSurf_PntOn2S& theNewPt)
|
|
{
|
|
double 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 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 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 occ::handle<IntPatch_WLine>& theWline,
|
|
const IntSurf_PntOn2S& theAddedPt)
|
|
{
|
|
double 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 (int 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 (int 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 occ::handle<IntPatch_WLine>& theWline,
|
|
const IntSurf_PntOn2S& theAddedPt)
|
|
{
|
|
double aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
|
|
theAddedPt.Parameters(aU1, aV1, aU2, aV2);
|
|
|
|
const int aNbPnts = theWline->NbPnts();
|
|
if (theAddedPt.IsSame(theWline->Point(aNbPnts), Precision::Confusion()))
|
|
{
|
|
theWline->Curve()->Value(aNbPnts, theAddedPt);
|
|
}
|
|
else
|
|
{
|
|
theWline->Curve()->Add(theAddedPt);
|
|
}
|
|
|
|
for (int 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 bool IsOutOfDomain(const Bnd_Box2d& theBoxS1,
|
|
const Bnd_Box2d& theBoxS2,
|
|
const IntSurf_PntOn2S& thePOn2S,
|
|
const double* const theArrPeriods)
|
|
{
|
|
double aU1 = 0.0, aV1 = 0.0, aU2 = 0.0, aV2 = 0.0;
|
|
double aU1min = 0.0, aU1max = 0.0, aV1min = 0.0, aV1max = 0.0;
|
|
double 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 occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& 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 double theToler3D,
|
|
const double* const theArrPeriods)
|
|
{
|
|
const double aSqToler = theToler3D * theToler3D;
|
|
IntPatchWT_WLsConnectionType aRetVal = IntPatchWT_NotConnected;
|
|
if (theVec3.SquareMagnitude() <= aSqToler)
|
|
{
|
|
if ((theVec1.Angle(theVec2) > IntPatch_WLineTool::myMaxConcatAngle))
|
|
{
|
|
return aRetVal;
|
|
}
|
|
else
|
|
{
|
|
aRetVal = IntPatchWT_Common;
|
|
}
|
|
}
|
|
else if ((theVec1.Angle(theVec2) > IntPatch_WLineTool::myMaxConcatAngle)
|
|
|| (theVec1.Angle(theVec3) > IntPatch_WLineTool::myMaxConcatAngle)
|
|
|| (theVec2.Angle(theVec3) > IntPatch_WLineTool::myMaxConcatAngle))
|
|
{
|
|
return aRetVal;
|
|
}
|
|
|
|
const gp_Pnt aPmid(0.5 * (thePtWL1.Value().XYZ() + thePtWL2.Value().XYZ()));
|
|
|
|
double aNewPar[4] = {0.0, 0.0, 0.0, 0.0};
|
|
|
|
// Left-bottom corner
|
|
double 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;
|
|
}
|
|
|
|
double 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;
|
|
|
|
bool isOnBoundary = false;
|
|
for (int 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 double aPar =
|
|
aParWL1[i] + theArrPeriods[i] * std::ceil((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 double aPar =
|
|
aParWL2[i] - theArrPeriods[i] * std::ceil((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 = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isOnBoundary)
|
|
{
|
|
return IntPatchWT_Singular;
|
|
}
|
|
|
|
if (aRetVal == IntPatchWT_Common)
|
|
{
|
|
return IntPatchWT_Common;
|
|
}
|
|
|
|
return IntPatchWT_ReqExtend;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : CheckArgumentsToJoin
|
|
// purpose : Check if joining is possible
|
|
// (see IntPatch_WLineTool::JoinWLines(...))
|
|
//=======================================================================
|
|
bool CheckArgumentsToJoin(const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const IntSurf_PntOn2S& thePnt,
|
|
const gp_Pnt& theP1,
|
|
const gp_Pnt& theP2,
|
|
const gp_Pnt& theP3,
|
|
const double theMinRad)
|
|
{
|
|
const double aRad = IntPatch_PointLine::CurvatureRadiusOfIntersLine(theS1, theS2, thePnt);
|
|
|
|
if (aRad > theMinRad)
|
|
{
|
|
return true;
|
|
}
|
|
else if (aRad > 0.0)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Curvature radius cannot be computed.
|
|
// Check smoothness of polygon.
|
|
|
|
// theP2
|
|
// *
|
|
// |
|
|
// |
|
|
// * o *
|
|
// theP1 O theP3
|
|
|
|
// Joining is enabled if two conditions are satisfied together:
|
|
// 1. Angle (theP1, theP2, theP3) is quite big;
|
|
// 2. Modulus of perpendicular (O->theP2) to the segment (theP1->theP3)
|
|
// is less than 0.01*<modulus of this segment>.
|
|
|
|
const gp_Vec aV12f(theP1, theP2), aV12l(theP2, theP3);
|
|
|
|
if (aV12f.Angle(aV12l) > IntPatch_WLineTool::myMaxConcatAngle)
|
|
return false;
|
|
|
|
const gp_Vec aV13(theP1, theP3);
|
|
const double aSq13 = aV13.SquareMagnitude();
|
|
|
|
return (aV12f.CrossSquareMagnitude(aV13) < 1.0e-4 * aSq13 * aSq13);
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : ExtendTwoWLFirstFirst
|
|
// purpose : Performs extending theWLine1 and theWLine2 through their
|
|
// respecting start point.
|
|
//=======================================================================
|
|
static void ExtendTwoWLFirstFirst(const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const occ::handle<IntPatch_WLine>& theWLine1,
|
|
const occ::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 double theToler3D,
|
|
const double* const theArrPeriods,
|
|
unsigned int& theCheckResult,
|
|
bool& 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;
|
|
|
|
double 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 int aNbPts = theWLine2->NbPnts();
|
|
for (int aNPt = 2; aNPt <= aNbPts; aNPt++)
|
|
{
|
|
const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
|
|
theWLine1->Curve()->InsertBefore(1, aPt);
|
|
}
|
|
|
|
for (int aNVtx = 1; aNVtx <= theWLine1->NbVertex(); aNVtx++)
|
|
{
|
|
IntPatch_Point& aVert = theWLine1->ChangeVertex(aNVtx);
|
|
const double aCurParam = aVert.ParameterOnLine();
|
|
aVert.SetParameter(aNbPts + aCurParam - 1);
|
|
}
|
|
|
|
for (int aNVtx = 1; aNVtx <= theWLine2->NbVertex(); aNVtx++)
|
|
{
|
|
IntPatch_Point& aVert = theWLine2->ChangeVertex(aNVtx);
|
|
const double aCurParam = aVert.ParameterOnLine();
|
|
aVert.SetParameter(aNbPts - aCurParam + 1);
|
|
theWLine1->AddVertex(aVert, true);
|
|
}
|
|
|
|
theHasBeenJoined = true;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : ExtendTwoWLFirstLast
|
|
// purpose : Performs extending theWLine1 through its start point and theWLine2
|
|
// through its end point.
|
|
//=======================================================================
|
|
static void ExtendTwoWLFirstLast(const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const occ::handle<IntPatch_WLine>& theWLine1,
|
|
const occ::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 double theToler3D,
|
|
const double* const theArrPeriods,
|
|
unsigned int& theCheckResult,
|
|
bool& 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;
|
|
|
|
double 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 int aNbPts = theWLine2->NbPnts();
|
|
for (int aNPt = aNbPts - 1; aNPt >= 1; aNPt--)
|
|
{
|
|
const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
|
|
theWLine1->Curve()->InsertBefore(1, aPt);
|
|
}
|
|
|
|
for (int aNVtx = 1; aNVtx <= theWLine1->NbVertex(); aNVtx++)
|
|
{
|
|
IntPatch_Point& aVert = theWLine1->ChangeVertex(aNVtx);
|
|
const double aCurParam = aVert.ParameterOnLine();
|
|
aVert.SetParameter(aNbPts + aCurParam - 1);
|
|
}
|
|
|
|
for (int aNVtx = theWLine2->NbVertex(); aNVtx >= 1; aNVtx--)
|
|
{
|
|
const IntPatch_Point& aVert = theWLine2->Vertex(aNVtx);
|
|
theWLine1->AddVertex(aVert, true);
|
|
}
|
|
|
|
theHasBeenJoined = true;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : ExtendTwoWLLastFirst
|
|
// purpose : Performs extending theWLine1 through its end point and theWLine2
|
|
// through its start point.
|
|
//=======================================================================
|
|
static void ExtendTwoWLLastFirst(const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const occ::handle<IntPatch_WLine>& theWLine1,
|
|
const occ::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 double theToler3D,
|
|
const double* const theArrPeriods,
|
|
unsigned int& theCheckResult,
|
|
bool& 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;
|
|
}
|
|
|
|
double 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 int aNbPts = theWLine1->NbPnts();
|
|
for (int aNPt = 2; aNPt <= theWLine2->NbPnts(); aNPt++)
|
|
{
|
|
const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
|
|
theWLine1->Curve()->Add(aPt);
|
|
}
|
|
|
|
for (int aNVtx = 1; aNVtx <= theWLine2->NbVertex(); aNVtx++)
|
|
{
|
|
IntPatch_Point& aVert = theWLine2->ChangeVertex(aNVtx);
|
|
const double aCurParam = aVert.ParameterOnLine();
|
|
aVert.SetParameter(aNbPts + aCurParam - 1);
|
|
theWLine1->AddVertex(aVert, false);
|
|
}
|
|
|
|
theHasBeenJoined = true;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
static void ExtendTwoWLLastLast(const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const occ::handle<IntPatch_WLine>& theWLine1,
|
|
const occ::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 double theToler3D,
|
|
const double* const theArrPeriods,
|
|
unsigned int& theCheckResult,
|
|
bool& 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;
|
|
|
|
double 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 int aNbPts = theWLine1->NbPnts() + theWLine2->NbPnts();
|
|
for (int aNPt = theWLine2->NbPnts() - 1; aNPt >= 1; aNPt--)
|
|
{
|
|
const IntSurf_PntOn2S& aPt = theWLine2->Point(aNPt);
|
|
theWLine1->Curve()->Add(aPt);
|
|
}
|
|
|
|
for (int aNVtx = theWLine2->NbVertex(); aNVtx >= 1; aNVtx--)
|
|
{
|
|
IntPatch_Point& aVert = theWLine2->ChangeVertex(aNVtx);
|
|
const double aCurParam = aVert.ParameterOnLine();
|
|
aVert.SetParameter(aNbPts - aCurParam);
|
|
theWLine1->AddVertex(aVert, false);
|
|
}
|
|
|
|
theHasBeenJoined = true;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
occ::handle<IntPatch_WLine> IntPatch_WLineTool::ComputePurgedWLine(
|
|
const occ::handle<IntPatch_WLine>& theWLine,
|
|
const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const occ::handle<Adaptor3d_TopolTool>& theDom1,
|
|
const occ::handle<Adaptor3d_TopolTool>& theDom2)
|
|
{
|
|
int i, k, v, nb, nbvtx;
|
|
occ::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;
|
|
}
|
|
|
|
occ::handle<IntPatch_WLine> aLocalWLine;
|
|
occ::handle<IntPatch_WLine> aTmpWLine = theWLine;
|
|
occ::handle<IntSurf_LineOn2S> aLineOn2S = new IntSurf_LineOn2S();
|
|
aLocalWLine = new IntPatch_WLine(aLineOn2S, false);
|
|
aLocalWLine->SetCreatingWayInfo(theWLine->GetCreatingWay());
|
|
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++)
|
|
{
|
|
int aStartIndex = i + 1;
|
|
int 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);
|
|
|
|
double UV[8];
|
|
p1.Parameters(UV[0], UV[1], UV[2], UV[3]);
|
|
p2.Parameters(UV[4], UV[5], UV[6], UV[7]);
|
|
|
|
double aMax = std::abs(UV[0]);
|
|
for (int anIdx = 1; anIdx < 8; anIdx++)
|
|
{
|
|
if (aMax < std::abs(UV[anIdx]))
|
|
aMax = std::abs(UV[anIdx]);
|
|
}
|
|
|
|
if (p1.Value().IsEqual(p2.Value(), gp::Resolution())
|
|
|| std::abs(UV[0] - UV[4]) + std::abs(UV[1] - UV[5]) < 1.0e-16 * aMax
|
|
|| std::abs(UV[2] - UV[6]) + std::abs(UV[3] - UV[7]) < 1.0e-16 * aMax)
|
|
{
|
|
aTmpWLine = aLocalWLine;
|
|
aLocalWLine = new IntPatch_WLine(aLineOn2S, false);
|
|
aLocalWLine->SetCreatingWayInfo(theWLine->GetCreatingWay());
|
|
|
|
for (v = 1; v <= aTmpWLine->NbVertex(); v++)
|
|
{
|
|
IntPatch_Point aVertex = aTmpWLine->Vertex(v);
|
|
int avertexindex = (int)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.
|
|
occ::handle<IntPatch_WLine> aLocalWLineTube = DeleteByTube(aLocalWLine, theS1, theS2);
|
|
|
|
if (aLocalWLineTube->NbPnts() > 1)
|
|
{
|
|
aResult = aLocalWLineTube;
|
|
}
|
|
return aResult;
|
|
}
|
|
|
|
//=================================================================================================
|
|
|
|
void IntPatch_WLineTool::JoinWLines(NCollection_Sequence<occ::handle<IntPatch_Line>>& theSlin,
|
|
NCollection_Sequence<IntPatch_Point>& theSPnt,
|
|
const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const double theTol3D)
|
|
{
|
|
if (theSlin.Length() == 0)
|
|
return;
|
|
|
|
// For two cylindrical surfaces only
|
|
const double aMinRad = 1.0e-3 * std::min(theS1->Cylinder().Radius(), theS2->Cylinder().Radius());
|
|
|
|
const double 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 double anArrFBonds[4] = {theS1->FirstUParameter(),
|
|
theS1->FirstVParameter(),
|
|
theS2->FirstUParameter(),
|
|
theS2->FirstVParameter()};
|
|
const double anArrLBonds[4] = {theS1->LastUParameter(),
|
|
theS1->LastVParameter(),
|
|
theS2->LastUParameter(),
|
|
theS2->LastVParameter()};
|
|
|
|
occ::handle<NCollection_IncAllocator> anAlloc = new NCollection_IncAllocator();
|
|
|
|
for (int aN1 = 1; aN1 <= theSlin.Length(); aN1++)
|
|
{
|
|
occ::handle<IntPatch_WLine> aWLine1(occ::down_cast<IntPatch_WLine>(theSlin.Value(aN1)));
|
|
|
|
if (aWLine1.IsNull())
|
|
{ // We must have failed to join not-point-lines
|
|
continue;
|
|
}
|
|
|
|
const int aNbPntsWL1 = aWLine1->NbPnts();
|
|
const IntSurf_PntOn2S& aPntFWL1 = aWLine1->Point(1);
|
|
const IntSurf_PntOn2S& aPntLWL1 = aWLine1->Point(aNbPntsWL1);
|
|
|
|
for (int 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(false);
|
|
NCollection_List<int> aListFC(anAlloc), aListLC(anAlloc);
|
|
|
|
bool isFirstConnected = false, isLastConnected = false;
|
|
|
|
for (int aN2 = 1; aN2 <= theSlin.Length(); aN2++)
|
|
{
|
|
if (aN2 == aN1)
|
|
continue;
|
|
|
|
occ::handle<IntPatch_WLine> aWLine2(occ::down_cast<IntPatch_WLine>(theSlin.Value(aN2)));
|
|
|
|
if (aWLine2.IsNull())
|
|
continue;
|
|
|
|
isFirstConnected = isLastConnected = false;
|
|
|
|
const int aNbPntsWL2 = aWLine2->NbPnts();
|
|
|
|
const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
|
|
const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aNbPntsWL2);
|
|
|
|
double aSqDistF = aPntFWL1.Value().SquareDistance(aPntFWL2.Value());
|
|
double aSqDistL = aPntFWL1.Value().SquareDistance(aPntLWL2.Value());
|
|
|
|
const double aSqMinFDist = std::min(aSqDistF, aSqDistL);
|
|
if (aSqMinFDist < Precision::SquareConfusion())
|
|
{
|
|
const bool 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 = true;
|
|
}
|
|
}
|
|
|
|
aSqDistF = aPntLWL1.Value().SquareDistance(aPntFWL2.Value());
|
|
aSqDistL = aPntLWL1.Value().SquareDistance(aPntLWL2.Value());
|
|
|
|
const double aSqMinLDist = std::min(aSqDistF, aSqDistL);
|
|
if (aSqMinLDist < Precision::SquareConfusion())
|
|
{
|
|
const bool 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 = 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 int anIndexWL2 = isFirstConnected ? aListFC.First() : aListLC.First();
|
|
occ::handle<IntPatch_WLine> aWLine2(occ::down_cast<IntPatch_WLine>(theSlin.Value(anIndexWL2)));
|
|
const int aNbPntsWL2 = aWLine2->NbPnts();
|
|
const IntSurf_PntOn2S& aPntFWL2 = aWLine2->Point(1);
|
|
const IntSurf_PntOn2S& aPntLWL2 = aWLine2->Point(aNbPntsWL2);
|
|
|
|
if (isFirstConnected)
|
|
{
|
|
const double aSqDistF = aPntFWL1.Value().SquareDistance(aPntFWL2.Value());
|
|
const double aSqDistL = aPntFWL1.Value().SquareDistance(aPntLWL2.Value());
|
|
const bool isFM = (aSqDistF < aSqDistL);
|
|
|
|
const IntSurf_PntOn2S& aPt1 = aWLine1->Point(2);
|
|
const IntSurf_PntOn2S& aPt2 = isFM ? aWLine2->Point(2) : aWLine2->Point(aNbPntsWL2 - 1);
|
|
|
|
if (!CheckArgumentsToJoin(theS1,
|
|
theS2,
|
|
aPntFWL1,
|
|
aPt1.Value(),
|
|
aPntFWL1.Value(),
|
|
aPt2.Value(),
|
|
aMinRad))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
aWLine1->ClearVertexes();
|
|
|
|
if (isFM)
|
|
{
|
|
// First-First-connection
|
|
for (int aNPt = 1; aNPt <= aNbPntsWL2; aNPt++)
|
|
{
|
|
const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
|
|
aWLine1->Curve()->InsertBefore(1, aPt);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// First-Last-connection
|
|
for (int aNPt = aNbPntsWL2; aNPt >= 1; aNPt--)
|
|
{
|
|
const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
|
|
aWLine1->Curve()->InsertBefore(1, aPt);
|
|
}
|
|
}
|
|
}
|
|
else // if (isLastConnected)
|
|
{
|
|
const double aSqDistF = aPntLWL1.Value().SquareDistance(aPntFWL2.Value());
|
|
const double aSqDistL = aPntLWL1.Value().SquareDistance(aPntLWL2.Value());
|
|
|
|
const bool isFM = (aSqDistF < aSqDistL);
|
|
const IntSurf_PntOn2S& aPt1 = aWLine1->Point(aNbPntsWL1 - 1);
|
|
const IntSurf_PntOn2S& aPt2 = isFM ? aWLine2->Point(2) : aWLine2->Point(aNbPntsWL2 - 1);
|
|
|
|
if (!CheckArgumentsToJoin(theS1,
|
|
theS2,
|
|
aPntLWL1,
|
|
aPt1.Value(),
|
|
aPntLWL1.Value(),
|
|
aPt2.Value(),
|
|
aMinRad))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
aWLine1->ClearVertexes();
|
|
|
|
if (isFM)
|
|
{
|
|
// Last-First connection
|
|
for (int aNPt = 1; aNPt <= aNbPntsWL2; aNPt++)
|
|
{
|
|
const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
|
|
aWLine1->Curve()->Add(aPt);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Last-Last connection
|
|
for (int aNPt = aNbPntsWL2; aNPt >= 1; aNPt--)
|
|
{
|
|
const IntSurf_PntOn2S& aPt = aWLine2->Point(aNPt);
|
|
aWLine1->Curve()->Add(aPt);
|
|
}
|
|
}
|
|
}
|
|
|
|
aWLine1->ComputeVertexParameters(theTol3D);
|
|
theSlin.Remove(anIndexWL2);
|
|
aN1--;
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : IsNeedSkipWL
|
|
// purpose : Detect is WLine need to skip.
|
|
//=======================================================================
|
|
static bool IsNeedSkipWL(const occ::handle<IntPatch_WLine>& theWL,
|
|
const Bnd_Box2d& theBoxS1,
|
|
const Bnd_Box2d& theBoxS2,
|
|
const double* const theArrPeriods)
|
|
{
|
|
double aFirstp, aLastp;
|
|
int aNbVtx = theWL->NbVertex();
|
|
|
|
for (int i = 1; i < aNbVtx; i++)
|
|
{
|
|
aFirstp = theWL->Vertex(i).ParameterOnLine();
|
|
aLastp = theWL->Vertex(i + 1).ParameterOnLine();
|
|
|
|
double aU1, aV1, aU2, aV2;
|
|
const int pmid = (int)((aFirstp + aLastp) / 2);
|
|
const IntSurf_PntOn2S& aPmid = theWL->Point(pmid);
|
|
aPmid.Parameters(aU1, aV1, aU2, aV2);
|
|
|
|
if (IsOutOfDomain(theBoxS1, theBoxS2, aPmid, theArrPeriods))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//=======================================================================
|
|
// function : ExtendTwoWLines
|
|
// purpose : Performs extending theWLine1 and theWLine2 through their
|
|
// respecting end point.
|
|
//=======================================================================
|
|
void IntPatch_WLineTool::ExtendTwoWLines(NCollection_Sequence<occ::handle<IntPatch_Line>>& theSlin,
|
|
const occ::handle<Adaptor3d_Surface>& theS1,
|
|
const occ::handle<Adaptor3d_Surface>& theS2,
|
|
const double theToler3D,
|
|
const double* const theArrPeriods,
|
|
const Bnd_Box2d& theBoxS1,
|
|
const Bnd_Box2d& theBoxS2,
|
|
const NCollection_List<gp_Pnt>& theListOfCriticalPoints)
|
|
{
|
|
if (theSlin.Length() < 2)
|
|
return;
|
|
|
|
gp_Vec aVec1, aVec2, aVec3;
|
|
|
|
unsigned int hasBeenJoinedCounter = 0;
|
|
|
|
for (int aNumOfLine1 = 1; aNumOfLine1 <= theSlin.Length(); aNumOfLine1++)
|
|
{
|
|
if (hasBeenJoinedCounter > 0)
|
|
{
|
|
aNumOfLine1--;
|
|
}
|
|
|
|
hasBeenJoinedCounter = 0;
|
|
|
|
occ::handle<IntPatch_WLine> aWLine1(occ::down_cast<IntPatch_WLine>(theSlin.Value(aNumOfLine1)));
|
|
|
|
if (aWLine1.IsNull())
|
|
{ // We must have failed to join not-point-lines
|
|
continue;
|
|
}
|
|
|
|
const int 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);
|
|
|
|
if (IsNeedSkipWL(aWLine1, theBoxS1, theBoxS2, theArrPeriods))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Enable/Disable of some check. 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 (int aNumOfLine2 = aNumOfLine1 + 1; aNumOfLine2 <= theSlin.Length(); aNumOfLine2++)
|
|
{
|
|
occ::handle<IntPatch_WLine> aWLine2(
|
|
occ::down_cast<IntPatch_WLine>(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, Precision::PConfusion()))
|
|
&& !(aPntFWL1.IsSame(aPntLWL2, theToler3D, Precision::PConfusion())))
|
|
{
|
|
if (aPntFWL1.IsSame(aPntFWL2, theToler3D) || aPntFWL1.IsSame(aPntLWL2, theToler3D))
|
|
{
|
|
aCheckResult |= IntPatchWT_DisFirstFirst | IntPatchWT_DisFirstLast;
|
|
}
|
|
}
|
|
|
|
if (!(aPntLWL1.IsSame(aPntFWL2, theToler3D, Precision::PConfusion()))
|
|
&& !(aPntLWL1.IsSame(aPntLWL2, theToler3D, Precision::PConfusion())))
|
|
{
|
|
if (aPntLWL1.IsSame(aPntFWL2, theToler3D) || aPntLWL1.IsSame(aPntLWL2, theToler3D))
|
|
{
|
|
aCheckResult |= IntPatchWT_DisLastFirst | IntPatchWT_DisLastLast;
|
|
}
|
|
}
|
|
|
|
if (!theListOfCriticalPoints.IsEmpty())
|
|
{
|
|
for (NCollection_List<gp_Pnt>::Iterator anItr(theListOfCriticalPoints); anItr.More();
|
|
anItr.Next())
|
|
{
|
|
const gp_Pnt& aPt = anItr.Value();
|
|
if (!(aCheckResult & (IntPatchWT_DisFirstFirst | IntPatchWT_DisFirstLast)))
|
|
{
|
|
if (aPt.SquareDistance(aPntFWL1.Value()) < Precision::Confusion())
|
|
{
|
|
aCheckResult |= IntPatchWT_DisFirstFirst | IntPatchWT_DisFirstLast;
|
|
}
|
|
}
|
|
|
|
if (!(aCheckResult & (IntPatchWT_DisLastFirst | IntPatchWT_DisLastLast)))
|
|
{
|
|
if (aPt.SquareDistance(aPntLWL1.Value()) < Precision::Confusion())
|
|
{
|
|
aCheckResult |= IntPatchWT_DisLastFirst | IntPatchWT_DisLastLast;
|
|
}
|
|
}
|
|
|
|
if (!(aCheckResult & (IntPatchWT_DisFirstFirst | IntPatchWT_DisLastFirst)))
|
|
{
|
|
if (aPt.SquareDistance(aPntFWL2.Value()) < Precision::Confusion())
|
|
{
|
|
aCheckResult |= IntPatchWT_DisFirstFirst | IntPatchWT_DisLastFirst;
|
|
}
|
|
}
|
|
|
|
if (!(aCheckResult & (IntPatchWT_DisFirstLast | IntPatchWT_DisLastLast)))
|
|
{
|
|
if (aPt.SquareDistance(aPntLWL2.Value()) < Precision::Confusion())
|
|
{
|
|
aCheckResult |= IntPatchWT_DisFirstLast | IntPatchWT_DisLastLast;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (aCheckResult
|
|
== (IntPatchWT_DisFirstFirst | IntPatchWT_DisFirstLast | IntPatchWT_DisLastFirst
|
|
| IntPatchWT_DisLastLast))
|
|
continue;
|
|
|
|
for (int aNumOfLine2 = aNumOfLine1 + 1; aNumOfLine2 <= theSlin.Length(); aNumOfLine2++)
|
|
{
|
|
occ::handle<IntPatch_WLine> aWLine2(
|
|
occ::down_cast<IntPatch_WLine>(theSlin.Value(aNumOfLine2)));
|
|
|
|
if (aWLine2.IsNull())
|
|
continue;
|
|
|
|
if (aWLine2->Vertex(1).ParameterOnLine() != 1)
|
|
continue;
|
|
|
|
if (aWLine2->Vertex(aWLine2->NbVertex()).ParameterOnLine() != aWLine2->NbPnts())
|
|
continue;
|
|
|
|
bool hasBeenJoined = false;
|
|
|
|
const int 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 (IsNeedSkipWL(aWLine2, theBoxS1, theBoxS2, theArrPeriods))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
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)
|
|
{
|
|
hasBeenJoinedCounter++;
|
|
theSlin.Remove(aNumOfLine2);
|
|
aNumOfLine2--;
|
|
}
|
|
}
|
|
}
|
|
}
|