0031709: Draw Harness - move methods ViewerTest::ParseOnOff()/ParseColor() to package...
[occt.git] / src / ViewerTest / ViewerTest_RelationCommands.cxx
1 // Created on: 1998-11-12
2 // Created by: Robert COUBLANC
3 // Copyright (c) 1998-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
5 //
6 // This file is part of Open CASCADE Technology software library.
7 //
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
13 //
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
16
17 #include <ViewerTest.hxx>
18
19 #include <AIS_Circle.hxx>
20 #include <AIS_DisplayMode.hxx>
21 #include <AIS_InteractiveContext.hxx>
22 #include <AIS_ListIteratorOfListOfInteractive.hxx>
23 #include <AIS_ListOfInteractive.hxx>
24 #include <AIS_MapOfInteractive.hxx>
25 #include <AIS_Point.hxx>
26 #include <AIS_Shape.hxx>
27 #include <PrsDim_AngleDimension.hxx>
28 #include <PrsDim_ConcentricRelation.hxx>
29 #include <PrsDim_DiameterDimension.hxx>
30 #include <PrsDim_EqualDistanceRelation.hxx>
31 #include <PrsDim_EqualRadiusRelation.hxx>
32 #include <PrsDim_FixRelation.hxx>
33 #include <PrsDim_IdenticRelation.hxx>
34 #include <PrsDim_KindOfRelation.hxx>
35 #include <PrsDim_LengthDimension.hxx>
36 #include <PrsDim_OffsetDimension.hxx>
37 #include <PrsDim_ParallelRelation.hxx>
38 #include <PrsDim_PerpendicularRelation.hxx>
39 #include <PrsDim_RadiusDimension.hxx>
40 #include <PrsDim_Relation.hxx>
41 #include <PrsDim_SymmetricRelation.hxx>
42 #include <PrsDim_TangentRelation.hxx>
43 #include <BRep_Builder.hxx>
44 #include <BRep_Tool.hxx>
45 #include <BRepAdaptor_Curve.hxx>
46 #include <BRepBuilderAPI_MakeVertex.hxx>
47 #include <BRepExtrema_ExtCC.hxx>
48 #include <BRepExtrema_ExtPC.hxx>
49 #include <BRepExtrema_ExtCF.hxx>
50 #include <BRepExtrema_ExtPF.hxx>
51 #include <BRepExtrema_ExtFF.hxx>
52 #include <BRepTools.hxx>
53 #include <Draw_Interpretor.hxx>
54 #include <Draw.hxx>
55 #include <Draw_Appli.hxx>
56 #include <Draw_Window.hxx>
57 #include <DBRep.hxx>
58 #include <ElSLib.hxx>
59 #include <Font_FontMgr.hxx>
60 #include <GC_MakePlane.hxx>
61 #include <Geom_CartesianPoint.hxx>
62 #include <Geom_Circle.hxx>
63 #include <Geom_Line.hxx>
64 #include <Geom_Plane.hxx>
65 #include <GeomAPI_IntCS.hxx>
66 #include <gce_MakeLin.hxx>
67 #include <gce_MakePln.hxx>
68 #include <gp_Circ.hxx>
69 #include <gp_Pln.hxx>
70 #include <IntAna_IntConicQuad.hxx>
71 #include <IntAna_Quadric.hxx>
72 #include <Message.hxx>
73 #include <Precision.hxx>
74 #include <StdSelect.hxx>
75 #include <TCollection_AsciiString.hxx>
76 #include <TCollection_ExtendedString.hxx>
77 #include <TColStd_MapOfInteger.hxx>
78 #include <TColStd_SequenceOfReal.hxx>
79 #include <TopAbs.hxx>
80 #include <TopAbs_ShapeEnum.hxx>
81 #include <TopExp.hxx>
82 #include <TopExp_Explorer.hxx>
83 #include <TopoDS.hxx>
84 #include <TopoDS_Face.hxx>
85 #include <TopoDS_Solid.hxx>
86 #include <TopoDS_Vertex.hxx>
87 #include <V3d_Viewer.hxx>
88 #include <V3d_View.hxx>
89 #include <V3d.hxx>
90 #include <ViewerTest_DoubleMapOfInteractiveAndName.hxx>
91 #include <ViewerTest_DoubleMapIteratorOfDoubleMapOfInteractiveAndName.hxx>
92 #include <ViewerTest_EventManager.hxx>
93
94 extern Standard_Boolean VDisplayAISObject (const TCollection_AsciiString& theName,
95                                            const Handle(AIS_InteractiveObject)& theAISObj,
96                                            Standard_Boolean theReplaceIfExists = Standard_True);
97 extern ViewerTest_DoubleMapOfInteractiveAndName& GetMapOfAIS();
98 extern int ViewerMainLoop(Standard_Integer argc, const char** argv);
99 extern Handle(AIS_InteractiveContext)& TheAISContext ();
100
101 #define VertexMask 0x01
102 #define EdgeMask 0x02
103 #define FaceMask 0x04
104
105 //=======================================================================
106 //function : Get3DPointAtMousePosition
107 //purpose  : Calculates the 3D points corresponding to the mouse position
108 //           in the plane of the view
109 //=======================================================================
110 static gp_Pnt Get3DPointAtMousePosition()
111 {
112   Handle(V3d_View) aView = ViewerTest::CurrentView();
113
114   Standard_Real xv,yv,zv;
115   aView->Proj (xv,yv,zv);
116   Standard_Real xat,yat,zat;
117   aView->At(xat,yat,zat);
118   gp_Pln aPlane (gp_Pnt(xat,yat,zat), gp_Dir(xv,yv,zv));
119   
120   Standard_Integer aPixX, aPixY;
121   Standard_Real aX, aY, aZ, aDX, aDY, aDZ;
122
123   ViewerTest::GetMousePosition (aPixX, aPixY);
124   aView->ConvertWithProj (aPixX, aPixY, aX, aY, aZ, aDX, aDY, aDZ);
125   gp_Lin aLine( gp_Pnt(aX, aY, aZ), gp_Dir(aDX, aDY, aDZ) );
126
127   // Compute intersection
128   Handle(Geom_Line) aGeomLine = new Geom_Line (aLine);
129   Handle(Geom_Plane) aGeomPlane = new Geom_Plane (aPlane);
130   GeomAPI_IntCS anIntersector (aGeomLine, aGeomPlane);
131   if (!anIntersector.IsDone() || anIntersector.NbPoints() == 0)
132   {
133     return gp::Origin();
134   }
135   return anIntersector.Point (1);
136 }
137
138 //=======================================================================
139 //function : Get3DPointAtMousePosition
140 //purpose  : Calculates the 3D points corresponding to the mouse position
141 //           in the plane of the view
142 //=======================================================================
143 static Standard_Boolean Get3DPointAtMousePosition (const gp_Pnt& theFirstPoint,
144                                                    const gp_Pnt& theSecondPoint,
145                                                    gp_Pnt& theOutputPoint)
146 {
147   theOutputPoint = gp::Origin();
148
149   Handle(V3d_View) aView = ViewerTest::CurrentView();
150
151   Standard_Integer aPixX, aPixY;
152   Standard_Real aX, aY, aZ, aDx, aDy, aDz, aUx, aUy, aUz;
153
154   // Get 3D point in view coordinates and projection vector from the pixel point.
155   ViewerTest::GetMousePosition (aPixX, aPixY);
156   aView->ConvertWithProj (aPixX, aPixY, aX, aY, aZ, aDx, aDy, aDz);
157   gp_Lin aProjLin (gp_Pnt(aX, aY, aZ), gp_Dir(aDx, aDy, aDz));
158
159   // Get plane
160   gp_Vec aDimVec (theFirstPoint, theSecondPoint);
161   aView->Up (aUx, aUy, aUz);
162   gp_Vec aViewUp (aUx, aUy, aUz);
163
164   if (aDimVec.IsParallel (aViewUp, Precision::Angular()))
165   {
166     theOutputPoint = Get3DPointAtMousePosition();
167     return Standard_True;
168   }
169
170   gp_Vec aDimNormal = aDimVec ^ aViewUp;
171   gp_Pln aViewPlane= gce_MakePln (theFirstPoint, aDimNormal);
172
173   // Get intersection of view plane and projection line
174   Handle(Geom_Plane) aPlane = new Geom_Plane (aViewPlane);
175   Handle(Geom_Line) aProjLine = new Geom_Line (aProjLin);
176   GeomAPI_IntCS anIntersector (aProjLine, aPlane);
177   if (!anIntersector.IsDone() || anIntersector.NbPoints() == 0)
178   {
179     return Standard_False;
180   }
181
182   theOutputPoint = anIntersector.Point (1);
183   return Standard_True;
184 }
185
186 //=======================================================================
187 //function : ParseDimensionParams
188 //purpose  : Auxilliary function: sets aspect parameters for
189 //           length, angle, radius and diameter dimension.
190 //
191 //draw args: -text [3d|2d] [wf|sh|wireframe|shading] [Size]
192 //           -label [left|right|hcenter|hfit] [top|bottom|vcenter|vfit]
193 //           -arrow [external|internal|fit] [Length(int)]
194 //           -arrowangle ArrowAngle(degrees)
195 //           -plane xoy|yoz|zox
196 //           -flyout FloatValue -extension FloatValue
197 //           -autovalue
198 //           -value CustomRealValue
199 //           -textvalue CustomTextValue
200 //           -dispunits DisplayUnitsString
201 //           -modelunits ModelUnitsString
202 //           -showunits
203 //           -hideunits
204 //
205 // Warning! flyout is not an aspect value, it is for dimension parameter
206 // likewise text position, but text position override other paramaters.
207 // For text position changing use 'vmovedim'.
208 //=======================================================================
209 static int ParseDimensionParams (Standard_Integer  theArgNum,
210                                  const char**      theArgVec,
211                                  Standard_Integer  theStartIndex,
212                                  const Handle(Prs3d_DimensionAspect)& theAspect,
213                                  Standard_Boolean& theIsCustomPlane, gp_Pln& thePlane,
214                                  NCollection_DataMap<TCollection_AsciiString, Standard_Real>& theRealParams,
215                                  NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString>& theStringParams,
216                                  NCollection_List<Handle(AIS_InteractiveObject)>* theShapeList = NULL)
217 {
218   theRealParams.Clear();
219   theStringParams.Clear();
220
221   theIsCustomPlane  = Standard_False;
222
223   // Begin from the second parameter: the first one is dimension name
224   for (Standard_Integer anIt = theStartIndex; anIt < theArgNum; ++anIt)
225   {
226     TCollection_AsciiString aParam (theArgVec[anIt]);
227     aParam.LowerCase();
228
229     if (aParam.Search ("-") == -1)
230     {
231       continue;
232     }
233
234     // Boolean flags
235     if (aParam.IsEqual ("-autovalue"))
236     {
237       theRealParams.Bind ("autovalue", 1);
238       continue;
239     }
240
241     if (aParam.IsEqual ("-showunits"))
242     {
243       theAspect->MakeUnitsDisplayed (Standard_True);
244       continue;
245     }
246     else if (aParam.IsEqual ("-hideunits"))
247     {
248       theAspect->MakeUnitsDisplayed (Standard_False);
249       continue;
250     }
251     else if (aParam.IsEqual ("-selected"))
252     {
253       if (!theShapeList)
254       {
255         Message::SendFail() << "Error: unknown parameter '" << aParam << "'";
256         return 1;
257       }
258
259       for (TheAISContext()->InitSelected(); TheAISContext()->MoreSelected(); TheAISContext()->NextSelected())
260       {
261         TopoDS_Shape aShape = TheAISContext()->SelectedShape();
262         if (!aShape.IsNull())
263         {
264           theShapeList->Append (new AIS_Shape (aShape));
265         }
266       }
267       continue;
268     }
269
270     // Before all non-boolean flags parsing check if a flag have at least one value.
271     if (anIt + 1 >= theArgNum)
272     {
273       Message::SendFail() << "Error: "<< aParam <<" flag should have value.";
274       return 1;
275     }
276
277     // Non-boolean flags
278     if (aParam.IsEqual ("-shape")
279      || aParam.IsEqual ("-shapes"))
280     {
281       if (!theShapeList)
282       {
283         Message::SendFail() << "Error: unknown parameter '" << aParam << "'";
284         return 1;
285       }
286
287       do
288       {
289         anIt++;
290         TCollection_AsciiString anArgString = theArgVec[anIt];
291         Handle(AIS_InteractiveObject) anAISObject;
292         Standard_CString aStr   = anArgString.ToCString();
293         TopoDS_Shape     aShape =  DBRep::Get (aStr);
294         if (!aShape.IsNull())
295         {
296           anAISObject = new AIS_Shape (aShape);
297         }
298         else if (!GetMapOfAIS().Find2 (anArgString, anAISObject)
299                || anAISObject.IsNull())
300         {
301           Message::SendFail() << "Error: shape with name '" << aStr << "' is not found.";
302           return 1;
303         }
304         theShapeList->Append (anAISObject);
305       }
306       while (anIt + 1 < theArgNum && theArgVec[anIt + 1][0] != '-');
307     }
308     else if (aParam.IsEqual ("-text"))
309     {
310       do
311       {
312         anIt++;
313         TCollection_AsciiString aValue (theArgVec[anIt]);
314         aValue.LowerCase();
315         if (aValue.IsEqual ("3d"))
316         {
317           theAspect->MakeText3d (Standard_True);
318         }
319         else if (aValue.IsEqual ("2d"))
320         {
321           theAspect->MakeText3d (Standard_False);
322         }
323         else if (aValue.IsEqual ("wf") || aValue.IsEqual ("wireframe"))
324         {
325            theAspect->MakeTextShaded (Standard_False);
326         }
327         else if ( aValue.IsEqual ("sh") || aValue.IsEqual ("shading"))
328         {
329           theAspect->MakeTextShaded (Standard_True);
330         }
331         else if (aValue.IsIntegerValue()) // text size
332         {
333           theAspect->TextAspect()->SetHeight (Draw::Atoi (aValue.ToCString()));
334         }
335       }
336       while (anIt + 1 < theArgNum && theArgVec[anIt + 1][0] != '-');
337     }
338     else if (aParam.IsEqual ("-font"))
339     {
340       if (anIt + 1 >= theArgNum)
341       {
342         Message::SendFail() << "Error: wrong number of values for parameter '" << aParam << "'";
343         return 1;
344       }
345
346       theAspect->TextAspect()->SetFont (theArgVec[++anIt]);
347     }
348     else if (aParam.IsEqual ("-label"))
349     {
350       do
351       {
352         anIt++;
353         TCollection_AsciiString aParamValue (theArgVec[anIt]);
354         aParamValue.LowerCase();
355
356         if (aParamValue == "left")         { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Left);  }
357         else if (aParamValue == "right")   { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Right); }
358         else if (aParamValue == "hcenter") { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Center);}
359         else if (aParamValue == "hfit")    { theAspect->SetTextHorizontalPosition (Prs3d_DTHP_Fit);   }
360         else if (aParamValue == "above")   { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_Above); }
361         else if (aParamValue == "below")   { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_Below); }
362         else if (aParamValue == "vcenter") { theAspect->SetTextVerticalPosition   (Prs3d_DTVP_Center);}
363         else
364         {
365           Message::SendFail() << "Error: invalid label position: '" << aParamValue << "'.";
366           return 1;
367         }
368       }
369       while (anIt + 1 < theArgNum && theArgVec[anIt+1][0] != '-');
370     }
371     else if (aParam.IsEqual ("-arrow"))
372     {
373       TCollection_AsciiString aLocalParam(theArgVec[++anIt]);
374       aLocalParam.LowerCase();
375
376       if (aLocalParam == "external") { theAspect->SetArrowOrientation (Prs3d_DAO_External); }
377       if (aLocalParam == "internal") { theAspect->SetArrowOrientation (Prs3d_DAO_Internal); }
378       if (aLocalParam == "fit")      { theAspect->SetArrowOrientation (Prs3d_DAO_Fit); }
379     }
380     else if (aParam.IsEqual ("-arrowlength") || aParam.IsEqual ("-arlen"))
381     {
382       TCollection_AsciiString aValue (theArgVec[++anIt]);
383       if (!aValue.IsRealValue())
384       {
385         Message::SendFail() << "Error: arrow lenght should be float degree value.";
386         return 1;
387       }
388       theAspect->ArrowAspect()->SetLength (Draw::Atof (aValue.ToCString()));
389     }
390     else if (aParam.IsEqual ("-arrowangle") || aParam.IsEqual ("-arangle"))
391     {
392       TCollection_AsciiString aValue (theArgVec[++anIt]);
393       if (!aValue.IsRealValue())
394       {
395         Message::SendFail ("Error: arrow angle should be float degree value.");
396         return 1;
397       }
398       theAspect->ArrowAspect()->SetAngle (Draw::Atof (aValue.ToCString()));
399     }
400     else if (aParam.IsEqual ("-color"))
401     {
402       Quantity_Color aColor;
403       Standard_Integer aNbParsed = Draw::ParseColor (theArgNum - anIt - 1,
404                                                      theArgVec + anIt + 1,
405                                                      aColor);
406       anIt += aNbParsed;
407       if (aNbParsed == 0)
408       {
409         Message::SendFail() << "Error: wrong syntax at '" << aParam << "'";
410         return 1;
411       }
412       theAspect->SetCommonColor (aColor);
413     }
414     else if (aParam.IsEqual ("-extension"))
415     {
416       TCollection_AsciiString aLocalParam(theArgVec[++anIt]);
417       if (!aLocalParam.IsRealValue())
418       {
419         Message::SendFail ("Error: extension size for dimension should be real value.");
420         return 1;
421       }
422       theAspect->SetExtensionSize (Draw::Atof (aLocalParam.ToCString()));
423     }
424     else if (aParam.IsEqual ("-plane"))
425     {
426       TCollection_AsciiString aValue (theArgVec[++anIt]);
427       aValue.LowerCase();
428       if (aValue == "xoy")
429       {
430         theIsCustomPlane = Standard_True;
431         thePlane = gp_Pln (gp_Ax3 (gp::XOY()));
432       }
433       else if (aValue == "zox")
434       {
435         theIsCustomPlane = Standard_True;
436         thePlane = gp_Pln (gp_Ax3 (gp::ZOX()));
437       }
438       else if (aValue == "yoz")
439       {
440         theIsCustomPlane = Standard_True;
441         thePlane = gp_Pln (gp_Ax3 (gp::YOZ()));
442       }
443       else
444       {
445         Message::SendFail() << "Error: wrong plane '" << aValue << "'";
446         return 1;
447       }
448     }
449     else if (aParam.IsEqual ("-flyout"))
450     {
451       TCollection_AsciiString aLocalParam(theArgVec[++anIt]);
452       if (!aLocalParam.IsRealValue())
453       {
454         Message::SendFail ("Error: flyout for dimension should be real value.");
455         return 1;
456       }
457
458       theRealParams.Bind ("flyout", Draw::Atof (aLocalParam.ToCString()));
459     }
460     else if (aParam.IsEqual ("-value"))
461     {
462       TCollection_AsciiString aLocalParam(theArgVec[++anIt]);
463       if (!aLocalParam.IsRealValue())
464       {
465         Message::SendFail ("Error: dimension value for dimension should be real value");
466         return 1;
467       }
468
469       theRealParams.Bind ("value", Draw::Atof (aLocalParam.ToCString()));
470     }
471     else if (aParam.IsEqual ("-textvalue"))
472     {
473       TCollection_AsciiString aLocalParam(theArgVec[++anIt]);
474
475       theStringParams.Bind ("textvalue", aLocalParam);
476     }
477     else if (aParam.IsEqual ("-modelunits"))
478     {
479       TCollection_AsciiString aLocalParam(theArgVec[++anIt]);
480
481       theStringParams.Bind ("modelunits", aLocalParam);
482     }
483     else if (aParam.IsEqual ("-dispunits"))
484     {
485       TCollection_AsciiString aLocalParam(theArgVec[++anIt]);
486
487       theStringParams.Bind ("dispunits", aLocalParam);
488     }
489     else
490     {
491       Message::SendFail() << "Error: unknown parameter '" << aParam << "'";
492       return 1;
493     }
494   }
495
496   return 0;
497 }
498
499 //=======================================================================
500 //function : SetDimensionParams
501 //purpose  : Sets parameters for dimension
502 //=======================================================================
503 static void SetDimensionParams (const Handle(PrsDim_Dimension)& theDim,
504                                 const NCollection_DataMap<TCollection_AsciiString, Standard_Real>& theRealParams,
505                                 const NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString>& theStringParams)
506 {
507   if (theRealParams.IsBound ("flyout"))
508   {
509     theDim->SetFlyout (theRealParams.Find ("flyout"));
510   }
511
512   if (theRealParams.IsBound ("autovalue"))
513   {
514     theDim->SetComputedValue();
515   }
516
517   if (theRealParams.IsBound ("value"))
518   {
519     theDim->SetCustomValue (theRealParams.Find ("value"));
520   }
521
522   if (theStringParams.IsBound ("textvalue"))
523   {
524     theDim->SetCustomValue (theStringParams.Find ("textvalue"));
525   }
526
527   if (theStringParams.IsBound ("modelunits"))
528   {
529     theDim->SetModelUnits (theStringParams.Find ("modelunits"));
530   }
531
532   if (theStringParams.IsBound ("dispunits"))
533   {
534     theDim->SetDisplayUnits (theStringParams.Find ("dispunits"));
535   }
536 }
537
538 //=======================================================================
539 //function : ParseAngleDimensionParams
540 //purpose  : Auxilliary function: sets custom parameters for angle dimension.
541 //
542 //draw args: -type [interior|exterior]
543 //           -showarrow [first|second|both|none]
544 //=======================================================================
545 static int ParseAngleDimensionParams (Standard_Integer  theArgNum,
546                                const char**      theArgVec,
547                                Standard_Integer  theStartIndex,
548                                NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString>& theStringParams)
549 {
550   theStringParams.Clear();
551
552   // Begin from the second parameter: the first one is dimension name
553   for (Standard_Integer anIt = theStartIndex; anIt < theArgNum; ++anIt)
554   {
555     TCollection_AsciiString aParam (theArgVec[anIt]);
556     aParam.LowerCase();
557
558     if (aParam.Search ("-") == -1)
559     {
560       Message::SendFail() << "Error: wrong parameter '" << aParam << "'.";
561       return 1;
562     }
563
564     // Before all non-boolean flags parsing check if a flag have at least one value.
565     if (anIt + 1 >= theArgNum)
566     {
567       Message::SendFail() << "Error: "<< aParam <<" flag should have value.";
568       return 1;
569     }
570
571     if (aParam.IsEqual ("-type"))
572     {
573       TCollection_AsciiString aLocalParam(theArgVec[++anIt]);
574
575       theStringParams.Bind ("type", aLocalParam);
576     }
577     else if (aParam.IsEqual ("-showarrow"))
578     {
579       TCollection_AsciiString aLocalParam(theArgVec[++anIt]);
580
581       theStringParams.Bind ("showarrow", aLocalParam);
582     }
583     else
584     {
585       Message::SendFail() << "Error: unknown parameter '" << aParam << "'.";
586       return 1;
587     }
588   }
589
590   return 0;
591 }
592
593 //=======================================================================
594 //function : SetAngleDimensionParams
595 //purpose  : Sets parameters for angle dimension
596 //=======================================================================
597 static void SetAngleDimensionParams (const Handle(PrsDim_Dimension)& theDim,
598                                      const NCollection_DataMap<TCollection_AsciiString,
599                                      TCollection_AsciiString>& theStringParams)
600 {
601   Handle(PrsDim_AngleDimension) anAngleDim = Handle(PrsDim_AngleDimension)::DownCast (theDim);
602   if (anAngleDim.IsNull())
603   {
604     return;
605   }
606
607   if (theStringParams.IsBound ("type"))
608   {
609     PrsDim_TypeOfAngle anAngleType = PrsDim_TypeOfAngle_Interior;
610     TCollection_AsciiString anAngleTypeStr = theStringParams.Find ("type");
611     if (anAngleTypeStr.IsEqual("interior"))
612     {
613       anAngleType = PrsDim_TypeOfAngle_Interior;
614     }
615     else if (anAngleTypeStr.IsEqual("exterior"))
616     {
617       anAngleType = PrsDim_TypeOfAngle_Exterior;
618     }
619     else
620     {
621       Message::SendFail() << "Error: wrong angle type.";
622     }
623     anAngleDim->SetType(anAngleType);
624   }
625
626   if (theStringParams.IsBound ("showarrow"))
627   {
628     PrsDim_TypeOfAngleArrowVisibility anArrowType = PrsDim_TypeOfAngleArrowVisibility_Both;
629     TCollection_AsciiString anArrowTypeStr = theStringParams.Find ("showarrow");
630     if (anArrowTypeStr.IsEqual("both"))
631     {
632       anArrowType = PrsDim_TypeOfAngleArrowVisibility_Both;
633     }
634     else if (anArrowTypeStr.IsEqual("first"))
635     {
636       anArrowType = PrsDim_TypeOfAngleArrowVisibility_First;
637     }
638     else if (anArrowTypeStr.IsEqual("second"))
639     {
640       anArrowType = PrsDim_TypeOfAngleArrowVisibility_Second;
641     }
642     else if (anArrowTypeStr.IsEqual("none"))
643     {
644       anArrowType = PrsDim_TypeOfAngleArrowVisibility_None;
645     }
646     else
647     {
648       Message::SendFail() << "Error: wrong showarrow type.";
649     }
650     anAngleDim->SetArrowsVisibility(anArrowType);
651   }
652 }
653
654 //=======================================================================
655 //function : VDimBuilder
656 //purpose  : Command for building dimension presentations: angle,
657 //           length, radius, diameter
658 //=======================================================================
659 static int VDimBuilder (Draw_Interpretor& /*theDi*/,
660                         Standard_Integer  theArgsNb,
661                         const char**      theArgs)
662 {
663   if (theArgsNb < 2)
664   {
665     Message::SendFail ("Syntax error: wrong number of arguments");
666     return 1;
667   }
668
669   // Parse parameters
670   TCollection_AsciiString aName (theArgs[1]);
671
672   NCollection_List<Handle(AIS_InteractiveObject)> aShapes;
673   Handle(Prs3d_DimensionAspect) anAspect = new Prs3d_DimensionAspect;
674   Standard_Boolean isPlaneCustom = Standard_False;
675   gp_Pln aWorkingPlane;
676
677   NCollection_DataMap<TCollection_AsciiString, Standard_Real> aRealParams;
678   NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString> aStringParams;
679
680   TCollection_AsciiString aDimType(theArgs[2]);
681   aDimType.LowerCase();
682   PrsDim_KindOfDimension aKindOfDimension;
683   if (aDimType == "-length")
684   {
685     aKindOfDimension = PrsDim_KOD_LENGTH;
686   }
687   else if (aDimType == "-angle")
688   {
689     aKindOfDimension = PrsDim_KOD_PLANEANGLE;
690   }
691   else if (aDimType == "-radius")
692   {
693     aKindOfDimension = PrsDim_KOD_RADIUS;
694   }
695   else if (aDimType == "-diameter" || aDimType == "-diam")
696   {
697     aKindOfDimension = PrsDim_KOD_DIAMETER;
698   }
699   else
700   {
701     Message::SendFail ("Error: wrong type of dimension");
702     return 1;
703   }
704
705
706   if (ParseDimensionParams (theArgsNb, theArgs, 3,
707                             anAspect,isPlaneCustom,aWorkingPlane,
708                             aRealParams, aStringParams, &aShapes))
709   {
710     return 1;
711   }
712
713   // Build dimension
714   Handle(PrsDim_Dimension) aDim;
715   switch (aKindOfDimension)
716   {
717     case PrsDim_KOD_LENGTH:
718     {
719       if (aShapes.Extent() == 1)
720       {
721         if (aShapes.First()->Type() == AIS_KOI_Shape
722           && (Handle(AIS_Shape)::DownCast(aShapes.First()))->Shape().ShapeType() != TopAbs_EDGE)
723         {
724           Message::SendFail ("Error: wrong shape type");
725           return 1;
726         }
727         if (!isPlaneCustom)
728         {
729           Message::SendFail ("Error: can not build dimension without working plane");
730           return 1;
731         }
732
733         // Adjust working plane
734         TopoDS_Edge anEdge = TopoDS::Edge ((Handle(AIS_Shape)::DownCast(aShapes.First()))->Shape());
735         TopoDS_Vertex aFirst, aSecond;
736         TopExp::Vertices (anEdge, aFirst, aSecond);
737         aDim = new PrsDim_LengthDimension (anEdge, aWorkingPlane);
738
739         // Move standard plane (XOY, YOZ or ZOX) to the first point to make it working for dimension
740         aWorkingPlane.SetLocation (Handle(PrsDim_LengthDimension)::DownCast (aDim)->FirstPoint());
741       }
742       else if (aShapes.Extent() == 2)
743       {
744         TopoDS_Shape aShape1, aShape2;
745
746         // Getting shapes
747         if (aShapes.First()->DynamicType() == STANDARD_TYPE (AIS_Point))
748         {
749           aShape1 = Handle(AIS_Point)::DownCast (aShapes.First ())->Vertex();
750         }
751         else if (aShapes.First()->Type() == AIS_KOI_Shape)
752         {
753           aShape1 = (Handle(AIS_Shape)::DownCast (aShapes.First()))->Shape();
754         }
755
756         if (aShapes.Last()->DynamicType() == STANDARD_TYPE (AIS_Point))
757         {
758           aShape2 = Handle(AIS_Point)::DownCast (aShapes.Last ())->Vertex();
759         }
760         else if (aShapes.Last()->Type() == AIS_KOI_Shape)
761         {
762           aShape2 = (Handle(AIS_Shape)::DownCast (aShapes.Last()))->Shape();
763         }
764
765         if (aShape1.IsNull() || aShape2.IsNull())
766         {
767           Message::SendFail ("Error: wrong shape type.");
768           return 1;
769         }
770
771         // Face-Face case
772         if (aShape1.ShapeType() == TopAbs_FACE && aShape2.ShapeType() == TopAbs_FACE)
773         {
774           aDim = new PrsDim_LengthDimension (TopoDS::Face (aShape1), TopoDS::Face (aShape2));
775         }
776         else if (aShape1.ShapeType() == TopAbs_FACE && aShape2.ShapeType() == TopAbs_EDGE)
777         {
778           aDim = new PrsDim_LengthDimension (TopoDS::Face (aShape1), TopoDS::Edge (aShape2));
779         }
780         else if (aShape1.ShapeType() == TopAbs_EDGE && aShape2.ShapeType() == TopAbs_FACE)
781         {
782           aDim = new PrsDim_LengthDimension (TopoDS::Face (aShape2), TopoDS::Edge (aShape1));
783         }
784         else
785         {
786           if (!isPlaneCustom)
787           {
788             Message::SendFail ("Error: can not build dimension without working plane.");
789             return 1;
790           }
791           // Vertex-Vertex case
792           if (aShape1.ShapeType() == TopAbs_VERTEX)
793           {
794             aWorkingPlane.SetLocation (BRep_Tool::Pnt (TopoDS::Vertex (aShape1)));
795           }
796           else if (aShape2.ShapeType() == TopAbs_VERTEX)
797           {
798             aWorkingPlane.SetLocation (BRep_Tool::Pnt (TopoDS::Vertex (aShape2)));
799           }
800
801           aDim = new PrsDim_LengthDimension (aShape1, aShape2, aWorkingPlane);
802         }
803       }
804       else
805       {
806         Message::SendFail ("Error: wrong number of shapes to build dimension");
807         return 1;
808       }
809
810       break;
811     }
812     case PrsDim_KOD_PLANEANGLE:
813     {
814       if (aShapes.Extent() == 1 && aShapes.First()->Type()==AIS_KOI_Shape)
815       {
816         Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(aShapes.First());
817         if (aShape->Shape().ShapeType() == TopAbs_FACE)
818           aDim = new PrsDim_AngleDimension (TopoDS::Face(aShape->Shape()));
819       }
820       if (aShapes.Extent() == 2)
821       {
822         Handle(AIS_Shape) aShape1 = Handle(AIS_Shape)::DownCast(aShapes.First());
823         Handle(AIS_Shape) aShape2 = Handle(AIS_Shape)::DownCast(aShapes.Last());
824         if (!aShape1.IsNull() && !aShape2.IsNull()
825           && aShape1->Shape().ShapeType() == TopAbs_EDGE
826           && aShape2->Shape().ShapeType() == TopAbs_EDGE)
827           aDim = new PrsDim_AngleDimension (TopoDS::Edge(aShape1->Shape()),TopoDS::Edge(aShape2->Shape()));
828         else
829         {
830           Message::SendFail ("Error: wrong shapes for angle dimension");
831           return 1;
832         }
833       }
834       else if (aShapes.Extent() == 3)
835       {
836         gp_Pnt aP1, aP2, aP3;
837         Handle(AIS_Point) aPoint = Handle(AIS_Point)::DownCast (aShapes.First());
838         if (aPoint.IsNull())
839           return 1;
840         aP1 = aPoint->Component()->Pnt();
841         aShapes.RemoveFirst();
842         aPoint = Handle(AIS_Point)::DownCast (aShapes.First());
843         if (aPoint.IsNull())
844           return 1;
845         aP2 = aPoint->Component()->Pnt();
846         aShapes.RemoveFirst();
847         aPoint = Handle(AIS_Point)::DownCast (aShapes.First());
848         if (aPoint.IsNull())
849           return 1;
850         aP3 = aPoint->Component()->Pnt();
851         aDim = new PrsDim_AngleDimension (aP1, aP2, aP3);
852       }
853       else
854       {
855         Message::SendFail ("Error: wrong number of shapes to build dimension");
856         return 1;
857       }
858
859       break;
860     }
861     case PrsDim_KOD_RADIUS: // radius of the circle
862     {
863       gp_Pnt anAnchor;
864       bool hasAnchor = false;
865       for (NCollection_List<Handle(AIS_InteractiveObject)>::Iterator aShapeIter (aShapes); aShapeIter.More(); aShapeIter.Next())
866       {
867         if (Handle(AIS_Point) aPoint = Handle(AIS_Point)::DownCast(aShapeIter.Value()))
868         {
869           hasAnchor = true;
870           anAnchor = aPoint->Component()->Pnt();
871           aShapes.Remove (aShapeIter);
872           break;
873         }
874       }
875       if (aShapes.Extent() != 1)
876       {
877         Message::SendFail ("Syntax error: wrong number of shapes to build dimension");
878         return 1;
879       }
880
881       if (Handle(AIS_Circle) aShapeCirc = Handle(AIS_Circle)::DownCast(aShapes.First()))
882       {
883         gp_Circ aCircle = aShapeCirc->Circle()->Circ();
884         if (hasAnchor)
885         {
886           aDim = new PrsDim_RadiusDimension (aCircle, anAnchor);
887         }
888         else
889         {
890           aDim = new PrsDim_RadiusDimension (aCircle);
891         }
892       }
893       else if (Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast(aShapes.First()))
894       {
895         Handle(PrsDim_RadiusDimension) aRadDim = new PrsDim_RadiusDimension (aShape->Shape());
896         if (hasAnchor)
897         {
898           aRadDim->SetMeasuredGeometry (aShape->Shape(), anAnchor);
899         }
900         aDim = aRadDim;
901       }
902       else
903       {
904         Message::SendFail ("Error: shape for radius has wrong type");
905         return 1;
906       }
907       break;
908     }
909     case PrsDim_KOD_DIAMETER:
910     {
911       if (aShapes.Extent() == 1)
912       {
913         if (aShapes.First()->DynamicType() == STANDARD_TYPE(AIS_Circle))
914         {
915           Handle(AIS_Circle) aShape = Handle(AIS_Circle)::DownCast (aShapes.First());
916           gp_Circ aCircle = aShape->Circle()->Circ();
917           aDim = new PrsDim_DiameterDimension (aCircle);
918         }
919         else
920         {
921           Handle(AIS_Shape) aShape = Handle(AIS_Shape)::DownCast (aShapes.First());
922           if (aShape.IsNull())
923           {
924             Message::SendFail ("Error: shape for radius is of wrong type");
925             return 1;
926           }
927           aDim = new PrsDim_DiameterDimension (aShape->Shape());
928         }
929       }
930       else
931       {
932         Message::SendFail ("Error: wrong number of shapes to build dimension");
933         return 1;
934       }
935
936       break;
937     }
938     default:
939     {
940       Message::SendFail ("Error: wrong type of dimension. Type help for more information");
941       return 1;
942     }
943   }
944
945   // Check dimension geometry
946   if (!aDim->IsValid())
947   {
948     Message::SendFail() << "Error: dimension geometry is invalid, " << aDimType
949                         << " dimension can't be built on input shapes.";
950     return 1;
951   }
952
953   aDim->SetDimensionAspect (anAspect);
954
955   SetDimensionParams (aDim, aRealParams, aStringParams);
956
957   VDisplayAISObject (aName,aDim);
958
959   return 0;
960 }
961
962 namespace
963 {
964   //! If the given shapes are edges then check whether they are parallel else return true.
965   Standard_Boolean IsParallel (const TopoDS_Shape& theShape1,
966                                const TopoDS_Shape& theShape2)
967   {
968     if (theShape1.ShapeType() == TopAbs_EDGE
969      && theShape2.ShapeType() == TopAbs_EDGE)
970     {
971       BRepExtrema_ExtCC aDelta (TopoDS::Edge (theShape1),
972                                 TopoDS::Edge (theShape2));
973       return aDelta.IsParallel();
974     }
975
976     return Standard_True;
977   }
978 }
979 //=======================================================================
980 //function : VRelationBuilder
981 //purpose  : Command for building realation presentation
982 //=======================================================================
983 static int VRelationBuilder (Draw_Interpretor& /*theDi*/,
984                              Standard_Integer  theArgsNb,
985                              const char**      theArgs)
986 {
987   if (theArgsNb < 2)
988   {
989     Message::SendFail ("Error: wrong number of arguments");
990     return 1;
991   }
992
993   TCollection_AsciiString aName (theArgs[1]);
994   TCollection_AsciiString aType (theArgs[2]);
995
996   PrsDim_KindOfRelation aKindOfRelation = PrsDim_KOR_NONE;
997   if (aType == "-concentric")
998   {
999     aKindOfRelation = PrsDim_KOR_CONCENTRIC;
1000   }
1001   else if (aType == "-equaldistance")
1002   {
1003     aKindOfRelation = PrsDim_KOR_EQUALDISTANCE;
1004   }
1005   else if (aType == "-equalradius")
1006   {
1007     aKindOfRelation = PrsDim_KOR_EQUALRADIUS;
1008   }
1009   else if (aType == "-fix")
1010   {
1011     aKindOfRelation = PrsDim_KOR_FIX;
1012   }
1013   else if (aType == "-identic")
1014   {
1015     aKindOfRelation = PrsDim_KOR_IDENTIC;
1016   }
1017   else if (aType == "-offset")
1018   {
1019     aKindOfRelation = PrsDim_KOR_OFFSET;
1020   }
1021   else if (aType == "-parallel")
1022   {
1023     aKindOfRelation = PrsDim_KOR_PARALLEL;
1024   }
1025   else if (aType == "-perpendicular")
1026   {
1027     aKindOfRelation = PrsDim_KOR_PERPENDICULAR;
1028   }
1029   else if (aType == "-tangent")
1030   {
1031     aKindOfRelation = PrsDim_KOR_TANGENT;
1032   }
1033   else if (aType == "-symmetric")
1034   {
1035     aKindOfRelation = PrsDim_KOR_SYMMETRIC;
1036   }
1037
1038   TopTools_ListOfShape aShapes;
1039   ViewerTest::GetSelectedShapes (aShapes);
1040
1041   // Build relation.
1042   Handle(PrsDim_Relation) aRelation;
1043   switch (aKindOfRelation)
1044   {
1045     case PrsDim_KOR_CONCENTRIC:
1046     {
1047       if (aShapes.Extent() != 2)
1048       {
1049         Message::SendFail ("Error: Wrong number of selected shapes");
1050         return 1;
1051       }
1052
1053       const TopoDS_Shape& aShape1 = aShapes.First();
1054       const TopoDS_Shape& aShape2 = aShapes.Last();
1055
1056       if (!(aShape1.ShapeType() == TopAbs_EDGE
1057          && aShape2.ShapeType() == TopAbs_EDGE))
1058       {
1059         Message::SendFail ("Syntax error: selected shapes are not edges");
1060         return 1;
1061       }
1062
1063       BRepAdaptor_Curve aCurve1 (TopoDS::Edge (aShape1));
1064       gp_Circ           aCircle1 = aCurve1.Circle();
1065       gp_Pnt            aCenter1 = aCircle1.Location();
1066       gp_Pnt            B = aCurve1.Value (0.25);
1067       gp_Pnt            C = aCurve1.Value (0.75);
1068       GC_MakePlane      aMkPlane (aCenter1, B, C);
1069
1070       aRelation = new PrsDim_ConcentricRelation (aShape1, aShape2, aMkPlane.Value());
1071
1072       break;
1073     }
1074     case PrsDim_KOR_EQUALDISTANCE:
1075     {
1076       if (aShapes.Extent() != 4)
1077       {
1078         Message::SendFail ("Error: Wrong number of selected shapes");
1079         return 1;
1080       }
1081
1082       TopoDS_Shape aSelectedShapes[4];
1083
1084       Standard_Integer anIdx = 0;
1085       TopTools_ListOfShape::Iterator anIter (aShapes);
1086       for (; anIter.More(); anIter.Next(), ++anIdx)
1087       {
1088         aSelectedShapes[anIdx] = anIter.Value();
1089       }
1090
1091       if (!IsParallel (aSelectedShapes[0], aSelectedShapes[1])
1092        || !IsParallel (aSelectedShapes[2], aSelectedShapes[3]))
1093       {
1094         Message::SendFail ("Syntax error: non parallel edges");
1095         return 1;
1096       }
1097
1098       gp_Pnt A, B, C;
1099       if (aSelectedShapes[0].ShapeType() == TopAbs_EDGE)
1100       {
1101         TopoDS_Vertex Va, Vb;
1102         TopExp::Vertices (TopoDS::Edge (aSelectedShapes[0]), Va, Vb);
1103         A = BRep_Tool::Pnt (Va);
1104         B = BRep_Tool::Pnt (Vb);
1105
1106         if (aSelectedShapes[1].ShapeType() == TopAbs_EDGE)
1107         {
1108           TopoDS_Vertex Vc, Vd;
1109           TopExp::Vertices (TopoDS::Edge (aSelectedShapes[1]), Vc, Vd);
1110           C = BRep_Tool::Pnt (Vc);
1111         }
1112         else
1113         {
1114           C = BRep_Tool::Pnt (TopoDS::Vertex (aSelectedShapes[1]));
1115         }
1116       }
1117       else
1118       {
1119         A = BRep_Tool::Pnt (TopoDS::Vertex (aSelectedShapes[0]));
1120
1121         if (aSelectedShapes[1].ShapeType() == TopAbs_EDGE)
1122         {
1123           TopoDS_Vertex Vb, Vc;
1124           TopExp::Vertices (TopoDS::Edge (aSelectedShapes[1]), Vb, Vc);
1125           B = BRep_Tool::Pnt (Vb);
1126           C = BRep_Tool::Pnt (Vc);
1127
1128         }
1129         else
1130         {
1131           B = BRep_Tool::Pnt (TopoDS::Vertex (aSelectedShapes[1]));
1132           C.SetX (B.X() + 5.0);
1133           C.SetY (B.Y() + 5.0);
1134           C.SetZ (B.Z() + 5.0);
1135
1136         }
1137       }
1138
1139       GC_MakePlane aMkPlane (A, B, C);
1140       aRelation = new PrsDim_EqualDistanceRelation (aSelectedShapes[0], aSelectedShapes[1], aSelectedShapes[2], aSelectedShapes[3], aMkPlane.Value());
1141
1142       break;
1143     }
1144     case PrsDim_KOR_EQUALRADIUS:
1145     {
1146       if (aShapes.Extent() != 2 && aShapes.Extent() != 1)
1147       {
1148         Message::SendFail ("Error: Wrong number of selected shapes");
1149         return 1;
1150       }
1151
1152       const TopoDS_Shape& aShape1 = aShapes.First();
1153       const TopoDS_Shape& aShape2 = (aShapes.Extent() == 2) ? aShapes.Last() : aShape1;
1154       if (!(aShape1.ShapeType() == TopAbs_EDGE
1155          && aShape2.ShapeType() == TopAbs_EDGE))
1156       {
1157         Message::SendFail ("Syntax error: selected shapes are not edges");
1158         return 1;
1159       }
1160
1161       TopoDS_Edge       anEdge1 = TopoDS::Edge (aShape1);
1162       TopoDS_Edge       anEdge2 = TopoDS::Edge (aShape2);
1163       BRepAdaptor_Curve aCurve1 (anEdge1);
1164       gp_Pnt            A = aCurve1.Value (0.1);
1165       gp_Pnt            B = aCurve1.Value (0.5);
1166       gp_Pnt            C = aCurve1.Value (0.9);
1167       GC_MakePlane      aMkPlane (A, B, C);
1168
1169       aRelation = new PrsDim_EqualRadiusRelation (anEdge1, anEdge2, aMkPlane.Value());
1170       break;
1171     }
1172     case PrsDim_KOR_FIX:
1173     {
1174       if (aShapes.Extent() != 1)
1175       {
1176         Message::SendFail ("Error: Wrong number of selected shapes");
1177         return 1;
1178       }
1179
1180       const TopoDS_Shape& aShape = aShapes.First();
1181       if (aShape.ShapeType() != TopAbs_EDGE)
1182       {
1183         Message::SendFail ("Syntax error: selected shapes are not edges");
1184         return 1;
1185       }
1186
1187       TopoDS_Edge anEdge = TopoDS::Edge (aShape);
1188       BRepAdaptor_Curve aCurve (anEdge);
1189       gp_Pnt A = aCurve.Value(0.1);
1190       gp_Pnt B = aCurve.Value(0.5);
1191       gp_Pnt D = aCurve.Value(0.9);
1192       gp_Pnt C (B.X() + 5.0, B.Y() + 5.0, B.Z() + 5.0);
1193       GC_MakePlane aMkPlane (A, D, C);
1194
1195       aRelation = new PrsDim_FixRelation (anEdge, aMkPlane.Value());
1196       break;
1197     }
1198     case PrsDim_KOR_IDENTIC:
1199     {
1200       if (aShapes.Extent() != 2)
1201       {
1202         Message::SendFail ("Error: Wrong number of selected shapes");
1203         return 1;
1204       }
1205
1206       const TopoDS_Shape& aShapeA = aShapes.First();
1207       const TopoDS_Shape& aShapeB = aShapes.Last();
1208
1209       gp_Pnt A,B,C;
1210       if (aShapeA.ShapeType() == TopAbs_EDGE)
1211       {
1212         TopoDS_Edge anEdgeA = TopoDS::Edge (aShapeA);
1213         BRepAdaptor_Curve aCurveA (anEdgeA);
1214
1215         A = aCurveA.Value (0.1);
1216         B = aCurveA.Value (0.9);
1217         C.SetX (B.X() + 5.0);
1218         C.SetY (B.Y() + 5.0);
1219         C.SetZ (B.Z() + 5.0);
1220       }
1221       else if (aShapeA.ShapeType() == TopAbs_VERTEX)
1222       {
1223         if (aShapeB.ShapeType() == TopAbs_EDGE)
1224         {
1225           TopoDS_Edge anEdgeB = TopoDS::Edge (aShapeB);
1226           BRepAdaptor_Curve aCurveB (anEdgeB);
1227
1228           A = aCurveB.Value (0.1);
1229           B = aCurveB.Value (0.9);
1230           C.SetX (B.X() + 5.0);
1231           C.SetY (B.Y() + 5.0);
1232           C.SetZ (B.Z() + 5.0);
1233         }
1234         else if (aShapeB.ShapeType() == TopAbs_FACE)
1235         {
1236           TopoDS_Face aFaceB = TopoDS::Face (aShapeB);
1237           TopExp_Explorer aFaceExp (aFaceB, TopAbs_EDGE);
1238           TopoDS_Edge anEdgeFromB = TopoDS::Edge (aFaceExp.Current());
1239           BRepAdaptor_Curve aCurveB (anEdgeFromB);
1240           A = aCurveB.Value (0.1);
1241           B = aCurveB.Value (0.5);
1242           C = aCurveB.Value (0.9);
1243         }
1244         else
1245         {
1246           A = BRep_Tool::Pnt (TopoDS::Vertex (aShapeA));
1247           B = BRep_Tool::Pnt (TopoDS::Vertex (aShapeB));
1248           C.SetX (B.X() + 5.0);
1249           C.SetY (B.Y() + 5.0);
1250           C.SetZ (B.Z() + 5.0);
1251         }
1252       }
1253       else
1254       {
1255         TopoDS_Face aFaceA = TopoDS::Face (aShapeA);
1256         TopExp_Explorer aFaceExp (aFaceA, TopAbs_EDGE);
1257         TopoDS_Edge anEdgeFromA = TopoDS::Edge (aFaceExp.Current());
1258         BRepAdaptor_Curve aCurveA (anEdgeFromA);
1259         A = aCurveA.Value (0.1);
1260         B = aCurveA.Value (0.5);
1261         C = aCurveA.Value (0.9);
1262       }
1263
1264       GC_MakePlane aMkPlane (A ,B ,C);
1265       aRelation = new PrsDim_IdenticRelation (aShapeA, aShapeB, aMkPlane.Value());
1266       break;
1267     }
1268     case PrsDim_KOR_OFFSET:
1269     {
1270       if (aShapes.Extent() != 2)
1271       {
1272         Message::SendFail ("Error: Wrong number of selected shapes");
1273         return 1;
1274       }
1275
1276       const TopoDS_Shape& aShape1 = aShapes.First();
1277       const TopoDS_Shape& aShape2 = aShapes.Last();
1278       if (!(aShape1.ShapeType() == TopAbs_FACE
1279          && aShape2.ShapeType() == TopAbs_FACE))
1280       {
1281         Message::SendFail ("Syntax error: selected shapes are not faces");
1282         return 1;
1283       }
1284
1285       TopoDS_Face aFace1 = TopoDS::Face (aShape1);
1286       TopoDS_Face aFace2 = TopoDS::Face (aShape2);
1287
1288       BRepExtrema_ExtFF aDelta (aFace1, aFace2);
1289       if (!aDelta.IsParallel())
1290       {
1291         Message::SendFail ("Syntax error: the faces are not parallel");
1292         return 1;
1293       }
1294
1295       Standard_Real aDist = Round (sqrt (aDelta.SquareDistance (1)) * 10.0) / 10.0;
1296       TCollection_ExtendedString aMessage (TCollection_ExtendedString ("offset=") + TCollection_ExtendedString (aDist));
1297       aRelation = new PrsDim_OffsetDimension (aFace1, aFace2, aDist, aMessage);
1298       break;
1299     }
1300     case PrsDim_KOR_PARALLEL:
1301     {
1302       if (aShapes.Extent() != 2)
1303       {
1304         Message::SendFail ("Error: wrong number of selected shapes");
1305         return 1;
1306       }
1307
1308       const TopoDS_Shape& aShapeA = aShapes.First();
1309       const TopoDS_Shape& aShapeB = aShapes.Last();
1310       if (aShapeA.ShapeType() == TopAbs_EDGE)
1311       {
1312         TopoDS_Edge anEdgeA = TopoDS::Edge (aShapeA);
1313         TopoDS_Edge anEdgeB = TopoDS::Edge (aShapeB);
1314         BRepExtrema_ExtCC aDeltaEdge (anEdgeA, anEdgeB);
1315
1316         if (!aDeltaEdge.IsParallel())
1317         {
1318           Message::SendFail ("Error: the edges are not parallel");
1319           return 1;
1320         }
1321
1322         BRepAdaptor_Curve aCurveA (anEdgeA);
1323         BRepAdaptor_Curve aCurveB (anEdgeB);
1324
1325         gp_Pnt A = aCurveA.Value (0.1);
1326         gp_Pnt B = aCurveA.Value (0.9);
1327         gp_Pnt C = aCurveB.Value (0.5);
1328
1329         GC_MakePlane aMkPlane (A, B, C);
1330
1331         aRelation = new PrsDim_ParallelRelation (anEdgeA, anEdgeB, aMkPlane.Value());
1332       }
1333       else
1334       {
1335         TopoDS_Face aFaceA = TopoDS::Face (aShapeA);
1336         TopoDS_Face aFaceB = TopoDS::Face (aShapeB);
1337
1338         BRepExtrema_ExtFF aDeltaFace (aFaceA, aFaceB);
1339         if (!aDeltaFace.IsParallel())
1340         {
1341           Message::SendFail ("Error: the faces are not parallel");
1342           return 1;
1343         }
1344
1345         TopExp_Explorer aFaceExpA (aFaceA, TopAbs_EDGE);
1346         TopExp_Explorer aFaceExpB (aFaceB, TopAbs_EDGE);
1347
1348         TopoDS_Edge anEdgeA = TopoDS::Edge (aFaceExpA.Current());
1349         TopoDS_Edge anEdgeB = TopoDS::Edge (aFaceExpB.Current());
1350
1351         BRepAdaptor_Curve aCurveA (anEdgeA);
1352         BRepAdaptor_Curve aCurveB (anEdgeB);
1353         gp_Pnt A = aCurveA.Value (0.1);
1354         gp_Pnt B = aCurveA.Value (0.9);
1355         gp_Pnt C = aCurveB.Value (0.5);
1356
1357         GC_MakePlane aMkPlane (A, B, C);
1358
1359         aRelation = new PrsDim_ParallelRelation (aFaceA, aFaceB, aMkPlane.Value());
1360       }
1361       break;
1362     }
1363     case PrsDim_KOR_PERPENDICULAR:
1364     {
1365       if (aShapes.Extent() != 2)
1366       {
1367         Message::SendFail ("Error: Wrong number of selected shapes");
1368         return 1;
1369       }
1370
1371       const TopoDS_Shape& aShapeA = aShapes.First();
1372       const TopoDS_Shape& aShapeB = aShapes.Last();
1373
1374       if (aShapeA.ShapeType() == TopAbs_EDGE)
1375       {
1376         TopoDS_Edge anEdgeA = TopoDS::Edge (aShapeA);
1377         TopoDS_Edge anEdgeB = TopoDS::Edge (aShapeB);
1378
1379         BRepAdaptor_Curve aCurveA (anEdgeA);
1380         BRepAdaptor_Curve aCurveB (anEdgeB);
1381
1382         gp_Pnt A = aCurveA.Value (0.1);
1383         gp_Pnt B = aCurveA.Value (0.9);
1384         gp_Pnt C = aCurveB.Value (0.5);
1385
1386         GC_MakePlane aMkPlane (A, B, C);
1387
1388         aRelation = new PrsDim_PerpendicularRelation (anEdgeA, anEdgeB, aMkPlane.Value());
1389       }
1390       else
1391       {
1392         TopoDS_Face aFaceA = TopoDS::Face (aShapeA);
1393         TopoDS_Face aFaceB = TopoDS::Face (aShapeB);
1394
1395         TopExp_Explorer aFaceExpA (aFaceA, TopAbs_EDGE);
1396         TopExp_Explorer aFaceExpB (aFaceB, TopAbs_EDGE);
1397
1398         TopoDS_Edge anEdgeA = TopoDS::Edge (aFaceExpA.Current());
1399         TopoDS_Edge anEdgeB = TopoDS::Edge (aFaceExpB.Current());
1400
1401         BRepAdaptor_Curve aCurveA (anEdgeA);
1402         BRepAdaptor_Curve aCurveB (anEdgeB);
1403
1404         gp_Pnt A = aCurveA.Value (0.1);
1405         gp_Pnt B = aCurveA.Value (0.9);
1406         gp_Pnt C = aCurveB.Value (0.5);
1407
1408         GC_MakePlane aMkPlane (A, B, C);
1409
1410         aRelation = new PrsDim_PerpendicularRelation (aFaceA, aFaceB);
1411       }
1412
1413       break;
1414     }
1415     case PrsDim_KOR_TANGENT:
1416     {
1417       if (aShapes.Extent() != 2)
1418       {
1419         Message::SendFail ("Error: Wrong number of selected shapes");
1420         return 1;
1421       }
1422
1423       const TopoDS_Shape& aShapeA = aShapes.First();
1424       const TopoDS_Shape& aShapeB = aShapes.Last();
1425
1426       if (aShapeA.ShapeType() == TopAbs_EDGE)
1427       {
1428         TopoDS_Edge anEdgeA = TopoDS::Edge (aShapeA);
1429         TopoDS_Edge anEdgeB = TopoDS::Edge (aShapeB);
1430
1431         BRepAdaptor_Curve aCurveA (anEdgeA);
1432         BRepAdaptor_Curve aCurveB (anEdgeB);
1433     
1434         gp_Pnt A = aCurveA.Value (0.1);
1435         gp_Pnt B = aCurveA.Value (0.9);
1436         gp_Pnt C = aCurveB.Value (0.5);
1437
1438         GC_MakePlane aMkPlane (A,B,C);
1439
1440         aRelation = new PrsDim_TangentRelation (anEdgeA, anEdgeB, aMkPlane.Value());
1441       }
1442       else
1443       {
1444         TopoDS_Face aFaceA = TopoDS::Face (aShapeA);
1445         TopoDS_Face aFaceB = TopoDS::Face (aShapeB);
1446
1447         TopExp_Explorer aFaceExpA (aFaceA, TopAbs_EDGE);
1448         TopExp_Explorer aFaceExpB (aFaceB, TopAbs_EDGE);
1449     
1450         TopoDS_Edge anEdgeA = TopoDS::Edge (aFaceExpA.Current());
1451         TopoDS_Edge anEdgeB = TopoDS::Edge (aFaceExpB.Current());
1452
1453         BRepAdaptor_Curve aCurveA (anEdgeA);
1454         BRepAdaptor_Curve aCurveB (anEdgeB);
1455
1456         gp_Pnt A = aCurveA.Value (0.1);
1457         gp_Pnt B = aCurveA.Value (0.9);
1458         gp_Pnt C = aCurveB.Value (0.5);
1459
1460         GC_MakePlane aMkPlane (A,B,C);
1461
1462         aRelation = new PrsDim_TangentRelation (aFaceA, aFaceB, aMkPlane.Value());
1463       }
1464       break;
1465     }
1466     case PrsDim_KOR_SYMMETRIC:
1467     {
1468       if (aShapes.Extent() != 3)
1469       {
1470         Message::SendFail ("Error: Wrong number of selected shapes");
1471         return 1;
1472       }
1473
1474       TopoDS_Shape aSelectedShapes[3];
1475       Standard_Integer anIdx = 0;
1476       TopTools_ListOfShape::Iterator anIter (aShapes);
1477       for (; anIter.More(); anIter.Next(), ++anIdx)
1478       {
1479         aSelectedShapes[anIdx] = anIter.Value();
1480       }
1481
1482       TopoDS_Edge anEdgeA = TopoDS::Edge (aSelectedShapes[0]);
1483       if (aSelectedShapes[1].ShapeType() == TopAbs_EDGE)
1484       {
1485         // 1 - edge,  2 - edge, 3 - edge.
1486         TopoDS_Edge anEdgeB = TopoDS::Edge (aSelectedShapes[1]);
1487         TopoDS_Edge anEdgeC = TopoDS::Edge (aSelectedShapes[2]);
1488
1489         BRepExtrema_ExtCC aDeltaEdgeAB (anEdgeA, anEdgeB);
1490         BRepExtrema_ExtCC aDeltaEdgeAC (anEdgeA, anEdgeC);
1491
1492         if (!aDeltaEdgeAB.IsParallel())
1493         {
1494           Message::SendFail ("Syntax error: the edges are not parallel");
1495           return 1;
1496         }
1497         if (!aDeltaEdgeAC.IsParallel())
1498         {
1499           Message::SendFail ("Syntax error: the edges are not parallel");
1500           return 1;
1501         }
1502
1503         TopoDS_Vertex Va, Vb, Vc, Vd;
1504         TopExp::Vertices (anEdgeB, Va, Vb);
1505         TopExp::Vertices (anEdgeC, Vc, Vd);
1506         gp_Pnt A = BRep_Tool::Pnt (Va);
1507         gp_Pnt B = BRep_Tool::Pnt (Vc);
1508         gp_Pnt C = Get3DPointAtMousePosition();
1509
1510         GC_MakePlane aMkPlane (A, B, C);
1511
1512         aRelation = new PrsDim_SymmetricRelation (anEdgeA, anEdgeB, anEdgeC, aMkPlane.Value());
1513       }
1514       else
1515       {
1516         // 1 - edge, 2 - vertex, 3 - vertex
1517         TopoDS_Vertex aVertexB = TopoDS::Vertex (aSelectedShapes[1]);
1518         TopoDS_Vertex aVertexC = TopoDS::Vertex (aSelectedShapes[2]);
1519
1520         gp_Pnt B = BRep_Tool::Pnt (aVertexB);
1521         gp_Pnt C = BRep_Tool::Pnt (aVertexC);
1522
1523         TopoDS_Vertex Va, Vb;
1524         TopExp::Vertices (anEdgeA, Va, Vb);
1525         gp_Pnt A = BRep_Tool::Pnt (Va);
1526
1527         GC_MakePlane aMkPlane(A, B, C);
1528         aRelation = new PrsDim_SymmetricRelation (anEdgeA, aVertexB, aVertexC, aMkPlane.Value());
1529       }
1530
1531       break;
1532     }
1533     case PrsDim_KOR_NONE:
1534     {
1535       Message::SendFail ("Error: Unknown type of relation!");
1536       return 1;
1537     }
1538   }
1539
1540   VDisplayAISObject (aName, aRelation);
1541   return 0;
1542 }
1543
1544 //=======================================================================
1545 //function : VDimParam
1546 //purpose  : Sets aspect parameters to dimension.
1547 //=======================================================================
1548 static int VDimParam (Draw_Interpretor& theDi, Standard_Integer theArgNum, const char** theArgVec)
1549 {
1550   if (theArgNum < 3)
1551   {
1552     theDi << theArgVec[0] << " error: the wrong number of input parameters.\n";
1553     return 1;
1554   }
1555
1556
1557   TCollection_AsciiString aName (theArgVec[1]);
1558   gp_Pln aWorkingPlane;
1559   Standard_Boolean isCustomPlane = Standard_False;
1560   Standard_Boolean toUpdate = Standard_True;
1561
1562   NCollection_DataMap<TCollection_AsciiString, Standard_Real> aRealParams;
1563   NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString> aStringParams;
1564
1565   Handle(AIS_InteractiveObject) anObject;
1566   if (!GetMapOfAIS().Find2 (aName, anObject))
1567   {
1568     theDi << theArgVec[0] << "error: no object with this name.\n";
1569     return 1;
1570   }
1571   Handle(PrsDim_Dimension) aDim = Handle(PrsDim_Dimension)::DownCast (anObject);
1572   if (aDim.IsNull())
1573   {
1574     theDi << theArgVec[0] << "error: no dimension with this name.\n";
1575     return 1;
1576   }
1577
1578   Handle(Prs3d_DimensionAspect) anAspect = aDim->DimensionAspect();
1579
1580   if (ParseDimensionParams (theArgNum, theArgVec, 2, anAspect,
1581                             isCustomPlane, aWorkingPlane,
1582                             aRealParams, aStringParams))
1583   {
1584     return 1;
1585   }
1586
1587   if (isCustomPlane)
1588   {
1589     aDim->SetCustomPlane (aWorkingPlane);
1590   }
1591
1592   SetDimensionParams (aDim, aRealParams, aStringParams);
1593
1594   if (!aDim->IsValid())
1595   {
1596     Message::SendFail ("Error: Dimension geometry or plane is not valid");
1597     return 1;
1598   }
1599
1600   // Redisplay a dimension after parameter changing.
1601   if (ViewerTest::GetAISContext()->IsDisplayed (aDim))
1602   {
1603     ViewerTest::GetAISContext()->Redisplay (aDim, toUpdate);
1604   }
1605
1606   return 0;
1607 }
1608
1609 //=======================================================================
1610 //function : VLengthParam
1611 //purpose  : Sets parameters to length dimension.
1612 //=======================================================================
1613 static int VLengthParam (Draw_Interpretor&, Standard_Integer theArgNum, const char** theArgVec)
1614 {
1615   if (theArgNum < 3)
1616   {
1617     Message::SendFail ("Syntax error: the wrong number of input parameters");
1618     return 1;
1619   }
1620
1621   TCollection_AsciiString aName (theArgVec[1]);
1622   Handle(AIS_InteractiveObject) anObject;
1623   if (!GetMapOfAIS().Find2 (aName, anObject))
1624   {
1625     Message::SendFail() << "Syntax error: no object with name '" << aName << "'";
1626     return 1;
1627   }
1628
1629   Handle(PrsDim_LengthDimension) aLengthDim = Handle(PrsDim_LengthDimension)::DownCast (anObject);
1630   if (aLengthDim.IsNull())
1631   {
1632     Message::SendFail() << "Syntax error: no length dimension with name '" << aName << "'";
1633     return 1;
1634   }
1635
1636   // parse direction value
1637   gp_Dir aDirection;
1638   int anArgumentIt = 2;
1639   TCollection_AsciiString aParam (theArgVec[anArgumentIt]);
1640   aParam.LowerCase();
1641
1642   bool isCustomDirection = false;
1643   if (aParam.IsEqual ("-direction"))
1644   {
1645     if (anArgumentIt + 1 >= theArgNum)
1646     {
1647       Message::SendFail() << "Error: "<< aParam <<" direction should have value";
1648       return 1;
1649     }
1650     anArgumentIt++;
1651     isCustomDirection = Standard_True;
1652     TCollection_AsciiString aValue = theArgVec[anArgumentIt];
1653     aValue.LowerCase();
1654     if (aValue == "ox")
1655       aDirection = gp::DX();
1656     else if (aValue == "oy")
1657       aDirection = gp::DY();
1658     else if (aValue == "oz")
1659       aDirection = gp::DZ();
1660     else if (aValue == "autodirection")
1661       isCustomDirection = false;
1662     else
1663     {
1664       if (anArgumentIt + 2 >= theArgNum)
1665       {
1666         Message::SendFail() << "Error: wrong number of values for parameter '" << aParam << "'";
1667         return 1;
1668       }
1669       // access coordinate arguments
1670       TColStd_SequenceOfReal aCoords;
1671       for (; anArgumentIt < theArgNum; ++anArgumentIt)
1672       {
1673         TCollection_AsciiString anArg (theArgVec[anArgumentIt]);
1674         if (!anArg.IsRealValue())
1675         {
1676           break;
1677         }
1678         aCoords.Append (anArg.RealValue());
1679       }
1680       // non-numeric argument too early
1681       if (aCoords.IsEmpty() || aCoords.Size() != 3)
1682       {
1683         Message::SendFail ("Error: wrong number of direction arguments");
1684         return 1;
1685       }
1686       aDirection = gp_Dir (aCoords.Value (1), aCoords.Value (2), aCoords.Value (3));
1687     }
1688   }
1689
1690   aLengthDim->SetDirection (aDirection, isCustomDirection);
1691   if (!aLengthDim->IsValid())
1692   {
1693     Message::SendFail ("Error: Dimension geometry or plane is not valid");
1694     return 1;
1695   }
1696
1697   // Redisplay a dimension after parameter changing.
1698   if (ViewerTest::GetAISContext()->IsDisplayed (aLengthDim))
1699   {
1700     ViewerTest::GetAISContext()->Redisplay (aLengthDim, true);
1701   }
1702
1703   return 0;
1704 }
1705
1706 //=======================================================================
1707 //function : VAngleParam
1708 //purpose  : Sets aspect parameters to angle dimension.
1709 //=======================================================================
1710 static int VAngleParam (Draw_Interpretor& theDi, Standard_Integer theArgNum, const char** theArgVec)
1711 {
1712   if (theArgNum < 3)
1713   {
1714     theDi << theArgVec[0] << " error: the wrong number of input parameters.\n";
1715     return 1;
1716   }
1717
1718
1719   TCollection_AsciiString aName (theArgVec[1]);
1720   gp_Pln aWorkingPlane;
1721   Standard_Boolean toUpdate = Standard_True;
1722
1723   NCollection_DataMap<TCollection_AsciiString, TCollection_AsciiString> aStringParams;
1724   Handle(AIS_InteractiveObject) anObject;
1725   if (!GetMapOfAIS().Find2 (aName, anObject))
1726   {
1727     theDi << theArgVec[0] << "error: no object with this name.\n";
1728     return 1;
1729   }
1730
1731   Handle(PrsDim_Dimension) aDim = Handle(PrsDim_Dimension)::DownCast (anObject);
1732   if (aDim.IsNull())
1733   {
1734     theDi << theArgVec[0] << "error: no dimension with this name.\n";
1735     return 1;
1736   }
1737
1738   Handle(Prs3d_DimensionAspect) anAspect = aDim->DimensionAspect();
1739   if (ParseAngleDimensionParams (theArgNum, theArgVec, 2, aStringParams))
1740   {
1741     return 1;
1742   }
1743
1744   SetAngleDimensionParams (aDim, aStringParams);
1745
1746   if (!aDim->IsValid())
1747   {
1748     Message::SendFail ("Error: Dimension geometry or plane is not valid");
1749     return 1;
1750   }
1751
1752   // Redisplay a dimension after parameter changing.
1753   if (ViewerTest::GetAISContext()->IsDisplayed (aDim))
1754   {
1755     ViewerTest::GetAISContext()->Redisplay (aDim, toUpdate);
1756   }
1757   return 0;
1758 }
1759
1760 //=======================================================================
1761 //function : VMoveDim
1762 //purpose  : Moves dimension or relation text label to defined or picked
1763 //           position and updates the object.
1764 //draw args: vmovedim [name] [x y z]
1765 //=======================================================================
1766 static int VMoveDim (Draw_Interpretor& theDi, Standard_Integer theArgNum, const char** theArgVec) 
1767 {
1768   if (theArgNum > 5)
1769   {
1770     theDi << theArgVec[0] << " error: the wrong number of parameters.\n";
1771     return 1;
1772   }
1773
1774   // Parameters parsing
1775   Standard_Boolean isNameSet = (theArgNum ==2 || theArgNum == 5);
1776   Standard_Boolean isPointSet = (theArgNum == 4 || theArgNum == 5);
1777
1778   Handle(AIS_InteractiveObject) aPickedObj;
1779   gp_Pnt aPoint (gp::Origin());
1780   Standard_Integer aMaxPickNum = 5;
1781
1782   // Find object
1783   if (isNameSet)
1784   {
1785      TCollection_AsciiString aName (theArgVec[1]);
1786      if (!GetMapOfAIS().Find2 (aName, aPickedObj)
1787        || aPickedObj.IsNull())
1788      {
1789        theDi << theArgVec[0] << " error: no object with this name.\n";
1790        return 1;
1791      }
1792
1793      if (aPickedObj->Type() != AIS_KOI_Dimension && aPickedObj->Type() != AIS_KOI_Relation)
1794      {
1795        theDi << theArgVec[0] << " error: no dimension or relation with this name.\n";
1796        return 1;
1797      }
1798   }
1799   else // Pick dimension or relation
1800   {
1801     // Loop that will be handle picking.
1802     Standard_Integer anArgNum = 5;
1803     const char *aBuffer[] = { "VPick", "X", "VPickY","VPickZ", "VPickShape" };
1804     const char **anArgVec = (const char **) aBuffer;
1805
1806     Standard_Boolean isPicked = Standard_False;
1807     Standard_Integer aPickNum = 0;
1808     while (!isPicked && aPickNum < aMaxPickNum)
1809     {
1810       while (ViewerMainLoop (anArgNum, anArgVec)) { }
1811
1812       for (TheAISContext()->InitSelected(); TheAISContext()->MoreSelected(); TheAISContext()->NextSelected())
1813       {
1814         aPickedObj = TheAISContext()->SelectedInteractive();
1815       }
1816
1817       isPicked = (!aPickedObj.IsNull() && (aPickedObj->Type() == AIS_KOI_Dimension || aPickedObj->Type() == AIS_KOI_Relation));
1818
1819       if (isPicked)
1820       {
1821         break;
1822       }
1823       aPickNum++;
1824     }
1825     if (!isPicked)
1826     {
1827       theDi << theArgVec[0] << ": no dimension or relation is selected.\n";
1828       return 1;
1829     }
1830   }
1831
1832   // Find point
1833   if (isPointSet)
1834   {
1835     aPoint = theArgNum == 4 ? gp_Pnt (atoi (theArgVec[1]), atoi (theArgVec[2]), atoi (theArgVec[3]))
1836                             : gp_Pnt (atoi (theArgVec[2]), atoi (theArgVec[3]), atoi (theArgVec[4]));
1837   }
1838   else // Pick the point
1839   {
1840     Standard_Integer aPickArgNum = 5;
1841     const char *aPickBuff[] = {"VPick", "X", "VPickY", "VPickZ", "VPickShape"};
1842     const char **aPickArgVec = (const char **) aPickBuff;
1843
1844     while (ViewerMainLoop (aPickArgNum, aPickArgVec)) { }
1845
1846     // Set text position, update relation or dimension.
1847     if (aPickedObj->Type() == AIS_KOI_Relation)
1848     {
1849       Handle(PrsDim_Relation) aRelation = Handle(PrsDim_Relation)::DownCast (aPickedObj);
1850       aPoint = Get3DPointAtMousePosition();
1851       aRelation->SetPosition (aPoint);
1852       TheAISContext()->Redisplay (aRelation, Standard_True);
1853     }
1854     else
1855     {
1856       Handle(PrsDim_Dimension) aDim = Handle(PrsDim_Dimension)::DownCast (aPickedObj);
1857       gp_Pnt aFirstPoint, aSecondPoint;
1858       if (aDim->KindOfDimension() == PrsDim_KOD_PLANEANGLE)
1859       {
1860         Handle(PrsDim_AngleDimension) anAngleDim = Handle(PrsDim_AngleDimension)::DownCast (aDim);
1861         aFirstPoint = anAngleDim->FirstPoint();
1862         aSecondPoint = anAngleDim->SecondPoint();
1863       }
1864       else if (aDim->KindOfDimension() == PrsDim_KOD_LENGTH)
1865       {
1866         Handle(PrsDim_LengthDimension) aLengthDim = Handle(PrsDim_LengthDimension)::DownCast (aDim);
1867         aFirstPoint = aLengthDim->FirstPoint();
1868         aSecondPoint = aLengthDim->SecondPoint();
1869       }
1870       else if (aDim->KindOfDimension() == PrsDim_KOD_RADIUS)
1871       {
1872         Handle(PrsDim_RadiusDimension) aRadiusDim = Handle(PrsDim_RadiusDimension)::DownCast (aDim);
1873         aFirstPoint = aRadiusDim->AnchorPoint();
1874         aSecondPoint = aRadiusDim->Circle().Location();
1875       }
1876       else if (aDim->KindOfDimension() == PrsDim_KOD_DIAMETER)
1877       {
1878         Handle(PrsDim_DiameterDimension) aDiameterDim = Handle(PrsDim_DiameterDimension)::DownCast (aDim);
1879         aFirstPoint = aDiameterDim->AnchorPoint();
1880         aSecondPoint = aDiameterDim->Circle().Location();
1881       }
1882
1883       if (!Get3DPointAtMousePosition (aFirstPoint, aSecondPoint, aPoint))
1884       {
1885         return 1;
1886       }
1887
1888       aDim->SetTextPosition (aPoint);
1889       TheAISContext()->Redisplay (aDim, Standard_True);
1890     }
1891
1892   }
1893
1894   // Set text position, update relation or dimension.
1895   if (aPickedObj->Type() == AIS_KOI_Relation)
1896   {
1897     Handle(PrsDim_Relation) aRelation = Handle(PrsDim_Relation)::DownCast (aPickedObj);
1898     aRelation->SetPosition (aPoint);
1899     TheAISContext()->Redisplay (aRelation, Standard_True);
1900   }
1901   else
1902   {
1903     Handle(PrsDim_Dimension) aDim = Handle(PrsDim_Dimension)::DownCast (aPickedObj);
1904     aDim->SetTextPosition (aPoint);
1905     TheAISContext()->Redisplay (aDim, Standard_True);
1906   }
1907
1908   return 0;
1909 }
1910
1911 //=======================================================================
1912 //function : RelationsCommands
1913 //purpose  : 
1914 //=======================================================================
1915       
1916
1917 void ViewerTest::RelationCommands(Draw_Interpretor& theCommands)
1918 {
1919   const char *group = "AISRelations";
1920
1921   theCommands.Add("vdimension",
1922       "vdimension name {-angle|-length|-radius|-diameter}"
1923       "[-shapes shape1 [shape2 [shape3]]\n"
1924       "[-selected]\n"
1925       "[-text 3d|2d wf|sh|wireframe|shading IntegerSize]\n"
1926       "[-font FontName]\n"
1927       "[-label left|right|hcenter|hfit top|bottom|vcenter|vfit]\n"
1928       "[-arrow external|internal|fit]\n"
1929       "[{-arrowlength|-arlen} RealArrowLength]\n"
1930       "[{-arrowangle|-arangle} ArrowAngle(degrees)]\n"
1931       "[-plane xoy|yoz|zox]\n"
1932       "[-flyout FloatValue -extension FloatValue]\n"
1933       "[-autovalue]\n"
1934       "[-value CustomRealValue]\n"
1935       "[-textvalue CustomTextValue]\n"
1936       "[-dispunits DisplayUnitsString]\n"
1937       "[-modelunits ModelUnitsString]\n"
1938       "[-showunits | -hideunits]\n"
1939       " -Builds angle, length, radius and diameter dimensions.\n"
1940       " -See also: vdimparam, vmovedim.\n",
1941       __FILE__,VDimBuilder,group);
1942
1943   theCommands.Add ("vrelation",
1944       "vrelation name {-concentric|-equaldistance|-equalradius|-fix|-identic|-offset|-parallel|-perpendicular|-tangent|-symmetric}"
1945       "\n\t\t: concentric - 2 circled edges."
1946       "\n\t\t: equaldistance - 4 vertex/edges."
1947       "\n\t\t: equalradius - 1 or 2 circled edges."
1948       "\n\t\t: fix - 1 edge."
1949       "\n\t\t: identic - 2 faces, edges or vertices."
1950       "\n\t\t: offset - 2 faces."
1951       "\n\t\t: parallel - 2 faces or 2 edges."
1952       "\n\t\t: perpendicular - 2 faces or 2 edges."
1953       "\n\t\t: tangent - two coplanar edges (first the circular edge then the tangent edge) or two faces."
1954       "\n\t\t: symmetric - 3 edges or 1 edge and 2 vertices."
1955       "-Builds specific relation from selected objects.",
1956       __FILE__, VRelationBuilder, group);
1957
1958   theCommands.Add("vdimparam",
1959     "vdimparam name"
1960     "[-text 3d|2d wf|sh|wireframe|shading IntegerSize]\n"
1961     "[-font FontName]\n"
1962     "[-label left|right|hcenter|hfit top|bottom|vcenter|vfit]\n"
1963     "[-arrow external|internal|fit]\n"
1964     "[{-arrowlength|-arlen} RealArrowLength]\n"
1965     "[{-arrowangle|-arangle} ArrowAngle(degrees)]\n"
1966     "[-plane xoy|yoz|zox]\n"
1967     "[-flyout FloatValue -extension FloatValue]\n"
1968     "[-value CustomNumberValue]\n"
1969     "[-textvalue CustomTextValue]\n"
1970     "[-dispunits DisplayUnitsString]\n"
1971     "[-modelunits ModelUnitsString]\n"
1972     "[-showunits | -hideunits]\n"
1973     " -Sets parameters for angle, length, radius and diameter dimensions.\n"
1974     " -See also: vmovedim, vdimension.\n",
1975     __FILE__,VDimParam,group);
1976
1977   theCommands.Add("vlengthparam",
1978     "vlengthparam name"
1979     "[-direction {ox|oy|oz|x y z|autodirection}]\n"
1980     " -Sets parameters for length dimension.\n"
1981     " -See also: vdimparam, vdimension.\n",
1982     __FILE__,VLengthParam,group);
1983
1984   theCommands.Add("vangleparam",
1985     "vangleparam name"
1986     "[-type interior|exterior]\n"
1987     "[-showarrow first|second|both|none]\n"
1988     " -Sets parameters for angle dimension.\n"
1989     " -See also: vdimparam, vdimension.\n",
1990     __FILE__,VAngleParam,group);
1991
1992   theCommands.Add("vmovedim",
1993       "vmovedim : vmovedim [name] [x y z]"
1994       "\n\t\t: Moves picked or named (if name defined)"
1995       "\n\t\t: dimension to picked mouse position or input point."
1996       "\n\t\t: Text label of dimension 'name' is moved to position, another parts of dimensionare adjusted.",
1997                   __FILE__,VMoveDim,group);
1998
1999 }