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