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>
17 #include <gp_Circ.hxx>
18 #include <gp_Lin2d.hxx>
19 #include <gp_Circ2d.hxx>
21 #include <Standard_TypeMismatch.hxx>
23 #include <BRepBuilderAPI_MakeEdge.hxx>
24 #include <BRepBuilderAPI_MakeWire.hxx>
25 #include <BRepBuilderAPI_MakeFace.hxx>
27 #include <GeomAPI_ExtremaCurveCurve.hxx>
28 #include <IntAna2d_AnaIntersection.hxx>
29 #include <ShapeAnalysis_Wire.hxx>
30 #include <Geom_Circle.hxx>
32 #include <BRepAdaptor_Curve.hxx>
33 #include <BRep_Tool.hxx>
36 #include <TopoDS_Iterator.hxx>
38 #include <ProjLib.hxx>
42 // Compute the flag: CW || CCW
43 static Standard_Boolean isCW(const BRepAdaptor_Curve& AC)
45 const Standard_Real f = AC.FirstParameter();
46 const Standard_Real l = AC.LastParameter();
47 Handle(Geom_Circle) circle = Handle(Geom_Circle)::DownCast(AC.Curve().Curve());
48 gp_Pnt start = AC.Value(f);
49 gp_Pnt end = AC.Value(l);
50 gp_Pnt center = AC.Circle().Location();
51 gp_Ax3 plane = AC.Circle().Position();
53 // Get point on circle at half angle
55 circle->D0(0.5 * (f + l), m);
57 // Compare angles between vectors to middle point and to the end point.
58 gp_Vec startv(center, start), endv(center, end), middlev(center, m);
59 double middlea = startv.AngleWithRef(middlev, plane.Direction());
61 middlea += 2.0 * M_PI;
62 double enda = startv.AngleWithRef(endv, plane.Direction());
66 Standard_Boolean is_cw = middlea > enda ? Standard_True : Standard_False;
70 // Equality of points computed through square distance between the points.
71 static Standard_Boolean IsEqual(const gp_Pnt& p1, const gp_Pnt& p2)
73 return p1.SquareDistance(p2) < Precision::SquareConfusion();
75 static Standard_Boolean IsEqual(const gp_Pnt2d& p1, const gp_Pnt2d& p2)
77 return p1.SquareDistance(p2) < Precision::SquareConfusion();
80 // An empty constructor.
81 // Use the method Init() to initialize the class.
82 ChFi2d_AnaFilletAlgo::ChFi2d_AnaFilletAlgo()
88 // It expects two edges having a common point of type:
91 ChFi2d_AnaFilletAlgo::ChFi2d_AnaFilletAlgo(const TopoDS_Wire& theWire,
92 const gp_Pln& thePlane)
94 Init(theWire, thePlane);
98 // It expects two edges having a common point of type:
101 ChFi2d_AnaFilletAlgo::ChFi2d_AnaFilletAlgo(const TopoDS_Edge& theEdge1,
102 const TopoDS_Edge& theEdge2,
103 const gp_Pln& thePlane)
105 // Make a wire consisting of two edges.
106 Init(theEdge1, theEdge2, thePlane);
109 // Initializes the class by a wire consisting of two edges.
110 void ChFi2d_AnaFilletAlgo::Init(const TopoDS_Wire& theWire, const gp_Pln& thePlane)
113 TopoDS_Iterator itr(theWire);
114 for (; itr.More(); itr.Next())
117 e1 = TopoDS::Edge(itr.Value());
118 else if (e2.IsNull())
119 e2 = TopoDS::Edge(itr.Value());
121 if (e1.IsNull() || e2.IsNull())
122 Standard_TypeMismatch::Raise("The algorithm expects a wire consisting of two linear or circular edges.");
125 BRepAdaptor_Curve AC1(e1);
126 if (AC1.GetType() != GeomAbs_Line && AC1.GetType() != GeomAbs_Circle)
127 Standard_TypeMismatch::Raise("A segment or an arc of circle is expected.");
129 TopoDS_Vertex v1, v2;
130 TopExp::Vertices(e1, v1, v2, Standard_True);
131 if (v1.IsNull() || v2.IsNull())
132 Standard_Failure::Raise("An infinite edge.");
134 gp_Pnt P1 = BRep_Tool::Pnt(v1);
135 gp_Pnt P2 = BRep_Tool::Pnt(v2);
136 gp_Pnt2d p1 = ProjLib::Project(thePlane, P1);
137 gp_Pnt2d p2 = ProjLib::Project(thePlane, P2);
142 if (AC1.GetType() == GeomAbs_Circle)
145 gp_Circ c = AC1.Circle();
147 gp_Pnt2d loc = ProjLib::Project(thePlane, c.Location());
150 radius1 = c.Radius();
155 BRepAdaptor_Curve AC2(e2);
156 if (AC2.GetType() != GeomAbs_Line && AC2.GetType() != GeomAbs_Circle)
157 Standard_TypeMismatch::Raise("A segment or an arc of circle is expected.");
159 TopExp::Vertices(e2, v1, v2, Standard_True);
160 if (v1.IsNull() || v2.IsNull())
161 Standard_Failure::Raise("An infinite edge.");
163 P1 = BRep_Tool::Pnt(v1);
164 P2 = BRep_Tool::Pnt(v2);
165 p1 = ProjLib::Project(thePlane, P1);
166 p2 = ProjLib::Project(thePlane, P2);
171 if (AC2.GetType() == GeomAbs_Circle)
174 gp_Circ c = AC2.Circle();
176 gp_Pnt2d loc = ProjLib::Project(thePlane, c.Location());
179 radius2 = c.Radius();
184 // Initializes the class by two edges.
185 void ChFi2d_AnaFilletAlgo::Init(const TopoDS_Edge& theEdge1, const TopoDS_Edge& theEdge2,
186 const gp_Pln& thePlane)
188 // Make a wire consisting of two edges.
191 TopoDS_Vertex v11, v12, v21, v22;
192 TopExp::Vertices(theEdge1, v11, v12, Standard_True);
193 TopExp::Vertices(theEdge2, v21, v22, Standard_True);
194 if (v11.IsNull() || v12.IsNull() || v21.IsNull() || v22.IsNull())
195 Standard_Failure::Raise("An infinite edge.");
197 gp_Pnt p11 = BRep_Tool::Pnt(v11);
198 gp_Pnt p12 = BRep_Tool::Pnt(v12);
199 gp_Pnt p21 = BRep_Tool::Pnt(v21);
200 gp_Pnt p22 = BRep_Tool::Pnt(v22);
203 if (IsEqual(p11, p21) || IsEqual(p11, p22))
207 else if (IsEqual(p12, p21) || IsEqual(p12, p22))
212 Standard_Failure::Raise("The edges have no common point.");
214 // Reverse the edges in case of need (to construct a wire).
215 Standard_Boolean is1stReversed(Standard_False), is2ndReversed(Standard_False);
216 if (IsEqual(pcommon, p11))
217 is1stReversed = Standard_True;
218 else if (IsEqual(pcommon, p22))
219 is2ndReversed = Standard_True;
222 BRepBuilderAPI_MakeWire mkWire;
224 mkWire.Add(TopoDS::Edge(theEdge1.Reversed()));
226 mkWire.Add(theEdge1);
228 mkWire.Add(TopoDS::Edge(theEdge2.Reversed()));
230 mkWire.Add(theEdge2);
231 if (!mkWire.IsDone())
232 Standard_Failure::Raise("Can't make a wire.");
234 const TopoDS_Wire& W = mkWire.Wire();
238 // Calculates a fillet.
239 Standard_Boolean ChFi2d_AnaFilletAlgo::Perform(const Standard_Real radius)
241 Standard_Boolean bRet(false);
242 if (e1.IsNull() || e2.IsNull() ||
243 radius < Precision::Confusion())
248 // Fillet definition.
249 Standard_Real xc = 0.0, yc = 0.0;
250 Standard_Real start = 0.0, end = 0.0; // parameters on neighbours
251 Standard_Real xstart = DBL_MAX, ystart = DBL_MAX; // point on left neighbour
252 Standard_Real xend = DBL_MAX, yend = DBL_MAX; // point on right neighbour
253 Standard_Boolean cw = Standard_False;
255 // Analytical algorithm works for non-intersecting arcs only.
256 // Check arcs on self-intersection.
257 Standard_Boolean isCut(Standard_False);
258 if (!segment1 || !segment2)
260 BRepBuilderAPI_MakeWire mkWire(e1, e2);
263 const TopoDS_Wire& W = mkWire.Wire();
264 BRepBuilderAPI_MakeFace mkFace(plane);
267 const TopoDS_Face& F = mkFace.Face();
268 ShapeAnalysis_Wire analyzer(W, F, Precision::Confusion());
269 if (analyzer.CheckSelfIntersection() == Standard_True)
271 // Cut the edges at the point of intersection.
272 isCut = Standard_True;
273 if (!Cut(plane, e1, e2))
275 return Standard_False;
280 }// a case of segment - segment
283 BRepAdaptor_Curve AC1(e1), AC2(e2);
284 if (segment1 && segment2)
286 bRet = SegmentFilletSegment(radius, xc, yc, cw, start, end);
288 else if (segment1 && !segment2)
290 bRet = SegmentFilletArc(radius, xc, yc, cw, start, end, xend, yend);
292 else if (!segment1 && segment2)
294 bRet = ArcFilletSegment(radius, xc, yc, cw, start, end, xstart, ystart);
296 else if (!segment1 && !segment2)
298 bRet = ArcFilletArc(radius, xc, yc, cw, start, end);
302 return Standard_False;
304 // Invert the fillet for left-handed plane.
305 if (plane.Position().Direct() == Standard_False)
308 // Construct a fillet.
310 gp_Pnt center = ElSLib::Value(xc, yc, plane);
311 const gp_Dir& normal = plane.Position().Direction();
312 gp_Circ circ(gp_Ax2(center, cw ? -normal : normal), radius);
314 // Fillet may only shrink a neighbour edge, it can't prolongate it.
315 const Standard_Real delta1 = AC1.LastParameter() - AC1.FirstParameter();
316 const Standard_Real delta2 = AC2.LastParameter() - AC2.FirstParameter();
317 if (!isCut && (start > delta1 || end > delta2))
319 // Check a case when a neighbour edge almost disappears:
320 // try to reduce the fillet radius for a little (1.e-5 mm).
321 const Standard_Real little = 100.0 * Precision::Confusion();
322 const Standard_Real d1 = fabs(start - delta1);
323 const Standard_Real d2 = fabs(end - delta2);
324 if (d1 < little || d2 < little)
326 if (segment1 && segment2)
328 bRet = SegmentFilletSegment(radius - little, xc, yc, cw, start, end);
330 else if (segment1 && !segment2)
332 bRet = SegmentFilletArc(radius - little, xc, yc, cw, start, end, xend, yend);
334 else if (!segment1 && segment2)
336 bRet = ArcFilletSegment(radius - little, xc, yc, cw, start, end, xstart, ystart);
338 else if (!segment1 && !segment2)
340 bRet = ArcFilletArc(radius - little, xc, yc, cw, start, end);
344 // Invert the fillet for left-handed planes.
345 if (plane.Position().Direct() == Standard_False)
348 // Make the circle again.
349 center = ElSLib::Value(xc, yc, plane);
350 circ.SetLocation(center);
351 circ.SetRadius(radius - little);
355 return Standard_False;
360 return Standard_False;
365 // start: (xstart, ystart) - pstart.
367 if (xstart != DBL_MAX)
369 pstart = ElSLib::Value(xstart, ystart, plane);
373 if (e1.Orientation() == TopAbs_FORWARD)
374 pstart = AC1.Value(AC1.LastParameter() - start);
376 pstart = AC1.Value(AC1.FirstParameter() + start);
378 // end: (xend, yend) -> pend.
382 pend = ElSLib::Value(xend, yend, plane);
386 if (e2.Orientation() == TopAbs_FORWARD)
387 pend = AC2.Value(AC2.FirstParameter() + end);
389 pend = AC2.Value(AC2.LastParameter() - end);
393 BRepBuilderAPI_MakeEdge mkEdge(circ, pstart, pend);
394 bRet = mkEdge.IsDone();
397 fillet = mkEdge.Edge();
399 // Limit the neighbours.
404 BRepBuilderAPI_MakeEdge mkSegment1;
405 if (e1.Orientation() == TopAbs_FORWARD)
406 mkSegment1.Init(AC1.Curve().Curve(), AC1.FirstParameter(), AC1.LastParameter() - start);
408 mkSegment1.Init(AC1.Curve().Curve(), AC1.FirstParameter() + start, AC1.LastParameter());
409 if (mkSegment1.IsDone())
410 shrinke1 = mkSegment1.Edge();
414 BRepBuilderAPI_MakeEdge mkCirc1;
415 if (e1.Orientation() == TopAbs_FORWARD)
416 mkCirc1.Init(AC1.Curve().Curve(), AC1.FirstParameter(), AC1.LastParameter() - start);
418 mkCirc1.Init(AC1.Curve().Curve(), AC1.FirstParameter() + start, AC1.LastParameter());
419 if (mkCirc1.IsDone())
420 shrinke1 = mkCirc1.Edge();
427 BRepBuilderAPI_MakeEdge mkSegment2;
428 if (e2.Orientation() == TopAbs_FORWARD)
429 mkSegment2.Init(AC2.Curve().Curve(), AC2.FirstParameter() + end, AC2.LastParameter());
431 mkSegment2.Init(AC2.Curve().Curve(), AC2.FirstParameter(), AC2.LastParameter() - end);
432 if (mkSegment2.IsDone())
433 shrinke2 = mkSegment2.Edge();
437 BRepBuilderAPI_MakeEdge mkCirc2;
438 if (e2.Orientation() == TopAbs_FORWARD)
439 mkCirc2.Init(AC2.Curve().Curve(), AC2.FirstParameter() + end, AC2.LastParameter());
441 mkCirc2.Init(AC2.Curve().Curve(), AC2.FirstParameter(), AC2.LastParameter() - end);
442 if (mkCirc2.IsDone())
443 shrinke2 = mkCirc2.Edge();
446 bRet = !shrinke1.IsNull() && !shrinke2.IsNull();
447 }// fillet edge is done
448 }// shrinking is good
453 // Retrieves a result (fillet and shrinked neighbours).
454 const TopoDS_Edge& ChFi2d_AnaFilletAlgo::Result(TopoDS_Edge& theE1, TopoDS_Edge& theE2)
461 // WW5 method to compute fillet.
462 // It returns a constructed fillet definition:
463 // center point (xc, yc)
464 // point on the 1st segment (xstart, ystart)
465 // point on the 2nd segment (xend, yend)
466 // is the arc of fillet clockwise (cw = true) or counterclockwise (cw = false).
467 Standard_Boolean ChFi2d_AnaFilletAlgo::SegmentFilletSegment(const Standard_Real radius,
468 Standard_Real& xc, Standard_Real& yc,
469 Standard_Boolean& cw,
470 Standard_Real& start, Standard_Real& end)
472 // Make normalized vectors at p12.
473 gp_Pnt2d p11(x11, y11);
474 gp_Pnt2d p12(x12, y12);
475 gp_Pnt2d p22(x22, y22);
477 // Check length of segments.
478 if (IsEqual(p12, p11) || IsEqual(p12, p22))
480 return Standard_False;
484 gp_Vec2d v1(p12, p11);
485 gp_Vec2d v2(p12, p22);
490 gp_Vec2d bisec = 0.5 * (v1 + v2);
492 // Check bisectrissa.
493 if (bisec.SquareMagnitude() < Precision::SquareConfusion())
494 return Standard_False;
496 // Normalize the bisectrissa.
499 // Angle at bisectrissa.
500 Standard_Real beta = v1.Angle(bisec);
502 // Length along the bisectrissa till the center of fillet.
503 Standard_Real L = radius / sin(fabs(beta));
505 // Center point of fillet.
506 gp_Pnt2d pc = p12.Translated(L * bisec);
509 // Shrinking length along segments.
510 start = sqrt(L * L - radius * radius);
513 // Orientation of fillet.
515 return Standard_True;
518 // A function constructs a fillet between a segment and an arc.
519 Standard_Boolean ChFi2d_AnaFilletAlgo::SegmentFilletArc(const Standard_Real radius,
520 Standard_Real& xc, Standard_Real& yc,
521 Standard_Boolean& cw,
522 Standard_Real& start, Standard_Real& end,
523 Standard_Real& xend, Standard_Real& yend)
525 // Make a line parallel to the segment at the side of center point of fillet.
526 // This side may be defined through making a bisectrissa for vectors at p12 (or p21).
529 gp_Pnt2d p12(x12, y12);
530 gp_Pnt2d p11(x11, y11);
531 gp_Pnt2d pc2(xc2, yc2);
533 // Check length of segment.
534 if (p11.SquareDistance(p12) < gp::Resolution())
535 return Standard_False;
538 gp_Vec2d v1(p12, p11);
539 gp_Vec2d v2(p12, pc2);
541 // Rotate the arc vector to become tangential at p21.
547 // If vectors coincide (segment and arc are tangent),
548 // the algorithm doesn't work...
549 Standard_Real angle = v1.Angle(v2);
550 if (fabs(angle) < Precision::Angular())
551 return Standard_False;
553 // Make a bissectrisa of vectors at p12.
556 gp_Vec2d bisec = 0.5 * (v1 + v2);
558 // If segment and arc look in opposite direction,
559 // no fillet is possible.
560 if (bisec.SquareMagnitude() < gp::Resolution())
561 return Standard_False;
563 // Define an appropriate point to choose center of fillet.
565 gp_Pnt2d nearp = p12.Translated(radius * bisec);
566 gp_Lin2d nearl(p12, bisec);
568 // Make a line parallel to segment and
569 // passing near the "near" point.
571 gp_Lin2d line(p11, -d1);
573 line.Translate(radius * d1);
574 if (line.Distance(nearp) > radius)
575 line.Translate(-2.0 * radius * d1);
577 // Make a circle of radius of the arc +/- fillet radius.
578 gp_Ax2d axes(pc2, gp::DX2d());
579 gp_Circ2d circ(axes, radius2 + radius);
580 if (radius2 > radius && circ.Distance(nearp) > radius)
581 circ.SetRadius(radius2 - radius);
583 // Calculate intersection of the line and the circle.
584 IntAna2d_AnaIntersection intersector(line, circ);
585 if (!intersector.IsDone() || !intersector.NbPoints())
586 return Standard_False;
588 // Find center point of fillet.
590 Standard_Real minDist = DBL_MAX;
591 for (i = 1; i <= intersector.NbPoints(); ++i)
593 const IntAna2d_IntPoint& intp = intersector.Point(i);
594 const gp_Pnt2d& p = intp.Value();
596 Standard_Real d = nearl.Distance(p);
604 // Shrink of segment.
606 Standard_Real L2 = pc.SquareDistance(p12);
607 const Standard_Real Rf2 = radius * radius;
608 start = sqrt(L2 - Rf2);
611 gp_Vec2d pcc(pc2, pc);
612 end = fabs(gp_Vec2d(pc2, p12).Angle(pcc));
614 // Duplicate the information on shrink the arc:
615 // calculate a point on the arc coinciding with the end of fillet.
616 line.SetLocation(pc2);
617 line.SetDirection(pcc);
618 circ.SetLocation(pc2);
619 circ.SetRadius(radius2);
620 intersector.Perform(line, circ);
621 if (!intersector.IsDone() || !intersector.NbPoints())
622 return Standard_False;
626 for (i = 1; i <= intersector.NbPoints(); ++i)
628 const IntAna2d_IntPoint& intp = intersector.Point(i);
629 const gp_Pnt2d& p = intp.Value();
631 const Standard_Real d2 = p.SquareDistance(pc);
632 if (fabs(d2 - Rf2) < Precision::Confusion())
639 // Orientation of the fillet.
640 angle = v1.Angle(v2);
642 return Standard_True;
645 // A function constructs a fillet between an arc and a segment.
646 Standard_Boolean ChFi2d_AnaFilletAlgo::ArcFilletSegment(const Standard_Real radius,
647 Standard_Real& xc, Standard_Real& yc,
648 Standard_Boolean& cw,
649 Standard_Real& start, Standard_Real& end,
650 Standard_Real& xstart, Standard_Real& ystart)
652 // Make a line parallel to the segment at the side of center point of fillet.
653 // This side may be defined through making a bisectrissa for vectors at p12 (or p21).
656 gp_Pnt2d p12(x12, y12);
657 gp_Pnt2d p22(x22, y22);
658 gp_Pnt2d pc1(xc1, yc1);
660 // Check length of segment.
661 if (p12.SquareDistance(p22) < gp::Resolution())
662 return Standard_False;
665 gp_Vec2d v1(p12, pc1);
666 gp_Vec2d v2(p12, p22);
668 // Rotate the arc vector to become tangential at p21.
674 // If vectors coincide (segment and arc are tangent),
675 // the algorithm doesn't work...
676 Standard_Real angle = v1.Angle(v2);
677 if (fabs(angle) < Precision::Angular())
678 return Standard_False;
680 // Make a bisectrissa of vectors at p12.
683 gp_Vec2d bisec = 0.5 * (v1 + v2);
685 // If segment and arc look in opposite direction,
686 // no fillet is possible.
687 if (bisec.SquareMagnitude() < gp::Resolution())
688 return Standard_False;
690 // Define an appropriate point to choose center of fillet.
692 gp_Pnt2d nearPoint = p12.Translated(radius * bisec);
693 gp_Lin2d nearLine(p12, bisec);
695 // Make a line parallel to segment and
696 // passing near the "near" point.
698 gp_Lin2d line(p22, -d2);
700 line.Translate(radius * d2);
701 if (line.Distance(nearPoint) > radius)
702 line.Translate(-2.0 * radius * d2);
704 // Make a circle of radius of the arc +/- fillet radius.
705 gp_Ax2d axes(pc1, gp::DX2d());
706 gp_Circ2d circ(axes, radius1 + radius);
707 if (radius1 > radius && circ.Distance(nearPoint) > radius)
708 circ.SetRadius(radius1 - radius);
710 // Calculate intersection of the line and the big circle.
711 IntAna2d_AnaIntersection intersector(line, circ);
712 if (!intersector.IsDone() || !intersector.NbPoints())
713 return Standard_False;
715 // Find center point of fillet.
717 Standard_Real minDist = DBL_MAX;
718 for (i = 1; i <= intersector.NbPoints(); ++i)
720 const IntAna2d_IntPoint& intp = intersector.Point(i);
721 const gp_Pnt2d& p = intp.Value();
723 Standard_Real d = nearLine.Distance(p);
731 // Shrink of segment.
733 Standard_Real L2 = pc.SquareDistance(p12);
734 const Standard_Real Rf2 = radius * radius;
735 end = sqrt(L2 - Rf2);
738 gp_Vec2d pcc(pc1, pc);
739 start = fabs(gp_Vec2d(pc1, p12).Angle(pcc));
741 // Duplicate the information on shrink the arc:
742 // calculate a point on the arc coinciding with the start of fillet.
743 line.SetLocation(pc1);
744 line.SetDirection(pcc);
745 circ.SetLocation(pc1);
746 circ.SetRadius(radius1);
747 intersector.Perform(line, circ);
748 if (!intersector.IsDone() || !intersector.NbPoints())
749 return Standard_False;
753 for (i = 1; i <= intersector.NbPoints(); ++i)
755 const IntAna2d_IntPoint& intp = intersector.Point(i);
756 const gp_Pnt2d& p = intp.Value();
758 const Standard_Real d2 = p.SquareDistance(pc);
759 if (fabs(d2 - Rf2) < Precision::SquareConfusion())
761 p.Coord(xstart, ystart);
766 // Orientation of the fillet.
767 angle = v2.Angle(v1);
769 return Standard_True;
772 // WW5 method to compute fillet: arc - arc.
773 // It returns a constructed fillet definition:
774 // center point (xc, yc)
775 // shrinking parameter of the 1st circle (start)
776 // shrinking parameter of the 2nd circle (end)
777 // if the arc of fillet clockwise (cw = true) or counterclockwise (cw = false).
778 Standard_Boolean ChFi2d_AnaFilletAlgo::ArcFilletArc(const Standard_Real radius,
779 Standard_Real& xc, Standard_Real& yc,
780 Standard_Boolean& cw,
781 Standard_Real& start, Standard_Real& end)
784 const gp_Pnt2d pc1(xc1, yc1);
785 const gp_Pnt2d pc2(xc2, yc2);
786 const gp_Pnt2d p12(x12, y12);
788 // Make vectors at p12.
789 gp_Vec2d v1(pc1, p12);
790 gp_Vec2d v2(pc2, p12);
792 // Rotate the vectors so that they are tangent to circles at p12.
802 // Make a "check" point for choosing an offset circle.
805 gp_Vec2d bisec = 0.5 * (v1 + v2);
806 if (bisec.SquareMagnitude() < gp::Resolution())
807 return Standard_False;
809 const gp_Pnt2d checkp = p12.Translated(radius * bisec);
810 const gp_Lin2d checkl(p12, bisec);
812 // Make two circles of radius r1 +/- r and r2 +/- r
813 // with center point equal to pc1 and pc2.
815 gp_Ax2d axes(pc1, gp::DX2d());
816 gp_Circ2d c1(axes, radius1 + radius);
817 if (radius1 > radius && c1.Distance(checkp) > radius)
818 c1.SetRadius(radius1 - radius);
820 axes.SetLocation(pc2);
821 gp_Circ2d c2(axes, radius2 + radius);
822 if (radius2 > radius && c2.Distance(checkp) > radius)
823 c2.SetRadius(radius2 - radius);
825 // Calculate an intersection point of these two circles
826 // and choose the one closer to the "check" point.
827 IntAna2d_AnaIntersection intersector(c1, c2);
828 if (!intersector.IsDone() || !intersector.NbPoints())
829 return Standard_False;
831 // Find center point of fillet.
833 Standard_Real minDist = DBL_MAX;
834 for (int i = 1; i <= intersector.NbPoints(); ++i)
836 const IntAna2d_IntPoint& intp = intersector.Point(i);
837 const gp_Pnt2d& p = intp.Value();
839 Standard_Real d = checkp.SquareDistance(p);
848 // Orientation of fillet.
849 Standard_Real angle = v1.Angle(v2);
850 if (fabs(angle) < Precision::Angular())
852 angle = gp_Vec2d(pc, pc1).Angle(gp_Vec2d(pc, pc2));
860 // Shrinking of circles.
861 start = fabs(gp_Vec2d(pc1, p12).Angle(gp_Vec2d(pc1, pc)));
862 end = fabs(gp_Vec2d(pc2, p12).Angle(gp_Vec2d(pc2, pc)));
863 return Standard_True;
866 // Cuts intersecting edges of a contour.
867 Standard_Boolean ChFi2d_AnaFilletAlgo::Cut(const gp_Pln& thePlane, TopoDS_Edge& theE1, TopoDS_Edge& theE2)
870 Standard_Boolean found(Standard_False);
871 Standard_Real param1 = 0.0, param2 = 0.0;
872 Standard_Real f1, l1, f2, l2;
873 Handle(Geom_Curve) c1 = BRep_Tool::Curve(theE1, f1, l1);
874 Handle(Geom_Curve) c2 = BRep_Tool::Curve(theE2, f2, l2);
875 GeomAPI_ExtremaCurveCurve extrema(c1, c2, f1, l1, f2, l2);
876 if (extrema.NbExtrema())
878 Standard_Integer i, nb = extrema.NbExtrema();
879 for (i = 1; i <= nb; ++i)
881 const Standard_Real d = extrema.Distance(i);
882 if (d < Precision::Confusion())
884 extrema.Parameters(i, param1, param2);
885 if (fabs(l1 - param1) > Precision::Confusion() &&
886 fabs(f2 - param2) > Precision::Confusion())
888 found = Standard_True;
889 extrema.Points(i, p, p);
898 BRepBuilderAPI_MakeEdge mkEdge1(c1, f1, param1);
899 if (mkEdge1.IsDone())
901 theE1 = mkEdge1.Edge();
903 BRepBuilderAPI_MakeEdge mkEdge2(c2, param2, l2);
904 if (mkEdge2.IsDone())
906 theE2 = mkEdge2.Edge();
908 gp_Pnt2d p2d = ProjLib::Project(thePlane, p);
912 return Standard_True;
916 return Standard_False;