Salome HOME
Task 3.3 Build/Edge and Build/Wire on a whole Sketch (issue #3083)
[modules/shaper.git] / src / GeomAPI / GeomAPI_Edge.cpp
1 // Copyright (C) 2014-2019  CEA/DEN, EDF R&D
2 //
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.
7 //
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.
12 //
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
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include<GeomAPI_Edge.h>
21 #include<GeomAPI_Pln.h>
22 #include<GeomAPI_Pnt.h>
23 #include<GeomAPI_Circ.h>
24 #include<GeomAPI_Dir.h>
25 #include<GeomAPI_Lin.h>
26 #include<GeomAPI_Ax2.h>
27 #include<GeomAPI_Ellipse.h>
28 #include<GeomAPI_Vertex.h>
29
30 #include <BRepAdaptor_Curve.hxx>
31
32 #include <TopoDS_Shape.hxx>
33 #include <TopoDS_Edge.hxx>
34 #include <TopoDS.hxx>
35 #include <BRep_Builder.hxx>
36 #include <BRep_Tool.hxx>
37 #include <ElCLib.hxx>
38 #include <GCPnts_UniformAbscissa.hxx>
39 #include <Geom_Curve.hxx>
40 #include <Geom_Line.hxx>
41 #include <Geom_Circle.hxx>
42 #include <Geom_TrimmedCurve.hxx>
43 #include <Geom_Ellipse.hxx>
44 #include <Geom_Plane.hxx>
45 #include <GeomAPI_ExtremaCurveCurve.hxx>
46 #include <GeomAPI_ExtremaCurveSurface.hxx>
47 #include <GeomAPI_IntCS.hxx>
48 #include <GeomAdaptor_Curve.hxx>
49 #include <gp_Ax1.hxx>
50 #include <gp_Pln.hxx>
51 #include <gp_Elips.hxx>
52 #include <TopExp.hxx>
53
54 #include <GCPnts_AbscissaPoint.hxx>
55
56 GeomAPI_Edge::GeomAPI_Edge()
57 {
58   TopoDS_Edge* anEdge = new TopoDS_Edge;
59
60   BRep_Builder aBuilder;
61   aBuilder.MakeEdge(*anEdge);
62
63   setImpl(anEdge);
64 }
65
66 GeomAPI_Edge::GeomAPI_Edge(const std::shared_ptr<GeomAPI_Shape>& theShape)
67 {
68   if (!theShape->isNull() && theShape->isEdge()) {
69     setImpl(new TopoDS_Shape(theShape->impl<TopoDS_Shape>()));
70   }
71 }
72
73 void GeomAPI_Edge::vertices(std::shared_ptr<GeomAPI_Vertex>& theStartVertex,
74                             std::shared_ptr<GeomAPI_Vertex>& theEndVertex) const
75 {
76   const TopoDS_Edge& anEdge = impl<TopoDS_Edge>();
77   TopoDS_Vertex aStart, aEnd;
78   TopExp::Vertices(anEdge, aStart, aEnd);
79   theStartVertex.reset(new GeomAPI_Vertex);
80   theStartVertex->setImpl(new TopoDS_Vertex(aStart));
81   theEndVertex.reset(new GeomAPI_Vertex);
82   theEndVertex->setImpl(new TopoDS_Vertex(aEnd));
83 }
84
85 static Handle(Geom_Curve) baseCurve(const TopoDS_Edge& theEdge)
86 {
87   double aFirst, aLast;
88   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(theEdge, aFirst, aLast);
89   while (aCurve->IsKind(STANDARD_TYPE(Geom_TrimmedCurve))) {
90     Handle(Geom_TrimmedCurve) tc = Handle(Geom_TrimmedCurve)::DownCast(aCurve);
91     aCurve = tc->BasisCurve();
92   }
93   return aCurve;
94 }
95
96 bool GeomAPI_Edge::isSameGeometry(const std::shared_ptr<GeomAPI_Shape> theShape) const
97 {
98   if (!theShape->isEdge())
99     return false;
100   if (isSame(theShape))
101     return true;
102
103   TopoDS_Edge anOwnEdge = TopoDS::Edge(impl<TopoDS_Shape>());
104   TopoDS_Edge anOtherEdge = TopoDS::Edge(theShape->impl<TopoDS_Shape>());
105
106   Handle(Geom_Curve) anOwnCurve = baseCurve(anOwnEdge);
107   Handle(Geom_Curve) anOtherCurve = baseCurve(anOtherEdge);
108   GeomAPI_ExtremaCurveCurve anExtrema(anOwnCurve, anOtherCurve);
109
110   bool isSame = anExtrema.Extrema().IsParallel() &&
111                 anExtrema.TotalLowerDistance() < Precision::Confusion();
112   return isSame;
113 }
114
115 bool GeomAPI_Edge::isLine() const
116 {
117   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
118   double aFirst, aLast;
119   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
120   if (aCurve.IsNull()) // degenerative edge
121     return false;
122   if (aCurve->IsKind(STANDARD_TYPE(Geom_Line)))
123     return true;
124   return false;
125 }
126
127 /// extracts a circle curve from the arbitrary curve, returns null is it is different type
128 static Handle(Geom_Circle) circ(const Handle(Geom_Curve) theCurve)
129 {
130   Handle(Geom_Circle) aResult = Handle(Geom_Circle)::DownCast(theCurve);
131   if (!aResult.IsNull())
132     return aResult;
133   // check this may be a trimmed curve that contains circle inside
134   Handle(Geom_TrimmedCurve) aTrimmed = Handle(Geom_TrimmedCurve)::DownCast(theCurve);
135   while(!aTrimmed.IsNull()) {
136     aResult = Handle(Geom_Circle)::DownCast(aTrimmed->BasisCurve());
137     if (!aResult.IsNull())
138       return aResult;
139     aTrimmed = Handle(Geom_TrimmedCurve)::DownCast(aTrimmed->BasisCurve());
140   }
141   return aResult; // null, not circle
142 }
143
144 bool GeomAPI_Edge::isCircle() const
145 {
146   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
147   double aFirst, aLast;
148   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
149   if (!circ(aCurve).IsNull()) {
150     // Check the difference of first and last parameters to be equal to the curve period
151     if (Abs(aLast - aFirst - aCurve->Period()) < Precision::PConfusion())
152       return true;
153   }
154   return false;
155 }
156
157 bool GeomAPI_Edge::isArc() const
158 {
159   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
160   double aFirst, aLast;
161   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
162   if (!circ(aCurve).IsNull()) {
163     // Check the difference of first and last parameters is not equal the curve period
164     if (Abs(aLast - aFirst - aCurve->Period()) >= Precision::PConfusion())
165       return true;
166   }
167   return false;
168 }
169
170 bool GeomAPI_Edge::isEllipse() const
171 {
172   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
173   double aFirst, aLast;
174   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
175   if (aCurve.IsNull()) // degenerative edge
176     return false;
177   if (aCurve->IsKind(STANDARD_TYPE(Geom_Ellipse)))
178     return true;
179   return false;
180 }
181
182 std::shared_ptr<GeomAPI_Pnt> GeomAPI_Edge::firstPoint()
183 {
184   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
185   double aFirst, aLast;
186   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
187   gp_Pnt aPoint;
188   aCurve->D0(aFirst, aPoint);
189   return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aPoint.X(), aPoint.Y(), aPoint.Z()));
190 }
191
192 std::shared_ptr<GeomAPI_Pnt> GeomAPI_Edge::lastPoint()
193 {
194   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
195   double aFirst, aLast;
196   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
197   gp_Pnt aPoint;
198   aCurve->D0(aLast, aPoint);
199   return std::shared_ptr<GeomAPI_Pnt>(new GeomAPI_Pnt(aPoint.X(), aPoint.Y(), aPoint.Z()));
200 }
201
202 std::shared_ptr<GeomAPI_Circ> GeomAPI_Edge::circle() const
203 {
204   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
205   double aFirst, aLast;
206   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
207   Handle(Geom_Circle) aCirc = circ(aCurve);
208   if (!aCirc.IsNull()) {
209     gp_Pnt aLoc = aCirc->Location();
210     std::shared_ptr<GeomAPI_Pnt> aCenter(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z()));
211     gp_Dir anAxis = aCirc->Axis().Direction();
212     std::shared_ptr<GeomAPI_Dir> aDir(new GeomAPI_Dir(anAxis.X(), anAxis.Y(), anAxis.Z()));
213     return std::shared_ptr<GeomAPI_Circ>(new GeomAPI_Circ(aCenter, aDir, aCirc->Radius()));
214   }
215   return std::shared_ptr<GeomAPI_Circ>(); // not circle
216 }
217
218 std::shared_ptr<GeomAPI_Ellipse> GeomAPI_Edge::ellipse() const
219 {
220   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
221   double aFirst, aLast;
222   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
223   if (!aCurve.IsNull()) {
224     Handle(Geom_Ellipse) aElips = Handle(Geom_Ellipse)::DownCast(aCurve);
225     if (!aElips.IsNull()) {
226       gp_Elips aGpElips = aElips->Elips();
227       std::shared_ptr<GeomAPI_Ellipse> aEllipse(new GeomAPI_Ellipse());
228       aEllipse->setImpl(new gp_Elips(aGpElips));
229       return aEllipse;
230     }
231   }
232   return std::shared_ptr<GeomAPI_Ellipse>(); // not ellipse
233 }
234
235 std::shared_ptr<GeomAPI_Lin> GeomAPI_Edge::line() const
236 {
237   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
238   double aFirst, aLast;
239   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
240   if (aCurve) {
241     Handle(Geom_Line) aLine = Handle(Geom_Line)::DownCast(aCurve);
242     if (aLine) {
243       gp_Pnt aStartPnt = aLine->Value(aFirst);
244       std::shared_ptr<GeomAPI_Pnt> aStart(
245           new GeomAPI_Pnt(aStartPnt.X(), aStartPnt.Y(), aStartPnt.Z()));
246       gp_Pnt aEndPnt = aLine->Value(aLast);
247       std::shared_ptr<GeomAPI_Pnt> aEnd(
248           new GeomAPI_Pnt(aEndPnt.X(), aEndPnt.Y(), aEndPnt.Z()));
249       return std::shared_ptr<GeomAPI_Lin>(new GeomAPI_Lin(aStart, aEnd));
250     }
251   }
252   return std::shared_ptr<GeomAPI_Lin>(); // not circle
253 }
254
255
256 bool GeomAPI_Edge::isEqual(const std::shared_ptr<GeomAPI_Shape> theEdge) const
257 {
258   if (!theEdge.get() || ! theEdge->isEdge())
259     return false;
260   const TopoDS_Shape& aMyShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
261   const TopoDS_Shape& aInShape = theEdge->impl<TopoDS_Shape>();
262
263   if (aMyShape.IsNull() || aInShape.IsNull())
264     return false;
265
266   if (aMyShape.ShapeType() != aInShape.ShapeType())
267     return false;
268
269   double aMyStart, aMyEnd;
270   Handle(Geom_Curve) aMyCurve = BRep_Tool::Curve(TopoDS::Edge(aMyShape), aMyStart, aMyEnd);
271   double aInStart, aInEnd;
272   Handle(Geom_Curve) aInCurve = BRep_Tool::Curve(TopoDS::Edge(aInShape), aInStart, aInEnd);
273
274   // Check that end point parameters are the same
275   if ((aMyStart != aInStart) || (aMyEnd != aInEnd))
276     return false;
277
278   // Check that curves a the same type
279   GeomAdaptor_Curve aMyAdaptor(aMyCurve);
280   GeomAdaptor_Curve aInAdaptor(aInCurve);
281   if (aMyAdaptor.GetType() != aInAdaptor.GetType())
282     return false;
283
284   // Check that end points are equal
285   gp_Pnt aMyPnt1 = aMyAdaptor.Value(aMyStart);
286   gp_Pnt aMyPnt2 = aMyAdaptor.Value(aMyEnd);
287   gp_Pnt aInPnt1 = aInAdaptor.Value(aInStart);
288   gp_Pnt aInPnt2 = aInAdaptor.Value(aInEnd);
289
290   if ((!aMyPnt1.IsEqual(aInPnt1, Precision::Confusion())) ||
291     (!aMyPnt2.IsEqual(aInPnt2, Precision::Confusion())))
292     return false;
293
294   return true;
295 }
296
297 // LCOV_EXCL_START
298 void GeomAPI_Edge::getRange(double& theFirst, double& theLast) const
299 {
300   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
301   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, theFirst, theLast);
302 }
303
304 bool GeomAPI_Edge::isInPlane(std::shared_ptr<GeomAPI_Pln> thePlane) const
305 {
306   double aFirst, aLast;
307   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
308   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
309   if (aCurve.IsNull())
310     return false;
311
312   double A, B, C, D;
313   thePlane->coefficients(A, B, C, D);
314   gp_Pln aPlane(A, B, C, D);
315
316   bool inPlane = false;
317   if (aCurve->IsKind(STANDARD_TYPE(Geom_Line))) {
318     // check start and end points on the plane
319     gp_Pnt aFirstPnt = aCurve->Value(aFirst);
320     gp_Pnt aLastPnt = aCurve->Value(aLast);
321     inPlane = aPlane.SquareDistance(aFirstPnt) < Precision::SquareConfusion() &&
322               aPlane.SquareDistance(aLastPnt) < Precision::SquareConfusion();
323   } else {
324     Handle(Geom_Circle) aCirc = circ(aCurve);
325     if (!aCirc.IsNull()) {
326       gp_Pnt aCenter = aCirc->Location();
327       Standard_Real aDot = aPlane.Axis().Direction().Dot(aCirc->Axis().Direction());
328       inPlane = aPlane.SquareDistance(aCenter) < Precision::SquareConfusion() &&
329                 Abs(Abs(aDot) - 1.0) < Precision::Confusion();
330     } else {
331       // three points checking
332       gp_Pnt aFirstPnt = aCurve->Value(aFirst);
333       gp_Pnt aMidPnt = aCurve->Value((aFirst + aLast) / 2.);
334       gp_Pnt aLastPnt = aCurve->Value(aLast);
335       inPlane = aPlane.SquareDistance(aFirstPnt) < Precision::SquareConfusion() &&
336                 aPlane.SquareDistance(aMidPnt) < Precision::SquareConfusion() &&
337                 aPlane.SquareDistance(aLastPnt) < Precision::SquareConfusion();
338     }
339   }
340   return inPlane;
341 }
342 // LCOV_EXCL_STOP
343
344 void GeomAPI_Edge::intersectWithPlane(const std::shared_ptr<GeomAPI_Pln> thePlane,
345                                       std::list<std::shared_ptr<GeomAPI_Pnt>>& theResult) const
346 {
347   double aFirst, aLast;
348   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
349   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
350   if (!aCurve.IsNull()) {
351     double A, B, C, D;
352     thePlane->coefficients(A, B, C, D);
353     gp_Pln aPln(A, B, C, D);
354     Handle(Geom_Plane) aPlane = new Geom_Plane(aPln);
355
356     // intersect the plane with the curve
357     GeomAPI_IntCS aIntersect;
358     aIntersect.Perform(aCurve, aPlane);
359     if (aIntersect.IsDone() && (aIntersect.NbPoints() > 0)) {
360       gp_Pnt aPnt;
361       for (int i = 1; i <= aIntersect.NbPoints(); i++) {
362         // check the parameter of intersection in the edge range
363         aIntersect.Parameters(i, A, B, C);
364         if (aCurve->IsPeriodic())
365           C = ElCLib::InPeriod(C, aFirst, aFirst + aCurve->Period());
366         if (C < aFirst - Precision::PConfusion() || C > aLast + Precision::PConfusion())
367           continue;
368
369         // obtain intersection point
370         aPnt = aIntersect.Point(i);
371         std::shared_ptr<GeomAPI_Pnt> aPntPtr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
372         theResult.push_back(aPntPtr);
373       }
374     }
375     else {
376       // find minimal distance between the plane and the curve
377       GeomAPI_ExtremaCurveSurface anExtrema(aCurve, aPlane);
378       double aTolerance = BRep_Tool::Tolerance(TopoDS::Edge(aShape));
379       if (anExtrema.NbExtrema() > 0 &&
380           anExtrema.LowerDistance() < aTolerance) {
381         // distance is lower than tolerance => tangent case
382         gp_Pnt aPntC, aPntS;
383         anExtrema.NearestPoints(aPntC, aPntS);
384         std::shared_ptr<GeomAPI_Pnt> aPntPtr(new GeomAPI_Pnt(aPntS.X(), aPntS.Y(), aPntS.Z()));
385         theResult.push_back(aPntPtr);
386       }
387     }
388   }
389 }
390
391 double GeomAPI_Edge::length() const
392 {
393   const TopoDS_Edge& anEdge = TopoDS::Edge(impl<TopoDS_Shape>());
394   BRepAdaptor_Curve aBRepAdaptor = BRepAdaptor_Curve(anEdge);
395   Adaptor3d_Curve* anAdaptor3d = &aBRepAdaptor;
396   return GCPnts_AbscissaPoint::Length(*anAdaptor3d);
397 }
398
399 bool GeomAPI_Edge::isClosed() const
400 {
401   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
402   if (aShape.IsNull())
403     return false;
404   double aFirst, aLast;
405   Handle(Geom_Curve) aCurve = BRep_Tool::Curve((const TopoDS_Edge&)aShape, aFirst, aLast);
406   if (aCurve.IsNull() || !aCurve->IsPeriodic())
407     return false;
408   aLast += aLast > aFirst ? -aCurve->Period() : aCurve->Period();;
409
410   return fabs(aFirst - aLast) < 1.e-9;
411 }
412
413 bool GeomAPI_Edge::isDegenerated() const
414 {
415   const TopoDS_Shape& aShape = const_cast<GeomAPI_Edge*>(this)->impl<TopoDS_Shape>();
416   if (aShape.IsNull() || aShape.ShapeType() != TopAbs_EDGE)
417     return false;
418   return BRep_Tool::Degenerated(TopoDS::Edge(aShape));
419 }
420
421 void GeomAPI_Edge::setFirstPointTolerance(const double theTolerance)
422 {
423   TopoDS_Edge anEdge = impl<TopoDS_Edge>();
424   TopoDS_Vertex aVFirst, aVLast;
425   TopExp::Vertices(anEdge, aVFirst, aVLast);
426   BRep_Builder().UpdateVertex(aVFirst, theTolerance);
427 }
428
429 void GeomAPI_Edge::setLastPointTolerance(const double theTolerance)
430 {
431   TopoDS_Edge anEdge = impl<TopoDS_Edge>();
432   TopoDS_Vertex aVFirst, aVLast;
433   TopExp::Vertices(anEdge, aVFirst, aVLast);
434   BRep_Builder().UpdateVertex(aVLast, theTolerance);
435 }
436
437 GeomPointPtr GeomAPI_Edge::middlePoint() const
438 {
439   GeomPointPtr aMiddlePoint;
440
441   const TopoDS_Edge& anEdge = impl<TopoDS_Edge>();
442   if (anEdge.IsNull())
443     return aMiddlePoint;
444   double aFirst, aLast;
445   Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
446   if (aCurve.IsNull())
447     return aMiddlePoint;
448
449   static const int NB_POINTS = 3;
450   GeomAdaptor_Curve aCurveAdaptor(aCurve, aFirst, aLast);
451   GCPnts_UniformAbscissa anAlgo(aCurveAdaptor, NB_POINTS);
452   if (anAlgo.IsDone()) {
453     gp_Pnt aPnt = aCurveAdaptor.Value(anAlgo.Parameter(2));
454     aMiddlePoint = GeomPointPtr(new GeomAPI_Pnt(aPnt.X(), aPnt.Y(), aPnt.Z()));
455   }
456   return aMiddlePoint;
457 }