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