1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 // This file is part of Open CASCADE Technology software library.
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
14 #include <ChFi2d_AnaFilletAlgo.hxx>
18 #include <Standard_TypeMismatch.hxx>
20 #include <BRepBuilderAPI_MakeEdge.hxx>
21 #include <BRepBuilderAPI_MakeWire.hxx>
22 #include <BRepBuilderAPI_MakeFace.hxx>
24 #include <GeomAPI_ExtremaCurveCurve.hxx>
25 #include <IntAna2d_AnaIntersection.hxx>
26 #include <ShapeAnalysis_Wire.hxx>
27 #include <Geom_Circle.hxx>
29 #include <BRepAdaptor_Curve.hxx>
30 #include <BRep_Tool.hxx>
33 #include <TopoDS_Iterator.hxx>
35 #include <ProjLib.hxx>
39 // Compute the flag: CW || CCW
40 static Standard_Boolean isCW(const BRepAdaptor_Curve& AC)
42 const Standard_Real f = AC.FirstParameter();
43 const Standard_Real l = AC.LastParameter();
44 Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(AC.Curve().Curve());
45 gp_Pnt start = AC.Value(f);
46 gp_Pnt end = AC.Value(l);
47 gp_Pnt center = AC.Circle().Location();
48 gp_Ax3 plane = AC.Circle().Position();
50 // Get point on circle at half angle
52 circle->D0(0.5 * (f + l), m);
54 // Compare angles between vectors to middle point and to the end point.
55 gp_Vec startv(center, start), endv(center, end), middlev(center, m);
56 double middlea = startv.AngleWithRef(middlev, plane.Direction());
58 middlea += 2.0 * M_PI;
59 double enda = startv.AngleWithRef(endv, plane.Direction());
63 Standard_Boolean is_cw = middlea > enda ? Standard_True : Standard_False;
67 // Equality of points computed through square distance between the points.
68 static Standard_Boolean IsEqual(const gp_Pnt& p1, const gp_Pnt& p2)
70 return p1.SquareDistance(p2) < Precision::SquareConfusion();
72 static Standard_Boolean IsEqual(const gp_Pnt2d& p1, const gp_Pnt2d& p2)
74 return p1.SquareDistance(p2) < Precision::SquareConfusion();
77 // An empty constructor.
78 // Use the method Init() to initialize the class.
79 ChFi2d_AnaFilletAlgo::ChFi2d_AnaFilletAlgo()
80 : segment1(Standard_False),
89 segment2(Standard_False),
102 // It expects two edges having a common point of type:
105 ChFi2d_AnaFilletAlgo::ChFi2d_AnaFilletAlgo(const TopoDS_Wire& theWire,
106 const gp_Pln& thePlane)
108 segment1(Standard_False),
117 segment2(Standard_False),
127 Init(theWire, thePlane);
131 // It expects two edges having a common point of type:
134 ChFi2d_AnaFilletAlgo::ChFi2d_AnaFilletAlgo(const TopoDS_Edge& theEdge1,
135 const TopoDS_Edge& theEdge2,
136 const gp_Pln& thePlane)
138 segment1(Standard_False),
147 segment2(Standard_False),
157 // Make a wire consisting of two edges.
158 Init(theEdge1, theEdge2, thePlane);
161 // Initializes the class by a wire consisting of two edges.
162 void ChFi2d_AnaFilletAlgo::Init(const TopoDS_Wire& theWire, const gp_Pln& thePlane)
165 TopoDS_Iterator itr(theWire);
166 for (; itr.More(); itr.Next())
169 e1 = TopoDS::Edge(itr.Value());
170 else if (e2.IsNull())
171 e2 = TopoDS::Edge(itr.Value());
173 if (e1.IsNull() || e2.IsNull())
174 throw Standard_TypeMismatch("The algorithm expects a wire consisting of two linear or circular edges.");
177 BRepAdaptor_Curve AC1(e1);
178 if (AC1.GetType() != GeomAbs_Line && AC1.GetType() != GeomAbs_Circle)
179 throw Standard_TypeMismatch("A segment or an arc of circle is expected.");
181 TopoDS_Vertex v1, v2;
182 TopExp::Vertices(e1, v1, v2, Standard_True);
183 if (v1.IsNull() || v2.IsNull())
184 throw Standard_Failure("An infinite edge.");
186 gp_Pnt P1 = BRep_Tool::Pnt(v1);
187 gp_Pnt P2 = BRep_Tool::Pnt(v2);
188 gp_Pnt2d p1 = ProjLib::Project(thePlane, P1);
189 gp_Pnt2d p2 = ProjLib::Project(thePlane, P2);
194 if (AC1.GetType() == GeomAbs_Circle)
197 gp_Circ c = AC1.Circle();
199 gp_Pnt2d loc = ProjLib::Project(thePlane, c.Location());
202 radius1 = c.Radius();
207 BRepAdaptor_Curve AC2(e2);
208 if (AC2.GetType() != GeomAbs_Line && AC2.GetType() != GeomAbs_Circle)
209 throw Standard_TypeMismatch("A segment or an arc of circle is expected.");
211 TopExp::Vertices(e2, v1, v2, Standard_True);
212 if (v1.IsNull() || v2.IsNull())
213 throw Standard_Failure("An infinite edge.");
215 P1 = BRep_Tool::Pnt(v1);
216 P2 = BRep_Tool::Pnt(v2);
217 p1 = ProjLib::Project(thePlane, P1);
218 p2 = ProjLib::Project(thePlane, P2);
223 if (AC2.GetType() == GeomAbs_Circle)
226 gp_Circ c = AC2.Circle();
228 gp_Pnt2d loc = ProjLib::Project(thePlane, c.Location());
231 radius2 = c.Radius();
236 // Initializes the class by two edges.
237 void ChFi2d_AnaFilletAlgo::Init(const TopoDS_Edge& theEdge1, const TopoDS_Edge& theEdge2,
238 const gp_Pln& thePlane)
240 // Make a wire consisting of two edges.
243 TopoDS_Vertex v11, v12, v21, v22;
244 TopExp::Vertices(theEdge1, v11, v12, Standard_True);
245 TopExp::Vertices(theEdge2, v21, v22, Standard_True);
246 if (v11.IsNull() || v12.IsNull() || v21.IsNull() || v22.IsNull())
247 throw Standard_Failure("An infinite edge.");
249 gp_Pnt p11 = BRep_Tool::Pnt(v11);
250 gp_Pnt p12 = BRep_Tool::Pnt(v12);
251 gp_Pnt p21 = BRep_Tool::Pnt(v21);
252 gp_Pnt p22 = BRep_Tool::Pnt(v22);
255 if (IsEqual(p11, p21) || IsEqual(p11, p22))
259 else if (IsEqual(p12, p21) || IsEqual(p12, p22))
264 throw Standard_Failure("The edges have no common point.");
266 // Reverse the edges in case of need (to construct a wire).
267 Standard_Boolean is1stReversed(Standard_False), is2ndReversed(Standard_False);
268 if (IsEqual(pcommon, p11))
269 is1stReversed = Standard_True;
270 else if (IsEqual(pcommon, p22))
271 is2ndReversed = Standard_True;
274 BRepBuilderAPI_MakeWire mkWire;
276 mkWire.Add(TopoDS::Edge(theEdge1.Reversed()));
278 mkWire.Add(theEdge1);
280 mkWire.Add(TopoDS::Edge(theEdge2.Reversed()));
282 mkWire.Add(theEdge2);
283 if (!mkWire.IsDone())
284 throw Standard_Failure("Can't make a wire.");
286 const TopoDS_Wire& W = mkWire.Wire();
290 // Calculates a fillet.
291 Standard_Boolean ChFi2d_AnaFilletAlgo::Perform(const Standard_Real radius)
293 Standard_Boolean bRet(false);
294 if (e1.IsNull() || e2.IsNull() ||
295 radius < Precision::Confusion())
300 // Fillet definition.
301 Standard_Real xc = 0.0, yc = 0.0;
302 Standard_Real start = 0.0, end = 0.0; // parameters on neighbours
303 Standard_Real xstart = DBL_MAX, ystart = DBL_MAX; // point on left neighbour
304 Standard_Real xend = DBL_MAX, yend = DBL_MAX; // point on right neighbour
305 Standard_Boolean cw = Standard_False;
307 // Analytical algorithm works for non-intersecting arcs only.
308 // Check arcs on self-intersection.
309 Standard_Boolean isCut(Standard_False);
310 if (!segment1 || !segment2)
312 BRepBuilderAPI_MakeWire mkWire(e1, e2);
315 const TopoDS_Wire& W = mkWire.Wire();
316 BRepBuilderAPI_MakeFace mkFace(plane);
319 const TopoDS_Face& F = mkFace.Face();
320 ShapeAnalysis_Wire analyzer(W, F, Precision::Confusion());
321 if (analyzer.CheckSelfIntersection() == Standard_True)
323 // Cut the edges at the point of intersection.
324 isCut = Standard_True;
325 if (!Cut(plane, e1, e2))
327 return Standard_False;
332 }// a case of segment - segment
335 BRepAdaptor_Curve AC1(e1), AC2(e2);
336 if (segment1 && segment2)
338 bRet = SegmentFilletSegment(radius, xc, yc, cw, start, end);
340 else if (segment1 && !segment2)
342 bRet = SegmentFilletArc(radius, xc, yc, cw, start, end, xend, yend);
344 else if (!segment1 && segment2)
346 bRet = ArcFilletSegment(radius, xc, yc, cw, start, end, xstart, ystart);
348 else if (!segment1 && !segment2)
350 bRet = ArcFilletArc(radius, xc, yc, cw, start, end);
354 return Standard_False;
356 // Invert the fillet for left-handed plane.
357 if (plane.Position().Direct() == Standard_False)
360 // Construct a fillet.
362 gp_Pnt center = ElSLib::Value(xc, yc, plane);
363 const gp_Dir& normal = plane.Position().Direction();
364 gp_Circ circ(gp_Ax2(center, cw ? -normal : normal), radius);
366 // Fillet may only shrink a neighbour edge, it can't prolongate it.
367 const Standard_Real delta1 = AC1.LastParameter() - AC1.FirstParameter();
368 const Standard_Real delta2 = AC2.LastParameter() - AC2.FirstParameter();
369 if (!isCut && (start > delta1 || end > delta2))
371 // Check a case when a neighbour edge almost disappears:
372 // try to reduce the fillet radius for a little (1.e-5 mm).
373 const Standard_Real little = 100.0 * Precision::Confusion();
374 const Standard_Real d1 = fabs(start - delta1);
375 const Standard_Real d2 = fabs(end - delta2);
376 if (d1 < little || d2 < little)
378 if (segment1 && segment2)
380 bRet = SegmentFilletSegment(radius - little, xc, yc, cw, start, end);
382 else if (segment1 && !segment2)
384 bRet = SegmentFilletArc(radius - little, xc, yc, cw, start, end, xend, yend);
386 else if (!segment1 && segment2)
388 bRet = ArcFilletSegment(radius - little, xc, yc, cw, start, end, xstart, ystart);
390 else if (!segment1 && !segment2)
392 bRet = ArcFilletArc(radius - little, xc, yc, cw, start, end);
396 // Invert the fillet for left-handed planes.
397 if (plane.Position().Direct() == Standard_False)
400 // Make the circle again.
401 center = ElSLib::Value(xc, yc, plane);
402 circ.SetLocation(center);
403 circ.SetRadius(radius - little);
407 return Standard_False;
412 return Standard_False;
417 // start: (xstart, ystart) - pstart.
419 if (xstart != DBL_MAX)
421 pstart = ElSLib::Value(xstart, ystart, plane);
425 if (e1.Orientation() == TopAbs_FORWARD)
426 pstart = AC1.Value(AC1.LastParameter() - start);
428 pstart = AC1.Value(AC1.FirstParameter() + start);
430 // end: (xend, yend) -> pend.
434 pend = ElSLib::Value(xend, yend, plane);
438 if (e2.Orientation() == TopAbs_FORWARD)
439 pend = AC2.Value(AC2.FirstParameter() + end);
441 pend = AC2.Value(AC2.LastParameter() - end);
445 BRepBuilderAPI_MakeEdge mkEdge(circ, pstart, pend);
446 bRet = mkEdge.IsDone();
449 fillet = mkEdge.Edge();
451 // Limit the neighbours.
455 if (e1.Orientation() == TopAbs_FORWARD)
457 p1 = AC1.Value(AC1.FirstParameter());
463 p2 = AC1.Value(AC1.LastParameter());
467 BRepBuilderAPI_MakeEdge mkSegment1;
468 mkSegment1.Init(AC1.Curve().Curve(), p1, p2);
469 if (mkSegment1.IsDone())
470 shrinke1 = mkSegment1.Edge();
474 BRepBuilderAPI_MakeEdge mkCirc1;
475 mkCirc1.Init(AC1.Curve().Curve(), p1, p2);
476 if (mkCirc1.IsDone())
477 shrinke1 = mkCirc1.Edge();
482 if (e1.Orientation() == TopAbs_FORWARD)
485 p2 = AC2.Value(AC2.LastParameter());
489 p1 = AC2.Value(AC2.FirstParameter());
494 BRepBuilderAPI_MakeEdge mkSegment2;
495 mkSegment2.Init(AC2.Curve().Curve(), p1, p2);
496 if (mkSegment2.IsDone())
497 shrinke2 = mkSegment2.Edge();
501 BRepBuilderAPI_MakeEdge mkCirc2;
502 mkCirc2.Init(AC2.Curve().Curve(), p1, p2);
503 if (mkCirc2.IsDone())
504 shrinke2 = mkCirc2.Edge();
507 bRet = !shrinke1.IsNull() && !shrinke2.IsNull();
508 }// fillet edge is done
509 }// shrinking is good
514 // Retrieves a result (fillet and shrinked neighbours).
515 const TopoDS_Edge& ChFi2d_AnaFilletAlgo::Result(TopoDS_Edge& theE1, TopoDS_Edge& theE2)
522 // WW5 method to compute fillet.
523 // It returns a constructed fillet definition:
524 // center point (xc, yc)
525 // point on the 1st segment (xstart, ystart)
526 // point on the 2nd segment (xend, yend)
527 // is the arc of fillet clockwise (cw = true) or counterclockwise (cw = false).
528 Standard_Boolean ChFi2d_AnaFilletAlgo::SegmentFilletSegment(const Standard_Real radius,
529 Standard_Real& xc, Standard_Real& yc,
530 Standard_Boolean& cw,
531 Standard_Real& start, Standard_Real& end)
533 // Make normalized vectors at p12.
534 gp_Pnt2d p11(x11, y11);
535 gp_Pnt2d p12(x12, y12);
536 gp_Pnt2d p22(x22, y22);
538 // Check length of segments.
539 if (IsEqual(p12, p11) || IsEqual(p12, p22))
541 return Standard_False;
545 gp_Vec2d v1(p12, p11);
546 gp_Vec2d v2(p12, p22);
551 gp_Vec2d bisec = 0.5 * (v1 + v2);
553 // Check bisectrissa.
554 if (bisec.SquareMagnitude() < Precision::SquareConfusion())
555 return Standard_False;
557 // Normalize the bisectrissa.
560 // Angle at bisectrissa.
561 Standard_Real beta = v1.Angle(bisec);
563 // Length along the bisectrissa till the center of fillet.
564 Standard_Real L = radius / sin(fabs(beta));
566 // Center point of fillet.
567 gp_Pnt2d pc = p12.Translated(L * bisec);
570 // Shrinking length along segments.
571 start = sqrt(L * L - radius * radius);
574 // Orientation of fillet.
576 return Standard_True;
579 // A function constructs a fillet between a segment and an arc.
580 Standard_Boolean ChFi2d_AnaFilletAlgo::SegmentFilletArc(const Standard_Real radius,
581 Standard_Real& xc, Standard_Real& yc,
582 Standard_Boolean& cw,
583 Standard_Real& start, Standard_Real& end,
584 Standard_Real& xend, Standard_Real& yend)
586 // Make a line parallel to the segment at the side of center point of fillet.
587 // This side may be defined through making a bisectrissa for vectors at p12 (or p21).
590 gp_Pnt2d p12(x12, y12);
591 gp_Pnt2d p11(x11, y11);
592 gp_Pnt2d pc2(xc2, yc2);
594 // Check length of segment.
595 if (p11.SquareDistance(p12) < gp::Resolution())
596 return Standard_False;
599 gp_Vec2d v1(p12, p11);
600 gp_Vec2d v2(p12, pc2);
602 // Rotate the arc vector to become tangential at p21.
608 // If vectors coincide (segment and arc are tangent),
609 // the algorithm doesn't work...
610 Standard_Real angle = v1.Angle(v2);
611 if (fabs(angle) < Precision::Angular())
612 return Standard_False;
614 // Make a bissectrisa of vectors at p12.
617 gp_Vec2d bisec = 0.5 * (v1 + v2);
619 // If segment and arc look in opposite direction,
620 // no fillet is possible.
621 if (bisec.SquareMagnitude() < gp::Resolution())
622 return Standard_False;
624 // Define an appropriate point to choose center of fillet.
626 gp_Pnt2d nearp = p12.Translated(radius * bisec);
627 gp_Lin2d nearl(p12, bisec);
629 // Make a line parallel to segment and
630 // passing near the "near" point.
632 gp_Lin2d line(p11, -d1);
634 line.Translate(radius * d1);
635 if (line.Distance(nearp) > radius)
636 line.Translate(-2.0 * radius * d1);
638 // Make a circle of radius of the arc +/- fillet radius.
639 gp_Ax2d axes(pc2, gp::DX2d());
640 gp_Circ2d circ(axes, radius2 + radius);
641 if (radius2 > radius && circ.Distance(nearp) > radius)
642 circ.SetRadius(radius2 - radius);
644 // Calculate intersection of the line and the circle.
645 IntAna2d_AnaIntersection intersector(line, circ);
646 if (!intersector.IsDone() || !intersector.NbPoints())
647 return Standard_False;
649 // Find center point of fillet.
651 Standard_Real minDist = DBL_MAX;
652 for (i = 1; i <= intersector.NbPoints(); ++i)
654 const IntAna2d_IntPoint& intp = intersector.Point(i);
655 const gp_Pnt2d& p = intp.Value();
657 Standard_Real d = nearl.Distance(p);
665 // Shrink of segment.
667 Standard_Real L2 = pc.SquareDistance(p12);
668 const Standard_Real Rf2 = radius * radius;
669 start = sqrt(L2 - Rf2);
672 gp_Vec2d pcc(pc2, pc);
673 end = fabs(gp_Vec2d(pc2, p12).Angle(pcc));
675 // Duplicate the information on shrink the arc:
676 // calculate a point on the arc coinciding with the end of fillet.
677 line.SetLocation(pc2);
678 line.SetDirection(pcc);
679 circ.SetLocation(pc2);
680 circ.SetRadius(radius2);
681 intersector.Perform(line, circ);
682 if (!intersector.IsDone() || !intersector.NbPoints())
683 return Standard_False;
687 for (i = 1; i <= intersector.NbPoints(); ++i)
689 const IntAna2d_IntPoint& intp = intersector.Point(i);
690 const gp_Pnt2d& p = intp.Value();
692 const Standard_Real d2 = p.SquareDistance(pc);
693 if (fabs(d2 - Rf2) < Precision::Confusion())
700 // Orientation of the fillet.
701 angle = v1.Angle(v2);
703 return Standard_True;
706 // A function constructs a fillet between an arc and a segment.
707 Standard_Boolean ChFi2d_AnaFilletAlgo::ArcFilletSegment(const Standard_Real radius,
708 Standard_Real& xc, Standard_Real& yc,
709 Standard_Boolean& cw,
710 Standard_Real& start, Standard_Real& end,
711 Standard_Real& xstart, Standard_Real& ystart)
713 // Make a line parallel to the segment at the side of center point of fillet.
714 // This side may be defined through making a bisectrissa for vectors at p12 (or p21).
717 gp_Pnt2d p12(x12, y12);
718 gp_Pnt2d p22(x22, y22);
719 gp_Pnt2d pc1(xc1, yc1);
721 // Check length of segment.
722 if (p12.SquareDistance(p22) < gp::Resolution())
723 return Standard_False;
726 gp_Vec2d v1(p12, pc1);
727 gp_Vec2d v2(p12, p22);
729 // Rotate the arc vector to become tangential at p21.
735 // If vectors coincide (segment and arc are tangent),
736 // the algorithm doesn't work...
737 Standard_Real angle = v1.Angle(v2);
738 if (fabs(angle) < Precision::Angular())
739 return Standard_False;
741 // Make a bisectrissa of vectors at p12.
744 gp_Vec2d bisec = 0.5 * (v1 + v2);
746 // If segment and arc look in opposite direction,
747 // no fillet is possible.
748 if (bisec.SquareMagnitude() < gp::Resolution())
749 return Standard_False;
751 // Define an appropriate point to choose center of fillet.
753 gp_Pnt2d nearPoint = p12.Translated(radius * bisec);
754 gp_Lin2d nearLine(p12, bisec);
756 // Make a line parallel to segment and
757 // passing near the "near" point.
759 gp_Lin2d line(p22, -aD2Vec);
760 aD2Vec.Rotate(M_PI_2);
761 line.Translate(radius * aD2Vec);
762 if (line.Distance(nearPoint) > radius)
763 line.Translate(-2.0 * radius * aD2Vec);
765 // Make a circle of radius of the arc +/- fillet radius.
766 gp_Ax2d axes(pc1, gp::DX2d());
767 gp_Circ2d circ(axes, radius1 + radius);
768 if (radius1 > radius && circ.Distance(nearPoint) > radius)
769 circ.SetRadius(radius1 - radius);
771 // Calculate intersection of the line and the big circle.
772 IntAna2d_AnaIntersection intersector(line, circ);
773 if (!intersector.IsDone() || !intersector.NbPoints())
774 return Standard_False;
776 // Find center point of fillet.
778 Standard_Real minDist = DBL_MAX;
779 for (i = 1; i <= intersector.NbPoints(); ++i)
781 const IntAna2d_IntPoint& intp = intersector.Point(i);
782 const gp_Pnt2d& p = intp.Value();
784 Standard_Real d = nearLine.Distance(p);
792 // Shrink of segment.
794 Standard_Real L2 = pc.SquareDistance(p12);
795 const Standard_Real Rf2 = radius * radius;
796 end = sqrt(L2 - Rf2);
799 gp_Vec2d pcc(pc1, pc);
800 start = fabs(gp_Vec2d(pc1, p12).Angle(pcc));
802 // Duplicate the information on shrink the arc:
803 // calculate a point on the arc coinciding with the start of fillet.
804 line.SetLocation(pc1);
805 line.SetDirection(pcc);
806 circ.SetLocation(pc1);
807 circ.SetRadius(radius1);
808 intersector.Perform(line, circ);
809 if (!intersector.IsDone() || !intersector.NbPoints())
810 return Standard_False;
814 for (i = 1; i <= intersector.NbPoints(); ++i)
816 const IntAna2d_IntPoint& intp = intersector.Point(i);
817 const gp_Pnt2d& p = intp.Value();
819 const Standard_Real d2 = p.SquareDistance(pc);
820 if (fabs(d2 - Rf2) < Precision::SquareConfusion())
822 p.Coord(xstart, ystart);
827 // Orientation of the fillet.
828 angle = v2.Angle(v1);
830 return Standard_True;
833 // WW5 method to compute fillet: arc - arc.
834 // It returns a constructed fillet definition:
835 // center point (xc, yc)
836 // shrinking parameter of the 1st circle (start)
837 // shrinking parameter of the 2nd circle (end)
838 // if the arc of fillet clockwise (cw = true) or counterclockwise (cw = false).
839 Standard_Boolean ChFi2d_AnaFilletAlgo::ArcFilletArc(const Standard_Real radius,
840 Standard_Real& xc, Standard_Real& yc,
841 Standard_Boolean& cw,
842 Standard_Real& start, Standard_Real& end)
845 const gp_Pnt2d pc1(xc1, yc1);
846 const gp_Pnt2d pc2(xc2, yc2);
847 const gp_Pnt2d p12(x12, y12);
849 // Make vectors at p12.
850 gp_Vec2d v1(pc1, p12);
851 gp_Vec2d v2(pc2, p12);
853 // Rotate the vectors so that they are tangent to circles at p12.
863 // Make a "check" point for choosing an offset circle.
866 gp_Vec2d bisec = 0.5 * (v1 + v2);
867 if (bisec.SquareMagnitude() < gp::Resolution())
868 return Standard_False;
870 const gp_Pnt2d checkp = p12.Translated(radius * bisec);
871 const gp_Lin2d checkl(p12, bisec);
873 // Make two circles of radius r1 +/- r and r2 +/- r
874 // with center point equal to pc1 and pc2.
876 gp_Ax2d axes(pc1, gp::DX2d());
877 gp_Circ2d c1(axes, radius1 + radius);
878 if (radius1 > radius && c1.Distance(checkp) > radius)
879 c1.SetRadius(radius1 - radius);
881 axes.SetLocation(pc2);
882 gp_Circ2d c2(axes, radius2 + radius);
883 if (radius2 > radius && c2.Distance(checkp) > radius)
884 c2.SetRadius(radius2 - radius);
886 // Calculate an intersection point of these two circles
887 // and choose the one closer to the "check" point.
888 IntAna2d_AnaIntersection intersector(c1, c2);
889 if (!intersector.IsDone() || !intersector.NbPoints())
890 return Standard_False;
892 // Find center point of fillet.
894 Standard_Real minDist = DBL_MAX;
895 for (int i = 1; i <= intersector.NbPoints(); ++i)
897 const IntAna2d_IntPoint& intp = intersector.Point(i);
898 const gp_Pnt2d& p = intp.Value();
900 Standard_Real d = checkp.SquareDistance(p);
909 // Orientation of fillet.
910 Standard_Real angle = v1.Angle(v2);
911 if (fabs(angle) < Precision::Angular())
913 angle = gp_Vec2d(pc, pc1).Angle(gp_Vec2d(pc, pc2));
921 // Shrinking of circles.
922 start = fabs(gp_Vec2d(pc1, p12).Angle(gp_Vec2d(pc1, pc)));
923 end = fabs(gp_Vec2d(pc2, p12).Angle(gp_Vec2d(pc2, pc)));
924 return Standard_True;
927 // Cuts intersecting edges of a contour.
928 Standard_Boolean ChFi2d_AnaFilletAlgo::Cut(const gp_Pln& thePlane, TopoDS_Edge& theE1, TopoDS_Edge& theE2)
931 Standard_Boolean found(Standard_False);
932 Standard_Real param1 = 0.0, param2 = 0.0;
933 Standard_Real f1, l1, f2, l2;
934 Handle(Geom_Curve) c1 = BRep_Tool::Curve(theE1, f1, l1);
935 Handle(Geom_Curve) c2 = BRep_Tool::Curve(theE2, f2, l2);
936 GeomAPI_ExtremaCurveCurve extrema(c1, c2, f1, l1, f2, l2);
937 if (extrema.NbExtrema())
939 Standard_Integer i, nb = extrema.NbExtrema();
940 for (i = 1; i <= nb; ++i)
942 const Standard_Real d = extrema.Distance(i);
943 if (d < Precision::Confusion())
945 extrema.Parameters(i, param1, param2);
946 if (fabs(l1 - param1) > Precision::Confusion() &&
947 fabs(f2 - param2) > Precision::Confusion())
949 found = Standard_True;
950 extrema.Points(i, p, p);
959 BRepBuilderAPI_MakeEdge mkEdge1(c1, f1, param1);
960 if (mkEdge1.IsDone())
962 theE1 = mkEdge1.Edge();
964 BRepBuilderAPI_MakeEdge mkEdge2(c2, param2, l2);
965 if (mkEdge2.IsDone())
967 theE2 = mkEdge2.Edge();
969 gp_Pnt2d p2d = ProjLib::Project(thePlane, p);
973 return Standard_True;
977 return Standard_False;