0031687: Draw Harness, ViewerTest - extend command vrenderparams with option updating...
[occt.git] / src / V3d / V3d_Trihedron.cxx
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_LineAspect.hxx>
27 #include <Prs3d_ShadingAspect.hxx>
28 #include <Prs3d_Text.hxx>
29 #include <Prs3d_TextAspect.hxx>
30 #include <Prs3d_ToolSphere.hxx>
31 #include <V3d_View.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
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.
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.
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 // ============================================================================
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     myArrowLineAspects[anIt]    = new Prs3d_LineAspect (Quantity_NOC_WHITE, Aspect_TOL_SOLID, 1.0);
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   myArrowShadingAspects[0]->SetColor (Quantity_NOC_RED);
108   myArrowLineAspects   [0]->SetColor (Quantity_NOC_RED);
109   myArrowShadingAspects[1]->SetColor (Quantity_NOC_GREEN);
110   myArrowLineAspects   [1]->SetColor (Quantity_NOC_GREEN);
111   myArrowShadingAspects[2]->SetColor (Quantity_NOC_BLUE1);
112   myArrowLineAspects   [2]->SetColor (Quantity_NOC_BLUE1);
113
114   mySphereShadingAspect = new Prs3d_ShadingAspect();
115   mySphereLineAspect    = new Prs3d_LineAspect (Quantity_NOC_WHITE, Aspect_TOL_SOLID, 1.0);
116
117   // mark texture map ON to actually disable environment map
118   mySphereShadingAspect->Aspect()->SetTextureMapOn();
119   mySphereShadingAspect->Aspect()->SetInteriorStyle (Aspect_IS_SOLID);
120   mySphereShadingAspect->SetMaterial (aShadingMaterial);
121   mySphereShadingAspect->SetColor (Quantity_NOC_WHITE);
122
123   myTextAspect = new Prs3d_TextAspect();
124   myTextAspect->SetFont ("Courier");
125   myTextAspect->SetHeight (16);
126   myTextAspect->SetHorizontalJustification (Graphic3d_HTA_LEFT);
127   myTextAspect->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
128 }
129
130 // ============================================================================
131 // function : V3d_Trihedron
132 // purpose  :
133 // ============================================================================
134 V3d_Trihedron::~V3d_Trihedron()
135 {
136   Erase();
137 }
138
139 // ============================================================================
140 // function : SetLabelsColor
141 // purpose  :
142 // ============================================================================
143 void V3d_Trihedron::SetLabelsColor (const Quantity_Color& theColor)
144 {
145   myTextAspect->SetColor (theColor);
146 }
147
148 // ============================================================================
149 // function : SetArrowsColor
150 // purpose  :
151 // ============================================================================
152 void V3d_Trihedron::SetArrowsColor (const Quantity_Color& theXColor,
153                                     const Quantity_Color& theYColor,
154                                     const Quantity_Color& theZColor)
155 {
156   const Quantity_Color aColors[3] = { theXColor, theYColor, theZColor };
157   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
158   {
159     myArrowShadingAspects[anIt]->SetColor (aColors[anIt]);
160     myArrowLineAspects   [anIt]->SetColor (aColors[anIt]);
161   }
162 }
163
164 // ============================================================================
165 // function : SetScale
166 // purpose  :
167 // ============================================================================
168 void V3d_Trihedron::SetScale (const Standard_Real theScale)
169 {
170   if (Abs (myScale - theScale) > Precision::Confusion())
171   {
172     invalidate();
173   }
174   myScale = theScale;
175 }
176
177 // =======================================================================
178 // function : SetSizeRatio
179 // purpose  :
180 // =======================================================================
181 void V3d_Trihedron::SetSizeRatio (const Standard_Real theRatio)
182 {
183   if (Abs (myRatio - theRatio) > Precision::Confusion())
184   {
185     invalidate();
186   }
187   myRatio = theRatio;
188 }
189
190 // =======================================================================
191 // function : SetArrowDiameter
192 // purpose  :
193 // =======================================================================
194 void V3d_Trihedron::SetArrowDiameter (const Standard_Real theDiam)
195 {
196   if (Abs (myDiameter - theDiam) > Precision::Confusion())
197   {
198     invalidate();
199   }
200   myDiameter = theDiam;
201 }
202
203 // =======================================================================
204 // function : SetNbFacets
205 // purpose  :
206 // =======================================================================
207 void V3d_Trihedron::SetNbFacets (const Standard_Integer theNbFacets)
208 {
209   if (Abs (myNbFacettes - theNbFacets) > 0)
210   {
211     invalidate();
212   }
213   myNbFacettes = theNbFacets;
214 }
215
216 // ============================================================================
217 // function : Display
218 // purpose  :
219 // ============================================================================
220 void V3d_Trihedron::Display (const V3d_View& theView)
221 {
222   if (myStructure.IsNull())
223   {
224     myStructure = new TrihedronStructure (theView.Viewer()->StructureManager(), this);
225     myStructure->SetTransformPersistence (myTransformPers);
226     myStructure->SetZLayer (Graphic3d_ZLayerId_Topmost);
227     myStructure->SetDisplayPriority (9);
228     myStructure->SetInfiniteState (Standard_True);
229     myStructure->CStructure()->ViewAffinity = new Graphic3d_ViewAffinity();
230     myStructure->CStructure()->ViewAffinity->SetVisible (Standard_False);
231     myStructure->CStructure()->ViewAffinity->SetVisible (theView.View()->Identification(), true);
232     myToCompute = Standard_True;
233   }
234   if (myToCompute)
235   {
236     compute();
237   }
238
239   myStructure->Display();
240 }
241
242 // ============================================================================
243 // function : Erase
244 // purpose  :
245 // ============================================================================
246 void V3d_Trihedron::Erase()
247 {
248   if (!myStructure.IsNull())
249   {
250     myStructure->Erase();
251     myStructure.Nullify();
252   }
253 }
254
255 // ============================================================================
256 // function : SetPosition
257 // purpose  :
258 // ============================================================================
259 void V3d_Trihedron::SetPosition (const Aspect_TypeOfTriedronPosition thePosition)
260 {
261   Graphic3d_Vec2i anOffset (0, 0);
262   if ((thePosition & (Aspect_TOTP_LEFT | Aspect_TOTP_RIGHT)) != 0)
263   {
264     anOffset.x() = static_cast<Standard_Integer> (myScale * THE_INTERNAL_SCALE_FACTOR);
265   }
266   if ((thePosition & (Aspect_TOTP_TOP | Aspect_TOTP_BOTTOM)) != 0)
267   {
268     anOffset.y() = static_cast<Standard_Integer> (myScale * THE_INTERNAL_SCALE_FACTOR);
269   }
270
271   myTransformPers->SetCorner2d (thePosition);
272   myTransformPers->SetOffset2d (anOffset);
273 }
274
275 // ============================================================================
276 // function : compute
277 // purpose  :
278 // ============================================================================
279 void V3d_Trihedron::compute()
280 {
281   myToCompute = Standard_False;
282   myStructure->GraphicClear (Standard_False);
283
284   // Create trihedron.
285   const Standard_Real aScale          = myScale * myRatio * THE_INTERNAL_SCALE_FACTOR;
286   const Standard_Real aCylinderLength = aScale * THE_CYLINDER_LENGTH;
287   const Standard_Real aCylinderRadius = aScale * myDiameter;
288   const Standard_Real aConeRadius     = myIsWireframe ? aCylinderRadius : (aCylinderRadius * 2.0);
289   const Standard_Real aConeLength     = aScale * (1.0 - THE_CYLINDER_LENGTH);
290   const Standard_Real aSphereRadius   = aCylinderRadius * 2.0;
291   const Standard_Real aRayon          = aScale / 30.0;
292   Standard_Integer aGroupIter = myStructure->Groups().Lower();
293   {
294     Handle(Graphic3d_Group) aSphereGroup = addGroup (myStructure, aGroupIter);
295
296     // Display origin.
297     if (myIsWireframe)
298     {
299       Handle(Graphic3d_ArrayOfPolylines) anCircleArray = new Graphic3d_ArrayOfPolylines (THE_CIRCLE_SERMENTS_NB + 2);
300       for (Standard_Integer anIt = THE_CIRCLE_SERMENTS_NB; anIt >= 0; --anIt)
301       {
302         anCircleArray->AddVertex (aRayon * Sin (anIt * THE_CIRCLE_SEGMENT_ANGLE),
303                                   aRayon * Cos (anIt * THE_CIRCLE_SEGMENT_ANGLE), 0.0);
304       }
305       anCircleArray->AddVertex (aRayon * Sin (THE_CIRCLE_SERMENTS_NB * THE_CIRCLE_SEGMENT_ANGLE),
306                                 aRayon * Cos (THE_CIRCLE_SERMENTS_NB * THE_CIRCLE_SEGMENT_ANGLE), 0.0);
307
308       aSphereGroup->SetGroupPrimitivesAspect (mySphereLineAspect->Aspect());
309       aSphereGroup->AddPrimitiveArray (anCircleArray);
310     }
311     else
312     {
313       gp_Trsf aSphereTransform;
314       aSphereGroup->SetGroupPrimitivesAspect (mySphereShadingAspect->Aspect());
315       aSphereGroup->AddPrimitiveArray (Prs3d_ToolSphere::Create (aSphereRadius, myNbFacettes, myNbFacettes, aSphereTransform));
316     }
317   }
318
319   // Display axes.
320   {
321     const gp_Ax1 anAxes[3] = { gp::OX(), gp::OY(), gp::OZ() };
322     for (Standard_Integer anIter = 0; anIter < 3; ++anIter)
323     {
324       Handle(Graphic3d_Group) anAxisGroup = addGroup (myStructure, aGroupIter);
325       if (myIsWireframe)
326       {
327         // create a tube
328         Handle(Graphic3d_ArrayOfPrimitives) anArray = new Graphic3d_ArrayOfSegments (2);
329         anArray->AddVertex (0.0f, 0.0f, 0.0f);
330         anArray->AddVertex (anAxes[anIter].Direction().XYZ() * aCylinderLength);
331
332         anAxisGroup->SetGroupPrimitivesAspect (myArrowLineAspects[anIter]->Aspect());
333         anAxisGroup->AddPrimitiveArray (anArray);
334       }
335
336       Handle(Graphic3d_ArrayOfTriangles) aTriangles = Prs3d_Arrow::DrawShaded (anAxes[anIter],
337                                                                                myIsWireframe ? 0.0 : aCylinderRadius,
338                                                                                aCylinderLength + aConeLength,
339                                                                                aConeRadius,
340                                                                                aConeLength,
341                                                                                myNbFacettes);
342       anAxisGroup->SetGroupPrimitivesAspect (myArrowShadingAspects[anIter]->Aspect());
343       anAxisGroup->AddPrimitiveArray (aTriangles);
344     }
345   }
346
347   // Display labels.
348   {
349     Handle(Graphic3d_Group) aLabelGroup = addGroup (myStructure, aGroupIter);
350     const TCollection_ExtendedString aLabels[3] = { "X", "Y", "Z" };
351     const gp_Pnt aPoints[3] = { gp_Pnt (aScale + 2.0 * aRayon,                   0.0,               -aRayon),
352                                 gp_Pnt (               aRayon, aScale + 3.0 * aRayon,          2.0 * aRayon),
353                                 gp_Pnt (        -2.0 * aRayon,          0.5 * aRayon, aScale + 3.0 * aRayon) };
354     for (Standard_Integer anAxisIter = 0; anAxisIter < 3; ++anAxisIter)
355     {
356       Prs3d_Text::Draw (aLabelGroup, myTextAspect, aLabels[anAxisIter], aPoints[anAxisIter]);
357     }
358   }
359 }