0027816: Visualization - provide an API for overriding clipping planes list
[occt.git] / src / OpenGl / OpenGl_GraduatedTrihedron.cxx
1 // Created on: 2011-09-20
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2013 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 <OpenGl_GlCore11.hxx>
17
18 #include <OpenGl_GraduatedTrihedron.hxx>
19
20 #include <Graphic3d_ArrayOfPolylines.hxx>
21 #include <Graphic3d_ArrayOfSegments.hxx>
22 #include <Graphic3d_GraphicDriver.hxx>
23 #include <Graphic3d_TransformPers.hxx>
24 #include <Graphic3d_TransformUtils.hxx>
25 #include <gp_Ax3.hxx>
26 #include <OpenGl_AspectLine.hxx>
27 #include <OpenGl_Workspace.hxx>
28 #include <OpenGl_View.hxx>
29 #include <OpenGl_Cylinder.hxx>
30 #include <Precision.hxx>
31
32 #ifndef _WIN32
33   #include <string.h>
34 #endif
35
36 namespace
37 {
38   static const OpenGl_TextParam THE_LABEL_PARAMS =
39   {
40     16, Graphic3d_HTA_LEFT, Graphic3d_VTA_BOTTOM
41   };
42 }
43
44 // =======================================================================
45 // function : Constructor
46 // purpose  :
47 // =======================================================================
48 OpenGl_GraduatedTrihedron::OpenGl_GraduatedTrihedron()
49 : myMin (0.0f, 0.0f, 0.0f),
50   myMax (100.0f, 100.0f, 100.0f),
51   myIsInitialized (Standard_False)
52 {
53   //
54 }
55
56 // =======================================================================
57 // function : SetValues
58 // purpose  :
59 // =======================================================================
60 void OpenGl_GraduatedTrihedron::SetValues (const Graphic3d_GraduatedTrihedron& theData)
61 {
62   myData          = theData;
63   myIsInitialized = Standard_False;
64 }
65
66 // =======================================================================
67 // function : Destructor
68 // purpose  :
69 // =======================================================================
70 OpenGl_GraduatedTrihedron::~OpenGl_GraduatedTrihedron()
71 {
72   //
73 }
74
75 // =======================================================================
76 // function : Release
77 // purpose  :
78 // =======================================================================
79 void OpenGl_GraduatedTrihedron::Release (OpenGl_Context* theCtx)
80 {
81   myAxes[0].Release (theCtx);
82   myAxes[1].Release (theCtx);
83   myAxes[2].Release (theCtx);
84   myLabelValues.Release (theCtx);
85 }
86
87 // =======================================================================
88 // function : initResources
89 // purpose  :
90 // =======================================================================
91 void OpenGl_GraduatedTrihedron::initGlResources (const Handle(OpenGl_Context)& theCtx) const
92 {
93   myAxes[0].Release     (theCtx.operator->());
94   myAxes[1].Release     (theCtx.operator->());
95   myAxes[2].Release     (theCtx.operator->());
96   myLabelValues.Release (theCtx.operator->());
97
98   // Initialize text label parameters for x, y, and z axes
99   myAxes[0] = Axis (myData.XAxisAspect(), OpenGl_Vec3 (1.0f, 0.0f, 0.0f));
100   myAxes[1] = Axis (myData.YAxisAspect(), OpenGl_Vec3 (0.0f, 1.0f, 0.0f));
101   myAxes[2] = Axis (myData.ZAxisAspect(), OpenGl_Vec3 (0.0f, 0.0f, 1.0f));
102
103   // Initialize constant primitives: text, arrows.
104   myAxes[0].InitArrow (theCtx, myData.ArrowsLength(), OpenGl_Vec3 (0.0f, 0.0f, 1.0f));
105   myAxes[1].InitArrow (theCtx, myData.ArrowsLength(), OpenGl_Vec3 (0.0f, 0.0f, 1.0f));
106   myAxes[2].InitArrow (theCtx, myData.ArrowsLength(), OpenGl_Vec3 (1.0f, 0.0f, 0.0f));
107   for (Standard_Integer anIt = 0; anIt < 3; ++anIt)
108   {
109     myAxes[anIt].Label.SetFontSize (theCtx, myData.NamesSize());
110   }
111
112   myLabelValues.SetFontSize (theCtx, myData.ValuesSize());
113
114   myAspectLabels.Aspect()->SetTextFontAspect (myData.NamesFontAspect());
115   myAspectLabels.Aspect()->SetFont (myData.NamesFont());
116
117   myAspectValues.Aspect()->SetTextFontAspect (myData.ValuesFontAspect());
118   myAspectValues.Aspect()->SetFont (myData.ValuesFont());
119
120   // Grid aspect
121   myGridLineAspect.Aspect()->SetColor (myData.GridColor());
122 }
123
124 // =======================================================================
125 // method  : getNormal
126 // purpose : Normal of the view (not normalized!)
127 // =======================================================================
128 Standard_ShortReal OpenGl_GraduatedTrihedron::getNormal (const Handle(OpenGl_Context)& theContext,
129                                                          OpenGl_Vec3& theNormal) const
130 {
131   const Standard_Integer* aViewport = theContext->Viewport();
132
133   OpenGl_Mat4 aModelMatrix;
134   OpenGl_Mat4 aProjMatrix;
135   aModelMatrix.Convert (theContext->ModelWorldState.Current() * theContext->WorldViewState.Current());
136   aProjMatrix .Convert (theContext->ProjectionState.Current());
137
138   OpenGl_Vec3 aPoint1, aPoint2, aPoint3;
139   Graphic3d_TransformUtils::UnProject<Standard_ShortReal> ((Standard_ShortReal) aViewport[0],
140                                                            (Standard_ShortReal) aViewport[1],
141                                                            0.0f,
142                                                            aModelMatrix, aProjMatrix, aViewport,
143                                                            aPoint1.x(), aPoint1.y(), aPoint1.z());
144
145   Graphic3d_TransformUtils::UnProject<Standard_ShortReal> ((Standard_ShortReal) (aViewport[0] + aViewport[2]),
146                                                            (Standard_ShortReal) aViewport[1],
147                                                            0.0f,
148                                                            aModelMatrix, aProjMatrix, aViewport,
149                                                            aPoint2.x(), aPoint2.y(), aPoint2.z());
150
151   Graphic3d_TransformUtils::UnProject<Standard_ShortReal> ((Standard_ShortReal) aViewport[0],
152                                                            (Standard_ShortReal) (aViewport[1] + aViewport[3]),
153                                                            0.0f,
154                                                            aModelMatrix, aProjMatrix, aViewport,
155                                                            aPoint3.x(), aPoint3.y(), aPoint3.z());
156
157   const OpenGl_Vec3 aD1 = aPoint3 - aPoint1;
158   const OpenGl_Vec3 aD2 = aPoint2 - aPoint1;
159   theNormal =  OpenGl_Vec3::Cross (aD1, aD2);
160
161   // Distance corresponding to 1 pixel
162   return aD2.Modulus() / (float) aViewport[2];
163 }
164
165 // =======================================================================
166 // method  : getDistancetoCorner
167 // purpose : 
168 // =======================================================================
169 Standard_ShortReal OpenGl_GraduatedTrihedron::getDistanceToCorner (const OpenGl_Vec3& theNormal,
170                                                                    const OpenGl_Vec3& theCenter,
171                                                                    const Standard_ShortReal theX,
172                                                                    const Standard_ShortReal theY,
173                                                                    const Standard_ShortReal theZ) const
174 {
175   return theNormal.x() * (theX - theCenter.x())
176        + theNormal.y() * (theY - theCenter.y())
177        + theNormal.z() * (theZ - theCenter.z());
178 }
179
180 // =======================================================================
181 // method  : getGridAxes
182 // purpose : 
183 // =======================================================================
184 Standard_ExtCharacter OpenGl_GraduatedTrihedron::getGridAxes (const Standard_ShortReal theCorners[8],
185                                                               GridAxes& theGridAxes) const
186 {
187   // Find the farest corner
188   Standard_Byte aMaxIndex = 0;
189   Standard_ShortReal aMax = theCorners[aMaxIndex] > 0.0f ? theCorners[aMaxIndex] : 0.0f;
190
191   for (Standard_Byte anIt = 0; anIt < 8; ++anIt)
192   {
193     if (theCorners[anIt] > aMax)
194     {
195       aMax = theCorners[anIt];
196       aMaxIndex = anIt;
197     }
198   }
199
200   switch (aMaxIndex)
201   {
202     case 0: // (0,0,0)
203     {
204       theGridAxes.Origin = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
205       theGridAxes.Axes[0] = OpenGl_Vec3 (1.0f, 0.0f, 0.0f);
206       theGridAxes.Axes[1] = OpenGl_Vec3 (0.0f, 1.0f, 0.0f);
207       theGridAxes.Axes[2] = OpenGl_Vec3 (0.0f, 0.0f, 1.0f);
208
209       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
210       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
211       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
212
213       return OOZ_XOZ | OYO_XYO |
214              XOO_XYO | OOZ_OYZ |
215              XOO_XOZ | OYO_OYZ;
216     }
217     case 1: // (0,0,1)
218     {
219       theGridAxes.Origin = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
220       theGridAxes.Axes[0] = OpenGl_Vec3 (1.0f, 0.0f, 0.0f);
221       theGridAxes.Axes[1] = OpenGl_Vec3 (0.0f, 1.0f, 0.0f);
222       theGridAxes.Axes[2] = OpenGl_Vec3 (0.0f, 0.0f, -1.0f);
223
224       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
225       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
226       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMax.z());
227
228       return OOZ_XOZ | OYZ_XYZ |
229              OOZ_OYZ | XOZ_XYZ |
230              XOO_XOZ | OYO_OYZ;
231     }
232     case 2: // (0,1,0)
233     {
234       theGridAxes.Origin = OpenGl_Vec3 (myMin.x(), myMax.y(), myMin.z());
235       theGridAxes.Axes[0] = OpenGl_Vec3 (1.0f, 0.0f, 0.0f);
236       theGridAxes.Axes[1] = OpenGl_Vec3 (0.0f, -1.0f, 0.0f);
237       theGridAxes.Axes[2] = OpenGl_Vec3 (0.0f, 0.0f, 1.0f);
238
239       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
240       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
241       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
242
243       return OYO_XYO | OYZ_XYZ |
244              XOO_XYO | OOZ_OYZ |
245              XYO_XYZ | OYO_OYZ;
246     }
247     case 3: // (0,1,1)
248     {
249       theGridAxes.Origin = OpenGl_Vec3 (myMin.x(), myMax.y(), myMax.z());
250       theGridAxes.Axes[0] = OpenGl_Vec3 (1.0f, 0.0f, 0.0f);
251       theGridAxes.Axes[1] = OpenGl_Vec3 (0.0f, -1.0f, 0.0f);
252       theGridAxes.Axes[2] = OpenGl_Vec3 (0.0f, 0.0f, -1.0f);
253
254       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
255       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMin.x(), myMax.y(), myMin.z());
256       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
257
258       return OOZ_XOZ | OYZ_XYZ | OYO_XYO |
259              OOZ_OYZ | XOZ_XYZ |
260              OYO_OYZ | XYO_XYZ;
261     }
262     case 4: // (1,0,0)
263     {
264       theGridAxes.Origin = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
265       theGridAxes.Axes[0] = OpenGl_Vec3 (-1, 0, 0);
266       theGridAxes.Axes[1] = OpenGl_Vec3 (0, 1, 0);
267       theGridAxes.Axes[2] = OpenGl_Vec3 (0, 0, 1);
268
269       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMax.z());
270       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
271       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMin.z());
272
273       return OOZ_XOZ | OYO_XYO |
274              XOO_XYO | XOZ_XYZ |
275              XOO_XOZ | XYO_XYZ;
276     }
277     case 5: // (1,0,1)
278     {
279       theGridAxes.Origin = OpenGl_Vec3 (myMax.x(), myMin.y(), myMax.z());
280       theGridAxes.Axes[0] = OpenGl_Vec3 (-1, 0, 0);
281       theGridAxes.Axes[1] = OpenGl_Vec3 (0, 1, 0);
282       theGridAxes.Axes[2] = OpenGl_Vec3 (0, 0, -1);
283
284       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
285       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
286       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMin.x(), myMin.y(), myMax.z());
287
288       return OOZ_XOZ | OYZ_XYZ |
289              XOO_XYO | XOZ_XYZ | OOZ_OYZ |
290              XOO_XOZ | XYO_XYZ;
291     }
292     case 6: // (1,1,0)
293     {
294       theGridAxes.Origin = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
295       theGridAxes.Axes[0] = OpenGl_Vec3 (-1, 0, 0);
296       theGridAxes.Axes[1] = OpenGl_Vec3 (0, -1, 0);
297       theGridAxes.Axes[2] = OpenGl_Vec3 (0, 0, 1);
298
299       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
300       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMin.x(), myMax.y(), myMin.z());
301       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMin.z());
302
303       return OYO_XYO | OYZ_XYZ |
304              XOO_XYO | XOZ_XYZ |
305              XOO_XOZ | XYO_XYZ | OYO_OYZ;
306     }
307     case 7: // (1,1,1)
308     default:
309     {
310       theGridAxes.Origin = OpenGl_Vec3 (myMax.x(), myMax.y(), myMax.z());
311       theGridAxes.Axes[0] = OpenGl_Vec3 (-1, 0, 0);
312       theGridAxes.Axes[1] = OpenGl_Vec3 (0, -1, 0);
313       theGridAxes.Axes[2] = OpenGl_Vec3 (0, 0, -1);
314
315       theGridAxes.Ticks[0] = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
316       theGridAxes.Ticks[1] = OpenGl_Vec3 (myMax.x(), myMax.y(), myMin.z());
317       theGridAxes.Ticks[2] = OpenGl_Vec3 (myMax.x(), myMin.y(), myMax.z());
318
319       return OYO_XYO | OYZ_XYZ | OOZ_XOZ |
320              XOO_XYO | XOZ_XYZ | OOZ_OYZ |
321              XOO_XOZ | XYO_XYZ | OYO_OYZ;
322     }
323   }
324 }
325
326 // =======================================================================
327 // function : renderLine
328 // purpose  :
329 // =======================================================================
330 void OpenGl_GraduatedTrihedron::renderLine (const OpenGl_PrimitiveArray&    theLine,
331                                             const Handle(OpenGl_Workspace)& theWorkspace,
332                                             const OpenGl_Mat4& theMat,
333                                             const Standard_ShortReal theXt,
334                                             const Standard_ShortReal theYt,
335                                             const Standard_ShortReal theZt) const
336 {
337   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
338   OpenGl_Mat4 aMat (theMat);
339   Graphic3d_TransformUtils::Translate (aMat, theXt, theYt, theZt);
340   aContext->WorldViewState.SetCurrent (aMat);
341   aContext->ApplyWorldViewMatrix();
342   theLine.Render (theWorkspace);
343 }
344
345 // =======================================================================
346 // function : renderGridPlane
347 // purpose  :
348 // =======================================================================
349 void OpenGl_GraduatedTrihedron::renderGridPlane (const Handle(OpenGl_Workspace)& theWorkspace,
350                                                  const Standard_Integer& theIndex,
351                                                  const GridAxes& theGridAxes,
352                                                  OpenGl_Mat4& theMat) const
353 {
354   const Graphic3d_AxisAspect& aCurAspect = myData.AxisAspect (theIndex);
355   if (aCurAspect.TickmarksNumber() <= 0)
356   {
357     return;
358   }
359
360   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
361
362   Standard_ShortReal aStep = theGridAxes.Axes[theIndex].GetData()[theIndex]
363                             * (myMax.GetData()[theIndex] - myMin.GetData()[theIndex]) / aCurAspect.TickmarksNumber();
364
365   // NOTE:
366   // Get two other axes directions and draw lines Axis.TickmarksNumber times.
367   // Combining together from three axes, these lines will make a grid.
368   for (Standard_Integer anIter = 1; anIter <= 2; ++anIter)
369   {
370     OpenGl_Mat4 aMat (theMat);
371     const Standard_Integer anIndex = (theIndex + anIter) % 3;
372     const Axis& anAxis = myAxes[anIndex];
373     OpenGl_Vec3 aStart (theGridAxes.Origin);
374     if (theGridAxes.Axes[anIndex].GetData()[anIndex] < 0.0)
375     {
376       aStart.ChangeData()[anIndex] = myMin.GetData()[anIndex];
377     }
378
379     Graphic3d_TransformUtils::Translate (aMat, aStart.x(), aStart.y(), aStart.z());
380     aContext->WorldViewState.SetCurrent (aMat);
381     aContext->ApplyWorldViewMatrix();
382
383     const OpenGl_Vec3 aStepVec (myAxes[theIndex].Direction * aStep);
384     for (Standard_Integer anIt = myData.ToDrawAxes() ? 1 : 0; anIt < aCurAspect.TickmarksNumber(); ++anIt)
385     {
386       Graphic3d_TransformUtils::Translate (aMat, aStepVec.x(), aStepVec.y(), aStepVec.z());
387       aContext->WorldViewState.SetCurrent (aMat);
388       aContext->ApplyWorldViewMatrix();
389       anAxis.Line.Render (theWorkspace);
390     }
391   }
392 }
393
394 // =======================================================================
395 // function : renderAxis
396 // purpose  :
397 // =======================================================================
398 void OpenGl_GraduatedTrihedron::renderAxis (const Handle(OpenGl_Workspace)& theWorkspace,
399                                             const Standard_Integer& theIndex,
400                                             const OpenGl_Mat4& theMat) const
401 {
402   const Axis& anAxis = myAxes[theIndex];
403
404   theWorkspace->SetAspectLine (&anAxis.LineAspect);
405   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
406
407   // Reset transformations
408   aContext->WorldViewState.SetCurrent (theMat);
409   aContext->ApplyWorldViewMatrix();
410
411   // Render arrow
412   OpenGl_Vec3 anArrowVec = myMin + anAxis.Direction * (myMax - myMin);
413
414   Graphic3d_TransformPers aTransMode;
415   aTransMode.Flags = Graphic3d_TMF_ZoomPers;
416   aTransMode.Point.x() = anArrowVec.x();
417   aTransMode.Point.y() = anArrowVec.y();
418   aTransMode.Point.z() = anArrowVec.z();
419
420   const OpenGl_Mat4& aProjection = aContext->ProjectionState.Current();
421   const OpenGl_Mat4& aWorldView  = aContext->WorldViewState.Current();
422   const Standard_Integer aWidth  = theWorkspace->Width();
423   const Standard_Integer aHeight = theWorkspace->Height();
424
425   // Take into account Transform Persistence
426   aContext->ModelWorldState.SetCurrent (aTransMode.Compute (theWorkspace->View()->Camera(), aProjection, aWorldView, aWidth, aHeight));
427   aContext->ApplyModelViewMatrix();
428
429   anAxis.Arrow.Render (theWorkspace);
430
431   // Get current Model-View and Projection states
432   OpenGl_Mat4 aModelMat;
433   OpenGl_Mat4 aProjMat;
434   aModelMat.Convert (aContext->WorldViewState.Current() * aContext->ModelWorldState.Current());
435   aProjMat .Convert (aContext->ProjectionState.Current());
436
437   // Get the window's (fixed) coordinates for before matrices modifications
438   OpenGl_Vec3 aEndPoint = -anAxis.Direction * myData.ArrowsLength();
439   OpenGl_Vec3 aWinPoint;
440   Graphic3d_TransformUtils::Project<Standard_ShortReal> (aEndPoint.x(), aEndPoint.y(), aEndPoint.z(),
441                                                          aModelMat, aProjMat, aContext->Viewport(),
442                                                          aWinPoint.x(), aWinPoint.y(), aWinPoint.z());
443
444   aContext->ModelWorldState.SetIdentity();
445   aModelMat.Convert (aContext->WorldViewState.Current());
446   aProjMat .Convert (aContext->ProjectionState.Current());
447
448   // Get start point of zoom persistent arrow
449   OpenGl_Vec3 anArrowStart;
450   Graphic3d_TransformUtils::UnProject<Standard_ShortReal> (aWinPoint.x(), aWinPoint.y(), aWinPoint.z(),
451                                                            aModelMat, aProjMat, aContext->Viewport(),
452                                                            anArrowStart.x(), anArrowStart.y(), anArrowStart.z());
453   // Render axis line
454   aModelMat = theMat;
455   Graphic3d_TransformUtils::Translate (aModelMat, myMin.x(), myMin.y(), myMin.z());
456
457   Standard_ShortReal aScaleFactor = ( (anArrowStart - myMin)*anAxis.Direction ).Modulus()
458                                      / (anAxis.Direction * (myMax - myMin) ).Modulus();
459   OpenGl_Vec3 aScaleAxes = anAxis.Direction * aScaleFactor;
460   Graphic3d_TransformUtils::Scale (aModelMat, aScaleAxes.x(), aScaleAxes.y(), aScaleAxes.z());
461
462   aContext->WorldViewState.SetCurrent (aModelMat);
463   aContext->ApplyWorldViewMatrix();
464   anAxis.Line.Render (theWorkspace);
465 }
466
467 // =======================================================================
468 // function : renderTickmarkTextLabels
469 // purpose  :
470 // =======================================================================
471 void OpenGl_GraduatedTrihedron::renderTickmarkLabels (const Handle(OpenGl_Workspace)& theWorkspace,
472                                                       const OpenGl_Mat4& theMat,
473                                                       const Standard_Integer theIndex,
474                                                       const GridAxes& theGridAxes,
475                                                       const Standard_ShortReal theDpix) const
476 {
477   const Graphic3d_AxisAspect& aCurAspect = myData.AxisAspect (theIndex);
478   if (!aCurAspect.ToDrawName() && !aCurAspect.ToDrawValues())
479   {
480     return;
481   }
482
483   Standard_Character aTextValue[128];
484   const Axis& anAxis = myAxes[theIndex];
485   const OpenGl_Vec3 aSizeVec (myMax - myMin);
486   Standard_ShortReal aStep = theGridAxes.Axes[theIndex].GetData()[theIndex]
487                        * (myMax.GetData()[theIndex] - myMin.GetData()[theIndex]) / aCurAspect.TickmarksNumber();
488
489   OpenGl_Vec3 aDir = (theGridAxes.Ticks[theIndex] - theGridAxes.Origin).Normalized();
490   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
491
492   if (aCurAspect.ToDrawTickmarks() && aCurAspect.TickmarksNumber() > 0)
493   {
494     theWorkspace->SetAspectLine (&myGridLineAspect);
495
496     OpenGl_Mat4 aModelMat (theMat);
497
498     anAxis.InitTickmark (aContext, aDir * (Standard_ShortReal) aCurAspect.TickmarksLength() * theDpix);
499     Graphic3d_TransformUtils::Translate (aModelMat, theGridAxes.Ticks[theIndex].x(),
500                                                     theGridAxes.Ticks[theIndex].y(),
501                                                     theGridAxes.Ticks[theIndex].z());
502     aContext->WorldViewState.SetCurrent (aModelMat);
503     aContext->ApplyWorldViewMatrix();
504     OpenGl_Vec3 aStepVec = anAxis.Direction * aStep;
505     for (Standard_Integer anIter = 0; anIter <= aCurAspect.TickmarksNumber(); ++anIter)
506     {
507       anAxis.Tickmark.Render (theWorkspace);
508       Graphic3d_TransformUtils::Translate (aModelMat, aStepVec.x(), aStepVec.y(), aStepVec.z());
509       aContext->WorldViewState.SetCurrent (aModelMat);
510       aContext->ApplyWorldViewMatrix();
511     }
512   }
513
514   // Restore matrix
515   aContext->WorldViewState.SetCurrent (theMat);
516   aContext->ApplyWorldViewMatrix();
517
518   if (aCurAspect.ToDrawName())
519   {
520     Standard_Real anOffset = aCurAspect.NameOffset() + aCurAspect.TickmarksLength();
521
522     OpenGl_Vec3 aMiddle (theGridAxes.Ticks[theIndex] + aSizeVec * theGridAxes.Axes[theIndex] * 0.5f + aDir * (Standard_ShortReal)(theDpix * anOffset));
523
524     myAspectLabels.Aspect()->SetColor (anAxis.NameColor);
525     theWorkspace->SetAspectText (&myAspectLabels);
526     anAxis.Label.SetPosition (aMiddle);
527     anAxis.Label.Render (theWorkspace);
528   }
529
530   if (aCurAspect.ToDrawValues() && aCurAspect.TickmarksNumber() > 0)
531   {
532     myAspectValues.Aspect()->SetColor (anAxis.LineAspect.Aspect()->Color());
533     theWorkspace->SetAspectText (&myAspectValues);
534     Standard_Real anOffset = aCurAspect.ValuesOffset() + aCurAspect.TickmarksLength();
535
536     for (Standard_Integer anIt = 0; anIt <= aCurAspect.TickmarksNumber(); ++anIt)
537     {
538       sprintf (aTextValue, "%g", theGridAxes.Ticks[theIndex].GetData()[theIndex] + anIt * aStep);
539       OpenGl_Vec3 aPos (theGridAxes.Ticks[theIndex] + anAxis.Direction* (Standard_ShortReal) (anIt * aStep) + aDir * (Standard_ShortReal) (theDpix * anOffset));
540       myLabelValues.Init (theWorkspace->GetGlContext(), aTextValue, aPos);
541       myLabelValues.Render (theWorkspace);
542     }
543   }
544 }
545
546 // =======================================================================
547 // function : Render
548 // purpose  : call_graduatedtrihedron_redraw
549 // =======================================================================
550 void OpenGl_GraduatedTrihedron::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
551 {
552   const Handle(OpenGl_Context)& aContext = theWorkspace->GetGlContext();
553   if (!myIsInitialized)
554   {
555     initGlResources (theWorkspace->GetGlContext());
556     myIsInitialized = Standard_True;
557   }
558
559   // Update boundary box
560   OpenGl_Vec3 anOldMin = myMin;
561   OpenGl_Vec3 anOldMax = myMax;
562
563   if (myData.CubicAxesCallback)
564   {
565     myData.CubicAxesCallback (myData.PtrView);
566     if (!myAxes[0].Line.IsInitialized()
567      || !myAxes[1].Line.IsInitialized()
568      || !myAxes[2].Line.IsInitialized()
569      ||  OpenGl_Vec3 (anOldMin - myMin).Modulus() > Precision::Confusion()
570      ||  OpenGl_Vec3 (anOldMax - myMax).Modulus() > Precision::Confusion())
571     {
572       myAxes[0].InitLine (aContext, OpenGl_Vec3 (myMax.x() - myMin.x(), 0.0f, 0.0f));
573       myAxes[1].InitLine (aContext, OpenGl_Vec3 (0.0f, myMax.y() - myMin.y(), 0.0f));
574       myAxes[2].InitLine (aContext, OpenGl_Vec3 (0.0f, 0.0f, myMax.z() - myMin.z()));
575     }
576   }
577
578   // Find the farest point of bounding box
579
580   // Get normal of the view out of user and distance corresponding to 1 pixel
581   OpenGl_Vec3 aNormal;
582   Standard_ShortReal aDpix = getNormal (aContext, aNormal);
583   aNormal.Normalize();
584
585   // Get central point of bounding box
586   OpenGl_Vec3 aCenter;
587   aCenter = (myMin + myMax) * 0.5f;
588
589   // Check distance to corners of bounding box along the normal
590   Standard_ShortReal aCorners[8];
591   aCorners[0] = getDistanceToCorner (aNormal, aCenter, myMin.x(), myMin.y(), myMin.z());
592   aCorners[1] = getDistanceToCorner (aNormal, aCenter, myMin.x(), myMin.y(), myMax.z());
593   aCorners[2] = getDistanceToCorner (aNormal, aCenter, myMin.x(), myMax.y(), myMin.z());
594   aCorners[3] = getDistanceToCorner (aNormal, aCenter, myMin.x(), myMax.y(), myMax.z());
595   aCorners[4] = getDistanceToCorner (aNormal, aCenter, myMax.x(), myMin.y(), myMin.z());
596   aCorners[5] = getDistanceToCorner (aNormal, aCenter, myMax.x(), myMin.y(), myMax.z());
597   aCorners[6] = getDistanceToCorner (aNormal, aCenter, myMax.x(), myMax.y(), myMin.z());
598   aCorners[7] = getDistanceToCorner (aNormal, aCenter, myMax.x(), myMax.y(), myMax.z());
599
600   // NOTE:
601   // (0, 0, 1), (0, 1, 0) and (0, 0, 1) directions from (myMin.x(), Ymin, Zmin) point
602   // are reserved for trihedron axes.
603   // So for the grid here are 9 edges of cube,
604   // and, depending on the farest point, 2 or 3 of them may not be drawn
605   // if they overlap displayed model.
606   
607   // Write an axes state what axes of bounding box are to be drawn
608   GridAxes aGridAxes;
609   Standard_ExtCharacter anAxesState = getGridAxes (aCorners, aGridAxes);
610
611   // Remember current aspects
612   const OpenGl_AspectLine* anOldAspectLine = theWorkspace->AspectLine();
613   const OpenGl_AspectText* anOldAspectText = theWorkspace->AspectText();
614
615   OpenGl_Mat4 aModelMatrix;
616   aModelMatrix.Convert (aContext->WorldViewState.Current());
617
618   // Remember model-view matrix
619   aContext->WorldViewState.Push();
620   aContext->WorldViewState.SetCurrent (aModelMatrix);
621   aContext->ApplyWorldViewMatrix();
622
623   if (myData.ToDrawGrid())
624   {
625     theWorkspace->SetAspectLine (&myGridLineAspect);
626
627     // render grid edges
628     if (anAxesState & XOO_XYO)
629     {
630       renderLine (myAxes[1].Line, theWorkspace, aModelMatrix, myMax.x(), myMin.y(), myMin.z());
631     }
632
633     if (anAxesState & XOO_XOZ)
634     {
635       renderLine (myAxes[2].Line,theWorkspace, aModelMatrix, myMax.x(), myMin.y(), myMin.z());
636     }
637
638     if (anAxesState & OYO_OYZ)
639     {
640       renderLine (myAxes[2].Line, theWorkspace, aModelMatrix, myMin.x(), myMax.y(), myMin.z());
641     }
642
643     if (anAxesState & OYO_XYO)
644     {
645       renderLine (myAxes[0].Line, theWorkspace, aModelMatrix, myMin.x(), myMax.y(), myMin.z());
646     }
647
648     if (anAxesState & OOZ_XOZ)
649     {
650       renderLine (myAxes[0].Line, theWorkspace, aModelMatrix, myMin.z(), myMin.y(), myMax.z());
651     }
652
653     if (anAxesState & OOZ_OYZ)
654     {
655       renderLine (myAxes[1].Line, theWorkspace, aModelMatrix, myMin.x(), myMin.y(), myMax.z());
656     }
657
658     if (anAxesState & OYZ_XYZ)
659     {
660       renderLine (myAxes[0].Line, theWorkspace, aModelMatrix, myMin.x(), myMax.y(), myMax.z());
661     }
662
663     if (anAxesState & XOZ_XYZ)
664     {
665       renderLine (myAxes[1].Line, theWorkspace, aModelMatrix, myMax.x(), myMin.y(), myMax.z());
666     }
667
668     if (anAxesState & XYO_XYZ)
669     {
670       renderLine (myAxes[2].Line, theWorkspace, aModelMatrix, myMax.x(), myMax.y(), myMin.z());
671     }
672
673     for (Standard_Integer anIter = 0 ; anIter < 3; ++anIter)
674     {
675       renderGridPlane (theWorkspace, anIter, aGridAxes, aModelMatrix);
676     }
677   }
678
679   // Axes (arrows)
680   if (myData.ToDrawAxes())
681   {
682     for (Standard_Integer anIter = 0; anIter < 3; ++anIter)
683     {
684       renderAxis (theWorkspace, anIter, aModelMatrix);
685     }
686   }
687
688   // Names of axes & values
689   for (Standard_Integer anIter = 0; anIter < 3; ++anIter)
690   {
691     // Restore current matrix
692     aContext->WorldViewState.SetCurrent (aModelMatrix);
693     aContext->ApplyWorldViewMatrix();
694     renderTickmarkLabels (theWorkspace, aModelMatrix, anIter, aGridAxes, aDpix);
695   }
696
697   theWorkspace->SetAspectLine (anOldAspectLine);
698   theWorkspace->SetAspectText (anOldAspectText);
699
700   aContext->WorldViewState.Pop();
701   aContext->ApplyWorldViewMatrix();
702 }
703
704 // =======================================================================
705 // method  : SetMinMax
706 // purpose :
707 // =======================================================================
708 void OpenGl_GraduatedTrihedron::SetMinMax (const OpenGl_Vec3& theMin, const OpenGl_Vec3& theMax)
709 {
710   myMin = theMin;
711   myMax = theMax;
712 }
713
714 // =======================================================================
715 // method  : OpenGl_GraduatedTrihedron::Axis constructor
716 // purpose :
717 // =======================================================================
718 OpenGl_GraduatedTrihedron::Axis::Axis (const Graphic3d_AxisAspect& theAspect,
719                                        const OpenGl_Vec3&          theDirection)
720 : Direction (theDirection),
721   Label     (NCollection_String ((Standard_Utf16Char* )theAspect.Name().ToExtString()).ToCString(), theDirection, THE_LABEL_PARAMS),
722   Tickmark  (NULL),
723   Line      (NULL),
724   Arrow     (NULL)
725 {
726   NameColor = theAspect.NameColor();
727   LineAspect.Aspect()->SetColor (theAspect.Color());
728 }
729
730 // =======================================================================
731 // method  : OpenGl_GraduatedTrihedron::Axis::~Axis
732 // purpose :
733 // =======================================================================
734 OpenGl_GraduatedTrihedron::Axis::~Axis()
735 {
736   //
737 }
738
739 // =======================================================================
740 // method  : OpenGl_GraduatedTrihedron::Axis operator=
741 // purpose :
742 // =======================================================================
743 OpenGl_GraduatedTrihedron::Axis& OpenGl_GraduatedTrihedron::Axis::operator= (const Axis& theOther)
744 {
745   Direction  = theOther.Direction;
746   NameColor  = theOther.NameColor;
747   LineAspect = theOther.LineAspect;
748   Label      = theOther.Label;
749
750   Line    .InitBuffers (NULL, Graphic3d_TOPA_SEGMENTS,  theOther.Line.Indices(),     theOther.Line.Attributes(),     theOther.Line.Bounds());
751   Tickmark.InitBuffers (NULL, Graphic3d_TOPA_SEGMENTS,  theOther.Tickmark.Indices(), theOther.Tickmark.Attributes(), theOther.Tickmark.Bounds());
752   Arrow   .InitBuffers (NULL, Graphic3d_TOPA_POLYLINES, theOther.Arrow.Indices(),    theOther.Arrow.Attributes(),    theOther.Arrow.Bounds());
753   return *this;
754 }
755
756 // =======================================================================
757 // method  : InitArrow
758 // purpose :
759 // =======================================================================
760 void OpenGl_GraduatedTrihedron::Axis::InitArrow (const Handle(OpenGl_Context)& theContext,
761                                                  const Standard_ShortReal theLength,
762                                                  const OpenGl_Vec3& theNormal) const
763 {
764   // Draw from the end point of the aris
765   OpenGl_Vec3 aLengthVec = -Direction * theLength;
766
767   // Radial direction to the arrow
768   OpenGl_Vec3 aRadial = OpenGl_Vec3::Cross (this->Direction, theNormal);
769   if (aRadial.Modulus() < (Standard_ShortReal) Precision::Confusion())
770   {
771     return;
772   }
773   aRadial = aRadial.Normalized() * theLength * 0.2f;
774
775   // Initialize arrow primitive array
776   // Make loop from polyline
777   const OpenGl_Vec3 aPoint1 = aRadial + aLengthVec;
778   const OpenGl_Vec3 aPoint2 (0.0f, 0.0f, 0.0f);
779   const OpenGl_Vec3 aPoint3 = -aRadial + aLengthVec;
780
781   Handle(Graphic3d_ArrayOfPolylines) anArray = new Graphic3d_ArrayOfPolylines (4);
782   anArray->AddVertex (aPoint1);
783   anArray->AddVertex (aPoint2);
784   anArray->AddVertex (aPoint3);
785   anArray->AddVertex (aPoint1);
786
787   Arrow.InitBuffers (theContext, Graphic3d_TOPA_POLYLINES,
788                      anArray->Indices(), anArray->Attributes(), anArray->Bounds());
789 }
790
791 // =======================================================================
792 // function : InitTickmark
793 // purpose  :
794 // =======================================================================
795 void OpenGl_GraduatedTrihedron::Axis::InitTickmark (const Handle(OpenGl_Context)& theContext,
796                                                     const OpenGl_Vec3& theDir) const
797 {
798
799   Handle(Graphic3d_ArrayOfSegments) anArray = new Graphic3d_ArrayOfSegments (2);
800   anArray->AddVertex (0.0f, 0.0f, 0.0f);
801   anArray->AddVertex (theDir);
802   Tickmark.InitBuffers (theContext, Graphic3d_TOPA_SEGMENTS,
803                         anArray->Indices(), anArray->Attributes(), anArray->Bounds());
804
805 }
806
807 // =======================================================================
808 // function : InitLine
809 // purpose  :
810 // =======================================================================
811 void OpenGl_GraduatedTrihedron::Axis::InitLine (const Handle(OpenGl_Context)& theContext,
812                                                 const OpenGl_Vec3& theDir) const
813 {
814
815   Handle(Graphic3d_ArrayOfSegments) anArray = new Graphic3d_ArrayOfSegments (2);
816   anArray->AddVertex (0.0f, 0.0f, 0.0f);
817   anArray->AddVertex (theDir);
818
819   Line.InitBuffers (theContext, Graphic3d_TOPA_SEGMENTS,
820                     anArray->Indices(), anArray->Attributes(), anArray->Bounds());
821 }
822
823 // =======================================================================
824 // function : Release
825 // purpose  :
826 // =======================================================================
827 void OpenGl_GraduatedTrihedron::Axis::Release (OpenGl_Context* theCtx)
828 {
829   Label   .Release (theCtx);
830   Tickmark.Release (theCtx);
831   Line    .Release (theCtx);
832   Arrow   .Release (theCtx);
833 }