1 // Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2 //
3 // See the LICENSE.txt file in the Gmsh root directory for license information.
4 // Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5
6 #include <string.h>
7 #include "drawContext.h"
8 #include "GmshDefines.h"
9 #include "Numeric.h"
10 #include "StringUtils.h"
11 #include "Context.h"
12 #include "gl2ps.h"
13 #include "SVector3.h"
14 #include "GModel.h"
15
drawString(const std::string & s,double x,double y,double z,const std::string & font_name,int font_enum,int font_size,int align,int line_num)16 void drawContext::drawString(const std::string &s, double x, double y, double z,
17 const std::string &font_name, int font_enum,
18 int font_size, int align, int line_num)
19 {
20 if(s.empty()) return;
21 if(CTX::instance()->printing && !CTX::instance()->print.text) return;
22
23 if(s.size() > 8 && s.substr(0, 7) == "file://") {
24 drawImage(s.substr(7), x, y, z, align);
25 return;
26 }
27
28 glRasterPos3d(x, y, z);
29 GLboolean valid;
30 glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
31 if(valid == GL_FALSE) return; // the primitive is culled
32
33 if(align > 0 || line_num) {
34 GLdouble pos[4];
35 glGetDoublev(GL_CURRENT_RASTER_POSITION, pos);
36 double x[3], w[3] = {pos[0], pos[1], pos[2]};
37 drawContext::global()->setFont(font_enum, font_size);
38 double width = drawContext::global()->getStringWidth(s.c_str());
39 double height = drawContext::global()->getStringHeight();
40 // width and height must here be computed in true pixel coordinates, because
41 // viewport2world uses the actual, pixel-sized (not FLTK-sized) viewport
42 width *= highResolutionPixelFactor();
43 height *= highResolutionPixelFactor();
44 // alignment for TeX is handled directly by gl2ps
45 if(!CTX::instance()->printing ||
46 CTX::instance()->print.fileFormat != FORMAT_TEX) {
47 switch(align) {
48 case 1:
49 w[0] -= width / 2.;
50 break; // bottom center
51 case 2:
52 w[0] -= width;
53 break; // bottom right
54 case 3:
55 w[1] -= height;
56 break; // top left
57 case 4:
58 w[0] -= width / 2.;
59 w[1] -= height;
60 break; // top center
61 case 5:
62 w[0] -= width;
63 w[1] -= height;
64 break; // top right
65 case 6:
66 w[1] -= height / 2.;
67 break; // center left
68 case 7:
69 w[0] -= width / 2.;
70 w[1] -= height / 2.;
71 break; // center center
72 case 8:
73 w[0] -= width;
74 w[1] -= height / 2.;
75 break; // center right
76 default: break;
77 }
78 }
79 // treat line number also for TeX
80 if(line_num) w[1] -= line_num * (1.1 * height);
81 viewport2World(w, x);
82 glRasterPos3d(x[0], x[1], x[2]);
83 }
84
85 if(!CTX::instance()->printing) {
86 drawContext::global()->setFont(font_enum, font_size);
87 drawContext::global()->drawString(s.c_str());
88 }
89 else {
90 if(CTX::instance()->print.fileFormat == FORMAT_TEX) {
91 std::string tmp =
92 SanitizeTeXString(s.c_str(), CTX::instance()->print.texAsEquation);
93 int opt;
94 switch(align) {
95 case 1:
96 opt = GL2PS_TEXT_B;
97 break; // bottom center
98 case 2:
99 opt = GL2PS_TEXT_BR;
100 break; // bottom right
101 case 3:
102 opt = GL2PS_TEXT_TL;
103 break; // top left
104 case 4:
105 opt = GL2PS_TEXT_T;
106 break; // top center
107 case 5:
108 opt = GL2PS_TEXT_TR;
109 break; // top right
110 case 6:
111 opt = GL2PS_TEXT_CL;
112 break; // center left
113 case 7:
114 opt = GL2PS_TEXT_C;
115 break; // center center
116 case 8:
117 opt = GL2PS_TEXT_CR;
118 break; // center right
119 default:
120 opt = GL2PS_TEXT_BL;
121 break; // bottom left
122 }
123 gl2psTextOpt(tmp.c_str(), font_name.c_str(), font_size, opt, 0.);
124 }
125 else if(CTX::instance()->print.epsQuality &&
126 (CTX::instance()->print.fileFormat == FORMAT_PS ||
127 CTX::instance()->print.fileFormat == FORMAT_EPS ||
128 CTX::instance()->print.fileFormat == FORMAT_PDF ||
129 CTX::instance()->print.fileFormat == FORMAT_SVG ||
130 CTX::instance()->print.fileFormat == FORMAT_TIKZ)) {
131 gl2psText(s.c_str(), font_name.c_str(), font_size);
132 }
133 else {
134 drawContext::global()->setFont(font_enum, font_size);
135 drawContext::global()->drawString(s.c_str());
136 }
137 }
138 }
139
drawString(const std::string & s,double x,double y,double z,int line_num)140 void drawContext::drawString(const std::string &s, double x, double y, double z,
141 int line_num)
142 {
143 drawString(s, x, y, z, CTX::instance()->glFont, CTX::instance()->glFontEnum,
144 CTX::instance()->glFontSize, 0, line_num);
145 }
146
drawStringCenter(const std::string & s,double x,double y,double z,int line_num)147 void drawContext::drawStringCenter(const std::string &s, double x, double y,
148 double z, int line_num)
149 {
150 drawString(s, x, y, z, CTX::instance()->glFont, CTX::instance()->glFontEnum,
151 CTX::instance()->glFontSize, 1, line_num);
152 }
153
drawStringRight(const std::string & s,double x,double y,double z,int line_num)154 void drawContext::drawStringRight(const std::string &s, double x, double y,
155 double z, int line_num)
156 {
157 drawString(s, x, y, z, CTX::instance()->glFont, CTX::instance()->glFontEnum,
158 CTX::instance()->glFontSize, 2, line_num);
159 }
160
drawString(const std::string & s,double x,double y,double z,double style,int line_num)161 void drawContext::drawString(const std::string &s, double x, double y, double z,
162 double style, int line_num)
163 {
164 unsigned int bits = (unsigned int)style;
165
166 if(!bits) { // use defaults
167 drawString(s, x, y, z, line_num);
168 }
169 else {
170 int size = (bits & 0xff);
171 int font = (bits >> 8 & 0xff);
172 int align = (bits >> 16 & 0xff);
173 int font_enum = drawContext::global()->getFontEnum(font);
174 std::string font_name = drawContext::global()->getFontName(font);
175 if(!size) size = CTX::instance()->glFontSize;
176 drawString(s, x, y, z, font_name, font_enum, size, align, line_num);
177 }
178 }
179
drawImage(const std::string & name,double x,double y,double z,int align)180 void drawContext::drawImage(const std::string &name, double x, double y,
181 double z, int align)
182 {
183 // format can be "@wxh" or "@wxh,wx,wy,wz,hx,hy,hz", where w and h are the
184 // width and height (in model coordinates for T3 or in pixels for T2) of the
185 // image, wx,wy,wz is the direction of the bottom edge of the image and
186 // hx,hy,hz is the direction of the left edge of the image.
187 size_t p = name.find_last_of('@');
188 std::string file = name, format;
189 if(p != std::string::npos) {
190 format = name.substr(p + 1);
191 file = name.substr(0, p);
192 }
193 double w = 0., h = 0., wx = 1., wy = 0., wz = 0., hx = 0., hy = 1., hz = 0.;
194 bool billboard = false;
195 if(format.size()) {
196 bool ok;
197 if(format.find(',') != std::string::npos)
198 ok = (sscanf(format.c_str(), "%lfx%lf,%lf,%lf,%lf,%lf,%lf,%lf", &w, &h,
199 &wx, &wy, &wz, &hx, &hy, &hz) == 8);
200 else
201 ok = (sscanf(format.c_str(), "%lfx%lf", &w, &h) == 2);
202 if(!ok)
203 Msg::Warning("Bad image format: use `@wxh' or `@wxh,wx,wy,wz,hx,hy,hz'");
204 if(format.find('#') != std::string::npos)
205 billboard = true; // texture will always face camera
206 }
207
208 imgtex *img;
209 if(!_imageTextures.count(file)) {
210 img = &_imageTextures[file];
211 file = FixRelativePath(GModel::current()->getFileName(), file);
212 if(!generateTextureForImage(file, 1, img->tex, img->w, img->h)) {
213 return;
214 }
215 }
216 else {
217 img = &_imageTextures[file];
218 }
219 if(!img->tex) {
220 Msg::Debug("No texture for image - skipping image draw");
221 return;
222 }
223
224 if(w == 0 && h == 0) {
225 w = img->w;
226 h = img->h;
227 }
228 else if(h == 0) {
229 h = w * img->h / img->w;
230 }
231 else if(w == 0) {
232 w = h * img->w / img->h;
233 }
234
235 GLboolean valid = GL_TRUE;
236 GLint matrixMode = 0;
237 if(billboard) {
238 glRasterPos3d(x, y, z);
239 GLfloat pos[4];
240 glGetFloatv(GL_CURRENT_RASTER_POSITION, pos);
241 glGetIntegerv(GL_MATRIX_MODE, &matrixMode);
242 glMatrixMode(GL_PROJECTION);
243 glPushMatrix();
244 glLoadIdentity();
245 glMatrixMode(GL_MODELVIEW);
246 glPushMatrix();
247 glLoadIdentity();
248 double fact = highResolutionPixelFactor();
249 glOrtho((double)viewport[0], (double)viewport[2] * fact,
250 (double)viewport[1], (double)viewport[3] * fact, -1, 1);
251 x = pos[0];
252 y = pos[1];
253 z = 0;
254 w *= fact * s[0] / pixel_equiv_x;
255 h *= fact * s[1] / pixel_equiv_y;
256 glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
257 }
258 if(valid == GL_TRUE) {
259 switch(align) {
260 case 1:
261 x -= w / 2.;
262 break; // bottom center
263 case 2:
264 x -= w;
265 break; // bottom right
266 case 3:
267 y -= h;
268 break; // top left
269 case 4:
270 x -= w / 2.;
271 y -= h;
272 break; // top center
273 case 5:
274 x -= w;
275 y -= h;
276 break; // top right
277 case 6:
278 y -= h / 2.;
279 break; // center left
280 case 7:
281 x -= w / 2.;
282 y -= h / 2.;
283 break; // center center
284 case 8:
285 x -= w;
286 y -= h / 2.;
287 break; // center right
288 default: break;
289 }
290 glEnable(GL_BLEND);
291 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
292 glEnable(GL_TEXTURE_2D);
293 glBindTexture(GL_TEXTURE_2D, img->tex);
294 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
295 glBegin(GL_QUADS);
296 glTexCoord2f(1.0f, 1.0f);
297 glVertex3d(x + wx * w, y + wy * w, z + wz * w);
298 glTexCoord2f(1.0f, 0.0f);
299 glVertex3d(x + wx * w + hx * h, y + wy * w + hy * h, z + wz * w + hz * h);
300 glTexCoord2f(0.0f, 0.0f);
301 glVertex3d(x + hx * h, y + hy * h, z + hz * h);
302 glTexCoord2f(0.0f, 1.0f);
303 glVertex3d(x, y, z);
304 glEnd();
305 glDisable(GL_TEXTURE_2D);
306 glDisable(GL_BLEND);
307 }
308 if(billboard) {
309 glPopMatrix();
310 glMatrixMode(GL_PROJECTION);
311 glPopMatrix();
312 glMatrixMode(matrixMode);
313 }
314 }
315
drawCube(double x,double y,double z,double val[9],int light)316 void drawContext::drawCube(double x, double y, double z, double val[9],
317 int light)
318 {
319 double d0[3] = {val[0], val[1], val[2]};
320 double d1[3] = {val[3], val[4], val[5]};
321 double d2[3] = {val[6], val[7], val[8]};
322
323 double x0[3] = {x + d1[0] + d1[0] + d2[0], x + d0[1] + d1[1] + d2[1],
324 z + d0[2] + d1[2] + d2[2]};
325 double x1[3] = {x - d1[0] + d1[0] + d2[0], x - d0[1] + d1[1] + d2[1],
326 z - d0[2] + d1[2] + d2[2]};
327 double x2[3] = {x - d1[0] - d1[0] + d2[0], x - d0[1] - d1[1] + d2[1],
328 z - d0[2] - d1[2] + d2[2]};
329 double x3[3] = {x + d1[0] - d1[0] + d2[0], x + d0[1] - d1[1] + d2[1],
330 z + d0[2] - d1[2] + d2[2]};
331
332 double x4[3] = {x + d1[0] + d1[0] - d2[0], x + d0[1] + d1[1] - d2[1],
333 z + d0[2] + d1[2] - d2[2]};
334 double x5[3] = {x - d1[0] + d1[0] - d2[0], x - d0[1] + d1[1] - d2[1],
335 z - d0[2] + d1[2] - d2[2]};
336 double x6[3] = {x - d1[0] - d1[0] - d2[0], x - d0[1] - d1[1] - d2[1],
337 z - d0[2] - d1[2] - d2[2]};
338 double x7[3] = {x + d1[0] - d1[0] - d2[0], x + d0[1] - d1[1] - d2[1],
339 z + d0[2] - d1[2] - d2[2]};
340
341 if(light) glEnable(GL_LIGHTING);
342 glPushMatrix();
343
344 glBegin(GL_POLYGON);
345 glColor3f(x0[0], x0[1], x0[2]);
346 glColor3f(x1[0], x1[1], x1[2]);
347 glColor3f(x2[0], x2[1], x2[2]);
348 glColor3f(x3[0], x3[1], x3[2]);
349 glEnd();
350
351 glBegin(GL_POLYGON);
352 glColor3f(x4[0], x4[1], x4[2]);
353 glColor3f(x7[0], x7[1], x7[2]);
354 glColor3f(x6[0], x6[1], x6[2]);
355 glColor3f(x5[0], x5[1], x5[2]);
356 glEnd();
357
358 glBegin(GL_POLYGON);
359 glColor3f(x0[0], x0[1], x0[2]);
360 glColor3f(x3[0], x3[1], x3[2]);
361 glColor3f(x7[0], x7[1], x7[2]);
362 glColor3f(x4[0], x4[1], x4[2]);
363 glEnd();
364
365 glBegin(GL_POLYGON);
366 glColor3f(x1[0], x1[1], x1[2]);
367 glColor3f(x5[0], x5[1], x5[2]);
368 glColor3f(x6[0], x6[1], x6[2]);
369 glColor3f(x2[0], x2[1], x2[2]);
370 glEnd();
371
372 glBegin(GL_POLYGON);
373 glColor3f(x0[0], x0[1], x0[2]);
374 glColor3f(x4[0], x4[1], x4[2]);
375 glColor3f(x5[0], x5[1], x5[2]);
376 glColor3f(x1[0], x1[1], x1[2]);
377 glEnd();
378
379 glBegin(GL_POLYGON);
380 glColor3f(x3[0], x3[1], x3[2]);
381 glColor3f(x2[0], x2[1], x2[2]);
382 glColor3f(x6[0], x6[1], x6[2]);
383 glColor3f(x7[0], x7[1], x7[2]);
384 glEnd();
385
386 glPopMatrix();
387 glDisable(GL_LIGHTING);
388 }
389
drawSphere(double R,double x,double y,double z,int n1,int n2,int light)390 void drawContext::drawSphere(double R, double x, double y, double z, int n1,
391 int n2, int light)
392 {
393 if(light) glEnable(GL_LIGHTING);
394 glPushMatrix();
395 glTranslated(x, y, z);
396 gluSphere(_quadric, R, n1, n2);
397 glPopMatrix();
398 glDisable(GL_LIGHTING);
399 }
400
drawEllipse(double x,double y,double z,float v0[3],float v1[3],int light)401 void drawContext::drawEllipse(double x, double y, double z, float v0[3],
402 float v1[3], int light)
403 {
404 if(light) glEnable(GL_LIGHTING);
405 glPushMatrix();
406 GLfloat m[16] = {v0[0],
407 v0[1],
408 v0[2],
409 .0f,
410 v1[0],
411 v1[1],
412 v1[2],
413 .0f,
414 v0[1] * v1[2] - v0[2] * v1[1],
415 v0[2] * v1[0] - v0[0] * v1[2],
416 v0[0] * v1[1] - v0[1] * v1[0],
417 .0f,
418 (GLfloat)x,
419 (GLfloat)y,
420 (GLfloat)z,
421 1.f};
422 glMultMatrixf(m);
423 glCallList(_displayLists + 2);
424 glPopMatrix();
425 glDisable(GL_LIGHTING);
426 }
427
drawEllipsoid(double x,double y,double z,float v0[3],float v1[3],float v2[3],int light)428 void drawContext::drawEllipsoid(double x, double y, double z, float v0[3],
429 float v1[3], float v2[3], int light)
430 {
431 if(light) glEnable(GL_LIGHTING);
432 glPushMatrix();
433 GLfloat m[16] = {v0[0], v0[1], v0[2], .0f, v1[0], v1[1],
434 v1[2], .0f, v2[0], v2[1], v2[2], .0f,
435 (GLfloat)x, (GLfloat)y, (GLfloat)z, 1.f};
436 glMultMatrixf(m);
437 glCallList(_displayLists + 0);
438 glPopMatrix();
439 glDisable(GL_LIGHTING);
440 }
441
drawSphere(double size,double x,double y,double z,int light)442 void drawContext::drawSphere(double size, double x, double y, double z,
443 int light)
444 {
445 double ss = size * pixel_equiv_x / s[0]; // size is in pixels
446 if(light) glEnable(GL_LIGHTING);
447 glPushMatrix();
448 glTranslated(x, y, z);
449 glScaled(ss, ss, ss);
450 glCallList(_displayLists + 0);
451 glPopMatrix();
452 glDisable(GL_LIGHTING);
453 }
454
drawTaperedCylinder(double width,double val1,double val2,double ValMin,double ValMax,double * x,double * y,double * z,int light)455 void drawContext::drawTaperedCylinder(double width, double val1, double val2,
456 double ValMin, double ValMax, double *x,
457 double *y, double *z, int light)
458 {
459 if(light) glEnable(GL_LIGHTING);
460
461 double dx = x[1] - x[0];
462 double dy = y[1] - y[0];
463 double dz = z[1] - z[0];
464 double const length = std::sqrt(dx * dx + dy * dy + dz * dz);
465 double fact = width * pixel_equiv_x / s[0] / (ValMax - ValMin);
466 double radius1 = (val1 - ValMin) * fact;
467 double radius2 = (val2 - ValMin) * fact;
468 double zdir[3] = {0., 0., 1.};
469 double vdir[3] = {dx / length, dy / length, dz / length};
470 double axis[3], phi;
471 prodve(zdir, vdir, axis);
472 double const cosphi = prosca(zdir, vdir);
473 if(!norme(axis)) {
474 axis[0] = 0.;
475 axis[1] = 1.;
476 axis[2] = 0.;
477 }
478 phi = 180. * myacos(cosphi) / M_PI;
479
480 glPushMatrix();
481 glTranslated(x[0], y[0], z[0]);
482 glRotated(phi, axis[0], axis[1], axis[2]);
483 gluCylinder(_quadric, radius1, radius2, length,
484 CTX::instance()->quadricSubdivisions, 1);
485 glPopMatrix();
486
487 glDisable(GL_LIGHTING);
488 }
489
drawCylinder(double width,double * x,double * y,double * z,int light)490 void drawContext::drawCylinder(double width, double *x, double *y, double *z,
491 int light)
492 {
493 if(light) glEnable(GL_LIGHTING);
494
495 double dx = x[1] - x[0];
496 double dy = y[1] - y[0];
497 double dz = z[1] - z[0];
498 double const length = std::sqrt(dx * dx + dy * dy + dz * dz);
499 double radius = width * pixel_equiv_x / s[0];
500 double zdir[3] = {0., 0., 1.};
501 double vdir[3] = {dx / length, dy / length, dz / length};
502 double axis[3], phi;
503 prodve(zdir, vdir, axis);
504 double const cosphi = prosca(zdir, vdir);
505 if(!norme(axis)) {
506 axis[0] = 0.;
507 axis[1] = 1.;
508 axis[2] = 0.;
509 }
510 phi = 180. * myacos(cosphi) / M_PI;
511
512 glPushMatrix();
513 glTranslated(x[0], y[0], z[0]);
514 glRotated(phi, axis[0], axis[1], axis[2]);
515 gluCylinder(_quadric, radius, radius, length,
516 CTX::instance()->quadricSubdivisions, 1);
517 glPopMatrix();
518
519 glDisable(GL_LIGHTING);
520 }
521
drawSimpleVector(int arrow,int fill,double x,double y,double z,double dx,double dy,double dz,double d,int light)522 static void drawSimpleVector(int arrow, int fill, double x, double y, double z,
523 double dx, double dy, double dz, double d,
524 int light)
525 {
526 double n[3], t[3], u[3];
527
528 n[0] = dx / d;
529 n[1] = dy / d;
530 n[2] = dz / d;
531
532 if((fabs(n[0]) >= fabs(n[1]) && fabs(n[0]) >= fabs(n[2])) ||
533 (fabs(n[1]) >= fabs(n[0]) && fabs(n[1]) >= fabs(n[2]))) {
534 t[0] = n[1];
535 t[1] = -n[0];
536 t[2] = 0.;
537 }
538 else {
539 t[0] = 0.;
540 t[1] = n[2];
541 t[2] = -n[1];
542 }
543
544 double l = sqrt(t[0] * t[0] + t[1] * t[1] + t[2] * t[2]);
545 t[0] /= l;
546 t[1] /= l;
547 t[2] /= l;
548
549 u[0] = n[1] * t[2] - n[2] * t[1];
550 u[1] = n[2] * t[0] - n[0] * t[2];
551 u[2] = n[0] * t[1] - n[1] * t[0];
552
553 l = sqrt(u[0] * u[0] + u[1] * u[1] + u[2] * u[2]);
554 u[0] /= l;
555 u[1] /= l;
556 u[2] /= l;
557
558 double b = CTX::instance()->arrowRelHeadRadius * d;
559
560 if(arrow) {
561 double f1 = CTX::instance()->arrowRelStemLength;
562 double f2 = (1 - 2. * CTX::instance()->arrowRelStemRadius) * f1; // hack :-)
563
564 if(fill) {
565 glBegin(GL_LINES);
566 glVertex3d(x, y, z);
567 glVertex3d(x + f1 * dx, y + f1 * dy, z + f1 * dz);
568 glEnd();
569
570 if(light && fill) glEnable(GL_LIGHTING);
571 glBegin(GL_TRIANGLES);
572 if(light) glNormal3dv(u);
573 glVertex3d(x + dx, y + dy, z + dz);
574 glVertex3d(x + f2 * dx + b * (t[0]), y + f2 * dy + b * (t[1]),
575 z + f2 * dz + b * (t[2]));
576 glVertex3d(x + f1 * dx, y + f1 * dy, z + f1 * dz);
577
578 glVertex3d(x + f1 * dx, y + f1 * dy, z + f1 * dz);
579 glVertex3d(x + f2 * dx + b * (-t[0]), y + f2 * dy + b * (-t[1]),
580 z + f2 * dz + b * (-t[2]));
581 glVertex3d(x + dx, y + dy, z + dz);
582
583 if(light) glNormal3dv(t);
584 glVertex3d(x + dx, y + dy, z + dz);
585 glVertex3d(x + f2 * dx + b * (-u[0]), y + f2 * dy + b * (-u[1]),
586 z + f2 * dz + b * (-u[2]));
587 glVertex3d(x + f1 * dx, y + f1 * dy, z + f1 * dz);
588
589 glVertex3d(x + f1 * dx, y + f1 * dy, z + f1 * dz);
590 glVertex3d(x + f2 * dx + b * (u[0]), y + f2 * dy + b * (u[1]),
591 z + f2 * dz + b * (u[2]));
592 glVertex3d(x + dx, y + dy, z + dz);
593 glEnd();
594 glDisable(GL_LIGHTING);
595 }
596 else {
597 glBegin(GL_LINE_STRIP);
598 glVertex3d(x, y, z);
599 glVertex3d(x + dx, y + dy, z + dz);
600 glVertex3d(x + f2 * dx + b * (t[0]), y + f2 * dy + b * (t[1]),
601 z + f2 * dz + b * (t[2]));
602 glVertex3d(x + f1 * dx, y + f1 * dy, z + f1 * dz);
603 glVertex3d(x + f2 * dx + b * (-t[0]), y + f2 * dy + b * (-t[1]),
604 z + f2 * dz + b * (-t[2]));
605 glVertex3d(x + dx, y + dy, z + dz);
606 glVertex3d(x + f2 * dx + b * (-u[0]), y + f2 * dy + b * (-u[1]),
607 z + f2 * dz + b * (-u[2]));
608 glVertex3d(x + f1 * dx, y + f1 * dy, z + f1 * dz);
609 glVertex3d(x + f2 * dx + b * (u[0]), y + f2 * dy + b * (u[1]),
610 z + f2 * dz + b * (u[2]));
611 glVertex3d(x + dx, y + dy, z + dz);
612 glEnd();
613 }
614 }
615 else { // simple pyramid
616 if(fill) {
617 double top[3] = {x + dx, y + dy, z + dz};
618 double tp[3] = {x + b * t[0], y + b * t[1], z + b * t[2]};
619 double tm[3] = {x - b * t[0], y - b * t[1], z - b * t[2]};
620 double up[3] = {x + b * u[0], y + b * u[1], z + b * u[2]};
621 double um[3] = {x - b * u[0], y - b * u[1], z - b * u[2]};
622 double nn[3];
623
624 if(light && fill) glEnable(GL_LIGHTING);
625 glBegin(GL_TRIANGLES);
626 if(light) {
627 normal3points(tm[0], tm[1], tm[2], um[0], um[1], um[2], top[0], top[1],
628 top[2], nn);
629 glNormal3dv(nn);
630 }
631 glVertex3d(tm[0], tm[1], tm[2]);
632 glVertex3d(um[0], um[1], um[2]);
633 glVertex3d(top[0], top[1], top[2]);
634
635 if(light) {
636 normal3points(um[0], um[1], um[2], tp[0], tp[1], tp[2], top[0], top[1],
637 top[2], nn);
638 glNormal3dv(nn);
639 }
640 glVertex3d(um[0], um[1], um[2]);
641 glVertex3d(tp[0], tp[1], tp[2]);
642 glVertex3d(top[0], top[1], top[2]);
643
644 if(light) {
645 normal3points(tp[0], tp[1], tp[2], up[0], up[1], up[2], top[0], top[1],
646 top[2], nn);
647 glNormal3dv(nn);
648 }
649 glVertex3d(tp[0], tp[1], tp[2]);
650 glVertex3d(up[0], up[1], up[2]);
651 glVertex3d(top[0], top[1], top[2]);
652
653 if(light) {
654 normal3points(up[0], up[1], up[2], tm[0], tm[1], tm[2], top[0], top[1],
655 top[2], nn);
656 glNormal3dv(nn);
657 }
658 glVertex3d(up[0], up[1], up[2]);
659 glVertex3d(tm[0], tm[1], tm[2]);
660 glVertex3d(top[0], top[1], top[2]);
661 glEnd();
662 glDisable(GL_LIGHTING);
663 }
664 else {
665 glBegin(GL_LINE_LOOP);
666 glVertex3d(x + b * (t[0]), y + b * (t[1]), z + b * (t[2]));
667 glVertex3d(x + b * (-u[0]), y + b * (-u[1]), z + b * (-u[2]));
668 glVertex3d(x + b * (-t[0]), y + b * (-t[1]), z + b * (-t[2]));
669 glVertex3d(x + b * (u[0]), y + b * (u[1]), z + b * (u[2]));
670 glEnd();
671
672 glBegin(GL_LINES);
673 glVertex3d(x + b * (t[0]), y + b * (t[1]), z + b * (t[2]));
674 glVertex3d(x + dx, y + dy, z + dz);
675
676 glVertex3d(x + b * (-u[0]), y + b * (-u[1]), z + b * (-u[2]));
677 glVertex3d(x + dx, y + dy, z + dz);
678
679 glVertex3d(x + b * (-t[0]), y + b * (-t[1]), z + b * (-t[2]));
680 glVertex3d(x + dx, y + dy, z + dz);
681
682 glVertex3d(x + b * (u[0]), y + b * (u[1]), z + b * (u[2]));
683 glVertex3d(x + dx, y + dy, z + dz);
684 glEnd();
685 }
686 }
687 }
688
drawArrow3d(double x,double y,double z,double dx,double dy,double dz,double length,int light)689 void drawContext::drawArrow3d(double x, double y, double z, double dx,
690 double dy, double dz, double length, int light)
691 {
692 double zdir[3] = {0., 0., 1.};
693 double vdir[3] = {dx / length, dy / length, dz / length};
694 double axis[3];
695 prodve(zdir, vdir, axis);
696 double const cosphi = prosca(zdir, vdir);
697 if(!norme(axis)) {
698 axis[0] = 0.;
699 axis[1] = 1.;
700 axis[2] = 0.;
701 }
702 double phi = 180. * myacos(cosphi) / M_PI;
703
704 if(light) glEnable(GL_LIGHTING);
705 glPushMatrix();
706 glTranslated(x, y, z);
707 glScaled(length, length, length);
708 glRotated(phi, axis[0], axis[1], axis[2]);
709 glCallList(_displayLists + 1);
710 glPopMatrix();
711 glDisable(GL_LIGHTING);
712 }
713
drawVector(int Type,int Fill,double x,double y,double z,double dx,double dy,double dz,int light)714 void drawContext::drawVector(int Type, int Fill, double x, double y, double z,
715 double dx, double dy, double dz, int light)
716 {
717 double length = sqrt(dx * dx + dy * dy + dz * dz);
718
719 if(length == 0.0) return;
720
721 switch(Type) {
722 case 1:
723 glBegin(GL_LINES);
724 glVertex3d(x, y, z);
725 glVertex3d(x + dx, y + dy, z + dz);
726 glEnd();
727 break;
728 case 6:
729 if(CTX::instance()->arrowRelHeadRadius) {
730 glBegin(GL_POINTS);
731 glVertex3d(x + dx, y + dy, z + dz);
732 glEnd();
733 }
734 glBegin(GL_LINES);
735 glVertex3d(x + dx, y + dy, z + dz);
736 // color gradient
737 glColor4ubv((GLubyte *)&CTX::instance()->color.bg);
738 glVertex3d(x, y, z);
739 glEnd();
740 break;
741 case 2: drawSimpleVector(1, Fill, x, y, z, dx, dy, dz, length, light); break;
742 case 3: drawSimpleVector(0, Fill, x, y, z, dx, dy, dz, length, light); break;
743 case 4:
744 default: drawArrow3d(x, y, z, dx, dy, dz, length, light); break;
745 }
746 }
747
748 namespace {
749 class point {
750 public:
751 double x, y, z;
752 bool valid;
point()753 point() : x(0.), y(0.), z(0.), valid(false) {}
point(double xi,double yi,double zi)754 point(double xi, double yi, double zi) : x(xi), y(yi), z(zi), valid(true) {}
755 };
756
757 class plane {
758 private:
759 double _a, _b, _c, _d;
760
761 public:
plane(double a,double b,double c,double d)762 plane(double a, double b, double c, double d) : _a(a), _b(b), _c(c), _d(d) {}
val(point & p)763 double val(point &p) { return _a * p.x + _b * p.y + _c * p.z + _d; };
intersect(point & p1,point & p2)764 point intersect(point &p1, point &p2)
765 {
766 double v1 = val(p1), v2 = val(p2);
767 if(fabs(v1) < 1.e-12) {
768 if(fabs(v2) < 1.e-12)
769 return point();
770 else
771 return point(p1.x, p1.y, p1.z);
772 }
773 else if(fabs(v2) < 1.e-12) {
774 return point(p2.x, p2.y, p2.z);
775 }
776 else if(v1 * v2 < 0.) {
777 double coef = -v1 / (v2 - v1);
778 return point(coef * (p2.x - p1.x) + p1.x, coef * (p2.y - p1.y) + p1.y,
779 coef * (p2.z - p1.z) + p1.z);
780 }
781 else
782 return point();
783 }
784 };
785 }
786
drawBox(double xmin,double ymin,double zmin,double xmax,double ymax,double zmax,bool labels)787 void drawContext::drawBox(double xmin, double ymin, double zmin, double xmax,
788 double ymax, double zmax, bool labels)
789 {
790 glBegin(GL_LINE_LOOP);
791 glVertex3d(xmin, ymin, zmin);
792 glVertex3d(xmax, ymin, zmin);
793 glVertex3d(xmax, ymax, zmin);
794 glVertex3d(xmin, ymax, zmin);
795 glEnd();
796 glBegin(GL_LINE_LOOP);
797 glVertex3d(xmin, ymin, zmax);
798 glVertex3d(xmax, ymin, zmax);
799 glVertex3d(xmax, ymax, zmax);
800 glVertex3d(xmin, ymax, zmax);
801 glEnd();
802 glBegin(GL_LINES);
803 glVertex3d(xmin, ymin, zmin);
804 glVertex3d(xmin, ymin, zmax);
805 glVertex3d(xmax, ymin, zmin);
806 glVertex3d(xmax, ymin, zmax);
807 glVertex3d(xmax, ymax, zmin);
808 glVertex3d(xmax, ymax, zmax);
809 glVertex3d(xmin, ymax, zmin);
810 glVertex3d(xmin, ymax, zmax);
811 glEnd();
812 if(labels) {
813 char label[256];
814 double offset = 0.3 * CTX::instance()->glFontSize * pixel_equiv_x;
815 sprintf(label, "(%g,%g,%g)", xmin, ymin, zmin);
816 drawString(label, xmin + offset / s[0], ymin + offset / s[1],
817 zmin + offset / s[2]);
818 sprintf(label, "(%g,%g,%g)", xmax, ymax, zmax);
819 drawString(label, xmax + offset / s[0], ymax + offset / s[1],
820 zmax + offset / s[2]);
821 }
822 }
823
drawPlaneInBoundingBox(double xmin,double ymin,double zmin,double xmax,double ymax,double zmax,double a,double b,double c,double d,int shade)824 void drawContext::drawPlaneInBoundingBox(double xmin, double ymin, double zmin,
825 double xmax, double ymax, double zmax,
826 double a, double b, double c, double d,
827 int shade)
828 {
829 plane pl(a, b, c, d);
830 point p1(xmin, ymin, zmin), p2(xmax, ymin, zmin);
831 point p3(xmax, ymax, zmin), p4(xmin, ymax, zmin);
832 point p5(xmin, ymin, zmax), p6(xmax, ymin, zmax);
833 point p7(xmax, ymax, zmax), p8(xmin, ymax, zmax);
834
835 point edge[12];
836 edge[0] = pl.intersect(p1, p2);
837 edge[1] = pl.intersect(p1, p4);
838 edge[2] = pl.intersect(p1, p5);
839 edge[3] = pl.intersect(p2, p3);
840 edge[4] = pl.intersect(p2, p6);
841 edge[5] = pl.intersect(p3, p4);
842 edge[6] = pl.intersect(p3, p7);
843 edge[7] = pl.intersect(p4, p8);
844 edge[8] = pl.intersect(p5, p6);
845 edge[9] = pl.intersect(p5, p8);
846 edge[10] = pl.intersect(p6, p7);
847 edge[11] = pl.intersect(p7, p8);
848
849 int face[6][4] = {{0, 2, 4, 8}, {0, 1, 3, 5}, {1, 2, 7, 9},
850 {3, 4, 6, 10}, {5, 6, 7, 11}, {8, 9, 10, 11}};
851
852 double n[3] = {a, b, c}, ll = 50;
853 norme(n);
854 if(CTX::instance()->arrowRelStemRadius)
855 ll = CTX::instance()->lineWidth / CTX::instance()->arrowRelStemRadius;
856 n[0] *= ll * pixel_equiv_x / s[0];
857 n[1] *= ll * pixel_equiv_x / s[1];
858 n[2] *= ll * pixel_equiv_x / s[2];
859 double length = sqrt(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
860
861 int n_shade = 0;
862 point p_shade[24];
863
864 for(int i = 0; i < 6; i++) {
865 int nb = 0;
866 point p[4];
867 for(int j = 0; j < 4; j++) {
868 if(edge[face[i][j]].valid == true) p[nb++] = edge[face[i][j]];
869 }
870 if(nb > 1) {
871 for(int j = 1; j < nb; j++) {
872 double xx[2] = {p[j].x, p[j - 1].x};
873 double yy[2] = {p[j].y, p[j - 1].y};
874 double zz[2] = {p[j].z, p[j - 1].z};
875 drawCylinder(CTX::instance()->lineWidth, xx, yy, zz, 1);
876 }
877 for(int j = 0; j < nb; j++) {
878 drawArrow3d(p[j].x, p[j].y, p[j].z, n[0], n[1], n[2], length, 1);
879 if(shade) {
880 p_shade[n_shade].x = p[j].x;
881 p_shade[n_shade].y = p[j].y;
882 p_shade[n_shade].z = p[j].z;
883 n_shade++;
884 }
885 }
886 }
887 }
888
889 if(shade) {
890 // disable two-side lighting beacuse polygon can overlap itself
891 GLboolean twoside;
892 glGetBooleanv(GL_LIGHT_MODEL_TWO_SIDE, &twoside);
893 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
894 glEnable(GL_LIGHTING);
895 glBegin(GL_POLYGON);
896 glNormal3d(n[0], n[1], n[2]);
897 for(int j = 0; j < n_shade; j++) {
898 glVertex3d(p_shade[j].x, p_shade[j].y, p_shade[j].z);
899 }
900 glEnd();
901 glDisable(GL_LIGHTING);
902 glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, twoside);
903 }
904 }
905