b311480e |
1 | // Created by: Joelle CHAUVET |
2 | // Copyright (c) 1996-1999 Matra Datavision |
973c2be1 |
3 | // Copyright (c) 1999-2014 OPEN CASCADE SAS |
b311480e |
4 | // |
973c2be1 |
5 | // This file is part of Open CASCADE Technology software library. |
b311480e |
6 | // |
d5f74e42 |
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 |
973c2be1 |
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. |
b311480e |
12 | // |
973c2be1 |
13 | // Alternatively, this file may be used under the terms of Open CASCADE |
14 | // commercial license or contractual agreement. |
b311480e |
15 | |
7fd59977 |
16 | // Modified: Tue Oct 15 10:12:02 1996 |
7fd59977 |
17 | // Add ChFi2d_TangencyError (PRO3529) |
18 | // Modified: Fri Sep 25 09:38:04 1998 |
7fd59977 |
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> |
8b7c5e47 |
33 | #include <TopExp_Explorer.hxx> |
7fd59977 |
34 | #include <TopExp.hxx> |
8b7c5e47 |
35 | #include <TopoDS.hxx> |
07ef8bdf |
36 | #include <TopTools_MapOfShape.hxx> |
8b7c5e47 |
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> |
7fd59977 |
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 | |
91322f44 |
111 | Standard_Real p1 = Draw::Atof(a[i+1]); |
7fd59977 |
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 | } |
91322f44 |
124 | Standard_Real p2 = Draw::Atof(a[i+2]); |
7fd59977 |
125 | if (a[i][2] == 'D') { |
126 | MF.AddChamfer(E1,E2,p1,p2); |
127 | } |
128 | else { |
c6541a0c |
129 | MF.AddChamfer(E1,V,p1,p2 * (M_PI / 180.0)); |
7fd59977 |
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 | |
8b7c5e47 |
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; |
cf0786da |
243 | TopExp_Explorer aExp(W, TopAbs_VERTEX); |
244 | for (; aExp.More(); aExp.Next()) |
8b7c5e47 |
245 | { |
cf0786da |
246 | if (!vertices.Add(aExp.Current())) |
8b7c5e47 |
247 | { |
cf0786da |
248 | return BRep_Tool::Pnt(TopoDS::Vertex(aExp.Current())); |
8b7c5e47 |
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 | |
7fd59977 |
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); |
8b7c5e47 |
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); |
7fd59977 |
449 | } |