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