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