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