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