]> git.mxchange.org Git - flightgear.git/blob - src/Instrumentation/HUD/HUD_tape.cxx
NavDisplay enhancements for Syd.
[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
253         float y = _y + (v - vmin) * factor();
254
255         if (y < _y + TICK_OFFSET)
256             continue;
257         if (y > top - TICK_OFFSET)
258             break;
259
260         if (_div_ratio && i % _div_ratio) { // minor div
261             if (option_both()) {
262                 if (_tick_type == LINE) {
263                     if (_tick_length == VARIABLE) {
264                         draw_line(_x, y, marker_xs, y);
265                         draw_line(marker_xe, y, right, y);
266                     } else {
267                         draw_line(_x, y, marker_xs, y);
268                         draw_line(marker_xe, y, right, y);
269                     }
270
271                 } else { // _tick_type == CIRCLE
272                     draw_bullet(_x, y, 3.0);
273                 }
274
275             } else if (option_left()) {
276                 if (_tick_type == LINE) {
277                     if (_tick_length == VARIABLE) {
278                         draw_line(marker_xs + min_diff, y, marker_xe, y);
279                     } else {
280                         draw_line(marker_xs, y, marker_xe, y);
281                     }
282                 } else { // _tick_type == CIRCLE
283                     draw_bullet(marker_xs + 4, y, 3.0);
284                 }
285
286             } else { // if (option_right())
287                 if (_tick_type == LINE) {
288                     if (_tick_length == VARIABLE) {
289                         draw_line(marker_xs, y, marker_xe - min_diff, y);
290                     } else {
291                         draw_line(marker_xs, y, marker_xe, y);
292                     }
293
294                 } else { // _tick_type == CIRCLE
295                     draw_bullet(marker_xe - 4, y, 3.0);
296                 }
297             } // end huds both
298
299         } else { // major div
300             if (_modulo)
301                 v = fmodf(v + _modulo, _modulo);
302
303             float x;
304             int align;
305
306             if (option_both()) {
307                 if (_tick_type == LINE) {
308                     draw_line(_x, y, marker_xs, y);
309                     draw_line(marker_xs, y, right, y);
310
311                 } else { // _tick_type == CIRCLE
312                     draw_bullet(_x, y, 5.0);
313                 }
314
315                 x = marker_xs, align = CENTER;
316
317             } else {
318                 if (_tick_type == LINE)
319                     draw_line(marker_xs, y, marker_xe, y);
320                 else // _tick_type == CIRCLE
321                     draw_bullet(marker_xs + 4, y, 5.0);
322
323                 if (option_left())
324                     x = marker_xs - _label_offset, align = RIGHT|VCENTER;
325                 else
326                     x = marker_xe + _label_offset, align = LEFT|VCENTER;
327             }
328
329             if (!option_notext()) {
330                 char *s = format_value(v);
331
332                 float l, r, b, t;
333                 _hud->_text_list.align(s, align, &x, &y, &l, &r, &b, &t);
334
335                 if (b < _y || t > top)
336                     continue;
337
338                 if (_label_gap == 0.0
339                         || (b < _center_y - _label_gap && t < _center_y - _label_gap)
340                         || (b > _center_y + _label_gap && t > _center_y + _label_gap)) {
341                     draw_text(x, y, s);
342                 }
343             }
344         }
345     } // for
346 }
347
348
349 void HUD::Tape::draw_horizontal(float value)
350 {
351     float vmin = 0.0;//, vmax = 0.0;
352     float marker_xs;
353 //    float marker_xe;
354     float marker_ys;
355     float marker_ye;
356 //    float text_y = 0.0;
357
358     float top = _y + _h;
359     float right = _x + _w;
360
361
362     if (!_pointer) {
363         vmin = value - _half_width_units; // width units == needle travel
364 //        vmax = value + _half_width_units; // or picture unit span.
365 //        text_y = _center_y;
366
367     } else if (_pointer_type == MOVING) {
368         vmin = _input.min();
369 //        vmax = _input.max();
370
371     } else { // FIXED
372         vmin = value - _half_width_units; // width units == needle travel
373 //        vmax = value + _half_width_units; // or picture unit span.
374 //        text_y = _center_y;
375     }
376
377     // left tick bar
378     if (_draw_tick_left)
379         draw_line(_x, _y, _x, top);
380
381     // right tick bar
382     if (_draw_tick_right)
383         draw_line(right, _y, right, top);
384
385     marker_ys = _y;    // Starting point for
386     marker_ye = top;           // tick y location calcs
387 //    marker_xe = right;
388     marker_xs = _x + ((value - vmin) * factor());
389
390     if (option_top()) {
391         if (_draw_cap_bottom)
392             draw_line(_x, _y, right, _y);
393
394         // Tick point adjust
395         marker_ye  = _y + _h / 2;
396         // Bottom arrow
397         // draw_line(_center_x, marker_ye, _center_x - _h / 4, _y);
398         // draw_line(_center_x, marker_ye, _center_x + _h / 4, _y);
399         // draw pointer
400         if (_pointer) {
401             if (_pointer_type == MOVING) {
402                 float xcentre = _center_x;
403                 float range = _w;
404                 float xpoint = xcentre + (value * range / _val_span);
405                 float ypoint = _y - _marker_offset;
406                 draw_line(xcentre, ypoint, xpoint, ypoint);
407                 draw_line(xpoint, ypoint, xpoint, ypoint + _marker_offset);
408                 draw_line(xpoint, ypoint + _marker_offset, xpoint + 5.0, ypoint + 5.0);
409                 draw_line(xpoint, ypoint + _marker_offset, xpoint - 5.0, ypoint + 5.0);
410
411             } else { // FIXED
412                 draw_fixed_pointer(marker_xs - _h / 4, _y, marker_xs,
413                         marker_ye, marker_xs + _h / 4, _y);
414             }
415         }
416     } // if (option_top())
417
418     if (option_bottom()) {
419         if (_draw_cap_top)
420             draw_line(_x, top, right, top);
421
422         // Tick point adjust
423         marker_ys = top - _h / 2;
424         // Top arrow
425         // draw_line(_center_x + _h / 4, _y + _h, _center_x, marker_ys);
426         // draw_line(_center_x - _h / 4, _y + _h, _center_x , marker_ys);
427
428         if (_pointer) {
429             if (_pointer_type == MOVING) {
430                 float xcentre = _center_x;
431                 float range = _w;
432                 float hgt = _y + _h;
433                 float xpoint = xcentre + (value * range / _val_span);
434                 float ypoint = hgt + _marker_offset;
435                 draw_line(xcentre, ypoint, xpoint, ypoint);
436                 draw_line(xpoint, ypoint, xpoint, ypoint - _marker_offset);
437                 draw_line(xpoint, ypoint - _marker_offset, xpoint + 5.0, ypoint - 5.0);
438                 draw_line(xpoint, ypoint - _marker_offset, xpoint - 5.0, ypoint - 5.0);
439
440             } else { // FIXED
441                 draw_fixed_pointer(marker_xs + _h / 4, top, marker_xs, marker_ys,
442                         marker_xs - _h / 4, top);
443             }
444         }
445     } // if (option_bottom())
446
447
448     float vstart = floorf(vmin / _major_divs) * _major_divs;
449     float min_diff = _h / 6.0;    // length difference between major & minor tick
450
451     // FIXME consider oddtype
452     for (int i = 0; ; i++) {
453         float v = vstart + i * _minor_divs;
454
455         if (!_modulo) {
456             if (v < _input.min())
457                 continue;
458             else if (v > _input.max())
459                 break;
460         }
461
462         float x = _x + (v - vmin) * factor();
463
464         if (x < _x + TICK_OFFSET)
465             continue;
466         if (x > right - TICK_OFFSET)
467             break;
468
469         if (_div_ratio && i % _div_ratio) { // minor div
470             if (option_both()) {
471                 if (_tick_length == VARIABLE) {
472                     draw_line(x, _y, x, marker_ys - 4);
473                     draw_line(x, marker_ye + 4, x, top);
474                 } else {
475                     draw_line(x, _y, x, marker_ys);
476                     draw_line(x, marker_ye, x, top);
477                 }
478
479             } else {
480                 if (option_top()) {
481                     // draw minor ticks
482                     if (_tick_length == VARIABLE)
483                         draw_line(x, marker_ys, x, marker_ye - min_diff);
484                     else
485                         draw_line(x, marker_ys, x, marker_ye);
486
487                 } else if (_tick_length == VARIABLE) {
488                     draw_line(x, marker_ys + 4, x, marker_ye);
489                 } else {
490                     draw_line(x, marker_ys, x, marker_ye);
491                 }
492             }
493
494         } else { // major divs
495             if (_modulo)
496                 v = fmodf(v + _modulo, _modulo);
497
498             float y;
499             int align;
500
501             if (option_both()) {
502                 draw_line(x, _y, x, marker_ye);
503                 draw_line(x, marker_ye, x, _y + _h);
504                 y = marker_ys, align = CENTER;
505
506             } else {
507                 draw_line(x, marker_ys, x, marker_ye);
508
509                 if (option_top())
510                     y = top - _label_offset, align = TOP|HCENTER;
511                 else
512                     y = _y + _label_offset, align = BOTTOM|HCENTER;
513             }
514
515             if (!option_notext()) {
516                 char *s = format_value(v);
517
518                 float l, r, b, t;
519                 _hud->_text_list.align(s, align, &x, &y, &l, &r, &b, &t);
520
521                 if (l < _x || r > right)
522                     continue;
523
524                 if (_label_gap == 0.0
525                         || (l < _center_x - _label_gap && r < _center_x - _label_gap)
526                         || (l > _center_x + _label_gap && r > _center_x + _label_gap)) {
527                     draw_text(x, y, s);
528                 }
529             }
530         }
531     } // for
532 }
533
534
535 char *HUD::Tape::format_value(float v)
536 {
537     if (fabs(v) < 1e-8)   // avoid -0.0
538         v = 0.0f;
539
540     if (_label_fmt == INT)
541         snprintf(_buf, BUFSIZE, _format.c_str(), int(v));
542     else if (_label_fmt == LONG)
543         snprintf(_buf, BUFSIZE, _format.c_str(), long(v));
544     else if (_label_fmt == FLOAT)
545         snprintf(_buf, BUFSIZE, _format.c_str(), v);
546     else // _label_fmt == DOUBLE
547         snprintf(_buf, BUFSIZE, _format.c_str(), double(v));
548     return _buf;
549 }
550
551
552 void HUD::Tape::draw_fixed_pointer(float x1, float y1, float x2, float y2, float x3, float y3)
553 {
554     glBegin(GL_LINE_STRIP);
555     glVertex2f(x1, y1);
556     glVertex2f(x2, y2);
557     glVertex2f(x3, y3);
558     glEnd();
559 }
560
561