]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/HUD/HUD_tape.cxx
add <label-offset> param for adjusting number labels in scales
[flightgear.git] / src / Instrumentation / HUD / HUD_tape.cxx
1 // HUD_tape.cxx -- HUD Tape Instrument
2 //
3 // Written by Michele America, started September 1997.
4 //
5 // Copyright (C) 1997  Michele F. America  [micheleamerica#geocities:com]
6 // Copyright (C) 2006  Melchior FRANZ  [mfranz#aon:at]
7 //
8 // This program is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU General Public License as
10 // published by the Free Software Foundation; either version 2 of the
11 // License, or (at your option) any later version.
12 //
13 // This program is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 // General Public License for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // along with this program; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21
22 #include "HUD.hxx"
23
24 static const float TICK_OFFSET = 2.f;
25
26
27 HUD::Tape::Tape(HUD *hud, const SGPropertyNode *n, float x, float y) :
28     Scale(hud, n, x, y),
29     _draw_tick_bottom(n->getBoolValue("tick-bottom", false)),
30     _draw_tick_top(n->getBoolValue("tick-top", false)),
31     _draw_tick_right(n->getBoolValue("tick-right", false)),
32     _draw_tick_left(n->getBoolValue("tick-left", false)),
33     _draw_cap_bottom(n->getBoolValue("cap-bottom", false)),
34     _draw_cap_top(n->getBoolValue("cap-top", false)),
35     _draw_cap_right(n->getBoolValue("cap-right", false)),
36     _draw_cap_left(n->getBoolValue("cap-left", false)),
37     _marker_offset(n->getFloatValue("marker-offset")),
38     _label_offset(n->getFloatValue("label-offset", 3.0)),
39     _label_gap(n->getFloatValue("label-gap-width") / 2.0),
40     _pointer(n->getBoolValue("enable-pointer", true)),
41     _format(n->getStringValue("format", "%d"))
42 {
43     _half_width_units = range_to_show() / 2.0;
44
45     const char *s;
46     s = n->getStringValue("pointer-type");
47     _pointer_type = strcmp(s, "moving") ? FIXED : MOVING;    // "fixed", "moving"
48
49     s = n->getStringValue("tick-type");
50     _tick_type = strcmp(s, "bullet") ? LINE : CIRCLE;        // "bullet", "line"
51
52     s = n->getStringValue("tick-length");                    // "variable", "constant"
53     _tick_length = strcmp(s, "constant") ? VARIABLE : CONSTANT;
54
55     _label_fmt = check_format(_format.c_str());
56     if (_label_fmt != INT && _label_fmt != LONG
57             && _label_fmt != FLOAT && _label_fmt != DOUBLE) {
58         SG_LOG(SG_INPUT, SG_ALERT, "HUD: invalid <format> '" << _format.c_str()
59                 << "' in <tape> '" << _name << "' (must be number format)");
60         _label_fmt = INT;
61         _format = "%d";
62     }
63
64     if (_minor_divs != 0.0f)
65         _div_ratio = int(_major_divs / _minor_divs + 0.5f);
66     else
67         _div_ratio = 0, _minor_divs = _major_divs;
68
69 //    int k; //odd or even values for ticks             // FIXME odd scale
70     _odd_type = false;
71     if (_input.max() + .5f < float(SGLimits<long>::max()))
72         _odd_type = long(floorf(_input.max() + 0.5f)) & 1 ? true : false;
73 }
74
75
76 void HUD::Tape::draw(void) //  (HUD_scale * pscale)
77 {
78     if (!_input.isValid())
79         return;
80
81     float value = _input.getFloatValue();
82
83     if (option_vert())
84         draw_vertical(value);
85     else
86         draw_horizontal(value);
87 }
88
89
90 void HUD::Tape::draw_vertical(float value)
91 {
92     float vmin = 0.0, vmax = 0.0;
93     float marker_xs;
94     float marker_xe;
95     float marker_ye;
96     float text_y = 0.0;
97
98     float top = _y + _h;
99     float right = _x + _w;
100
101
102     if (!_pointer) {
103         vmin = value - _half_width_units; // width units == needle travel
104         vmax = value + _half_width_units; // or picture unit span.
105         text_y = _center_y;
106
107     } else if (_pointer_type == MOVING) {
108         vmin = _input.min();
109         vmax = _input.max();
110
111     } else { // FIXED
112         vmin = value - _half_width_units; // width units == needle travel
113         vmax = value + _half_width_units; // or picture unit span.
114         text_y = _center_y;
115     }
116
117     // Bottom tick bar
118     if (_draw_tick_bottom)
119         draw_line(_x, _y, right, _y);
120
121     // Top tick bar
122     if (_draw_tick_top)
123         draw_line(_x, top, right, top);
124
125     marker_xs = _x;       // x start
126     marker_xe = right;    // x extent
127     marker_ye = top;
128
129     // We do not use else in the following so that combining the
130     // two options produces a "caged" display with double
131     // carrots. The same is done for horizontal card indicators.
132
133     // draw capping lines and pointers
134     if (option_left()) {    // Calculate x marker offset
135
136         if (_draw_cap_right)
137             draw_line(marker_xe, _y, marker_xe, marker_ye);
138
139         marker_xs = marker_xe - _w / 3.0;
140
141         // draw_line(marker_xs, _center_y, marker_xe, _center_y + _w / 6);
142         // draw_line(marker_xs, _center_y, marker_xe, _center_y - _w / 6);
143
144         if (_pointer) {
145             if (_pointer_type == MOVING) {
146                 float ycentre, ypoint, xpoint;
147                 float range, right;
148
149                 if (_input.min() >= 0.0)
150                     ycentre = _y;
151                 else if (_input.max() + _input.min() == 0.0)
152                     ycentre = _center_y;
153                 else if (_odd_type)
154                     ycentre = _y + (1.0 - _input.min()) * _h / (_input.max() - _input.min());
155                 else
156                     ycentre = _y + _input.min() * _h / (_input.max() - _input.min());
157
158                 range = _h;
159                 right = _x + _w;
160
161                 if (_odd_type)
162                     ypoint = ycentre + ((value - 1.0) * range / _val_span);
163                 else
164                     ypoint = ycentre + (value * range / _val_span);
165
166                 xpoint = right + _marker_offset;
167                 draw_line(xpoint, ycentre, xpoint, ypoint);
168                 draw_line(xpoint, ypoint, xpoint - _marker_offset, ypoint);
169                 draw_line(xpoint - _marker_offset, ypoint, xpoint - 5.0, ypoint + 5.0);
170                 draw_line(xpoint - _marker_offset, ypoint, xpoint - 5.0, ypoint - 5.0);
171
172             } else { // FIXED
173                 draw_fixed_pointer(_marker_offset + marker_xe, text_y + _w / 6,
174                         _marker_offset + marker_xs, text_y, _marker_offset + marker_xe,
175                         text_y - _w / 6);
176             }
177         }
178     } // if (option_left())
179
180
181     // draw capping lines and pointers
182     if (option_right()) {
183
184         if (_draw_cap_left)
185             draw_line(_x, _y, _x, marker_ye);
186
187         marker_xe = _x + _w / 3.0;
188         // Indicator carrot
189         // draw_line(_x, _center_y +  _w / 6, marker_xe, _center_y);
190         // draw_line(_x, _center_y -  _w / 6, marker_xe, _center_y);
191
192         if (_pointer) {
193             if (_pointer_type == MOVING) {
194                 float ycentre, ypoint, xpoint;
195                 float range;
196
197                 if (_input.min() >= 0.0)
198                     ycentre = _y;
199                 else if (_input.max() + _input.min() == 0.0)
200                     ycentre = _center_y;
201                 else if (_odd_type)
202                     ycentre = _y + (1.0 - _input.min()) * _h / (_input.max() - _input.min());
203                 else
204                     ycentre = _y + _input.min() * _h / (_input.max() - _input.min());
205
206                 range = _h;
207
208                 if (_odd_type)
209                     ypoint = ycentre + ((value - 1.0) * range / _val_span);
210                 else
211                     ypoint = ycentre + (value * range / _val_span);
212
213                 xpoint = _x - _marker_offset;
214                 draw_line(xpoint, ycentre, xpoint, ypoint);
215                 draw_line(xpoint, ypoint, xpoint + _marker_offset, ypoint);
216                 draw_line(xpoint + _marker_offset, ypoint, xpoint + 5.0, ypoint + 5.0);
217                 draw_line(xpoint + _marker_offset, ypoint, xpoint + 5.0, ypoint - 5.0);
218
219             } else { // FIXED
220                 draw_fixed_pointer(-_marker_offset + _x, text_y +  _w / 6,
221                         -_marker_offset + marker_xe, text_y, -_marker_offset + _x,
222                         text_y - _w / 6);
223             }
224         } // if (_pointer)
225     } // if (option_right())
226
227
228     // At this point marker x_start and x_end values are transposed.
229     // To keep this from confusing things they are now swapped.
230     if (option_both())
231         marker_ye = marker_xs, marker_xs = marker_xe, marker_xe = marker_ye;
232
233
234
235     // Work through from bottom to top of scale. Calculating where to put
236     // minor and major ticks.
237
238     // draw scale or tape
239     float vstart = floorf(vmin / _major_divs) * _major_divs;
240     float min_diff = _w / 6.0;    // length difference between major & minor tick
241
242     // FIXME consider oddtype
243     for (int i = 0; ; i++) {
244         float v = vstart + i * _minor_divs;
245
246         if (!_modulo)
247             if (v < _input.min())
248                 continue;
249             else if (v > _input.max())
250                 break;
251
252         float y = _y + (v - vmin) * factor();
253
254         if (y < _y + TICK_OFFSET)
255             continue;
256         if (y > top - TICK_OFFSET)
257             break;
258
259         if (_div_ratio && i % _div_ratio) { // minor div
260             if (option_both()) {
261                 if (_tick_type == LINE) {
262                     if (_tick_length == VARIABLE) {
263                         draw_line(_x, y, marker_xs, y);
264                         draw_line(marker_xe, y, right, y);
265                     } else {
266                         draw_line(_x, y, marker_xs, y);
267                         draw_line(marker_xe, y, right, y);
268                     }
269
270                 } else { // _tick_type == CIRCLE
271                     draw_bullet(_x, y, 3.0);
272                 }
273
274             } else if (option_left()) {
275                 if (_tick_type == LINE) {
276                     if (_tick_length == VARIABLE) {
277                         draw_line(marker_xs + min_diff, y, marker_xe, y);
278                     } else {
279                         draw_line(marker_xs, y, marker_xe, y);
280                     }
281                 } else { // _tick_type == CIRCLE
282                     draw_bullet(marker_xs + 4, y, 3.0);
283                 }
284
285             } else { // if (option_right())
286                 if (_tick_type == LINE) {
287                     if (_tick_length == VARIABLE) {
288                         draw_line(marker_xs, y, marker_xe - min_diff, y);
289                     } else {
290                         draw_line(marker_xs, y, marker_xe, y);
291                     }
292
293                 } else { // _tick_type == CIRCLE
294                     draw_bullet(marker_xe - 4, y, 3.0);
295                 }
296             } // end huds both
297
298         } else { // major div
299             if (_modulo)
300                 v = fmodf(v + _modulo, _modulo);
301
302             float x;
303             int align;
304
305             if (option_both()) {
306                 if (_tick_type == LINE) {
307                     draw_line(_x, y, marker_xs, y);
308                     draw_line(marker_xs, y, right, y);
309
310                 } else { // _tick_type == CIRCLE
311                     draw_bullet(_x, y, 5.0);
312                 }
313
314                 x = marker_xs, align = CENTER;
315
316             } else {
317                 if (_tick_type == LINE)
318                     draw_line(marker_xs, y, marker_xe, y);
319                 else // _tick_type == CIRCLE
320                     draw_bullet(marker_xs + 4, y, 5.0);
321
322                 if (option_left())
323                     x = marker_xs - _label_offset, align = RIGHT|VCENTER;
324                 else
325                     x = marker_xe + _label_offset, align = LEFT|VCENTER;
326             }
327
328             if (!option_notext()) {
329                 char *s = format_value(v);
330
331                 float l, r, b, t;
332                 _hud->_text_list.align(s, align, &x, &y, &l, &r, &b, &t);
333
334                 if (b < _y || t > top)
335                     continue;
336
337                 if (_label_gap == 0.0
338                         || b < _center_y - _label_gap && t < _center_y - _label_gap
339                         || b > _center_y + _label_gap && t > _center_y + _label_gap) {
340                     draw_text(x, y, s);
341                 }
342             }
343         }
344     } // for
345 }
346
347
348 void HUD::Tape::draw_horizontal(float value)
349 {
350     float vmin = 0.0, vmax = 0.0;
351     float marker_xs;
352     float marker_xe;
353     float marker_ys;
354     float marker_ye;
355     float text_y = 0.0;
356
357     float top = _y + _h;
358     float right = _x + _w;
359
360
361     if (!_pointer) {
362         vmin = value - _half_width_units; // width units == needle travel
363         vmax = value + _half_width_units; // or picture unit span.
364         text_y = _center_y;
365
366     } else if (_pointer_type == MOVING) {
367         vmin = _input.min();
368         vmax = _input.max();
369
370     } else { // FIXED
371         vmin = value - _half_width_units; // width units == needle travel
372         vmax = value + _half_width_units; // or picture unit span.
373         text_y = _center_y;
374     }
375
376     // left tick bar
377     if (_draw_tick_left)
378         draw_line(_x, _y, _x, top);
379
380     // right tick bar
381     if (_draw_tick_right)
382         draw_line(right, _y, right, top);
383
384     marker_ys = _y;    // Starting point for
385     marker_ye = top;           // tick y location calcs
386     marker_xe = right;
387     marker_xs = _x + ((value - vmin) * factor());
388
389     if (option_top()) {
390         if (_draw_cap_bottom)
391             draw_line(_x, _y, right, _y);
392
393         // Tick point adjust
394         marker_ye  = _y + _h / 2;
395         // Bottom arrow
396         // draw_line(_center_x, marker_ye, _center_x - _h / 4, _y);
397         // draw_line(_center_x, marker_ye, _center_x + _h / 4, _y);
398         // draw pointer
399         if (_pointer) {
400             if (_pointer_type == MOVING) {
401                 float xcentre = _center_x;
402                 float range = _w;
403                 float xpoint = xcentre + (value * range / _val_span);
404                 float ypoint = _y - _marker_offset;
405                 draw_line(xcentre, ypoint, xpoint, ypoint);
406                 draw_line(xpoint, ypoint, xpoint, ypoint + _marker_offset);
407                 draw_line(xpoint, ypoint + _marker_offset, xpoint + 5.0, ypoint + 5.0);
408                 draw_line(xpoint, ypoint + _marker_offset, xpoint - 5.0, ypoint + 5.0);
409
410             } else { // FIXED
411                 draw_fixed_pointer(marker_xs - _h / 4, _y, marker_xs,
412                         marker_ye, marker_xs + _h / 4, _y);
413             }
414         }
415     } // if (option_top())
416
417     if (option_bottom()) {
418         if (_draw_cap_top)
419             draw_line(_x, top, right, top);
420
421         // Tick point adjust
422         marker_ys = top - _h / 2;
423         // Top arrow
424         // draw_line(_center_x + _h / 4, _y + _h, _center_x, marker_ys);
425         // draw_line(_center_x - _h / 4, _y + _h, _center_x , marker_ys);
426
427         if (_pointer) {
428             if (_pointer_type == MOVING) {
429                 float xcentre = _center_x;
430                 float range = _w;
431                 float hgt = _y + _h;
432                 float xpoint = xcentre + (value * range / _val_span);
433                 float ypoint = hgt + _marker_offset;
434                 draw_line(xcentre, ypoint, xpoint, ypoint);
435                 draw_line(xpoint, ypoint, xpoint, ypoint - _marker_offset);
436                 draw_line(xpoint, ypoint - _marker_offset, xpoint + 5.0, ypoint - 5.0);
437                 draw_line(xpoint, ypoint - _marker_offset, xpoint - 5.0, ypoint - 5.0);
438
439             } else { // FIXED
440                 draw_fixed_pointer(marker_xs + _h / 4, top, marker_xs, marker_ys,
441                         marker_xs - _h / 4, top);
442             }
443         }
444     } // if (option_bottom())
445
446
447     float vstart = floorf(vmin / _major_divs) * _major_divs;
448     float min_diff = _h / 6.0;    // length difference between major & minor tick
449
450     // FIXME consider oddtype
451     for (int i = 0; ; i++) {
452         float v = vstart + i * _minor_divs;
453
454         if (!_modulo)
455             if (v < _input.min())
456                 continue;
457             else if (v > _input.max())
458                 break;
459
460         float x = _x + (v - vmin) * factor();
461
462         if (x < _x + TICK_OFFSET)
463             continue;
464         if (x > right - TICK_OFFSET)
465             break;
466
467         if (_div_ratio && i % _div_ratio) { // minor div
468             if (option_both()) {
469                 if (_tick_length == VARIABLE) {
470                     draw_line(x, _y, x, marker_ys - 4);
471                     draw_line(x, marker_ye + 4, x, top);
472                 } else {
473                     draw_line(x, _y, x, marker_ys);
474                     draw_line(x, marker_ye, x, top);
475                 }
476
477             } else {
478                 if (option_top()) {
479                     // draw minor ticks
480                     if (_tick_length == VARIABLE)
481                         draw_line(x, marker_ys, x, marker_ye - min_diff);
482                     else
483                         draw_line(x, marker_ys, x, marker_ye);
484
485                 } else if (_tick_length == VARIABLE) {
486                     draw_line(x, marker_ys + 4, x, marker_ye);
487                 } else {
488                     draw_line(x, marker_ys, x, marker_ye);
489                 }
490             }
491
492         } else { // major divs
493             if (_modulo)
494                 v = fmodf(v + _modulo, _modulo);
495
496             float y;
497             int align;
498
499             if (option_both()) {
500                 draw_line(x, _y, x, marker_ye);
501                 draw_line(x, marker_ye, x, _y + _h);
502                 y = marker_ys, align = CENTER;
503
504             } else {
505                 draw_line(x, marker_ys, x, marker_ye);
506
507                 if (option_top())
508                     y = top - _label_offset, align = TOP|HCENTER;
509                 else
510                     y = _y + _label_offset, align = BOTTOM|HCENTER;
511             }
512
513             if (!option_notext()) {
514                 char *s = format_value(v);
515
516                 float l, r, b, t;
517                 _hud->_text_list.align(s, align, &x, &y, &l, &r, &b, &t);
518
519                 if (l < _x || r > right)
520                     continue;
521
522                 if (_label_gap == 0.0
523                         || l < _center_x - _label_gap && r < _center_x - _label_gap
524                         || l > _center_x + _label_gap && r > _center_x + _label_gap) {
525                     draw_text(x, y, s);
526                 }
527             }
528         }
529     } // for
530 }
531
532
533 char *HUD::Tape::format_value(float v)
534 {
535     if (fabsf(v) < 1e-8)   // avoid -0.0
536         v = 0.0f;
537
538     if (_label_fmt == INT)
539         snprintf(_buf, BUFSIZE, _format.c_str(), int(v));
540     else if (_label_fmt == LONG)
541         snprintf(_buf, BUFSIZE, _format.c_str(), long(v));
542     else if (_label_fmt == FLOAT)
543         snprintf(_buf, BUFSIZE, _format.c_str(), v);
544     else // _label_fmt == DOUBLE
545         snprintf(_buf, BUFSIZE, _format.c_str(), double(v));
546     return _buf;
547 }
548
549
550 void HUD::Tape::draw_fixed_pointer(float x1, float y1, float x2, float y2, float x3, float y3)
551 {
552     glBegin(GL_LINE_STRIP);
553     glVertex2f(x1, y1);
554     glVertex2f(x2, y2);
555     glVertex2f(x3, y3);
556     glEnd();
557 }
558
559