Salome HOME
Merge from V6_main_20120808 08Aug12
[modules/geom.git] / src / SKETCHER / Sketcher_Profile.cxx
1 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
2 //
3 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
5 //
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
10 //
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 // Lesser General Public License for more details.
15 //
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
19 //
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
21 //
22
23 //  GEOM SKETCHER : basic sketcher
24 //  File   : Sketcher_Profile.cxx
25 //  Author : Damien COQUERET
26 //  Module : GEOM
27
28 #include <Standard_Stream.hxx>
29
30 #include <Sketcher_Profile.hxx>
31
32 #include <TopoDS_Vertex.hxx>
33 #include <TopoDS_Face.hxx>
34 #include <BRepLib.hxx>
35 #include <BRepBuilderAPI_MakeVertex.hxx>
36 #include <BRepBuilderAPI_MakeEdge.hxx>
37 #include <BRepBuilderAPI_MakeWire.hxx>
38 #include <BRepBuilderAPI_MakeFace.hxx>
39
40 #include <GeomAPI.hxx>
41 #include <Geom2d_Line.hxx>
42 #include <Geom2d_Circle.hxx>
43 #include <Geom_Surface.hxx>
44
45 #include <Precision.hxx>
46 #include <gp_Pln.hxx>
47 #include <gp_Ax2.hxx>
48
49 #include <TCollection_AsciiString.hxx>
50 #include <TColStd_Array1OfAsciiString.hxx>
51
52 #include "utilities.h"
53
54 //=======================================================================
55 // profile
56 // command to build a profile
57 //=======================================================================
58 Sketcher_Profile::Sketcher_Profile()
59 {
60 }
61
62
63 //=======================================================================
64 // profile
65 // command to build a profile
66 //=======================================================================
67 Sketcher_Profile::Sketcher_Profile(const char* aCmd)
68 {
69   enum {line, circle, point, none} move;
70
71   Standard_Integer i = 1;
72   Standard_Real x0, y0, x, y, dx, dy;
73   x0 = y0 = x = y = dy = 0;
74   dx = 1;
75
76   Standard_Boolean first, stayfirst, face, close;
77   first = Standard_True;
78   stayfirst = face = close = Standard_False;
79
80   Standard_Integer reversed = 0;
81   Standard_Integer control_Tolerance = 0;
82
83   TopoDS_Shape S;
84   TopoDS_Vertex MP;
85   BRepBuilderAPI_MakeWire MW;
86   gp_Ax3 DummyHP(gp::XOY());
87   gp_Pln P(DummyHP);
88   TopLoc_Location TheLocation;
89   Handle(Geom_Surface) Surface;
90
91   myOK = Standard_False;
92   myError = 0;
93
94   //TCollection_AsciiString aCommand(CORBA::string_dup(aCmd));
95   TCollection_AsciiString aCommand ((char*)aCmd);
96   TCollection_AsciiString aToken = aCommand.Token(":", 1);
97   int n = 0;
98   // porting to WNT
99   TColStd_Array1OfAsciiString aTab (0, aCommand.Length() - 1);
100   if ( aCommand.Length() )
101   {
102     while(aToken.Length() != 0) {
103       if(aCommand.Token(":", n + 1).Length() > 0)
104         aTab(n) = aCommand.Token(":", n + 1);
105       aToken = aCommand.Token(":", ++n);
106     }
107     n = n - 1;
108   }
109   if ( aTab.Length() && aTab(0).Length() )
110     while(i < n) {
111       Standard_Real length = 0, radius = 0, angle = 0;
112       move = point;
113
114       int n1 = 0;
115       TColStd_Array1OfAsciiString a (0, aTab(0).Length());
116       aToken = aTab(i).Token(" ", 1);
117       while (aToken.Length() != 0) {
118         if (aTab(i).Token(" ", n1 + 1).Length() > 0)
119           a(n1) = aTab(i).Token(" ", n1 + 1);
120         aToken = aTab(i).Token(" ", ++n1);
121       }
122       n1 = n1 - 1;
123
124       switch(a(0).Value(1))
125       {
126       case 'F':
127         {
128           if (n1 != 3) goto badargs;
129           if (!first) {
130             MESSAGE("profile : The F instruction must precede all moves");
131             return;
132           }
133           x0 = x = a(1).RealValue();
134           y0 = y = a(2).RealValue();
135           stayfirst = Standard_True;
136           break;
137         }
138       case 'O':
139         {
140           if (n1 != 4) goto badargs;
141           P.SetLocation(gp_Pnt(a(1).RealValue(), a(2).RealValue(), a(3).RealValue()));
142           stayfirst = Standard_True;
143           break;
144         }
145       case 'P':
146         {
147           if (n1 != 7) goto badargs;
148           gp_Vec vn(a(1).RealValue(), a(2).RealValue(), a(3).RealValue());
149           gp_Vec vx(a(4).RealValue(), a(5).RealValue(), a(6).RealValue());
150           if (vn.Magnitude() <= Precision::Confusion() || vx.Magnitude() <= Precision::Confusion()) {
151             MESSAGE("profile : null direction");
152             return;
153           }
154           gp_Ax2 ax(P.Location(), vn, vx);
155           P.SetPosition(ax);
156           stayfirst = Standard_True;
157           break;
158         }
159       case 'X':
160         {
161           if (n1 != 2) goto badargs;
162           length = a(1).RealValue();
163           if (a(0) == "XX")
164             length -= x;
165           dx = 1; dy = 0;
166           move = line;
167           break;
168         }
169       case 'Y':
170         {
171           if (n1 != 2) goto badargs;
172           length = a(1).RealValue();
173           if (a(0) == "YY")
174             length -= y;
175           dx = 0; dy = 1;
176           move = line;
177           break;
178         }
179       case 'L':
180         {
181           if (n1 != 2) goto badargs;
182           length = a(1).RealValue();
183           if (Abs(length) > Precision::Confusion())
184             move = line;
185           else
186             move = none;
187           break;
188         }
189       case 'T':
190         {
191           if (n1 != 3) goto badargs;
192           Standard_Real vx = a(1).RealValue();
193           Standard_Real vy = a(2).RealValue();
194           if (a(0) == "TT") {
195             vx -= x;
196             vy -= y;
197           }
198           length = Sqrt(vx * vx + vy * vy);
199           if (length > Precision::Confusion()) {
200             move = line;
201             dx = vx / length;
202             dy = vy / length;
203           }
204           else
205             move = none;
206           break;
207         }
208       case 'R':
209         {
210           if (n1 != 2) goto badargs;
211           angle = a(1).RealValue() * M_PI / 180.;
212           if (a(0) == "RR") {
213             dx = Cos(angle);
214             dy = Sin(angle);
215           }
216           else {
217             Standard_Real c = Cos(angle);
218             Standard_Real s = Sin(angle);
219             Standard_Real t = c * dx - s * dy;
220             dy = s * dx + c * dy;
221             dx = t;
222           }
223           break;
224         }
225       case 'D':
226         {
227           if (n1 != 3) goto badargs;
228           Standard_Real vx = a(1).RealValue();
229           Standard_Real vy = a(2).RealValue();
230           length = Sqrt(vx * vx + vy * vy);
231           if (length > Precision::Confusion()) {
232             dx = vx / length;
233             dy = vy / length;
234           }
235           else
236             move = none;
237           break;
238         }
239       case 'C':
240         {
241           if (n1 != 3) goto badargs;
242           radius = a(1).RealValue();
243           if (Abs(radius) > Precision::Confusion()) {
244             angle = a(2).RealValue() * M_PI / 180.;
245             move = circle;
246           }
247           else
248             move = none;
249           break;
250         }
251       case 'A':                                // TAngential arc by end point
252         {
253           if (n1 != 3) goto badargs;
254           Standard_Real vx = a(1).RealValue();
255           Standard_Real vy = a(2).RealValue();
256           if (a(0) == "AA") {
257             vx -= x;
258             vy -= y;
259           }
260           Standard_Real det = dx * vy - dy * vx;
261           if ( Abs(det) > Precision::Confusion()) {
262             // Cosine of alpha = arc of angle / 2 , alpha in [0,Pi]
263             Standard_Real c = (dx * vx + dy * vy) / Sqrt((dx * dx + dy * dy) * (vx * vx + vy * vy));
264             // radius = distance between start and end point / 2 * sin(alpha)
265             // radius is > 0 or < 0
266             radius = (vx * vx + vy * vy)* Sqrt(dx * dx + dy * dy) / (2.0 * det);
267             if (Abs(radius) > Precision::Confusion()) {
268               angle = 2.0 * acos(c); // angle in [0,2Pi]
269               move = circle;
270             }
271             else
272               move = none;
273             break;
274           }
275           else
276             move = none;
277           break;
278         }
279       case 'U':                                // Arc by end point and radiUs
280         {
281           if (n1 != 5) goto badargs;
282           Standard_Real vx = a(1).RealValue();
283           Standard_Real vy = a(2).RealValue();
284           radius  = a(3).RealValue();
285           reversed = a(4).IntegerValue();
286           if (a(0) == "UU") {                 // Absolute
287             vx -= x;
288             vy -= y;
289           }
290           Standard_Real length = Sqrt(vx * vx + vy * vy);
291           if ( (4.0 - (vx * vx + vy * vy) / (radius * radius) >= 0.0 ) && (length > Precision::Confusion()) ) {
292             // Cosine of alpha = arc angle / 2 , alpha in [0,Pi/2]
293             Standard_Real c = 0.5 * Sqrt(4.0 - (vx * vx + vy * vy) / (radius * radius));
294             angle = 2.0 * acos(c); // angle in [0,Pi]
295             if ( reversed == 2 )
296               angle = angle - 2 * M_PI;
297             dx =    0.5 * (  vy * 1.0/radius
298                            + vx * Sqrt(4.0  / (vx * vx + vy * vy) - 1.0 / (radius * radius)));
299             dy = -  0.5 * (  vx * 1.0/radius
300                            - vy * Sqrt(4.0  / (vx * vx + vy * vy) - 1.0 / (radius * radius)));
301             move = circle;
302           }
303           else{
304             move = none;
305           }
306           break;
307         }
308       case 'E':                                // Arc by end point and cEnter
309         {
310           if (n1 != 7) goto badargs;
311           Standard_Real vx = a(1).RealValue();
312           Standard_Real vy = a(2).RealValue();
313           Standard_Real vxc  = a(3).RealValue();
314           Standard_Real vyc  = a(4).RealValue();
315           reversed = a(5).IntegerValue();
316           control_Tolerance = a(6).IntegerValue();
317
318           if (a(0) == "EE") {                 // Absolute
319             vx -= x;
320             vy -= y;
321             vxc -= x;
322             vyc -= y;
323           }
324           radius = Sqrt( vxc * vxc + vyc * vyc );
325           Standard_Real det = vx * vyc - vy * vxc;
326           Standard_Real length = Sqrt(vx * vx + vy * vy);
327           Standard_Real length2 = Sqrt((vx-vxc) * (vx-vxc) + (vy-vyc) * (vy-vyc));
328           Standard_Real length3 = Sqrt(vxc * vxc + vyc * vyc);
329           Standard_Real error = Abs(length2 - radius);
330           myError = error;
331           if ( error > Precision::Confusion() ){
332             MESSAGE("Warning : The specified end point is not on the Arc, distance = "<<error);
333           }
334           if ( error > Precision::Confusion() && control_Tolerance == 1)                      // Don't create the arc if the end point
335             move = none;                                                                      // is too far from it
336           else if ( (length > Precision::Confusion()) &&
337                     (length2 > Precision::Confusion()) &&
338                     (length3 > Precision::Confusion()) ) {
339             Standard_Real c = ( radius * radius - (vx * vxc + vy * vyc) )
340                             / ( radius * Sqrt((vx-vxc) * (vx-vxc) + (vy-vyc) * (vy-vyc)) ) ;  // Cosine of arc angle
341             angle = acos(c);                                                                  // angle in [0,Pi]
342             if ( reversed == 2 )
343               angle = angle - 2 * M_PI;
344             if (det < 0)
345               angle = -angle;
346             dx =  vyc / radius;
347             dy = -vxc / radius;
348             move = circle;
349           }
350           else {
351             move = none;
352           }
353           break;
354         }
355       case 'I':
356         {
357           if (n1 != 2) goto badargs;
358           length = a(1).RealValue();
359           if (a(0) == "IX") {
360             if (Abs(dx) < Precision::Confusion()) {
361               MESSAGE("profile : cannot intersect, arg "<<i-1);
362               return;
363             }
364             length = (length - x) / dx;
365           }
366           else if (a(0) == "IY") {
367             if (Abs(dy) < Precision::Confusion()) {
368               MESSAGE("profile : cannot intersect, arg "<<i-1);
369               return;
370             }
371             length = (length - y) / dy;
372           }
373           if (Abs(length) > Precision::Confusion())
374             move = line;
375           else
376             move = none;
377           break;
378         }
379       case 'W':
380         {
381           if (a(0) == "WW")
382             close = Standard_True;
383           else if(a(0) == "WF") {
384             close = Standard_True;
385             face = Standard_True;
386           }
387           i = n - 1;
388           break;
389         }
390       default:
391         {
392           MESSAGE("profile : unknown code " << a(i));
393           return;
394         }
395     }
396
397 again :
398     switch (move)
399     {
400     case line :
401       {
402         if (length < 0) {
403           length = -length;
404           dx = -dx;
405           dy = -dy;
406         }
407         Handle(Geom2d_Line) l = new Geom2d_Line(gp_Pnt2d(x,y),gp_Dir2d(dx,dy));
408         BRepBuilderAPI_MakeEdge ME (GeomAPI::To3d(l,P),0,length);
409         if (!ME.IsDone())
410           return;
411         MW.Add(ME);
412         x += length*dx;
413         y += length*dy;
414         break;
415       }
416     case circle :
417       {
418         Standard_Boolean sense = Standard_True;
419         if (radius < 0) {
420           radius = -radius;
421           sense = !sense;
422           dx = -dx;
423           dy = -dy;
424         }
425         gp_Ax2d ax(gp_Pnt2d(x-radius*dy,y+radius*dx),gp_Dir2d(dy,-dx));
426         if (angle < 0) {
427           angle = -angle;
428           sense = !sense;
429         }
430         Handle(Geom2d_Circle) c = new Geom2d_Circle(ax,radius,sense);
431         BRepBuilderAPI_MakeEdge ME (GeomAPI::To3d(c,P),0,angle);
432         if (!ME.IsDone())
433           return;
434         MW.Add(ME);
435         gp_Pnt2d p;
436         gp_Vec2d v;
437         c->D1(angle,p,v);
438         x = p.X();
439         y = p.Y();
440         dx = v.X() / radius;
441         dy = v.Y() / radius;
442         break;
443       }
444     case point:
445       {
446         MP = BRepBuilderAPI_MakeVertex(gp_Pnt(x, y, 0.0));
447         break;
448       }
449     case none:
450       {
451         i = n - 1;
452         break;
453       }
454     }
455
456     // update first
457     first = stayfirst;
458     stayfirst = Standard_False;
459
460     if(!(dx == 0 && dy == 0))
461       myLastDir.SetCoord(dx, dy, 0.0);
462     else
463       return;
464     myLastPoint.SetX(x);
465     myLastPoint.SetY(y);
466
467     // next segment....
468     i++;
469     if ((i == n) && close) {
470       // the closing segment
471       dx = x0 - x;
472       dy = y0 - y;
473       length = Sqrt(dx * dx + dy * dy);
474       move = line;
475       if (length > Precision::Confusion()) {
476         dx = dx / length;
477         dy = dy / length;
478         goto again;
479       }
480     }
481   }
482
483   // get the result, face or wire
484   if (move == none) {
485     return;
486   } else if (move == point) {
487     S = MP;
488   } else if (face) {
489     if (!MW.IsDone()) {
490       return;
491     }
492     BRepBuilderAPI_MakeFace MF (P, MW.Wire());
493     if (!MF.IsDone()) {
494       return;
495     }
496     S = MF;
497   } else {
498     if (!MW.IsDone()) {
499       return;
500     }
501     S = MW;
502   }
503
504   if(!TheLocation.IsIdentity())
505     S.Move(TheLocation);
506
507   myShape = S;
508   myOK = true;
509   return;
510
511   badargs :
512     MESSAGE("profile : bad number of arguments");
513     return;
514 }