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 <Graphic3d_Text.hxx>
23 #include <NCollection_Lerp.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>
34 #include <V3d_View.hxx>
36 IMPLEMENT_STANDARD_RTTIEXT(AIS_ViewCube, AIS_InteractiveObject)
37 IMPLEMENT_STANDARD_RTTIEXT(AIS_ViewCubeOwner, SelectMgr_EntityOwner)
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;
45 //! Return the number of non-zero components.
46 static Standard_Integer nbDirectionComponents (const gp_Dir& theDir)
48 Standard_Integer aNbComps = 0;
49 for (Standard_Integer aCompIter = 1; aCompIter <= 3; ++aCompIter)
51 if (Abs (theDir.Coord (aCompIter)) > gp::Resolution())
60 //! Simple sensitive element for picking by point only.
61 class AIS_ViewCubeSensitive : public Select3D_SensitivePrimitiveArray
63 DEFINE_STANDARD_RTTI_INLINE(AIS_ViewCubeSensitive, Select3D_SensitivePrimitiveArray)
66 AIS_ViewCubeSensitive (const Handle(SelectMgr_EntityOwner)& theOwner,
67 const Handle(Graphic3d_ArrayOfTriangles)& theTris)
68 : Select3D_SensitivePrimitiveArray (theOwner)
70 InitTriangulation (theTris->Attributes(), theTris->Indices(), TopLoc_Location());
73 //! Checks whether element overlaps current selecting volume.
74 virtual Standard_Boolean Matches (SelectBasics_SelectingVolumeManager& theMgr,
75 SelectBasics_PickResult& thePickResult) Standard_OVERRIDE
77 return isValidRay (theMgr)
78 && Select3D_SensitivePrimitiveArray::Matches (theMgr, thePickResult);
81 //! Checks if picking ray can be used for detection.
82 bool isValidRay (const SelectBasics_SelectingVolumeManager& theMgr) const
84 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
86 // disallow rectangular selection
90 if (AIS_ViewCubeOwner* anOwner = dynamic_cast<AIS_ViewCubeOwner* >(myOwnerId.get()))
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);
101 //=======================================================================
102 //function : IsBoxSide
104 //=======================================================================
105 bool AIS_ViewCube::IsBoxSide (V3d_TypeOfOrientation theOrient)
107 return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 1;
110 //=======================================================================
111 //function : IsBoxEdge
113 //=======================================================================
114 bool AIS_ViewCube::IsBoxEdge (V3d_TypeOfOrientation theOrient)
116 return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 2;
119 //=======================================================================
120 //function : IsBoxCorner
122 //=======================================================================
123 bool AIS_ViewCube::IsBoxCorner (V3d_TypeOfOrientation theOrient)
125 return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 3;
128 //=======================================================================
129 //function : AIS_ViewCube
131 //=======================================================================
132 AIS_ViewCube::AIS_ViewCube()
133 : myBoxEdgeAspect (new Prs3d_ShadingAspect()),
134 myBoxCornerAspect (new Prs3d_ShadingAspect()),
136 myBoxEdgeMinSize (2.0),
138 myBoxFacetExtension (1.0),
141 myAxesConeRadius (3.0),
142 myAxesSphereRadius (4.0),
143 myCornerMinSize (2.0),
145 myToDisplayAxes (true),
146 myToDisplayEdges (true),
147 myToDisplayVertices (true),
149 myViewAnimation (new AIS_AnimationCamera ("AIS_ViewCube", Handle(V3d_View)())),
150 myStartState(new Graphic3d_Camera()),
151 myEndState (new Graphic3d_Camera()),
152 myToAutoStartAnim (true),
153 myIsFixedAnimation (true),
154 myToFitSelected (true),
155 myToResetCameraUp (false)
157 myViewAnimation->SetOwnDuration (0.5);
158 myInfiniteState = true;
160 myDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
161 myTransformPersistence = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_LEFT_LOWER, Graphic3d_Vec2i (100, 100));
163 myDrawer->SetTextAspect (new Prs3d_TextAspect());
164 myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
166 myDynHilightDrawer = new Prs3d_Drawer();
167 myDynHilightDrawer->SetLink (myDrawer);
168 myDynHilightDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
170 setDefaultAttributes();
171 setDefaultHighlightAttributes();
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");
181 myAxesLabels.Bind (Prs3d_DP_XAxis, "X");
182 myAxesLabels.Bind (Prs3d_DP_YAxis, "Y");
183 myAxesLabels.Bind (Prs3d_DP_ZAxis, "Z");
185 // define default size
189 //=======================================================================
190 //function : setDefaultAttributes
192 //=======================================================================
193 void AIS_ViewCube::setDefaultAttributes()
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);
204 Graphic3d_MaterialAspect aMat (Graphic3d_NOM_UserDefined);
205 aMat.SetColor (Quantity_NOC_WHITE);
206 aMat.SetAmbientColor (Quantity_NOC_GRAY60);
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);
216 *myBoxEdgeAspect ->Aspect() = *aShading;
217 myBoxEdgeAspect->SetColor (Quantity_NOC_GRAY30);
218 *myBoxCornerAspect->Aspect() = *aShading;
219 myBoxCornerAspect->SetColor (Quantity_NOC_GRAY30);
222 //=======================================================================
223 //function : setDefaultHighlightAttributes
225 //=======================================================================
226 void AIS_ViewCube::setDefaultHighlightAttributes()
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);
241 //=======================================================================
244 //=======================================================================
245 void AIS_ViewCube::SetYup (Standard_Boolean theIsYup,
246 Standard_Boolean theToUpdateLabels)
248 if (myIsYup == theIsYup)
255 static const V3d_TypeOfOrientation THE_ZUP_ORI_LIST[6] =
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
261 static const V3d_TypeOfOrientation THE_YUP_ORI_LIST[6] =
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
267 if (theToUpdateLabels)
269 NCollection_Array1<TCollection_AsciiString> aLabels (0, 5);
270 for (Standard_Integer aLabelIter = 0; aLabelIter < 6; ++aLabelIter)
272 myBoxSideLabels.Find (!myIsYup ? THE_YUP_ORI_LIST[aLabelIter] : THE_ZUP_ORI_LIST[aLabelIter],
273 aLabels.ChangeValue (aLabelIter));
275 for (Standard_Integer aLabelIter = 0; aLabelIter < 6; ++aLabelIter)
277 myBoxSideLabels.Bind (myIsYup ? THE_YUP_ORI_LIST[aLabelIter] : THE_ZUP_ORI_LIST[aLabelIter],
278 aLabels.Value (aLabelIter));
285 //=======================================================================
286 //function : ResetStyles
288 //=======================================================================
289 void AIS_ViewCube::ResetStyles()
292 UnsetHilightAttributes();
294 myBoxEdgeMinSize = 2.0;
295 myCornerMinSize = 2.0;
299 myToDisplayAxes = true;
300 myToDisplayEdges = true;
301 myToDisplayVertices = true;
303 myBoxFacetExtension = 1.0;
308 //=======================================================================
311 //=======================================================================
312 void AIS_ViewCube::SetSize (Standard_Real theValue,
313 Standard_Boolean theToAdaptAnother)
315 const bool isNewSize = Abs (mySize - theValue) > Precision::Confusion();
317 if (theToAdaptAnother)
319 if (myBoxFacetExtension > 0.0)
321 SetBoxFacetExtension (mySize * 0.15);
323 if (myAxesPadding > 0.0)
325 SetAxesPadding (mySize * 0.1);
327 SetFontHeight (mySize * 0.16);
335 //=======================================================================
336 //function : SetRoundRadius
338 //=======================================================================
339 void AIS_ViewCube::SetRoundRadius (const Standard_Real theValue)
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())
345 myRoundRadius = theValue;
350 //=======================================================================
351 //function : createRoundRectangleTriangles
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)
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;
367 const Standard_Integer aNbNodes = (THE_NB_ROUND_SPLITS + 1) * 4 + 1;
368 theNbNodes += aNbNodes;
369 theNbTris += aNbNodes;
370 if (theTris.IsNull())
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)
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));
381 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
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));
386 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
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));
391 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
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));
397 // split triangle fan
398 theTris->AddTriangleFanEdges (aVertFirst + 1, theTris->VertexNumber(), true);
404 if (theTris.IsNull())
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);
416 for (Standard_Integer aVertIter = aVertFirst + 1; aVertIter <= theTris->VertexNumber(); ++aVertIter)
418 theTris->SetVertexNormal (aVertIter, -aNorm);
422 //=======================================================================
423 //function : createBoxPartTriangles
425 //=======================================================================
426 void AIS_ViewCube::createBoxPartTriangles (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
427 Standard_Integer& theNbNodes,
428 Standard_Integer& theNbTris,
429 V3d_TypeOfOrientation theDir) const
431 if (IsBoxSide (theDir))
433 createBoxSideTriangles (theTris, theNbNodes, theNbTris, theDir);
435 else if (IsBoxEdge (theDir)
438 createBoxEdgeTriangles (theTris, theNbNodes, theNbTris, theDir);
440 else if (IsBoxCorner (theDir)
441 && myToDisplayVertices)
443 createBoxCornerTriangles (theTris, theNbNodes, theNbTris, theDir);
447 //=======================================================================
448 //function : createBoxSideTriangles
450 //=======================================================================
451 void AIS_ViewCube::createBoxSideTriangles (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
452 Standard_Integer& theNbNodes,
453 Standard_Integer& theNbTris,
454 V3d_TypeOfOrientation theDirection) const
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());
460 gp_Ax3 aSystem (aPosition);
462 aTrsf.SetTransformation (aSystem, gp_Ax3());
464 createRoundRectangleTriangles (theTris, theNbNodes, theNbTris,
465 gp_XY (mySize, mySize), myRoundRadius * mySize, aTrsf);
468 //=======================================================================
469 //function : createBoxEdgeTriangles
471 //=======================================================================
472 void AIS_ViewCube::createBoxEdgeTriangles (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
473 Standard_Integer& theNbNodes,
474 Standard_Integer& theNbTris,
475 V3d_TypeOfOrientation theDirection) const
477 const Standard_Real aThickness = Max (myBoxFacetExtension * gp_XY (1.0, 1.0).Modulus() - myBoxEdgeGap, myBoxEdgeMinSize);
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());
483 gp_Ax3 aSystem (aPosition);
485 aTrsf.SetTransformation (aSystem, gp_Ax3());
487 createRoundRectangleTriangles (theTris, theNbNodes, theNbTris,
488 gp_XY (aThickness, mySize), myRoundRadius * mySize, aTrsf);
491 //=======================================================================
492 //function : createBoxCornerTriangles
494 //=======================================================================
495 void AIS_ViewCube::createBoxCornerTriangles (const Handle(Graphic3d_ArrayOfTriangles)& theTris,
496 Standard_Integer& theNbNodes,
497 Standard_Integer& theNbTris,
498 V3d_TypeOfOrientation theDir) const
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)
506 theNbNodes += THE_NB_DISK_SLICES + 1;
507 theNbTris += THE_NB_DISK_SLICES + 1;
508 if (theTris.IsNull())
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);
519 aTrsf.SetTransformation (aSystem, gp_Ax3());
520 const Standard_Real aRadius = Max (myBoxFacetExtension * 0.5 / Cos (M_PI_4), myCornerMinSize);
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)
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));
528 theTris->AddTriangleFanEdges (aVertFirst + 1, theTris->VertexNumber(), true);
534 if (theTris.IsNull())
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());
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)
549 theTris->AddTriangleEdges (aVertFirst + 1, aVertFirst + 3, aVertFirst + 2);
553 theTris->AddTriangleEdges (aVertFirst + 1, aVertFirst + 2, aVertFirst + 3);
557 for (Standard_Integer aVertIter = aVertFirst + 1; aVertIter <= theTris->VertexNumber(); ++aVertIter)
559 theTris->SetVertexNormal (aVertIter, aDir);
563 //=======================================================================
566 //=======================================================================
567 void AIS_ViewCube::Compute (const Handle(PrsMgr_PresentationManager3d)& ,
568 const Handle(Prs3d_Presentation)& thePrs,
569 const Standard_Integer theMode)
571 thePrs->SetInfiniteState (true);
577 const gp_Pnt aLocation = (mySize * 0.5 + myBoxFacetExtension + myAxesPadding) * gp_XYZ (-1.0, -1.0, -1.0);
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)
586 const Prs3d_DatumParts aPart = (Prs3d_DatumParts )anAxisIter;
587 if (!aDatumAspect->DrawDatumPart (aPart))
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;
601 Handle(Graphic3d_Group) anAxisGroup = thePrs->NewGroup();
602 anAxisGroup->SetGroupPrimitivesAspect (aDatumAspect->ShadingAspect (aPart)->Aspect());
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);
608 TCollection_AsciiString anAxisLabel;
609 if (aDatumAspect->ToDrawLabels()
610 && myAxesLabels.Find (aPart, anAxisLabel)
611 && !anAxisLabel.IsEmpty())
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);
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);
629 aTrsf.SetTranslation (gp_Vec (gp::Origin(), aLocation));
630 Handle(Graphic3d_ArrayOfTriangles) aCenterArray;
631 aTool.FillArray (aCenterArray, aTrsf);
632 aGroup->AddPrimitiveArray (aCenterArray);
638 Standard_Integer aNbNodes = 0, aNbTris = 0;
639 for (Standard_Integer aPartIter = V3d_Xpos; aPartIter <= Standard_Integer(V3d_Zneg); ++aPartIter)
641 createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, (V3d_TypeOfOrientation )aPartIter);
645 Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbTris * 3, Graphic3d_ArrayFlags_VertexNormal);
646 Handle(Graphic3d_ArrayOfSegments) aSegs;
647 if (myDrawer->FaceBoundaryDraw())
649 aSegs = new Graphic3d_ArrayOfSegments (aNbNodes, aNbNodes * 2, Graphic3d_ArrayFlags_None);
651 aNbNodes = aNbTris = 0;
652 for (Standard_Integer aPartIter = V3d_Xpos; aPartIter <= Standard_Integer(V3d_Zneg); ++aPartIter)
654 Standard_Integer aTriNodesFrom = aTris->VertexNumber();
655 const Standard_Integer aTriFrom = aNbTris;
656 createBoxPartTriangles (aTris, aNbNodes, aNbTris, (V3d_TypeOfOrientation )aPartIter);
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)
666 aSegs->AddVertex (aTris->Vertice (aVertIter));
668 aSegs->AddPolylineEdges (aFirstNode + 1, aSegs->VertexNumber(), true);
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);
680 Handle(Graphic3d_Group) aGroupSegs = thePrs->NewGroup();
681 aGroupSegs->SetGroupPrimitivesAspect (myDrawer->FaceBoundaryAspect()->Aspect());
682 aGroupSegs->AddPrimitiveArray (aSegs);
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)
691 const V3d_TypeOfOrientation anOrient = (V3d_TypeOfOrientation )aPartIter;
693 TCollection_AsciiString aLabel;
694 if (!myBoxSideLabels.Find (anOrient, aLabel)
700 const gp_Dir aDir = V3d::GetProjAxis (anOrient);
701 gp_Dir anUp = myIsYup ? gp::DY() : gp::DZ();
704 if (anOrient == V3d_Ypos
705 || anOrient == V3d_Yneg)
712 if (anOrient == V3d_Zpos)
716 else if (anOrient == V3d_Zneg)
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));
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);
738 Standard_Integer aNbNodes = 0, aNbTris = 0;
739 for (Standard_Integer aPartIter = V3d_XposYpos; aPartIter <= Standard_Integer(V3d_YposZneg); ++aPartIter)
741 createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, (V3d_TypeOfOrientation )aPartIter);
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)
749 const V3d_TypeOfOrientation anOrient = (V3d_TypeOfOrientation )aPartIter;
750 createBoxPartTriangles (aTris, aNbNodes, aNbTris, anOrient);
753 Handle(Graphic3d_Group) aGroupEdges = thePrs->NewGroup();
754 aGroupEdges->SetClosed (true);
755 aGroupEdges->SetGroupPrimitivesAspect (myBoxEdgeAspect->Aspect());
756 aGroupEdges->AddPrimitiveArray (aTris);
760 // Display box corners
762 Standard_Integer aNbNodes = 0, aNbTris = 0;
763 for (Standard_Integer aPartIter = V3d_XposYposZpos; aPartIter <= Standard_Integer(V3d_XnegYnegZneg); ++aPartIter)
765 createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, (V3d_TypeOfOrientation )aPartIter);
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)
773 const V3d_TypeOfOrientation anOrient = (V3d_TypeOfOrientation )aPartIter;
774 createBoxPartTriangles (aTris, aNbNodes, aNbTris, anOrient);
777 Handle(Graphic3d_Group) aGroupCorners = thePrs->NewGroup();
778 aGroupCorners->SetClosed (true);
779 aGroupCorners->SetGroupPrimitivesAspect (myBoxCornerAspect->Aspect());
780 aGroupCorners->AddPrimitiveArray (aTris);
785 //=======================================================================
786 //function : ComputeSelection
788 //=======================================================================
789 void AIS_ViewCube::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
790 const Standard_Integer theMode)
797 for (Standard_Integer aPartIter = 0; aPartIter <= Standard_Integer(V3d_XnegYnegZneg); ++aPartIter)
799 const V3d_TypeOfOrientation anOri = (V3d_TypeOfOrientation )aPartIter;
800 Standard_Integer aNbNodes = 0, aNbTris = 0;
801 createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, anOri);
807 Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbTris * 3, Graphic3d_ArrayFlags_None);
808 aNbNodes = aNbTris = 0;
809 createBoxPartTriangles (aTris, aNbNodes, aNbTris, anOri);
811 Standard_Integer aSensitivity = 2;
812 if (IsBoxCorner (anOri))
816 else if (IsBoxEdge (anOri))
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);
827 //=======================================================================
828 //function : Duration
830 //=======================================================================
831 Standard_Real AIS_ViewCube::Duration() const
833 return myViewAnimation->OwnDuration();
836 //=======================================================================
837 //function : SetDuration
839 //=======================================================================
840 void AIS_ViewCube::SetDuration (Standard_Real theDurationSec)
842 myViewAnimation->SetOwnDuration (theDurationSec);
845 //=======================================================================
846 //function : HasAnimation
848 //=======================================================================
849 Standard_Boolean AIS_ViewCube::HasAnimation() const
851 return !myViewAnimation->IsStopped();
854 //=======================================================================
855 //function : viewFitAll
857 //=======================================================================
858 void AIS_ViewCube::viewFitAll (const Handle(V3d_View)& theView,
859 const Handle(Graphic3d_Camera)& theCamera)
861 Bnd_Box aBndBox = myToFitSelected ? GetContext()->BoundingBoxOfSelection() : theView->View()->MinMaxValues();
865 aBndBox = theView->View()->MinMaxValues();
867 if (!aBndBox.IsVoid())
869 theView->FitMinMax (theCamera, aBndBox, 0.01, 10.0 * Precision::Confusion());
873 //=======================================================================
874 //function : StartAnimation
876 //=======================================================================
877 void AIS_ViewCube::StartAnimation (const Handle(AIS_ViewCubeOwner)& theOwner)
879 Handle(V3d_View) aView = GetContext()->LastActiveView();
880 if (theOwner.IsNull()
886 myStartState->Copy (aView->Camera());
887 myEndState ->Copy (aView->Camera());
891 Handle(Graphic3d_Camera) aBackupCamera = aView->Camera();
892 const bool wasImmediateUpdate = aView->SetImmediateUpdate (false);
893 aView->SetCamera (myEndState);
894 aView->SetProj (theOwner->MainOrientation(), myIsYup);
895 aView->SetCamera (aBackupCamera);
896 aView->SetImmediateUpdate (wasImmediateUpdate);
899 const gp_Dir aNewDir = myEndState->Direction();
900 if (!myToResetCameraUp
901 && !aNewDir.IsEqual (myStartState->Direction(), Precision::Angular()))
903 // find the Up direction closest to current instead of default one
904 const gp_Ax1 aNewDirAx1 (gp::Origin(), aNewDir);
905 const gp_Dir anOldUp = myStartState->Up();
906 const gp_Dir anUpList[4] =
909 myEndState->Up().Rotated (aNewDirAx1, M_PI_2),
910 myEndState->Up().Rotated (aNewDirAx1, M_PI),
911 myEndState->Up().Rotated (aNewDirAx1, M_PI * 1.5),
914 Standard_Real aBestAngle = Precision::Infinite();
916 for (Standard_Integer anUpIter = 0; anUpIter < 4; ++anUpIter)
918 Standard_Real anAngle = anUpList[anUpIter].Angle (anOldUp);
919 if (aBestAngle > anAngle)
921 aBestAngle = anAngle;
922 anUpBest = anUpList[anUpIter];
925 myEndState->SetUp (anUpBest);
928 viewFitAll (aView, myEndState);
931 myViewAnimation->SetView (aView);
932 myViewAnimation->SetCameraStart (myStartState);
933 myViewAnimation->SetCameraEnd (myEndState);
934 myViewAnimation->StartTimer (0.0, 1.0, true, false);
937 //=======================================================================
938 //function : updateAnimation
940 //=======================================================================
941 Standard_Boolean AIS_ViewCube::updateAnimation()
943 const Standard_Real aPts = myViewAnimation->UpdateTimer();
944 if (aPts >= myViewAnimation->OwnDuration())
946 myViewAnimation->Stop();
947 onAnimationFinished();
948 myViewAnimation->SetView (Handle(V3d_View)());
949 return Standard_False;
951 return Standard_True;
954 //=======================================================================
955 //function : UpdateAnimation
957 //=======================================================================
958 Standard_Boolean AIS_ViewCube::UpdateAnimation (const Standard_Boolean theToUpdate)
960 Handle(V3d_View) aView = myViewAnimation->View();
962 || !updateAnimation())
964 return Standard_False;
970 aView->IsInvalidated() ? aView->Redraw() : aView->RedrawImmediate();
974 return Standard_True;
977 //=======================================================================
978 //function : HandleClick
980 //=======================================================================
981 void AIS_ViewCube::HandleClick (const Handle(AIS_ViewCubeOwner)& theOwner)
983 if (!myToAutoStartAnim)
988 StartAnimation (theOwner);
989 if (!myIsFixedAnimation)
993 for (; HasAnimation(); )
995 UpdateAnimation (true);
999 //=======================================================================
1000 //function : HilightOwnerWithColor
1002 //=======================================================================
1003 void AIS_ViewCube::HilightOwnerWithColor (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
1004 const Handle(Prs3d_Drawer)& theStyle,
1005 const Handle(SelectMgr_EntityOwner)& theOwner)
1007 if (theOwner.IsNull()
1008 || !thePrsMgr->IsImmediateModeOn())
1013 const Graphic3d_ZLayerId aLayer = theStyle->ZLayer() != Graphic3d_ZLayerId_UNKNOWN ? theStyle->ZLayer() : myDrawer->ZLayer();
1014 const AIS_ViewCubeOwner* aCubeOwner = dynamic_cast<AIS_ViewCubeOwner* >(theOwner.get());
1016 Handle(Prs3d_Presentation) aHiPrs = GetHilightPresentation (thePrsMgr);
1018 aHiPrs->CStructure()->ViewAffinity = thePrsMgr->StructureManager()->ObjectAffinity (Handle(Standard_Transient)(this));
1019 aHiPrs->SetTransformPersistence (TransformPersistence());
1020 aHiPrs->SetZLayer (aLayer);
1023 Handle(Graphic3d_Group) aGroup = aHiPrs->NewGroup();
1024 aGroup->SetGroupPrimitivesAspect (theStyle->ShadingAspect()->Aspect());
1025 Standard_Integer aNbNodes = 0, aNbTris = 0;
1026 createBoxPartTriangles (Handle(Graphic3d_ArrayOfTriangles)(), aNbNodes, aNbTris, aCubeOwner->MainOrientation());
1029 Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbTris * 3, Graphic3d_ArrayFlags_None);
1030 aNbNodes = aNbTris = 0;
1031 createBoxPartTriangles (aTris, aNbNodes, aNbTris, aCubeOwner->MainOrientation());
1032 aGroup->AddPrimitiveArray (aTris);
1036 if (thePrsMgr->IsImmediateModeOn())
1038 thePrsMgr->AddToImmediateList (aHiPrs);
1042 //=======================================================================
1043 //function : HilightSelected
1045 //=======================================================================
1046 void AIS_ViewCube::HilightSelected (const Handle(PrsMgr_PresentationManager3d)& ,
1047 const SelectMgr_SequenceOfOwner& theSeq)
1049 // this method should never be called since AIS_InteractiveObject::HandleClick() has been overridden
1050 if (theSeq.Size() == 1)
1052 //HandleClick (Handle(AIS_ViewCubeOwner)::DownCast (theSeq.First()));