0028954: Visualization - implement interactive object for camera manipulations
[occt.git] / src / AIS / AIS_ViewCube.cxx
CommitLineData
2108d9a2 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 <NCollection_Lerp.hxx>
23#include <Prs3d.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>
32#include <V3d.hxx>
33#include <V3d_View.hxx>
34
35IMPLEMENT_STANDARD_RTTIEXT(AIS_ViewCube, AIS_InteractiveObject)
36IMPLEMENT_STANDARD_RTTIEXT(AIS_ViewCubeOwner, SelectMgr_EntityOwner)
37
38namespace
39{
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;
43
44 //! Return the number of non-zero components.
45 static Standard_Integer nbDirectionComponents (const gp_Dir& theDir)
46 {
47 Standard_Integer aNbComps = 0;
48 for (Standard_Integer aCompIter = 1; aCompIter <= 3; ++aCompIter)
49 {
50 if (Abs (theDir.Coord (aCompIter)) > gp::Resolution())
51 {
52 ++aNbComps;
53 }
54 }
55 return aNbComps;
56 }
57}
58
59//! Simple sensitive element for picking by point only.
60class AIS_ViewCubeSensitive : public Select3D_SensitivePrimitiveArray
61{
62 DEFINE_STANDARD_RTTI_INLINE(AIS_ViewCubeSensitive, Select3D_SensitivePrimitiveArray)
63public:
64 //! Constructor.
65 AIS_ViewCubeSensitive (const Handle(SelectMgr_EntityOwner)& theOwner,
66 const Handle(Graphic3d_ArrayOfTriangles)& theTris)
67 : Select3D_SensitivePrimitiveArray (theOwner)
68 {
69 InitTriangulation (theTris->Attributes(), theTris->Indices(), TopLoc_Location());
70 }
71
72 //! Checks whether element overlaps current selecting volume.
73 virtual Standard_Boolean Matches (SelectBasics_SelectingVolumeManager& theMgr,
74 SelectBasics_PickResult& thePickResult) Standard_OVERRIDE
75 {
76 return isValidRay (theMgr)
77 && Select3D_SensitivePrimitiveArray::Matches (theMgr, thePickResult);
78 }
79
80 //! Checks if picking ray can be used for detection.
81 bool isValidRay (const SelectBasics_SelectingVolumeManager& theMgr) const
82 {
83 if (theMgr.GetActiveSelectionType() != SelectBasics_SelectingVolumeManager::Point)
84 {
85 // disallow rectangular selection
86 return false;
87 }
88
89 if (AIS_ViewCubeOwner* anOwner = dynamic_cast<AIS_ViewCubeOwner* >(myOwnerId.get()))
90 {
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);
95 }
96 return true;
97 }
98};
99
100//=======================================================================
101//function : IsBoxSide
102//purpose :
103//=======================================================================
104bool AIS_ViewCube::IsBoxSide (V3d_TypeOfOrientation theOrient)
105{
106 return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 1;
107}
108
109//=======================================================================
110//function : IsBoxEdge
111//purpose :
112//=======================================================================
113bool AIS_ViewCube::IsBoxEdge (V3d_TypeOfOrientation theOrient)
114{
115 return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 2;
116}
117
118//=======================================================================
119//function : IsBoxCorner
120//purpose :
121//=======================================================================
122bool AIS_ViewCube::IsBoxCorner (V3d_TypeOfOrientation theOrient)
123{
124 return nbDirectionComponents (V3d::GetProjAxis (theOrient)) == 3;
125}
126
127//=======================================================================
128//function : AIS_ViewCube
129//purpose :
130//=======================================================================
131AIS_ViewCube::AIS_ViewCube()
132: myBoxEdgeAspect (new Prs3d_ShadingAspect()),
133 myBoxCornerAspect (new Prs3d_ShadingAspect()),
134 mySize (1.0),
135 myBoxEdgeMinSize (2.0),
136 myBoxEdgeGap (0.0),
137 myBoxFacetExtension (1.0),
138 myAxesPadding (1.0),
139 myCornerMinSize (2.0),
140 myRoundRadius (0.0),
141 myToDisplayAxes (true),
142 myToDisplayEdges (true),
143 myToDisplayVertices (true),
144 myIsYup (false),
145 myViewAnimation (new AIS_AnimationCamera ("AIS_ViewCube", Handle(V3d_View)())),
146 myStartState(new Graphic3d_Camera()),
147 myEndState (new Graphic3d_Camera()),
148 myDuration (0.5),
149 myToAutoStartAnim (true),
150 myIsFixedAnimation (true),
151 myToFitSelected (true),
152 myToResetCameraUp (false)
153{
154 myInfiniteState = true;
155 myIsMutable = true;
156 myDrawer->SetZLayer (Graphic3d_ZLayerId_Topmost);
157 myTransformPersistence = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_LEFT_LOWER, Graphic3d_Vec2i (100, 100));
158
159 myDrawer->SetTextAspect (new Prs3d_TextAspect());
160 myDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
161
162 myDynHilightDrawer = new Prs3d_Drawer();
163 myDynHilightDrawer->SetLink (myDrawer);
164 myDynHilightDrawer->SetShadingAspect (new Prs3d_ShadingAspect());
165
166 setDefaultAttributes();
167 setDefaultHighlightAttributes();
168
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");
176
177 myAxesLabels.Bind (Prs3d_DP_XAxis, "X");
178 myAxesLabels.Bind (Prs3d_DP_YAxis, "Y");
179 myAxesLabels.Bind (Prs3d_DP_ZAxis, "Z");
180
181 // define default size
182 SetSize (70.0);
183}
184
185//=======================================================================
186//function : setDefaultAttributes
187//purpose :
188//=======================================================================
189void AIS_ViewCube::setDefaultAttributes()
190{
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);
198
199 Graphic3d_MaterialAspect aMat (Graphic3d_NOM_UserDefined);
200 aMat.SetColor (Quantity_NOC_WHITE);
201 aMat.SetAmbientColor (Quantity_NOC_GRAY60);
202
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);
210
211 *myBoxEdgeAspect ->Aspect() = *aShading;
212 myBoxEdgeAspect->SetColor (Quantity_NOC_GRAY30);
213 *myBoxCornerAspect->Aspect() = *aShading;
214 myBoxCornerAspect->SetColor (Quantity_NOC_GRAY30);
215}
216
217//=======================================================================
218//function : setDefaultHighlightAttributes
219//purpose :
220//=======================================================================
221void AIS_ViewCube::setDefaultHighlightAttributes()
222{
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);
234}
235
236//=======================================================================
237//function : SetYup
238//purpose :
239//=======================================================================
240void AIS_ViewCube::SetYup (Standard_Boolean theIsYup,
241 Standard_Boolean theToUpdateLabels)
242{
243 if (myIsYup == theIsYup)
244 {
245 return;
246 }
247
248 myIsYup = theIsYup;
249
250 static const V3d_TypeOfOrientation THE_ZUP_ORI_LIST[6] =
251 {
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
255 };
256 static const V3d_TypeOfOrientation THE_YUP_ORI_LIST[6] =
257 {
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
261 };
262 if (theToUpdateLabels)
263 {
264 NCollection_Array1<TCollection_AsciiString> aLabels (0, 5);
265 for (Standard_Integer aLabelIter = 0; aLabelIter < 6; ++aLabelIter)
266 {
267 myBoxSideLabels.Find (!myIsYup ? THE_YUP_ORI_LIST[aLabelIter] : THE_ZUP_ORI_LIST[aLabelIter],
268 aLabels.ChangeValue (aLabelIter));
269 }
270 for (Standard_Integer aLabelIter = 0; aLabelIter < 6; ++aLabelIter)
271 {
272 myBoxSideLabels.Bind (myIsYup ? THE_YUP_ORI_LIST[aLabelIter] : THE_ZUP_ORI_LIST[aLabelIter],
273 aLabels.Value (aLabelIter));
274 }
275 }
276
277 SetToUpdate();
278}
279
280//=======================================================================
281//function : ResetStyles
282//purpose :
283//=======================================================================
284void AIS_ViewCube::ResetStyles()
285{
286 UnsetAttributes();
287 UnsetHilightAttributes();
288
289 myBoxEdgeMinSize = 2.0;
290 myCornerMinSize = 2.0;
291 myBoxEdgeGap = 0.0;
292 myRoundRadius = 0.0;
293
294 myToDisplayAxes = true;
295 myToDisplayEdges = true;
296 myToDisplayVertices = true;
297
298 myBoxFacetExtension = 1.0;
299 myAxesPadding = 1.0;
300 SetSize (70.0);
301}
302
303//=======================================================================
304//function : SetSize
305//purpose :
306//=======================================================================
307void AIS_ViewCube::SetSize (Standard_Real theValue,
308 Standard_Boolean theToAdaptAnother)
309{
310 const bool isNewSize = Abs (mySize - theValue) > Precision::Confusion();
311 mySize = theValue;
312 if (theToAdaptAnother)
313 {
314 if (myBoxFacetExtension > 0.0)
315 {
316 SetBoxFacetExtension (mySize * 0.15);
317 }
318 if (myAxesPadding > 0.0)
319 {
320 SetAxesPadding (mySize * 0.1);
321 }
322 SetFontHeight (mySize * 0.16);
323 }
324 if (isNewSize)
325 {
326 SetToUpdate();
327 }
328}
329
330//=======================================================================
331//function : SetRoundRadius
332//purpose :
333//=======================================================================
334void AIS_ViewCube::SetRoundRadius (const Standard_Real theValue)
335{
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())
339 {
340 myRoundRadius = theValue;
341 SetToUpdate();
342 }
343}
344
345//=======================================================================
346//function : createRoundRectangleTriangles
347//purpose :
348//=======================================================================
349Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createRoundRectangleTriangles (const gp_XY& theSize,
350 Standard_Real theRadius,
351 const gp_Trsf& theTrsf)
352{
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;
357 if (aRadius > 0.0)
358 {
359 const Standard_Integer aNbNodes = (THE_NB_ROUND_SPLITS + 1) * 4 + 1;
360 aTris = new Graphic3d_ArrayOfTriangles (aNbNodes, aNbNodes * 3, Graphic3d_ArrayFlags_VertexNormal);
361
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)
364 {
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));
367 }
368 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
369 {
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));
372 }
373 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
374 {
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));
377 }
378 for (Standard_Integer aNodeIter = 0; aNodeIter <= THE_NB_ROUND_SPLITS; ++aNodeIter)
379 {
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));
382 }
383
384 // split triangle fan
385 for (Standard_Integer aNodeIter = 2; aNodeIter <= aTris->VertexNumber(); ++aNodeIter)
386 {
387 aTris->AddEdge (1);
388 aTris->AddEdge (aNodeIter - 1);
389 aTris->AddEdge (aNodeIter);
390 }
391 aTris->AddEdge (1);
392 aTris->AddEdge (aTris->VertexNumber());
393 aTris->AddEdge (2);
394 }
395 else
396 {
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);
404 }
405
406 for (Standard_Integer aVertIter = 1; aVertIter <= aTris->VertexNumber(); ++aVertIter)
407 {
408 aTris->SetVertexNormal (aVertIter, -aNorm);
409 }
410 return aTris;
411}
412
413//=======================================================================
414//function : createBoxPartTriangles
415//purpose :
416//=======================================================================
417Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createBoxPartTriangles (V3d_TypeOfOrientation theDir) const
418{
419 if (IsBoxSide (theDir))
420 {
421 return createBoxSideTriangles (theDir);
422 }
423 else if (IsBoxEdge (theDir)
424 && myToDisplayEdges)
425 {
426 return createBoxEdgeTriangles (theDir);
427 }
428 else if (IsBoxCorner (theDir)
429 && myToDisplayVertices)
430 {
431 return createBoxCornerTriangles (theDir);
432 }
433 return Handle(Graphic3d_ArrayOfTriangles)();
434}
435
436//=======================================================================
437//function : createBoxSideTriangles
438//purpose :
439//=======================================================================
440Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createBoxSideTriangles (V3d_TypeOfOrientation theDirection) const
441{
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());
445
446 gp_Ax3 aSystem (aPosition);
447 gp_Trsf aTrsf;
448 aTrsf.SetTransformation (aSystem, gp_Ax3());
449
450 return createRoundRectangleTriangles (gp_XY (mySize, mySize), myRoundRadius * mySize, aTrsf);
451}
452
453//=======================================================================
454//function : createBoxEdgeTriangles
455//purpose :
456//=======================================================================
457Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createBoxEdgeTriangles (V3d_TypeOfOrientation theDirection) const
458{
459 const Standard_Real aThickness = Max (myBoxFacetExtension * gp_XY (1.0, 1.0).Modulus() - myBoxEdgeGap, myBoxEdgeMinSize);
460
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());
464
465 gp_Ax3 aSystem (aPosition);
466 gp_Trsf aTrsf;
467 aTrsf.SetTransformation (aSystem, gp_Ax3());
468
469 return createRoundRectangleTriangles (gp_XY (aThickness, mySize), myRoundRadius * mySize, aTrsf);
470}
471
472//=======================================================================
473//function : createBoxCornerTriangles
474//purpose :
475//=======================================================================
476Handle(Graphic3d_ArrayOfTriangles) AIS_ViewCube::createBoxCornerTriangles (V3d_TypeOfOrientation theDir) const
477{
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)
482 {
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);
488 gp_Trsf aTrsf;
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);
492 }
493
494 Handle(Graphic3d_ArrayOfTriangles) aTris = new Graphic3d_ArrayOfTriangles (3, 3, Graphic3d_ArrayFlags_VertexNormal);
495
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());
499
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)
505 {
506 aTris->AddEdges (1, 3, 2);
507 }
508 else
509 {
510 aTris->AddEdges (1, 2, 3);
511 }
512
513 for (Standard_Integer aVertIter = 1; aVertIter <= aTris->VertexNumber(); ++aVertIter)
514 {
515 aTris->SetVertexNormal (aVertIter, aDir);
516 }
517 return aTris;
518}
519
520//=======================================================================
521//function : Compute
522//purpose :
523//=======================================================================
524void AIS_ViewCube::Compute (const Handle(PrsMgr_PresentationManager3d)& ,
525 const Handle(Prs3d_Presentation)& thePrs,
526 const Standard_Integer theMode)
527{
528 thePrs->SetInfiniteState (true);
529 if (theMode != 0)
530 {
531 return;
532 }
533
534 const gp_Pnt aLocation = (mySize * 0.5 + myBoxFacetExtension + myAxesPadding) * gp_XYZ (-1.0, -1.0, -1.0);
535
536 // Display axes
537 if (myToDisplayAxes)
538 {
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)
542 {
543 const Prs3d_DatumParts aPart = (Prs3d_DatumParts )anAxisIter;
544 if (!aDatumAspect->DrawDatumPart (aPart))
545 {
546 continue;
547 }
548
549 gp_Ax1 anAx1;
550 switch (aPart)
551 {
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;
555 default: break;
556 }
557
558 Handle(Graphic3d_Group) anAxisGroup = thePrs->NewGroup();
559 anAxisGroup->SetGroupPrimitivesAspect (aDatumAspect->ShadingAspect (aPart)->Aspect());
560
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);
564
565 TCollection_AsciiString anAxisLabel;
566 if (aDatumAspect->ToDrawLabels()
567 && myAxesLabels.Find (aPart, anAxisLabel)
568 && !anAxisLabel.IsEmpty())
569 {
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);
575 }
576 }
577
578 // Display center
579 {
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);
585 gp_Trsf aTrsf;
586 aTrsf.SetTranslation (gp_Vec (gp::Origin(), aLocation));
587 Handle(Graphic3d_ArrayOfTriangles) aCenterArray;
588 aTool.FillArray (aCenterArray, aTrsf);
589 aGroup->AddPrimitiveArray (aCenterArray);
590 }
591 }
592
593 // Display box
594 {
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());
598
599 aGroupEdges->SetClosed (true);
600 aGroupEdges->SetGroupPrimitivesAspect (myBoxEdgeAspect->Aspect());
601
602 aGroupCorners->SetClosed (true);
603 aGroupCorners->SetGroupPrimitivesAspect (myBoxCornerAspect->Aspect());
604
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)
609 {
610 const V3d_TypeOfOrientation anOrient = (V3d_TypeOfOrientation )aPartIter;
611 if (Handle(Graphic3d_ArrayOfTriangles) aTris = createBoxPartTriangles (anOrient))
612 {
613 if (IsBoxSide (anOrient))
614 {
615 aGroupSides->AddPrimitiveArray (aTris);
616
617 TCollection_AsciiString aLabel;
618 if (!myBoxSideLabels.Find (anOrient, aLabel)
619 || aLabel.IsEmpty())
620 {
621 continue;
622 }
623
624 const gp_Dir aDir = V3d::GetProjAxis (anOrient);
625 gp_Dir anUp = myIsYup ? gp::DY() : gp::DZ();
626 if (myIsYup)
627 {
628 if (anOrient == V3d_Ypos
629 || anOrient == V3d_Yneg)
630 {
631 anUp = -gp::DZ();
632 }
633 }
634 else
635 {
636 if (anOrient == V3d_Zpos)
637 {
638 anUp = gp::DY();
639 }
640 else if (anOrient == V3d_Zneg)
641 {
642 anUp = -gp::DY();
643 }
644 }
645
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);
650 }
651 else if (IsBoxEdge (anOrient))
652 {
653 aGroupEdges->AddPrimitiveArray (aTris);
654 }
655 else if (IsBoxCorner (anOrient))
656 {
657 aGroupCorners->AddPrimitiveArray (aTris);
658 }
659 }
660 }
661 }
662}
663
664//=======================================================================
665//function : ComputeSelection
666//purpose :
667//=======================================================================
668void AIS_ViewCube::ComputeSelection (const Handle(SelectMgr_Selection)& theSelection,
669 const Standard_Integer theMode)
670{
671 if (theMode != 0)
672 {
673 return;
674 }
675
676 for (Standard_Integer aPartIter = 0; aPartIter <= Standard_Integer(V3d_XnegYnegZneg); ++aPartIter)
677 {
678 const V3d_TypeOfOrientation anOri = (V3d_TypeOfOrientation )aPartIter;
679 if (Handle(Graphic3d_ArrayOfTriangles) aTris = createBoxPartTriangles (anOri))
680 {
681 Standard_Integer aSensitivity = 2;
682 if (IsBoxCorner (anOri))
683 {
684 aSensitivity = 8;
685 }
686 else if (IsBoxEdge (anOri))
687 {
688 aSensitivity = 4;
689 }
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);
694 }
695 }
696}
697
698//=======================================================================
699//function : HasAnimation
700//purpose :
701//=======================================================================
702Standard_Boolean AIS_ViewCube::HasAnimation() const
703{
704 return !myViewAnimation->IsStopped();
705}
706
707//=======================================================================
708//function : StartAnimation
709//purpose :
710//=======================================================================
711void AIS_ViewCube::StartAnimation (const Handle(AIS_ViewCubeOwner)& theOwner)
712{
713 Handle(V3d_View) aView = GetContext()->LastActiveView();
714 if (theOwner.IsNull()
715 || aView.IsNull())
716 {
717 return;
718 }
719
720 myStartState->Copy (aView->Camera());
721 myEndState ->Copy (aView->Camera());
722
723 {
724 Handle(Graphic3d_Camera) aBackupCamera = new Graphic3d_Camera (aView->Camera());
725
726 const bool wasImmediateUpdate = aView->SetImmediateUpdate (false);
727 aView->SetCamera (myEndState);
728 aView->SetProj (theOwner->MainOrientation(), myIsYup);
729
730 const gp_Dir aNewDir = aView->Camera()->Direction();
731 if (!myToResetCameraUp
732 && !aNewDir.IsEqual (aBackupCamera->Direction(), Precision::Angular()))
733 {
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] =
738 {
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),
743 };
744
745 Standard_Real aBestAngle = Precision::Infinite();
746 gp_Dir anUpBest;
747 for (Standard_Integer anUpIter = 0; anUpIter < 4; ++anUpIter)
748 {
749 Standard_Real anAngle = anUpList[anUpIter].Angle (anOldUp);
750 if (aBestAngle > anAngle)
751 {
752 aBestAngle = anAngle;
753 anUpBest = anUpList[anUpIter];
754 }
755 }
756 aView->Camera()->SetUp (anUpBest);
757 }
758
759 const Bnd_Box aBndSelected = myToFitSelected ? GetContext()->BoundingBoxOfSelection() : Bnd_Box();
760 if (!aBndSelected.IsVoid())
761 {
762 aView->FitAll (aBndSelected, 0.01, false);
763 }
764 else
765 {
766 aView->FitAll (0.01, false);
767 }
768 aView->SetCamera (aBackupCamera);
769 aView->SetImmediateUpdate (wasImmediateUpdate);
770 }
771
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);
777}
778
779//=======================================================================
780//function : updateAnimation
781//purpose :
782//=======================================================================
783Standard_Boolean AIS_ViewCube::updateAnimation()
784{
785 const Standard_Real aPts = myViewAnimation->UpdateTimer();
786 if (aPts >= myDuration)
787 {
788 myViewAnimation->Stop();
789 onAnimationFinished();
790 myViewAnimation->SetView (Handle(V3d_View)());
791 return Standard_False;
792 }
793 return Standard_True;
794}
795
796//=======================================================================
797//function : UpdateAnimation
798//purpose :
799//=======================================================================
800Standard_Boolean AIS_ViewCube::UpdateAnimation (const Standard_Boolean theToUpdate)
801{
802 Handle(V3d_View) aView = myViewAnimation->View();
803 if (!HasAnimation()
804 || !updateAnimation())
805 {
806 return Standard_False;
807 }
808
809 if (theToUpdate
810 && !aView.IsNull())
811 {
812 aView->IsInvalidated() ? aView->Redraw() : aView->RedrawImmediate();
813 }
814
815 onAfterAnimation();
816 return Standard_True;
817}
818
819//=======================================================================
820//function : HandleClick
821//purpose :
822//=======================================================================
823void AIS_ViewCube::HandleClick (const Handle(AIS_ViewCubeOwner)& theOwner)
824{
825 if (!myToAutoStartAnim)
826 {
827 return;
828 }
829
830 StartAnimation (theOwner);
831 if (!myIsFixedAnimation)
832 {
833 return;
834 }
835 for (; HasAnimation(); )
836 {
837 UpdateAnimation (true);
838 }
839}
840
841//=======================================================================
842//function : HilightOwnerWithColor
843//purpose :
844//=======================================================================
845void AIS_ViewCube::HilightOwnerWithColor (const Handle(PrsMgr_PresentationManager3d)& thePrsMgr,
846 const Handle(Prs3d_Drawer)& theStyle,
847 const Handle(SelectMgr_EntityOwner)& theOwner)
848{
849 if (theOwner.IsNull()
850 || !thePrsMgr->IsImmediateModeOn())
851 {
852 return;
853 }
854
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());
857
858 Handle(Prs3d_Presentation) aHiPrs = GetHilightPresentation (thePrsMgr);
859 aHiPrs->Clear();
860 aHiPrs->CStructure()->ViewAffinity = thePrsMgr->StructureManager()->ObjectAffinity (Handle(Standard_Transient)(this));
861 aHiPrs->SetTransformPersistence (TransformPersistence());
862 aHiPrs->SetZLayer (aLayer);
863
864 {
865 Handle(Graphic3d_Group) aGroup = aHiPrs->NewGroup();
866 aGroup->SetGroupPrimitivesAspect (theStyle->ShadingAspect()->Aspect());
867 if (Handle(Graphic3d_ArrayOfTriangles) aTris = createBoxPartTriangles (aCubeOwner->MainOrientation()))
868 {
869 aGroup->AddPrimitiveArray (aTris);
870 }
871 }
872
873 if (thePrsMgr->IsImmediateModeOn())
874 {
875 thePrsMgr->AddToImmediateList (aHiPrs);
876 }
877}
878
879//=======================================================================
880//function : HilightSelected
881//purpose :
882//=======================================================================
883void AIS_ViewCube::HilightSelected (const Handle(PrsMgr_PresentationManager3d)& ,
884 const SelectMgr_SequenceOfOwner& theSeq)
885{
886 // this method should never be called since AIS_InteractiveObject::HandleClick() has been overridden
887 if (theSeq.Size() == 1)
888 {
889 //HandleClick (Handle(AIS_ViewCubeOwner)::DownCast (theSeq.First()));
890 }
891}