0012121: Optimization of existing selection classes
[occt.git] / src / OpenGl / OpenGl_graduatedtrihedron.cxx
1 // File:      OpenGl_graduatedtrihedron.cxx
2 // Created:   6 March 2011
3 // Author:    Sergey ZERCHANINOV
4 // Copyright: OPEN CASCADE SA 2011
5
6 #include <OpenGl_tgl_all.hxx>
7 #include <OpenGl_graduatedtrihedron.hxx>
8
9 #include <stddef.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <math.h>
13
14 #include <GL/gl.h>
15 #include <GL/glu.h>
16
17 #include <InterfaceGraphic_Graphic3d.hxx>
18 #include <InterfaceGraphic_Aspect.hxx>
19 #include <InterfaceGraphic_Visual3d.hxx>
20
21 #include <OpenGl_tgl_funcs.hxx>
22 #include <OpenGl_tgl_subrs.hxx>
23 #include <OpenGl_TextRender.hxx>
24
25 #ifdef HAVE_CONFIG_H
26 #include <config.h>
27 #endif
28 #ifdef HAVE_STRING_H
29 #include <string.h>
30 #endif
31
32 struct TEL_GRADUATEDTRIHEDRON_DATA
33 {
34   int WsId;
35   wchar_t *xname, *yname, *zname;
36   unsigned char xdrawname, ydrawname, zdrawname;
37   unsigned char xdrawvalues, ydrawvalues, zdrawvalues;
38   unsigned char drawgrid;
39   unsigned char drawaxes;
40   unsigned int nbx, nby, nbz;
41   int xoffset, yoffset, zoffset;
42   int xaxisoffset, yaxisoffset, zaxisoffset;
43   unsigned char xdrawtickmarks, ydrawtickmarks, zdrawtickmarks;
44   unsigned int xtickmarklength, ytickmarklength, ztickmarklength;
45   float gridcolor[3];
46   float xnamecolor[3];
47   float ynamecolor[3];
48   float znamecolor[3];
49   float xcolor[3];
50   float ycolor[3];
51   float zcolor[3];
52   char* fontOfNames;
53   OSD_FontAspect styleOfNames;
54   int sizeOfNames;
55   char* fontOfValues;
56   OSD_FontAspect styleOfValues;
57   int sizeOfValues;
58   minMaxValuesCallback cbCubicAxes;
59   void* ptrVisual3dView;
60   IMPLEMENT_MEMORY_OPERATORS
61 };
62 typedef TEL_GRADUATEDTRIHEDRON_DATA* tel_graduatedtrihedron_data;
63
64 /* Graduated trihedron data */
65 static int nbWsIds = 0; /* Number of the views (size of the arrays below */
66 static tel_graduatedtrihedron_data* graduatedTrihedronData = 0; /* The array contains graduated trihedron data of all views */
67
68 /* Bounding box */
69 float xmin = 0.0f, ymin = 0.0f, zmin = 0.0f, xmax = 100.0f, ymax = 100.0f, zmax = 100.0f;
70
71 static void copyData(const Graphic3d_CGraduatedTrihedron *fromData, TEL_GRADUATEDTRIHEDRON_DATA* toData)
72 {
73   int len;
74
75   /* Names of axes */
76   /* X-name */
77   len = fromData->xname.Length();
78   if (len)
79   {
80     Standard_ExtString iname = fromData->xname.ToExtString();
81     toData->xname = new wchar_t[len+1];
82     len = 0; while (toData->xname[len] = (wchar_t)(iname[len])) len++;
83   }
84   else
85     toData->xname = NULL;
86   /* Y-name */
87   len = fromData->yname.Length();
88   if (len)
89   {
90     Standard_ExtString iname = fromData->yname.ToExtString();
91     toData->yname = new wchar_t[len+1];
92     len = 0; while (toData->yname[len] = (wchar_t)(iname[len])) len++;
93   }
94   else
95     toData->yname = NULL;
96   /* Z-name */
97   len = fromData->zname.Length();
98   if (len)
99   {
100     Standard_ExtString iname = fromData->zname.ToExtString();
101     toData->zname = new wchar_t[len+1];
102     len = 0; while (toData->zname[len] = (wchar_t)(iname[len])) len++;
103   }
104   else
105     toData->zname = NULL;
106   /* Draw names */
107   toData->xdrawname = fromData->xdrawname;
108   toData->ydrawname = fromData->ydrawname; 
109   toData->zdrawname = fromData->zdrawname;
110   /* Draw values */
111   toData->xdrawvalues = fromData->xdrawvalues; 
112   toData->ydrawvalues = fromData->ydrawvalues; 
113   toData->zdrawvalues = fromData->zdrawvalues;
114   /* Draw grid */
115   toData->drawgrid = fromData->drawgrid;
116   /* Draw axes */
117   toData->drawaxes = fromData->drawaxes;
118   /* Number of splits along axes */
119   toData->nbx = fromData->nbx; 
120   toData->nby = fromData->nby; 
121   toData->nbz = fromData->nbz;
122   /* Offset for drawing values */
123   toData->xoffset = fromData->xoffset; 
124   toData->yoffset = fromData->yoffset; 
125   toData->zoffset = fromData->zoffset;
126   /* Offset for drawing names of axes */
127   toData->xaxisoffset = fromData->xaxisoffset;
128   toData->yaxisoffset = fromData->yaxisoffset; 
129   toData->zaxisoffset = fromData->zaxisoffset;
130   /* Draw tickmarks */
131   toData->xdrawtickmarks = fromData->xdrawtickmarks; 
132   toData->ydrawtickmarks = fromData->ydrawtickmarks; 
133   toData->zdrawtickmarks = fromData->zdrawtickmarks;
134   /* Length of tickmarks */
135   toData->xtickmarklength = fromData->xtickmarklength; 
136   toData->ytickmarklength = fromData->ytickmarklength; 
137   toData->ztickmarklength = fromData->ztickmarklength;
138   /* Grid color */
139   toData->gridcolor[0] = (float) fromData->gridcolor.Red();
140   toData->gridcolor[1] = (float) fromData->gridcolor.Green();
141   toData->gridcolor[2] = (float) fromData->gridcolor.Blue();
142   /* X name color */
143   toData->xnamecolor[0] = (float) fromData->xnamecolor.Red();
144   toData->xnamecolor[1] = (float) fromData->xnamecolor.Green();
145   toData->xnamecolor[2] = (float) fromData->xnamecolor.Blue();
146   /* Y name color */
147   toData->ynamecolor[0] = (float) fromData->ynamecolor.Red();
148   toData->ynamecolor[1] = (float) fromData->ynamecolor.Green();
149   toData->ynamecolor[2] = (float) fromData->ynamecolor.Blue();
150   /* Z name color */
151   toData->znamecolor[0] = (float) fromData->znamecolor.Red();
152   toData->znamecolor[1] = (float) fromData->znamecolor.Green();
153   toData->znamecolor[2] = (float) fromData->znamecolor.Blue();
154   /* X color of axis and values */
155   toData->xcolor[0] = (float) fromData->xcolor.Red();
156   toData->xcolor[1] = (float) fromData->xcolor.Green();
157   toData->xcolor[2] = (float) fromData->xcolor.Blue();
158   /* Y color of axis and values */
159   toData->ycolor[0] = (float) fromData->ycolor.Red();
160   toData->ycolor[1] = (float) fromData->ycolor.Green();
161   toData->ycolor[2] = (float) fromData->ycolor.Blue();
162   /* Z color of axis and values */
163   toData->zcolor[0] = (float) fromData->zcolor.Red();
164   toData->zcolor[1] = (float) fromData->zcolor.Green();
165   toData->zcolor[2] = (float) fromData->zcolor.Blue();
166   /* Font name of names of axes: Courier, Arial, ... */
167   len = fromData->fontOfNames.Length();
168   toData->fontOfNames = new char[len+1];
169   if (len)
170     strcpy(toData->fontOfNames, fromData->fontOfNames.ToCString());
171   else
172     toData->fontOfNames[0] = L'\0';
173   /* Style of names of axes: OSD_FA_Regular, OSD_FA_Bold, ... */
174   toData->styleOfNames = fromData->styleOfNames;
175   /* Size of names of axes: 8, 10, 12, 14, ... */
176   toData->sizeOfNames = fromData->sizeOfNames;
177   /* Font name of values: Courier, Arial, ... */
178   len = fromData->fontOfValues.Length();
179   toData->fontOfValues = new char[len+1];
180   if (len)
181     strcpy(toData->fontOfValues, fromData->fontOfValues.ToCString());
182   else
183     toData->fontOfValues[0] = L'\0';
184   /* Style of values: OSD_FA_Regular, OSD_FA_Bold, ... */
185   toData->styleOfValues = fromData->styleOfValues;
186   /* Size of values: 8, 10, 12, 14, ... */
187   toData->sizeOfValues = fromData->sizeOfValues;
188   /* Callback - updater of boundary box */
189   toData->cbCubicAxes = fromData->cbCubicAxes;
190   toData->ptrVisual3dView = fromData->ptrVisual3dView;
191 }
192
193 static void freeData()
194 {
195   if (nbWsIds)
196   {
197     int i = 0;
198     tel_graduatedtrihedron_data gtdata;
199     for (i = 0; i < nbWsIds; i++)
200     {
201       gtdata = graduatedTrihedronData[i];
202
203       // Names of axes
204       if (gtdata->xname)
205         delete[] gtdata->xname;
206       if (gtdata->yname)
207         delete[] gtdata->yname;
208       if (gtdata->zname)
209         delete[] gtdata->zname;
210
211       // Fonts
212       if (gtdata->fontOfNames)
213         delete[] gtdata->fontOfNames;
214       if (gtdata->fontOfValues)
215         delete[] gtdata->fontOfValues;
216
217       delete gtdata;
218     }
219     delete graduatedTrihedronData;
220     graduatedTrihedronData = 0;
221     nbWsIds = 0;
222   }
223 }
224
225 static int getGraduatedTrihedronDataIndex(int WsId)
226 {
227   int i = 0;
228   for (; i < nbWsIds; i++)
229   {
230     if (graduatedTrihedronData[i]->WsId == WsId)
231       return i;
232   }
233   return -1;
234 }
235
236 /* Normal of the view (not normalized!) */
237 static float getNormal(float* normal) 
238 {
239         GLint viewport[4];
240         GLdouble model_matrix[16], proj_matrix[16];
241         double x1, y1, z1, x2, y2, z2, x3, y3, z3;
242     double dx1, dy1, dz1, dx2, dy2, dz2, width;
243
244         glGetDoublev(GL_MODELVIEW_MATRIX,  model_matrix);
245         glGetDoublev(GL_PROJECTION_MATRIX, proj_matrix);
246         glGetIntegerv(GL_VIEWPORT, viewport);
247
248         gluUnProject(viewport[0], viewport[1], 0., model_matrix, proj_matrix, viewport, &x1, &y1, &z1);
249         gluUnProject(viewport[0] + viewport[2], viewport[1], 0., model_matrix, proj_matrix, viewport, &x2, &y2, &z2);
250         gluUnProject(viewport[0], viewport[1] + viewport[3], 0., model_matrix, proj_matrix, viewport, &x3, &y3, &z3);
251
252     /* Normal out of user is p1p3^p1p2 */
253     dx1 = x3 - x1; dy1 = y3 - y1; dz1 = z3 - z1;
254     dx2 = x2 - x1; dy2 = y2 - y1; dz2 = z2 - z1;
255     normal[0] = (float) (dy1 * dz2 - dz1 * dy2);
256         normal[1] = (float) (dz1 * dx2 - dx1 * dz2);
257         normal[2] = (float) (dx1 * dy2 - dy1 * dx2);
258
259     /* Distance corresponding to 1 pixel */
260     width = sqrt(dx2 * dx2 + dy2 * dy2 + dz2 * dz2);
261     return (float) width / (float) viewport[2];
262 }
263
264 static float getDistance2Corner(float* normal, float* center, float x, float y, float z)
265 {
266     return normal[0] * (x - center[0]) + normal[1] * (y - center[1]) + normal[2] * (z - center[2]);
267 }
268
269 static char getFarestCorner(float d000, float d100, float d010, float d001, 
270                             float d110, float d101, float d011, float d111)
271 {
272     if (d000 > 0.0f && 
273         d000 > d100 && d000 > d010 && d000 > d001 && d000 > d110 && 
274         d000 > d101 && d000 > d011 && d000 > d111)
275     {
276         return 1;
277     }
278     else if (d100 > 0.0f &&
279              d100 > d000 && d100 > d010 && d100 > d001 && d100 > d110 && 
280              d100 > d101 && d100 > d011 && d100 > d111)
281     {
282         return 2;
283     }
284     else if (d010 > 0.0f &&
285              d010 > d000 && d010 > d100 && d010 > d001 && d010 > d110 && 
286              d010 > d101 && d010 > d011 && d010 > d111)
287     {
288         return 3;
289     }
290     else if (d001 > 0.0f &&
291              d001 > d000 && d001 > d100 && d001 > d010 && d001 > d110 && 
292              d001 > d101 && d001 > d011 && d001 > d111)
293     {
294         return 4;
295     }
296     else if (d110 > 0.0f &&
297              d110 > d000 && d110 > d100 && d110 > d010 && d110 > d001 && 
298              d110 > d101 && d110 > d011 && d110 > d111)
299     {
300         return 5;
301     }
302     else if (d101 > 0.0f &&
303              d101 > d000 && d101 > d100 && d101 > d010 && d101 > d001 && 
304              d101 > d110 && d101 > d011 && d101 > d111)
305     {
306         return 6;
307     }
308     else if (d011 > 0.0f &&
309              d011 > d000 && d011 > d100 && d011 > d010 && d011 > d001 && 
310              d011 > d110 && d011 > d101 && d011 > d111)
311     {
312         return 7;
313     }
314     return 8; /* d111 */
315 }
316
317 static void drawText(const wchar_t* text, char* font, OSD_FontAspect style, int size, float x, float y, float z)
318 {
319   OpenGl_TextRender* textRenderer = OpenGl_TextRender::instance();
320   const GLuint fontBase = textRenderer->FindFont((Tchar*) font, style, (float) size);
321   textRenderer->RenderText(text, fontBase, 0, x, y, z);
322
323 /* 4 OCC 6.3.1 and older:
324     GLuint fontBase;
325
326 #ifndef WNT
327      fontBase = tXfmsetfont (1.0F, 1.0F);
328 #else
329      fontBase = WNTSetFont (1.0F, 1.0F);
330 #endif
331
332 #ifndef WNT
333      tXfmprstr(text, fontBase, x, y, z);
334 #else
335      WNTPuts(text, fontBase, 0, x, y, z);
336 #endif
337 */
338 }
339
340 static void drawArrow(float x1, float y1, float z1, 
341                       float x2, float y2, float z2,
342                       float xn, float yn, float zn)
343 {
344     float h, r;
345     float xa, ya, za;
346     float x0, y0, z0;
347     float xr, yr, zr;
348     float xa1, ya1, za1, xa2, ya2, za2;
349
350     /* Start of arrow: at 10% from the end */
351     x0 = x1 + 0.9f * (x2 - x1); y0 = y1 + 0.9f * (y2 - y1); z0 = z1 + 0.9f * (z2 - z1);
352
353     /* Base of the arrow */
354     xa = (x2 - x0); ya = (y2 - y0); za = (z2 - z0);
355
356     /* Height of the arrow */
357     h = sqrtf(xa * xa + ya * ya + za * za);
358     if (h <= 0.0f)
359         return;
360     xa = xa / h; ya = ya / h; za = za / h;
361
362     /* Radial direction to the arrow */
363     xr = ya * zn - za * yn;
364     yr = za * xn - xa * zn;
365     zr = xa * yn - ya * xn;
366
367     /* Normalize the radial vector */
368     r = sqrtf(xr * xr + yr * yr + zr * zr);
369     if (r <= 0.0f)
370         return;
371     xr = xr / r; yr = yr / r; zr = zr / r;
372
373     /* First point of the base of the arrow */
374     r = 0.2f * h;
375     xr = r * xr; yr = r * yr; zr = r * zr;
376     xa1 = x0 + xr; ya1 = y0 + yr; za1 = z0 + zr;
377
378     /* Second point of the base of the arrow */
379     xa2 = x0 - xr; ya2 = y0 - yr; za2 = z0 - zr;
380
381     /* Draw a line to the arrow */
382     glBegin(GL_LINES);
383         glVertex3f(x1, y1, z1);
384         glVertex3f(x0, y0, z0);
385     glEnd();
386
387     /* Draw a triangle of the arrow */
388     glBegin(GL_LINE_LOOP);
389         glVertex3f(xa1, ya1, za1);
390         glVertex3f(xa2, ya2, za2);
391         glVertex3f(x2,  y2,  z2);
392     glEnd();
393 }
394
395 TStatus call_graduatedtrihedron_display(int WsId, const Graphic3d_CGraduatedTrihedron &data)
396 {
397   /* Initialize data for a new view */
398   int index = getGraduatedTrihedronDataIndex(WsId);
399   if (index == -1)
400   {
401     /* Extend array for +1 */
402     tel_graduatedtrihedron_data* newGraduatedTrihedronData = new tel_graduatedtrihedron_data[nbWsIds+1];
403
404     /* Copy existing contents */
405     int i;
406     for (i = 0; i < nbWsIds; i++)
407       newGraduatedTrihedronData[i] = graduatedTrihedronData[i];
408
409     /* Add new item */
410     index = nbWsIds++;
411     newGraduatedTrihedronData[index] = new TEL_GRADUATEDTRIHEDRON_DATA;
412     newGraduatedTrihedronData[index]->WsId = WsId;
413
414     /* Switch to new array */
415     delete graduatedTrihedronData;
416     graduatedTrihedronData = newGraduatedTrihedronData;
417   }
418   copyData(&data, graduatedTrihedronData[index]);
419   return call_graduatedtrihedron_redraw(WsId);
420 }
421
422 TStatus call_graduatedtrihedron_erase(int WsId)
423 {
424   int index = getGraduatedTrihedronDataIndex(WsId);
425   if (index == -1)
426     return TSuccess; /* Nothing to remove */
427
428   /* If trihedron is displayed only in one view, just free the array and set nbWsIds equal to 0. */
429   if (nbWsIds == 1)
430   {
431     freeData();
432     return TSuccess;
433   }
434
435   /* Reduce array for -1 */
436   tel_graduatedtrihedron_data* newGraduatedTrihedronData = new tel_graduatedtrihedron_data[nbWsIds-1];
437
438   /* Copy existing contents */
439   int i, j;
440   for (i = 0, j = 0; i < nbWsIds; i++)
441   {
442     if (graduatedTrihedronData[i]->WsId != WsId)
443       newGraduatedTrihedronData[j++] = graduatedTrihedronData[i];
444   }
445   nbWsIds--;
446
447   /* Switch to new array */
448   delete graduatedTrihedronData;
449   graduatedTrihedronData = newGraduatedTrihedronData;
450
451   return TSuccess;
452 }
453
454 TStatus call_graduatedtrihedron_redraw(int WsId)
455 {
456   /* Get index of the trihedron data */
457   int index = getGraduatedTrihedronDataIndex(WsId);
458   if (index == -1)
459     return TFailure;
460
461   tel_graduatedtrihedron_data data = graduatedTrihedronData[index];
462
463   /* Update boundary box */
464   if (data->cbCubicAxes)
465     data->cbCubicAxes(data->ptrVisual3dView);
466
467   /* Disable lighting for lines */
468   GLboolean light = glIsEnabled(GL_LIGHTING);
469   if (light)
470     glDisable(GL_LIGHTING);
471     
472   /* Find the farest point of bounding box */
473
474   /* Get normal of the view out of user. */
475   /* Also, the method return distance corresponding to 1 pixel */
476   float normal[3];
477   float dpix = getNormal(normal);
478     
479   /* Normalize normal */
480   float d = sqrtf(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]);
481   normal[0] /= d;
482   normal[1] /= d;
483   normal[2] /= d;
484
485   /* Get central point of bounding box */
486   float center[3];
487   center[0] = 0.5f * (xmin + xmax);
488   center[1] = 0.5f * (ymin + ymax);
489   center[2] = 0.5f * (zmin + zmax);
490
491   /* Check distance to corners of bounding box along the normal */
492   float d000 = getDistance2Corner(normal, center, xmin, ymin, zmin);
493   float d100 = getDistance2Corner(normal, center, xmax, ymin, zmin);
494   float d010 = getDistance2Corner(normal, center, xmin, ymax, zmin);
495   float d001 = getDistance2Corner(normal, center, xmin, ymin, zmax);
496   float d110 = getDistance2Corner(normal, center, xmax, ymax, zmin);
497   float d101 = getDistance2Corner(normal, center, xmax, ymin, zmax);
498   float d011 = getDistance2Corner(normal, center, xmin, ymax, zmax);
499   float d111 = getDistance2Corner(normal, center, xmax, ymax, zmax);
500   unsigned char farestCorner = getFarestCorner(d000, d100, d010, d001, d110, d101, d011, d111);
501
502   /* Choose axes for the grid. */
503   float LX1[6], LX2[6], LX3[6]; /* Lines along X direction */
504   float LY1[6], LY2[6], LY3[6]; /* Lines along Y direction */
505   float LZ1[6], LZ2[6], LZ3[6]; /* Lines along Z direction */
506   unsigned char LX1draw, LX2draw, LX3draw; /* Allows drawing of X-line (000 - 100 is forbidden) */
507   unsigned char LY1draw, LY2draw, LY3draw; /* Allows drawing of Y-line (000 - 010 is forbidden) */
508   unsigned char LZ1draw, LZ2draw, LZ3draw; /* Allows drawing of Z-line (000 - 001 is forbidden) */
509
510   /* The first axis will be used for drawing the text and the values. */
511   switch (farestCorner)
512   {
513     case 1: /* d000 */
514     {
515       /* 001 - 101 */
516       LX1draw = 1;
517       LX1[0] = xmin; LX1[1] = ymin; LX1[2] = zmax; LX1[3] = xmax; LX1[4] = ymin; LX1[5] = zmax;
518       /* 000 - 100 */
519       LX2draw = 0; /* forbidden! */
520       LX2[0] = xmin; LX2[1] = ymin; LX2[2] = zmin; LX2[3] = xmax; LX2[4] = ymin; LX2[5] = zmin;
521       /* 010 - 110 */
522       LX3draw = 1;
523       LX3[0] = xmin; LX3[1] = ymax; LX3[2] = zmin; LX3[3] = xmax; LX3[4] = ymax; LX3[5] = zmin;
524
525       /* 100 - 110 */
526       LY1draw = 1;
527       LY1[0] = xmax; LY1[1] = ymin; LY1[2] = zmin; LY1[3] = xmax; LY1[4] = ymax; LY1[5] = zmin;
528       /* 000 - 010 */
529       LY2draw = 0; /* forbidden! */
530       LY2[0] = xmin; LY2[1] = ymin; LY2[2] = zmin; LY2[3] = xmin; LY2[4] = ymax; LY2[5] = zmin;
531       /* 001 - 011 */
532       LY3draw = 1;
533       LY3[0] = xmin; LY3[1] = ymin; LY3[2] = zmax; LY3[3] = xmin; LY3[4] = ymax; LY3[5] = zmax;
534
535       /* 100 - 101 */
536       LZ1draw = 1;
537       LZ1[0] = xmax; LZ1[1] = ymin; LZ1[2] = zmin; LZ1[3] = xmax; LZ1[4] = ymin; LZ1[5] = zmax;
538       /* 000 - 001 */
539       LZ2draw = 0; /* forbidden! */
540       LZ2[0] = xmin; LZ2[1] = ymin; LZ2[2] = zmin; LZ2[3] = xmin; LZ2[4] = ymin; LZ2[5] = zmax;
541       /* 010 - 011 */
542       LZ3draw = 1;
543       LZ3[0] = xmin; LZ3[1] = ymax; LZ3[2] = zmin; LZ3[3] = xmin; LZ3[4] = ymax; LZ3[5] = zmax;
544
545       break;
546     }
547     case 2: /* d100 */
548     {
549       /* 001 - 101 */
550       LX1draw = 1;
551       LX1[0] = xmin; LX1[1] = ymin; LX1[2] = zmax; LX1[3] = xmax; LX1[4] = ymin; LX1[5] = zmax;
552       /* 000 - 100 */
553       LX2draw = 0; /* forbidden! */
554       LX2[0] = xmin; LX2[1] = ymin; LX2[2] = zmin; LX2[3] = xmax; LX2[4] = ymin; LX2[5] = zmin;
555       /* 010 - 110 */
556       LX3draw = 1;
557       LX3[0] = xmin; LX3[1] = ymax; LX3[2] = zmin; LX3[3] = xmax; LX3[4] = ymax; LX3[5] = zmin;
558
559       /* 000 - 010 */
560       LY1draw = 0; /* forbidden! */
561       LY1[0] = xmin; LY1[1] = ymin; LY1[2] = zmin; LY1[3] = xmin; LY1[4] = ymax; LY1[5] = zmin;
562       /* 100 - 110 */
563       LY2draw = 1;
564       LY2[0] = xmax; LY2[1] = ymin; LY2[2] = zmin; LY2[3] = xmax; LY2[4] = ymax; LY2[5] = zmin;
565       /* 101 - 111 */
566       LY3draw = 1;
567       LY3[0] = xmax; LY3[1] = ymin; LY3[2] = zmax; LY3[3] = xmax; LY3[4] = ymax; LY3[5] = zmax;
568
569       /* 000 - 001 */
570       LZ1draw = 0; /* forbidden! */
571       LZ1[0] = xmin; LZ1[1] = ymin; LZ1[2] = zmin; LZ1[3] = xmin; LZ1[4] = ymin; LZ1[5] = zmax;
572       /* 100 - 101 */
573       LZ2draw = 1;
574       LZ2[0] = xmax; LZ2[1] = ymin; LZ2[2] = zmin; LZ2[3] = xmax; LZ2[4] = ymin; LZ2[5] = zmax;
575       /* 110 - 111 */
576       LZ3draw = 1;
577       LZ3[0] = xmax; LZ3[1] = ymax; LZ3[2] = zmin; LZ3[3] = xmax; LZ3[4] = ymax; LZ3[5] = zmax;
578
579       break;
580     }
581     case 3: /* d010 */
582     {
583       /* 000 - 100 */
584       LX1draw = 0; /* forbidden */
585       LX1[0] = xmin; LX1[1] = ymin; LX1[2] = zmin; LX1[3] = xmax; LX1[4] = ymin; LX1[5] = zmin;
586       /* 010 - 110 */
587       LX2draw = 1;
588       LX2[0] = xmin; LX2[1] = ymax; LX2[2] = zmin; LX2[3] = xmax; LX2[4] = ymax; LX2[5] = zmin;
589       /* 011 - 111 */
590       LX3draw = 1;
591       LX3[0] = xmin; LX3[1] = ymax; LX3[2] = zmax; LX3[3] = xmax; LX3[4] = ymax; LX3[5] = zmax;
592
593       /* 100 - 110 */
594       LY1draw = 1;
595       LY1[0] = xmax; LY1[1] = ymin; LY1[2] = zmin; LY1[3] = xmax; LY1[4] = ymax; LY1[5] = zmin;
596       /* 000 - 010 */
597       LY2draw = 0; /* forbidden */
598       LY2[0] = xmin; LY2[1] = ymin; LY2[2] = zmin; LY2[3] = xmin; LY2[4] = ymax; LY2[5] = zmin;
599       /* 001 - 011 */
600       LY3draw = 1;
601       LY3[0] = xmin; LY3[1] = ymin; LY3[2] = zmax; LY3[3] = xmin; LY3[4] = ymax; LY3[5] = zmax;
602
603       /* 110 - 111 */
604       LZ1draw = 1;
605       LZ1[0] = xmax; LZ1[1] = ymax; LZ1[2] = zmin; LZ1[3] = xmax; LZ1[4] = ymax; LZ1[5] = zmax;
606       /* 010 - 011 */
607       LZ2draw = 1;
608       LZ2[0] = xmin; LZ2[1] = ymax; LZ2[2] = zmin; LZ2[3] = xmin; LZ2[4] = ymax; LZ2[5] = zmax;
609       /* 000 - 001 */
610       LZ3draw = 0; /* forbidden */
611       LZ3[0] = xmin; LZ3[1] = ymin; LZ3[2] = zmin; LZ3[3] = xmin; LZ3[4] = ymin; LZ3[5] = zmax;
612
613       break;
614     }
615     case 4: /* d001 */
616     {
617       /* 000 - 100 */
618       LX1draw = 0; /* forbidden */
619       LX1[0] = xmin; LX1[1] = ymin; LX1[2] = zmin; LX1[3] = xmax; LX1[4] = ymin; LX1[5] = zmin;
620       /* 001 - 101 */
621       LX2draw = 1;
622       LX2[0] = xmin; LX2[1] = ymin; LX2[2] = zmax; LX2[3] = xmax; LX2[4] = ymin; LX2[5] = zmax;
623       /* 011 - 111 */
624       LX3draw = 1;
625       LX3[0] = xmin; LX3[1] = ymax; LX3[2] = zmax; LX3[3] = xmax; LX3[4] = ymax; LX3[5] = zmax;
626
627       /* 000 - 010 */
628       LY1draw = 0; /* forbidden */
629       LY1[0] = xmin; LY1[1] = ymin; LY1[2] = zmin; LY1[3] = xmin; LY1[4] = ymax; LY1[5] = zmin;
630       /* 001 - 011 */
631       LY2draw = 1;
632       LY2[0] = xmin; LY2[1] = ymin; LY2[2] = zmax; LY2[3] = xmin; LY2[4] = ymax; LY2[5] = zmax;
633       /* 101 - 111 */
634       LY3draw = 1;
635       LY3[0] = xmax; LY3[1] = ymin; LY3[2] = zmax; LY3[3] = xmax; LY3[4] = ymax; LY3[5] = zmax;
636
637       /* 100 - 101 */
638       LZ1draw = 1;
639       LZ1[0] = xmax; LZ1[1] = ymin; LZ1[2] = zmin; LZ1[3] = xmax; LZ1[4] = ymin; LZ1[5] = zmax;
640       /* 000 - 001 */
641       LZ2draw = 0; /* forbidden */
642       LZ2[0] = xmin; LZ2[1] = ymin; LZ2[2] = zmin; LZ2[3] = xmin; LZ2[4] = ymin; LZ2[5] = zmax;
643       /* 010 - 011 */
644       LZ3draw = 1;
645       LZ3[0] = xmin; LZ3[1] = ymax; LZ3[2] = zmin; LZ3[3] = xmin; LZ3[4] = ymax; LZ3[5] = zmax;
646
647       break;
648     }
649     case 5: /* d110 */
650     {
651       /* 000 - 100 */
652       LX1draw = 0; /* forbidden */
653       LX1[0] = xmin; LX1[1] = ymin; LX1[2] = zmin; LX1[3] = xmax; LX1[4] = ymin; LX1[5] = zmin;
654       /* 010 - 110 */
655       LX2draw = 1;
656       LX2[0] = xmin; LX2[1] = ymax; LX2[2] = zmin; LX2[3] = xmax; LX2[4] = ymax; LX2[5] = zmin;
657       /* 011 - 111 */
658       LX3draw = 1;
659       LX3[0] = xmin; LX3[1] = ymax; LX3[2] = zmax; LX3[3] = xmax; LX3[4] = ymax; LX3[5] = zmax;
660
661       /* 000 - 010 */
662       LY1draw = 0; /* forbidden */
663       LY1[0] = xmin; LY1[1] = ymin; LY1[2] = zmin; LY1[3] = xmin; LY1[4] = ymax; LY1[5] = zmin;
664       /* 100 - 110 */
665       LY2draw = 1;
666       LY2[0] = xmax; LY2[1] = ymin; LY2[2] = zmin; LY2[3] = xmax; LY2[4] = ymax; LY2[5] = zmin;
667       /* 101 - 111 */
668       LY3draw = 1;
669       LY3[0] = xmax; LY3[1] = ymin; LY3[2] = zmax; LY3[3] = xmax; LY3[4] = ymax; LY3[5] = zmax;
670
671       /* 100 - 101 */
672       LZ1draw = 1;
673       LZ1[0] = xmax; LZ1[1] = ymin; LZ1[2] = zmin; LZ1[3] = xmax; LZ1[4] = ymin; LZ1[5] = zmax;
674       /* 110 - 111 */
675       LZ2draw = 1;
676       LZ2[0] = xmax; LZ2[1] = ymax; LZ2[2] = zmin; LZ2[3] = xmax; LZ2[4] = ymax; LZ2[5] = zmax;
677       /* 010 - 011 */
678       LZ3draw = 1;
679       LZ3[0] = xmin; LZ3[1] = ymax; LZ3[2] = zmin; LZ3[3] = xmin; LZ3[4] = ymax; LZ3[5] = zmax;
680
681       break;
682     }
683     case 6: /* d101 */
684     {
685       /* 000 - 100 */
686       LX1draw = 0; /* forbidden */
687       LX1[0] = xmin; LX1[1] = ymin; LX1[2] = zmin; LX1[3] = xmax; LX1[4] = ymin; LX1[5] = zmin;
688       /* 001 - 101 */
689       LX2draw = 1;
690       LX2[0] = xmin; LX2[1] = ymin; LX2[2] = zmax; LX2[3] = xmax; LX2[4] = ymin; LX2[5] = zmax;
691       /* 011 - 111 */
692       LX3draw = 1;
693       LX3[0] = xmin; LX3[1] = ymax; LX3[2] = zmax; LX3[3] = xmax; LX3[4] = ymax; LX3[5] = zmax;
694
695       /* 100 - 110 */
696       LY1draw = 1;
697       LY1[0] = xmax; LY1[1] = ymin; LY1[2] = zmin; LY1[3] = xmax; LY1[4] = ymax; LY1[5] = zmin;
698       /* 101 - 111 */
699       LY2draw = 1;
700       LY2[0] = xmax; LY2[1] = ymin; LY2[2] = zmax; LY2[3] = xmax; LY2[4] = ymax; LY2[5] = zmax;
701       /* 001 - 011 */
702       LY3draw = 1;
703       LY3[0] = xmin; LY3[1] = ymin; LY3[2] = zmax; LY3[3] = xmin; LY3[4] = ymax; LY3[5] = zmax;
704
705       /* 000 - 001 */
706       LZ1draw = 0; /* forbidden */
707       LZ1[0] = xmin; LZ1[1] = ymin; LZ1[2] = zmin; LZ1[3] = xmin; LZ1[4] = ymin; LZ1[5] = zmax;
708       /* 100 - 101 */
709       LZ2draw = 1;
710       LZ2[0] = xmax; LZ2[1] = ymin; LZ2[2] = zmin; LZ2[3] = xmax; LZ2[4] = ymin; LZ2[5] = zmax;
711       /* 110 - 111 */
712       LZ3draw = 1;
713       LZ3[0] = xmax; LZ3[1] = ymax; LZ3[2] = zmin; LZ3[3] = xmax; LZ3[4] = ymax; LZ3[5] = zmax;
714
715       break;
716     }
717     case 7: /* d011 */
718     {
719       /* 001 - 101 */
720       LX1draw = 1;
721       LX1[0] = xmin; LX1[1] = ymin; LX1[2] = zmax; LX1[3] = xmax; LX1[4] = ymin; LX1[5] = zmax;
722       /* 011 - 111 */
723       LX2draw = 1;
724       LX2[0] = xmin; LX2[1] = ymax; LX2[2] = zmax; LX2[3] = xmax; LX2[4] = ymax; LX2[5] = zmax;
725       /* 010 - 110 */
726       LX3draw = 1;
727       LX3[0] = xmin; LX3[1] = ymax; LX3[2] = zmin; LX3[3] = xmax; LX3[4] = ymax; LX3[5] = zmin;
728
729       /* 000 - 010 */
730       LY1draw = 0; /* forbidden */
731       LY1[0] = xmin; LY1[1] = ymin; LY1[2] = zmin; LY1[3] = xmin; LY1[4] = ymax; LY1[5] = zmin;
732       /* 001 - 011 */
733       LY2draw = 1;
734       LY2[0] = xmin; LY2[1] = ymin; LY2[2] = zmax; LY2[3] = xmin; LY2[4] = ymax; LY2[5] = zmax;
735       /* 101 - 111 */
736       LY3draw = 1;
737       LY3[0] = xmax; LY3[1] = ymin; LY3[2] = zmax; LY3[3] = xmax; LY3[4] = ymax; LY3[5] = zmax;
738
739       /* 000 - 001 */
740       LZ1draw = 0; /* forbidden */
741       LZ1[0] = xmin; LZ1[1] = ymin; LZ1[2] = zmin; LZ1[3] = xmin; LZ1[4] = ymin; LZ1[5] = zmax;
742       /* 010 - 011 */
743       LZ2draw = 1;
744       LZ2[0] = xmin; LZ2[1] = ymax; LZ2[2] = zmin; LZ2[3] = xmin; LZ2[4] = ymax; LZ2[5] = zmax;
745       /* 110 - 111 */
746       LZ3draw = 1;
747       LZ3[0] = xmax; LZ3[1] = ymax; LZ3[2] = zmin; LZ3[3] = xmax; LZ3[4] = ymax; LZ3[5] = zmax;
748
749       break;
750     }
751     case 8: /* d111 */
752     {
753       /* 010 - 110 */
754       LX1draw = 1;
755       LX1[0] = xmin; LX1[1] = ymax; LX1[2] = zmin; LX1[3] = xmax; LX1[4] = ymax; LX1[5] = zmin;
756       /* 011 - 111 */
757       LX2draw = 1;
758       LX2[0] = xmin; LX2[1] = ymax; LX2[2] = zmax; LX2[3] = xmax; LX2[4] = ymax; LX2[5] = zmax;
759       /* 001 - 101 */
760       LX3draw = 1;
761       LX3[0] = xmin; LX3[1] = ymin; LX3[2] = zmax; LX3[3] = xmax; LX3[4] = ymin; LX3[5] = zmax;
762
763       /* 100 - 110 */
764       LY1draw = 1;
765       LY1[0] = xmax; LY1[1] = ymin; LY1[2] = zmin; LY1[3] = xmax; LY1[4] = ymax; LY1[5] = zmin;
766       /* 101 - 111 */
767       LY2draw = 1;
768       LY2[0] = xmax; LY2[1] = ymin; LY2[2] = zmax; LY2[3] = xmax; LY2[4] = ymax; LY2[5] = zmax;
769       /* 001 - 011 */
770       LY3draw = 1;
771       LY3[0] = xmin; LY3[1] = ymin; LY3[2] = zmax; LY3[3] = xmin; LY3[4] = ymax; LY3[5] = zmax;
772
773       /* 100 - 101 */
774       LZ1draw = 1;
775       LZ1[0] = xmax; LZ1[1] = ymin; LZ1[2] = zmin; LZ1[3] = xmax; LZ1[4] = ymin; LZ1[5] = zmax;
776       /* 110 - 111 */
777       LZ2draw = 1;
778       LZ2[0] = xmax; LZ2[1] = ymax; LZ2[2] = zmin; LZ2[3] = xmax; LZ2[4] = ymax; LZ2[5] = zmax;
779       /* 010 - 011 */
780       LZ3draw = 1;
781       LZ3[0] = xmin; LZ3[1] = ymax; LZ3[2] = zmin; LZ3[3] = xmin; LZ3[4] = ymax; LZ3[5] = zmax;
782
783       break;
784     }
785   }
786
787   /* Draw the graduated trihedron */
788   unsigned int i, j, offset;
789   float m1[3], m2[3];
790   float step, dx, dy, dz;
791
792   /* Grid */
793   if (data->drawgrid)
794   {
795     glColor3fv(data->gridcolor);
796     glBegin(GL_LINES);
797     /* Boundary grid-lines */
798     if (LX1draw == 1)
799     {
800       glVertex3fv(&(LX1[0]));
801       glVertex3fv(&(LX1[3]));
802     }
803     if (LX2draw == 1)
804     {
805       glVertex3fv(&(LX2[0]));
806       glVertex3fv(&(LX2[3]));
807     }
808     if (LX3draw == 1)
809     {
810       glVertex3fv(&(LX3[0]));
811       glVertex3fv(&(LX3[3]));
812     }
813     if (LY1draw == 1)
814     {
815       glVertex3fv(&(LY1[0]));
816       glVertex3fv(&(LY1[3]));
817     }
818     if (LY2draw == 1)
819     {
820       glVertex3fv(&(LY2[0]));
821       glVertex3fv(&(LY2[3]));
822     }
823     if (LY3draw == 1)
824     {
825       glVertex3fv(&(LY3[0]));
826       glVertex3fv(&(LY3[3]));
827     }
828     if (LZ1draw == 1)
829     {
830       glVertex3fv(&(LZ1[0]));
831       glVertex3fv(&(LZ1[3]));
832     }
833     if (LZ2draw == 1)
834     {
835       glVertex3fv(&(LZ2[0]));
836       glVertex3fv(&(LZ2[3]));
837     }
838     if (LZ3draw == 1)
839     {
840       glVertex3fv(&(LZ3[0]));
841       glVertex3fv(&(LZ3[3]));
842     }
843     glEnd();
844
845     /* Intermediate grid-lines */
846     /* X-Grid lines */
847     if (data->nbx > 0)
848     {
849       i = data->drawaxes ? 1 : 0;
850       step = fabsf(LX1[3] - LX1[0]) / (float) data->nbx;
851       while (i < data->nbx)
852       {
853         glBegin(GL_LINE_STRIP);
854         glVertex3f(LX1[0] + i * step, LX1[1], LX1[2]);
855         glVertex3f(LX2[0] + i * step, LX2[1], LX2[2]);
856         glVertex3f(LX3[0] + i * step, LX3[1], LX3[2]);
857         glEnd();
858         i++;
859       }
860     }
861     /* Y-Grid lines */
862     if (data->nby > 0)
863     {
864       i = data->drawaxes ? 1 : 0;
865       step = fabsf(LY1[4] - LY1[1]) / (float) data->nby;
866       while (i < data->nby)
867       {
868         glBegin(GL_LINE_STRIP);
869         glVertex3f(LY1[0], LY1[1] + i * step, LY1[2]);
870         glVertex3f(LY2[0], LY2[1] + i * step, LY2[2]);
871         glVertex3f(LY3[0], LY3[1] + i * step, LY3[2]);
872         glEnd();
873         i++;
874       }
875     }
876     /* Z-Grid lines */
877     if (data->nbz > 0)
878     {
879       i = data->drawaxes ? 1 : 0;
880       step = fabsf(LZ1[5] - LZ1[2]) / (float) data->nbz;
881       while (i < data->nbz)
882       {
883         glBegin(GL_LINE_STRIP);
884         glVertex3f(LZ1[0], LZ1[1], LZ1[2] + i * step);
885         glVertex3f(LZ2[0], LZ2[1], LZ2[2] + i * step);
886         glVertex3f(LZ3[0], LZ3[1], LZ3[2] + i * step);
887         glEnd();
888         i++;
889       }
890     }
891   }
892
893   /* Axes (arrows) */
894   if (data->drawaxes)
895   {
896     /* X-axis */
897     glColor3fv(data->xcolor);
898     drawArrow(xmin, ymin, zmin, xmax, ymin, zmin, normal[0], normal[1], normal[2]);
899
900     /* Y-axis */
901     glColor3fv(data->ycolor);
902     drawArrow(xmin, ymin, zmin, xmin, ymax, zmin, normal[0], normal[1], normal[2]);
903
904     /* Z-axis */
905     glColor3fv(data->zcolor);
906     drawArrow(xmin, ymin, zmin, xmin, ymin, zmax, normal[0], normal[1], normal[2]);
907   }
908
909   /* Names of axes & values */
910   char textValue[128];
911   wchar_t wtextValue[128];
912
913   if (data->xdrawname || data->xdrawvalues)
914   {
915     /* Middle point of the first X-axis */
916     m1[0] = 0.5f * (LX1[0] + LX1[3]);
917     m1[1] = 0.5f * (LX1[1] + LX1[4]);
918     m1[2] = 0.5f * (LX1[2] + LX1[5]);
919
920     /* Middle point of the second X-axis */
921     m2[0] = 0.5f * (LX2[0] + LX2[3]);
922     m2[1] = 0.5f * (LX2[1] + LX2[4]);
923     m2[2] = 0.5f * (LX2[2] + LX2[5]);
924
925     /* Apply offset to m1 */
926     dy = m1[1] - m2[1];
927     if (fabsf(dy) > 1.e-7f)
928     {
929       dy = (dy > 0.0f)? 1.0f : -1.0f;
930     }
931     dz = m1[2] - m2[2];
932     if (fabsf(dz) > 1.e-7f)
933     {
934       dz = (dz > 0.0f)? 1.0f : -1.0f;
935     }
936     m2[1] = dpix * dy;
937     m2[2] = dpix * dz;
938
939     /* Name of X-axis */
940     if (data->xdrawname)
941     {
942       glColor3fv(data->xnamecolor);
943       offset = data->xaxisoffset + data->xtickmarklength;
944       drawText(data->xname, data->fontOfNames, data->styleOfNames, data->sizeOfNames, 
945                m1[0], m1[1] + offset * m2[1], m1[2] + offset * m2[2]);
946     }
947
948     /* X-values */
949     if (data->xdrawvalues && data->nbx > 0)
950     {
951       glColor3fv(data->xcolor);
952
953       i = 0;
954       step = fabsf(LX1[3] - LX1[0]) / (float) data->nbx;
955       offset = data->xoffset + data->xtickmarklength;
956       while (i <= data->nbx)
957       {
958         sprintf(textValue, "%g", LX1[0] + i * step);
959         j = 0; while (wtextValue[j] = textValue[j]) j++;
960         drawText(wtextValue, data->fontOfValues, data->styleOfValues, data->sizeOfValues, 
961                  LX1[0] + i * step, m1[1] + offset * m2[1], m1[2] + offset * m2[2]);
962         i++;
963       }
964     }
965
966     /* X-tickmark */
967     if (data->xdrawtickmarks && data->nbx > 0)
968     {
969       glColor3fv(data->gridcolor);
970
971       i = 0;
972       step = fabsf(LX1[3] - LX1[0]) / (float) data->nbx;
973       while (i <= data->nbx)
974       {
975         glBegin(GL_LINES);
976         glVertex3f(LX1[0] + i * step, m1[1],                                 m1[2]);
977         glVertex3f(LX1[0] + i * step, m1[1] + data->xtickmarklength * m2[1], m1[2] + data->xtickmarklength * m2[2]);
978         glEnd();
979         i++;
980       }
981     }
982   }
983
984   if (data->ydrawname || data->ydrawvalues)
985   {
986     /* Middle point of the first Y-axis */
987     m1[0] = 0.5f * (LY1[0] + LY1[3]);
988     m1[1] = 0.5f * (LY1[1] + LY1[4]);
989     m1[2] = 0.5f * (LY1[2] + LY1[5]);
990
991     /* Middle point of the second Y-axis */
992     m2[0] = 0.5f * (LY2[0] + LY2[3]);
993     m2[1] = 0.5f * (LY2[1] + LY2[4]);
994     m2[2] = 0.5f * (LY2[2] + LY2[5]);
995
996     /* Apply offset to m1 */
997     dx = m1[0] - m2[0];
998     if (fabsf(dx) > 1.e-7f)
999     {
1000       dx = (dx > 0.0f)? 1.0f : -1.0f;
1001     }
1002     dz = m1[2] - m2[2];
1003     if (fabsf(dz) > 1.e-7f)
1004     {
1005       dz = (dz > 0.0f)? 1.0f : -1.0f;
1006     }
1007
1008     m2[0] = dpix * dx;
1009     m2[2] = dpix * dz;
1010
1011     /* Name of Y-axis */
1012     if (data->ydrawname)
1013     {
1014       glColor3fv(data->ynamecolor);
1015       offset = data->yaxisoffset + data->ytickmarklength;
1016       drawText(data->yname, data->fontOfNames, data->styleOfNames, data->sizeOfNames, 
1017                m1[0] + offset * m2[0], m1[1], m1[2] + offset * m2[2]);
1018     }
1019
1020     /* Y-values */
1021     if (data->ydrawvalues && data->nby > 0)
1022     {
1023       glColor3fv(data->ycolor);
1024
1025       i = 0;
1026       step = fabsf(LY1[4] - LY1[1]) / (float) data->nby;
1027       offset = data->yoffset + data->ytickmarklength;
1028       while (i <= data->nby)
1029       {
1030         sprintf(textValue, "%g", LY1[1] + i * step);
1031         j = 0; while (wtextValue[j] = textValue[j]) j++;
1032         drawText(wtextValue, data->fontOfValues, data->styleOfValues, data->sizeOfValues, 
1033                  m1[0] + offset * m2[0], LY1[1] + i * step, m1[2] + offset * m2[2]);
1034         i++;
1035       }
1036     }
1037
1038     /* Y-tickmark */
1039     if (data->ydrawtickmarks && data->nby > 0)
1040     {
1041       glColor3fv(data->gridcolor);
1042
1043       i = 0;
1044       step = fabsf(LY1[4] - LY1[1]) / (float) data->nby;
1045       while (i <= data->nby)
1046       {
1047         glBegin(GL_LINES);
1048         glVertex3f(m1[0],                                 LY1[1] + i * step, m1[2]);
1049         glVertex3f(m1[0] + data->ytickmarklength * m2[0], LY1[1] + i * step, m1[2] + data->ytickmarklength * m2[2]);
1050         glEnd();
1051         i++;
1052       }
1053     }
1054   }
1055
1056   if (data->zdrawname || data->zdrawvalues)
1057   {
1058     /* Middle point of the first Z-axis */
1059     m1[0] = 0.5f * (LZ1[0] + LZ1[3]);
1060     m1[1] = 0.5f * (LZ1[1] + LZ1[4]);
1061     m1[2] = 0.5f * (LZ1[2] + LZ1[5]);
1062
1063     /* Middle point of the second Z-axis */
1064     m2[0] = 0.5f * (LZ2[0] + LZ2[3]);
1065     m2[1] = 0.5f * (LZ2[1] + LZ2[4]);
1066     m2[2] = 0.5f * (LZ2[2] + LZ2[5]);
1067
1068     /* Apply offset to m1 */
1069     dx = m1[0] - m2[0];
1070     if (fabsf(dx) > 1.e-7f)
1071     {
1072       dx = (dx > 0.0f)? 1.0f : -1.0f;
1073     }
1074     dy = m1[1] - m2[1];
1075     if (fabsf(dy) > 1.e-7f)
1076     {
1077       dy = (dy > 0.0f)? 1.0f : -1.0f;
1078     }
1079
1080     m2[0] = dpix * dx;
1081     m2[1] = dpix * dy;
1082
1083     /* Name of Z-axis */
1084     if (data->zdrawname)
1085     {
1086       glColor3fv(data->znamecolor);
1087       offset = data->zaxisoffset + data->ztickmarklength;
1088       drawText(data->zname, data->fontOfNames, data->styleOfNames, data->sizeOfNames, 
1089                m1[0] + offset * m2[0], m1[1] + offset * m2[1], m1[2]);
1090     }
1091
1092     /* Z-values */
1093     if (data->zdrawvalues && data->nbz > 0)
1094     {
1095       glColor3fv(data->zcolor);
1096
1097       i = 0;
1098       step = fabsf(LZ1[5] - LZ1[2]) / (float) data->nbz;
1099       offset = data->zoffset + data->ztickmarklength;
1100       while (i <= data->nbz)
1101       {
1102         sprintf(textValue, "%g", LZ1[2] + i * step);
1103         j = 0; while (wtextValue[j] = textValue[j]) j++;
1104         drawText(wtextValue, data->fontOfValues, data->styleOfValues, data->sizeOfValues, 
1105                  m1[0] + offset * m2[0], m1[1] + offset * m2[1], LZ1[2] + i * step);
1106         i++;
1107       }
1108     }
1109
1110     /* Z-tickmark */
1111     if (data->zdrawtickmarks && data->nbz > 0)
1112     {
1113       glColor3fv(data->gridcolor);
1114
1115       i = 0;
1116       step = fabsf(LZ1[5] - LZ1[2]) / (float) data->nbz;
1117       while (i <= data->nbz)
1118       {
1119         glBegin(GL_LINES);
1120         glVertex3f(m1[0],                                 m1[1],                                LZ1[2] + i * step);
1121         glVertex3f(m1[0] + data->ztickmarklength * m2[0], m1[1] + data->ztickmarklength * m2[1], LZ1[2] + i * step);
1122         glEnd();
1123         i++;
1124       }
1125     }
1126   }
1127
1128   /* Activate the lighting if it was turned off by this method call */
1129   if (light)
1130     glEnable(GL_LIGHTING);
1131     
1132   return TSuccess;
1133 }
1134
1135 TStatus call_graduatedtrihedron_minmaxvalues(const float xMin,
1136                                              const float yMin,
1137                                              const float zMin,
1138                                              const float xMax,
1139                                              const float yMax,
1140                                              const float zMax)
1141 {
1142     xmin = xMin;
1143     ymin = yMin;
1144     zmin = zMin;
1145     xmax = xMax;
1146     ymax = yMax;
1147     zmax = zMax;
1148     return TSuccess;
1149 }