1 // Created on: 2017-07-25
2 // Created by: Anastasia BOBYLEVA
3 // Copyright (c) 2017-2019 OPEN CASCADE SAS
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #include <AIS_ViewCube.hxx>
18 #include <AIS_AnimationCamera.hxx>
19 #include <AIS_InteractiveContext.hxx>
21 #include <Graphic3d_ViewAffinity.hxx>
22 #include <NCollection_Lerp.hxx>
24 #include <Prs3d_Arrow.hxx>
25 #include <Prs3d_DatumAspect.hxx>
26 #include <Prs3d_Root.hxx>
27 #include <Prs3d_Text.hxx>
28 #include <Prs3d_ToolDisk.hxx>
29 #include <Prs3d_ToolSphere.hxx>
30 #include <Select3D_SensitivePrimitiveArray.hxx>
31 #include <SelectMgr_SequenceOfOwner.hxx>
33 #include <V3d_View.hxx>
35 IMPLEMENT_STANDARD_RTTIEXT(AIS_ViewCube, AIS_InteractiveObject)
36 IMPLEMENT_STANDARD_RTTIEXT(AIS_ViewCubeOwner, SelectMgr_EntityOwner)
40 static const Standard_Integer THE_NB_ROUND_SPLITS = 8;
41 static const Standard_Integer THE_NB_DISK_SLICES = 20;
42 static const Standard_Integer THE_NB_ARROW_FACETTES = 20;
44 //! Return the number of non-zero components.
45 static Standard_Integer nbDirectionComponents (const gp_Dir& theDir)
47 Standard_Integer aNbComps = 0;
48 for (Standard_Integer aCompIter = 1; aCompIter <= 3; ++aCompIter)
50 if (Abs (theDir.Coord (aCompIter)) > gp::Resolution())
59 //! Simple sensitive element for picking by point only.
60 class AIS_ViewCubeSensitive : public Select3D_SensitivePrimitiveArray
62 DEFINE_STANDARD_RTTI_INLINE(AIS_ViewCubeSensitive, Select3D_SensitivePrimitiveArray)
65 AIS_ViewCubeSensitive (const Handle(SelectMgr_EntityOwner)& theOwner,
66 const Handle(Graphic3d_ArrayOfTriangles)& theTris)
67 : Select3D_SensitivePrimitiveArray (theOwner)
69 InitTriangulation (theTris->Attributes(), theTris->Indices(), TopLoc_Location());
72 //! Checks whether element overlaps current selecting volume.
73 virtual Standard_Boolean Matches (SelectBasics_SelectingVolumeManager& theMgr,
74 SelectBasics_PickResult& thePickResult) Standard_OVERRIDE
76 return isValidRay (theMgr)
77 && Select3D_SensitivePrimitiveArray::Matches (theMgr, thePickResult);
80 //! Checks if picking ray can be used for detection.
81 bool isValidRay (const SelectBasics_SelectingVolumeManager& theMgr) const
83 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
85 // disallow rectangular selection
89 if (AIS_ViewCubeOwner* anOwner = dynamic_cast<AIS_ViewCubeOwner* >(myOwnerId.get()))
91 const Standard_Real anAngleToler = 10.0 * M_PI / 180.0;
92 const gp_Vec aRay (theMgr.GetNearPickedPnt(), theMgr.GetFarPickedPnt());
93 const gp_Dir aDir = V3d::GetProjAxis (anOwner->MainOrientation());
94 return !aRay.IsNormal (aDir, anAngleToler);
100 //=======================================================================
101 //function : IsBoxSide
103 //=======================================================================
104 bool AIS_ViewCube::IsBoxSide (V3d_TypeOfOrientation theOrient)
106 return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 1;
109 //=======================================================================
110 //function : IsBoxEdge
112 //=======================================================================
113 bool AIS_ViewCube::IsBoxEdge (V3d_TypeOfOrientation theOrient)
115 return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 2;
118 //=======================================================================
119 //function : IsBoxCorner
121 //=======================================================================
122 bool AIS_ViewCube::IsBoxCorner (V3d_TypeOfOrientation theOrient)
124 return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 3;
127 //=======================================================================
128 //function : AIS_ViewCube
130 //=======================================================================
131 AIS_ViewCube::AIS_ViewCube()
132 : myBoxEdgeAspect (new Prs3d_ShadingAspect()),
133 myBoxCornerAspect (new Prs3d_ShadingAspect()),
135 myBoxEdgeMinSize (2.0),
137 myBoxFacetExtension (1.0),
139 myCornerMinSize (2.0),
141 myToDisplayAxes (true),
142 myToDisplayEdges (true),
143 myToDisplayVertices (true),
145 myViewAnimation (new AIS_AnimationCamera ("AIS_ViewCube", Handle(V3d_View)())),
146 myStartState(new Graphic3d_Camera()),
147 myEndState (new Graphic3d_Camera()),
149 myToAutoStartAnim (true),
150 myIsFixedAnimation (true),
151 myToFitSelected (true),
152 myToResetCameraUp (false)
154 myInfiniteState = true;
156 myDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
157 myTransformPersistence = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_LEFT_LOWER, Graphic3d_Vec2i (100, 100));
159 myDrawer->SetTextAspect (new Prs3d_TextAspect());
160 myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
162 myDynHilightDrawer = new Prs3d_Drawer();
163 myDynHilightDrawer->SetLink (myDrawer);
164 myDynHilightDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
166 setDefaultAttributes();
167 setDefaultHighlightAttributes();
169 // setup default labels
170 myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Front, "FRONT");
171 myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Back, "BACK");
172 myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Top, "TOP");
173 myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Bottom, "BOTTOM");
174 myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Left, "LEFT");
175 myBoxSideLabels.Bind (V3d_TypeOfOrientation_Zup_Right, "RIGHT");
177 myAxesLabels.Bind (Prs3d_DP_XAxis, "X");
178 myAxesLabels.Bind (Prs3d_DP_YAxis, "Y");
179 myAxesLabels.Bind (Prs3d_DP_ZAxis, "Z");
181 // define default size
185 //=======================================================================
186 //function : setDefaultAttributes
188 //=======================================================================
189 void AIS_ViewCube::setDefaultAttributes()
191 myDrawer->TextAspect()->SetHorizontalJustification(Graphic3d_HTA_CENTER);
192 myDrawer->TextAspect()->SetVerticalJustification (Graphic3d_VTA_CENTER);
193 myDrawer->TextAspect()->SetColor (Quantity_NOC_BLACK);
194 myDrawer->TextAspect()->SetFont (Font_NOF_SANS_SERIF);
195 myDrawer->TextAspect()->SetHeight (16.0);
196 // this should be forced back-face culling regardless Closed flag
197 myDrawer->TextAspect()->Aspect()->SetSuppressBackFaces (true);
199 Graphic3d_MaterialAspect aMat (Graphic3d_NOM_UserDefined);
200 aMat.SetColor (Quantity_NOC_WHITE);
201 aMat.SetAmbientColor (Quantity_NOC_GRAY60);
203 const Handle(Graphic3d_AspectFillArea3d)& aShading = myDrawer->ShadingAspect()->Aspect();
204 aShading->SetInteriorStyle (Aspect_IS_SOLID);
205 // this should be forced back-face culling regardless Closed flag
206 aShading->SetSuppressBackFaces (true);
207 aShading->SetInteriorColor (aMat.Color());
208 aShading->SetFrontMaterial (aMat);
209 myDrawer->SetFaceBoundaryDraw (false);
211 *myBoxEdgeAspect ->Aspect() = *aShading;
212 myBoxEdgeAspect->SetColor (Quantity_NOC_GRAY30);
213 *myBoxCornerAspect->Aspect() = *aShading;
214 myBoxCornerAspect->SetColor (Quantity_NOC_GRAY30);
217 //=======================================================================
218 //function : setDefaultHighlightAttributes
220 //=======================================================================
221 void AIS_ViewCube::setDefaultHighlightAttributes()
223 Graphic3d_MaterialAspect aHighlightMaterial;
224 aHighlightMaterial.SetReflectionModeOff (Graphic3d_TOR_AMBIENT);
225 aHighlightMaterial.SetReflectionModeOff (Graphic3d_TOR_DIFFUSE);
226 aHighlightMaterial.SetReflectionModeOff (Graphic3d_TOR_SPECULAR);
227 aHighlightMaterial.SetReflectionModeOff (Graphic3d_TOR_EMISSION);
228 aHighlightMaterial.SetMaterialType (Graphic3d_MATERIAL_ASPECT);
229 myDynHilightDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
230 myDynHilightDrawer->ShadingAspect()->SetMaterial (aHighlightMaterial);
231 myDynHilightDrawer->ShadingAspect()->SetColor (Quantity_NOC_CYAN1);
232 myDynHilightDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
233 myDynHilightDrawer->SetColor (Quantity_NOC_CYAN1);
236 //=======================================================================
239 //=======================================================================
240 void AIS_ViewCube::SetYup (Standard_Boolean theIsYup,
241 Standard_Boolean theToUpdateLabels)
243 if (myIsYup == theIsYup)
250 static const V3d_TypeOfOrientation THE_ZUP_ORI_LIST[6] =
252 V3d_TypeOfOrientation_Zup_Front, V3d_TypeOfOrientation_Zup_Back,
253 V3d_TypeOfOrientation_Zup_Top, V3d_TypeOfOrientation_Zup_Bottom,
254 V3d_TypeOfOrientation_Zup_Left, V3d_TypeOfOrientation_Zup_Right
256 static const V3d_TypeOfOrientation THE_YUP_ORI_LIST[6] =
258 V3d_TypeOfOrientation_Yup_Front, V3d_TypeOfOrientation_Yup_Back,
259 V3d_TypeOfOrientation_Yup_Top, V3d_TypeOfOrientation_Yup_Bottom,
260 V3d_TypeOfOrientation_Yup_Left, V3d_TypeOfOrientation_Yup_Right
262 if (theToUpdateLabels)
264 NCollection_Array1<TCollection_AsciiString> aLabels (0, 5);
265 for (Standard_Integer aLabelIter = 0; aLabelIter < 6; ++aLabelIter)
267 myBoxSideLabels.Find (!myIsYup ? THE_YUP_ORI_LIST[aLabelIter] : THE_ZUP_ORI_LIST[aLabelIter],
268 aLabels.ChangeValue (aLabelIter));
270 for (Standard_Integer aLabelIter = 0; aLabelIter < 6; ++aLabelIter)
272 myBoxSideLabels.Bind (myIsYup ? THE_YUP_ORI_LIST[aLabelIter] : THE_ZUP_ORI_LIST[aLabelIter],
273 aLabels.Value (aLabelIter));
280 //=======================================================================
281 //function : ResetStyles
283 //=======================================================================
284 void AIS_ViewCube::ResetStyles()
287 UnsetHilightAttributes();
289 myBoxEdgeMinSize = 2.0;
290 myCornerMinSize = 2.0;
294 myToDisplayAxes = true;
295 myToDisplayEdges = true;
296 myToDisplayVertices = true;
298 myBoxFacetExtension = 1.0;
303 //=======================================================================
306 //=======================================================================
307 void AIS_ViewCube::SetSize (Standard_Real theValue,
308 Standard_Boolean theToAdaptAnother)
310 const bool isNewSize = Abs (mySize - theValue) > Precision::Confusion();
312 if (theToAdaptAnother)
314 if (myBoxFacetExtension > 0.0)
316 SetBoxFacetExtension (mySize * 0.15);
318 if (myAxesPadding > 0.0)
320 SetAxesPadding (mySize * 0.1);
322 SetFontHeight (mySize * 0.16);
330 //=======================================================================
331 //function : SetRoundRadius
333 //=======================================================================
334 void AIS_ViewCube::SetRoundRadius (const Standard_Real theValue)
336 Standard_OutOfRange_Raise_if (theValue < 0.0 || theValue > 0.5,
337 "AIS_ViewCube::SetRoundRadius(): theValue should be in [0; 0.5]");
338 if (Abs (myRoundRadius - theValue) > Precision::Confusion())
340 myRoundRadius = theValue;
345 //=======================================================================
346 //function : createRoundRectangleTriangles
348 //=======================================================================
349 Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createRoundRectangleTriangles (const gp_XY& theSize,
350 Standard_Real theRadius,
351 const gp_Trsf& theTrsf)
353 const Standard_Real aRadius = Min (theRadius, Min (theSize.X(), theSize.Y()) * 0.5);
354 const gp_XY aHSize (theSize.X() * 0.5 - aRadius, theSize.Y() * 0.5 - aRadius);
355 const gp_Dir aNorm = gp::DZ().Transformed (theTrsf);
356 Handle(Graphic3d_ArrayOfTriangles) aTris;
359 const Standard_Integer aNbNodes = (THE_NB_ROUND_SPLITS + 1) * 4 + 1;
360 aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbNodes * 3, Graphic3d_ArrayFlags_VertexNormal);
362 aTris->AddVertex (gp_Pnt (0.0, 0.0, 0.0).Transformed (theTrsf));
363 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
365 const Standard_Real anAngle = NCollection_Lerp<Standard_Real>::Interpolate (M_PI * 0.5, 0.0, Standard_Real(aNodeIter) / Standard_Real(THE_NB_ROUND_SPLITS));
366 aTris->AddVertex (gp_Pnt (aHSize.X() + aRadius * Cos (anAngle), aHSize.Y() + aRadius * Sin (anAngle), 0.0).Transformed (theTrsf));
368 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
370 const Standard_Real anAngle = NCollection_Lerp<Standard_Real>::Interpolate (0.0, -M_PI * 0.5, Standard_Real(aNodeIter) / Standard_Real(THE_NB_ROUND_SPLITS));
371 aTris->AddVertex (gp_Pnt (aHSize.X() + aRadius * Cos (anAngle), -aHSize.Y() + aRadius * Sin (anAngle), 0.0).Transformed (theTrsf));
373 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
375 const Standard_Real anAngle = NCollection_Lerp<Standard_Real>::Interpolate (-M_PI * 0.5, -M_PI, Standard_Real(aNodeIter) / Standard_Real(THE_NB_ROUND_SPLITS));
376 aTris->AddVertex (gp_Pnt (-aHSize.X() + aRadius * Cos (anAngle), -aHSize.Y() + aRadius * Sin (anAngle), 0.0).Transformed (theTrsf));
378 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
380 const Standard_Real anAngle = NCollection_Lerp<Standard_Real>::Interpolate (-M_PI, -M_PI * 1.5, Standard_Real(aNodeIter) / Standard_Real(THE_NB_ROUND_SPLITS));
381 aTris->AddVertex (gp_Pnt (-aHSize.X() + aRadius * Cos (anAngle), aHSize.Y() + aRadius * Sin (anAngle), 0.0).Transformed (theTrsf));
384 // split triangle fan
385 for (Standard_Integer aNodeIter = 2; aNodeIter <= aTris->VertexNumber(); ++aNodeIter)
388 aTris->AddEdge (aNodeIter - 1);
389 aTris->AddEdge (aNodeIter);
392 aTris->AddEdge (aTris->VertexNumber());
397 aTris = new Graphic3d_ArrayOfTriangles (4, 6, Graphic3d_ArrayFlags_VertexNormal);
398 aTris->AddVertex (gp_Pnt (-aHSize.X(), -aHSize.Y(), 0.0).Transformed (theTrsf));
399 aTris->AddVertex (gp_Pnt (-aHSize.X(), aHSize.Y(), 0.0).Transformed (theTrsf));
400 aTris->AddVertex (gp_Pnt ( aHSize.X(), aHSize.Y(), 0.0).Transformed (theTrsf));
401 aTris->AddVertex (gp_Pnt ( aHSize.X(), -aHSize.Y(), 0.0).Transformed (theTrsf));
402 aTris->AddEdges (3, 1, 2);
403 aTris->AddEdges (1, 3, 4);
406 for (Standard_Integer aVertIter = 1; aVertIter <= aTris->VertexNumber(); ++aVertIter)
408 aTris->SetVertexNormal (aVertIter, -aNorm);
413 //=======================================================================
414 //function : createBoxPartTriangles
416 //=======================================================================
417 Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createBoxPartTriangles (V3d_TypeOfOrientation theDir) const
419 if (IsBoxSide (theDir))
421 return createBoxSideTriangles (theDir);
423 else if (IsBoxEdge (theDir)
426 return createBoxEdgeTriangles (theDir);
428 else if (IsBoxCorner (theDir)
429 && myToDisplayVertices)
431 return createBoxCornerTriangles (theDir);
433 return Handle(Graphic3d_ArrayOfTriangles)();
436 //=======================================================================
437 //function : createBoxSideTriangles
439 //=======================================================================
440 Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createBoxSideTriangles (V3d_TypeOfOrientation theDirection) const
442 const gp_Dir aDir = V3d::GetProjAxis (theDirection);
443 const gp_Pnt aPos = aDir.XYZ() * (mySize * 0.5 + myBoxFacetExtension);
444 const gp_Ax2 aPosition (aPos, aDir.Reversed());
446 gp_Ax3 aSystem (aPosition);
448 aTrsf.SetTransformation (aSystem, gp_Ax3());
450 return createRoundRectangleTriangles (gp_XY (mySize, mySize), myRoundRadius * mySize, aTrsf);
453 //=======================================================================
454 //function : createBoxEdgeTriangles
456 //=======================================================================
457 Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createBoxEdgeTriangles (V3d_TypeOfOrientation theDirection) const
459 const Standard_Real aThickness = Max (myBoxFacetExtension * gp_XY (1.0, 1.0).Modulus() - myBoxEdgeGap, myBoxEdgeMinSize);
461 const gp_Dir aDir = V3d::GetProjAxis (theDirection);
462 const gp_Pnt aPos = aDir.XYZ() * (mySize * 0.5 * gp_XY (1.0, 1.0).Modulus() + myBoxFacetExtension * Cos (M_PI_4));
463 const gp_Ax2 aPosition (aPos, aDir.Reversed());
465 gp_Ax3 aSystem (aPosition);
467 aTrsf.SetTransformation (aSystem, gp_Ax3());
469 return createRoundRectangleTriangles (gp_XY (aThickness, mySize), myRoundRadius * mySize, aTrsf);
472 //=======================================================================
473 //function : createBoxCornerTriangles
475 //=======================================================================
476 Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createBoxCornerTriangles (V3d_TypeOfOrientation theDir) const
478 const Standard_Real aHSize = mySize * 0.5;
479 const gp_Dir aDir = V3d::GetProjAxis (theDir);
480 const gp_XYZ aHSizeDir = aDir.XYZ() * (aHSize * gp_Vec (1.0, 1.0, 1.0).Magnitude());
481 if (myRoundRadius > 0.0)
483 const Standard_Real anEdgeHWidth = myBoxFacetExtension * gp_XY (1.0, 1.0).Modulus() * 0.5;
484 const Standard_Real aHeight = anEdgeHWidth * Sqrt (2.0 / 3.0); // tetrahedron height
485 const gp_Pnt aPos = aDir.XYZ() * (aHSize * gp_Vec (1.0, 1.0, 1.0).Magnitude() + aHeight);
486 const gp_Ax2 aPosition (aPos, aDir.Reversed());
487 gp_Ax3 aSystem (aPosition);
489 aTrsf.SetTransformation (aSystem, gp_Ax3());
490 const Standard_Real aRadius = Max (myBoxFacetExtension * 0.5 / Cos (M_PI_4), myCornerMinSize);
491 return Prs3d_ToolDisk::Create (0.0, aRadius, THE_NB_DISK_SLICES, 1, aTrsf);
494 Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (3, 3, Graphic3d_ArrayFlags_VertexNormal);
496 aTris->AddVertex (aHSizeDir + myBoxFacetExtension * gp_Dir (aDir.X(), 0.0, 0.0).XYZ());
497 aTris->AddVertex (aHSizeDir + myBoxFacetExtension * gp_Dir (0.0, aDir.Y(), 0.0).XYZ());
498 aTris->AddVertex (aHSizeDir + myBoxFacetExtension * gp_Dir (0.0, 0.0, aDir.Z()).XYZ());
500 const gp_XYZ aNode1 = aTris->Vertice (1).XYZ();
501 const gp_XYZ aNode2 = aTris->Vertice (2).XYZ();
502 const gp_XYZ aNode3 = aTris->Vertice (3).XYZ();
503 const gp_XYZ aNormTri = ((aNode2 - aNode1).Crossed (aNode3 - aNode1));
504 if (aNormTri.Dot (aDir.XYZ()) < 0.0)
506 aTris->AddEdges (1, 3, 2);
510 aTris->AddEdges (1, 2, 3);
513 for (Standard_Integer aVertIter = 1; aVertIter <= aTris->VertexNumber(); ++aVertIter)
515 aTris->SetVertexNormal (aVertIter, aDir);
520 //=======================================================================
523 //=======================================================================
524 void AIS_ViewCube::Compute (const Handle(PrsMgr_PresentationManager3d)& ,
525 const Handle(Prs3d_Presentation)& thePrs,
526 const Standard_Integer theMode)
528 thePrs->SetInfiniteState (true);
534 const gp_Pnt aLocation = (mySize * 0.5 + myBoxFacetExtension + myAxesPadding) * gp_XYZ (-1.0, -1.0, -1.0);
539 const Standard_Real anAxisSize = mySize + 2.0 * myBoxFacetExtension + myAxesPadding;
540 const Handle(Prs3d_DatumAspect)& aDatumAspect = myDrawer->DatumAspect();
541 for (Standard_Integer anAxisIter = Prs3d_DP_XAxis; anAxisIter <= Prs3d_DP_ZAxis; ++anAxisIter)
543 const Prs3d_DatumParts aPart = (Prs3d_DatumParts )anAxisIter;
544 if (!aDatumAspect->DrawDatumPart (aPart))
552 case Prs3d_DP_XAxis: anAx1 = gp_Ax1 (aLocation, gp::DX()); break;
553 case Prs3d_DP_YAxis: anAx1 = gp_Ax1 (aLocation, gp::DY()); break;
554 case Prs3d_DP_ZAxis: anAx1 = gp_Ax1 (aLocation, gp::DZ()); break;
558 Handle(Graphic3d_Group) anAxisGroup = thePrs->NewGroup();
559 anAxisGroup->SetGroupPrimitivesAspect (aDatumAspect->ShadingAspect (aPart)->Aspect());
561 const Standard_Real anArrowLength = 0.2 * anAxisSize;
562 Handle(Graphic3d_ArrayOfTriangles) aTriangleArray = Prs3d_Arrow::DrawShaded (anAx1, 1.0, anAxisSize, 3.0, anArrowLength, THE_NB_ARROW_FACETTES);
563 anAxisGroup->AddPrimitiveArray (aTriangleArray);
565 TCollection_AsciiString anAxisLabel;
566 if (aDatumAspect->ToDrawLabels()
567 && myAxesLabels.Find (aPart, anAxisLabel)
568 && !anAxisLabel.IsEmpty())
570 Handle(Graphic3d_Group) anAxisLabelGroup = thePrs->NewGroup();
571 gp_Pnt aTextOrigin = anAx1.Location().Translated (gp_Vec (anAx1.Direction().X() * (anAxisSize + anArrowLength),
572 anAx1.Direction().Y() * (anAxisSize + anArrowLength),
573 anAx1.Direction().Z() * (anAxisSize + anArrowLength)));
574 Prs3d_Text::Draw (anAxisLabelGroup, aDatumAspect->TextAspect(), TCollection_ExtendedString (anAxisLabel), aTextOrigin);
580 Handle(Graphic3d_Group) aGroup = thePrs->NewGroup();
581 Handle(Prs3d_ShadingAspect) anAspectCen = new Prs3d_ShadingAspect();
582 anAspectCen->SetColor (Quantity_NOC_WHITE);
583 aGroup->SetGroupPrimitivesAspect (anAspectCen->Aspect());
584 Prs3d_ToolSphere aTool (4.0, THE_NB_DISK_SLICES, THE_NB_DISK_SLICES);
586 aTrsf.SetTranslation (gp_Vec (gp::Origin(), aLocation));
587 Handle(Graphic3d_ArrayOfTriangles) aCenterArray;
588 aTool.FillArray (aCenterArray, aTrsf);
589 aGroup->AddPrimitiveArray (aCenterArray);
595 Handle(Graphic3d_Group) aGroupSides = thePrs->NewGroup(), aGroupEdges = thePrs->NewGroup(), aGroupCorners = thePrs->NewGroup();
596 aGroupSides->SetClosed (true); // should be replaced by forced back-face culling aspect
597 aGroupSides->SetGroupPrimitivesAspect (myDrawer->ShadingAspect()->Aspect());
599 aGroupEdges->SetClosed (true);
600 aGroupEdges->SetGroupPrimitivesAspect (myBoxEdgeAspect->Aspect());
602 aGroupCorners->SetClosed (true);
603 aGroupCorners->SetGroupPrimitivesAspect (myBoxCornerAspect->Aspect());
605 Handle(Graphic3d_Group) aTextGroup = thePrs->NewGroup();
606 //aTextGroup->SetClosed (true);
607 aTextGroup->SetGroupPrimitivesAspect (myDrawer->TextAspect()->Aspect());
608 for (Standard_Integer aPartIter = 0; aPartIter <= Standard_Integer(V3d_XnegYnegZneg); ++aPartIter)
610 const V3d_TypeOfOrientation anOrient = (V3d_TypeOfOrientation )aPartIter;
611 if (Handle(Graphic3d_ArrayOfTriangles) aTris = createBoxPartTriangles (anOrient))
613 if (IsBoxSide (anOrient))
615 aGroupSides->AddPrimitiveArray (aTris);
617 TCollection_AsciiString aLabel;
618 if (!myBoxSideLabels.Find (anOrient, aLabel)
624 const gp_Dir aDir = V3d::GetProjAxis (anOrient);
625 gp_Dir anUp = myIsYup ? gp::DY() : gp::DZ();
628 if (anOrient == V3d_Ypos
629 || anOrient == V3d_Yneg)
636 if (anOrient == V3d_Zpos)
640 else if (anOrient == V3d_Zneg)
646 const Standard_Real anOffset = 2.0; // extra offset to avoid overlapping with triangulation
647 const gp_Pnt aPos = aDir.XYZ() * (mySize * 0.5 + myBoxFacetExtension + anOffset);
648 const gp_Ax2 aPosition (aPos, aDir, anUp.Crossed (aDir));
649 Prs3d_Text::Draw (aTextGroup, myDrawer->TextAspect(), aLabel, aPosition);
651 else if (IsBoxEdge (anOrient))
653 aGroupEdges->AddPrimitiveArray (aTris);
655 else if (IsBoxCorner (anOrient))
657 aGroupCorners->AddPrimitiveArray (aTris);
664 //=======================================================================
665 //function : ComputeSelection
667 //=======================================================================
668 void AIS_ViewCube::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
669 const Standard_Integer theMode)
676 for (Standard_Integer aPartIter = 0; aPartIter <= Standard_Integer(V3d_XnegYnegZneg); ++aPartIter)
678 const V3d_TypeOfOrientation anOri = (V3d_TypeOfOrientation )aPartIter;
679 if (Handle(Graphic3d_ArrayOfTriangles) aTris = createBoxPartTriangles (anOri))
681 Standard_Integer aSensitivity = 2;
682 if (IsBoxCorner (anOri))
686 else if (IsBoxEdge (anOri))
690 Handle(AIS_ViewCubeOwner) anOwner = new AIS_ViewCubeOwner (this, anOri);
691 Handle(AIS_ViewCubeSensitive) aTriSens = new AIS_ViewCubeSensitive (anOwner, aTris);
692 aTriSens->SetSensitivityFactor (aSensitivity);
693 theSelection->Add (aTriSens);
698 //=======================================================================
699 //function : HasAnimation
701 //=======================================================================
702 Standard_Boolean AIS_ViewCube::HasAnimation() const
704 return !myViewAnimation->IsStopped();
707 //=======================================================================
708 //function : StartAnimation
710 //=======================================================================
711 void AIS_ViewCube::StartAnimation (const Handle(AIS_ViewCubeOwner)& theOwner)
713 Handle(V3d_View) aView = GetContext()->LastActiveView();
714 if (theOwner.IsNull()
720 myStartState->Copy (aView->Camera());
721 myEndState ->Copy (aView->Camera());
724 Handle(Graphic3d_Camera) aBackupCamera = new Graphic3d_Camera (aView->Camera());
726 const bool wasImmediateUpdate = aView->SetImmediateUpdate (false);
727 aView->SetCamera (myEndState);
728 aView->SetProj (theOwner->MainOrientation(), myIsYup);
730 const gp_Dir aNewDir = aView->Camera()->Direction();
731 if (!myToResetCameraUp
732 && !aNewDir.IsEqual (aBackupCamera->Direction(), Precision::Angular()))
734 // find the Up direction closest to current instead of default one
735 const gp_Ax1 aNewDirAx1 (gp::Origin(), aNewDir);
736 const gp_Dir anOldUp = aBackupCamera->Up();
737 const gp_Dir anUpList[4] =
739 aView->Camera()->Up(),
740 aView->Camera()->Up().Rotated (aNewDirAx1, M_PI_2),
741 aView->Camera()->Up().Rotated (aNewDirAx1, M_PI),
742 aView->Camera()->Up().Rotated (aNewDirAx1, M_PI * 1.5),
745 Standard_Real aBestAngle = Precision::Infinite();
747 for (Standard_Integer anUpIter = 0; anUpIter < 4; ++anUpIter)
749 Standard_Real anAngle = anUpList[anUpIter].Angle (anOldUp);
750 if (aBestAngle > anAngle)
752 aBestAngle = anAngle;
753 anUpBest = anUpList[anUpIter];
756 aView->Camera()->SetUp (anUpBest);
759 const Bnd_Box aBndSelected = myToFitSelected ? GetContext()->BoundingBoxOfSelection() : Bnd_Box();
760 if (!aBndSelected.IsVoid())
762 aView->FitAll (aBndSelected, 0.01, false);
766 aView->FitAll (0.01, false);
768 aView->SetCamera (aBackupCamera);
769 aView->SetImmediateUpdate (wasImmediateUpdate);
772 myViewAnimation->SetView (aView);
773 myViewAnimation->SetCameraStart (myStartState);
774 myViewAnimation->SetCameraEnd (myEndState);
775 myViewAnimation->SetOwnDuration (myDuration);
776 myViewAnimation->StartTimer (0.0, 1.0, true, false);
779 //=======================================================================
780 //function : updateAnimation
782 //=======================================================================
783 Standard_Boolean AIS_ViewCube::updateAnimation()
785 const Standard_Real aPts = myViewAnimation->UpdateTimer();
786 if (aPts >= myDuration)
788 myViewAnimation->Stop();
789 onAnimationFinished();
790 myViewAnimation->SetView (Handle(V3d_View)());
791 return Standard_False;
793 return Standard_True;
796 //=======================================================================
797 //function : UpdateAnimation
799 //=======================================================================
800 Standard_Boolean AIS_ViewCube::UpdateAnimation (const Standard_Boolean theToUpdate)
802 Handle(V3d_View) aView = myViewAnimation->View();
804 || !updateAnimation())
806 return Standard_False;
812 aView->IsInvalidated() ? aView->Redraw() : aView->RedrawImmediate();
816 return Standard_True;
819 //=======================================================================
820 //function : HandleClick
822 //=======================================================================
823 void AIS_ViewCube::HandleClick (const Handle(AIS_ViewCubeOwner)& theOwner)
825 if (!myToAutoStartAnim)
830 StartAnimation (theOwner);
831 if (!myIsFixedAnimation)
835 for (; HasAnimation(); )
837 UpdateAnimation (true);
841 //=======================================================================
842 //function : HilightOwnerWithColor
844 //=======================================================================
845 void AIS_ViewCube::HilightOwnerWithColor (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
846 const Handle(Prs3d_Drawer)& theStyle,
847 const Handle(SelectMgr_EntityOwner)& theOwner)
849 if (theOwner.IsNull()
850 || !thePrsMgr->IsImmediateModeOn())
855 const Graphic3d_ZLayerId aLayer = theStyle->ZLayer() != Graphic3d_ZLayerId_UNKNOWN ? theStyle->ZLayer() : myDrawer->ZLayer();
856 const AIS_ViewCubeOwner* aCubeOwner = dynamic_cast<AIS_ViewCubeOwner* >(theOwner.get());
858 Handle(Prs3d_Presentation) aHiPrs = GetHilightPresentation (thePrsMgr);
860 aHiPrs->CStructure()->ViewAffinity = thePrsMgr->StructureManager()->ObjectAffinity (Handle(Standard_Transient)(this));
861 aHiPrs->SetTransformPersistence (TransformPersistence());
862 aHiPrs->SetZLayer (aLayer);
865 Handle(Graphic3d_Group) aGroup = aHiPrs->NewGroup();
866 aGroup->SetGroupPrimitivesAspect (theStyle->ShadingAspect()->Aspect());
867 if (Handle(Graphic3d_ArrayOfTriangles) aTris = createBoxPartTriangles (aCubeOwner->MainOrientation()))
869 aGroup->AddPrimitiveArray (aTris);
873 if (thePrsMgr->IsImmediateModeOn())
875 thePrsMgr->AddToImmediateList (aHiPrs);
879 //=======================================================================
880 //function : HilightSelected
882 //=======================================================================
883 void AIS_ViewCube::HilightSelected (const Handle(PrsMgr_PresentationManager3d)& ,
884 const SelectMgr_SequenceOfOwner& theSeq)
886 // this method should never be called since AIS_InteractiveObject::HandleClick() has been overridden
887 if (theSeq.Size() == 1)
889 //HandleClick (Handle(AIS_ViewCubeOwner)::DownCast (theSeq.First()));