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