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 <algorithm>
7 #include "drawContext.h"
8 #include "PView.h"
9 #include "PViewOptions.h"
10 #include "PViewData.h"
11 #include "Context.h"
12 #include "gl2ps.h"
13 
drawScaleBar(PView * p,double xmin,double ymin,double width,double height,double tic,int horizontal)14 static void drawScaleBar(PView *p, double xmin, double ymin, double width,
15                          double height, double tic, int horizontal)
16 {
17   PViewOptions *opt = p->getOptions();
18 
19   double box = (horizontal ? width : height) / (opt->nbIso ? opt->nbIso : 1);
20 
21   for(int i = 0; i < opt->nbIso; i++) {
22     if(opt->intervalsType == PViewOptions::Discrete ||
23        opt->intervalsType == PViewOptions::Numeric) {
24       unsigned int col = opt->getColor(i, opt->nbIso);
25       glColor4ubv((GLubyte *)&col);
26       glBegin(GL_QUADS);
27       if(horizontal) {
28         glVertex2d(xmin + i * box, ymin);
29         glVertex2d(xmin + (i + 1) * box, ymin);
30         glVertex2d(xmin + (i + 1) * box, ymin + height);
31         glVertex2d(xmin + i * box, ymin + height);
32       }
33       else {
34         glVertex2d(xmin, ymin + i * box);
35         glVertex2d(xmin + width, ymin + i * box);
36         glVertex2d(xmin + width, ymin + (i + 1) * box);
37         glVertex2d(xmin, ymin + (i + 1) * box);
38       }
39       glEnd();
40     }
41     else if(opt->intervalsType == PViewOptions::Continuous) {
42       glBegin(GL_QUADS);
43       double dv = (opt->tmpMax - opt->tmpMin) / (opt->nbIso ? opt->nbIso : 1);
44       double v1 = opt->tmpMin + i * dv;
45       unsigned int col1 = opt->getColor(v1, opt->tmpMin, opt->tmpMax, true);
46       glColor4ubv((GLubyte *)&col1);
47       if(horizontal) {
48         glVertex2d(xmin + i * box, ymin + height);
49         glVertex2d(xmin + i * box, ymin);
50       }
51       else {
52         glVertex2d(xmin, ymin + i * box);
53         glVertex2d(xmin + width, ymin + i * box);
54       }
55       double v2 = opt->tmpMin + (i + 1) * dv;
56       unsigned int col2 = opt->getColor(v2, opt->tmpMin, opt->tmpMax, true);
57       glColor4ubv((GLubyte *)&col2);
58       if(horizontal) {
59         glVertex2d(xmin + (i + 1) * box, ymin);
60         glVertex2d(xmin + (i + 1) * box, ymin + height);
61       }
62       else {
63         glVertex2d(xmin + width, ymin + (i + 1) * box);
64         glVertex2d(xmin, ymin + (i + 1) * box);
65       }
66       glEnd();
67     }
68     else {
69       unsigned int col = opt->getColor(i, opt->nbIso);
70       glColor4ubv((GLubyte *)&col);
71       glBegin(GL_LINES);
72       if(horizontal) {
73         glVertex2d(xmin + box / 2. + i * box, ymin);
74         glVertex2d(xmin + box / 2. + i * box, ymin + height);
75       }
76       else {
77         glVertex2d(xmin, ymin + box / 2. + i * box);
78         glVertex2d(xmin + width, ymin + box / 2. + i * box);
79       }
80       glEnd();
81     }
82   }
83 }
84 
drawScaleValues(drawContext * ctx,PView * p,double xmin,double ymin,double width,double height,double tic,int horizontal)85 static void drawScaleValues(drawContext *ctx, PView *p, double xmin,
86                             double ymin, double width, double height,
87                             double tic, int horizontal)
88 {
89   PViewOptions *opt = p->getOptions();
90 
91   if(!opt->nbIso) return;
92 
93   drawContext::global()->setFont(CTX::instance()->glFontEnum,
94                                  CTX::instance()->glFontSize);
95   double font_h = drawContext::global()->getStringHeight(); // total font height
96   double font_a =
97     drawContext::global()->getStringHeight() -
98     drawContext::global()->getStringDescent(); // height above ref pt
99 
100   char label[1024];
101   sprintf(label, opt->format.c_str(), -M_PI * 1.e-4);
102   double maxw = drawContext::global()->getStringWidth(label);
103 
104   int nbv = opt->nbIso;
105   double f = (opt->intervalsType == PViewOptions::Discrete ||
106               opt->intervalsType == PViewOptions::Numeric ||
107               opt->intervalsType == PViewOptions::Continuous) ?
108                2 :
109                2.5;
110 
111   if(horizontal && width < nbv * maxw) {
112     if(width < f * maxw)
113       nbv = 1;
114     else
115       nbv = 2;
116   }
117   else if(!horizontal && height < nbv * font_h) {
118     if(height < f * font_h)
119       nbv = 1;
120     else
121       nbv = 2;
122   }
123 
124   double box = (horizontal ? width : height) / opt->nbIso;
125   double vbox = (horizontal ? width : height) / nbv;
126 
127   glColor4ubv((GLubyte *)&CTX::instance()->color.text);
128 
129   if(opt->intervalsType == PViewOptions::Discrete ||
130      opt->intervalsType == PViewOptions::Numeric ||
131      opt->intervalsType == PViewOptions::Continuous) {
132     for(int i = 0; i < nbv + 1; i++) {
133       double v = opt->getScaleValue(i, nbv + 1, opt->tmpMin, opt->tmpMax);
134       sprintf(label, opt->format.c_str(), v);
135       if(horizontal) {
136         ctx->drawStringCenter(label, xmin + i * vbox, ymin + height + tic, 0.);
137       }
138       else {
139         ctx->drawString(label, xmin + width + tic,
140                         ymin + i * vbox - font_a / 3., 0.);
141       }
142     }
143   }
144   else {
145     if(opt->nbIso > 2 && (nbv == 1 || nbv == 2)) {
146       vbox = (vbox * nbv - box) / nbv;
147       nbv++;
148     }
149     for(int i = 0; i < nbv; i++) {
150       double v = opt->getScaleValue(i, nbv, opt->tmpMin, opt->tmpMax);
151       sprintf(label, opt->format.c_str(), v);
152       if(horizontal) {
153         ctx->drawStringCenter(label, xmin + box / 2. + i * vbox,
154                               ymin + height + tic, 0.);
155       }
156       else {
157         ctx->drawString(label, xmin + width + tic,
158                         ymin + box / 2. + i * vbox - font_a / 3., 0.);
159       }
160     }
161   }
162 }
163 
drawScaleLabel(drawContext * ctx,PView * p,double xmin,double ymin,double width,double height,double tic,int horizontal)164 static void drawScaleLabel(drawContext *ctx, PView *p, double xmin, double ymin,
165                            double width, double height, double tic,
166                            int horizontal)
167 {
168   PViewOptions *opt = p->getOptions();
169   PViewData *data;
170 
171   // requested by Laurent: but is this really what we should be doing?
172   if(opt->externalViewIndex >= 0 &&
173      opt->externalViewIndex < (int)PView::list.size())
174     data = PView::list[opt->externalViewIndex]->getData();
175   else
176     data = p->getData();
177 
178   drawContext::global()->setFont(CTX::instance()->glFontEnum,
179                                  CTX::instance()->glFontSize);
180   double font_h = drawContext::global()->getStringHeight();
181 
182   char label[1024];
183 
184   int nt = data->getNumTimeSteps();
185   int n0 = data->getFirstNonEmptyTimeStep();
186   int n = (nt - n0 > 0) ? nt - n0 : 1;
187   char time[256];
188   sprintf(time, opt->format.c_str(), data->getTime(opt->timeStep));
189   int choice = opt->showTime;
190   if(choice == 3) { // automatic
191     if(n == 1)
192       choice = 0; // nothing
193     else if(n == 2)
194       choice = 2; // harmonic
195     else
196       choice = 5; // multi-step data
197   }
198   switch(choice) {
199   case 1: // time series
200     sprintf(label, "%s - time %s", data->getName().c_str(), time);
201     break;
202   case 2: // harmonic data
203     if(n <= 2)
204       sprintf(label, "%s - %s part", data->getName().c_str(),
205               ((opt->timeStep - n0) % 2) ? "imaginary" : "real");
206     else
207       sprintf(label, "%s - harmonic %s (%s part)", data->getName().c_str(),
208               time, ((opt->timeStep - n0) % 2) ? "imaginary" : "real");
209     break;
210   case 3: // automatic
211     // never here
212     break;
213   case 4: // step data
214     sprintf(label, "%s - step %d", data->getName().c_str(), opt->timeStep);
215     break;
216   case 5: // multi-step data
217     sprintf(label, "%s - step %d in [0,%d]", data->getName().c_str(),
218             opt->timeStep, data->getNumTimeSteps() - 1);
219     break;
220   case 6: // real eigenvalues
221     sprintf(label, "%s - eigenvalue %s", data->getName().c_str(), time);
222     break;
223   case 7: // complex eigenvalues
224     sprintf(label, "%s - eigenvalue %s (%s part)", data->getName().c_str(),
225             time, ((opt->timeStep - n0) % 2) ? "imaginary" : "real");
226     break;
227   default: sprintf(label, "%s", data->getName().c_str()); break;
228   }
229 
230   if(horizontal) {
231     ctx->drawString(
232       label, xmin + width / 2., ymin + height + tic + 1.4 * font_h, 0.,
233       CTX::instance()->glFontTitle, CTX::instance()->glFontEnumTitle,
234       CTX::instance()->glFontSizeTitle, 1);
235   }
236   else {
237     ctx->drawString(
238       label, xmin, ymin - 2 * font_h, 0., CTX::instance()->glFontTitle,
239       CTX::instance()->glFontEnumTitle, CTX::instance()->glFontSizeTitle, 0);
240   }
241 }
242 
drawScale(drawContext * ctx,PView * p,double xmin,double ymin,double width,double height,double tic,int horizontal)243 static void drawScale(drawContext *ctx, PView *p, double xmin, double ymin,
244                       double width, double height, double tic, int horizontal)
245 {
246   // use adaptive data if available
247   PViewData *data = p->getData(true);
248   PViewOptions *opt = p->getOptions();
249 
250   if(opt->externalViewIndex >= 0) {
251     opt->tmpMin = opt->externalMin;
252     opt->tmpMax = opt->externalMax;
253   }
254   else if(opt->rangeType == PViewOptions::Custom) {
255     opt->tmpMin = opt->customMin;
256     opt->tmpMax = opt->customMax;
257   }
258   else if(opt->rangeType == PViewOptions::PerTimeStep) {
259     opt->tmpMin = data->getMin(opt->timeStep);
260     opt->tmpMax = data->getMax(opt->timeStep);
261   }
262   else {
263     opt->tmpMin = data->getMin();
264     opt->tmpMax = data->getMax();
265   }
266 
267   drawScaleBar(p, xmin, ymin, width, height, tic, horizontal);
268   drawScaleValues(ctx, p, xmin, ymin, width, height, tic, horizontal);
269   drawScaleLabel(ctx, p, xmin, ymin, width, height, tic, horizontal);
270 }
271 
drawScales()272 void drawContext::drawScales()
273 {
274   std::vector<PView *> scales;
275   for(std::size_t i = 0; i < PView::list.size(); i++) {
276     PViewData *data = PView::list[i]->getData();
277     PViewOptions *opt = PView::list[i]->getOptions();
278     if(!data->getDirty() && opt->visible && opt->showScale &&
279        opt->type == PViewOptions::Plot3D && data->getNumElements() &&
280        isVisible(PView::list[i]))
281       scales.push_back(PView::list[i]);
282   }
283   if(scales.empty()) return;
284 
285   drawContext::global()->setFont(CTX::instance()->glFontEnum,
286                                  CTX::instance()->glFontSize);
287   char label[1024];
288   double maxw = 0.;
289   for(std::size_t i = 0; i < scales.size(); i++) {
290     PViewOptions *opt = scales[i]->getOptions();
291     sprintf(label, opt->format.c_str(), -M_PI * 1.e-4);
292     maxw = std::max(maxw, drawContext::global()->getStringWidth(label));
293   }
294 
295   const double tic = 10., bar_size = 16.;
296   double width = 0., width_prev = 0., width_total = 0.;
297 
298   for(std::size_t i = 0; i < scales.size(); i++) {
299     PView *p = scales[i];
300     PViewData *data = p->getData();
301     PViewOptions *opt = p->getOptions();
302 
303     if(!opt->autoPosition) {
304       double w = opt->size[0], h = opt->size[1];
305       double x = opt->position[0], y = opt->position[1];
306       int c = fix2dCoordinates(&x, &y);
307       if(c & 1) x -= w / 2.;
308       if(c & 2) y -= h / 2.;
309       drawScale(this, p, x, y, w, h, tic,
310                 CTX::instance()->post.horizontalScales);
311     }
312     else if(CTX::instance()->post.horizontalScales) {
313       double ysep = 20.;
314       double xc = (viewport[2] - viewport[0]) / 2.;
315       if(scales.size() == 1) {
316         double w = (viewport[2] - viewport[0]) / 2., h = bar_size;
317         double x = xc - w / 2., y = viewport[1] + ysep;
318         drawScale(this, p, x, y, w, h, tic, 1);
319       }
320       else {
321         double xsep = maxw / 4. + (viewport[2] - viewport[0]) / 10.;
322         double w = (viewport[2] - viewport[0] - 4 * xsep) / 2.;
323         if(w < 20.) w = 20.;
324         double h = bar_size;
325         double x = xc - (i % 2 ? -xsep / 1.5 : w + xsep / 1.5);
326         double y =
327           viewport[1] + ysep +
328           (i / 2) * (bar_size + tic +
329                      2 * drawContext::global()->getStringHeight() + ysep);
330         drawScale(this, p, x, y, w, h, tic, 1);
331       }
332     }
333     else {
334       double xsep = 20.;
335       double dy = 2. * drawContext::global()->getStringHeight();
336       if(scales.size() == 1) {
337         double ysep = (viewport[3] - viewport[1]) / 6.;
338         double w = bar_size, h = viewport[3] - viewport[1] - 2 * ysep - dy;
339         double x = viewport[0] + xsep, y = viewport[1] + ysep + dy;
340         drawScale(this, p, x, y, w, h, tic, 0);
341       }
342       else {
343         double ysep = (viewport[3] - viewport[1]) / 15.;
344         double w = bar_size;
345         double h = (viewport[3] - viewport[1] - 3 * ysep - 2.5 * dy) / 2.;
346         double x = viewport[0] + xsep + width_total + (i / 2) * xsep;
347         double y =
348           viewport[1] + ysep + dy + (1 - i % 2) * (h + 1.5 * dy + ysep);
349         drawScale(this, p, x, y, w, h, tic, 0);
350       }
351       // compute width
352       width_prev = width;
353       sprintf(label, opt->format.c_str(), -M_PI * 1.e-4);
354       width = bar_size + tic + drawContext::global()->getStringWidth(label);
355       if(opt->showTime) {
356         char tmp[256];
357         sprintf(tmp, opt->format.c_str(), data->getTime(opt->timeStep));
358         sprintf(label, "%s (%s)", data->getName().c_str(), tmp);
359       }
360       else
361         sprintf(label, "%s", data->getName().c_str());
362       width = std::max(width, drawContext::global()->getStringWidth(label));
363       if(i % 2)
364         width_total += std::max(bar_size + width, bar_size + width_prev);
365     }
366   }
367 }
368