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