1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00
occt/src/IntTools/IntTools_EdgeEdge.cxx
emv ce544c1225 0024696: Lower performance of the new Edge/Edge intersection algorithm
Performance improvements in IntTools_EdgeEdge algorithm:
1. Added check for common box between edges: if common box between edges is thin,
   find exact solutions at once, without looking for rough ranges first;
2. Improved methods IntTools_EdgeEdge::FindBestSolution() and
   IntTools_EdgeEdge::CheckCoincidence(...) by using method SplitRangeOnSegments
   with resolution of the curve as a criteria for size of the ranges.

Test cases for issue CR24696
2014-03-25 17:00:51 +04:00

1292 lines
37 KiB
C++

// Created by: Eugeny MALTCHIKOV
// Copyright (c) 2013-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 <IntTools_EdgeEdge.ixx>
#include <NCollection_UBTreeFiller.hxx>
#include <gp_Dir.hxx>
#include <gp_Lin.hxx>
#include <ElCLib.hxx>
#include <TopoDS_Iterator.hxx>
#include <Bnd_Box.hxx>
#include <BndLib_Add3dCurve.hxx>
#include <GeomAPI_ProjectPointOnCurve.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BOPCol_MapOfInteger.hxx>
#include <BOPCol_BoxBndTree.hxx>
#include <IntTools_Tools.hxx>
#include <IntTools_CommonPrt.hxx>
static
Standard_Boolean BndCommon(const Bnd_Box& theB1,
const Bnd_Box& theB2,
Bnd_Box& theBOut);
static
void BndBuildBox(const BRepAdaptor_Curve& theBAC,
const Standard_Real aT1,
const Standard_Real aT2,
const Standard_Real theTol,
Bnd_Box& theBox);
static
Standard_Boolean SplitRangeOnSegments(const Standard_Real aT1,
const Standard_Real aT2,
const Standard_Real theResolution,
const Standard_Integer theNbSeg,
IntTools_SequenceOfRanges& theSegments);
static
void SplitRangeOnTwo(const Standard_Real aT1,
const Standard_Real aT2,
IntTools_SequenceOfRanges& theSegments);
static
Standard_Integer DistPC(const Standard_Real aT1,
const Handle(Geom_Curve)& theC1,
const Standard_Real theCriteria,
GeomAPI_ProjectPointOnCurve& theProjector,
Standard_Real& aD,
Standard_Real& aT2,
const Standard_Integer iC = 1);
static
Standard_Integer DistPC(const Standard_Real aT1,
const Handle(Geom_Curve)& theC1,
const Standard_Real theCriteria,
GeomAPI_ProjectPointOnCurve& theProjector,
Standard_Real& aD,
Standard_Real& aT2,
Standard_Real& aDmax,
Standard_Real& aT1max,
Standard_Real& aT2max,
const Standard_Integer iC = 1);
static
Standard_Integer FindDistPC(const Standard_Real aT1A,
const Standard_Real aT1B,
const Handle(Geom_Curve)& theC1,
const Standard_Real theCriteria,
const Standard_Real theEps,
GeomAPI_ProjectPointOnCurve& theProjector,
Standard_Real& aDmax,
Standard_Real& aT1max,
Standard_Real& aT2max,
const Standard_Boolean bMaxDist = Standard_True);
static
Standard_Integer TypeToInteger(const GeomAbs_CurveType theCType);
//=======================================================================
//function : Prepare
//purpose :
//=======================================================================
void IntTools_EdgeEdge::Prepare()
{
GeomAbs_CurveType aCT1, aCT2;
Standard_Integer iCT1, iCT2;
//
myCurve1.Initialize(myEdge1);
myCurve2.Initialize(myEdge2);
//
if (myRange1.First() == 0. && myRange1.Last() == 0.) {
myRange1.SetFirst(myCurve1.FirstParameter());
myRange1.SetLast (myCurve1.LastParameter());
}
//
if (myRange2.First() == 0. && myRange2.Last() == 0.) {
myRange2.SetFirst(myCurve2.FirstParameter());
myRange2.SetLast (myCurve2.LastParameter());
}
//
aCT1 = myCurve1.GetType();
aCT2 = myCurve2.GetType();
//
iCT1 = TypeToInteger(aCT1);
iCT2 = TypeToInteger(aCT2);
//
if (iCT1 == iCT2) {
if (iCT1 != 0) {
//compute deflection
Standard_Integer i;
Standard_Real aDt, aT, aT1, aT2;
gp_Vec aV1, aV2;
gp_Pnt aP;
//
Standard_Real aC1(0.), aC2(0.);
for (i = 0; i < 2; ++i) {
Standard_Real &aC = !i ? aC1 : aC2;
IntTools_Range aR = !i ? myRange1 : myRange2;
const BRepAdaptor_Curve& aBAC = !i ? myCurve1 : myCurve2;
aR.Range(aT1, aT2);
aDt = (aT2 - aT1) / 10.;
aT = aT1;
aBAC.D1(aT, aP, aV1);
while (aT < aT2) {
aT += aDt;
aBAC.D1(aT, aP, aV2);
if (aV1.Magnitude() > gp::Resolution() &&
aV2.Magnitude() > gp::Resolution()) {
gp_Dir aD1(aV1), aD2(aV2);
aC += aD1.Angle(aD2);
}
aV1 = aV2;
}
}
//
if (aC1 < aC2) {
--iCT1;
}
}
}
//
if (iCT1 < iCT2) {
TopoDS_Edge tmpE = myEdge1;
myEdge1 = myEdge2;
myEdge2 = tmpE;
//
BRepAdaptor_Curve tmpC = myCurve1;
myCurve1 = myCurve2;
myCurve2 = tmpC;
//
IntTools_Range tmpR = myRange1;
myRange1 = myRange2;
myRange2 = tmpR;
//
mySwap = Standard_True;
}
//
myTol1 = myCurve1.Tolerance();
myTol2 = myCurve2.Tolerance();
myTol = myTol1 + myTol2;
//
myRes1 = myCurve1.Resolution(myTol);
myRes2 = myCurve2.Resolution(myTol);
//
if (iCT1 != 0 || iCT2 != 0) {
Standard_Real f, l;
myGeom1 = BRep_Tool::Curve(myEdge1, f, l);
myGeom2 = BRep_Tool::Curve(myEdge2, f, l);
}
}
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
void IntTools_EdgeEdge::Perform()
{
//1. Check data
CheckData();
if (myErrorStatus) {
return;
}
//
//2. Prepare Data
Prepare();
//
//3.1. Check Line/Line case
if (myCurve1.GetType() == GeomAbs_Line &&
myCurve2.GetType() == GeomAbs_Line) {
ComputeLineLine();
return;
}
//
//3.2. Find solutions
IntTools_SequenceOfRanges aRanges1, aRanges2;
//
FindSolutions(aRanges1, aRanges2);
//
//4. Merge solutions and save common parts
MergeSolutions(aRanges1, aRanges2);
}
//=======================================================================
//function : FindSolutions
//purpose :
//=======================================================================
void IntTools_EdgeEdge::FindSolutions(IntTools_SequenceOfRanges& theRanges1,
IntTools_SequenceOfRanges& theRanges2)
{
// According to the common box of the edges decide which method to use
Standard_Real aT11, aT12, aT21, aT22;
Bnd_Box aB1, aB2, aBC;
//
myRange1.Range(aT11, aT12);
myRange2.Range(aT21, aT22);
//
BndBuildBox(myCurve1, aT11, aT12, myTol1, aB1);
BndBuildBox(myCurve2, aT21, aT22, myTol2, aB2);
//
if (!BndCommon(aB1, aB2, aBC)) {
// No intersections at all
return;
}
//
if (aBC.IsThin(10*myTol)) {
// As soon as the common box of the edges is thin,
// find exact solution at once
FindSolutions(myRange1, myRange2, aBC, theRanges1, theRanges2);
}
else {
// First find the rough ranges containing solutions,
// than find exact ranges
IntTools_SequenceOfRanges aSegments1;
Standard_Integer i, aNb;
//
// Find rough ranges
FindRoughRanges(myRange1, myRange2, aSegments1);
aNb = aSegments1.Length();
// Find exact ranges
for (i = 1; i <= aNb; ++i) {
const IntTools_Range& aR1 = aSegments1(i);
aR1.Range(aT11, aT12);
BndBuildBox(myCurve1, aT11, aT12, myTol1, aB1);
if (BndCommon(aB1, aB2, aBC)) {
FindSolutions(aR1, myRange2, aBC, theRanges1, theRanges2);
}
}
}
}
//=======================================================================
//function : FindSolutions
//purpose :
//=======================================================================
void IntTools_EdgeEdge::FindSolutions(const IntTools_Range& theR1,
const IntTools_Range& theR2,
const Bnd_Box& theBC,
IntTools_SequenceOfRanges& theRanges1,
IntTools_SequenceOfRanges& theRanges2)
{
Standard_Boolean bOut, bStop, bThin;
Standard_Real aT11, aT12, aT21, aT22;
Standard_Real aTB11, aTB12, aTB21, aTB22;
Standard_Real aTol, aSmallStep1, aSmallStep2;
Standard_Integer iCom;
Bnd_Box aB1, aB2;
//
theR1.Range(aT11, aT12);
theR2.Range(aT21, aT22);
aB1 = theBC;
//
bOut = Standard_False;
bThin = Standard_False;
bStop = Standard_False;
aTol = 2*myTol;
iCom = 1;
//
do {
bOut = !FindParameters(myCurve2, aT21, aT22, myRes2, aB1, aTB21, aTB22);
if (bOut) {
break;
}
//
bThin = (aTB22 - aTB21) < myRes2;
if (bThin) {
bOut = !FindParameters(myCurve1, aT11, aT12, myRes1, aB1, aTB11, aTB12);
break;
}
//
BndBuildBox(myCurve2, aTB21, aTB22, myTol2, aB2);
BndCommon(aB1, aB2, aB2);
//
bOut = !FindParameters(myCurve1, aT11, aT12, myRes1, aB2, aTB11, aTB12);
if (bOut) {
break;
}
//
bThin = ((aTB12 - aTB11) < myRes1) ||
(aB2.IsXThin(aTol) && aB2.IsYThin(aTol) && aB2.IsZThin(aTol));
//
if (!bThin) {
aSmallStep1 = (aT12 - aT11) / 250.;
aSmallStep2 = (aT22 - aT21) / 250.;
//
if (aSmallStep1 < myRes1) {
aSmallStep1 = myRes1;
}
if (aSmallStep2 < myRes2) {
aSmallStep2 = myRes2;
}
//
if (((aTB11 - aT11) < aSmallStep1) && ((aT12 - aTB12) < aSmallStep1) &&
((aTB21 - aT21) < aSmallStep2) && ((aT22 - aTB22) < aSmallStep2)) {
bStop = Standard_True;
} else {
BndBuildBox(myCurve1, aTB11, aTB12, myTol1, aB1);
bOut = !BndCommon(aB1, aB2, aB1);
if (bOut) {
break;
}
}
}
//
aT11 = aTB11;
aT12 = aTB12;
aT21 = aTB21;
aT22 = aTB22;
} while (!bThin && !bStop);
//
if (bOut) {
//no intersection;
return;
}
//
if (!bThin) {
//check curves for coincidence on the ranges
iCom = CheckCoincidence(aT11, aT12, aT21, aT22, myTol, myRes1);
if (!iCom) {
bThin = Standard_True;
}
}
//
if (bThin) {
if (iCom != 0) {
//check intermediate points
Standard_Real aT1, aT2, aDist;
gp_Pnt aP1, aP2;
//
aT1 = IntTools_Tools::IntermediatePoint(aT11, aT12);
aT2 = IntTools_Tools::IntermediatePoint(aT21, aT22);
//
aP1 = myGeom1->Value(aT1);
aP2 = myGeom2->Value(aT2);
//
aDist = aP1.Distance(aP2);
if (aDist > myTol) {
return;
}
}
//add common part
IntTools_Range aR1(aT11, aT12), aR2(aT21, aT22);
//
theRanges1.Append(aR1);
theRanges2.Append(aR2);
return;
}
//
if (!IsIntersection(aT11, aT12, aT21, aT22)) {
return;
}
//
//split ranges on segments and repeat
Standard_Integer i, aNb1;
IntTools_SequenceOfRanges aSegments1;
//
IntTools_Range aR2(aT21, aT22);
BndBuildBox(myCurve2, aT21, aT22, myTol2, aB2);
//
SplitRangeOnSegments(aT11, aT12, myRes1, 3, aSegments1);
aNb1 = aSegments1.Length();
for (i = 1; i <= aNb1; ++i) {
const IntTools_Range& aR1 = aSegments1(i);
aR1.Range(aT11, aT12);
BndBuildBox(myCurve1, aT11, aT12, myTol1, aB1);
if (BndCommon(aB1, aB2, aB1)) {
FindSolutions(aR1, aR2, aB1, theRanges1, theRanges2);
}
}
}
//=======================================================================
//function : FindParameters
//purpose :
//=======================================================================
Standard_Boolean IntTools_EdgeEdge::FindParameters(const BRepAdaptor_Curve& theBAC,
const Standard_Real aT1,
const Standard_Real aT2,
const Standard_Real theRes,
const Bnd_Box& theCBox,
Standard_Real& aTB1,
Standard_Real& aTB2)
{
Standard_Boolean bRet;
Standard_Integer aC, i, k;
Standard_Real aCf, aDiff, aDt, aT, aTB, aTOut, aTIn, aPTol, aTol,
aDist, aDistP;
gp_Pnt aP;
Bnd_Box aCBx;
//
bRet = Standard_False;
aCf = 0.6180339887498948482045868343656;// =0.5*(1.+sqrt(5.))/2.;
aDt = theRes;
aPTol = theRes * 0.001;
aTol = theBAC.Tolerance();
aDistP = 0.;
aCBx = theCBox;
aCBx.Enlarge(aTol);
//
for (i = 0; i < 2; ++i) {
aTB = !i ? aT1 : aT2;
aT = !i ? aT2 : aTB1;
aC = !i ? 1 : -1;
bRet = Standard_False;
k = 0;
//looking for the point on the edge which is in the box;
while (aC*(aT-aTB) >= 0) {
aP = theBAC.Value(aTB);
Bnd_Box aBP;
aBP.Add(aP);
aDist = aBP.Distance(theCBox);
k = (fabs(aDist - aDistP) < Precision::PConfusion()) ? k+1 : 0;
if (aDist > aTol) {
aDt = theBAC.Resolution(aDist*Max(k, 1));
aTB += aC*aDt;
} else {
bRet = Standard_True;
break;
}
aDistP = aDist;
}
//
if (!bRet) {
if (!i) {
//edge is out of the box;
return bRet;
} else {
bRet = !bRet;
aTB = aTB1;
aDt = aT2 - aTB1;
}
}
//
aT = !i ? aT1 : aT2;
if (aTB != aT) {
//one point IN, one point OUT; looking for the bounding point;
aTIn = aTB;
aTOut = aTB - aC*aDt;
aDiff = aTIn - aTOut;
while (fabs(aDiff) > aPTol) {
aTB = aTOut + aDiff*aCf;
aP = theBAC.Value(aTB);
if (aCBx.IsOut(aP)) {
aTOut = aTB;
} else {
aTIn = aTB;
}
aDiff = aTIn - aTOut;
}
}
if (!i) {
aTB1 = aTB;
} else {
aTB2 = aTB;
}
}
return bRet;
}
//=======================================================================
//function : MergeSolutions
//purpose :
//=======================================================================
void IntTools_EdgeEdge::MergeSolutions(const IntTools_SequenceOfRanges& theRanges1,
const IntTools_SequenceOfRanges& theRanges2)
{
IntTools_Range aRi1, aRi2, aRj1, aRj2;
Standard_Integer aNbCP, i, j;
TopAbs_ShapeEnum aType;
Standard_Real aTi11, aTi12, aTi21, aTi22,
aTj11, aTj12, aTj21, aTj22;
//
aNbCP = theRanges1.Length();
aType = TopAbs_VERTEX;
//
for (i = 1; i <= aNbCP; ) {
aRi1 = theRanges1(i);
aRi2 = theRanges2(i);
//
aRi1.Range(aTi11, aTi12);
aRi2.Range(aTi21, aTi22);
//
for (j = i+1; j <= aNbCP; ++j) {
aRj1 = theRanges1(j);
aRj2 = theRanges2(j);
//
aRj1.Range(aTj11, aTj12);
aRj2.Range(aTj21, aTj22);
if (fabs(aTi12 - aTj11) < 10*myRes1 ||
fabs(aTi22 - aTj21) < 10*myRes2) {
aTi11 = Min(aTi11, aTj11);
aTi12 = Max(aTi12, aTj12);
aTi21 = Min(aTi21, aTj21);
aTi22 = Max(aTi22, aTj22);
} else {
break;
}
}
i = j;
//
if (aTi11 == myRange1.First() && aTi12 == myRange1.Last() &&
aTi21 == myRange2.First() && aTi22 == myRange2.Last()) {
aType = TopAbs_EDGE;
}
//
AddSolution(aTi11, aTi12, aTi21, aTi22, aType);
}
}
//=======================================================================
//function : AddSolution
//purpose :
//=======================================================================
void IntTools_EdgeEdge::AddSolution(const Standard_Real aT11,
const Standard_Real aT12,
const Standard_Real aT21,
const Standard_Real aT22,
const TopAbs_ShapeEnum theType)
{
IntTools_CommonPrt aCPart;
//
aCPart.SetType(theType);
if (!mySwap) {
aCPart.SetEdge1(myEdge1);
aCPart.SetEdge2(myEdge2);
aCPart.SetRange1(aT11, aT12);
aCPart.AppendRange2(aT21, aT22);
} else {
aCPart.SetEdge1(myEdge2);
aCPart.SetEdge2(myEdge1);
aCPart.SetRange1(aT21, aT22);
aCPart.AppendRange2(aT11, aT12);
}
//
if (theType == TopAbs_VERTEX) {
Standard_Real aT1, aT2;
//
FindBestSolution(aT11, aT12, aT21, aT22, aT1, aT2);
//
if (!mySwap) {
aCPart.SetVertexParameter1(aT1);
aCPart.SetVertexParameter2(aT2);
} else {
aCPart.SetVertexParameter1(aT2);
aCPart.SetVertexParameter2(aT1);
}
}
myCommonParts.Append(aCPart);
}
//=======================================================================
//function : FindBestSolution
//purpose :
//=======================================================================
void IntTools_EdgeEdge::FindBestSolution(const Standard_Real aT11,
const Standard_Real aT12,
const Standard_Real aT21,
const Standard_Real aT22,
Standard_Real& aT1,
Standard_Real& aT2)
{
Standard_Integer i, aNbS, iErr;
Standard_Real aDMin, aD, aCrit, aMinStep, aTMax;
Standard_Real aT1x, aT2x, aT1p, aT2p;
GeomAPI_ProjectPointOnCurve aProj;
IntTools_SequenceOfRanges aSeg1;
//
aT1 = IntTools_Tools::IntermediatePoint(aT11, aT12);
aT2 = IntTools_Tools::IntermediatePoint(aT21, aT22);
//
aDMin = 100.;
aD = 100.;
aCrit = 1.e-16;
aMinStep = 5.e-13;
aTMax = Max(fabs(aT11), fabs(aT12));
if (aTMax > 999.) {
aMinStep = 5.e-16 * aTMax;
}
//
aNbS = 10;
SplitRangeOnSegments(aT11, aT12, 3*myRes1, aNbS, aSeg1);
aNbS = aSeg1.Length();
//
aProj.Init(myGeom2, aT21, aT22);
for (i = 1; i <= aNbS; ++i) {
const IntTools_Range& aR1 = aSeg1(i);
aR1.Range(aT1x, aT2x);
//
iErr = FindDistPC(aT1x, aT2x, myGeom1, aCrit, aMinStep,
aProj, aD, aT1p, aT2p, Standard_False);
if (iErr != 1 && aD < aDMin) {
aT1 = aT1p;
aT2 = aT2p;
aDMin = aD;
if (aDMin < aCrit) {
break;
}
}
}
}
//=======================================================================
//function : ComputeLineLine
//purpose :
//=======================================================================
void IntTools_EdgeEdge::ComputeLineLine()
{
Standard_Boolean IsParallel, IsCoincide;
Standard_Real aSin, aCos, aAng, aTol;
Standard_Real aT1, aT2, aT11, aT12, aT21, aT22;
gp_Pnt aP11, aP12;
gp_Lin aL1, aL2;
gp_Dir aD1, aD2;
IntTools_CommonPrt aCommonPrt;
//
IsParallel = Standard_False;
IsCoincide = Standard_False;
aTol = myTol*myTol;
aL1 = myCurve1.Line();
aL2 = myCurve2.Line();
aD1 = aL1.Position().Direction();
aD2 = aL2.Position().Direction();
myRange1.Range(aT11, aT12);
myRange2.Range(aT21, aT22);
//
aCommonPrt.SetEdge1(myEdge1);
aCommonPrt.SetEdge2(myEdge2);
//
aCos = aD1.Dot(aD2);
aAng = (aCos >= 0.) ? 2.*(1. - aCos) : 2.*(1. + aCos);
//
if(aAng <= Precision::Angular()) {
IsParallel = Standard_True;
if(aL1.SquareDistance(aL2.Location()) <= aTol) {
IsCoincide = Standard_True;
aP11 = ElCLib::Value(aT11, aL1);
aP12 = ElCLib::Value(aT12, aL1);
}
}
else {
aP11 = ElCLib::Value(aT11, aL1);
aP12 = ElCLib::Value(aT12, aL1);
if(aL2.SquareDistance(aP11) <= aTol && aL2.SquareDistance(aP12) <= aTol) {
IsCoincide = Standard_True;
}
}
//
if (IsCoincide) {
Standard_Real t21, t22;
//
t21 = ElCLib::Parameter(aL2, aP11);
t22 = ElCLib::Parameter(aL2, aP12);
if((t21 > aT22 && t22 > aT22) || (t21 < aT21 && t22 < aT21)) {
return;
}
//
Standard_Real temp;
if(t21 > t22) {
temp = t21;
t21 = t22;
t22 = temp;
}
//
if(t21 >= aT21) {
if(t22 <= aT22) {
aCommonPrt.SetRange1(aT11, aT12);
aCommonPrt.SetAllNullFlag(Standard_True);
aCommonPrt.AppendRange2(t21, t22);
}
else {
aCommonPrt.SetRange1(aT11, aT12 - (t22 - aT22));
aCommonPrt.AppendRange2(t21, aT22);
}
}
else {
aCommonPrt.SetRange1(aT11 + (aT21 - t21), aT12);
aCommonPrt.AppendRange2(aT21, t22);
}
aCommonPrt.SetType(TopAbs_EDGE);
myCommonParts.Append(aCommonPrt);
return;
}
//
if (IsParallel) {
return;
}
//
{
TopoDS_Iterator aIt1, aIt2;
aIt1.Initialize(myEdge1);
for (; aIt1.More(); aIt1.Next()) {
const TopoDS_Shape& aV1 = aIt1.Value();
aIt2.Initialize(myEdge2);
for (; aIt2.More(); aIt2.Next()) {
const TopoDS_Shape& aV2 = aIt2.Value();
if (aV2.IsSame(aV1)) {
return;
}
}
}
}
//
aSin = 1. - aCos*aCos;
gp_Pnt O1 = aL1.Location();
gp_Pnt O2 = aL2.Location();
gp_Vec O1O2 (O1, O2);
//
aT2 = (aD1.XYZ()*(O1O2.Dot(aD1))-(O1O2.XYZ())).Dot(aD2.XYZ());
aT2 /= aSin;
//
if(aT2 < aT21 || aT2 > aT22) {
return;
}
//
gp_Pnt aP2(ElCLib::Value(aT2, aL2));
aT1 = (gp_Vec(O1, aP2)).Dot(aD1);
//
if(aT1 < aT11 || aT1 > aT12) {
return;
}
//
gp_Pnt aP1(ElCLib::Value(aT1, aL1));
Standard_Real aDist = aP1.SquareDistance(aP2);
//
if (aDist > aTol) {
return;
}
//
aCommonPrt.SetRange1(aT1 - myTol, aT1 + myTol);
aCommonPrt.AppendRange2(aT2 - myTol, aT2 + myTol);
aCommonPrt.SetType(TopAbs_VERTEX);
aCommonPrt.SetVertexParameter1(aT1);
aCommonPrt.SetVertexParameter2(aT2);
myCommonParts.Append(aCommonPrt);
}
//=======================================================================
//function : FindRoughRanges
//purpose :
//=======================================================================
Standard_Integer IntTools_EdgeEdge::FindRoughRanges(const IntTools_Range& theR1,
const IntTools_Range& theR2,
IntTools_SequenceOfRanges& theSegments1)
{
Standard_Integer iRet, i, j, aNbi, aNbj, aNbSD;
Standard_Real aTi1, aTi2, aTj1, aTj2, aDi, aDj;
IntTools_SequenceOfRanges aSi, aSj, aNewSi, aNewSj;
BOPCol_MapOfInteger aMj;
BOPCol_ListIteratorOfListOfInteger aItLI;
Bnd_Box aBi, aBj;
BOPCol_BoxBndTreeSelector aSelector;
BOPCol_BoxBndTree aBBTree;
NCollection_UBTreeFiller <Standard_Integer, Bnd_Box> aTreeFiller(aBBTree);
//
theR1.Range(aTi1, aTi2);
theR2.Range(aTj1, aTj2);
aDi = (aTi2 - aTi1) / 2.;
aDj = (aTj2 - aTj1) / 2.;
aNbi = 2;
aNbj = 2;
//
SplitRangeOnTwo(aTi1, aTi2, aSi);
SplitRangeOnTwo(aTj1, aTj2, aSj);
//
while (aDi > myRes1 || aDj > myRes2) {
aDi /= 2.;
aDj /= 2.;
//
aBBTree.Clear();
aTreeFiller.Reset();
for (j = 1; j <= aNbj; ++j) {
const IntTools_Range& aRj = aSj(j);
aRj.Range(aTj1, aTj2);
//
BndBuildBox(myCurve2, aTj1, aTj2, myTol2, aBj);
//
aTreeFiller.Add(j, aBj);
}
//
aTreeFiller.Fill();
//
for (i = 1; i <= aNbi; ++i) {
const IntTools_Range& aRi = aSi(i);
aRi.Range(aTi1, aTi2);
//
BndBuildBox(myCurve1, aTi1, aTi2, myTol1, aBi);
//
aSelector.Clear();
aSelector.SetBox(aBi);
//
aNbSD = aBBTree.Select(aSelector);
if (!aNbSD){
continue;
}
//
SplitRangeOnTwo(aTi1, aTi2, aNewSi);
//
const BOPCol_ListOfInteger& aLI = aSelector.Indices();
aItLI.Initialize(aLI);
for (; aItLI.More(); aItLI.Next()) {
j = aItLI.Value();
if (aMj.Add(j)) {
const IntTools_Range& aRj = aSj(j);
aRj.Range(aTj1, aTj2);
SplitRangeOnTwo(aTj1, aTj2, aNewSj);
}
}
}
//
aSi.Assign(aNewSi);
aSj.Assign(aNewSj);
aNbi = aSi.Length();
aNbj = aSj.Length();
//
if ((aNbi == 0) || (aNbj == 0) || (aNbi > 500) || (aNbj > 500)) {
break;
}
//
aNewSi.Clear();
aNewSj.Clear();
aMj.Clear();
}
//
iRet = (aNbi && aNbj) ? 1 : 0;
if (iRet) {
//collect ranges
IntTools_Range aRi1 = aSi(1), aRi2;
Standard_Real aT1 = aRi1.First();
for (i = 2; i <= aNbi; ++i) {
aRi2 = aSi(i);
if ((aRi2.First() - aRi1.Last()) > myRes1) {
theSegments1.Append(IntTools_Range(aT1, aRi1.Last()));
aT1 = aRi2.First();
}
aRi1 = aRi2;
}
theSegments1.Append(IntTools_Range(aT1, aRi2.Last()));
}
//
return iRet;
}
//=======================================================================
//function : IsIntersection
//purpose :
//=======================================================================
Standard_Boolean IntTools_EdgeEdge::IsIntersection(const Standard_Real aT11,
const Standard_Real aT12,
const Standard_Real aT21,
const Standard_Real aT22)
{
Standard_Boolean bRet;
gp_Pnt aP11, aP12, aP21, aP22;
gp_Vec aV11, aV12, aV21, aV22;
Standard_Real aD11_21, aD11_22, aD12_21, aD12_22, aCriteria, aCoef;
Standard_Boolean bSmall_11_21, bSmall_11_22, bSmall_12_21, bSmall_12_22;
//
bRet = Standard_True;
aCoef = 1.e+5;
if (((aT12 - aT11) > aCoef*myRes1) && ((aT22 - aT21) > aCoef*myRes2)) {
aCoef = 5000;
} else {
Standard_Real aTRMin = Min((aT12 - aT11)/myRes1, (aT22 - aT21)/myRes2);
aCoef = aTRMin / 100.;
if (aCoef < 1.) {
aCoef = 1.;
}
}
aCriteria = aCoef * myTol;
aCriteria *= aCriteria;
//
myGeom1->D1(aT11, aP11, aV11);
myGeom1->D1(aT12, aP12, aV12);
myGeom2->D1(aT21, aP21, aV21);
myGeom2->D1(aT22, aP22, aV22);
//
aD11_21 = aP11.SquareDistance(aP21);
aD11_22 = aP11.SquareDistance(aP22);
aD12_21 = aP12.SquareDistance(aP21);
aD12_22 = aP12.SquareDistance(aP22);
//
bSmall_11_21 = aD11_21 < aCriteria;
bSmall_11_22 = aD11_22 < aCriteria;
bSmall_12_21 = aD12_21 < aCriteria;
bSmall_12_22 = aD12_22 < aCriteria;
//
if ((bSmall_11_21 && bSmall_12_22) ||
(bSmall_11_22 && bSmall_12_21)) {
if (aCoef == 1.) {
return bRet;
}
//
Standard_Real anAngleCriteria;
Standard_Real anAngle1, anAngle2;
//
anAngleCriteria = 5.e-3;
if (bSmall_11_21 && bSmall_12_22) {
anAngle1 = aV11.Angle(aV21);
anAngle2 = aV12.Angle(aV22);
} else {
anAngle1 = aV11.Angle(aV22);
anAngle2 = aV12.Angle(aV21);
}
//
if (((anAngle1 < anAngleCriteria) || ((M_PI - anAngle1) < anAngleCriteria)) ||
((anAngle2 < anAngleCriteria) || ((M_PI - anAngle2) < anAngleCriteria))) {
GeomAPI_ProjectPointOnCurve aProj;
Standard_Integer iErr;
Standard_Real aD, aT1p, aT2p;
//
aD = 100.;
aProj.Init(myGeom2, aT21, aT22);
iErr = FindDistPC(aT11, aT12, myGeom1, myTol, myRes1, aProj, aD, aT1p, aT2p, Standard_False);
bRet = (iErr == 2);
}
}
return bRet;
}
//=======================================================================
//function : CheckCoincidence
//purpose :
//=======================================================================
Standard_Integer IntTools_EdgeEdge::CheckCoincidence(const Standard_Real aT11,
const Standard_Real aT12,
const Standard_Real aT21,
const Standard_Real aT22,
const Standard_Real theCriteria,
const Standard_Real theCurveRes1)
{
Standard_Boolean bSmall;
Standard_Integer iErr, aNb, i;
Standard_Real aT1A, aT1B, aT1max, aT2max, aDmax;
GeomAPI_ProjectPointOnCurve aProjPC;
IntTools_SequenceOfRanges aSeg1;
//
iErr = 0;
aDmax = -1.;
aProjPC.Init(myGeom2, aT21, aT22);
//
// 1. Express evaluation
aNb = 10; // Number of intervals on the curve #1
bSmall = !SplitRangeOnSegments(aT11, aT12, theCurveRes1, aNb, aSeg1);
aNb = aSeg1.Length();
for (i = 1; i < aNb; ++i) {
const IntTools_Range& aR1 = aSeg1(i);
aR1.Range(aT1A, aT1B);
//
iErr = DistPC(aT1B, myGeom1, theCriteria, aProjPC, aDmax, aT2max);
if (iErr) {
return iErr;
}
}
//
// if the ranges in aSeg1 are less than theCurveRes1,
// there is no need to do step 2 (deep evaluation)
if (bSmall) {
return iErr;
}
//
// 2. Deep evaluation
for (i = 2; i < aNb; ++i) {
const IntTools_Range& aR1 = aSeg1(i);
aR1.Range(aT1A, aT1B);
//
iErr = FindDistPC(aT1A, aT1B, myGeom1, theCriteria, theCurveRes1,
aProjPC, aDmax, aT1max, aT2max);
if (iErr) {
return iErr;
}
}
// Possible values:
// iErr == 0 - the patches are coincided
// iErr == 1 - a point from aC1 can not be projected on aC2
// iErr == 2 - the distance is too big
return iErr;
}
//=======================================================================
//function : FindDistPC
//purpose :
//=======================================================================
Standard_Integer FindDistPC(const Standard_Real aT1A,
const Standard_Real aT1B,
const Handle(Geom_Curve)& theC1,
const Standard_Real theCriteria,
const Standard_Real theEps,
GeomAPI_ProjectPointOnCurve& theProjPC,
Standard_Real& aDmax,
Standard_Real& aT1max,
Standard_Real& aT2max,
const Standard_Boolean bMaxDist)
{
Standard_Integer iErr, iC;
Standard_Real aGS, aXP, aA, aB, aXL, aYP, aYL, aT2P, aT2L;
//
iC = bMaxDist ? 1 : -1;
iErr = 0;
//
aGS = 0.6180339887498948482045868343656;// =0.5*(1.+sqrt(5.))-1.;
aA = aT1A;
aB = aT1B;
//
// check bounds
iErr = DistPC(aA, theC1, theCriteria, theProjPC, aYP, aT2P, aDmax, aT1max, aT2max, iC);
if (iErr == 2) {
return iErr;
}
//
iErr = DistPC(aB, theC1, theCriteria, theProjPC, aYL, aT2L, aDmax, aT1max, aT2max, iC);
if (iErr == 2) {
return iErr;
}
//
aXP = aA + (aB - aA)*aGS;
aXL = aB - (aB - aA)*aGS;
//
iErr = DistPC(aXP, theC1, theCriteria, theProjPC, aYP, aT2P, aDmax, aT1max, aT2max, iC);
if (iErr) {
return iErr;
}
//
iErr = DistPC(aXL, theC1, theCriteria, theProjPC, aYL, aT2L, aDmax, aT1max, aT2max, iC);
if (iErr) {
return iErr;
}
//
for (;;) {
if (iC*(aYP - aYL) > 0) {
aA = aXL;
aXL = aXP;
aYL = aYP;
aXP = aA + (aB - aA)*aGS;
iErr = DistPC(aXP, theC1, theCriteria, theProjPC, aYP, aT2P, aDmax, aT1max, aT2max, iC);
if (iErr) {
return iErr;
}
}
else {
aB = aXP;
aXP = aXL;
aYP = aYL;
aXL = aB - (aB - aA)*aGS;
iErr = DistPC(aXL, theC1, theCriteria, theProjPC, aYL, aT2L, aDmax, aT1max, aT2max, iC);
if (iErr) {
return iErr;
}
}
//
if ((aB - aA) < theEps) {
break;
}
}// for (;;) {
//
return iErr;
}
//=======================================================================
//function : DistPC
//purpose :
//=======================================================================
Standard_Integer DistPC(const Standard_Real aT1,
const Handle(Geom_Curve)& theC1,
const Standard_Real theCriteria,
GeomAPI_ProjectPointOnCurve& theProjPC,
Standard_Real& aD,
Standard_Real& aT2,
Standard_Real& aDmax,
Standard_Real& aT1max,
Standard_Real& aT2max,
const Standard_Integer iC)
{
Standard_Integer iErr;
//
iErr = DistPC(aT1, theC1, theCriteria, theProjPC, aD, aT2, iC);
if (iErr) {
return iErr;
}
//
if (iC*(aD - aDmax) > 0) {
aDmax = aD;
aT1max = aT1;
aT2max = aT2;
}
//
return iErr;
}
//=======================================================================
//function : DistPC
//purpose :
//=======================================================================
Standard_Integer DistPC(const Standard_Real aT1,
const Handle(Geom_Curve)& theC1,
const Standard_Real theCriteria,
GeomAPI_ProjectPointOnCurve& theProjPC,
Standard_Real& aD,
Standard_Real& aT2,
const Standard_Integer iC)
{
Standard_Integer iErr, aNbP2;
gp_Pnt aP1;
//
iErr = 0;
theC1->D0(aT1, aP1);
//
theProjPC.Perform(aP1);
aNbP2 = theProjPC.NbPoints();
if (!aNbP2) {
iErr = 1;// the point from aC1 can not be projected on aC2
return iErr;
}
//
aD = theProjPC.LowerDistance();
aT2 = theProjPC.LowerDistanceParameter();
if (iC*(aD - theCriteria) > 0) {
iErr = 2;// the distance is too big or small
}
//
return iErr;
}
//=======================================================================
//function : SplitRangeOnSegments
//purpose :
//=======================================================================
Standard_Boolean SplitRangeOnSegments(const Standard_Real aT1,
const Standard_Real aT2,
const Standard_Real theResolution,
const Standard_Integer theNbSeg,
IntTools_SequenceOfRanges& theSegments)
{
if ((aT2 - aT1) < theResolution) {
theSegments.Append(IntTools_Range(aT1, aT2));
return Standard_False;
}
//
Standard_Real aDt, aT1x, aT2x, aSeg;
Standard_Integer aNbSegments, i;
Standard_Boolean bRet;
//
bRet = Standard_True;
aNbSegments = theNbSeg;
aDt = (aT2 - aT1) / aNbSegments;
if (aDt < theResolution) {
aSeg = (aT2 - aT1) / theResolution;
aNbSegments = Standard_Integer(aSeg) + 1;
bRet = Standard_False;
}
//
aDt /= aNbSegments;
aT1x = aT1;
for (i = 1; i <= aNbSegments; ++i) {
aT2x = aT1x + aDt;
if (i==aNbSegments) {
aT2x = aT2;
}
//
IntTools_Range aR(aT1x, aT2x);
theSegments.Append(aR);
//
aT1x = aT2x;
}
//
return bRet;
}
//=======================================================================
//function : SplitRangeOnTwo
//purpose :
//=======================================================================
void SplitRangeOnTwo(const Standard_Real aT1,
const Standard_Real aT2,
IntTools_SequenceOfRanges& theSegments)
{
Standard_Real aCf, aT;
//
aCf=0.5;
aT = aT1 + (aT2-aT1)*aCf;
//
IntTools_Range aR1(aT1, aT), aR2(aT, aT2);
//
theSegments.Append(aR1);
theSegments.Append(aR2);
}
//=======================================================================
//function : BndCommon
//purpose :
//=======================================================================
Standard_Boolean BndCommon(const Bnd_Box& theB1,
const Bnd_Box& theB2,
Bnd_Box& theBOut)
{
Standard_Boolean bRet;
//
bRet = !theB1.IsOut(theB2);
if (bRet) {
Standard_Real aXmin1, aYmin1, aZmin1, aXmax1, aYmax1, aZmax1,
aXmin2, aYmin2, aZmin2, aXmax2, aYmax2, aZmax2;
Bnd_Box aBCom;
//
theB1.Get(aXmin1, aYmin1, aZmin1, aXmax1, aYmax1, aZmax1);
theB2.Get(aXmin2, aYmin2, aZmin2, aXmax2, aYmax2, aZmax2);
//
aBCom.Update(Max(aXmin1, aXmin2), Max(aYmin1, aYmin2), Max(aZmin1, aZmin2),
Min(aXmax1, aXmax2), Min(aYmax1, aYmax2), Min(aZmax1, aZmax2));
//
aBCom.Get(aXmin1, aYmin1, aZmin1, aXmax1, aYmax1, aZmax1);
theBOut = aBCom;
}
return bRet;
}
//=======================================================================
//function : BndBuildBox
//purpose :
//=======================================================================
void BndBuildBox(const BRepAdaptor_Curve& theBAC,
const Standard_Real aT1,
const Standard_Real aT2,
const Standard_Real theTol,
Bnd_Box& theBox)
{
Bnd_Box aB;
BndLib_Add3dCurve::Add(theBAC, aT1, aT2, theTol, aB);
theBox = aB;
}
//=======================================================================
//function : TypeToInteger
//purpose :
//=======================================================================
Standard_Integer TypeToInteger(const GeomAbs_CurveType theCType)
{
Standard_Integer iRet;
//
switch(theCType) {
case GeomAbs_Line:
iRet=0;
break;
case GeomAbs_Circle:
iRet=1;
break;
case GeomAbs_Ellipse:
case GeomAbs_Hyperbola:
case GeomAbs_Parabola:
iRet=2;
break;
case GeomAbs_BezierCurve:
case GeomAbs_BSplineCurve:
iRet=3;
break;
default:
iRet=4;
break;
}
return iRet;
}