0029885: Visualization, AIS_Manipulator - Translation is done in wrong direction...
[occt.git] / src / AIS / AIS_Manipulator.cxx
1 // Created on: 2015-12-23
2 // Created by: Anastasia BORISOVA
3 // Copyright (c) 2015 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <AIS_Manipulator.hxx>
17
18 #include <AIS_InteractiveContext.hxx>
19 #include <AIS_ManipulatorOwner.hxx>
20 #include <Extrema_ExtElC.hxx>
21 #include <gce_MakeDir.hxx>
22 #include <Geom_Circle.hxx>
23 #include <Geom_Transformation.hxx>
24 #include <IntAna_IntConicQuad.hxx>
25 #include <Prs3d_Arrow.hxx>
26 #include <Prs3d_Root.hxx>
27 #include <Prs3d_ShadingAspect.hxx>
28 #include <Prs3d_ToolDisk.hxx>
29 #include <Prs3d_ToolSphere.hxx>
30 #include <Select3D_SensitiveCircle.hxx>
31 #include <Select3D_SensitivePoint.hxx>
32 #include <Select3D_SensitiveSegment.hxx>
33 #include <Select3D_SensitiveTriangulation.hxx>
34 #include <Select3D_SensitivePrimitiveArray.hxx>
35 #include <SelectMgr_SequenceOfOwner.hxx>
36 #include <TColgp_Array1OfPnt.hxx>
37 #include <V3d_View.hxx>
38
39 IMPLEMENT_STANDARD_HANDLE (AIS_Manipulator, AIS_InteractiveObject)
40 IMPLEMENT_STANDARD_RTTIEXT(AIS_Manipulator, AIS_InteractiveObject)
41
42 IMPLEMENT_HSEQUENCE(AIS_ManipulatorObjectSequence)
43
44 namespace
45 {
46   //! Return Ax1 for specified direction of Ax2.
47   static gp_Ax1 getAx1FromAx2Dir (const gp_Ax2& theAx2,
48                                   int theIndex)
49   {
50     switch (theIndex)
51     {
52       case 0: return gp_Ax1 (theAx2.Location(), theAx2.XDirection());
53       case 1: return gp_Ax1 (theAx2.Location(), theAx2.YDirection());
54       case 2: return theAx2.Axis();
55     }
56     throw Standard_ProgramError ("AIS_Manipulator - Invalid axis index");
57   }
58 }
59
60 //=======================================================================
61 //function : init
62 //purpose  : 
63 //=======================================================================
64 void AIS_Manipulator::init()
65 {
66   // Create axis in the default coordinate system. The custom position is applied in local transformation.
67   myAxes[0] = Axis (gp::OX(), Quantity_NOC_RED);
68   myAxes[1] = Axis (gp::OY(), Quantity_NOC_GREEN);
69   myAxes[2] = Axis (gp::OZ(), Quantity_NOC_BLUE1);
70
71   Graphic3d_MaterialAspect aShadingMaterial;
72   aShadingMaterial.SetReflectionModeOff (Graphic3d_TOR_SPECULAR);
73   aShadingMaterial.SetMaterialType (Graphic3d_MATERIAL_ASPECT);
74
75   myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
76   myDrawer->ShadingAspect()->Aspect()->SetInteriorStyle (Aspect_IS_SOLID);
77   myDrawer->ShadingAspect()->SetColor (Quantity_NOC_WHITE);
78   myDrawer->ShadingAspect()->SetMaterial (aShadingMaterial);
79
80   Graphic3d_MaterialAspect aHilightMaterial;
81   aHilightMaterial.SetColor (Quantity_NOC_AZURE);
82   aHilightMaterial.SetReflectionModeOff (Graphic3d_TOR_AMBIENT);
83   aHilightMaterial.SetReflectionModeOff (Graphic3d_TOR_DIFFUSE);
84   aHilightMaterial.SetReflectionModeOff (Graphic3d_TOR_SPECULAR);
85   aHilightMaterial.SetReflectionModeOff (Graphic3d_TOR_EMISSION);
86   aHilightMaterial.SetMaterialType (Graphic3d_MATERIAL_ASPECT);
87
88   myHighlightAspect = new Prs3d_ShadingAspect();
89   myHighlightAspect->Aspect()->SetInteriorStyle (Aspect_IS_SOLID);
90   myHighlightAspect->SetMaterial (aHilightMaterial);
91
92   SetSize (100);
93   SetZLayer (Graphic3d_ZLayerId_Topmost);
94 }
95
96 //=======================================================================
97 //function : getHighlightPresentation
98 //purpose  : 
99 //=======================================================================
100 Handle(Prs3d_Presentation) AIS_Manipulator::getHighlightPresentation (const Handle(SelectMgr_EntityOwner)& theOwner) const
101 {
102   Handle(Prs3d_Presentation) aDummyPrs;
103   Handle(AIS_ManipulatorOwner) anOwner = Handle(AIS_ManipulatorOwner)::DownCast (theOwner);
104   if (anOwner.IsNull())
105   {
106     return aDummyPrs;
107   }
108
109   switch (anOwner->Mode())
110   {
111     case AIS_MM_Translation: return myAxes[anOwner->Index()].TranslatorHighlightPrs();
112     case AIS_MM_Rotation   : return myAxes[anOwner->Index()].RotatorHighlightPrs();
113     case AIS_MM_Scaling    : return myAxes[anOwner->Index()].ScalerHighlightPrs();
114     case AIS_MM_None       : break;
115   }
116
117   return aDummyPrs;
118 }
119
120 //=======================================================================
121 //function : getGroup
122 //purpose  : 
123 //=======================================================================
124 Handle(Graphic3d_Group) AIS_Manipulator::getGroup (const Standard_Integer theIndex, const AIS_ManipulatorMode theMode) const
125 {
126   Handle(Graphic3d_Group) aDummyGroup;
127
128   if (theIndex < 0 || theIndex > 2)
129   {
130     return aDummyGroup;
131   }
132
133   switch (theMode)
134   {
135     case AIS_MM_Translation: return myAxes[theIndex].TranslatorGroup();
136     case AIS_MM_Rotation   : return myAxes[theIndex].RotatorGroup();
137     case AIS_MM_Scaling    : return myAxes[theIndex].ScalerGroup();
138     case AIS_MM_None       : break;
139   }
140
141   return aDummyGroup;
142 }
143
144 //=======================================================================
145 //function : Constructor
146 //purpose  : 
147 //=======================================================================
148 AIS_Manipulator::AIS_Manipulator()
149 : myPosition (gp::XOY()),
150   myCurrentIndex (-1),
151   myCurrentMode (AIS_MM_None),
152   myIsActivationOnDetection (Standard_False),
153   myIsZoomPersistentMode (Standard_True),
154   myHasStartedTransformation (Standard_False),
155   myStartPosition (gp::XOY()),
156   myStartPick (0.0, 0.0, 0.0),
157   myPrevState (0.0)
158 {
159   SetInfiniteState();
160   SetMutable (Standard_True);
161   SetDisplayMode (AIS_Shaded);
162   init();
163 }
164
165 //=======================================================================
166 //function : Constructor
167 //purpose  : 
168 //=======================================================================
169 AIS_Manipulator::AIS_Manipulator (const gp_Ax2& thePosition)
170 : myPosition (thePosition),
171   myCurrentIndex (-1),
172   myCurrentMode (AIS_MM_None),
173   myIsActivationOnDetection (Standard_False),
174   myIsZoomPersistentMode (Standard_True),
175   myHasStartedTransformation (Standard_False),
176   myStartPosition (gp::XOY()),
177   myStartPick (0.0, 0.0, 0.0),
178   myPrevState (0.0)
179 {
180   SetInfiniteState();
181   SetMutable (Standard_True);
182   SetDisplayMode (AIS_Shaded);
183   init();
184 }
185
186 //=======================================================================
187 //function : SetPart
188 //purpose  : 
189 //=======================================================================
190 void AIS_Manipulator::SetPart (const Standard_Integer theAxisIndex, const AIS_ManipulatorMode theMode, const Standard_Boolean theIsEnabled)
191 {
192   Standard_ProgramError_Raise_if (theAxisIndex < 0 || theAxisIndex > 2, "AIS_Manipulator::SetMode(): axis index should be between 0 and 2");
193   switch (theMode)
194   {
195     case AIS_MM_Translation:
196       myAxes[theAxisIndex].SetTranslation (theIsEnabled);
197       break;
198
199     case AIS_MM_Rotation:
200       myAxes[theAxisIndex].SetRotation (theIsEnabled);
201       break;
202
203     case AIS_MM_Scaling:
204       myAxes[theAxisIndex].SetScaling (theIsEnabled);
205       break;
206
207     case AIS_MM_None:
208       break;
209   }
210 }
211
212 //=======================================================================
213 //function : EnableMode
214 //purpose  : 
215 //=======================================================================
216 void AIS_Manipulator::EnableMode (const AIS_ManipulatorMode theMode)
217 {
218   if (!IsAttached())
219   {
220     return;
221   }
222
223   const Handle(AIS_InteractiveContext)& aContext = GetContext();
224   if (aContext.IsNull())
225   {
226     return;
227   }
228
229   aContext->Activate (this, theMode);
230 }
231
232 //=======================================================================
233 //function : attachToBox
234 //purpose  : 
235 //=======================================================================
236 void AIS_Manipulator::attachToBox (const Bnd_Box& theBox)
237 {
238   if (theBox.IsVoid())
239   {
240     return;
241   }
242
243   Standard_Real anXmin = 0.0, anYmin = 0.0, aZmin = 0.0, anXmax = 0.0, anYmax = 0.0, aZmax = 0.0;
244   theBox.Get (anXmin, anYmin, aZmin, anXmax, anYmax, aZmax);
245
246   gp_Ax2 aPosition = gp::XOY();
247   aPosition.SetLocation (gp_Pnt ((anXmin + anXmax) * 0.5, (anYmin + anYmax) * 0.5, (aZmin + aZmax) * 0.5));
248   SetPosition (aPosition);
249 }
250
251 //=======================================================================
252 //function : adjustSize
253 //purpose  : 
254 //=======================================================================
255 void AIS_Manipulator::adjustSize (const Bnd_Box& theBox)
256 {
257   Standard_Real aXmin = 0., aYmin = 0., aZmin = 0., aXmax = 0., aYmax = 0., aZmax = 0.0;
258   theBox.Get (aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
259   Standard_Real aXSize = aXmax - aXmin;
260   Standard_Real aYSize = aYmax - aYmin;
261   Standard_Real aZSize  = aZmax  - aZmin;
262
263   SetSize ((Standard_ShortReal) (Max (aXSize, Max (aYSize, aZSize)) * 0.5));
264 }
265
266 //=======================================================================
267 //function : Attach
268 //purpose  : 
269 //=======================================================================
270 void AIS_Manipulator::Attach (const Handle(AIS_InteractiveObject)& theObject, const OptionsForAttach& theOptions)
271 {
272   if (theObject->IsKind (STANDARD_TYPE(AIS_Manipulator)))
273   {
274     return;
275   }
276
277   Handle(AIS_ManipulatorObjectSequence) aSeq = new AIS_ManipulatorObjectSequence();
278   aSeq->Append (theObject);
279   Attach (aSeq, theOptions);
280 }
281
282 //=======================================================================
283 //function : Attach
284 //purpose  : 
285 //=======================================================================
286 void AIS_Manipulator::Attach (const Handle(AIS_ManipulatorObjectSequence)& theObjects, const OptionsForAttach& theOptions)
287 {
288   if (theObjects->Size() < 1)
289   {
290     return;
291   }
292
293   SetOwner (theObjects);
294   Bnd_Box aBox;
295   const Handle(AIS_InteractiveObject)& aCurObject = theObjects->Value (theObjects->Lower());
296   aCurObject->BoundingBox (aBox);
297
298   if (theOptions.AdjustPosition)
299   {
300     attachToBox (aBox);
301   }
302
303   if (theOptions.AdjustSize)
304   {
305     adjustSize (aBox);
306   }
307
308   const Handle(AIS_InteractiveContext)& aContext = Object()->GetContext();
309   if (!aContext.IsNull())
310   {
311     if (!aContext->IsDisplayed (this))
312     {
313       aContext->Display (this, Standard_False);
314     }
315     else
316     {
317       aContext->Update (this, Standard_False);
318       aContext->RecomputeSelectionOnly (this);
319     }
320
321     aContext->Load (this);
322   }
323
324   if (theOptions.EnableModes)
325   {
326     EnableMode (AIS_MM_Rotation);
327     EnableMode (AIS_MM_Translation);
328     EnableMode (AIS_MM_Scaling);
329   }
330 }
331
332 //=======================================================================
333 //function : Detach
334 //purpose  : 
335 //=======================================================================
336 void AIS_Manipulator::Detach()
337 {
338   DeactivateCurrentMode();
339
340   if (!IsAttached())
341   {
342     return;
343   }
344
345   Handle(AIS_InteractiveObject) anObject = Object();
346   const Handle(AIS_InteractiveContext)& aContext = anObject->GetContext();
347   if (!aContext.IsNull())
348   {
349     aContext->Remove (this, Standard_False);
350   }
351
352   SetOwner (NULL);
353 }
354
355 //=======================================================================
356 //function : Objects
357 //purpose  : 
358 //=======================================================================
359 Handle(AIS_ManipulatorObjectSequence) AIS_Manipulator::Objects() const
360 {
361   return Handle(AIS_ManipulatorObjectSequence)::DownCast (GetOwner());
362 }
363
364 //=======================================================================
365 //function : Object
366 //purpose  : 
367 //=======================================================================
368 Handle(AIS_InteractiveObject) AIS_Manipulator::Object (const Standard_Integer theIndex) const
369 {
370   Handle(AIS_ManipulatorObjectSequence) anOwner = Handle(AIS_ManipulatorObjectSequence)::DownCast (GetOwner());
371
372   Standard_ProgramError_Raise_if (theIndex < anOwner->Lower() || theIndex > anOwner->Upper(), "AIS_Manipulator::Object(): wrong index value");
373
374   if (anOwner.IsNull() || anOwner->IsEmpty())
375   {
376     return NULL;
377   }
378
379   return anOwner->Value (theIndex);
380 }
381
382 //=======================================================================
383 //function : Object
384 //purpose  : 
385 //=======================================================================
386 Handle(AIS_InteractiveObject) AIS_Manipulator::Object() const
387 {
388   return Object (1);
389 }
390
391 //=======================================================================
392 //function : ObjectTransformation
393 //purpose  : 
394 //=======================================================================
395 Standard_Boolean AIS_Manipulator::ObjectTransformation (const Standard_Integer theMaxX, const Standard_Integer theMaxY,
396                                                         const Handle(V3d_View)& theView, gp_Trsf& theTrsf)
397 {
398   // Initialize start reference data
399   if (!myHasStartedTransformation)
400   {
401     myStartTrsfs.Clear();
402     Handle(AIS_ManipulatorObjectSequence) anObjects = Objects();
403     for (AIS_ManipulatorObjectSequence::Iterator anObjIter (*anObjects); anObjIter.More(); anObjIter.Next())
404     {
405       myStartTrsfs.Append (anObjIter.Value()->LocalTransformation());
406     }
407     myStartPosition = myPosition;
408   }
409
410   // Get 3d point with projection vector
411   Graphic3d_Vec3d anInputPoint, aProj;
412   theView->ConvertWithProj (theMaxX, theMaxY, anInputPoint.x(), anInputPoint.y(), anInputPoint.z(), aProj.x(), aProj.y(), aProj.z());
413   const gp_Lin anInputLine (gp_Pnt (anInputPoint.x(), anInputPoint.y(), anInputPoint.z()), gp_Dir (aProj.x(), aProj.y(), aProj.z()));
414   switch (myCurrentMode)
415   {
416     case AIS_MM_Translation:
417     case AIS_MM_Scaling:
418     {
419       const gp_Lin aLine (myStartPosition.Location(), myAxes[myCurrentIndex].Position().Direction());
420       Extrema_ExtElC anExtrema (anInputLine, aLine, Precision::Angular());
421       if (!anExtrema.IsDone()
422         || anExtrema.NbExt() != 1)
423       {
424         // translation cannot be done co-directed with camera
425         return Standard_False;
426       }
427
428       Extrema_POnCurv anExPnts[2];
429       anExtrema.Points (1, anExPnts[0], anExPnts[1]);
430       const gp_Pnt aNewPosition = anExPnts[1].Value();
431       if (!myHasStartedTransformation)
432       {
433         myStartPick = aNewPosition;
434         myHasStartedTransformation = Standard_True;
435         return Standard_True;
436       }
437       else if (aNewPosition.Distance (myStartPick) < Precision::Confusion())
438       {
439         return Standard_False;
440       }
441
442       gp_Trsf aNewTrsf;
443       if (myCurrentMode == AIS_MM_Translation)
444       {
445         aNewTrsf.SetTranslation (gp_Vec(myStartPick, aNewPosition));
446         theTrsf *= aNewTrsf;
447       }
448       else if (myCurrentMode == AIS_MM_Scaling)
449       {
450         if (aNewPosition.Distance (myStartPosition.Location()) < Precision::Confusion())
451         {
452           return Standard_False;
453         }
454
455         Standard_Real aCoeff = myStartPosition.Location().Distance (aNewPosition)
456                              / myStartPosition.Location().Distance (myStartPick);
457         aNewTrsf.SetScale (myPosition.Location(), aCoeff);
458         theTrsf = aNewTrsf;
459       }
460       return Standard_True;
461     }
462     case AIS_MM_Rotation:
463     {
464       const gp_Pnt aPosLoc   = myStartPosition.Location();
465       const gp_Ax1 aCurrAxis = getAx1FromAx2Dir (myStartPosition, myCurrentIndex);
466       IntAna_IntConicQuad aIntersector (anInputLine, gp_Pln (aPosLoc, aCurrAxis.Direction()), Precision::Angular(), Precision::Intersection());
467       if (!aIntersector.IsDone() || aIntersector.NbPoints() < 1)
468       {
469         return Standard_False;
470       }
471
472       const gp_Pnt aNewPosition = aIntersector.Point (1);
473       if (!myHasStartedTransformation)
474       {
475         myStartPick = aNewPosition;
476         myHasStartedTransformation = Standard_True;
477         gp_Dir aStartAxis = gce_MakeDir (aPosLoc, myStartPick);
478         myPrevState = aStartAxis.AngleWithRef (gce_MakeDir(aPosLoc, aNewPosition), aCurrAxis.Direction());
479         return Standard_True;
480       }
481
482       if (aNewPosition.Distance (myStartPick) < Precision::Confusion())
483       {
484         return Standard_False;
485       }
486
487       gp_Dir aStartAxis = aPosLoc.IsEqual (myStartPick, Precision::Confusion())
488         ? getAx1FromAx2Dir (myStartPosition, (myCurrentIndex + 1) % 3).Direction()
489         : gce_MakeDir (aPosLoc, myStartPick);
490
491       gp_Dir aCurrentAxis = gce_MakeDir (aPosLoc, aNewPosition);
492       Standard_Real anAngle = aStartAxis.AngleWithRef (aCurrentAxis, aCurrAxis.Direction());
493
494       // Change value of an angle if it should have different sign.
495       if (anAngle * myPrevState < 0 && Abs (anAngle) < M_PI_2)
496       {
497         Standard_Real aSign = myPrevState > 0 ? -1.0 : 1.0;
498         anAngle = aSign * (M_PI * 2 - anAngle);
499       }
500
501       if (Abs (anAngle) < Precision::Confusion())
502       {
503         return Standard_False;
504       }
505
506       gp_Trsf aNewTrsf;
507       aNewTrsf.SetRotation (aCurrAxis, anAngle);
508       theTrsf *= aNewTrsf;
509       myPrevState = anAngle;
510       return Standard_True;
511     }
512     case AIS_MM_None:
513     {
514       return Standard_False;
515     }
516   }
517   return Standard_False;
518 }
519
520 //=======================================================================
521 //function : StartTransform
522 //purpose  : 
523 //=======================================================================
524 void AIS_Manipulator::StartTransform (const Standard_Integer theX, const Standard_Integer theY, const Handle(V3d_View)& theView)
525 {
526   if (myHasStartedTransformation)
527   {
528     return;
529   }
530
531   gp_Trsf aTrsf;
532   ObjectTransformation (theX, theY, theView, aTrsf);
533 }
534
535 //=======================================================================
536 //function : StopTransform
537 //purpose  : 
538 //=======================================================================
539 void AIS_Manipulator::StopTransform (const Standard_Boolean theToApply)
540 {
541   if (!IsAttached() || !myHasStartedTransformation)
542   {
543     return;
544   }
545
546   myHasStartedTransformation = Standard_False;
547   if (theToApply)
548   {
549     return;
550   }
551
552   Handle(AIS_ManipulatorObjectSequence) anObjects = Objects();
553   AIS_ManipulatorObjectSequence::Iterator anObjIter (*anObjects);
554   NCollection_Sequence<gp_Trsf>::Iterator aTrsfIter (myStartTrsfs);
555   for (; anObjIter.More(); anObjIter.Next(), aTrsfIter.Next())
556   {
557     anObjIter.ChangeValue()->SetLocalTransformation (aTrsfIter.Value());
558   }
559   SetPosition (myStartPosition);
560 }
561
562 //=======================================================================
563 //function : Transform
564 //purpose  : 
565 //=======================================================================
566 void AIS_Manipulator::Transform (const gp_Trsf& theTrsf)
567 {
568   if (!IsAttached() || !myHasStartedTransformation)
569   {
570     return;
571   }
572
573   {
574     Handle(AIS_ManipulatorObjectSequence) anObjects = Objects();
575     AIS_ManipulatorObjectSequence::Iterator anObjIter (*anObjects);
576     NCollection_Sequence<gp_Trsf>::Iterator aTrsfIter (myStartTrsfs);
577     for (; anObjIter.More(); anObjIter.Next(), aTrsfIter.Next())
578     {
579       anObjIter.ChangeValue()->SetLocalTransformation (theTrsf * aTrsfIter.Value());
580     }
581   }
582
583   if ((myCurrentMode == AIS_MM_Translation && myBehaviorOnTransform.FollowTranslation)
584    || (myCurrentMode == AIS_MM_Rotation    && myBehaviorOnTransform.FollowRotation))
585   {
586     gp_Pnt aPos  = myStartPosition.Location().Transformed (theTrsf);
587     gp_Dir aVDir = myStartPosition.Direction().Transformed (theTrsf);
588     gp_Dir aXDir = myStartPosition.XDirection().Transformed (theTrsf);
589     SetPosition (gp_Ax2 (aPos, aVDir, aXDir));
590   }
591 }
592
593 //=======================================================================
594 //function : Transform
595 //purpose  : 
596 //=======================================================================
597 gp_Trsf AIS_Manipulator::Transform (const Standard_Integer thePX, const Standard_Integer thePY,
598                                     const Handle(V3d_View)& theView)
599 {
600   gp_Trsf aTrsf;
601   if (ObjectTransformation (thePX, thePY, theView, aTrsf))
602   {
603     Transform (aTrsf);
604   }
605
606   return aTrsf;
607 }
608
609 //=======================================================================
610 //function : SetPosition
611 //purpose  : 
612 //=======================================================================
613 void AIS_Manipulator::SetPosition (const gp_Ax2& thePosition)
614 {
615   if (!myPosition.Location().IsEqual (thePosition.Location(), Precision::Confusion())
616    || !myPosition.Direction().IsEqual (thePosition.Direction(), Precision::Angular())
617    || !myPosition.XDirection().IsEqual (thePosition.XDirection(), Precision::Angular()))
618   {
619     myPosition = thePosition;
620     myAxes[0].SetPosition (getAx1FromAx2Dir (thePosition, 0));
621     myAxes[1].SetPosition (getAx1FromAx2Dir (thePosition, 1));
622     myAxes[2].SetPosition (getAx1FromAx2Dir (thePosition, 2));
623     updateTransformation();
624   }
625 }
626
627 //=======================================================================
628 //function : updateTransformation
629 //purpose  : set local transformation to avoid graphics recomputation
630 //=======================================================================
631 void AIS_Manipulator::updateTransformation()
632 {
633   gp_Trsf aTrsf;
634
635   if (!myIsZoomPersistentMode)
636   {
637     aTrsf.SetTransformation (myPosition, gp::XOY());
638   }
639   else
640   {
641     const gp_Dir& aVDir = myPosition.Direction();
642     const gp_Dir& aXDir = myPosition.XDirection();
643     aTrsf.SetTransformation (gp_Ax2 (gp::Origin(), aVDir, aXDir), gp::XOY());
644   }
645
646   Handle(Geom_Transformation) aGeomTrsf = new Geom_Transformation (aTrsf);
647   // we explicitly call here setLocalTransformation() of the base class
648   // since AIS_Manipulator::setLocalTransformation() implementation throws exception
649   // as protection from external calls
650   AIS_InteractiveObject::setLocalTransformation (aGeomTrsf);
651   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
652   {
653     myAxes[anIt].Transform (aGeomTrsf);
654   }
655
656   if (myIsZoomPersistentMode)
657   {
658     if (TransformPersistence().IsNull()
659     ||  TransformPersistence()->Mode() != Graphic3d_TMF_ZoomPers
660     || !TransformPersistence()->AnchorPoint().IsEqual (myPosition.Location(), 0.0))
661     {
662       setTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_ZoomPers, myPosition.Location()));
663     }
664   }
665 }
666
667 //=======================================================================
668 //function : SetSize
669 //purpose  : 
670 //=======================================================================
671 void AIS_Manipulator::SetSize (const Standard_ShortReal theSideLength)
672 {
673   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
674   {
675     myAxes[anIt].SetSize (theSideLength);
676   }
677
678   SetToUpdate();
679 }
680
681 //=======================================================================
682 //function : SetGap
683 //purpose  : 
684 //=======================================================================
685 void AIS_Manipulator::SetGap (const Standard_ShortReal theValue)
686 {
687   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
688   {
689     myAxes[anIt].SetIndent (theValue);
690   }
691
692   SetToUpdate();
693 }
694
695 //=======================================================================
696 //function : DeactivateCurrentMode
697 //purpose  : 
698 //=======================================================================
699 void AIS_Manipulator::DeactivateCurrentMode()
700 {
701   if (!myIsActivationOnDetection)
702   {
703     Handle(Graphic3d_Group) aGroup = getGroup (myCurrentIndex, myCurrentMode);
704     if (aGroup.IsNull())
705     {
706       return;
707     }
708
709     Handle(Prs3d_ShadingAspect) anAspect = new Prs3d_ShadingAspect();
710     anAspect->Aspect()->SetInteriorStyle (Aspect_IS_SOLID);
711     anAspect->SetMaterial (myDrawer->ShadingAspect()->Material());
712     anAspect->SetTransparency (myDrawer->ShadingAspect()->Transparency());
713     anAspect->SetColor (myAxes[myCurrentIndex].Color());
714
715     aGroup->SetGroupPrimitivesAspect (anAspect->Aspect());
716   }
717
718   myCurrentIndex = -1;
719   myCurrentMode = AIS_MM_None;
720
721   if (myHasStartedTransformation)
722   {
723     myHasStartedTransformation = Standard_False;
724   }
725 }
726
727 //=======================================================================
728 //function : SetZoomPersistence
729 //purpose  : 
730 //=======================================================================
731 void AIS_Manipulator::SetZoomPersistence (const Standard_Boolean theToEnable)
732 {
733   if (myIsZoomPersistentMode != theToEnable)
734   {
735     SetToUpdate();
736   }
737
738   myIsZoomPersistentMode = theToEnable;
739
740   if (!theToEnable)
741   {
742     setTransformPersistence (Handle(Graphic3d_TransformPers)());
743   }
744
745   updateTransformation();
746 }
747
748 //=======================================================================
749 //function : SetTransformPersistence
750 //purpose  :
751 //=======================================================================
752 void AIS_Manipulator::SetTransformPersistence (const Handle(Graphic3d_TransformPers)& theTrsfPers)
753 {
754   Standard_ASSERT_RETURN (!myIsZoomPersistentMode,
755     "AIS_Manipulator::SetTransformPersistence: "
756     "Custom settings are not allowed by this class in ZoomPersistence mode",);
757
758   setTransformPersistence (theTrsfPers);
759 }
760
761 //=======================================================================
762 //function : setTransformPersistence
763 //purpose  : 
764 //=======================================================================
765 void AIS_Manipulator::setTransformPersistence (const Handle(Graphic3d_TransformPers)& theTrsfPers)
766 {
767   AIS_InteractiveObject::SetTransformPersistence (theTrsfPers);
768
769   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
770   {
771     myAxes[anIt].SetTransformPersistence (theTrsfPers);
772   }
773 }
774
775 //=======================================================================
776 //function : setLocalTransformation
777 //purpose  :
778 //=======================================================================
779 void AIS_Manipulator::setLocalTransformation (const Handle(Geom_Transformation)& /*theTrsf*/)
780 {
781   Standard_ASSERT_INVOKE ("AIS_Manipulator::setLocalTransformation: "
782                           "Custom transformation is not supported by this class");
783 }
784
785 //=======================================================================
786 //function : Compute
787 //purpose  : 
788 //=======================================================================
789 void AIS_Manipulator::Compute (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
790                                const Handle(Prs3d_Presentation)& thePrs,
791                                const Standard_Integer theMode)
792 {
793   if (theMode != AIS_Shaded)
794   {
795     return;
796   }
797
798   thePrs->SetInfiniteState (Standard_True);
799   thePrs->SetMutable (Standard_True);
800   Handle(Graphic3d_Group) aGroup;
801   Handle(Prs3d_ShadingAspect) anAspect = new Prs3d_ShadingAspect();
802   anAspect->Aspect()->SetInteriorStyle (Aspect_IS_SOLID);
803   anAspect->SetMaterial (myDrawer->ShadingAspect()->Material());
804   anAspect->SetTransparency (myDrawer->ShadingAspect()->Transparency());
805
806   // Display center
807   myCenter.Init (myAxes[0].AxisRadius() * 2.0f, gp::Origin());
808   aGroup = Prs3d_Root::NewGroup (thePrs);
809   aGroup->SetPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
810   aGroup->AddPrimitiveArray (myCenter.Array());
811
812   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
813   {
814     // Display axes
815     aGroup = Prs3d_Root::NewGroup (thePrs);
816
817     Handle(Prs3d_ShadingAspect) anAspectAx = new Prs3d_ShadingAspect (new Graphic3d_AspectFillArea3d(*anAspect->Aspect()));
818     anAspectAx->SetColor (myAxes[anIt].Color());
819     aGroup->SetGroupPrimitivesAspect (anAspectAx->Aspect());
820     myAxes[anIt].Compute (thePrsMgr, thePrs, anAspectAx);
821     myAxes[anIt].SetTransformPersistence (TransformPersistence());
822   }
823
824   updateTransformation();
825 }
826
827 //=======================================================================
828 //function : HilightSelected
829 //purpose  : 
830 //=======================================================================
831 void AIS_Manipulator::HilightSelected (const Handle(PrsMgr_PresentationManager3d)& thePM,
832                                        const SelectMgr_SequenceOfOwner& theSeq)
833 {
834   if (theSeq.IsEmpty())
835   {
836     return;
837   }
838
839   if (myIsActivationOnDetection)
840   {
841     return;
842   }
843
844   if (!theSeq (1)->IsKind (STANDARD_TYPE (AIS_ManipulatorOwner)))
845   {
846     thePM->Color (this, GetContext()->HighlightStyle(), 0);
847     return;
848   }
849
850   Handle(AIS_ManipulatorOwner) anOwner = Handle(AIS_ManipulatorOwner)::DownCast (theSeq (1));
851   myHighlightAspect->Aspect()->SetInteriorColor (GetContext()->HighlightStyle()->Color());
852   Handle(Graphic3d_Group) aGroup = getGroup (anOwner->Index(), anOwner->Mode());
853   if (aGroup.IsNull())
854   {
855     return;
856   }
857
858   aGroup->SetGroupPrimitivesAspect (myHighlightAspect->Aspect());
859
860   myCurrentIndex = anOwner->Index();
861   myCurrentMode = anOwner->Mode();
862 }
863
864 //=======================================================================
865 //function : ClearSelected
866 //purpose  :
867 //=======================================================================
868 void AIS_Manipulator::ClearSelected()
869 {
870   DeactivateCurrentMode();
871 }
872
873 //=======================================================================
874 //function : HilightOwnerWithColor
875 //purpose  : 
876 //=======================================================================
877 void AIS_Manipulator::HilightOwnerWithColor (const Handle(PrsMgr_PresentationManager3d)& thePM,
878                                              const Handle(Prs3d_Drawer)& theStyle,
879                                              const Handle(SelectMgr_EntityOwner)& theOwner)
880 {
881   Handle(AIS_ManipulatorOwner) anOwner = Handle(AIS_ManipulatorOwner)::DownCast (theOwner);
882   Handle(Prs3d_Presentation) aPresentation = getHighlightPresentation (anOwner);
883   if (aPresentation.IsNull())
884   {
885     return;
886   }
887   aPresentation->Highlight (theStyle);
888   for (Graphic3d_SequenceOfGroup::Iterator aGroupIter (aPresentation->Groups());
889        aGroupIter.More(); aGroupIter.Next())
890   {
891     Handle(Graphic3d_Group)& aGrp = aGroupIter.ChangeValue();
892     if (!aGrp.IsNull()
893      && aGrp->IsGroupPrimitivesAspectSet (Graphic3d_ASPECT_FILL_AREA))
894     {
895       aGrp->SetGroupPrimitivesAspect (myHighlightAspect->Aspect());
896     }
897   }
898   aPresentation->SetZLayer (Graphic3d_ZLayerId_Topmost);
899   thePM->AddToImmediateList (aPresentation);
900
901   if (myIsActivationOnDetection)
902   {
903     if (HasActiveMode())
904     {
905       DeactivateCurrentMode();
906     }
907
908     myCurrentIndex = anOwner->Index();
909     myCurrentMode = anOwner->Mode();
910   }
911 }
912
913 //=======================================================================
914 //function : ComputeSelection
915 //purpose  : 
916 //=======================================================================
917 void AIS_Manipulator::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
918                                         const Standard_Integer theMode)
919 {
920   //Check mode
921   AIS_ManipulatorMode aMode = (AIS_ManipulatorMode) theMode;
922   if (aMode == AIS_MM_None)
923   {
924     return;
925   }
926   Handle(SelectMgr_EntityOwner) anOwner;
927   if (aMode == AIS_MM_None)
928   {
929     anOwner = new SelectMgr_EntityOwner (this, 5);
930   }
931
932   if (aMode == AIS_MM_Translation || aMode == AIS_MM_None)
933   {
934     for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
935     {
936       const Axis& anAxis = myAxes[anIt];
937       if (aMode != AIS_MM_None)
938       {
939         anOwner = new AIS_ManipulatorOwner(this, anIt, AIS_MM_Translation, 9);
940       }
941       // define sensitivity by line
942       Handle(Select3D_SensitiveSegment) aLine = new Select3D_SensitiveSegment (anOwner, gp::Origin(), anAxis.TranslatorTipPosition());
943       aLine->SetSensitivityFactor (15);
944       theSelection->Add (aLine);
945
946       // enlarge sensitivity by triangulation
947       Handle(Select3D_SensitivePrimitiveArray) aTri = new Select3D_SensitivePrimitiveArray (anOwner);
948       aTri->InitTriangulation (anAxis.TriangleArray()->Attributes(), anAxis.TriangleArray()->Indices(), TopLoc_Location());
949       theSelection->Add (aTri);
950     }
951   }
952
953   if (aMode == AIS_MM_Rotation || aMode == AIS_MM_None)
954   {
955     for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
956     {
957       const Axis& anAxis = myAxes[anIt];
958       if (aMode != AIS_MM_None)
959       {
960         anOwner = new AIS_ManipulatorOwner (this, anIt, AIS_MM_Rotation, 9);
961       }
962       // define sensitivity by circle
963       Handle(Geom_Circle) aGeomCircle = new Geom_Circle (gp_Ax2 (gp::Origin(), anAxis.ReferenceAxis().Direction()), anAxis.RotatorDiskRadius());
964       Handle(Select3D_SensitiveCircle) aCircle = new Select3D_SensitiveCircle (anOwner, aGeomCircle, Standard_False, anAxis.FacettesNumber());
965       aCircle->SetSensitivityFactor (15);
966       theSelection->Add (aCircle);
967       // enlarge sensitivity by triangulation
968       Handle(Select3D_SensitiveTriangulation) aTri = new Select3D_SensitiveTriangulation (anOwner, myAxes[anIt].RotatorDisk().Triangulation(), TopLoc_Location(), Standard_True);
969       theSelection->Add (aTri);
970     }
971   }
972
973   if (aMode == AIS_MM_Scaling || aMode == AIS_MM_None)
974   {
975     for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
976     {
977       if (aMode != AIS_MM_None)
978       {
979         anOwner = new AIS_ManipulatorOwner (this, anIt, AIS_MM_Scaling, 9);
980       }
981       // define sensitivity by point
982       Handle(Select3D_SensitivePoint) aPnt = new Select3D_SensitivePoint (anOwner, myAxes[anIt].ScalerCubePosition());
983       aPnt->SetSensitivityFactor (15);
984       theSelection->Add (aPnt);
985       // enlarge sensitivity by triangulation
986       Handle(Select3D_SensitiveTriangulation) aTri = new Select3D_SensitiveTriangulation (anOwner, myAxes[anIt].ScalerCube().Triangulation(), TopLoc_Location(), Standard_True);
987       theSelection->Add (aTri);
988     }
989   }
990 }
991
992 //=======================================================================
993 //class    : Disk
994 //function : Init
995 //purpose  : 
996 //=======================================================================
997 void AIS_Manipulator::Disk::Init (const Standard_ShortReal theInnerRadius,
998                                   const Standard_ShortReal theOuterRadius,
999                                   const gp_Ax1& thePosition,
1000                                   const Standard_Integer theSlicesNb,
1001                                   const Standard_Integer theStacksNb)
1002 {
1003   myPosition = thePosition;
1004   myInnerRad = theInnerRadius;
1005   myOuterRad = theOuterRadius;
1006
1007   Prs3d_ToolDisk aTool (theInnerRadius, theOuterRadius, theSlicesNb, theStacksNb);
1008   gp_Ax3 aSystem (myPosition.Location(), myPosition.Direction());
1009   gp_Trsf aTrsf;
1010   aTrsf.SetTransformation (aSystem, gp_Ax3());
1011   aTool.FillArray (myArray, myTriangulation, aTrsf);
1012 }
1013
1014 //=======================================================================
1015 //class    : Sphere
1016 //function : Init
1017 //purpose  : 
1018 //=======================================================================
1019 void AIS_Manipulator::Sphere::Init (const Standard_ShortReal theRadius,
1020                                     const gp_Pnt& thePosition,
1021                                     const Standard_Integer theSlicesNb,
1022                                     const Standard_Integer theStacksNb)
1023 {
1024   myPosition = thePosition;
1025   myRadius = theRadius;
1026
1027   Prs3d_ToolSphere aTool (theRadius, theSlicesNb, theStacksNb);
1028   gp_Trsf aTrsf;
1029   aTrsf.SetTranslation (gp_Vec(gp::Origin(), thePosition));
1030   aTool.FillArray (myArray, myTriangulation, aTrsf);
1031 }
1032
1033 //=======================================================================
1034 //class    : Cube
1035 //function : Init
1036 //purpose  : 
1037 //=======================================================================
1038 void AIS_Manipulator::Cube::Init (const gp_Ax1& thePosition, const Standard_ShortReal theSize)
1039 {
1040   myArray = new Graphic3d_ArrayOfTriangles (12 * 3, 0, Standard_True);
1041
1042   Poly_Array1OfTriangle aPolyTriangles (1, 12);
1043   TColgp_Array1OfPnt aPoints (1, 36);
1044   NCollection_Array1<gp_Dir> aNormals (1, 12);
1045   myTriangulation = new Poly_Triangulation (aPoints, aPolyTriangles);
1046
1047   gp_Ax2 aPln (thePosition.Location(), thePosition.Direction());
1048   gp_Pnt aBottomLeft = thePosition.Location().XYZ() - aPln.XDirection().XYZ() * theSize * 0.5 - aPln.YDirection().XYZ() * theSize * 0.5;
1049   gp_Pnt aV2 = aBottomLeft.XYZ() + aPln.YDirection().XYZ() * theSize;
1050   gp_Pnt aV3 = aBottomLeft.XYZ() + aPln.YDirection().XYZ() * theSize + aPln.XDirection().XYZ() * theSize;
1051   gp_Pnt aV4 = aBottomLeft.XYZ() + aPln.XDirection().XYZ() * theSize;
1052   gp_Pnt aTopRight = thePosition.Location().XYZ() + thePosition.Direction().XYZ() * theSize
1053     + aPln.XDirection().XYZ() * theSize * 0.5 + aPln.YDirection().XYZ() * theSize * 0.5;
1054   gp_Pnt aV5 = aTopRight.XYZ() - aPln.YDirection().XYZ() * theSize;
1055   gp_Pnt aV6 = aTopRight.XYZ() - aPln.YDirection().XYZ() * theSize - aPln.XDirection().XYZ() * theSize;
1056   gp_Pnt aV7 = aTopRight.XYZ() - aPln.XDirection().XYZ() * theSize;
1057
1058   gp_Dir aRight ((gp_Vec(aTopRight, aV7) ^ gp_Vec(aTopRight, aV2)).XYZ());
1059   gp_Dir aFront ((gp_Vec(aV3, aV4) ^ gp_Vec(aV3, aV5)).XYZ());
1060
1061   // Bottom
1062   addTriangle (0, aBottomLeft, aV2, aV3, -thePosition.Direction());
1063   addTriangle (1, aBottomLeft, aV3, aV4, -thePosition.Direction());
1064
1065   // Front
1066   addTriangle (2, aV3, aV4, aV5, aFront);
1067   addTriangle (3, aV3, aV5, aTopRight, aFront);
1068
1069   // Back
1070   addTriangle (4, aBottomLeft, aV2, aV7, -aFront);
1071   addTriangle (5, aBottomLeft, aV7, aV6, -aFront);
1072
1073   // aTop
1074   addTriangle (6, aV7, aV6, aV5, thePosition.Direction());
1075   addTriangle (7, aTopRight, aV7, aV5, thePosition.Direction());
1076
1077   //Left
1078   addTriangle (8, aV6, aV5, aV4, -aRight);
1079   addTriangle (9, aBottomLeft, aV6, aV4, -aRight);
1080
1081   // Right
1082   addTriangle (10, aV3, aTopRight, aV7, aRight);
1083   addTriangle (11, aV3, aV7, aV2, aRight);
1084 }
1085
1086 //=======================================================================
1087 //class    : Cube
1088 //function : addTriangle
1089 //purpose  : 
1090 //=======================================================================
1091 void AIS_Manipulator::Cube::addTriangle (const Standard_Integer theIndex,
1092                                          const gp_Pnt& theP1, const gp_Pnt& theP2, const gp_Pnt& theP3,
1093                                          const gp_Dir& theNormal)
1094 {
1095   myTriangulation->ChangeNodes().SetValue (theIndex * 3 + 1, theP1);
1096   myTriangulation->ChangeNodes().SetValue (theIndex * 3 + 2, theP2);
1097   myTriangulation->ChangeNodes().SetValue (theIndex * 3 + 3, theP3);
1098
1099   myTriangulation->ChangeTriangles().SetValue (theIndex + 1, Poly_Triangle (theIndex * 3 + 1, theIndex * 3 + 2, theIndex * 3 + 3));
1100   myArray->AddVertex (theP1, theNormal);
1101   myArray->AddVertex (theP2, theNormal);
1102   myArray->AddVertex (theP3, theNormal);
1103 }
1104
1105 //=======================================================================
1106 //class    : Axis
1107 //function : Constructor
1108 //purpose  : 
1109 //=======================================================================
1110 AIS_Manipulator::Axis::Axis (const gp_Ax1& theAxis,
1111                              const Quantity_Color& theColor,
1112                              const Standard_ShortReal theLength)
1113 : myReferenceAxis (theAxis),
1114   myPosition (theAxis),
1115   myColor (theColor),
1116   myHasTranslation (Standard_True),
1117   myLength (theLength),
1118   myAxisRadius (0.5f),
1119   myHasScaling (Standard_True),
1120   myBoxSize (2.0f),
1121   myHasRotation (Standard_True),
1122   myInnerRadius (myLength + myBoxSize),
1123   myDiskThickness (myBoxSize * 0.5f),
1124   myIndent (0.2f),
1125   myFacettesNumber (20),
1126   myCircleRadius (myLength + myBoxSize + myBoxSize * 0.5f * 0.5f)
1127 {
1128   //
1129 }
1130
1131 //=======================================================================
1132 //class    : Axis
1133 //function : Compute
1134 //purpose  :
1135 //=======================================================================
1136
1137 void AIS_Manipulator::Axis::Compute (const Handle(PrsMgr_PresentationManager)& thePrsMgr,
1138                                      const Handle(Prs3d_Presentation)& thePrs,
1139                                      const Handle(Prs3d_ShadingAspect)& theAspect)
1140 {
1141   if (myHasTranslation)
1142   {
1143     const Standard_Real anArrowLength   = 0.25 * myLength;
1144     const Standard_Real aCylinderLength = myLength - anArrowLength;
1145     myArrowTipPos = gp_Pnt (0.0, 0.0, 0.0).Translated (myReferenceAxis.Direction().XYZ() * aCylinderLength);
1146
1147     myTriangleArray = Prs3d_Arrow::DrawShaded (gp_Ax1(gp::Origin(), myReferenceAxis.Direction()),
1148                                                myAxisRadius,
1149                                                myLength,
1150                                                myAxisRadius * 1.5,
1151                                                anArrowLength,
1152                                                myFacettesNumber);
1153     myTranslatorGroup = Prs3d_Root::NewGroup (thePrs);
1154     myTranslatorGroup->SetGroupPrimitivesAspect (theAspect->Aspect());
1155     myTranslatorGroup->AddPrimitiveArray (myTriangleArray);
1156
1157     if (myHighlightTranslator.IsNull())
1158     {
1159       myHighlightTranslator = new Prs3d_Presentation (thePrsMgr->StructureManager());
1160     }
1161     else
1162     {
1163       myHighlightTranslator->Clear();
1164     }
1165     {
1166       Handle(Graphic3d_Group) aGroup = Prs3d_Root::CurrentGroup (myHighlightTranslator);
1167       aGroup->SetGroupPrimitivesAspect (theAspect->Aspect());
1168       aGroup->AddPrimitiveArray (myTriangleArray);
1169     }
1170   }
1171
1172   if (myHasScaling)
1173   {
1174     myCubePos = myReferenceAxis.Direction().XYZ() * (myLength + myIndent);
1175     myCube.Init (gp_Ax1 (myCubePos, myReferenceAxis.Direction()), myBoxSize);
1176
1177     myScalerGroup = Prs3d_Root::NewGroup (thePrs);
1178     myScalerGroup->SetGroupPrimitivesAspect (theAspect->Aspect());
1179     myScalerGroup->AddPrimitiveArray (myCube.Array());
1180
1181     if (myHighlightScaler.IsNull())
1182     {
1183       myHighlightScaler = new Prs3d_Presentation (thePrsMgr->StructureManager());
1184     }
1185     else
1186     {
1187       myHighlightScaler->Clear();
1188     }
1189     {
1190       Handle(Graphic3d_Group) aGroup = Prs3d_Root::CurrentGroup (myHighlightScaler);
1191       aGroup->SetGroupPrimitivesAspect (theAspect->Aspect());
1192       aGroup->AddPrimitiveArray (myCube.Array());
1193     }
1194   }
1195
1196   if (myHasRotation)
1197   {
1198     myCircleRadius = myInnerRadius + myIndent * 2 + myDiskThickness * 0.5f;
1199     myCircle.Init (myInnerRadius + myIndent * 2, myInnerRadius + myDiskThickness + myIndent * 2, gp_Ax1(gp::Origin(), myReferenceAxis.Direction()), myFacettesNumber * 2);
1200     myRotatorGroup = Prs3d_Root::NewGroup (thePrs);
1201     myRotatorGroup->SetGroupPrimitivesAspect (theAspect->Aspect());
1202     myRotatorGroup->AddPrimitiveArray (myCircle.Array());
1203
1204     if (myHighlightRotator.IsNull())
1205     {
1206       myHighlightRotator = new Prs3d_Presentation (thePrsMgr->StructureManager());
1207     }
1208     else
1209     {
1210       myHighlightRotator->Clear();
1211     }
1212     {
1213       Handle(Graphic3d_Group) aGroup = Prs3d_Root::CurrentGroup (myHighlightRotator);
1214       aGroup->SetGroupPrimitivesAspect (theAspect->Aspect());
1215       aGroup->AddPrimitiveArray (myCircle.Array());
1216     }
1217   }
1218 }