1 // Copyright (C) 2007-2016 CEA/DEN, EDF R&D, OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 // File : GEOMImpl_Fillet1d.cxx
23 #include "GEOMImpl_Fillet1d.hxx"
25 #include <Basics_OCCTVersion.hxx>
27 #include <BRep_Tool.hxx>
28 #include <BRepAdaptor_Curve.hxx>
29 #include <BRepBuilderAPI_MakeEdge.hxx>
32 #include <gp_Circ.hxx>
33 #include <Geom2d_Line.hxx>
34 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
35 #include <Geom2dAPI_InterCurveCurve.hxx>
36 #include <GeomAPI_ProjectPointOnCurve.hxx>
37 #include <GeomProjLib.hxx>
38 #include <Geom_Circle.hxx>
39 #include <Precision.hxx>
40 #include <TColStd_ListIteratorOfListOfReal.hxx>
41 #include <IntRes2d_IntersectionSegment.hxx>
44 #include <Standard_NotImplemented.hxx>
48 * This function returns Standard_True if it is possible to divide edge, i.e.
49 * if one parameter either start or end one is inside the edge. This function
50 * is used in the method GEOMImpl_Fillet1d::Result.
52 * \param theEdge the edge
53 * \param theStart the start parameter
54 * \param theEnd the end parameter
55 * \return Standard_True if it is possible to split edge;
56 * Standard_False otherwise.
58 static Standard_Boolean IsDivideEdge(const TopoDS_Edge &theEdge,
59 const Standard_Real theStart,
60 const Standard_Real theEnd)
64 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst, aLast);
65 gp_Pnt aPStart = aCurve->Value(theStart);
66 gp_Pnt aPEnd = aCurve->Value(theEnd);
67 TopoDS_Vertex aVFirst = TopExp::FirstVertex(theEdge);
68 TopoDS_Vertex aVLast = TopExp::LastVertex(theEdge);
69 Standard_Real aTolFirst = BRep_Tool::Tolerance(aVFirst);
70 Standard_Real aTolLast = BRep_Tool::Tolerance(aVLast);
71 Standard_Real aTolConf = Precision::Confusion();
72 gp_Pnt aPFirst = BRep_Tool::Pnt(aVFirst);
73 gp_Pnt aPLast = BRep_Tool::Pnt(aVLast);
74 Standard_Real aDistSF = aPStart.Distance(aPFirst);
75 Standard_Real aDistSL = aPStart.Distance(aPLast);
76 Standard_Real aDistEF = aPEnd.Distance(aPFirst);
77 Standard_Real aDistEL = aPEnd.Distance(aPLast);
78 Standard_Boolean isSplit = Standard_True;
80 if (aDistSF <= aTolFirst + aTolConf ||
81 aDistSL <= aTolLast + aTolConf) {
82 if (aDistEF <= aTolFirst + aTolConf ||
83 aDistEL <= aTolLast + aTolConf) {
85 isSplit = Standard_False;
86 // in this case the original edge is thrown, and distance (gap) from new arc end
87 // to a vertex of original wire can reach (aVertexTolerance + Precision::Confusion()).
88 // Resulting wire is fixed (Mantis issue 0023411) in GEOMImpl_Fillet1dDriver::MakeFillet()
96 * class GEOMImpl_Fillet1d
99 //=======================================================================
100 //function : Constructor
102 //=======================================================================
103 GEOMImpl_Fillet1d::GEOMImpl_Fillet1d(const TopoDS_Edge& theEdge1,
104 const TopoDS_Edge& theEdge2,
105 const gp_Pln& thePlane)
106 : myEdgesExchnged( Standard_False )
108 myPlane = new Geom_Plane(thePlane);
110 BRepAdaptor_Curve aBAC1(theEdge1);
111 BRepAdaptor_Curve aBAC2(theEdge2);
112 if (aBAC1.GetType() < aBAC2.GetType())
113 { // first curve must be more complicated
116 myEdgesExchnged = Standard_True;
124 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(myEdge1, myStart1, myEnd1);
125 Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(myEdge2, myStart2, myEnd2);
127 myCurve1 = GeomProjLib::Curve2d(aCurve1, myStart1, myEnd1, myPlane);
128 myCurve2 = GeomProjLib::Curve2d(aCurve2, myStart2, myEnd2, myPlane);
130 while (myCurve1->IsPeriodic() && myStart1 >= myEnd1)
131 myEnd1 += myCurve1->Period();
132 while (myCurve2->IsPeriodic() && myStart2 >= myEnd2)
133 myEnd2 += myCurve2->Period();
135 if (aBAC1.GetType() == aBAC2.GetType())
137 if (myEnd2 - myStart2 < myEnd1 - myStart1)
138 { // first curve must be parametrically shorter
139 TopoDS_Edge anEdge = myEdge1;
142 Handle(Geom2d_Curve) aCurve = myCurve1;
145 Standard_Real a = myStart1;
151 myEdgesExchnged = Standard_True;
156 //=======================================================================
157 //function : isRadiusIntersected
158 //purpose : local function
159 //=======================================================================
160 static Standard_Boolean isRadiusIntersected(const Handle(Geom2d_Curve)& theCurve,
161 const gp_Pnt2d theStart,
162 const gp_Pnt2d theEnd,
163 const Standard_Boolean theStartConnected)
165 const Standard_Real aTol = Precision::Confusion();
166 const Standard_Real anAngTol = Precision::Angular();
167 Handle(Geom2d_Line) aRadiusLine = new Geom2d_Line (theStart, gp_Dir2d(gp_Vec2d(theStart, theEnd)));
168 Geom2dAPI_InterCurveCurve anInter (theCurve, aRadiusLine, aTol);
171 for(a = anInter.NbPoints(); a > 0; a--)
173 aPoint = anInter.Point(a);
174 if ( aPoint.Distance(theStart) < aTol && !theStartConnected )
175 return Standard_True;
176 if (aPoint.Distance(theEnd) < aTol * 200)
177 return Standard_True;
178 if (gp_Vec2d(aPoint, theStart).IsOpposite(gp_Vec2d(aPoint, theEnd), anAngTol))
179 return Standard_True;
181 Handle(Geom2d_Curve) aCurve;
182 for(a = anInter.NbSegments(); a > 0; a--)
184 // Porting to DEV version of OCCT 10.02.2017 BEGIN
185 #if OCC_VERSION_LARGE > 0x07010000
186 Standard_NotImplemented::Raise("The treatment of tangential intersection is not implemented");
188 // This piece of code seems never worked, because:
189 // 1. In case of two curves intersection
190 // method Segment with TWO output curves HAS TO be used.
191 // 2. Method Segment with ONE output curve (as below) just raises
192 // Standard_NotImplemented exception since 05.03.2012 (at least)
193 // and that is why has been eliminated 03.02.2017.
194 anInter.Segment(a, aCurve);
195 aPoint = aCurve->Value(aCurve->FirstParameter());
196 if (aPoint.Distance(theStart) < aTol)
197 if (!theStartConnected)
198 return Standard_True;
199 if (aPoint.Distance(theEnd) < aTol)
200 return Standard_True;
201 if (gp_Vec2d(aPoint, theStart).IsOpposite(gp_Vec2d(aPoint, theEnd), anAngTol))
202 return Standard_True;
203 aPoint = aCurve->Value(aCurve->LastParameter());
204 if (aPoint.Distance(theStart) < aTol)
205 if (!theStartConnected)
206 return Standard_True;
207 if (aPoint.Distance(theEnd) < aTol)
208 return Standard_True;
209 if (gp_Vec2d(aPoint, theStart).IsOpposite(gp_Vec2d(aPoint, theEnd), anAngTol))
210 return Standard_True;
212 // Porting to DEV version of OCCT 10.02.2017 END
214 return Standard_False;
218 //=======================================================================
219 //function : fillPoint
221 //=======================================================================
222 void GEOMImpl_Fillet1d::fillPoint(GEOMImpl_Fillet1dPoint* thePoint)
226 const Standard_Real aTol = Precision::Confusion();
227 myCurve1->D1(thePoint->GetParam(), aPoint, aVec);
228 if (aVec.SquareMagnitude() < aTol)
231 gp_Vec2d aPerp(((myStartSide)?-1:1) * aVec.Y(), ((myStartSide)?1:-1) * aVec.X());
233 aPerp.Multiply(myRadius);
234 gp_Pnt2d aCenter = aPoint.Translated(aPerp);
235 thePoint->SetCenter(aCenter);
237 // on the intersection point
238 Standard_Boolean aValid = Standard_True;
239 Geom2dAPI_ProjectPointOnCurve aProjInt(aPoint, myCurve2);
240 if (aProjInt.NbPoints() && aPoint.Distance(aProjInt.NearestPoint()) < aTol)
241 aValid = Standard_False;
243 aValid = !isRadiusIntersected(myCurve2, aPoint, aCenter, Standard_True);
245 Geom2dAPI_ProjectPointOnCurve aProj(aCenter, myCurve2);
246 Standard_Integer a, aNB = aProj.NbPoints();
247 for(a = aNB; a > 0; a--)
249 if (aPoint.Distance(aProj.Point(a)) < aTol)
252 Standard_Boolean aValid2 = aValid;
254 aValid2 = !isRadiusIntersected(myCurve1, aCenter, aProj.Point(a), Standard_False);
256 // checking the right parameter
257 Standard_Real aParam = aProj.Parameter(a);
258 while(myCurve2->IsPeriodic() && aParam < myStart2)
259 aParam += myCurve2->Period();
261 thePoint->AddValue(aProj.Distance(a) * aProj.Distance(a) - myRadius * myRadius,
262 (aParam >= myStart2 && aParam <= myEnd2 && aValid2));
263 if (fabs(fabs(aProj.Distance(a)) - myRadius) < aTol)
264 thePoint->SetParam2(aParam);
268 //=======================================================================
269 //function : fillDiff
271 //=======================================================================
272 void GEOMImpl_Fillet1d::fillDiff(GEOMImpl_Fillet1dPoint* thePoint, Standard_Real theDiffStep, Standard_Boolean theFront)
274 GEOMImpl_Fillet1dPoint* aDiff =
275 new GEOMImpl_Fillet1dPoint(thePoint->GetParam() + (theFront?(theDiffStep):(-theDiffStep)));
277 if (!thePoint->ComputeDifference(aDiff))
279 aDiff->SetParam(thePoint->GetParam() + (theFront?(-theDiffStep):(theDiffStep)));
281 thePoint->ComputeDifference(aDiff);
286 //=======================================================================
289 //=======================================================================
290 Standard_Boolean GEOMImpl_Fillet1d::Perform(const Standard_Real theRadius)
292 myDegreeOfRecursion = 0;
293 myResultParams.Clear();
294 myResultOrientation.Clear();
296 Standard_Real aNBSteps = 100;
297 Geom2dAdaptor_Curve aGAC(myCurve1);
298 switch (aGAC.GetType())
306 case GeomAbs_Ellipse:
309 case GeomAbs_BezierCurve:
310 case GeomAbs_BSplineCurve:
311 aNBSteps = 2 + aGAC.Degree() * aGAC.NbPoles();
313 default: // unknown: maximum
317 myRadius = theRadius;
319 // Compute the intervals.
320 const Standard_Real aTol = Precision::Confusion();
321 Geom2dAPI_InterCurveCurve anAPIInter(myCurve1, myCurve2, aTol);
322 const Geom2dInt_GInter &anInter = anAPIInter.Intersector();
323 Standard_Integer aNb = anInter.NbPoints();
325 TColStd_ListOfReal aParams;
326 TColStd_ListIteratorOfListOfReal anIter;
328 // Treat intersection points.
329 for(i = 1; i <= aNb; i++) {
330 const IntRes2d_IntersectionPoint &aPoint = anInter.Point(i);
331 Standard_Real aParam = aPoint.ParamOnFirst();
333 // Adjust parameter on periodic curve.
334 if (myCurve1->IsPeriodic()) {
335 aParam = ElCLib::InPeriod
336 (aParam, myStart1, myStart1 + myCurve1->Period());
339 if (aParam > myStart1 + aTol && aParam < myEnd1 - aTol) {
340 // Add the point in the list in increasing order.
341 for(anIter.Initialize(aParams); anIter.More(); anIter.Next()) {
342 if (anIter.Value() > aParam) {
343 aParams.InsertBefore(aParam, anIter);
348 if (!anIter.More()) {
349 aParams.Append(aParam);
354 // Treat intersection segments.
355 aNb = anInter.NbSegments();
357 for(i = 1; i <= aNb; i++) {
358 const IntRes2d_IntersectionSegment &aSegment = anInter.Segment(i);
360 if (aSegment.HasFirstPoint() && aSegment.HasLastPoint()) {
361 Standard_Real aParam1 = aSegment.FirstPoint().ParamOnFirst();
362 Standard_Real aParam2 = aSegment.LastPoint().ParamOnFirst();
364 // Adjust parameters on periodic curve.
365 if (myCurve1->IsPeriodic()) {
366 ElCLib::AdjustPeriodic(myStart1, myStart1 + myCurve1->Period(),
367 aTol, aParam1, aParam2);
370 if (aParam1 > myStart1 + aTol && aParam1 < myEnd1 - aTol &&
371 aParam2 > myStart1 + aTol && aParam2 < myEnd1 - aTol) {
372 // Add the point in the list in increasing order.
373 const Standard_Real aParam = 0.5*(aParam1 + aParam2);
375 for(anIter.Initialize(aParams); anIter.More(); anIter.Next()) {
376 if (anIter.Value() > aParam) {
377 aParams.InsertBefore(aParam, anIter);
382 if (!anIter.More()) {
383 aParams.Append(aParam);
389 // Add start and end parameters to the list.
390 aParams.Prepend(myStart1);
391 aParams.Append(myEnd1);
392 anIter.Initialize(aParams);
394 // Perform each interval.
395 Standard_Real aStart = anIter.Value();
397 for (anIter.Next(); anIter.More(); anIter.Next()) {
398 const Standard_Real anEnd = anIter.Value();
400 // Perform the interval.
401 performInterval(aStart, anEnd, aNBSteps);
405 if (myResultParams.Extent())
406 return Standard_True;
408 return Standard_False;
411 //=======================================================================
412 //function : performInterval
414 //=======================================================================
415 void GEOMImpl_Fillet1d::performInterval(const Standard_Real theStart,
416 const Standard_Real theEnd,
417 const Standard_Integer theNBSteps)
419 Standard_Real aParam, aStep, aDStep;
420 aStep = (theEnd - theStart) / theNBSteps;
421 aDStep = aStep/1000.;
423 Standard_Integer aCycle;
424 for(aCycle = 2, myStartSide = Standard_False; aCycle; myStartSide = !myStartSide, aCycle--)
426 GEOMImpl_Fillet1dPoint *aLeft = NULL, *aRight = NULL;
428 for(aParam = theStart + aStep; aParam < theEnd || fabs(theEnd - aParam) < Precision::Confusion(); aParam += aStep)
432 aLeft = new GEOMImpl_Fillet1dPoint(aParam - aStep);
434 fillDiff(aLeft, aDStep, Standard_True);
437 aRight = new GEOMImpl_Fillet1dPoint(aParam);
439 fillDiff(aRight, aDStep, Standard_False);
441 aLeft->FilterPoints(aRight);
442 performNewton(aLeft, aRight);
451 //=======================================================================
452 //function : processPoint
454 //=======================================================================
455 Standard_Boolean GEOMImpl_Fillet1d::processPoint(GEOMImpl_Fillet1dPoint* theLeft,
456 GEOMImpl_Fillet1dPoint* theRight,
457 Standard_Real theParameter)
459 if (theParameter >= theLeft->GetParam() && theParameter < theRight->GetParam())
461 Standard_Real aDX = theRight->GetParam() - theLeft->GetParam();
462 if (theParameter - theLeft->GetParam() < aDX / 100.)
464 theParameter = theLeft->GetParam() + aDX / 100.;
466 if (theRight->GetParam() - theParameter < aDX / 100.)
468 theParameter = theRight->GetParam() - aDX / 100.;
471 // Protection on infinite loop.
472 myDegreeOfRecursion++;
473 Standard_Real diffx = 0.001 * aDX;
474 if (myDegreeOfRecursion > 1000)
477 if (myDegreeOfRecursion > 10000)
480 if (myDegreeOfRecursion > 100000)
482 return Standard_True;
487 GEOMImpl_Fillet1dPoint* aPoint1 = theLeft->Copy();
488 GEOMImpl_Fillet1dPoint* aPoint2 = new GEOMImpl_Fillet1dPoint(theParameter);
490 fillDiff(aPoint2, diffx, Standard_True);
492 aPoint1->FilterPoints(aPoint2);
493 performNewton(aPoint1, aPoint2);
494 aPoint2->FilterPoints(theRight);
495 performNewton(aPoint2, theRight);
499 return Standard_True;
502 return Standard_False;
505 //=======================================================================
506 //function : performNewton
508 //=======================================================================
509 void GEOMImpl_Fillet1d::performNewton(GEOMImpl_Fillet1dPoint* theLeft,
510 GEOMImpl_Fillet1dPoint* theRight)
513 // check the left: if this is solution store it and remove it from the list of researching points of theLeft
514 a = theLeft->HasSolution(myRadius);
517 if (theLeft->IsValid(a))
519 myResultParams.Append(theLeft->GetParam());
520 myResultOrientation.Append(myStartSide);
525 Standard_Real aDX = theRight->GetParam() - theLeft->GetParam();
526 if ( aDX < Precision::Confusion() / 1000000.)
528 a = theRight->HasSolution(myRadius);
530 if (theRight->IsValid(a))
532 myResultParams.Append(theRight->GetParam());
533 myResultOrientation.Append(myStartSide);
538 for(a = 1; a <= theLeft->GetNBValues(); a++)
540 Standard_Integer aNear = theLeft->GetNear(a);
542 Standard_Real aA = (theRight->GetDiff(aNear) - theLeft->GetDiff(a)) / aDX;
543 Standard_Real aB = theLeft->GetDiff(a) - aA * theLeft->GetParam();
544 Standard_Real aC = theLeft->GetValue(a) - theLeft->GetDiff(a) * theLeft->GetParam() +
545 aA * theLeft->GetParam() * theLeft->GetParam() / 2.0;
546 Standard_Real aDet = aB * aB - 2.0 * aA * aC;
548 if ( fabs(aDet) < gp::Resolution() )
551 if (fabs(aA) < Precision::Confusion())
553 if (fabs(aB) > 10e-20)
555 Standard_Real aX0 = - aC / aB; // use extremum
556 if (aX0 > theLeft->GetParam() && aX0 < theRight->GetParam())
557 processPoint(theLeft, theRight, aX0);
561 processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
566 if (fabs(aB) > fabs(aDet * 1000000.))
567 { // possible floating point operations accuracy errors
568 processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
575 Standard_Boolean aRes = processPoint(theLeft, theRight, (- aB + aDet) / aA);
577 aRes = processPoint(theLeft, theRight, (- aB - aDet) / aA);
579 processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
583 Standard_Real aX0 = - aB / aA; // use extremum
584 if (aX0 > theLeft->GetParam() && aX0 < theRight->GetParam())
585 processPoint(theLeft, theRight, aX0);
587 processPoint(theLeft, theRight, theLeft->GetParam() + aDX / 2.0); // linear division otherwise
594 //=======================================================================
597 //=======================================================================
598 TopoDS_Edge GEOMImpl_Fillet1d::Result(const gp_Pnt& thePoint,
599 TopoDS_Edge& theEdge1,
600 TopoDS_Edge& theEdge2)
603 gp_Pnt2d aTargetPoint2d;
604 Standard_Real aX, aY;
605 ElSLib::PlaneParameters(myPlane->Pln().Position(), thePoint, aX, aY);
606 aTargetPoint2d.SetCoord(aX, aY);
608 // choose the nearest circle
609 Standard_Real aDistance, aP;
610 GEOMImpl_Fillet1dPoint *aNearest;
612 TColStd_ListIteratorOfListOfReal anIter(myResultParams);
613 for(aNearest = NULL, a = 1; anIter.More(); anIter.Next(), a++)
615 myStartSide = (myResultOrientation.Value(a)) ? Standard_True : Standard_False;
616 GEOMImpl_Fillet1dPoint *aPoint = new GEOMImpl_Fillet1dPoint(anIter.Value());
618 if (!aPoint->HasSolution(myRadius))
620 aP = fabs(aPoint->GetCenter().Distance(aTargetPoint2d) - myRadius);
621 if (!aNearest || aP < aDistance)
635 // create circle edge
636 gp_Pnt aCenter = ElSLib::PlaneValue(aNearest->GetCenter().X(),
637 aNearest->GetCenter().Y(),
638 myPlane->Pln().Position());
639 Handle(Geom_Circle) aCircle =
640 new Geom_Circle(gp_Ax2(aCenter, myPlane->Pln().Axis().Direction()), myRadius);
641 gp_Pnt2d aPoint2d1, aPoint2d2;
642 myCurve1->D0(aNearest->GetParam(), aPoint2d1);
643 myCurve2->D0(aNearest->GetParam2(), aPoint2d2);
644 gp_Pnt aPoint1 = ElSLib::PlaneValue(aPoint2d1.X(), aPoint2d1.Y(), myPlane->Pln().Position());
645 gp_Pnt aPoint2 = ElSLib::PlaneValue(aPoint2d2.X(), aPoint2d2.Y(), myPlane->Pln().Position());
647 GeomAPI_ProjectPointOnCurve aProj(thePoint, aCircle);
648 Standard_Real aTarGetParam = aProj.LowerDistanceParameter();
649 gp_Pnt aPointOnCircle = aProj.NearestPoint();
651 // Check extrema point manually, because there is a bug in Open CASCADE
652 // in calculation of nearest point to a circle near the parameter 0.0
653 gp_Pnt p0 = ElCLib::Value(0.0, aCircle->Circ());
654 if (p0.Distance(thePoint) < aPointOnCircle.Distance(thePoint))
660 aProj.Perform(aPoint1);
661 Standard_Real aParam1 = aProj.LowerDistanceParameter();
662 aProj.Perform(aPoint2);
663 Standard_Real aParam2 = aProj.LowerDistanceParameter();
664 Standard_Boolean aIsOut = ((aParam1 < aTarGetParam && aParam2 < aTarGetParam) ||
665 (aParam1 > aTarGetParam && aParam2 > aTarGetParam));
666 if (aParam1 > aParam2)
668 BRepBuilderAPI_MakeEdge aBuilder(aCircle->Circ(),
669 aIsOut ? aParam2 : aParam1,
670 aIsOut? aParam1 : aParam2);
671 aResult = aBuilder.Edge();
674 Standard_Real aStart, anEnd;
675 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(myEdge1, aStart, anEnd);
677 aCurve->D1(aNearest->GetParam(), aPoint1, aDir);
680 aCircle->D1(aParam1, aPoint1, aCircleDir);
681 if ((aCircleDir.Angle(aDir) > M_PI / 2.0) ^ aIsOut)
682 aStart = aNearest->GetParam();
684 anEnd = aNearest->GetParam();
686 if (IsDivideEdge(myEdge1, aStart, anEnd))
689 BRepBuilderAPI_MakeEdge aDivider1(aCurve, aStart, anEnd);
691 theEdge2 = aDivider1.Edge();
693 theEdge1 = aDivider1.Edge();
696 aCurve = BRep_Tool::Curve(myEdge2, aStart, anEnd);
697 aCurve->D1(aNearest->GetParam2(), aPoint2, aDir);
699 aCircle->D1(aParam2, aPoint2, aCircleDir);
700 if ((aCircleDir.Angle(aDir) > M_PI / 2.0) ^ (!aIsOut))
701 aStart = aNearest->GetParam2();
703 anEnd = aNearest->GetParam2();
705 if (IsDivideEdge(myEdge2, aStart, anEnd))
707 BRepBuilderAPI_MakeEdge aDivider2(aCurve, aStart, anEnd);
709 theEdge1 = aDivider2.Edge();
711 theEdge2 = aDivider2.Edge();
718 //=======================================================================
719 //function : AddValue
721 //=======================================================================
722 void GEOMImpl_Fillet1dPoint::AddValue(Standard_Real theValue, Standard_Boolean theValid)
725 for(a = 1; a <= myV.Length(); a++)
727 if (theValue < myV.Value(a))
729 myV.InsertBefore(a, theValue);
730 myValid.InsertBefore(a, (Standard_Integer)theValid);
734 myV.Append(theValue);
735 myValid.Append((Standard_Integer)theValid);
738 //=======================================================================
739 //function : ComputeDifference
741 //=======================================================================
742 Standard_Boolean GEOMImpl_Fillet1dPoint::ComputeDifference(GEOMImpl_Fillet1dPoint* thePoint)
745 Standard_Boolean aDiffsSet = (myD.Length() != 0);
746 Standard_Real aDX = thePoint->GetParam() - myParam, aDY;
747 if (thePoint->myV.Length() == myV.Length())
748 { // absolutely the same points
749 for(a = 1; a <= myV.Length(); a++)
751 aDY = thePoint->myV.Value(a) - myV.Value(a);
753 myD.SetValue(a, fabs(aDX) > gp::Resolution() ? (aDY/aDX) : 0);
755 myD.Append( fabs(aDX) > gp::Resolution() ? (aDY/aDX) : 0);
757 return Standard_True;
759 // between the diffeerent points searching for nearest analogs
761 for(a = 1; a <= myV.Length(); a++)
763 for(b = 1; b <= thePoint->myV.Length(); b++)
765 if (b == 1 || fabs(thePoint->myV.Value(b) - myV.Value(a)) < fabs(aDY))
766 aDY = thePoint->myV.Value(b) - myV.Value(a);
770 if ( fabs(aDX) > gp::Resolution() && fabs(aDY / aDX) < fabs(myD.Value(a)))
771 myD.SetValue(a, aDY / aDX);
777 myD.Append( fabs(aDX) > gp::Resolution() ? aDY/aDX : 0);
781 return Standard_False;
784 //=======================================================================
785 //function : FilterPoints
787 //=======================================================================
788 void GEOMImpl_Fillet1dPoint::FilterPoints(GEOMImpl_Fillet1dPoint* thePoint)
790 Standard_Integer a, b;
791 TColStd_SequenceOfReal aDiffs;
792 Standard_Real aY, aY2, aDX = thePoint->GetParam() - myParam;
793 for(a = 1; a <= myV.Length(); a++)
795 // searching for near point from thePoint
796 Standard_Integer aNear = 0;
797 Standard_Real aDiff = aDX * 10000.;
798 aY = myV.Value(a) + myD.Value(a) * aDX;
799 for(b = 1; b <= thePoint->myV.Length(); b++)
801 // calculate hypothesis value of the Y2 with the constant first and second derivative
802 aY2 = aY + aDX * (thePoint->myD.Value(b) - myD.Value(a)) / 2.0;
803 if (aNear == 0 || fabs(aY2 - thePoint->myV.Value(b)) < fabs(aDiff))
806 aDiff = aY2 - thePoint->myV.Value(b);
812 if (myV.Value(a) * thePoint->myV.Value(aNear) > 0)
813 {// the same sign at the same sides of the interval
814 if (myV.Value(a) * myD.Value(a) > 0)
816 if (fabs(myD.Value(a)) > Precision::Confusion())
821 if (fabs(myV.Value(a)) > fabs(thePoint->myV.Value(aNear)))
822 if (thePoint->myV.Value(aNear) * thePoint->myD.Value(aNear) < 0 &&
823 fabs(thePoint->myD.Value(aNear)) > Precision::Confusion())
833 if (myV.Value(a) * thePoint->myV.Value(aNear) > 0)
835 if ((myV.Value(a) + myD.Value(a) * aDX) * myV.Value(a) > Precision::Confusion() &&
836 (thePoint->myV.Value(aNear) + thePoint->myD.Value(aNear) * aDX) * thePoint->myV.Value(aNear) > Precision::Confusion())
845 if ( fabs(aDX) < gp::Resolution() || fabs(aDiff / aDX) > 1.e+7)
852 { // there is no near: remove it from the list
860 Standard_Boolean aFound = Standard_False;
861 for(b = 1; b <= myNear.Length(); b++)
863 if (myNear.Value(b) == aNear)
865 if (fabs(aDiffs.Value(b)) < fabs(aDiff))
866 { // return this 'near'
867 aFound = Standard_True;
875 { // remove the old 'near'
888 myNear.Append(aNear);
889 aDiffs.Append(aDiff);
895 //=======================================================================
898 //=======================================================================
899 GEOMImpl_Fillet1dPoint* GEOMImpl_Fillet1dPoint::Copy()
901 GEOMImpl_Fillet1dPoint* aCopy = new GEOMImpl_Fillet1dPoint(myParam);
903 for(a = 1; a <= myV.Length(); a++)
905 aCopy->myV.Append(myV.Value(a));
906 aCopy->myD.Append(myD.Value(a));
907 aCopy->myValid.Append(myValid.Value(a));
912 //=======================================================================
913 //function : HasSolution
915 //=======================================================================
916 Standard_Integer GEOMImpl_Fillet1dPoint::HasSolution(const Standard_Real theRadius)
919 for(a = 1; a <= myV.Length(); a++)
921 if (fabs(sqrt(fabs(fabs(myV.Value(a)) + theRadius * theRadius)) - theRadius) < Precision::Confusion() / 10.)
927 //=======================================================================
928 //function : RemoveSolution
930 //=======================================================================
931 void GEOMImpl_Fillet1dPoint::RemoveSolution(Standard_Integer theIndex)
933 myV.Remove(theIndex);
934 myD.Remove(theIndex);
935 myValid.Remove(theIndex);
936 myNear.Remove(theIndex);