mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-07-20 12:45:50 +03:00
1. Extrema algorithm calls Curve-surface intersector. This intersector returns flag about infinite solution (in spite of extrema's returning not-parallel status correctly - axes of considered cylinder and circle are not parallel). In this case, attempt of obtaining number of intersection points leads to exception. So, the fix adds check of infinite solution after the intersection algorithm. 2. The methods IsDone(), IsParallel(), NbExt(), SquareDistance() and Points() (of Extrema_* classes) have been corrected to make them consistent to the documentation. 3. Revision of some Extrema_* classes has been made in order to avoid places with uninitialized variables. 4. Currently Extrema does not store any points in case when the arguments are parallel. It stores the distance only. 5. Some cases on Extrema-algo have been moved from "fclasses"-group to "modalg"-group.
839 lines
28 KiB
C++
839 lines
28 KiB
C++
// Created on: 1994-07-06
|
|
// Created by: Laurent PAINNOT
|
|
// Copyright (c) 1994-1999 Matra Datavision
|
|
// Copyright (c) 1999-2014 OPEN CASCADE SAS
|
|
//
|
|
// This file is part of Open CASCADE Technology software library.
|
|
//
|
|
// This library is free software; you can redistribute it and/or modify it under
|
|
// the terms of the GNU Lesser General Public License version 2.1 as published
|
|
// by the Free Software Foundation, with special exception defined in the file
|
|
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
|
|
// distribution for complete text of the license and disclaimer of any warranty.
|
|
//
|
|
// Alternatively, this file may be used under the terms of Open CASCADE
|
|
// commercial license or contractual agreement.
|
|
|
|
// Modified by MPS (june 96) : correction du trap dans le cas droite/Bezier
|
|
// Modified by MPS (mai 97) : PRO 7598
|
|
// tri des solutions pour eviter de rendre plusieurs
|
|
// fois la meme solution
|
|
|
|
#include <Adaptor3d_Curve.hxx>
|
|
#include <Bnd_Range.hxx>
|
|
#include <ElCLib.hxx>
|
|
#include <Extrema_CurveTool.hxx>
|
|
#include <Extrema_ECC.hxx>
|
|
#include <Extrema_ExtCC.hxx>
|
|
#include <Extrema_ExtElC.hxx>
|
|
#include <Extrema_ExtPElC.hxx>
|
|
#include <Extrema_POnCurv.hxx>
|
|
#include <Extrema_SequenceOfPOnCurv.hxx>
|
|
#include <Geom_Circle.hxx>
|
|
#include <Geom_Curve.hxx>
|
|
#include <Geom_Ellipse.hxx>
|
|
#include <Geom_Hyperbola.hxx>
|
|
#include <Geom_Line.hxx>
|
|
#include <Geom_Parabola.hxx>
|
|
#include <Geom_TrimmedCurve.hxx>
|
|
#include <GeomAbs_CurveType.hxx>
|
|
#include <gp_Pnt.hxx>
|
|
#include <Precision.hxx>
|
|
#include <Standard_Failure.hxx>
|
|
#include <Standard_NotImplemented.hxx>
|
|
#include <Standard_NullObject.hxx>
|
|
#include <Standard_OutOfRange.hxx>
|
|
#include <StdFail_InfiniteSolutions.hxx>
|
|
#include <StdFail_NotDone.hxx>
|
|
#include <TColStd_Array1OfReal.hxx>
|
|
#include <TColStd_ListIteratorOfListOfTransient.hxx>
|
|
#include <TColStd_SequenceOfReal.hxx>
|
|
|
|
//=======================================================================
|
|
//function : Extrema_ExtCC
|
|
//purpose :
|
|
//=======================================================================
|
|
Extrema_ExtCC::Extrema_ExtCC (const Standard_Real TolC1,
|
|
const Standard_Real TolC2)
|
|
: myIsFindSingleSolution(Standard_False),
|
|
myDone (Standard_False)
|
|
{
|
|
myC[0] = 0; myC[1] = 0;
|
|
myInf[0] = myInf[1] = -Precision::Infinite();
|
|
mySup[0] = mySup[1] = Precision::Infinite();
|
|
myTol[0] = TolC1; myTol[1] = TolC2;
|
|
mydist11 = mydist12 = mydist21 = mydist22 = RealFirst();
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Extrema_ExtCC
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
Extrema_ExtCC::Extrema_ExtCC(const Adaptor3d_Curve& C1,
|
|
const Adaptor3d_Curve& C2,
|
|
const Standard_Real U1,
|
|
const Standard_Real U2,
|
|
const Standard_Real V1,
|
|
const Standard_Real V2,
|
|
const Standard_Real TolC1,
|
|
const Standard_Real TolC2)
|
|
: myIsFindSingleSolution(Standard_False),
|
|
myECC(C1, C2, U1, U2, V1, V2),
|
|
myDone (Standard_False)
|
|
{
|
|
SetCurve (1, C1, U1, U2);
|
|
SetCurve (2, C2, V1, V2);
|
|
SetTolerance (1, TolC1);
|
|
SetTolerance (2, TolC2);
|
|
mydist11 = mydist12 = mydist21 = mydist22 = RealFirst();
|
|
Perform();
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
//function : Extrema_ExtCC
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
Extrema_ExtCC::Extrema_ExtCC(const Adaptor3d_Curve& C1,
|
|
const Adaptor3d_Curve& C2,
|
|
const Standard_Real TolC1,
|
|
const Standard_Real TolC2)
|
|
: myIsFindSingleSolution(Standard_False),
|
|
myECC(C1, C2),
|
|
myDone (Standard_False)
|
|
{
|
|
SetCurve (1, C1, C1.FirstParameter(), C1.LastParameter());
|
|
SetCurve (2, C2, C2.FirstParameter(), C2.LastParameter());
|
|
SetTolerance (1, TolC1);
|
|
SetTolerance (2, TolC2);
|
|
mydist11 = mydist12 = mydist21 = mydist22 = RealFirst();
|
|
Perform();
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : SetCurve
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void Extrema_ExtCC::SetCurve (const Standard_Integer theRank, const Adaptor3d_Curve& C)
|
|
{
|
|
Standard_OutOfRange_Raise_if (theRank < 1 || theRank > 2, "Extrema_ExtCC::SetCurve()")
|
|
Standard_Integer anInd = theRank - 1;
|
|
myC[anInd] = (Standard_Address)&C;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : SetCurve
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void Extrema_ExtCC::SetCurve (const Standard_Integer theRank, const Adaptor3d_Curve& C,
|
|
const Standard_Real Uinf, const Standard_Real Usup)
|
|
{
|
|
SetCurve (theRank, C);
|
|
SetRange (theRank, Uinf, Usup);
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : SetRange
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void Extrema_ExtCC::SetRange (const Standard_Integer theRank,
|
|
const Standard_Real Uinf, const Standard_Real Usup)
|
|
{
|
|
Standard_OutOfRange_Raise_if (theRank < 1 || theRank > 2, "Extrema_ExtCC::SetRange()")
|
|
Standard_Integer anInd = theRank - 1;
|
|
myInf[anInd] = Uinf;
|
|
mySup[anInd] = Usup;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : SetTolerance
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void Extrema_ExtCC::SetTolerance (const Standard_Integer theRank, const Standard_Real theTol)
|
|
{
|
|
Standard_OutOfRange_Raise_if (theRank < 1 || theRank > 2, "Extrema_ExtCC::SetTolerance()")
|
|
Standard_Integer anInd = theRank - 1;
|
|
myTol[anInd] = theTol;
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
//function : Perform
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void Extrema_ExtCC::Perform()
|
|
{
|
|
Standard_NullObject_Raise_if (!myC[0] || !myC[1], "Extrema_ExtCC::Perform()")
|
|
myECC.SetParams(*((Adaptor3d_Curve*)myC[0]),
|
|
*((Adaptor3d_Curve*)myC[1]), myInf[0], mySup[0], myInf[1], mySup[1]);
|
|
myECC.SetTolerance(Min(myTol[0], myTol[1]));
|
|
myECC.SetSingleSolutionFlag(GetSingleSolutionFlag());
|
|
myDone = Standard_False;
|
|
mypoints.Clear();
|
|
mySqDist.Clear();
|
|
myIsPar = Standard_False;
|
|
|
|
GeomAbs_CurveType type1 = (*((Adaptor3d_Curve*)myC[0])).GetType();
|
|
GeomAbs_CurveType type2 = (*((Adaptor3d_Curve*)myC[1])).GetType();
|
|
Standard_Real U11, U12, U21, U22, Tol = Min(myTol[0], myTol[1]);
|
|
|
|
U11 = myInf[0];
|
|
U12 = mySup[0];
|
|
U21 = myInf[1];
|
|
U22 = mySup[1];
|
|
|
|
if (!Precision::IsInfinite(U11)) P1f = Extrema_CurveTool::Value(*((Adaptor3d_Curve*)myC[0]), U11);
|
|
if (!Precision::IsInfinite(U12)) P1l = Extrema_CurveTool::Value(*((Adaptor3d_Curve*)myC[0]), U12);
|
|
if (!Precision::IsInfinite(U21)) P2f = Extrema_CurveTool::Value(*((Adaptor3d_Curve*)myC[1]), U21);
|
|
if (!Precision::IsInfinite(U22)) P2l = Extrema_CurveTool::Value(*((Adaptor3d_Curve*)myC[1]), U22);
|
|
|
|
|
|
if (Precision::IsInfinite(U11) || Precision::IsInfinite(U21)) mydist11 = RealLast();
|
|
else mydist11 = P1f.SquareDistance(P2f);
|
|
if (Precision::IsInfinite(U11) || Precision::IsInfinite(U22)) mydist12 = RealLast();
|
|
else mydist12 = P1f.SquareDistance(P2l);
|
|
if (Precision::IsInfinite(U12) || Precision::IsInfinite(U21)) mydist21 = RealLast();
|
|
else mydist21 = P1l.SquareDistance(P2f);
|
|
if (Precision::IsInfinite(U12) || Precision::IsInfinite(U22)) mydist22 = RealLast();
|
|
else mydist22 = P1l.SquareDistance(P2l);
|
|
|
|
//Depending on the types of curves, the algorithm is chosen:
|
|
//- _ExtElC, when one of the curves is a line and the other is elementary,
|
|
// or there are two circles;
|
|
//- _GenExtCC, in all other cases
|
|
if ( (type1 == GeomAbs_Line && type2 <= GeomAbs_Parabola) ||
|
|
(type2 == GeomAbs_Line && type1 <= GeomAbs_Parabola) ) {
|
|
//analytical case - one curve is always a line
|
|
Standard_Integer anInd1 = 0, anInd2 = 1;
|
|
GeomAbs_CurveType aType2 = type2;
|
|
Standard_Boolean isInverse = (type1 > type2);
|
|
if (isInverse)
|
|
{
|
|
//algorithm uses inverse order of arguments
|
|
anInd1 = 1;
|
|
anInd2 = 0;
|
|
aType2 = type1;
|
|
}
|
|
switch (aType2) {
|
|
case GeomAbs_Line: {
|
|
Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Line(), Tol);
|
|
PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
|
|
break;
|
|
}
|
|
case GeomAbs_Circle: {
|
|
Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Circle(), Tol);
|
|
PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
|
|
break;
|
|
}
|
|
case GeomAbs_Ellipse: {
|
|
Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Ellipse());
|
|
PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
|
|
break;
|
|
}
|
|
case GeomAbs_Hyperbola: {
|
|
Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Hyperbola());
|
|
PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
|
|
break;
|
|
}
|
|
case GeomAbs_Parabola: {
|
|
Extrema_ExtElC Xtrem((*((Adaptor3d_Curve*)myC[anInd1])).Line(), (*((Adaptor3d_Curve*)myC[anInd2])).Parabola());
|
|
PrepareResults(Xtrem, isInverse, U11, U12, U21, U22);
|
|
break;
|
|
}
|
|
default: break;
|
|
}
|
|
} else if (type1 == GeomAbs_Circle && type2 == GeomAbs_Circle) {
|
|
//analytical case - two circles
|
|
Standard_Boolean bIsDone;
|
|
Extrema_ExtElC CCXtrem ((*((Adaptor3d_Curve*)myC[0])).Circle(), (*((Adaptor3d_Curve*)myC[1])).Circle());
|
|
bIsDone = CCXtrem.IsDone();
|
|
if(bIsDone) {
|
|
PrepareResults(CCXtrem, Standard_False, U11, U12, U21, U22);
|
|
}
|
|
else {
|
|
myECC.Perform();
|
|
PrepareResults(myECC, U11, U12, U21, U22);
|
|
}
|
|
} else {
|
|
myECC.Perform();
|
|
PrepareResults(myECC, U11, U12, U21, U22);
|
|
}
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
//function : IsDone
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
Standard_Boolean Extrema_ExtCC::IsDone() const
|
|
{
|
|
return myDone;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : IsParallel
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
Standard_Boolean Extrema_ExtCC::IsParallel() const
|
|
{
|
|
if (!IsDone())
|
|
{
|
|
throw StdFail_NotDone();
|
|
}
|
|
|
|
return myIsPar;
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
//function : Value
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
Standard_Real Extrema_ExtCC::SquareDistance(const Standard_Integer N) const
|
|
{
|
|
if ((N < 1) || (N > NbExt())) throw Standard_OutOfRange();
|
|
return mySqDist.Value(N);
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
//function : NbExt
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
Standard_Integer Extrema_ExtCC::NbExt() const
|
|
{
|
|
if(!myDone) throw StdFail_NotDone();
|
|
return mySqDist.Length();
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
//function : Points
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void Extrema_ExtCC::Points(const Standard_Integer N,
|
|
Extrema_POnCurv& P1,
|
|
Extrema_POnCurv& P2) const
|
|
{
|
|
if (IsParallel())
|
|
{
|
|
throw StdFail_InfiniteSolutions();
|
|
}
|
|
|
|
if (N < 1 || N > NbExt())
|
|
{
|
|
throw Standard_OutOfRange();
|
|
}
|
|
|
|
P1 = mypoints.Value(2 * N - 1);
|
|
P2 = mypoints.Value(2 * N);
|
|
}
|
|
|
|
|
|
|
|
//=======================================================================
|
|
//function : TrimmedDistances
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void Extrema_ExtCC::TrimmedSquareDistances(Standard_Real& dist11,
|
|
Standard_Real& dist12,
|
|
Standard_Real& dist21,
|
|
Standard_Real& dist22,
|
|
gp_Pnt& P11 ,
|
|
gp_Pnt& P12 ,
|
|
gp_Pnt& P21 ,
|
|
gp_Pnt& P22 ) const {
|
|
|
|
dist11 = mydist11;
|
|
dist12 = mydist12;
|
|
dist21 = mydist21;
|
|
dist22 = mydist22;
|
|
P11 = P1f;
|
|
P12 = P1l;
|
|
P21 = P2f;
|
|
P22 = P2l;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : ParallelResult
|
|
//purpose :
|
|
//=======================================================================
|
|
void Extrema_ExtCC::PrepareParallelResult(const Standard_Real theUt11,
|
|
const Standard_Real theUt12,
|
|
const Standard_Real theUt21,
|
|
const Standard_Real theUt22,
|
|
const Standard_Real theSqDist)
|
|
{
|
|
if (!myIsPar)
|
|
return;
|
|
|
|
const GeomAbs_CurveType aType1 = Extrema_CurveTool::GetType(*((Adaptor3d_Curve*) myC[0]));
|
|
const GeomAbs_CurveType aType2 = Extrema_CurveTool::GetType(*((Adaptor3d_Curve*) myC[1]));
|
|
|
|
if (((aType1 != GeomAbs_Line) && (aType1 != GeomAbs_Circle)) ||
|
|
((aType2 != GeomAbs_Line) && (aType2 != GeomAbs_Circle)))
|
|
{
|
|
mySqDist.Append(theSqDist);
|
|
myDone = Standard_True;
|
|
myIsPar = Standard_True;
|
|
return;
|
|
}
|
|
|
|
// Parallel case is only for line-line, circle-circle and circle-line!!!
|
|
// But really for trimmed curves extremas can not exist!
|
|
if (aType1 != aType2)
|
|
{
|
|
//The projection of the circle's location to the trimmed line must exist.
|
|
const Standard_Boolean isReversed = (aType1 != GeomAbs_Circle);
|
|
const gp_Pnt aPonC = !isReversed ?
|
|
Extrema_CurveTool::Value(*((Adaptor3d_Curve*) myC[0]), theUt11) :
|
|
Extrema_CurveTool::Value(*((Adaptor3d_Curve*) myC[1]), theUt21);
|
|
|
|
const gp_Lin aL = !isReversed ? ((Adaptor3d_Curve*) myC[1])->Line() :
|
|
((Adaptor3d_Curve*) myC[0])->Line();
|
|
const Extrema_ExtPElC ExtPLin(aPonC, aL, Precision::Confusion(),
|
|
!isReversed ? theUt21 : theUt11,
|
|
!isReversed ? theUt22 : theUt12);
|
|
|
|
if (ExtPLin.IsDone())
|
|
{
|
|
mySqDist.Append(theSqDist);
|
|
}
|
|
else
|
|
{
|
|
myIsPar = Standard_False;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (aType1 == GeomAbs_Line)
|
|
{
|
|
// Line - Line
|
|
|
|
const Standard_Real isFirstInfinite = (Precision::IsInfinite(theUt11) &&
|
|
Precision::IsInfinite(theUt12));
|
|
const Standard_Real isLastInfinite = (Precision::IsInfinite(theUt21) &&
|
|
Precision::IsInfinite(theUt22));
|
|
|
|
if (isFirstInfinite || isLastInfinite)
|
|
{
|
|
// Infinite number of solution
|
|
|
|
mySqDist.Append(theSqDist);
|
|
}
|
|
else
|
|
{
|
|
// The range created by projection of both ends of the 1st line
|
|
// to the 2nd one must intersect the (native) trimmed range of
|
|
// the 2nd line.
|
|
|
|
myIsPar = Standard_False;
|
|
|
|
const gp_Lin aLin1 = ((Adaptor3d_Curve*) myC[0])->Line();
|
|
const gp_Lin aLin2 = ((Adaptor3d_Curve*) myC[1])->Line();
|
|
const Standard_Boolean isOpposite(aLin1.Direction().Dot(aLin2.Direction()) < 0.0);
|
|
|
|
Bnd_Range aRange2(theUt21, theUt22);
|
|
Bnd_Range aProjRng12;
|
|
|
|
if (Precision::IsInfinite(theUt11))
|
|
{
|
|
if (isOpposite)
|
|
aProjRng12.Add(Precision::Infinite());
|
|
else
|
|
aProjRng12.Add(-Precision::Infinite());
|
|
}
|
|
else
|
|
{
|
|
const gp_Pnt aPonC1 = ElCLib::Value(theUt11, aLin1);
|
|
const Standard_Real aPar = ElCLib::Parameter(aLin2, aPonC1);
|
|
aProjRng12.Add(aPar);
|
|
}
|
|
|
|
if (Precision::IsInfinite(theUt12))
|
|
{
|
|
if (isOpposite)
|
|
aProjRng12.Add(-Precision::Infinite());
|
|
else
|
|
aProjRng12.Add(Precision::Infinite());
|
|
}
|
|
else
|
|
{
|
|
const gp_Pnt aPonC1 = ElCLib::Value(theUt12, aLin1);
|
|
const Standard_Real aPar = ElCLib::Parameter(aLin2, aPonC1);
|
|
aProjRng12.Add(aPar);
|
|
}
|
|
|
|
aRange2.Common(aProjRng12);
|
|
if (aRange2.Delta() > Precision::Confusion())
|
|
{
|
|
ClearSolutions();
|
|
mySqDist.Append(theSqDist);
|
|
myIsPar = Standard_True;
|
|
}
|
|
else if (!aRange2.IsVoid())
|
|
{
|
|
//Case like this:
|
|
|
|
// ************** aLin1
|
|
// o
|
|
// o
|
|
// *************** aLin2
|
|
|
|
ClearSolutions();
|
|
Standard_Real aPar1 = 0.0, aPar2 = 0.0;
|
|
aRange2.GetBounds(aPar1, aPar2);
|
|
aPar2 = 0.5*(aPar1 + aPar2);
|
|
gp_Pnt aP = ElCLib::Value(aPar2, aLin2);
|
|
const Extrema_POnCurv aP2(aPar2, aP);
|
|
aPar1 = ElCLib::Parameter(aLin1, aP);
|
|
aP = ElCLib::Value(aPar1, aLin1);
|
|
const Extrema_POnCurv aP1(aPar1, aP);
|
|
mypoints.Append(aP1);
|
|
mypoints.Append(aP2);
|
|
mySqDist.Append(theSqDist);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Circle - Circle
|
|
myIsPar = Standard_False;
|
|
|
|
//Two arcs with ranges [U1, U2] and [V1, V2] correspondingly are
|
|
//considered to be parallel in the following case:
|
|
// The range created by projection both points U1 and U2 of the
|
|
// 1st circle to the 2nd one intersects either the range [V1, V2] or
|
|
// the range [V1-PI, V2-PI]. All ranges must be adjusted to correspond
|
|
// periodic range before checking of intersection.
|
|
|
|
const gp_Circ aWorkCirc = ((Adaptor3d_Curve*) myC[1])->Circle();
|
|
const Standard_Real aPeriod = M_PI + M_PI;
|
|
gp_Vec aVTg1;
|
|
gp_Pnt aP11;
|
|
const gp_Pnt aP12 = Extrema_CurveTool::Value(*((Adaptor3d_Curve*) myC[0]), theUt12);
|
|
Extrema_CurveTool::D1(*((Adaptor3d_Curve*) myC[0]), theUt11, aP11, aVTg1);
|
|
|
|
const Bnd_Range aRange(theUt21, theUt22);
|
|
Bnd_Range aProjRng1;
|
|
|
|
// Project arc of the 1st circle between points theUt11 and theUt12 to the
|
|
// 2nd circle. It is necessary to chose correct arc from two possible ones.
|
|
|
|
Standard_Real aPar1 = ElCLib::InPeriod(ElCLib::Parameter(aWorkCirc, aP11),
|
|
theUt21, theUt21 + aPeriod);
|
|
const gp_Vec aVTg2 = Extrema_CurveTool::DN(*((Adaptor3d_Curve*) myC[1]), aPar1, 1);
|
|
|
|
// Check if circles have same/opposite directions
|
|
const Standard_Boolean isOpposite(aVTg1.Dot(aVTg2) < 0.0);
|
|
|
|
Standard_Real aPar2 = ElCLib::InPeriod(ElCLib::Parameter(aWorkCirc, aP12),
|
|
theUt21, theUt21 + aPeriod);
|
|
|
|
if (isOpposite)
|
|
{
|
|
// Must be aPar2 < aPar1
|
|
if ((aRange.Delta() > Precision::Angular()) &&
|
|
((aPar1 - aPar2) < Precision::Angular()))
|
|
{
|
|
aPar2 -= aPeriod;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Must be aPar2 > aPar1
|
|
if ((aRange.Delta() > Precision::Angular()) &&
|
|
((aPar2 - aPar1) < Precision::Angular()))
|
|
{
|
|
aPar1 -= aPeriod;
|
|
}
|
|
}
|
|
|
|
// Now the projection result is the range [aPar1, aPar2]
|
|
// if aPar1 < aPar2 or the range [aPar2, aPar1], otherwise.
|
|
|
|
Standard_Real aMinSquareDist = RealLast();
|
|
|
|
aProjRng1.Add(aPar1 - M_PI);
|
|
aProjRng1.Add(aPar2 - M_PI);
|
|
for (Standard_Integer i = 0; i < 2; i++)
|
|
{
|
|
// Repeat computation twice
|
|
|
|
Bnd_Range aRng = aProjRng1;
|
|
aRng.Common(aRange);
|
|
|
|
//Cases are possible and processed below:
|
|
//1. Extrema does not exist. In this case all common ranges are VOID.
|
|
//2. Arcs are parallel and distance between them is equal to sqrt(theSqDist).
|
|
// In this case myIsPar = TRUE definitely.
|
|
//3. Arcs are parallel and distance between them is equal to (sqrt(theSqDist) + R),
|
|
// where R is the least radius of the both circles. In this case myIsPar flag
|
|
// will temporary be set to TRUE but check will be continued until less
|
|
// distance will be found. At that, region with the least distance can be
|
|
// either a local point or continuous range. In 1st case myIsPar = FALSE and
|
|
// several (or single) extremas will be returned. In the 2nd one
|
|
// myIsPar = TRUE and only the least distance will be returned.
|
|
//4. Arcs are not parallel. Then several (or single) extremas will be returned.
|
|
|
|
if (aRng.Delta() > Precision::Angular())
|
|
{
|
|
Standard_Real aPar = 0.0;
|
|
aRng.GetIntermediatePoint(0.5, aPar);
|
|
const gp_Pnt aPCirc2 = ElCLib::Value(aPar, aWorkCirc);
|
|
Extrema_ExtPElC ExtPCir(aPCirc2,
|
|
Extrema_CurveTool::Circle(*((Adaptor3d_Curve*) myC[0])),
|
|
Precision::Confusion(), theUt11, theUt12);
|
|
|
|
Standard_Real aMinSqD = ExtPCir.SquareDistance(1);
|
|
for (Standard_Integer anExtID = 2; anExtID <= ExtPCir.NbExt(); anExtID++)
|
|
{
|
|
aMinSqD = Min(aMinSqD, ExtPCir.SquareDistance(anExtID));
|
|
}
|
|
|
|
if (aMinSqD <= aMinSquareDist)
|
|
{
|
|
ClearSolutions();
|
|
mySqDist.Append(aMinSqD);
|
|
myIsPar = Standard_True;
|
|
|
|
const Standard_Real aDeltaSqDist = aMinSqD - theSqDist;
|
|
const Standard_Real aSqD = Max(aMinSqD, theSqDist);
|
|
|
|
// 0 <= Dist1-Dist2 <= Eps
|
|
// 0 <= Dist1^2 - Dist2^2 < Eps*(Dist1+Dist2)
|
|
|
|
//If Dist1 ~= Dist2 ==> Dist1+Dist2 ~= 2*Dist2.
|
|
//Consequently,
|
|
// 0 <= Dist1^2 - Dist2^2 <= 2*Dist2*Eps
|
|
|
|
//Or
|
|
// (Dist1^2 - Dist2^2)^2 <= 4*Dist2^2*Eps^2
|
|
|
|
if (aDeltaSqDist*aDeltaSqDist < 4.0*aSqD*Precision::SquareConfusion())
|
|
{
|
|
// New solution is found
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Nearer solution can be found
|
|
}
|
|
else if (!aRng.IsVoid())
|
|
{
|
|
//Check cases like this:
|
|
|
|
// ************** aCirc1
|
|
// o
|
|
// o
|
|
// *************** aCirc2
|
|
|
|
Standard_Real aPar = 0.0;
|
|
aRng.GetIntermediatePoint(0.5, aPar);
|
|
const gp_Pnt aPCirc2 = ElCLib::Value(aPar, aWorkCirc);
|
|
const Extrema_POnCurv aP2(aPar, aPCirc2);
|
|
|
|
Extrema_ExtPElC ExtPCir(aPCirc2,
|
|
Extrema_CurveTool::Circle(*((Adaptor3d_Curve*) myC[0])),
|
|
Precision::Confusion(), theUt11, theUt12);
|
|
|
|
Standard_Boolean isFound = !myIsPar;
|
|
|
|
if (!isFound)
|
|
{
|
|
//If the flag myIsPar was set earlier then it does not mean that
|
|
//we have found the minimal distance. Here we check it. If there is
|
|
//a pair of points, which are in less distance then myIsPar flag
|
|
//was unset and the algorithm will return these nearest points.
|
|
|
|
for (Standard_Integer anExtID = 1; anExtID <= ExtPCir.NbExt(); anExtID++)
|
|
{
|
|
if (ExtPCir.SquareDistance(anExtID) < aMinSquareDist)
|
|
{
|
|
isFound = Standard_True;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (isFound)
|
|
{
|
|
ClearSolutions();
|
|
myIsPar = Standard_False;
|
|
for (Standard_Integer anExtID = 1; anExtID <= ExtPCir.NbExt(); anExtID++)
|
|
{
|
|
mypoints.Append(ExtPCir.Point(anExtID));
|
|
mypoints.Append(aP2);
|
|
mySqDist.Append(ExtPCir.SquareDistance(anExtID));
|
|
aMinSquareDist = Min(aMinSquareDist, ExtPCir.SquareDistance(anExtID));
|
|
}
|
|
}
|
|
}
|
|
|
|
aProjRng1.Shift(M_PI);
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : Results
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void Extrema_ExtCC::PrepareResults(const Extrema_ExtElC& AlgExt,
|
|
const Standard_Boolean theIsInverse,
|
|
const Standard_Real Ut11,
|
|
const Standard_Real Ut12,
|
|
const Standard_Real Ut21,
|
|
const Standard_Real Ut22)
|
|
{
|
|
Standard_Integer i, NbExt;
|
|
Standard_Real Val, U, U2;
|
|
Extrema_POnCurv P1, P2;
|
|
|
|
myDone = AlgExt.IsDone();
|
|
if (myDone) {
|
|
myIsPar = AlgExt.IsParallel();
|
|
if (myIsPar) {
|
|
PrepareParallelResult(Ut11, Ut12, Ut21, Ut22, AlgExt.SquareDistance());
|
|
}
|
|
else {
|
|
NbExt = AlgExt.NbExt();
|
|
for (i = 1; i <= NbExt; i++) {
|
|
// Verification de la validite des parametres
|
|
AlgExt.Points(i, P1, P2);
|
|
if (!theIsInverse)
|
|
{
|
|
U = P1.Parameter();
|
|
U2 = P2.Parameter();
|
|
}
|
|
else {
|
|
U2 = P1.Parameter();
|
|
U = P2.Parameter();
|
|
}
|
|
|
|
if (Extrema_CurveTool::IsPeriodic(*((Adaptor3d_Curve*)myC[0]))) {
|
|
U = ElCLib::InPeriod(U, Ut11, Ut11+Extrema_CurveTool::Period(*((Adaptor3d_Curve*)myC[0])));
|
|
}
|
|
if (Extrema_CurveTool::IsPeriodic(*((Adaptor3d_Curve*)myC[1]))) {
|
|
U2 = ElCLib::InPeriod(U2, Ut21, Ut21+Extrema_CurveTool::Period(*((Adaptor3d_Curve*)myC[1])));
|
|
}
|
|
|
|
if ((U >= Ut11 - RealEpsilon()) &&
|
|
(U <= Ut12 + RealEpsilon()) &&
|
|
(U2 >= Ut21 - RealEpsilon()) &&
|
|
(U2 <= Ut22 + RealEpsilon())) {
|
|
Val = AlgExt.SquareDistance(i);
|
|
mySqDist.Append(Val);
|
|
if (!theIsInverse)
|
|
{
|
|
P1.SetValues(U, P1.Value());
|
|
P2.SetValues(U2, P2.Value());
|
|
mypoints.Append(P1);
|
|
mypoints.Append(P2);
|
|
}
|
|
else {
|
|
P1.SetValues(U2, P1.Value());
|
|
P2.SetValues(U, P2.Value());
|
|
mypoints.Append(P2);
|
|
mypoints.Append(P1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
//=======================================================================
|
|
//function : Results
|
|
//purpose :
|
|
//=======================================================================
|
|
|
|
void Extrema_ExtCC::PrepareResults(const Extrema_ECC& AlgExt,
|
|
const Standard_Real Ut11,
|
|
const Standard_Real Ut12,
|
|
const Standard_Real Ut21,
|
|
const Standard_Real Ut22)
|
|
{
|
|
Standard_Integer i, NbExt;
|
|
Standard_Real Val, U, U2;
|
|
Extrema_POnCurv P1, P2;
|
|
|
|
myDone = AlgExt.IsDone();
|
|
if (myDone)
|
|
{
|
|
myIsPar = AlgExt.IsParallel();
|
|
if (myIsPar)
|
|
{
|
|
PrepareParallelResult(Ut11, Ut12, Ut21, Ut22, AlgExt.SquareDistance());
|
|
}
|
|
else
|
|
{
|
|
NbExt = AlgExt.NbExt();
|
|
for (i = 1; i <= NbExt; i++)
|
|
{
|
|
AlgExt.Points(i, P1, P2);
|
|
U = P1.Parameter();
|
|
U2 = P2.Parameter();
|
|
|
|
// Check points to be into param space.
|
|
if (Extrema_CurveTool::IsPeriodic(*((Adaptor3d_Curve*) myC[0])))
|
|
{
|
|
U = ElCLib::InPeriod(U, Ut11, Ut11 + Extrema_CurveTool::Period(*((Adaptor3d_Curve*) myC[0])));
|
|
}
|
|
if (Extrema_CurveTool::IsPeriodic(*((Adaptor3d_Curve*) myC[1])))
|
|
{
|
|
U2 = ElCLib::InPeriod(U2, Ut21, Ut21 + Extrema_CurveTool::Period(*((Adaptor3d_Curve*) myC[1])));
|
|
}
|
|
|
|
if ((U >= Ut11 - RealEpsilon()) &&
|
|
(U <= Ut12 + RealEpsilon()) &&
|
|
(U2 >= Ut21 - RealEpsilon()) &&
|
|
(U2 <= Ut22 + RealEpsilon()))
|
|
{
|
|
Val = AlgExt.SquareDistance(i);
|
|
mySqDist.Append(Val);
|
|
P1.SetValues(U, P1.Value());
|
|
P2.SetValues(U2, P2.Value());
|
|
mypoints.Append(P1);
|
|
mypoints.Append(P2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : SetSingleSolutionFlag
|
|
//purpose :
|
|
//=======================================================================
|
|
void Extrema_ExtCC::SetSingleSolutionFlag(const Standard_Boolean theFlag)
|
|
{
|
|
myIsFindSingleSolution = theFlag;
|
|
}
|
|
|
|
//=======================================================================
|
|
//function : GetSingleSolutionFlag
|
|
//purpose :
|
|
//=======================================================================
|
|
Standard_Boolean Extrema_ExtCC::GetSingleSolutionFlag() const
|
|
{
|
|
return myIsFindSingleSolution;
|
|
}
|