0031117: Visualization, AIS_ViewCube - additional properties for visualization of...
[occt.git] / src / AIS / AIS_ViewCube.cxx
1 // Created on: 2017-07-25
2 // Created by: Anastasia BOBYLEVA
3 // Copyright (c) 2017-2019 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_ViewCube.hxx>
17
18 #include <AIS_AnimationCamera.hxx>
19 #include <AIS_InteractiveContext.hxx>
20 #include <gp_Ax2.hxx>
21 #include <Graphic3d_ViewAffinity.hxx>
22 #include <Graphic3d_Text.hxx>
23 #include <NCollection_Lerp.hxx>
24 #include <Prs3d.hxx>
25 #include <Prs3d_Arrow.hxx>
26 #include <Prs3d_DatumAspect.hxx>
27 #include <Prs3d_Root.hxx>
28 #include <Prs3d_Text.hxx>
29 #include <Prs3d_ToolDisk.hxx>
30 #include <Prs3d_ToolSphere.hxx>
31 #include <Select3D_SensitivePrimitiveArray.hxx>
32 #include <SelectMgr_SequenceOfOwner.hxx>
33 #include <V3d.hxx>
34 #include <V3d_View.hxx>
35
36 IMPLEMENT_STANDARD_RTTIEXT(AIS_ViewCube, AIS_InteractiveObject)
37 IMPLEMENT_STANDARD_RTTIEXT(AIS_ViewCubeOwner, SelectMgr_EntityOwner)
38
39 namespace
40 {
41   static const Standard_Integer THE_NB_ROUND_SPLITS = 8;
42   static const Standard_Integer THE_NB_DISK_SLICES = 20;
43   static const Standard_Integer THE_NB_ARROW_FACETTES = 20;
44
45   //! Return the number of non-zero components.
46   static Standard_Integer nbDirectionComponents (const gp_Dir& theDir)
47   {
48     Standard_Integer aNbComps = 0;
49     for (Standard_Integer aCompIter = 1; aCompIter <= 3; ++aCompIter)
50     {
51       if (Abs (theDir.Coord (aCompIter)) > gp::Resolution())
52       {
53         ++aNbComps;
54       }
55     }
56     return aNbComps;
57   }
58 }
59
60 //! Simple sensitive element for picking by point only.
61 class AIS_ViewCubeSensitive : public Select3D_SensitivePrimitiveArray
62 {
63   DEFINE_STANDARD_RTTI_INLINE(AIS_ViewCubeSensitive, Select3D_SensitivePrimitiveArray)
64 public:
65   //! Constructor.
66   AIS_ViewCubeSensitive (const Handle(SelectMgr_EntityOwner)& theOwner,
67                          const Handle(Graphic3d_ArrayOfTriangles)& theTris)
68   : Select3D_SensitivePrimitiveArray (theOwner)
69   {
70     InitTriangulation (theTris->Attributes(), theTris->Indices(), TopLoc_Location());
71   }
72
73   //! Checks whether element overlaps current selecting volume.
74   virtual Standard_Boolean Matches (SelectBasics_SelectingVolumeManager& theMgr,
75                                     SelectBasics_PickResult& thePickResult) Standard_OVERRIDE
76   {
77     return isValidRay (theMgr)
78         && Select3D_SensitivePrimitiveArray::Matches (theMgr, thePickResult);
79   }
80
81   //! Checks if picking ray can be used for detection.
82   bool isValidRay (const SelectBasics_SelectingVolumeManager& theMgr) const
83   {
84     if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
85     {
86       // disallow rectangular selection
87       return false;
88     }
89
90     if (AIS_ViewCubeOwner* anOwner = dynamic_cast<AIS_ViewCubeOwner* >(myOwnerId.get()))
91     {
92       const Standard_Real anAngleToler = 10.0 * M_PI / 180.0;
93       const gp_Vec aRay (theMgr.GetNearPickedPnt(), theMgr.GetFarPickedPnt());
94       const gp_Dir aDir = V3d::GetProjAxis (anOwner->MainOrientation());
95       return !aRay.IsNormal (aDir, anAngleToler);
96     }
97     return true;
98   }
99 };
100
101 //=======================================================================
102 //function : IsBoxSide
103 //purpose  :
104 //=======================================================================
105 bool AIS_ViewCube::IsBoxSide (V3d_TypeOfOrientation theOrient)
106 {
107   return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 1;
108 }
109
110 //=======================================================================
111 //function : IsBoxEdge
112 //purpose  :
113 //=======================================================================
114 bool AIS_ViewCube::IsBoxEdge (V3d_TypeOfOrientation theOrient)
115 {
116   return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 2;
117 }
118
119 //=======================================================================
120 //function : IsBoxCorner
121 //purpose  :
122 //=======================================================================
123 bool AIS_ViewCube::IsBoxCorner (V3d_TypeOfOrientation theOrient)
124 {
125   return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 3;
126 }
127
128 //=======================================================================
129 //function : AIS_ViewCube
130 //purpose  :
131 //=======================================================================
132 AIS_ViewCube::AIS_ViewCube()
133 : myBoxEdgeAspect (new Prs3d_ShadingAspect()),
134   myBoxCornerAspect (new Prs3d_ShadingAspect()),
135   mySize (1.0),
136   myBoxEdgeMinSize (2.0),
137   myBoxEdgeGap (0.0),
138   myBoxFacetExtension (1.0),
139   myAxesPadding (1.0),
140   myAxesRadius (1.0),
141   myAxesConeRadius (3.0),
142   myAxesSphereRadius (4.0),
143   myCornerMinSize (2.0),
144   myRoundRadius  (0.0),
145   myToDisplayAxes (true),
146   myToDisplayEdges (true),
147   myToDisplayVertices (true),
148   myIsYup (false),
149   myViewAnimation (new AIS_AnimationCamera ("AIS_ViewCube", Handle(V3d_View)())),
150   myStartState(new Graphic3d_Camera()),
151   myEndState  (new Graphic3d_Camera()),
152   myDuration (0.5),
153   myToAutoStartAnim (true),
154   myIsFixedAnimation (true),
155   myToFitSelected (true),
156   myToResetCameraUp (false)
157 {
158   myInfiniteState = true;
159   myIsMutable = true;
160   myDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
161   myTransformPersistence = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_LEFT_LOWER, Graphic3d_Vec2i (100, 100));
162
163   myDrawer->SetTextAspect  (new Prs3d_TextAspect());
164   myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
165
166   myDynHilightDrawer = new Prs3d_Drawer();
167   myDynHilightDrawer->SetLink (myDrawer);
168   myDynHilightDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
169
170   setDefaultAttributes();
171   setDefaultHighlightAttributes();
172
173   // setup default labels
174   myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Front,  "FRONT");
175   myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Back,   "BACK");
176   myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Top,    "TOP");
177   myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Bottom, "BOTTOM");
178   myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Left,   "LEFT");
179   myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Right,  "RIGHT");
180
181   myAxesLabels.Bind (Prs3d_DP_XAxis, "X");
182   myAxesLabels.Bind (Prs3d_DP_YAxis, "Y");
183   myAxesLabels.Bind (Prs3d_DP_ZAxis, "Z");
184
185   // define default size
186   SetSize (70.0);
187 }
188
189 //=======================================================================
190 //function : setDefaultAttributes
191 //purpose  :
192 //=======================================================================
193 void AIS_ViewCube::setDefaultAttributes()
194 {
195   myDrawer->TextAspect()->SetHorizontalJustification(Graphic3d_HTA_CENTER);
196   myDrawer->TextAspect()->SetVerticalJustification  (Graphic3d_VTA_CENTER);
197   myDrawer->TextAspect()->SetColor (Quantity_NOC_BLACK);
198   myDrawer->TextAspect()->SetFont (Font_NOF_SANS_SERIF);
199   myDrawer->TextAspect()->SetHeight (16.0);
200   myDrawer->TextAspect()->Aspect()->SetTextZoomable (true); // the whole object is drawn within transformation-persistence
201   // this should be forced back-face culling regardless Closed flag
202   myDrawer->TextAspect()->Aspect()->SetSuppressBackFaces (true);
203
204   Graphic3d_MaterialAspect aMat (Graphic3d_NOM_UserDefined);
205   aMat.SetColor (Quantity_NOC_WHITE);
206   aMat.SetAmbientColor (Quantity_NOC_GRAY60);
207
208   const Handle(Graphic3d_AspectFillArea3d)& aShading = myDrawer->ShadingAspect()->Aspect();
209   aShading->SetInteriorStyle (Aspect_IS_SOLID);
210   // this should be forced back-face culling regardless Closed flag
211   aShading->SetSuppressBackFaces (true);
212   aShading->SetInteriorColor (aMat.Color());
213   aShading->SetFrontMaterial (aMat);
214   myDrawer->SetFaceBoundaryDraw (false);
215
216   *myBoxEdgeAspect  ->Aspect() = *aShading;
217   myBoxEdgeAspect->SetColor (Quantity_NOC_GRAY30);
218   *myBoxCornerAspect->Aspect() = *aShading;
219   myBoxCornerAspect->SetColor (Quantity_NOC_GRAY30);
220 }
221
222 //=======================================================================
223 //function : setDefaultHighlightAttributes
224 //purpose  :
225 //=======================================================================
226 void AIS_ViewCube::setDefaultHighlightAttributes()
227 {
228   Graphic3d_MaterialAspect aHighlightMaterial;
229   aHighlightMaterial.SetAmbientColor (Quantity_NOC_BLACK);
230   aHighlightMaterial.SetDiffuseColor (Quantity_NOC_BLACK);
231   aHighlightMaterial.SetSpecularColor(Quantity_NOC_BLACK);
232   aHighlightMaterial.SetEmissiveColor(Quantity_NOC_BLACK);
233   aHighlightMaterial.SetMaterialType (Graphic3d_MATERIAL_ASPECT);
234   myDynHilightDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
235   myDynHilightDrawer->ShadingAspect()->SetMaterial (aHighlightMaterial);
236   myDynHilightDrawer->ShadingAspect()->SetColor (Quantity_NOC_CYAN1);
237   myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
238   myDynHilightDrawer->SetColor (Quantity_NOC_CYAN1);
239 }
240
241 //=======================================================================
242 //function : SetYup
243 //purpose  :
244 //=======================================================================
245 void AIS_ViewCube::SetYup (Standard_Boolean theIsYup,
246                            Standard_Boolean theToUpdateLabels)
247 {
248   if (myIsYup == theIsYup)
249   {
250     return;
251   }
252
253   myIsYup = theIsYup;
254
255   static const V3d_TypeOfOrientation THE_ZUP_ORI_LIST[6] =
256   {
257     V3d_TypeOfOrientation_Zup_Front, V3d_TypeOfOrientation_Zup_Back,
258     V3d_TypeOfOrientation_Zup_Top,   V3d_TypeOfOrientation_Zup_Bottom,
259     V3d_TypeOfOrientation_Zup_Left,  V3d_TypeOfOrientation_Zup_Right
260   };
261   static const V3d_TypeOfOrientation THE_YUP_ORI_LIST[6] =
262   {
263     V3d_TypeOfOrientation_Yup_Front, V3d_TypeOfOrientation_Yup_Back,
264     V3d_TypeOfOrientation_Yup_Top,   V3d_TypeOfOrientation_Yup_Bottom,
265     V3d_TypeOfOrientation_Yup_Left,  V3d_TypeOfOrientation_Yup_Right
266   };
267   if (theToUpdateLabels)
268   {
269     NCollection_Array1<TCollection_AsciiString> aLabels (0, 5);
270     for (Standard_Integer aLabelIter = 0; aLabelIter < 6; ++aLabelIter)
271     {
272       myBoxSideLabels.Find (!myIsYup ? THE_YUP_ORI_LIST[aLabelIter] : THE_ZUP_ORI_LIST[aLabelIter],
273                             aLabels.ChangeValue (aLabelIter));
274     }
275     for (Standard_Integer aLabelIter = 0; aLabelIter < 6; ++aLabelIter)
276     {
277       myBoxSideLabels.Bind (myIsYup ? THE_YUP_ORI_LIST[aLabelIter] : THE_ZUP_ORI_LIST[aLabelIter],
278                             aLabels.Value (aLabelIter));
279     }
280   }
281
282   SetToUpdate();
283 }
284
285 //=======================================================================
286 //function : ResetStyles
287 //purpose  :
288 //=======================================================================
289 void AIS_ViewCube::ResetStyles()
290 {
291   UnsetAttributes();
292   UnsetHilightAttributes();
293
294   myBoxEdgeMinSize = 2.0;
295   myCornerMinSize  = 2.0;
296   myBoxEdgeGap     = 0.0;
297   myRoundRadius    = 0.0;
298
299   myToDisplayAxes = true;
300   myToDisplayEdges = true;
301   myToDisplayVertices = true;
302
303   myBoxFacetExtension = 1.0;
304   myAxesPadding = 1.0;
305   SetSize (70.0);
306 }
307
308 //=======================================================================
309 //function : SetSize
310 //purpose  :
311 //=======================================================================
312 void AIS_ViewCube::SetSize (Standard_Real theValue,
313                             Standard_Boolean theToAdaptAnother)
314 {
315   const bool isNewSize = Abs (mySize - theValue) > Precision::Confusion();
316   mySize = theValue;
317   if (theToAdaptAnother)
318   {
319     if (myBoxFacetExtension > 0.0)
320     {
321       SetBoxFacetExtension (mySize * 0.15);
322     }
323     if (myAxesPadding > 0.0)
324     {
325       SetAxesPadding (mySize * 0.1);
326     }
327     SetFontHeight (mySize * 0.16);
328   }
329   if (isNewSize)
330   {
331     SetToUpdate();
332   }
333 }
334
335 //=======================================================================
336 //function : SetRoundRadius
337 //purpose  :
338 //=======================================================================
339 void AIS_ViewCube::SetRoundRadius (const Standard_Real theValue)
340 {
341   Standard_OutOfRange_Raise_if (theValue < 0.0 || theValue > 0.5,
342                                 "AIS_ViewCube::SetRoundRadius(): theValue should be in [0; 0.5]");
343   if (Abs (myRoundRadius - theValue) > Precision::Confusion())
344   {
345     myRoundRadius = theValue;
346     SetToUpdate();
347   }
348 }
349
350 //=======================================================================
351 //function : createRoundRectangleTriangles
352 //purpose  :
353 //=======================================================================
354 void AIS_ViewCube::createRoundRectangleTriangles (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
355                                                   Standard_Integer& theNbNodes,
356                                                   Standard_Integer& theNbTris,
357                                                   const gp_XY& theSize,
358                                                   Standard_Real theRadius,
359                                                   const gp_Trsf& theTrsf)
360 {
361   const Standard_Real aRadius = Min (theRadius, Min (theSize.X(), theSize.Y()) * 0.5);
362   const gp_XY  aHSize (theSize.X() * 0.5 - aRadius, theSize.Y() * 0.5 - aRadius);
363   const gp_Dir aNorm = gp::DZ().Transformed (theTrsf);
364   const Standard_Integer aVertFirst = !theTris.IsNull() ? theTris->VertexNumber() : 0;
365   if (aRadius > 0.0)
366   {
367     const Standard_Integer aNbNodes = (THE_NB_ROUND_SPLITS + 1) * 4 + 1;
368     theNbNodes += aNbNodes;
369     theNbTris  += aNbNodes;
370     if (theTris.IsNull())
371     {
372       return;
373     }
374
375     theTris->AddVertex (gp_Pnt (0.0, 0.0, 0.0).Transformed (theTrsf));
376     for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
377     {
378       const Standard_Real anAngle = NCollection_Lerp<Standard_Real>::Interpolate (M_PI * 0.5, 0.0, Standard_Real(aNodeIter) / Standard_Real(THE_NB_ROUND_SPLITS));
379       theTris->AddVertex (gp_Pnt (aHSize.X() + aRadius * Cos (anAngle), aHSize.Y() + aRadius * Sin (anAngle), 0.0).Transformed (theTrsf));
380     }
381     for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
382     {
383       const Standard_Real anAngle = NCollection_Lerp<Standard_Real>::Interpolate (0.0, -M_PI * 0.5, Standard_Real(aNodeIter) / Standard_Real(THE_NB_ROUND_SPLITS));
384       theTris->AddVertex (gp_Pnt (aHSize.X() + aRadius * Cos (anAngle), -aHSize.Y() + aRadius * Sin (anAngle), 0.0).Transformed (theTrsf));
385     }
386     for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
387     {
388       const Standard_Real anAngle = NCollection_Lerp<Standard_Real>::Interpolate (-M_PI * 0.5, -M_PI, Standard_Real(aNodeIter) / Standard_Real(THE_NB_ROUND_SPLITS));
389       theTris->AddVertex (gp_Pnt (-aHSize.X() + aRadius * Cos (anAngle), -aHSize.Y() + aRadius * Sin (anAngle), 0.0).Transformed (theTrsf));
390     }
391     for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
392     {
393       const Standard_Real anAngle = NCollection_Lerp<Standard_Real>::Interpolate (-M_PI, -M_PI * 1.5, Standard_Real(aNodeIter) / Standard_Real(THE_NB_ROUND_SPLITS));
394       theTris->AddVertex (gp_Pnt (-aHSize.X() + aRadius * Cos (anAngle), aHSize.Y() + aRadius * Sin (anAngle), 0.0).Transformed (theTrsf));
395     }
396
397     // split triangle fan
398     theTris->AddTriangleFanEdges (aVertFirst + 1, theTris->VertexNumber(), true);
399   }
400   else
401   {
402     theNbNodes += 4;
403     theNbTris  += 2;
404     if (theTris.IsNull())
405     {
406       return;
407     }
408
409     theTris->AddVertex (gp_Pnt (-aHSize.X(), -aHSize.Y(), 0.0).Transformed (theTrsf));
410     theTris->AddVertex (gp_Pnt (-aHSize.X(),  aHSize.Y(), 0.0).Transformed (theTrsf));
411     theTris->AddVertex (gp_Pnt ( aHSize.X(),  aHSize.Y(), 0.0).Transformed (theTrsf));
412     theTris->AddVertex (gp_Pnt ( aHSize.X(), -aHSize.Y(), 0.0).Transformed (theTrsf));
413     theTris->AddQuadTriangleEdges (aVertFirst + 1, aVertFirst + 2, aVertFirst + 3, aVertFirst + 4);
414   }
415
416   for (Standard_Integer aVertIter = aVertFirst + 1; aVertIter <= theTris->VertexNumber(); ++aVertIter)
417   {
418     theTris->SetVertexNormal (aVertIter, -aNorm);
419   }
420 }
421
422 //=======================================================================
423 //function : createBoxPartTriangles
424 //purpose  :
425 //=======================================================================
426 void AIS_ViewCube::createBoxPartTriangles (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
427                                            Standard_Integer& theNbNodes,
428                                            Standard_Integer& theNbTris,
429                                            V3d_TypeOfOrientation theDir) const
430 {
431   if (IsBoxSide (theDir))
432   {
433     createBoxSideTriangles (theTris, theNbNodes, theNbTris, theDir);
434   }
435   else if (IsBoxEdge (theDir)
436         && myToDisplayEdges)
437   {
438     createBoxEdgeTriangles (theTris, theNbNodes, theNbTris, theDir);
439   }
440   else if (IsBoxCorner (theDir)
441         && myToDisplayVertices)
442   {
443     createBoxCornerTriangles (theTris, theNbNodes, theNbTris, theDir);
444   }
445 }
446
447 //=======================================================================
448 //function : createBoxSideTriangles
449 //purpose  :
450 //=======================================================================
451 void AIS_ViewCube::createBoxSideTriangles (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
452                                            Standard_Integer& theNbNodes,
453                                            Standard_Integer& theNbTris,
454                                            V3d_TypeOfOrientation theDirection) const
455 {
456   const gp_Dir aDir = V3d::GetProjAxis (theDirection);
457   const gp_Pnt aPos = aDir.XYZ() * (mySize * 0.5 + myBoxFacetExtension);
458   const gp_Ax2 aPosition (aPos, aDir.Reversed());
459
460   gp_Ax3 aSystem (aPosition);
461   gp_Trsf aTrsf;
462   aTrsf.SetTransformation (aSystem, gp_Ax3());
463
464   createRoundRectangleTriangles (theTris, theNbNodes, theNbTris,
465                                  gp_XY (mySize, mySize), myRoundRadius * mySize, aTrsf);
466 }
467
468 //=======================================================================
469 //function : createBoxEdgeTriangles
470 //purpose  :
471 //=======================================================================
472 void AIS_ViewCube::createBoxEdgeTriangles (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
473                                            Standard_Integer& theNbNodes,
474                                            Standard_Integer& theNbTris,
475                                            V3d_TypeOfOrientation theDirection) const
476 {
477   const Standard_Real aThickness = Max (myBoxFacetExtension * gp_XY (1.0, 1.0).Modulus() - myBoxEdgeGap, myBoxEdgeMinSize);
478
479   const gp_Dir aDir = V3d::GetProjAxis (theDirection);
480   const gp_Pnt aPos = aDir.XYZ() * (mySize * 0.5 * gp_XY (1.0, 1.0).Modulus() + myBoxFacetExtension * Cos (M_PI_4));
481   const gp_Ax2 aPosition (aPos, aDir.Reversed());
482
483   gp_Ax3 aSystem (aPosition);
484   gp_Trsf aTrsf;
485   aTrsf.SetTransformation (aSystem, gp_Ax3());
486
487   createRoundRectangleTriangles (theTris, theNbNodes, theNbTris,
488                                  gp_XY (aThickness, mySize), myRoundRadius * mySize, aTrsf);
489 }
490
491 //=======================================================================
492 //function : createBoxCornerTriangles
493 //purpose  :
494 //=======================================================================
495 void AIS_ViewCube::createBoxCornerTriangles (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
496                                              Standard_Integer& theNbNodes,
497                                              Standard_Integer& theNbTris,
498                                              V3d_TypeOfOrientation theDir) const
499 {
500   const Standard_Real aHSize = mySize * 0.5;
501   const gp_Dir aDir = V3d::GetProjAxis (theDir);
502   const gp_XYZ aHSizeDir = aDir.XYZ() * (aHSize * gp_Vec (1.0, 1.0, 1.0).Magnitude());
503   const Standard_Integer aVertFirst = !theTris.IsNull() ? theTris->VertexNumber() : 0;
504   if (myRoundRadius > 0.0)
505   {
506     theNbNodes += THE_NB_DISK_SLICES + 1;
507     theNbTris  += THE_NB_DISK_SLICES + 1;
508     if (theTris.IsNull())
509     {
510       return;
511     }
512
513     const Standard_Real anEdgeHWidth = myBoxFacetExtension * gp_XY (1.0, 1.0).Modulus() * 0.5;
514     const Standard_Real aHeight = anEdgeHWidth * Sqrt (2.0 / 3.0); // tetrahedron height
515     const gp_Pnt aPos = aDir.XYZ() * (aHSize * gp_Vec (1.0, 1.0, 1.0).Magnitude() + aHeight);
516     const gp_Ax2 aPosition (aPos, aDir.Reversed());
517     gp_Ax3 aSystem (aPosition);
518     gp_Trsf aTrsf;
519     aTrsf.SetTransformation (aSystem, gp_Ax3());
520     const Standard_Real aRadius = Max (myBoxFacetExtension * 0.5 / Cos (M_PI_4), myCornerMinSize);
521
522     theTris->AddVertex (gp_Pnt (0.0, 0.0, 0.0).Transformed (aTrsf));
523     for (Standard_Integer aNodeIter = 0; aNodeIter < THE_NB_DISK_SLICES; ++aNodeIter)
524     {
525       const Standard_Real anAngle = NCollection_Lerp<Standard_Real>::Interpolate (2.0 * M_PI, 0.0, Standard_Real(aNodeIter) / Standard_Real(THE_NB_DISK_SLICES));
526       theTris->AddVertex (gp_Pnt (aRadius * Cos (anAngle), aRadius * Sin (anAngle), 0.0).Transformed (aTrsf));
527     }
528     theTris->AddTriangleFanEdges (aVertFirst + 1, theTris->VertexNumber(), true);
529   }
530   else
531   {
532     theNbNodes += 3;
533     theNbTris  += 1;
534     if (theTris.IsNull())
535     {
536       return;
537     }
538
539     theTris->AddVertex (aHSizeDir + myBoxFacetExtension * gp_Dir (aDir.X(), 0.0, 0.0).XYZ());
540     theTris->AddVertex (aHSizeDir + myBoxFacetExtension * gp_Dir (0.0, aDir.Y(), 0.0).XYZ());
541     theTris->AddVertex (aHSizeDir + myBoxFacetExtension * gp_Dir (0.0, 0.0, aDir.Z()).XYZ());
542
543     const gp_XYZ aNode1 = theTris->Vertice (aVertFirst + 1).XYZ();
544     const gp_XYZ aNode2 = theTris->Vertice (aVertFirst + 2).XYZ();
545     const gp_XYZ aNode3 = theTris->Vertice (aVertFirst + 3).XYZ();
546     const gp_XYZ aNormTri = ((aNode2 - aNode1).Crossed (aNode3 - aNode1));
547     if (aNormTri.Dot (aDir.XYZ()) < 0.0)
548     {
549       theTris->AddTriangleEdges (aVertFirst + 1, aVertFirst + 3, aVertFirst + 2);
550     }
551     else
552     {
553       theTris->AddTriangleEdges (aVertFirst + 1, aVertFirst + 2, aVertFirst + 3);
554     }
555   }
556
557   for (Standard_Integer aVertIter = aVertFirst + 1; aVertIter <= theTris->VertexNumber(); ++aVertIter)
558   {
559     theTris->SetVertexNormal (aVertIter, aDir);
560   }
561 }
562
563 //=======================================================================
564 //function : Compute
565 //purpose  :
566 //=======================================================================
567 void AIS_ViewCube::Compute (const Handle(PrsMgr_PresentationManager3d)& ,
568                             const Handle(Prs3d_Presentation)& thePrs,
569                             const Standard_Integer theMode)
570 {
571   thePrs->SetInfiniteState (true);
572   if (theMode != 0)
573   {
574     return;
575   }
576
577   const gp_Pnt aLocation = (mySize * 0.5 + myBoxFacetExtension + myAxesPadding) * gp_XYZ (-1.0, -1.0, -1.0);
578
579   // Display axes
580   if (myToDisplayAxes)
581   {
582     const Standard_Real anAxisSize = mySize + 2.0 * myBoxFacetExtension + myAxesPadding;
583     const Handle(Prs3d_DatumAspect)& aDatumAspect = myDrawer->DatumAspect();
584     for (Standard_Integer anAxisIter = Prs3d_DP_XAxis; anAxisIter <= Prs3d_DP_ZAxis; ++anAxisIter)
585     {
586       const Prs3d_DatumParts aPart = (Prs3d_DatumParts )anAxisIter;
587       if (!aDatumAspect->DrawDatumPart (aPart))
588       {
589         continue;
590       }
591
592       gp_Ax1 anAx1;
593       switch (aPart)
594       {
595         case Prs3d_DP_XAxis: anAx1 = gp_Ax1 (aLocation, gp::DX()); break;
596         case Prs3d_DP_YAxis: anAx1 = gp_Ax1 (aLocation, gp::DY()); break;
597         case Prs3d_DP_ZAxis: anAx1 = gp_Ax1 (aLocation, gp::DZ()); break;
598         default: break;
599       }
600
601       Handle(Graphic3d_Group) anAxisGroup = thePrs->NewGroup();
602       anAxisGroup->SetGroupPrimitivesAspect (aDatumAspect->ShadingAspect (aPart)->Aspect());
603
604       const Standard_Real anArrowLength = 0.2 * anAxisSize;
605       Handle(Graphic3d_ArrayOfTriangles) aTriangleArray = Prs3d_Arrow::DrawShaded (anAx1, myAxesRadius, anAxisSize, myAxesConeRadius, anArrowLength, THE_NB_ARROW_FACETTES);
606       anAxisGroup->AddPrimitiveArray (aTriangleArray);
607
608       TCollection_AsciiString anAxisLabel;
609       if (aDatumAspect->ToDrawLabels()
610       &&  myAxesLabels.Find (aPart, anAxisLabel)
611       && !anAxisLabel.IsEmpty())
612       {
613         Handle(Graphic3d_Group) anAxisLabelGroup = thePrs->NewGroup();
614         gp_Pnt aTextOrigin = anAx1.Location().Translated (gp_Vec (anAx1.Direction().X() * (anAxisSize + anArrowLength),
615                                                                   anAx1.Direction().Y() * (anAxisSize + anArrowLength),
616                                                                   anAx1.Direction().Z() * (anAxisSize + anArrowLength)));
617         Prs3d_Text::Draw (anAxisLabelGroup, aDatumAspect->TextAspect(), TCollection_ExtendedString (anAxisLabel), aTextOrigin);
618       }
619     }
620
621     // Display center
622     {
623       Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
624       Handle(Prs3d_ShadingAspect) anAspectCen = new Prs3d_ShadingAspect();
625       anAspectCen->SetColor (Quantity_NOC_WHITE);
626       aGroup->SetGroupPrimitivesAspect (anAspectCen->Aspect());
627       Prs3d_ToolSphere aTool (myAxesSphereRadius, THE_NB_DISK_SLICES, THE_NB_DISK_SLICES);
628       gp_Trsf aTrsf;
629       aTrsf.SetTranslation (gp_Vec (gp::Origin(), aLocation));
630       Handle(Graphic3d_ArrayOfTriangles) aCenterArray;
631       aTool.FillArray (aCenterArray, aTrsf);
632       aGroup->AddPrimitiveArray (aCenterArray);
633     }
634   }
635
636   // Display box sides
637   {
638     Standard_Integer aNbNodes = 0, aNbTris = 0;
639     for (Standard_Integer aPartIter = V3d_Xpos; aPartIter <= Standard_Integer(V3d_Zneg); ++aPartIter)
640     {
641       createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, (V3d_TypeOfOrientation )aPartIter);
642     }
643     if (aNbNodes > 0)
644     {
645       Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbTris * 3, Graphic3d_ArrayFlags_VertexNormal);
646       Handle(Graphic3d_ArrayOfSegments) aSegs;
647       if (myDrawer->FaceBoundaryDraw())
648       {
649         aSegs = new Graphic3d_ArrayOfSegments (aNbNodes, aNbNodes * 2, Graphic3d_ArrayFlags_None);
650       }
651       aNbNodes = aNbTris = 0;
652       for (Standard_Integer aPartIter = V3d_Xpos; aPartIter <= Standard_Integer(V3d_Zneg); ++aPartIter)
653       {
654         Standard_Integer aTriNodesFrom = aTris->VertexNumber();
655         const Standard_Integer aTriFrom = aNbTris;
656         createBoxPartTriangles (aTris, aNbNodes, aNbTris, (V3d_TypeOfOrientation )aPartIter);
657         if (aSegs.IsNull())
658         {
659           continue;
660         }
661
662         const Standard_Integer aFirstNode = aSegs->VertexNumber();
663         for (Standard_Integer aVertIter = (aNbTris - aTriFrom) > 2 ? aTriNodesFrom + 2 : aTriNodesFrom + 1; // skip triangle fan center
664              aVertIter <= aTris->VertexNumber(); ++aVertIter)
665         {
666           aSegs->AddVertex (aTris->Vertice (aVertIter));
667         }
668         aSegs->AddPolylineEdges (aFirstNode + 1, aSegs->VertexNumber(), true);
669       }
670
671       {
672         Handle(Graphic3d_Group) aGroupSides = thePrs->NewGroup();
673         aGroupSides->SetClosed (true); // should be replaced by forced back-face culling aspect
674         aGroupSides->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
675         aGroupSides->AddPrimitiveArray (aTris);
676       }
677
678       if (!aSegs.IsNull())
679       {
680         Handle(Graphic3d_Group) aGroupSegs = thePrs->NewGroup();
681         aGroupSegs->SetGroupPrimitivesAspect (myDrawer->FaceBoundaryAspect()->Aspect());
682         aGroupSegs->AddPrimitiveArray (aSegs);
683       }
684     }
685
686     // Display box sides labels
687     Handle(Graphic3d_Group) aTextGroup = thePrs->NewGroup();
688     aTextGroup->SetGroupPrimitivesAspect (myDrawer->TextAspect()->Aspect());
689     for (Standard_Integer aPartIter = V3d_Xpos; aPartIter <= Standard_Integer(V3d_Zneg); ++aPartIter)
690     {
691       const V3d_TypeOfOrientation anOrient = (V3d_TypeOfOrientation )aPartIter;
692
693       TCollection_AsciiString aLabel;
694       if (!myBoxSideLabels.Find (anOrient, aLabel)
695         || aLabel.IsEmpty())
696       {
697         continue;
698       }
699
700       const gp_Dir aDir = V3d::GetProjAxis (anOrient);
701       gp_Dir anUp = myIsYup ? gp::DY() : gp::DZ();
702       if (myIsYup)
703       {
704         if (anOrient == V3d_Ypos
705           || anOrient == V3d_Yneg)
706         {
707           anUp = -gp::DZ();
708         }
709       }
710       else
711       {
712         if (anOrient == V3d_Zpos)
713         {
714           anUp = gp::DY();
715         }
716         else if (anOrient == V3d_Zneg)
717         {
718           anUp = -gp::DY();
719         }
720       }
721
722       const Standard_Real anOffset = 2.0; // extra offset to avoid overlapping with triangulation
723       const gp_Pnt aPos = aDir.XYZ() * (mySize * 0.5 + myBoxFacetExtension + anOffset);
724       const gp_Ax2 aPosition (aPos, aDir, anUp.Crossed (aDir));
725
726       Handle(Graphic3d_Text) aText = new Graphic3d_Text ((Standard_ShortReal)myDrawer->TextAspect()->Height());
727       aText->SetText (aLabel);
728       aText->SetOrientation (aPosition);
729       aText->SetOwnAnchorPoint (false);
730       aText->SetHorizontalAlignment(myDrawer->TextAspect()->HorizontalJustification());
731       aText->SetVerticalAlignment  (myDrawer->TextAspect()->VerticalJustification());
732       aTextGroup->AddText (aText);
733     }
734   }
735
736   // Display box edges
737   {
738     Standard_Integer aNbNodes = 0, aNbTris = 0;
739     for (Standard_Integer aPartIter = V3d_XposYpos; aPartIter <= Standard_Integer(V3d_YposZneg); ++aPartIter)
740     {
741       createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, (V3d_TypeOfOrientation )aPartIter);
742     }
743     if (aNbNodes > 0)
744     {
745       Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbTris * 3, Graphic3d_ArrayFlags_VertexNormal);
746       aNbNodes = aNbTris = 0;
747       for (Standard_Integer aPartIter = V3d_XposYpos; aPartIter <= Standard_Integer(V3d_YposZneg); ++aPartIter)
748       {
749         const V3d_TypeOfOrientation anOrient = (V3d_TypeOfOrientation )aPartIter;
750         createBoxPartTriangles (aTris, aNbNodes, aNbTris, anOrient);
751       }
752
753       Handle(Graphic3d_Group) aGroupEdges = thePrs->NewGroup();
754       aGroupEdges->SetClosed (true);
755       aGroupEdges->SetGroupPrimitivesAspect (myBoxEdgeAspect->Aspect());
756       aGroupEdges->AddPrimitiveArray (aTris);
757     }
758   }
759
760   // Display box corners
761   {
762     Standard_Integer aNbNodes = 0, aNbTris = 0;
763     for (Standard_Integer aPartIter = V3d_XposYposZpos; aPartIter <= Standard_Integer(V3d_XnegYnegZneg); ++aPartIter)
764     {
765       createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, (V3d_TypeOfOrientation )aPartIter);
766     }
767     if (aNbNodes > 0)
768     {
769       Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbTris * 3, Graphic3d_ArrayFlags_VertexNormal);
770       aNbNodes = aNbTris = 0;
771       for (Standard_Integer aPartIter = V3d_XposYposZpos; aPartIter <= Standard_Integer(V3d_XnegYnegZneg); ++aPartIter)
772       {
773         const V3d_TypeOfOrientation anOrient = (V3d_TypeOfOrientation )aPartIter;
774         createBoxPartTriangles (aTris, aNbNodes, aNbTris, anOrient);
775       }
776
777       Handle(Graphic3d_Group) aGroupCorners = thePrs->NewGroup();
778       aGroupCorners->SetClosed (true);
779       aGroupCorners->SetGroupPrimitivesAspect (myBoxCornerAspect->Aspect());
780       aGroupCorners->AddPrimitiveArray (aTris);
781     }
782   }
783 }
784
785 //=======================================================================
786 //function : ComputeSelection
787 //purpose  :
788 //=======================================================================
789 void AIS_ViewCube::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
790                                      const Standard_Integer theMode)
791 {
792   if (theMode != 0)
793   {
794     return;
795   }
796
797   for (Standard_Integer aPartIter = 0; aPartIter <= Standard_Integer(V3d_XnegYnegZneg); ++aPartIter)
798   {
799     const V3d_TypeOfOrientation anOri = (V3d_TypeOfOrientation )aPartIter;
800     Standard_Integer aNbNodes = 0, aNbTris = 0;
801     createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, anOri);
802     if (aNbNodes <= 0)
803     {
804       continue;
805     }
806
807     Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbTris * 3, Graphic3d_ArrayFlags_None);
808     aNbNodes = aNbTris = 0;
809     createBoxPartTriangles (aTris, aNbNodes, aNbTris, anOri);
810
811     Standard_Integer aSensitivity = 2;
812     if (IsBoxCorner (anOri))
813     {
814       aSensitivity = 8;
815     }
816     else if (IsBoxEdge (anOri))
817     {
818       aSensitivity = 4;
819     }
820     Handle(AIS_ViewCubeOwner) anOwner = new AIS_ViewCubeOwner (this, anOri);
821     Handle(AIS_ViewCubeSensitive) aTriSens = new AIS_ViewCubeSensitive (anOwner, aTris);
822     aTriSens->SetSensitivityFactor (aSensitivity);
823     theSelection->Add (aTriSens);
824   }
825 }
826
827 //=======================================================================
828 //function : HasAnimation
829 //purpose  :
830 //=======================================================================
831 Standard_Boolean AIS_ViewCube::HasAnimation() const
832 {
833   return !myViewAnimation->IsStopped();
834 }
835
836 //=======================================================================
837 //function : viewFitAll
838 //purpose  :
839 //=======================================================================
840 void AIS_ViewCube::viewFitAll (const Handle(V3d_View)& theView,
841                                const Handle(Graphic3d_Camera)& theCamera)
842 {
843   Bnd_Box aBndBox = myToFitSelected ? GetContext()->BoundingBoxOfSelection() : theView->View()->MinMaxValues();
844   if (aBndBox.IsVoid()
845    && myToFitSelected)
846   {
847     aBndBox = theView->View()->MinMaxValues();
848   }
849   if (!aBndBox.IsVoid())
850   {
851     theView->FitMinMax (theCamera, aBndBox, 0.01, 10.0 * Precision::Confusion());
852   }
853 }
854
855 //=======================================================================
856 //function : StartAnimation
857 //purpose  :
858 //=======================================================================
859 void AIS_ViewCube::StartAnimation (const Handle(AIS_ViewCubeOwner)& theOwner)
860 {
861   Handle(V3d_View) aView = GetContext()->LastActiveView();
862   if (theOwner.IsNull()
863    || aView.IsNull())
864   {
865     return;
866   }
867
868   myStartState->Copy (aView->Camera());
869   myEndState  ->Copy (aView->Camera());
870
871   {
872     {
873       Handle(Graphic3d_Camera) aBackupCamera = aView->Camera();
874       const bool wasImmediateUpdate = aView->SetImmediateUpdate (false);
875       aView->SetCamera (myEndState);
876       aView->SetProj (theOwner->MainOrientation(), myIsYup);
877       aView->SetCamera (aBackupCamera);
878       aView->SetImmediateUpdate (wasImmediateUpdate);
879     }
880
881     const gp_Dir aNewDir = myEndState->Direction();
882     if (!myToResetCameraUp
883      && !aNewDir.IsEqual (myStartState->Direction(), Precision::Angular()))
884     {
885       // find the Up direction closest to current instead of default one
886       const gp_Ax1 aNewDirAx1 (gp::Origin(), aNewDir);
887       const gp_Dir anOldUp = myStartState->Up();
888       const gp_Dir anUpList[4] =
889       {
890         myEndState->Up(),
891         myEndState->Up().Rotated (aNewDirAx1, M_PI_2),
892         myEndState->Up().Rotated (aNewDirAx1, M_PI),
893         myEndState->Up().Rotated (aNewDirAx1, M_PI * 1.5),
894       };
895
896       Standard_Real aBestAngle = Precision::Infinite();
897       gp_Dir anUpBest;
898       for (Standard_Integer anUpIter = 0; anUpIter < 4; ++anUpIter)
899       {
900         Standard_Real anAngle = anUpList[anUpIter].Angle (anOldUp);
901         if (aBestAngle > anAngle)
902         {
903           aBestAngle = anAngle;
904           anUpBest = anUpList[anUpIter];
905         }
906       }
907       myEndState->SetUp (anUpBest);
908     }
909
910     viewFitAll (aView, myEndState);
911   }
912
913   myViewAnimation->SetView (aView);
914   myViewAnimation->SetCameraStart (myStartState);
915   myViewAnimation->SetCameraEnd   (myEndState);
916   myViewAnimation->SetOwnDuration (myDuration);
917   myViewAnimation->StartTimer (0.0, 1.0, true, false);
918 }
919
920 //=======================================================================
921 //function : updateAnimation
922 //purpose  :
923 //=======================================================================
924 Standard_Boolean AIS_ViewCube::updateAnimation()
925 {
926   const Standard_Real aPts = myViewAnimation->UpdateTimer();
927   if (aPts >= myDuration)
928   {
929     myViewAnimation->Stop();
930     onAnimationFinished();
931     myViewAnimation->SetView (Handle(V3d_View)());
932     return Standard_False;
933   }
934   return Standard_True;
935 }
936
937 //=======================================================================
938 //function : UpdateAnimation
939 //purpose  :
940 //=======================================================================
941 Standard_Boolean AIS_ViewCube::UpdateAnimation (const Standard_Boolean theToUpdate)
942 {
943   Handle(V3d_View) aView = myViewAnimation->View();
944   if (!HasAnimation()
945    || !updateAnimation())
946   {
947     return Standard_False;
948   }
949
950   if (theToUpdate
951   && !aView.IsNull())
952   {
953     aView->IsInvalidated() ? aView->Redraw() : aView->RedrawImmediate();
954   }
955
956   onAfterAnimation();
957   return Standard_True;
958 }
959
960 //=======================================================================
961 //function : HandleClick
962 //purpose  :
963 //=======================================================================
964 void AIS_ViewCube::HandleClick (const Handle(AIS_ViewCubeOwner)& theOwner)
965 {
966   if (!myToAutoStartAnim)
967   {
968     return;
969   }
970
971   StartAnimation (theOwner);
972   if (!myIsFixedAnimation)
973   {
974     return;
975   }
976   for (; HasAnimation(); )
977   {
978     UpdateAnimation (true);
979   }
980 }
981
982 //=======================================================================
983 //function : HilightOwnerWithColor
984 //purpose  :
985 //=======================================================================
986 void AIS_ViewCube::HilightOwnerWithColor (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
987                                           const Handle(Prs3d_Drawer)& theStyle,
988                                           const Handle(SelectMgr_EntityOwner)& theOwner)
989 {
990   if (theOwner.IsNull()
991   || !thePrsMgr->IsImmediateModeOn())
992   {
993     return;
994   }
995
996   const Graphic3d_ZLayerId aLayer = theStyle->ZLayer() != Graphic3d_ZLayerId_UNKNOWN ? theStyle->ZLayer() : myDrawer->ZLayer();
997   const AIS_ViewCubeOwner* aCubeOwner = dynamic_cast<AIS_ViewCubeOwner* >(theOwner.get());
998
999   Handle(Prs3d_Presentation) aHiPrs = GetHilightPresentation (thePrsMgr);
1000   aHiPrs->Clear();
1001   aHiPrs->CStructure()->ViewAffinity = thePrsMgr->StructureManager()->ObjectAffinity (Handle(Standard_Transient)(this));
1002   aHiPrs->SetTransformPersistence (TransformPersistence());
1003   aHiPrs->SetZLayer (aLayer);
1004
1005   {
1006     Handle(Graphic3d_Group) aGroup = aHiPrs->NewGroup();
1007     aGroup->SetGroupPrimitivesAspect (theStyle->ShadingAspect()->Aspect());
1008     Standard_Integer aNbNodes = 0, aNbTris = 0;
1009     createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, aCubeOwner->MainOrientation());
1010     if (aNbNodes > 0)
1011     {
1012       Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbTris * 3, Graphic3d_ArrayFlags_None);
1013       aNbNodes = aNbTris = 0;
1014       createBoxPartTriangles (aTris, aNbNodes, aNbTris, aCubeOwner->MainOrientation());
1015       aGroup->AddPrimitiveArray (aTris);
1016     }
1017   }
1018
1019   if (thePrsMgr->IsImmediateModeOn())
1020   {
1021     thePrsMgr->AddToImmediateList (aHiPrs);
1022   }
1023 }
1024
1025 //=======================================================================
1026 //function : HilightSelected
1027 //purpose  :
1028 //=======================================================================
1029 void AIS_ViewCube::HilightSelected (const Handle(PrsMgr_PresentationManager3d)& ,
1030                                     const SelectMgr_SequenceOfOwner& theSeq)
1031 {
1032   // this method should never be called since AIS_InteractiveObject::HandleClick() has been overridden
1033   if (theSeq.Size() == 1)
1034   {
1035     //HandleClick (Handle(AIS_ViewCubeOwner)::DownCast (theSeq.First()));
1036   }
1037 }