Salome HOME
NRI : Merge from V1_2.
[modules/geom.git] / SKETCHER / GEOM_Sketcher.cxx
1 //  GEOM SKETCHER : basic sketcher
2 //
3 //  Copyright (C) 2003  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.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org 
21 //
22 //
23 //
24 //  File   : GEOM_Sketcher.cxx
25 //  Author : Nicolas REJNERI
26 //  Module : GEOM
27 //  $Header$
28
29 using namespace std;
30 #include "GEOM_Sketcher.h"
31 #include "utilities.h"
32
33 #include <qstring.h> 
34
35 #include <Geom_Axis1Placement.hxx>
36 #include <Geom_Circle.hxx>
37 #include <Geom_Line.hxx>
38 #include <Geom_CartesianPoint.hxx>
39 #include <BRep_Tool.hxx>
40 #include <BRepBuilderAPI_MakeEdge2d.hxx>
41 #include <BRepBuilderAPI_MakeEdge.hxx>
42 #include <BRepBuilderAPI_MakeVertex.hxx>
43 #include <gp_Lin2d.hxx>
44 #include <gp_Pln.hxx>
45 #include <gp_Lin.hxx>
46 #include <gp_Dir.hxx>
47 #include <gp_Circ2d.hxx>
48 #include <gp_Vec2d.hxx>
49 #include <IntAna_IntConicQuad.hxx>
50 #include <BRepLib.hxx>
51 #include <TopExp.hxx>
52 #include <ProjLib.hxx>
53 #include <Precision.hxx>
54 #include <ElSLib.hxx>
55 #include <BRepTools_WireExplorer.hxx>
56 #include <GccAna_Pnt2dBisec.hxx>
57 #include <GeomAPI.hxx>
58 #include <Geom2dAPI_ProjectPointOnCurve.hxx>
59 #include <Geom2d_TrimmedCurve.hxx>
60 #include <Geom2d_Circle.hxx>
61 #include <gce_MakeCirc2d.hxx>
62 #include <GccAna_Circ2d2TanRad.hxx>
63 #include <GccAna_Circ2d2TanOn.hxx>
64 #include <GccEnt.hxx>
65 #include <GccEnt_QualifiedLin.hxx>
66 #include <GccEnt_QualifiedCirc.hxx>
67 #include <GccAna_Lin2dTanPer.hxx>
68 #include <GccAna_Lin2dTanObl.hxx>
69 #include <gce_MakeLin2d.hxx>
70 #include <GCE2d_MakeArcOfCircle.hxx>
71 #include <Precision.hxx>
72 #include <ElCLib.hxx>
73 #include <AIS_Point.hxx>
74 #include <TColgp_HArray1OfPnt2d.hxx>
75 #include <Geom2dAPI_Interpolate.hxx>
76 #include <TColgp_Array1OfVec2d.hxx>
77 #include <TColStd_HArray1OfBoolean.hxx>
78 #include <GeomAPI_ProjectPointOnCurve.hxx>
79 #include <DsgPrs_ArrowSide.hxx>
80 #include <BRepBuilderAPI_Transform.hxx>
81
82 #include <AIS_Drawer.hxx>
83 #include <Prs3d_TextAspect.hxx>
84 #include <Prs3d_LineAspect.hxx>
85 #include <Graphic3d_NameOfFont.hxx>
86
87 #include <TopoDS_Wire.hxx>
88
89 /*!
90   \class GEOM_Sketcher GEOM_Sketcher.h
91   \brief ...
92 */
93
94 Standard_Real resol = 1.0;    
95
96 /*!
97   Constructor.
98 */
99 Sketch::Sketch()
100 {
101
102 }
103
104 /*!
105   Destructor.
106 */
107 Sketch::~Sketch()
108 {
109
110 }
111
112
113 /*!
114   Constructor.
115
116   \param V3d_Viewer
117 */
118 Sketch::Sketch(const Handle(V3d_Viewer)& aViewer) :
119 myInteractiveContext(new AIS_InteractiveContext(aViewer)),
120 myAxisColor(Quantity_Color(Quantity_NOC_YELLOW)),
121 myCurrentColor(Quantity_Color(Quantity_NOC_GREEN)),
122 myWireColor(Quantity_Color(Quantity_NOC_RED))
123 {
124         Init();
125 }
126
127 /*!
128   Constructor.
129
130   \param V3d_Viewer
131   \param Quantity_Color
132   \param Quantity_Color
133   \param Quantity_Color
134 */
135 Sketch::Sketch(const Handle(V3d_Viewer)& aViewer,
136                const Quantity_Color& anAxisColor,
137                const Quantity_Color& aCurrentColor,
138                const Quantity_Color& aWireColor):
139 myInteractiveContext(new AIS_InteractiveContext(aViewer)),
140 myAxisColor(anAxisColor),
141 myCurrentColor(aCurrentColor),
142 myWireColor(aWireColor)
143 {
144         Init();
145 }
146
147 /*!
148   Build the current edge in a graphic mode.
149   The first signature with view coordinates is used to connect to the move event from the user interface.
150   The second signature is used when the current point is known by 2d real coordinates.
151
152   \param Xp     
153   \param Yp     
154   \param V3d_View       
155 */
156 void Sketch::MakeCurrentEdge(const Standard_Integer  Xp   ,
157                              const Standard_Integer  Yp   ,
158                              const Handle(V3d_View)& aView )
159 {
160   /* 3d coordinates of the picked point */
161   Standard_Real Xv,Yv,Zv;
162   aView->Convert(Xp,Yp,Xv,Yv,Zv);
163   /* computation of real 2d coordinates in plane of sketch */
164   Standard_Real Vx,Vy,Vz;
165   aView->Proj(Vx,Vy,Vz);
166   gp_Dir D(Vx,Vy,Vz);
167   gp_Pnt P(Xv,Yv,Zv);
168   gp_Lin L(P,D);
169   Standard_Real X,Y;
170   gp_Pnt Sol;
171   IntAna_IntConicQuad Int(L,myPlane->Pln(),Precision::Angular());
172   if (Int.IsDone()) {
173     if (!Int.IsParallel()) {
174       if (Int.NbPoints() > 0 ) {
175         Sol = Int.Point(1);
176         ElSLib::Parameters(myPlane->Pln(),Sol,X,Y);
177       }
178     }
179   }
180   MakeCurrentEdge(X,Y);
181 }
182
183 /*!
184   Build the current edge in a graphic mode.
185   The first signature with view coordinates is used to connect to the move event from the user interface.
186   The second signature is used when the current point is known by 2d real coordinates.
187
188   \param X      
189   \param Y      
190 */
191 void Sketch::MakeCurrentEdge(const Standard_Real  X, const Standard_Real Y)
192 {
193   /* Create the current edge depending on the active mode */
194   switch (myCurrentStatus) {
195   case BEGIN_SKETCH:
196     myCurrentEdge = BRepBuilderAPI_MakeVertex(ElCLib::To3d(myPlane->Pln().Position().Ax2(),gp_Pnt2d(X,Y)));
197     break;
198   case SEGMENT:
199     MakeCurrentSegment(X,Y);
200     break;
201   case ARC_CHORD:
202     MakeCurrentSegment(X,Y);
203     break;
204   case ARC_CHORD_END:
205     MakeCurrentArc(X,Y);
206     break;
207   }
208   DisplayCurrentEdge();
209 }
210
211 /*!
212   Build the current edge in a graphic mode.
213   Function to connect to the input event from the user interface.
214 */
215 void Sketch::ValidateEdge()
216 {
217   gp_Pnt pt;
218   gp_Pnt2d pt2d;
219   switch (myCurrentStatus) {
220   case BEGIN_SKETCH:
221     {
222       myFirstPointSketch = TopoDS::Vertex(myCurrentEdge);
223       myPresentableWire = new AIS_Shape(myFirstPointSketch);
224       myPresentableWire->SetColor(myWireColor.Name());
225       myInteractiveContext->Display(myPresentableWire);
226       pt = BRep_Tool::Pnt(myFirstPointSketch);
227       pt2d = ProjLib::Project(myPlane->Pln(),pt);
228       myLastX = pt2d.X();
229       myLastY = pt2d.Y();
230       myCurrentStatus = SEGMENT;
231       break;    
232     }
233   case SEGMENT:
234     {
235       Standard_Real first,last;
236       TopLoc_Location L;
237       Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(TopoDS::Edge(myCurrentEdge),myPlane,L,first,last);
238       myCurrentEdge = BRepBuilderAPI_MakeEdge2d(Handle(Geom2d_Line)::DownCast(C)->Lin2d(),0.,myLengthDimension->Value());
239       if (myTransitionStatus == ANGLE || 
240           myTransitionStatus == LENGTH_FIXED ||
241           myTransitionStatus == X_FIXED ||
242           myTransitionStatus == Y_FIXED) 
243         myTransitionStatus = NOCONSTRAINT;
244       AddEdgeToWire();
245       break;
246     }
247   case ARC_CHORD:
248     {
249       myInteractiveContext->CloseLocalContext();
250       myInteractiveContext->OpenLocalContext();
251       gp_Pnt2d p1 (myLastX,myLastY);
252       pt = BRep_Tool::Pnt(TopExp::LastVertex(TopoDS::Edge(myCurrentEdge)));
253       gp_Pnt2d p2 = ProjLib::Project(myPlane->Pln(),pt);
254       GccAna_Pnt2dBisec ComputeMediatrice(p1,p2);
255       if (ComputeMediatrice.HasSolution()) {
256         myMediatrice = new Geom2d_Line(ComputeMediatrice.ThisSolution());
257         Handle(Geom_Curve) aMediatrice3d = GeomAPI::To3d(myMediatrice,myPlane->Pln());
258         myPresentableMediatrice = new AIS_Axis(Handle(Geom_Line)::DownCast(aMediatrice3d));
259         myInteractiveContext->Display(myPresentableMediatrice);
260       }
261       TopoDS_Edge e = BRepBuilderAPI_MakeEdge2d(gce_MakeCirc2d(gp_Pnt2d(0.,0),1.));
262       BRepLib::BuildCurve3d(e);
263       myLengthDimension->SetText(TCollection_ExtendedString());
264       myInteractiveContext->Redisplay(myLengthDimension,Standard_False);
265       if (myEdgesNumber == 0)
266         myPreviousEdge = TopoDS::Edge(myCurrentEdge);
267       pt2d = ProjLib::Project(myPlane->Pln(),pt);
268       myLastX = pt2d.X();
269       myLastY = pt2d.Y();
270       myTransitionStatus = NOCONSTRAINT;
271       myCurrentStatus = ARC_CHORD_END;
272       break;
273     }
274   case ARC_CHORD_END:
275     myCurrentStatus = ARC_CHORD;
276     AddEdgeToWire();    
277     break;
278   }
279 }
280
281 /*!
282   Add edge to current wire on an edge validation .
283 */
284 void Sketch::AddEdgeToWire()
285 {
286   myPreviousEdge = TopoDS::Edge(myCurrentEdge);
287   BRepLib::BuildCurve3d(myPreviousEdge);
288   myCurrentWire.Add(TopoDS::Edge(myPreviousEdge));
289   myEdgesNumber++;
290   myPresentableWire->Set( myCurrentWire.Wire() );
291   myInteractiveContext->Redisplay(myPresentableWire);
292   myConstructionMode.Append(myCurrentStatus);
293   myConstraintMode.Append(myTransitionStatus);
294   myInteractiveContext->CloseLocalContext();
295   gp_Pnt pt;
296   if (myPreviousEdge.Orientation() == TopAbs_FORWARD )
297     pt = BRep_Tool::Pnt(TopExp::LastVertex(TopoDS::Edge(myPreviousEdge)));
298   else 
299     pt = BRep_Tool::Pnt(TopExp::FirstVertex(TopoDS::Edge(myPreviousEdge)));
300   gp_Pnt2d pt2d= ProjLib::Project(myPlane->Pln(),pt);
301   myLastX = pt2d.X();
302   myLastY = pt2d.Y();
303 }
304
305 /*!
306   Set the numeric dimension for the current edge and validate creation.
307
308   \param aValue 
309   \return Standard_Boolean
310 */
311 Standard_Boolean Sketch::SetDimension(Standard_Real& aValue)
312 {
313   fitInResol(aValue); 
314   if (myCurrentStatus == SEGMENT ||
315       myCurrentStatus == ARC_CHORD){
316     Standard_Real first,last;
317     TopLoc_Location L;
318     Handle(Geom2d_Curve) C = 
319       BRep_Tool::CurveOnSurface(TopoDS::Edge(myCurrentEdge),myPlane,L,first,last);
320     myCurrentEdge = 
321       BRepBuilderAPI_MakeEdge2d(Handle(Geom2d_Line)::DownCast(C)->Lin2d(),0.,aValue);
322     DisplayCurrentEdge();
323     if (myTransitionStatus == NOCONSTRAINT) {
324       mySegmentLength = aValue;
325       myTransitionStatus = LENGTH_FIXED;
326     }
327     else
328       ValidateEdge();
329     return Standard_True;
330   }
331   
332   else if( myCurrentStatus == ARC_CHORD_END){
333     if (myTransitionStatus == TANGENT) return Standard_False;
334     gp_Pnt2d p;
335     if (myEdgesNumber > 0) {
336       if (myPreviousEdge.Orientation() == TopAbs_FORWARD)
337         p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::LastVertex(myPreviousEdge)));
338       else
339         p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::FirstVertex(myPreviousEdge)));
340     }
341     else
342       p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(myFirstPointSketch));
343     GccAna_Circ2d2TanRad aSol(p, gp_Pnt2d(myLastX,myLastY),aValue,Precision::Confusion());
344     Standard_Real dist = RealLast();
345     if (aSol.NbSolutions() > 0) {
346       gp_Circ2d CirSol;
347       gp_Pnt2d pc = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopoDS::Vertex(myCenterCircle->Shape())));
348       for (Standard_Integer i =1; i<= aSol.NbSolutions(); i++) {
349         if (pc.Distance(aSol.ThisSolution(i).Location()) < dist)
350           CirSol = aSol.ThisSolution(i);
351       }
352       if (myCurrentEdge.Orientation() == TopAbs_FORWARD)
353         myCurrentEdge = BRepBuilderAPI_MakeEdge2d(aSol.ThisSolution(1),p,gp_Pnt2d(myLastX,myLastY));
354       else {    
355         myCurrentEdge = BRepBuilderAPI_MakeEdge2d(aSol.ThisSolution(1),gp_Pnt2d(myLastX,myLastY),p);
356         myCurrentEdge.Reverse();
357       } 
358       DisplayCurrentEdge();
359       ValidateEdge();   
360       return Standard_True;
361     }
362   }
363   
364   return Standard_False;
365 }
366
367 /*!
368   Set the numeric dimension for the current edge and validate creation.
369   
370   \param deltaX 
371   \param deltaY 
372 */
373 void Sketch::SetDimension(Standard_Real& deltaX, Standard_Real& deltaY)
374 {
375   fitInResol(deltaX); 
376   fitInResol(deltaY);
377   Standard_Real X = myLastX + deltaX;
378   Standard_Real Y = myLastY + deltaY;
379   MakeCurrentEdge(X,Y);
380   ValidateEdge();
381 }
382
383 /*!
384   Set the numeric value of the X coordinate of current point giving a deltaX relative to previous point.
385
386   \param deltaX 
387 */
388 void Sketch::SetXDimension(Standard_Real& deltaX)
389 {
390   fitInResol(deltaX); 
391   Standard_Real X = myLastX + deltaX;
392   Standard_Real Y = myLastY;
393   if ( deltaX == 0. )
394     Y = Y + 100.0 * Precision::Confusion();
395
396   if (myTransitionStatus == NOCONSTRAINT) {
397     MakeCurrentEdge(X,Y);
398     myTransitionStatus = X_FIXED;
399     mySegmentX = X;
400   }
401   else if (myTransitionStatus == Y_FIXED) {
402     myTransitionStatus = NOCONSTRAINT;
403     MakeCurrentEdge(X,mySegmentY);
404     ValidateEdge();
405   }
406   else if (myTransitionStatus == ANGLE) {
407     myTransitionStatus = NOCONSTRAINT;
408     Standard_Real angle;
409     if (0 <= mySegmentAngle &&  mySegmentAngle<= PI )
410       angle = PI - mySegmentAngle;
411     else
412       angle = mySegmentAngle - PI;
413     Y = X*Tan(angle);
414     MakeCurrentEdge(X,Y);
415     ValidateEdge();
416   }
417   else
418     myTransitionStatus = NOCONSTRAINT;
419 }
420
421 /*!
422   Set the numeric value of the Y coordinate of current point giving a deltaY relative to previous point.
423
424   \param deltaY 
425 */
426 void Sketch::SetYDimension(Standard_Real& deltaY)
427 {
428   fitInResol(deltaY); 
429   Standard_Real X = myLastX;
430   Standard_Real Y = myLastY + deltaY;
431
432   if ( deltaY == 0. )
433     X = X + 100.0 * Precision::Confusion();
434
435   if (myTransitionStatus == NOCONSTRAINT) {
436     MakeCurrentEdge(X,Y);
437     myTransitionStatus = Y_FIXED;
438     mySegmentY = Y;
439   }
440   else if (myTransitionStatus == X_FIXED) {
441     myTransitionStatus = NOCONSTRAINT;
442     MakeCurrentEdge(mySegmentX,Y);
443     ValidateEdge();
444   }
445   else if (myTransitionStatus == ANGLE) {
446     myTransitionStatus = NOCONSTRAINT;
447     Standard_Real angle;
448     if (0 <= mySegmentAngle &&  mySegmentAngle<= PI )
449       angle = PI - mySegmentAngle;
450     else
451       angle = mySegmentAngle - PI;
452     X = Y/Tan(angle);
453     MakeCurrentEdge(X,Y);
454     ValidateEdge();
455   }
456   else
457     myTransitionStatus = NOCONSTRAINT;
458 }
459
460 /*!
461   Set the numeric value of angle between 2 segments.
462
463   \param aValue 
464 */
465 void Sketch::SetSegmentAngle(Standard_Real& aValue)
466 {
467   if (myEdgesNumber > 0) {
468     Standard_Real First,Last;
469     TopLoc_Location L;
470     Standard_Real angle;
471     if (0 <= aValue &&  aValue<= PI )
472       angle = PI - aValue;
473     else
474       angle = aValue - PI;
475     Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last);
476     if (PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) {
477       Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(myPreviousEdge),myPlane,L,First,Last);
478       
479       GccAna_Lin2dTanObl aSol(gp_Pnt2d(myLastX,myLastY),Handle(Geom2d_Line)::DownCast(PreviousCurve)->Lin2d(),angle);
480       myCurrentEdge = BRepBuilderAPI_MakeEdge2d(aSol.ThisSolution(1),0.,myLengthDimension->Value());
481     }
482     if (myTransitionStatus == LENGTH_FIXED)  {
483       ValidateEdge();
484     }
485     else if (myTransitionStatus == X_FIXED)  {
486       Standard_Real length = mySegmentX/Cos(angle);
487       SetDimension(length);
488       ValidateEdge();
489     }
490     else if (myTransitionStatus == Y_FIXED)  {
491       Standard_Real length = mySegmentY/Sin(angle);
492       SetDimension(length);
493       ValidateEdge();
494     }
495     else {
496       mySegmentAngle = aValue;
497       myTransitionStatus = ANGLE;
498     }
499   }
500 }
501
502 /*!
503   Get the angle value between 2 segments.
504
505   \return Standard_Real
506 */
507 Standard_Real Sketch::GetSegmentAngle()
508 {
509   return mySegmentAngle;
510 }
511
512 /*!
513   Close automatically an open sketch.
514
515   \return TopoDS_Wire.  Return null shape if not possible.
516 */
517 TopoDS_Wire Sketch::Close()
518
519   myCurrentStatus = END_SKETCH;
520   myInteractiveContext->CloseAllContexts();
521   myInteractiveContext->EraseAll(Standard_False);
522   if (myEdgesNumber >= 2) {
523     BRepTools_WireExplorer Ex(myCurrentWire.Wire());
524     TopoDS_Vertex V1;
525     if (myPreviousEdge.Orientation() == TopAbs_FORWARD)
526       V1 = TopExp::LastVertex(myPreviousEdge);
527     else
528       V1 = TopExp::FirstVertex(myPreviousEdge);
529     myCurrentWire.Add(BRepBuilderAPI_MakeEdge(V1,myFirstPointSketch).Edge());
530     myEdgesNumber++;
531     return myCurrentWire.Wire();
532   }
533   else
534     return TopoDS_Wire();
535 }
536
537
538
539 /*!
540   Clear sketch presentation.
541 */
542 void Sketch::Clear()
543 {
544   myCurrentStatus = END_SKETCH;
545   myInteractiveContext->CloseAllContexts();
546   myInteractiveContext->EraseAll(Standard_False);
547 }
548
549 /*!
550   Terminate sketch without closing.
551
552   \return TopoDS_Wire. Return null shape if not possible.
553 */
554 TopoDS_Wire Sketch::End()
555 {
556   myCurrentStatus = END_SKETCH;
557   myInteractiveContext->CloseAllContexts();
558   myInteractiveContext->EraseAll(Standard_False);
559   if (myCurrentWire.IsDone()) {
560     return myCurrentWire.Wire();
561   }
562   else
563     return TopoDS_Wire();
564 }
565
566
567 /*!
568   Delete current edge.
569 */
570 Standard_Boolean Sketch::Delete()
571 {
572   myInteractiveContext->Erase(myAngleDimension,Standard_True,Standard_False);
573   myInteractiveContext->Erase(myLengthDimension,Standard_True,Standard_False);
574   myInteractiveContext->Erase(myRadiusDimension,Standard_True,Standard_False);
575   myInteractiveContext->Erase(myCenterCircle,Standard_True,Standard_False);
576   myInteractiveContext->Erase(myXDimension,Standard_True,Standard_False);
577   myInteractiveContext->Erase(myYDimension,Standard_True,Standard_False);
578   
579   if (myCurrentStatus == BEGIN_SKETCH) {
580     myCurrentStatus = END_SKETCH;
581     myInteractiveContext->CloseAllContexts();
582     myInteractiveContext->EraseAll(Standard_False);
583     return true;
584   }
585   else if(myCurrentStatus == SEGMENT   ||
586           myCurrentStatus == ARC_CHORD ) {
587     RemoveLastEdge();
588   }
589   else if(myCurrentStatus ==  ARC_CHORD_END) {
590     myCurrentStatus = ARC_CHORD;
591     myInteractiveContext->CloseAllContexts();
592   }
593   gp_Pnt pt;
594   if (myEdgesNumber == 0) {
595     //myInteractiveContext->EraseAll(Standard_False);
596     ChangeMode(BEGIN_SKETCH); // DCQ
597     pt = BRep_Tool::Pnt(myFirstPointSketch);
598   }
599   else {
600     if (myPreviousEdge.Orientation() == TopAbs_FORWARD )
601       pt = BRep_Tool::Pnt(TopExp::LastVertex(TopoDS::Edge(myPreviousEdge)));
602     else 
603       pt = BRep_Tool::Pnt(TopExp::FirstVertex(TopoDS::Edge(myPreviousEdge)));
604   }
605   gp_Pnt2d pt2d= ProjLib::Project(myPlane->Pln(),pt);
606   myLastX = pt2d.X();
607   myLastY = pt2d.Y();
608
609   return false;
610 }
611
612 /*!
613   Set a specific plane for sketch.
614
615   \param GeomyPlane     
616 */
617 void Sketch::SetPlane(const Handle(Geom_Plane)& aPlane)
618 {
619   myPlane = aPlane;
620 }
621
622 /*!
623   Set display parameters.
624
625   \param aColor 
626 */
627 void Sketch::SetWireColor(const Quantity_Color& aColor)
628 {
629   myWireColor = aColor;
630 }
631
632 /*!
633   Set display parameters.
634
635   \param aColor 
636 */
637 void Sketch::SetCurrentColor(const Quantity_Color& aColor)
638 {
639   myCurrentColor = aColor;
640 }
641
642 /*!
643   Set display parameters.
644   
645   \param aColor 
646 */
647 void Sketch::SetAxisColor(const Quantity_Color& aColor)
648 {
649   myAxisColor = aColor;
650 }
651
652
653 /*!
654   Change mode of construction line.
655
656   \param aMode : SEGMENT, ARC_CHORD.
657 */
658 void Sketch::ChangeMode(const SketchStatus aMode)
659 {
660   gp_Pnt2d p;
661   if (myEdgesNumber > 0) {
662     if (myPreviousEdge.Orientation() == TopAbs_FORWARD)
663       p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::LastVertex(myPreviousEdge)));
664     else
665       p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::FirstVertex(myPreviousEdge)));
666     myLastX = p.X();
667     myLastY = p.Y();
668     myInteractiveContext->CloseLocalContext(myInteractiveContext->IndexOfCurrentLocal());
669   }
670   if (!myCurrentStatus == BEGIN_SKETCH) 
671     myCurrentStatus = aMode; /* change the mode only when the sketch is not in state BEGIN_SKETCH, i.d. fist point has been fixed */
672
673 }
674
675 /*!
676   Set transition constraint between consecutive edges.
677
678   \param aStatus : NOCONSTRAINT, TANGENT, PERPENDICULAR, ANGLE, LENGTH_FIXED, X_FIXED, Y_FIXED.
679 */
680 void Sketch::SetTransitionStatus(const TransitionStatus aStatus)
681 {
682   myTransitionStatus = aStatus;
683 }
684
685 /*!
686   Set or unset the display of dimensions.
687
688   \param atype  
689   \param OnOff  
690 */
691 void Sketch::SetParameterVisibility(const TypeOfParameter atype, const Standard_Boolean OnOff)
692 {
693   switch (atype) {
694   case ANGLE_PARAMETER:
695     myIsAngleDimensionVisible = OnOff;
696     if (!myIsAngleDimensionVisible && !myAngleDimension.IsNull())
697       myInteractiveContext->Erase(myAngleDimension,Standard_True,Standard_False);
698     //else DCQ
699     //  DisplayCurrentEdge();
700     break;
701   case LENGTH_PARAMETER:
702     myIsLengthDimensionVisible = OnOff;
703     if (!myIsLengthDimensionVisible&& !myLengthDimension.IsNull())
704       myInteractiveContext->Erase(myLengthDimension,Standard_True,Standard_False);
705     //else DCQ
706     //  DisplayCurrentEdge();
707     break;
708   case RADIUS_PARAMETER:
709     myIsRadiusDimensionVisible = OnOff;
710     if (!myIsRadiusDimensionVisible&& !myRadiusDimension.IsNull()){
711       myInteractiveContext->Erase(myRadiusDimension,Standard_True,Standard_False);
712       myInteractiveContext->Erase(myCenterCircle,Standard_True,Standard_False);
713     }
714     //else DCQ
715     //  DisplayCurrentEdge();
716     break;
717   case XVALUE_PARAMETER:
718     myIsXDimensionVisible = OnOff;
719     if (!myIsXDimensionVisible&& !myXDimension.IsNull())
720       myInteractiveContext->Erase(myXDimension,Standard_True,Standard_False);
721     break;
722   case YVALUE_PARAMETER:
723     myIsYDimensionVisible = OnOff;
724     if (!myIsYDimensionVisible&& !myYDimension.IsNull())
725       myInteractiveContext->Erase(myYDimension,Standard_True,Standard_False);
726     break;
727   }
728 }
729
730 /*!
731   Hilight parameters.
732
733   \param atype  
734   \param acolor 
735 */
736 void Sketch::HiligthWithColor(const TypeOfParameter atype, const Quantity_NameOfColor acolor)
737 {
738   switch (atype) {
739   case ANGLE_PARAMETER:
740     myInteractiveContext->HilightWithColor(myAngleDimension, acolor);
741     break;
742   case LENGTH_PARAMETER:
743     myInteractiveContext->HilightWithColor(myLengthDimension, acolor);
744     break;
745   case RADIUS_PARAMETER:
746     myInteractiveContext->HilightWithColor(myRadiusDimension, acolor);
747     break;
748   case XVALUE_PARAMETER:
749     myInteractiveContext->HilightWithColor(myXDimension, acolor);
750     break;
751   case YVALUE_PARAMETER:
752     myInteractiveContext->HilightWithColor(myYDimension, acolor);
753     break;
754   }
755 }
756
757         
758 /*!
759   Unhilight parameters.
760
761   \param atype  
762 */
763 void Sketch::Unhiligth(const TypeOfParameter atype)
764 {
765   switch (atype) {
766   case ANGLE_PARAMETER:
767     myInteractiveContext->Unhilight(myAngleDimension);
768     break;
769   case LENGTH_PARAMETER:
770     myInteractiveContext->Unhilight(myLengthDimension);
771     break;
772   case RADIUS_PARAMETER:
773     myInteractiveContext->Unhilight(myRadiusDimension);
774     break;
775   case XVALUE_PARAMETER:
776     myInteractiveContext->Unhilight(myXDimension);
777     break;
778   case YVALUE_PARAMETER:
779     myInteractiveContext->Unhilight(myYDimension);
780     break;
781   }
782 }
783
784 /*!
785   Check if the edition of a type of parameter is relevant depending on sketch current status.
786
787   \param atype  
788   \return Standard_Boolean
789 */
790 Standard_Boolean Sketch::IsValidCurrentParameter(const TypeOfParameter atype)
791 {
792   switch (atype) {
793   case ANGLE_PARAMETER:
794     if (myCurrentStatus != SEGMENT && myCurrentStatus != ARC_CHORD) 
795       return Standard_False;
796     else if (myTransitionStatus == TANGENT || myTransitionStatus == PERPENDICULAR)  
797       return Standard_False;
798     else if (myEdgesNumber < 1)
799       return Standard_False;
800     else  {
801       TopLoc_Location L;
802       Standard_Real First,Last;
803       Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last);
804       if (!PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) 
805         return Standard_False;
806     }
807     break;
808   case LENGTH_PARAMETER:
809     if (myCurrentStatus != SEGMENT   && 
810         myCurrentStatus != ARC_CHORD /*&&
811                                           myCurrentStatus != CURVE_POINTS*/
812         ) 
813       return Standard_False;
814     else if (myTransitionStatus == LENGTH_FIXED) 
815       return Standard_False;
816     break;
817   case RADIUS_PARAMETER:
818     if (myCurrentStatus != ARC_CHORD_END)
819       return Standard_False;
820     break;
821   case XVALUE_PARAMETER:
822     if (myCurrentStatus != SEGMENT   && 
823         myCurrentStatus != ARC_CHORD /*&&
824                                           myCurrentStatus != CURVE_POINTS*/
825         ) 
826       return Standard_False;
827     else if (myTransitionStatus == X_FIXED) 
828       return Standard_False;
829     break;
830   case YVALUE_PARAMETER:
831     if (myCurrentStatus != SEGMENT   && 
832         myCurrentStatus != ARC_CHORD /*&&
833                                           myCurrentStatus != CURVE_POINTS*/
834         ) 
835       return Standard_False;
836     else if (myTransitionStatus == Y_FIXED) 
837       return Standard_False;
838     break;
839   }
840   return Standard_True;
841 }
842
843 /*!
844   Set a parameter value.
845
846   \param atype  
847   \param aValue 
848 */
849 void Sketch::SetParameterValue(const TypeOfParameter atype, Standard_Real aValue)
850 {
851   switch (atype) {
852   case ANGLE_PARAMETER:
853     SetSegmentAngle(aValue);
854     break;
855   case LENGTH_PARAMETER:
856     SetDimension(aValue);
857     break;
858   case RADIUS_PARAMETER:
859     SetDimension(aValue);
860     break;
861   case XVALUE_PARAMETER:
862     SetXDimension(aValue);
863     break;
864   case YVALUE_PARAMETER:
865     SetYDimension(aValue);
866     break;
867   }
868 }
869
870 /*!
871   Initialisation of sketch parameters or options.
872 */
873 void Sketch::Init()
874 {
875   myPlane = new Geom_Plane (0.,0.,1.,0.);
876   CreateConstraints();
877   BRepLib::Plane(myPlane);
878   myEdgesNumber = 0;
879   myCurrentStatus = BEGIN_SKETCH;
880   /* In order to update the visulisation of current objects by using Redisplay method from InteractiveContext */
881   myCurrentEdge = BRepBuilderAPI_MakeVertex(gp_Pnt(0.,0.,0.));          
882   myPresentableEdge = new AIS_Shape(myCurrentEdge);
883   myPresentableEdge->SetColor(myCurrentColor.Name());
884   myInteractiveContext->Display(myPresentableEdge);
885   myTransitionStatus = NOCONSTRAINT;
886   /* Init for display objects */
887   TopoDS_Vertex V1 = BRepBuilderAPI_MakeVertex(gp_Pnt(0.,0.,0.));
888   TopoDS_Vertex V2 = BRepBuilderAPI_MakeVertex(gp_Pnt(10.,0.,0.));
889   myLengthDimension = new AIS_LengthDimension (V1,V2,myPlane,0.,TCollection_ExtendedString());
890   myXDimension = new AIS_LengthDimension (V1,V2,myPlane,0.,TCollection_ExtendedString(),gp_Pnt(),DsgPrs_AS_NONE,
891                                           AIS_TOD_Horizontal);
892   myYDimension = new AIS_LengthDimension (V1,V2,myPlane,0.,TCollection_ExtendedString(),gp_Pnt(),DsgPrs_AS_NONE,
893                                           AIS_TOD_Vertical);
894   myRadiusDimension = new AIS_LengthDimension (V1,V2,myPlane,0.,TCollection_ExtendedString());
895   myCenterCircle = new AIS_Shape(V1);
896   myIsLengthDimensionVisible = Standard_False;
897   myIsXDimensionVisible = Standard_False;
898   myIsYDimensionVisible = Standard_False;
899   myIsRadiusDimensionVisible = Standard_False;
900 }
901
902 /*!
903   Build the current segment.
904
905   \param X      
906   \param Y      
907 */
908 void Sketch::MakeCurrentSegment(Standard_Real X, Standard_Real Y)
909 {
910   if (myTransitionStatus == NOCONSTRAINT) 
911     myCurrentEdge = BRepBuilderAPI_MakeEdge2d(gp_Pnt2d(myLastX,myLastY), gp_Pnt2d(X,Y));
912   else if (myTransitionStatus == X_FIXED) 
913     myCurrentEdge = BRepBuilderAPI_MakeEdge2d(gp_Pnt2d(myLastX,myLastY),gp_Pnt2d(mySegmentX,Y));
914   else if (myTransitionStatus == Y_FIXED) 
915     myCurrentEdge = BRepBuilderAPI_MakeEdge2d(gp_Pnt2d(myLastX,myLastY),gp_Pnt2d(X,mySegmentY));
916   else if (myTransitionStatus == TANGENT && myEdgesNumber > 0) {
917     Standard_Real first,last;
918     TopLoc_Location L;
919     Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,first,last);
920     gp_Pnt2d p1;
921     gp_Vec2d Vt;
922     if (myPreviousEdge.Orientation() == TopAbs_FORWARD)
923       C->D1(last,p1,Vt);
924     else 
925       C->D1(first,p1,Vt);
926     gp_Lin2d aline(p1,Vt);
927     Geom2dAPI_ProjectPointOnCurve proj(gp_Pnt2d(X,Y),new Geom2d_Line(aline));
928     if (proj.NbPoints() > 0)
929       myCurrentEdge = BRepBuilderAPI_MakeEdge2d(p1,proj.Point(1));
930   }
931   else if (myTransitionStatus == PERPENDICULAR && myEdgesNumber > 0) {
932     Standard_Real first,last;
933     TopLoc_Location L;
934     Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,first,last);
935     gp_Pnt2d p1;
936     gp_Lin2d perpen;
937     if (myPreviousEdge.Orientation() == TopAbs_FORWARD)
938       C->D0(last,p1);
939     else 
940       C->D0(first,p1);
941     if (C->IsKind(STANDARD_TYPE(Geom2d_Line))) {
942       GccAna_Lin2dTanPer aSol(p1,Handle(Geom2d_Line)::DownCast(C)->Lin2d());
943       perpen = aSol.ThisSolution(1);
944     }
945     else if (C->IsKind(STANDARD_TYPE(Geom2d_Circle))) {
946       GccAna_Lin2dTanPer aSol(p1,Handle(Geom2d_Circle)::DownCast(C)->Circ2d());
947       perpen = aSol.ThisSolution(1);
948     }
949     Geom2dAPI_ProjectPointOnCurve proj(gp_Pnt2d(X,Y),new Geom2d_Line(perpen));
950     if (proj.NbPoints() > 0)
951       myCurrentEdge = BRepBuilderAPI_MakeEdge2d(p1,proj.Point(1));
952   }
953   else if (myTransitionStatus == ANGLE && myEdgesNumber > 0) {
954     Standard_Real First,Last;
955     TopLoc_Location L;
956     Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last);
957     if (PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) {
958       Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(myPreviousEdge),myPlane,L,First,Last);
959       Standard_Real angle;
960       if (0 <= mySegmentAngle &&  mySegmentAngle<= PI )
961         angle = PI - mySegmentAngle;
962       else
963         angle = mySegmentAngle - PI;
964       GccAna_Lin2dTanObl aSol(gp_Pnt2d(myLastX,myLastY),Handle(Geom2d_Line)::DownCast(PreviousCurve)->Lin2d(),angle);
965       Standard_Real dist = RealLast();
966       gp_Pnt2d pt(X,Y),ptproj;
967       for (Standard_Integer i =1; i<=aSol.NbSolutions(); i++) {
968         Geom2dAPI_ProjectPointOnCurve proj(pt,new Geom2d_Line(aSol.ThisSolution(i)));
969         if (pt.Distance(proj.Point(1)) < dist) {
970           dist = pt.Distance(proj.Point(1));
971           ptproj = proj.Point(1);
972         }
973       }
974       myCurrentEdge = BRepBuilderAPI_MakeEdge2d(gp_Pnt2d(myLastX,myLastY),ptproj);
975     }
976   }
977   else if (myTransitionStatus == LENGTH_FIXED && myEdgesNumber > 0) {
978     Standard_Real First,Last;
979     TopLoc_Location L;
980     Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last);
981     if (PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) {
982       Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(myPreviousEdge),myPlane,L,First,Last);
983       gp_Lin2d aline = gce_MakeLin2d(gp_Pnt2d(myLastX,myLastY), gp_Pnt2d(X,Y));
984       myCurrentEdge = BRepBuilderAPI_MakeEdge2d(aline,0.,mySegmentLength);
985     }
986   }
987 }
988
989 /*!
990   Build the current arc.
991
992   \param X      
993   \param Y      
994 */
995 void Sketch::MakeCurrentArc(Standard_Real X, Standard_Real Y)
996 {
997   gp_Circ2d CircSol;
998   Standard_Boolean OK(Standard_False);
999
1000   if (myTransitionStatus == NOCONSTRAINT) {
1001     GccAna_Circ2d2TanOn aSol(gp_Pnt2d(myLastX,myLastY), gp_Pnt2d(X,Y),myMediatrice->Lin2d(),Precision::Confusion());
1002     if (aSol.NbSolutions() > 0){
1003       CircSol = aSol.ThisSolution(1);
1004       OK = Standard_True;
1005     }
1006   }
1007   /* Tangency with previous edge */
1008   else if (myTransitionStatus == TANGENT && myEdgesNumber > 0) {
1009     Standard_Real first,last;
1010     TopLoc_Location L;
1011     Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,first,last);
1012     if (C->IsKind(STANDARD_TYPE(Geom2d_Line))){
1013       GccAna_Circ2d2TanOn aSol(GccEnt::Unqualified(Handle(Geom2d_Line)::DownCast(C)->Lin2d()), gp_Pnt2d(myLastX,myLastY),myMediatrice->Lin2d(),Precision::Confusion());
1014       if (aSol.NbSolutions() > 0){
1015         CircSol = aSol.ThisSolution(1);
1016         OK = Standard_True;
1017       }
1018     }
1019     else if (C->IsKind(STANDARD_TYPE(Geom2d_Circle))) {
1020       GccAna_Circ2d2TanOn aSol(GccEnt::Unqualified(Handle(Geom2d_Circle)::DownCast(C)->Circ2d()), gp_Pnt2d(myLastX,myLastY),myMediatrice->Lin2d(),Precision::Confusion());
1021       if (aSol.NbSolutions() > 0){
1022         CircSol = aSol.ThisSolution(1);
1023         OK = Standard_True;
1024       }
1025     }
1026     else if(C->IsKind(STANDARD_TYPE(Geom2d_BSplineCurve))) {
1027       gp_Pnt2d pc;
1028       gp_Vec2d Vt;
1029       C->D1(last,pc,Vt);
1030       gp_Lin2d alin2d(pc,gp_Dir2d(Vt));
1031       GccAna_Circ2d2TanOn aSol(GccEnt::Unqualified(alin2d), gp_Pnt2d(myLastX,myLastY),myMediatrice->Lin2d(),Precision::Confusion());
1032       if (aSol.NbSolutions() > 0){
1033         CircSol = aSol.ThisSolution(1);
1034         OK = Standard_True;
1035       }
1036     }
1037   }
1038   /* Tangency with the perpendicular to the previous edge */
1039   else if (myTransitionStatus == PERPENDICULAR && myEdgesNumber > 0) {
1040     Standard_Real first,last;
1041     TopLoc_Location L;
1042     Handle(Geom2d_Curve) C = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,first,last);
1043     gp_Pnt2d p1;
1044     gp_Lin2d perpen;
1045     if (myPreviousEdge.Orientation() == TopAbs_FORWARD)
1046       C->D0(last,p1);
1047     else 
1048       C->D0(first,p1);
1049     if (C->IsKind(STANDARD_TYPE(Geom2d_Line))) {
1050       GccAna_Lin2dTanPer aSol(p1,Handle(Geom2d_Line)::DownCast(C)->Lin2d());
1051       perpen = aSol.ThisSolution(1);
1052     }
1053     else if (C->IsKind(STANDARD_TYPE(Geom2d_Circle))) {
1054       GccAna_Lin2dTanPer aSol(p1,Handle(Geom2d_Circle)::DownCast(C)->Circ2d());
1055       perpen = aSol.ThisSolution(1);
1056     }
1057     GccAna_Circ2d2TanOn aSol(GccEnt::Unqualified(perpen), gp_Pnt2d(myLastX,myLastY),myMediatrice->Lin2d(),Precision::Confusion());
1058     if (aSol.NbSolutions() > 0){
1059       CircSol = aSol.ThisSolution(1);
1060       OK = Standard_True;
1061     }
1062   }
1063
1064   gp_Pnt2d p;
1065   if (myEdgesNumber > 0) {
1066     if (myPreviousEdge.Orientation() == TopAbs_FORWARD)
1067       p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::LastVertex(myPreviousEdge)));
1068     else
1069       p = ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(TopExp::FirstVertex(myPreviousEdge)));
1070   }
1071   else
1072     p =  ProjLib::Project(myPlane->Pln(),BRep_Tool::Pnt(myFirstPointSketch));
1073   if (OK){
1074     gp_Vec2d V1(p,gp_Pnt2d(X,Y));
1075     gp_Vec2d V2(p,gp_Pnt2d(myLastX,myLastY));
1076     if (V1.Angle(V2) > 0 )
1077       myCurrentEdge = BRepBuilderAPI_MakeEdge2d(CircSol,p,gp_Pnt2d(myLastX,myLastY));
1078     else {      
1079       myCurrentEdge = BRepBuilderAPI_MakeEdge2d(CircSol,gp_Pnt2d(myLastX,myLastY),p);
1080       myCurrentEdge.Reverse();
1081     }
1082   }
1083   else {
1084     myCurrentStatus = ARC_CHORD;
1085     myLastX = p.X();
1086     myLastY = p.Y();
1087     myInteractiveContext->CloseLocalContext();
1088   }
1089
1090 }
1091
1092 /*!
1093   Display the current edge under construction with it's dimension.
1094 */
1095 void Sketch::DisplayCurrentEdge()
1096 {
1097   myPresentableEdge->Set(myCurrentEdge);
1098   myInteractiveContext->Redisplay(myPresentableEdge);
1099   if (myCurrentStatus == SEGMENT ||
1100       myCurrentStatus == ARC_CHORD ) {
1101     /* Length dimension */
1102     TopoDS_Vertex V1 = TopExp::FirstVertex(TopoDS::Edge(myCurrentEdge));
1103     TopoDS_Vertex V2 = TopExp::LastVertex(TopoDS::Edge(myCurrentEdge));
1104     DisplayLengthDimension(V1,V2);
1105     /* Angular dimension */
1106     DisplayAngleDimension();
1107     DisplayXDimension(V1,V2);
1108     DisplayYDimension(V1,V2);
1109   }
1110   else if (myCurrentStatus == ARC_CHORD_END ) 
1111     DisplayRadiusDimension();
1112   else {
1113     TopoDS_Vertex V1 = TopoDS::Vertex(myCurrentEdge);
1114     TopoDS_Vertex V2 = BRepBuilderAPI_MakeVertex(gp_Pnt(0.,0.,0.));
1115     DisplayXDimension(V1,V2);
1116     DisplayYDimension(V1,V2);
1117   }
1118     
1119 }
1120
1121 /*!
1122   Display the current length dimension.
1123
1124   \param V1     
1125   \param V2     
1126 */
1127 void Sketch::DisplayLengthDimension(const TopoDS_Vertex& V1,const TopoDS_Vertex& V2)
1128 {
1129   gp_Pnt p1 = BRep_Tool::Pnt(TopoDS::Vertex(V1));
1130   gp_Pnt p2 = BRep_Tool::Pnt(TopoDS::Vertex(V2));
1131   Standard_Real length = p1.Distance(p2);
1132   if (length <= Precision::Confusion()) return;
1133   myLengthDimension->SetFirstShape(V1);
1134   myLengthDimension->SetSecondShape(V2);
1135   fitInResol(length);
1136   myLengthDimension->SetValue(length);
1137   QString S;
1138   S.sprintf("%.1f",length);
1139   myLengthDimension->SetText(TCollection_ExtendedString(strdup(S)));
1140   if (myIsLengthDimensionVisible) {
1141     if (myInteractiveContext->IsDisplayed(myLengthDimension))
1142       myInteractiveContext->Redisplay(myLengthDimension);
1143     else
1144       myInteractiveContext->Display(myLengthDimension);
1145   }
1146 }
1147
1148 /*!
1149   Display the current X dimension.
1150
1151   \param V1     
1152   \param V2     
1153 */
1154 void Sketch::DisplayXDimension(const TopoDS_Vertex& V1,const TopoDS_Vertex& V2)
1155 {
1156   if (myTransitionStatus != X_FIXED) {
1157   gp_Pnt p1 = BRep_Tool::Pnt(TopoDS::Vertex(V1));
1158   gp_Pnt p2 = BRep_Tool::Pnt(TopoDS::Vertex(V2));
1159
1160   gp_Lin aline(p1,myPlane->Pln().XAxis().Direction());
1161   GeomAPI_ProjectPointOnCurve proj(p2,new Geom_Line(aline));
1162
1163   gp_Pnt pb = p1;
1164
1165   if (proj.NbPoints() > 0) {
1166     Standard_Real length = p1.Distance(proj.Point(1));
1167     if (length <= Precision::Confusion()) return;
1168     myXDimension->SetFirstShape(V1);
1169     myXDimension->SetSecondShape(V2);
1170     fitInResol(length);
1171     myXDimension->SetValue(length);
1172     QString S;
1173     S.sprintf("%.1f",length);
1174     myXDimension->SetText(TCollection_ExtendedString(strdup(S)));
1175     //    myXDimension->SetPosition(proj.Point(1));
1176     pb.BaryCenter(5,proj.Point(1),5);
1177     myXDimension->SetPosition(pb);
1178     if (myIsXDimensionVisible) {
1179       if (myInteractiveContext->IsDisplayed(myXDimension))
1180         myInteractiveContext->Redisplay(myXDimension);
1181       else
1182         myInteractiveContext->Display(myXDimension);
1183     }
1184   }
1185   } else
1186     myInteractiveContext->Erase(myXDimension,Standard_True,Standard_False);
1187 }
1188
1189 /*!
1190   Display the current Y dimension.
1191
1192   \param V1     
1193   \param V2     
1194 */
1195 void Sketch::DisplayYDimension(const TopoDS_Vertex& V1,const TopoDS_Vertex& V2)
1196 {
1197   if (myTransitionStatus != Y_FIXED) {
1198
1199   gp_Pnt p1 = BRep_Tool::Pnt(TopoDS::Vertex(V1));
1200   gp_Pnt p2 = BRep_Tool::Pnt(TopoDS::Vertex(V2));
1201   gp_Lin aline(p2 /*p1*/, myPlane->Pln().YAxis().Direction());
1202   gp_Pnt pb = p2 /*p1*/;
1203   GeomAPI_ProjectPointOnCurve proj(p1 /*p2*/,new Geom_Line(aline));
1204   if (proj.NbPoints() > 0) {
1205     Standard_Real length = /*p1*/ p2.Distance(proj.Point(1));
1206     if (length <= Precision::Confusion()) return;
1207     myYDimension->SetFirstShape(V1);
1208     myYDimension->SetSecondShape(V2);
1209     fitInResol(length);
1210     myYDimension->SetValue(length);
1211     QString S;
1212     S.sprintf("%.1f",length);
1213     myYDimension->SetText(TCollection_ExtendedString(strdup(S)));
1214     pb.BaryCenter(5,proj.Point(1),5);
1215     myYDimension->SetPosition(pb);
1216     //    myYDimension->SetPosition(p2);
1217     if (myIsYDimensionVisible) {
1218       if (myInteractiveContext->IsDisplayed(myYDimension))
1219         myInteractiveContext->Redisplay(myYDimension);
1220       else
1221         myInteractiveContext->Display(myYDimension);
1222     }
1223   }
1224   } else
1225     myInteractiveContext->Erase(myYDimension,Standard_True,Standard_False);
1226 }
1227
1228 /*!
1229   Display the current angle dimension.
1230 */
1231 void Sketch::DisplayAngleDimension()
1232 {
1233   if (!myIsAngleDimensionVisible)
1234     return;
1235   if (myEdgesNumber > 0) {
1236     Standard_Real First,Last;
1237     TopLoc_Location L;
1238     Handle (Geom2d_Curve) PreviousCurve = BRep_Tool::CurveOnSurface(myPreviousEdge,myPlane,L,First,Last);
1239     Handle (Geom2d_Curve) CurrentCurve = BRep_Tool::CurveOnSurface(TopoDS::Edge(myCurrentEdge),myPlane,L,First,Last);
1240     if (PreviousCurve->IsKind(STANDARD_TYPE(Geom2d_Line)) && CurrentCurve->IsKind(STANDARD_TYPE(Geom2d_Line))) {
1241       Standard_Real angle = Handle(Geom2d_Line)::DownCast(PreviousCurve)->Lin2d().Angle(Handle(Geom2d_Line)::DownCast(CurrentCurve)->Lin2d());
1242       gp_Pnt2d apos;
1243       if (0 <= angle && angle<= PI) 
1244         angle = PI - angle;
1245       else 
1246         angle = PI + angle;
1247       CurrentCurve->D0((First+Last)/5.,apos);
1248       gp_Pnt apos3d = ElCLib::To3d(myPlane->Pln().Position().Ax2(),apos);
1249       Standard_Real angtext = angle*180./PI;
1250       mySegmentAngle = angle;
1251       BRepLib::BuildCurve3d(TopoDS::Edge(myCurrentEdge));
1252       fitInResol(angtext);
1253                         
1254       QString S;
1255       S.sprintf("%.1f",angtext);
1256       if (myInteractiveContext->IndexOfCurrentLocal() == 0) {
1257         myInteractiveContext->OpenLocalContext();
1258         myAngleDimension = new AIS_AngleDimension(myPreviousEdge,TopoDS::Edge(myCurrentEdge),myPlane,angle,
1259                                                   TCollection_ExtendedString(strdup(S)));
1260         myInteractiveContext->Display(myAngleDimension);
1261       }
1262       else {
1263         myAngleDimension->SetSecondShape(myCurrentEdge);
1264         myAngleDimension->SetValue(angle);
1265         myAngleDimension->SetPosition(apos3d);
1266         myAngleDimension->SetText(TCollection_ExtendedString(strdup(S)));
1267         myInteractiveContext->Redisplay(myAngleDimension);
1268       }
1269     }
1270   }
1271 }
1272
1273 /*!
1274   Display the current radius dimension.
1275 */
1276 void Sketch::DisplayRadiusDimension()
1277 {
1278   if (! myIsRadiusDimensionVisible)
1279     return;
1280   BRepLib::BuildCurve3d(TopoDS::Edge(myCurrentEdge));
1281   Standard_Real First,Last;
1282   Handle (Geom_Circle) C = Handle (Geom_Circle)::DownCast(BRep_Tool::Curve(TopoDS::Edge(myCurrentEdge),First,Last));
1283   if (!C.IsNull()) {
1284     Standard_Real R = C->Radius();
1285     TopoDS_Shape V1 = BRepBuilderAPI_MakeVertex(C->Location());
1286     gp_Pnt MidlePoint ;
1287     C->D0((First+Last)/2.,MidlePoint);
1288     TopoDS_Vertex V2 = BRepBuilderAPI_MakeVertex(MidlePoint);
1289     myRadiusDimension->SetFirstShape(V1);
1290     myRadiusDimension->SetSecondShape(V2);
1291     myRadiusDimension->SetValue(R);
1292     fitInResol(R);
1293     QString S;
1294     S.sprintf("%.1f",R);
1295     myRadiusDimension->SetText(TCollection_ExtendedString(strdup(S)));
1296     if (myInteractiveContext->IsDisplayed(myRadiusDimension))
1297       myInteractiveContext->Redisplay(myRadiusDimension);
1298     else
1299       myInteractiveContext->Display(myRadiusDimension);
1300     myCenterCircle->Set(V1);
1301     if (myInteractiveContext->IsDisplayed(myCenterCircle))
1302       myInteractiveContext->Redisplay(myCenterCircle);
1303     else
1304       myInteractiveContext->Display(myCenterCircle);
1305   }
1306 }
1307
1308 /*!
1309   Remove last edge from the current wire.
1310 */
1311 void Sketch::RemoveLastEdge()
1312 {
1313   if (myEdgesNumber == 0) {
1314     myCurrentStatus = END_SKETCH;
1315     myInteractiveContext->CloseAllContexts();
1316     myInteractiveContext->EraseAll(Standard_False);
1317     return;
1318   }
1319   else {
1320     BRepTools_WireExplorer Ex;
1321     BRepBuilderAPI_MakeWire MW;
1322     Standard_Integer index = 1;
1323     myCurrentEdge = myPreviousEdge;
1324     for (Ex.Init(myCurrentWire.Wire());Ex.More();Ex.Next()){
1325       if (index <= myEdgesNumber-1) {
1326         MW.Add(Ex.Current());
1327         myPreviousEdge = Ex.Current();
1328         index++;
1329       }
1330     }
1331     myCurrentWire = MW;
1332     myCurrentStatus = (SketchStatus)myConstructionMode(myEdgesNumber);
1333     myTransitionStatus = (TransitionStatus)myConstraintMode(myEdgesNumber);
1334     myEdgesNumber--;
1335     myConstructionMode.Remove(index);
1336     myConstraintMode.Remove(index);
1337     if (myEdgesNumber == 0) 
1338       myPresentableWire->Set(myFirstPointSketch);
1339     else
1340       myPresentableWire->Set(myCurrentWire.Wire());
1341     myInteractiveContext->Redisplay(myPresentableWire);
1342     myInteractiveContext->CloseLocalContext();
1343     myPresentableEdge->Set(myCurrentEdge);
1344     myInteractiveContext->Redisplay(myPresentableEdge);
1345   }
1346 }
1347
1348 /*!
1349   Create initial constraints.
1350 */
1351 void Sketch::CreateConstraints()
1352 {
1353   Handle(Geom_Axis1Placement) xAxis = new Geom_Axis1Placement(myPlane->Pln().XAxis());
1354   Handle(Geom_Axis1Placement) yAxis = new Geom_Axis1Placement(myPlane->Pln().YAxis());
1355   myHAxis = new AIS_Axis(xAxis);
1356   myVAxis = new AIS_Axis(yAxis);
1357   myAngularAxis = myVAxis;
1358   myHAxis->SetColor(myAxisColor.Name());
1359   myVAxis->SetColor(myAxisColor.Name());
1360   myAngularAxis->SetColor(myAxisColor.Name());
1361 }
1362
1363 /*!
1364   fitInResol.
1365
1366   \param toFit  
1367   \param minIsResol     
1368 */
1369 void Sketch::fitInResol(Standard_Real &toFit, Standard_Boolean minIsResol)
1370
1371   Standard_Real sign =  (toFit < 0) ? -1. : +1.;
1372   Standard_Real value = toFit + sign * resol/2.0; /* why "+ resol/2.0" ? because if resol = 0.5, 3.3 is rounded to 3.5 */
1373   int nTimesResol = int(value/resol);
1374   if ((nTimesResol == 0) &&  (minIsResol)) nTimesResol = 1;
1375   toFit = nTimesResol*resol;
1376 }
1377
1378 SketchStatus Sketch::GetCurrentStatus()
1379 {
1380   return myCurrentStatus;
1381 }
1382
1383 Standard_Integer Sketch::GetmyEdgesNumber()
1384 {
1385   return myEdgesNumber;
1386 }
1387
1388
1389