1 // Created on: 2016-10-11
2 // Created by: Ilya SEVRIKOV
3 // Copyright (c) 2016 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 <V3d_Trihedron.hxx>
17 
18 #include <gp_Ax3.hxx>
19 #include <Graphic3d_ArrayOfPolylines.hxx>
20 #include <Graphic3d_ArrayOfSegments.hxx>
21 #include <Graphic3d_ArrayOfTriangles.hxx>
22 #include <Graphic3d_Camera.hxx>
23 #include <Graphic3d_TransformPers.hxx>
24 #include <Prs3d.hxx>
25 #include <Prs3d_Arrow.hxx>
26 #include <Prs3d_ShadingAspect.hxx>
27 #include <Prs3d_Text.hxx>
28 #include <Prs3d_TextAspect.hxx>
29 #include <Prs3d_ToolSphere.hxx>
30 #include <V3d_View.hxx>
31 #include <V3d_Viewer.hxx>
32 
33 IMPLEMENT_STANDARD_RTTIEXT (V3d_Trihedron, Standard_Transient)
34 
35 namespace
36 {
37   //! Compensates difference between old implementation (without transform persistence) and current implementation.
38   static const Standard_Real THE_INTERNAL_SCALE_FACTOR = 500.0;
39 
40   static const Standard_ShortReal THE_CYLINDER_LENGTH      = 0.75f;
41   static const Standard_Integer   THE_CIRCLE_SERMENTS_NB   = 24;
42   static const Standard_Real      THE_CIRCLE_SEGMENT_ANGLE = 2.0 * M_PI / THE_CIRCLE_SERMENTS_NB;
43 
44   //! Create new or return existing group in the structure at specified position.
45   //! @param theStruct     [in]     structure holding graphic groups
46   //! @param theGroupIndex [in/out] group position, will be incremented as output
addGroup(const Handle (Graphic3d_Structure)& theStruct,Standard_Integer & theGroupIter)47   static Handle(Graphic3d_Group) addGroup (const Handle(Graphic3d_Structure)& theStruct,
48                                            Standard_Integer& theGroupIter)
49   {
50     const Graphic3d_SequenceOfGroup& aGroups = theStruct->Groups();
51     const Standard_Integer aGroupIndex = theGroupIter++;
52     if (!aGroups.IsEmpty()
53       && aGroupIndex <= aGroups.Upper())
54     {
55       return aGroups.Value (aGroupIndex);
56     }
57 
58     return theStruct->NewGroup();
59   }
60 }
61 
62 //! Dummy implementation of Graphic3d_Structure overriding ::Compute() method for handling Device Lost.
63 class V3d_Trihedron::TrihedronStructure : public Graphic3d_Structure
64 {
65 public:
66   //! Main constructor.
TrihedronStructure(const Handle (Graphic3d_StructureManager)& theManager,V3d_Trihedron * theTrihedron)67   TrihedronStructure (const Handle(Graphic3d_StructureManager)& theManager, V3d_Trihedron* theTrihedron)
68   : Graphic3d_Structure (theManager), myTrihedron (theTrihedron) {}
69 
70   //! Override method to redirect to V3d_Trihedron.
Compute()71   virtual void Compute() Standard_OVERRIDE { myTrihedron->compute(); }
72 
73 private:
74   V3d_Trihedron* myTrihedron;
75 };
76 
77 // ============================================================================
78 // function : V3d_Trihedron
79 // purpose  :
80 // ============================================================================
V3d_Trihedron()81 V3d_Trihedron::V3d_Trihedron()
82 : myScale      (1.0),
83   myRatio      (0.8),
84   myDiameter   (0.05),
85   myNbFacettes (12),
86   myIsWireframe(Standard_False),
87   myToCompute  (Standard_True)
88 {
89   myTransformPers = new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_LEFT_LOWER);
90   SetPosition (Aspect_TOTP_LEFT_LOWER);
91 
92   // Set material.
93   Graphic3d_MaterialAspect aShadingMaterial;
94   aShadingMaterial.SetSpecularColor(Quantity_NOC_BLACK);
95   aShadingMaterial.SetMaterialType (Graphic3d_MATERIAL_ASPECT);
96 
97   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
98   {
99     myArrowShadingAspects[anIt] = new Prs3d_ShadingAspect();
100     myTextAspects[anIt]         = new Prs3d_TextAspect();
101 
102     // mark texture map ON to actually disable environment map
103     myArrowShadingAspects[anIt]->Aspect()->SetTextureMapOn();
104     myArrowShadingAspects[anIt]->Aspect()->SetInteriorStyle (Aspect_IS_SOLID);
105     myArrowShadingAspects[anIt]->SetMaterial (aShadingMaterial);
106 
107     myTextAspects[anIt]->SetFont (Font_NOF_ASCII_MONO);
108     myTextAspects[anIt]->SetHeight (16);
109     myTextAspects[anIt]->SetHorizontalJustification (Graphic3d_HTA_LEFT);
110     myTextAspects[anIt]->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
111   }
112   myArrowShadingAspects[V3d_X]->SetColor (Quantity_NOC_RED);
113   myArrowShadingAspects[V3d_Y]->SetColor (Quantity_NOC_GREEN);
114   myArrowShadingAspects[V3d_Z]->SetColor (Quantity_NOC_BLUE);
115 
116   myLabels[V3d_X] = "X";
117   myLabels[V3d_Y] = "Y";
118   myLabels[V3d_Z] = "Z";
119 
120   mySphereShadingAspect = new Prs3d_ShadingAspect();
121   // mark texture map ON to actually disable environment map
122   mySphereShadingAspect->Aspect()->SetTextureMapOn();
123   mySphereShadingAspect->Aspect()->SetInteriorStyle (Aspect_IS_SOLID);
124   mySphereShadingAspect->SetMaterial (aShadingMaterial);
125   mySphereShadingAspect->SetColor (Quantity_NOC_WHITE);
126 }
127 
128 // ============================================================================
129 // function : V3d_Trihedron
130 // purpose  :
131 // ============================================================================
~V3d_Trihedron()132 V3d_Trihedron::~V3d_Trihedron()
133 {
134   Erase();
135 }
136 
137 // ============================================================================
138 // function : SetLabelsColor
139 // purpose  :
140 // ============================================================================
SetLabelsColor(const Quantity_Color & theColor)141 void V3d_Trihedron::SetLabelsColor (const Quantity_Color& theColor)
142 {
143   myTextAspects[V3d_X]->SetColor (theColor);
144   myTextAspects[V3d_Y]->SetColor (theColor);
145   myTextAspects[V3d_Z]->SetColor (theColor);
146 }
147 
148 // ============================================================================
149 // function : SetLabels
150 // purpose  :
151 // ============================================================================
SetLabels(const TCollection_AsciiString & theX,const TCollection_AsciiString & theY,const TCollection_AsciiString & theZ)152 void V3d_Trihedron::SetLabels (const TCollection_AsciiString& theX,
153                                const TCollection_AsciiString& theY,
154                                const TCollection_AsciiString& theZ)
155 {
156   if (!myLabels[V3d_X].IsEqual (theX)
157    || !myLabels[V3d_Y].IsEqual (theY)
158    || !myLabels[V3d_Z].IsEqual (theZ))
159   {
160     invalidate();
161     myLabels[V3d_X] = theX;
162     myLabels[V3d_Y] = theY;
163     myLabels[V3d_Z] = theZ;
164   }
165 }
166 
167 // ============================================================================
168 // function : SetLabelsColor
169 // purpose  :
170 // ============================================================================
SetLabelsColor(const Quantity_Color & theXColor,const Quantity_Color & theYColor,const Quantity_Color & theZColor)171 void V3d_Trihedron::SetLabelsColor (const Quantity_Color& theXColor,
172                                     const Quantity_Color& theYColor,
173                                     const Quantity_Color& theZColor)
174 {
175   myTextAspects[V3d_X]->SetColor (theXColor);
176   myTextAspects[V3d_Y]->SetColor (theYColor);
177   myTextAspects[V3d_Z]->SetColor (theZColor);
178 }
179 
180 // ============================================================================
181 // function : SetArrowsColor
182 // purpose  :
183 // ============================================================================
SetArrowsColor(const Quantity_Color & theXColor,const Quantity_Color & theYColor,const Quantity_Color & theZColor)184 void V3d_Trihedron::SetArrowsColor (const Quantity_Color& theXColor,
185                                     const Quantity_Color& theYColor,
186                                     const Quantity_Color& theZColor)
187 {
188   const Quantity_Color aColors[3] = { theXColor, theYColor, theZColor };
189   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
190   {
191     myArrowShadingAspects[anIt]->SetColor (aColors[anIt]);
192   }
193 }
194 
195 // ============================================================================
196 // function : SetScale
197 // purpose  :
198 // ============================================================================
SetScale(const Standard_Real theScale)199 void V3d_Trihedron::SetScale (const Standard_Real theScale)
200 {
201   if (Abs (myScale - theScale) > Precision::Confusion())
202   {
203     invalidate();
204   }
205   myScale = theScale;
206 }
207 
208 // =======================================================================
209 // function : SetSizeRatio
210 // purpose  :
211 // =======================================================================
SetSizeRatio(const Standard_Real theRatio)212 void V3d_Trihedron::SetSizeRatio (const Standard_Real theRatio)
213 {
214   if (Abs (myRatio - theRatio) > Precision::Confusion())
215   {
216     invalidate();
217   }
218   myRatio = theRatio;
219 }
220 
221 // =======================================================================
222 // function : SetArrowDiameter
223 // purpose  :
224 // =======================================================================
SetArrowDiameter(const Standard_Real theDiam)225 void V3d_Trihedron::SetArrowDiameter (const Standard_Real theDiam)
226 {
227   if (Abs (myDiameter - theDiam) > Precision::Confusion())
228   {
229     invalidate();
230   }
231   myDiameter = theDiam;
232 }
233 
234 // =======================================================================
235 // function : SetNbFacets
236 // purpose  :
237 // =======================================================================
SetNbFacets(const Standard_Integer theNbFacets)238 void V3d_Trihedron::SetNbFacets (const Standard_Integer theNbFacets)
239 {
240   if (Abs (myNbFacettes - theNbFacets) > 0)
241   {
242     invalidate();
243   }
244   myNbFacettes = theNbFacets;
245 }
246 
247 // ============================================================================
248 // function : Display
249 // purpose  :
250 // ============================================================================
Display(const V3d_View & theView)251 void V3d_Trihedron::Display (const V3d_View& theView)
252 {
253   if (myStructure.IsNull())
254   {
255     myStructure = new TrihedronStructure (theView.Viewer()->StructureManager(), this);
256     myStructure->SetTransformPersistence (myTransformPers);
257     myStructure->SetZLayer (Graphic3d_ZLayerId_Topmost);
258     myStructure->SetDisplayPriority (9);
259     myStructure->SetInfiniteState (Standard_True);
260     myStructure->CStructure()->ViewAffinity = new Graphic3d_ViewAffinity();
261     myStructure->CStructure()->ViewAffinity->SetVisible (Standard_False);
262     myStructure->CStructure()->ViewAffinity->SetVisible (theView.View()->Identification(), true);
263     myToCompute = Standard_True;
264   }
265   if (myToCompute)
266   {
267     compute();
268   }
269 
270   myStructure->Display();
271 }
272 
273 // ============================================================================
274 // function : Erase
275 // purpose  :
276 // ============================================================================
Erase()277 void V3d_Trihedron::Erase()
278 {
279   if (!myStructure.IsNull())
280   {
281     myStructure->Erase();
282     myStructure.Nullify();
283   }
284 }
285 
286 // ============================================================================
287 // function : SetPosition
288 // purpose  :
289 // ============================================================================
SetPosition(const Aspect_TypeOfTriedronPosition thePosition)290 void V3d_Trihedron::SetPosition (const Aspect_TypeOfTriedronPosition thePosition)
291 {
292   Graphic3d_Vec2i anOffset (0, 0);
293   if ((thePosition & (Aspect_TOTP_LEFT | Aspect_TOTP_RIGHT)) != 0)
294   {
295     anOffset.x() = static_cast<Standard_Integer> (myScale * THE_INTERNAL_SCALE_FACTOR);
296   }
297   if ((thePosition & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
298   {
299     anOffset.y() = static_cast<Standard_Integer> (myScale * THE_INTERNAL_SCALE_FACTOR);
300   }
301 
302   myTransformPers->SetCorner2d (thePosition);
303   myTransformPers->SetOffset2d (anOffset);
304 }
305 
306 // ============================================================================
307 // function : compute
308 // purpose  :
309 // ============================================================================
compute()310 void V3d_Trihedron::compute()
311 {
312   myToCompute = Standard_False;
313   myStructure->GraphicClear (Standard_False);
314 
315   // Create trihedron.
316   const Standard_Real aScale          = myScale * myRatio * THE_INTERNAL_SCALE_FACTOR;
317   const Standard_Real aCylinderLength = aScale * THE_CYLINDER_LENGTH;
318   const Standard_Real aCylinderRadius = aScale * myDiameter;
319   const Standard_Real aConeRadius     = myIsWireframe ? aCylinderRadius : (aCylinderRadius * 2.0);
320   const Standard_Real aConeLength     = aScale * (1.0 - THE_CYLINDER_LENGTH);
321   const Standard_Real aSphereRadius   = aCylinderRadius * 2.0;
322   const Standard_Real aRayon          = aScale / 30.0;
323   Standard_Integer aGroupIter = myStructure->Groups().Lower();
324   {
325     Handle(Graphic3d_Group) aSphereGroup = addGroup (myStructure, aGroupIter);
326     aSphereGroup->SetClosed (!myIsWireframe);
327 
328     // Display origin.
329     if (myIsWireframe)
330     {
331       Handle(Graphic3d_ArrayOfPolylines) anCircleArray = new Graphic3d_ArrayOfPolylines (THE_CIRCLE_SERMENTS_NB + 2);
332       for (Standard_Integer anIt = THE_CIRCLE_SERMENTS_NB; anIt >= 0; --anIt)
333       {
334         anCircleArray->AddVertex (aRayon * Sin (anIt * THE_CIRCLE_SEGMENT_ANGLE),
335                                   aRayon * Cos (anIt * THE_CIRCLE_SEGMENT_ANGLE), 0.0);
336       }
337       anCircleArray->AddVertex (aRayon * Sin (THE_CIRCLE_SERMENTS_NB * THE_CIRCLE_SEGMENT_ANGLE),
338                                 aRayon * Cos (THE_CIRCLE_SERMENTS_NB * THE_CIRCLE_SEGMENT_ANGLE), 0.0);
339 
340       aSphereGroup->SetGroupPrimitivesAspect (mySphereShadingAspect->Aspect());
341       aSphereGroup->AddPrimitiveArray (anCircleArray);
342     }
343     else
344     {
345       gp_Trsf aSphereTransform;
346       aSphereGroup->SetGroupPrimitivesAspect (mySphereShadingAspect->Aspect());
347       aSphereGroup->AddPrimitiveArray (Prs3d_ToolSphere::Create (aSphereRadius, myNbFacettes, myNbFacettes, aSphereTransform));
348     }
349   }
350 
351   // Display axes.
352   {
353     const gp_Ax1 anAxes[3] = { gp::OX(), gp::OY(), gp::OZ() };
354     for (Standard_Integer anIter = 0; anIter < 3; ++anIter)
355     {
356       Handle(Graphic3d_Group) anAxisGroup = addGroup (myStructure, aGroupIter);
357       anAxisGroup->SetClosed (!myIsWireframe);
358       if (myIsWireframe)
359       {
360         // create a tube
361         Handle(Graphic3d_ArrayOfPrimitives) anArray = new Graphic3d_ArrayOfSegments (2);
362         anArray->AddVertex (0.0f, 0.0f, 0.0f);
363         anArray->AddVertex (anAxes[anIter].Direction().XYZ() * aCylinderLength);
364 
365         anAxisGroup->SetGroupPrimitivesAspect (myArrowShadingAspects[anIter]->Aspect());
366         anAxisGroup->AddPrimitiveArray (anArray);
367       }
368 
369       Handle(Graphic3d_ArrayOfTriangles) aTriangles = Prs3d_Arrow::DrawShaded (anAxes[anIter],
370                                                                                myIsWireframe ? 0.0 : aCylinderRadius,
371                                                                                aCylinderLength + aConeLength,
372                                                                                aConeRadius,
373                                                                                aConeLength,
374                                                                                myNbFacettes);
375       anAxisGroup->SetGroupPrimitivesAspect (myArrowShadingAspects[anIter]->Aspect());
376       anAxisGroup->AddPrimitiveArray (aTriangles);
377     }
378   }
379 
380   // Display labels.
381   {
382     Handle(Graphic3d_Group) aLabelGroup = addGroup (myStructure, aGroupIter);
383     const gp_Pnt aPoints[3] = { gp_Pnt (aScale + 2.0 * aRayon,                   0.0,               -aRayon),
384                                 gp_Pnt (               aRayon, aScale + 3.0 * aRayon,          2.0 * aRayon),
385                                 gp_Pnt (        -2.0 * aRayon,          0.5 * aRayon, aScale + 3.0 * aRayon) };
386     for (Standard_Integer anAxisIter = 0; anAxisIter < 3; ++anAxisIter)
387     {
388       Prs3d_Text::Draw (aLabelGroup, myTextAspects[anAxisIter], myLabels[anAxisIter], aPoints[anAxisIter]);
389     }
390   }
391 }
392 
393 //=======================================================================
394 //function : DumpJson
395 //purpose  :
396 //=======================================================================
DumpJson(Standard_OStream & theOStream,Standard_Integer theDepth) const397 void V3d_Trihedron::DumpJson (Standard_OStream& theOStream, Standard_Integer theDepth) const
398 {
399   OCCT_DUMP_TRANSIENT_CLASS_BEGIN (theOStream)
400 
401   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, mySphereShadingAspect.get())
402 
403   for (Standard_Integer anIter = 0; anIter < 3; anIter++)
404   {
405     const Handle(Prs3d_TextAspect)& aTextAspect = myTextAspects[anIter];
406     OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, aTextAspect.get())
407   }
408   for (Standard_Integer anIter = 0; anIter < 3; anIter++)
409   {
410     const Handle(Prs3d_ShadingAspect)& anArrowShadinAspect = myArrowShadingAspects[anIter];
411     OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, anArrowShadinAspect.get())
412   }
413 
414   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myStructure.get())
415   OCCT_DUMP_FIELD_VALUES_DUMPED (theOStream, theDepth, myTransformPers.get())
416 
417   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myScale)
418   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myRatio)
419   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myDiameter)
420   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myNbFacettes)
421   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myIsWireframe)
422   OCCT_DUMP_FIELD_VALUE_NUMERICAL (theOStream, myToCompute)
423 }
424