0030346: Modeling Algorithms - BRepPrimAPI_MakeRevol throws "BRepSweep_Translation...
[occt.git] / src / BRepTest / BRepTest_Fillet2DCommands.cxx
1 // Created by: Joelle CHAUVET
2 // Copyright (c) 1996-1999 Matra Datavision
3 // Copyright (c) 1999-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 // Modified:    Tue Oct 15 10:12:02 1996
17 //              Add ChFi2d_TangencyError (PRO3529)
18 // Modified:    Fri Sep 25 09:38:04 1998
19 //              status = ChFi2d_NotAuthorized if edges are not
20 //              lines or circles  (BUC60288) + partial_result
21
22
23 #include <TColgp_Array1OfPnt2d.hxx>
24 #include <BRepTest.hxx>
25 #include <DBRep.hxx>
26 #include <Draw_Interpretor.hxx>
27 #include <Draw_Appli.hxx>
28 #include <BRepFilletAPI_MakeFillet2d.hxx>
29 #include <TopAbs_ShapeEnum.hxx>
30 #include <TopoDS_Shape.hxx>
31 #include <TopoDS_Edge.hxx>
32 #include <TopoDS_Vertex.hxx>
33 #include <TopExp_Explorer.hxx>
34 #include <TopExp.hxx>
35 #include <TopoDS.hxx>
36 #include <TopTools_MapOfShape.hxx>
37
38 #include <ChFi2d_FilletAPI.hxx>
39 #include <ChFi2d_ChamferAPI.hxx>
40
41 #include <BRepBuilderAPI_MakeWire.hxx>
42 #include <BRepBuilderAPI_FindPlane.hxx>
43 #include <BRep_Builder.hxx>
44
45 //=======================================================================
46 //function : chfi2d
47 //purpose  : 2d fillets and chamfers
48 //=======================================================================
49
50 static Standard_Integer chfi2d(Draw_Interpretor& di, Standard_Integer n, const char** a)
51 {
52   if (n < 3) {
53     di << "chfi2d : not enough args";
54     return 1;
55   }
56
57   // set up the algorithm
58   TopoDS_Shape F = DBRep::Get(a[2],TopAbs_FACE);
59   if (F.IsNull()) {
60     di << "chfi2d : "<< a[2] << " not a face";
61     return 1;
62   }
63
64   BRepFilletAPI_MakeFillet2d MF(TopoDS::Face(F));
65   if (MF.Status() == ChFi2d_NotPlanar) {
66     di << "chfi2d : not a planar face";
67     return 1;
68   }
69
70   TopoDS_Shape res;
71   Standard_Boolean partial_result = Standard_False;
72   Standard_Integer i = 3;
73   while (i+1 < n) {
74     
75     TopoDS_Shape aLocalEdge(DBRep::Get(a[i],TopAbs_EDGE));
76     TopoDS_Edge E1 = TopoDS::Edge(aLocalEdge);
77     aLocalEdge = DBRep::Get(a[i+1],TopAbs_EDGE);
78     TopoDS_Edge E2 = TopoDS::Edge(aLocalEdge);
79 //    TopoDS_Edge E1 = TopoDS::Edge(DBRep::Get(a[i],TopAbs_EDGE));
80 //    TopoDS_Edge E2 = TopoDS::Edge(DBRep::Get(a[i+1],TopAbs_EDGE));
81
82     if (E1.IsNull() || E2.IsNull()) {
83       di << "chfi2d : " << a[i] << " or " << a[i+1] << " not an edge";
84       if (partial_result) {
85         di <<" WARNING : this is a partial result ";
86         DBRep::Set(a[1],res);
87       }
88       return 1;
89     }
90
91     TopoDS_Vertex V;
92     if (!TopExp::CommonVertex(E1,E2,V)) {
93       di << "chfi2d " <<  a[i] << " and " << a[i+1] << " does not share a vertex";
94       if (partial_result) {
95         di <<" WARNING : this is a partial result ";
96         DBRep::Set(a[1],res);
97       }
98       return 1;
99     }
100
101     i += 2;
102     if (i+1 >= n) {
103       di << "chfi2d : not enough args";
104       if (partial_result) {
105         di <<" WARNING : this is a partial result ";
106         DBRep::Set(a[1],res);
107       }
108       return 1;
109     }
110
111     Standard_Real p1 = Draw::Atof(a[i+1]);
112     if (*a[i] == 'F') {
113       MF.AddFillet(V,p1);
114     }
115     else {
116       if (i+2 >= n) {
117         di << "chfi2d : not enough args";
118         if (partial_result) {
119           di <<" WARNING : this is a partial result ";
120           DBRep::Set(a[1],res);
121         }
122         return 1;
123       }
124       Standard_Real p2 = Draw::Atof(a[i+2]);
125       if (a[i][2] == 'D') {
126         MF.AddChamfer(E1,E2,p1,p2);
127       }
128       else {
129         MF.AddChamfer(E1,V,p1,p2 * (M_PI / 180.0));
130       }
131     }
132
133     if (MF.Status() == ChFi2d_TangencyError) {
134       di << "chfi2d : " <<  a[i-2] << " and " << a[i-1] << " are tangent ";
135       if (partial_result) {
136         di <<" WARNING : this is a partial result ";
137         DBRep::Set(a[1],res);
138       }
139       return 1;
140     }
141
142     if (MF.Status() == ChFi2d_NotAuthorized) {
143       di << "chfi2d : " <<  a[i-2] << " or " << a[i-1] << " is not a line or a circle ";
144       if (partial_result) {
145         di <<" WARNING : this is a partial result ";
146         DBRep::Set(a[1],res);
147       }
148       return 1;
149     }
150
151     if (MF.Status() != ChFi2d_IsDone) {
152       di << "chfi2d : operation failed on " << a[i-2];
153       if (partial_result) {
154         di <<" WARNING : this is a partial result ";
155         DBRep::Set(a[1],res);
156       }
157       return 1;
158     }
159     else {
160       partial_result = Standard_True;
161       MF.Build();
162       res = MF.Shape();
163     }
164     
165     if (*a[i] == 'F') {
166       i +=2;
167     }
168     else {
169       i +=3;
170     }
171   }
172   
173   MF.Build();
174   DBRep::Set(a[1],MF);
175
176   return 0;
177 }
178
179 //=======================================================================
180 //function : fillet2d
181 //purpose  : A method to find a plane for 2 edges.
182 //         : It may return a NULL object of the plane is not found
183 //         : (the edge are located not in a plane).
184 //=======================================================================
185
186 static Handle(Geom_Plane) findPlane(const TopoDS_Shape& S)
187 {
188   Handle(Geom_Plane) plane;
189   BRepBuilderAPI_FindPlane planeFinder(S);
190   if (planeFinder.Found())
191     plane = planeFinder.Plane();
192   return plane;
193 }
194
195 static Handle(Geom_Plane) findPlane(const TopoDS_Shape& E1, const TopoDS_Shape& E2)
196 {
197   BRep_Builder B;
198   TopoDS_Compound C;
199   B.MakeCompound(C);
200   B.Add(C, E1);
201   B.Add(C, E2);
202   return findPlane(C);
203 }
204
205 //=======================================================================
206 //function : findCommonPoint
207 //purpose  : Find a common (or the most close) point of two edges.
208 //=======================================================================
209
210 static gp_Pnt findCommonPoint(const TopoDS_Shape& E1, const TopoDS_Shape& E2)
211 {
212   TopoDS_Vertex v11, v12, v21, v22;
213   TopExp::Vertices(TopoDS::Edge(E1), v11, v12);
214   TopExp::Vertices(TopoDS::Edge(E2), v21, v22);
215
216   gp_Pnt p11 = BRep_Tool::Pnt(v11);
217   gp_Pnt p12 = BRep_Tool::Pnt(v12);
218   gp_Pnt p21 = BRep_Tool::Pnt(v21);
219   gp_Pnt p22 = BRep_Tool::Pnt(v22);
220
221   gp_Pnt common;
222   const double d1121 = p11.SquareDistance(p21);
223   const double d1122 = p11.SquareDistance(p22);
224   const double d1221 = p12.SquareDistance(p21);
225   const double d1222 = p12.SquareDistance(p22);
226   if (d1121 < d1122 && d1121 < d1221 && d1121 < d1222)
227     common = p11;
228   else if (d1122 < d1121 && d1122 < d1221 && d1122 < d1222)
229     common = p11;
230   else if (d1221 < d1121 && d1221 < d1122 && d1221 < d1222)
231     common = p12;
232   else if (d1222 < d1121 && d1222 < d1122 && d1222 < d1221)
233     common = p12;
234   
235   return common;
236 }
237
238 static gp_Pnt findCommonPoint(const TopoDS_Shape& W)
239 {
240   // The common point for two edges inside a wire
241   // is a sharing vertex of two edges.
242   TopTools_MapOfShape vertices;
243   TopExp_Explorer aExp(W, TopAbs_VERTEX);
244   for (; aExp.More(); aExp.Next())
245   {
246     if (!vertices.Add(aExp.Current()))
247     {
248       return BRep_Tool::Pnt(TopoDS::Vertex(aExp.Current()));
249     }
250   }
251   return gp::Origin(); // not found
252 }
253
254 //=======================================================================
255 //function : fillet2d
256 //purpose  : Fillet 2d based on Newton method (recursive, iteration)
257 //usage    : fillet2d result wire (or edge1 edge2) radius
258 //=======================================================================
259
260 static Standard_Integer fillet2d(Draw_Interpretor& di, Standard_Integer n, const char** a)
261 {
262   if (n != 4 && n != 5) 
263   {
264     di << "Usage : fillet2d result wire (or edge1 edge2) radius";
265     return 1;
266   }
267
268   TopoDS_Shape E1, E2, W;
269   if (n == 5)
270   {
271     // Get the edges.
272     E1 = DBRep::Get(a[2], TopAbs_EDGE, Standard_True);
273     E2 = DBRep::Get(a[3], TopAbs_EDGE, Standard_True);
274   }
275   else
276   {
277     // Get the wire.
278     W = DBRep::Get(a[2], TopAbs_WIRE, Standard_True);
279   }
280
281   // Get the radius value.
282   const Standard_Real radius = Atof(n == 5 ? a[4] : a[3]);
283
284   // Find plane of the edges.
285   Handle(Geom_Plane) hPlane = n == 5 ? findPlane(E1, E2) : findPlane(W);
286   if (hPlane.IsNull())
287   {
288     di << "Error: the edges are located not in a plane.";
289     return 1;
290   }
291
292   // Algo.
293   ChFi2d_FilletAPI algo;
294   gp_Pln plane = hPlane->Pln();
295   if (n == 5)
296   {
297     const TopoDS_Edge& e1 = TopoDS::Edge(E1);
298     const TopoDS_Edge& e2 = TopoDS::Edge(E2);
299     algo.Init(e1, e2, plane);
300   }
301   else
302   {
303     const TopoDS_Wire& w = TopoDS::Wire(W);
304     algo.Init(w, plane);
305   }
306   Standard_Boolean status = algo.Perform(radius);
307   if (!status)
308   {
309     di << "Error: the algrithm failed.";
310     return 1;
311   }
312
313   // Find a common point of the edges.
314   gp_Pnt common = n == 5 ? findCommonPoint(E1, E2) : findCommonPoint(W);
315
316   // Get the number of solutions (usually it is equal to 1).
317   Standard_Integer nbSolutions = algo.NbResults(common);
318   if (!nbSolutions)
319   {
320     di << "Error: no solutions.";
321     return 1;
322   }
323
324   // Get the result for the "nearest" solution (near the common point).
325   TopoDS_Edge M1, M2; // modified E1 and E2
326   TopoDS_Edge fillet = algo.Result(common, M1, M2);
327   if (fillet.IsNull())
328   {
329     di << "Error: the algrithm produced no result.";
330     return 1;
331   }
332
333   // Set result for DRAW.
334   DBRep::Set(a[1], fillet);
335
336   // Update neighbour edges in DRAW.
337   if (n == 5)
338   {
339     DBRep::Set(a[2], M1);
340     DBRep::Set(a[3], M2);
341   }
342   else // recreate the wire using the fillet
343   {
344     BRepBuilderAPI_MakeWire mkWire(M1, fillet, M2);
345     if (mkWire.IsDone())
346       DBRep::Set(a[1], mkWire.Wire());
347     else
348       DBRep::Set(a[1], fillet);
349   }
350   return 0;
351 }
352
353 //=======================================================================
354 //function : chamfer2d
355 //purpose  : Chamfer 2d.
356 //usage    : chamfer2d result wire (or edge1 edge2) length1 length2
357 //=======================================================================
358
359 static Standard_Integer chamfer2d(Draw_Interpretor& di, Standard_Integer n, const char** a)
360 {
361   if (n != 5 && n != 6) 
362   {
363     di << "Usage : chamfer2d result wire (or edge1 edge2) length1 length2";
364     return 1;
365   }
366
367   TopoDS_Shape W;
368   TopoDS_Shape E1, E2;
369   if (n == 6)
370   {
371     // Get the edges.
372     E1 = DBRep::Get(a[2], TopAbs_EDGE, Standard_True);
373     E2 = DBRep::Get(a[3], TopAbs_EDGE, Standard_True);
374   }
375   else 
376   {
377     W = DBRep::Get(a[2], TopAbs_WIRE, Standard_True);
378   }
379
380   // Get the lengths.
381   const Standard_Real length1 = (n == 6) ? Atof(a[4]) : Atof(a[3]);
382   const Standard_Real length2 = (n == 6) ? Atof(a[5]) : Atof(a[4]);
383
384   // Algo.
385   ChFi2d_ChamferAPI algo;
386   if (n == 6)
387   {
388     const TopoDS_Edge& e1 = TopoDS::Edge(E1);
389     const TopoDS_Edge& e2 = TopoDS::Edge(E2);
390     algo.Init(e1, e2);
391   }
392   else
393   {
394     const TopoDS_Wire& w = TopoDS::Wire(W);
395     algo.Init(w);
396   }
397
398   // Prepare the chamfer.
399   algo.Perform();
400
401   // Get the result.
402   TopoDS_Edge M1, M2; // modified E1 and E2
403   TopoDS_Edge chamfer = algo.Result(M1, M2, length1, length2);
404   if (chamfer.IsNull())
405   {
406     di << "Error: the algrithm produced no result.";
407     return 1;
408   }
409
410   if (n == 6)
411   {
412     // Set result for DRAW.
413     DBRep::Set(a[1], chamfer);
414     
415     // Update neighbour edges in DRAW.
416     DBRep::Set(a[2], M1);
417     DBRep::Set(a[3], M2);
418   }
419   else // recreate the wire using the chamfer
420   {
421     BRepBuilderAPI_MakeWire mkWire(M1, chamfer, M2);
422     if (mkWire.IsDone())
423       DBRep::Set(a[1], mkWire.Wire());
424     else
425       DBRep::Set(a[1], chamfer);
426   }
427
428   return 0;
429 }
430
431 //=======================================================================
432 //function : Fillet2DCommands
433 //purpose  : 
434 //=======================================================================
435
436 void  BRepTest::Fillet2DCommands(Draw_Interpretor& theCommands)
437 {
438   static Standard_Boolean done = Standard_False;
439   if (done) return;
440   done = Standard_True;
441
442   DBRep::BasicCommands(theCommands);
443
444   const char* g = "TOPOLOGY Fillet2D construction commands";
445    
446   theCommands.Add("chfi2d","chfi2d result face [edge1 edge2 (F radius/CDD d1 d2/CDA d ang) ....]",__FILE__,chfi2d,g);
447   theCommands.Add("fillet2d","fillet2d result wire (or edge1 edge2) radius",__FILE__,fillet2d,g);
448   theCommands.Add("chamfer2d","chamfer2d result wire (or edge1 edge2) length1 length2",__FILE__,chamfer2d,g);
449 }