]> git.mxchange.org Git - flightgear.git/blob - src/GUI/sgVec3Slider.cxx
Patch from Jim Wilson:
[flightgear.git] / src / GUI / sgVec3Slider.cxx
1 /**
2  *      sgVec3Slider.cxx
3  *
4  *      Simple PUI wrapper around sgVec3 class
5  *
6  *      Created by: Norman Vine [NHV]
7  *         nhv@yahoo.com, nhv@cape.com
8  *
9  *      Revision History
10  *      ---------------- 
11  *  Started 12:53 01/28/2001
12  *
13  */
14
15 #include "sgVec3Slider.hxx"
16 #include <Main/fg_props.hxx>
17 #include <simgear/sg_inlines.h>
18
19 class FloatSlider : public puSlider
20 {
21
22 protected:
23         float maxValue;
24         float minValue;
25         float origValue;
26         float Adjust;
27         float MyValue;
28         float TmpValue;
29         float SaveValue;
30         char buf[8];
31         char _title[32];
32         char _text[16];
33 public:
34         FloatSlider ( int x, int y, int sz, float f, const char *title,
35                                   float max = 100.0f, float min = 0.0f);
36
37         ~FloatSlider () {;}
38
39         static void adj( puObject *);
40                 
41         void updateText() {
42                 sprintf( _text, "%05.2f", MyValue );
43         }
44
45         float get() { return( MyValue ); }
46
47         // calc actual "setting" by multiplying the pui fraction by highest value setable
48         void  set() { MyValue = maxValue * TmpValue; }
49
50         float *getTmp() { return( &TmpValue ); }
51
52         // adjust the TmpValue back to 0 to 1 range of pui widget
53         void   setTmp() { TmpValue += 0.0f; }
54
55         void incTmp() { TmpValue += 0.0001f; setTmp(); }
56         void decTmp() { TmpValue -= 0.0001f; setTmp(); }
57
58         // adjust actual "setting" value back to fraction for pui widget
59         void init( float f ) {
60                 if (f > maxValue) f = maxValue;
61                 if (f < minValue) f = minValue;
62                 Adjust   = 1.0f / maxValue;
63                 setValue(f * Adjust);
64                 adj( this );
65         }
66
67         void reinit() { init( origValue ); }
68         void cancel() { MyValue = TmpValue; }
69         void reset () { init( origValue ); }
70
71 };
72
73 void FloatSlider::adj( puObject *hs )
74 {
75         FloatSlider *slider = (FloatSlider *)hs;
76         slider->getValue ( slider->getTmp() );
77         slider->setTmp();
78         slider->set();
79         slider->updateText();
80 }
81
82 FloatSlider::FloatSlider ( int x, int y, int sz, float f, const char *title,
83                                                    float max, float min ) :  puSlider( x, y, sz, FALSE )
84 {
85         maxValue = max;
86         minValue = min;
87         origValue = f;
88         init(f);
89         setDelta    ( 0.01 );
90         setCBMode   ( PUSLIDER_DELTA ) ;
91         strcpy      ( _title, title);
92         setLabel    ( _title );
93         setLabelPlace ( PUPLACE_LEFT );
94         setLegend(_text);
95         // setLegendPlace( PUPLACE_RIGHT );
96 }
97
98
99 class FloatDial : public puDial
100 {
101
102 protected:
103         float maxValue;
104         float minValue;
105         float origValue;
106         float Adjust;
107         float MyValue;
108         float TmpValue;
109         float SaveValue;
110         char buf[8];
111         char _title[32];
112         char _text[16];
113 public:
114         FloatDial ( int x, int y, int sz, float f, const char *title,
115                                   float max = 180.0f, float min = -180.0f );
116
117         ~FloatDial () {;}
118                 
119         static void adj( puObject *);
120
121         void updateText() {
122                 sprintf( _text, "%05.2f", MyValue );
123         }
124
125         float get() { return( MyValue ); }
126
127         // calc actual "setting" by multiplying the pui fraction by highest value setable
128         // in this case we're also turning a 0 to 1 range into a -.05 to +.05 before converting
129         void  set() { MyValue = ((2.0*maxValue) * (TmpValue - 0.5f)) - maxValue; }
130
131         float *getTmp() { return( &TmpValue ); }
132
133         // adjust the TmpValue back to 0 to 1 range of pui widget
134         void   setTmp() { TmpValue += 0.5f; }
135         
136         void incTmp() { TmpValue += 0.0001f; setTmp(); }
137         void decTmp() { TmpValue -= 0.0001f; setTmp(); }
138
139         // adjust actual "setting" value back to fraction for pui widget
140         // double the range from -max <-> max
141         void init( float f ) {
142                 if (f > maxValue) f = maxValue;
143                 if (f < minValue) f = minValue;
144                 Adjust   = 0.5f / maxValue;
145                 setValue((f * Adjust) + 0.5f);
146                 adj( this );
147         }
148
149         void reinit() { init( origValue ); }
150         void cancel() { MyValue = TmpValue; }
151         void reset () { init( origValue ); }
152
153 };
154
155 void FloatDial::adj( puObject *hs )
156 {
157         FloatDial *dial = (FloatDial *)hs;
158         dial->getValue ( dial->getTmp() );
159         dial->setTmp();
160         dial->set();
161         dial->updateText();
162 }
163
164 FloatDial::FloatDial ( int x, int y, int sz, float f, const char *title,
165                                                    float max, float min ) :  puDial( x, y, sz )
166 {
167         maxValue = max;
168         minValue = min;
169         origValue = f;
170         init(f);
171         setDelta    ( 0.01 );
172         setCBMode   ( PUSLIDER_DELTA ) ;
173         strcpy      ( _title, title);
174         setLabel    ( _title );
175         setLabelPlace ( PUPLACE_LEFT  );
176         setLegend(_text);
177         // setLegendPlace( PUPLACE_RIGHT );
178 }
179
180
181 /***********************************************/
182
183 class sgVec3Slider : public puDialogBox
184 {
185         static void handle_arrow(puObject *p_obj);
186         static void heading_adj(puObject *p_obj);
187         static void pitch_adj(puObject *p_obj);
188         static void radius_adj(puObject *p_obj);
189         static void goAway(puObject *p_obj);
190         static void reset(puObject *p_obj);
191         static void cancel(puObject *p_obj);
192
193 protected:
194         char Label[64];
195         FloatDial *HS0;
196         FloatDial *HS1;
197         FloatSlider *HS2;
198         puText *TitleText;
199         puOneShot *OkButton;
200         puOneShot *ResetButton;
201         puOneShot *CancelButton;
202         puArrowButton *right_arrow;
203         puArrowButton *left_arrow;
204         sgVec3 Vec, SaveVec;
205         
206 public:
207
208         sgVec3Slider ( int x, int y, sgVec3 vec,
209                                    const char *title = "Vector Adjuster",
210                                    const char *Xtitle = "Heading",
211                                    const char *Ytitle = "Pitch",
212                                    const char *Ztitle = "Radius   " );
213
214         ~sgVec3Slider () {;}
215
216
217         // calc the property Vec with the actual point on sphere
218         void setVec()
219         {
220                 Vec3FromHeadingPitchRadius( Vec,
221                                                 HS0->get(),
222                                                 HS1->get(),
223                                                 HS2->get());
224         }
225
226         // return the offset vector according to current widget values
227         sgVec3 *getVec()
228         { 
229                 setVec();
230                 return &Vec;
231         };
232
233         // save the Vector before pushing dialog (for cancel button)
234         sgVec3 *getStashVec() { return &SaveVec; }
235         void stashVec() { 
236                 SaveVec[2] = HS0->get();
237                 SaveVec[1] = HS1->get();
238                 SaveVec[0] = HS2->get();
239         }
240
241         // functions to return pointers to protected pui widget instances
242         FloatDial *getHS0() { return HS0; }
243         FloatDial *getHS1() { return HS1; }
244         FloatSlider *getHS2() { return HS2; }
245
246         static void adjust(puObject *p_obj);
247 };
248
249 // class constructor
250 sgVec3Slider::sgVec3Slider ( int x, int y, sgVec3 cart, const char *title,
251                              const char *Xtitle,
252                              const char *Ytitle,
253                              const char *Ztitle ): puDialogBox ( x, y )
254 {
255         puFont LegendFont, LabelFont;
256         puGetDefaultFonts ( &LegendFont, &LabelFont );
257         int fudge = 20;
258
259         HeadingPitchRadiusFromVec3( Vec, cart);
260         sgVec3 vec;
261         sgSetVec3(vec, Vec[0], Vec[1], Vec[2]);
262
263         int labelW = LabelFont.getStringWidth(Xtitle);
264         labelW = SG_MAX2( labelW, LabelFont.getStringWidth(Ytitle));
265         labelW = SG_MAX2( labelW, LabelFont.getStringWidth(Ztitle));
266                 
267
268         sgCopyVec3(SaveVec, vec);
269         sgCopyVec3(Vec, vec);
270         strcpy( Label, title );
271
272         int nSliders = 3;
273         int slider_x = 70+fudge;
274         int slider_y = 75;
275         int slider_width = 270;
276         int dialer_x = 70+fudge;
277         int dialer_y = 115;
278         int dialer_size = 100;
279
280         int horiz_slider_height = LabelFont.getStringHeight()
281             + LabelFont.getStringDescender()
282             + PUSTR_TGAP + PUSTR_BGAP + 5;
283
284         int DialogWidth = slider_width + 20 + fudge + labelW;
285         int DialogHeight = dialer_size + 115 + nSliders * horiz_slider_height;
286         
287         // HACKS
288         setUserData( this );
289         horiz_slider_height += 10;
290
291         new puFrame ( 0, 0, DialogWidth, DialogHeight );
292
293         setLabelPlace( PUPLACE_DEFAULT /*PUPLACE_CENTERED*/ );
294         setLabel( Label );
295
296         /* heading */
297         HS0 = new FloatDial (  dialer_x, dialer_y, dialer_size, vec[0], Xtitle, 180.0f, -180.0f );
298         dialer_x = dialer_x + 170;
299         HS0->setUserData (this);
300         HS0->setCallback ( heading_adj ) ;
301
302         /* pitch */
303         HS1 = new FloatDial (  dialer_x, dialer_y, dialer_size, vec[1], Ytitle, 89.99f, -89.99f );
304         HS1->setUserData (this);
305         HS1->setCallback ( pitch_adj ) ;
306
307         /* radius */
308         HS2 = new FloatSlider (  slider_x+20, slider_y, slider_width-40, vec[2], Ztitle, 100.0f, 0.0f );
309         HS2->setUserData (this);
310         HS2->setCallback ( radius_adj );
311
312         right_arrow = new puArrowButton ( slider_x + slider_width - 20, slider_y + 1, slider_x + slider_width, slider_y+21, PUARROW_RIGHT ) ;
313         right_arrow->setUserData ( HS2 ) ;
314         right_arrow->setCallback ( handle_arrow ) ;
315
316         left_arrow = new puArrowButton ( slider_x, slider_y + 1, slider_x+20, slider_y+21, PUARROW_LEFT ) ;
317         left_arrow->setUserData ( HS2 ) ;
318         left_arrow->setCallback ( handle_arrow ) ;
319
320         TitleText = new puText( 130, DialogHeight - 40);
321         TitleText->setLabel("Pilot Offset");
322
323         OkButton = new puOneShot ( 70+fudge, 20, 120+fudge, 50 );
324         OkButton-> setUserData( this );
325         OkButton-> setLegend ( gui_msg_OK );
326         OkButton-> makeReturnDefault ( TRUE );
327         OkButton-> setCallback ( goAway );
328
329         CancelButton = new puOneShot ( 130+fudge, 20, 210+fudge, 50 );
330         CancelButton-> setUserData( this );
331         CancelButton-> setLegend ( gui_msg_CANCEL );
332         CancelButton-> setCallback ( cancel );
333
334 // renabling this button requires binding in the sim/view[?]/config/?-offset-m values
335 //      ResetButton = new puOneShot ( 220+fudge, 20, 280+fudge, 50 );
336 //      ResetButton-> setUserData( this );
337 //      ResetButton-> setLegend ( gui_msg_RESET );
338 //      ResetButton-> setCallback ( reset );
339
340         FG_FINALIZE_PUI_DIALOG( this );
341 }
342
343 void sgVec3Slider::handle_arrow(puObject *arrow)
344 {
345   FloatSlider *slider = (FloatSlider *) arrow->getUserData();
346   if (((puArrowButton *)arrow)->getArrowType() == PUARROW_RIGHT)
347     slider->incTmp();
348   else
349     slider->decTmp();
350   slider->set();
351   slider->init( slider->get() );
352   sgVec3Slider *me = (sgVec3Slider *)slider->getUserData();
353   me->setVec();
354 };
355
356 void sgVec3Slider::heading_adj(puObject *p_obj)
357 {
358   sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
359   me->HS0->adj((puObject *)me ->HS0 );
360   me->setVec();
361 };
362
363 void sgVec3Slider::pitch_adj(puObject *p_obj)
364 {
365   sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
366   me->HS1->adj((puObject *)me ->HS1 );
367   me->setVec();
368 };
369
370 void sgVec3Slider::radius_adj(puObject *p_obj)
371 {
372   sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
373   me ->HS2-> adj((puObject *)me ->HS2 );
374   me->setVec();
375 };
376
377 void sgVec3Slider::goAway(puObject *p_obj)
378 {
379         sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
380         FG_POP_PUI_DIALOG( me );
381 };
382
383 void sgVec3Slider::reset(puObject *p_obj)
384 {
385         sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
386         me->HS0->reinit();
387         me->HS1->reinit();
388         me->HS2->reinit();
389 };
390
391 void sgVec3Slider::cancel(puObject *p_obj)
392 {
393         sgVec3 vec;
394         sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
395         sgVec3 *pvec = me -> getStashVec();
396         sgCopyVec3( vec, *pvec );
397         me->HS0->init(vec[2]);
398         me->HS1->init(vec[1]);
399         me->HS2->init(vec[0]);
400         me->setVec();
401         FG_POP_PUI_DIALOG( me );
402 };
403
404 void sgVec3Slider::adjust(puObject *p_obj)
405 {
406         sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData();
407         heading_adj( me );
408         pitch_adj( me );
409         radius_adj( me );
410
411         sgVec3 cart;
412         sgSetVec3(cart,
413                fgGetFloat("/sim/current-view/x-offset-m"),
414                fgGetFloat("/sim/current-view/y-offset-m"),
415                fgGetFloat("/sim/current-view/z-offset-m")
416         );
417
418         HeadingPitchRadiusFromVec3( me->Vec, cart);
419
420         me -> getHS0() -> init(me->Vec[0]);
421         me -> getHS1() -> init(me->Vec[1]);
422         me -> getHS2() -> init(me->Vec[2]);
423
424         me -> getHS0() -> adj((puObject *)me -> getHS0());
425         me -> getHS1() -> adj((puObject *)me -> getHS1());
426         me -> getHS2() -> adj((puObject *)me -> getHS2());
427         me -> setVec();
428 };
429
430 void sgVec3SliderAdjust( puObject *p_obj )
431 {
432         sgVec3Slider *me = (sgVec3Slider *)p_obj -> getUserData();
433         me -> adjust( me );
434         FG_PUSH_PUI_DIALOG( me );
435 }
436
437 // These are globals for now
438 static puObject *PO_vec = 0;
439
440 void PilotOffsetInit() {
441         sgVec3 cart;
442         sgSetVec3(cart,
443                fgGetFloat("/sim/current-view/x-offset-m"),
444                fgGetFloat("/sim/current-view/y-offset-m"),
445                fgGetFloat("/sim/current-view/z-offset-m")
446         );
447         PilotOffsetInit(cart);
448 }
449
450 void PilotOffsetInit( sgVec3 cart )
451 {
452         // Only one of these things for now
453         if( PO_vec == 0 ) {
454                 sgVec3Slider *PO = new sgVec3Slider ( 200, 200, cart, "Pilot Offset" );
455                 PO_vec = PO;
456                 // Bindings for Pilot Offset
457                 fgTie("/sim/current-view/x-offset-m", getPilotXOffset, setPilotXOffset);
458                 fgTie("/sim/current-view/y-offset-m", getPilotYOffset, setPilotYOffset);
459                 fgTie("/sim/current-view/z-offset-m", getPilotZOffset, setPilotZOffset);
460         }
461 }
462
463 void PilotOffsetAdjust( puObject * )
464 {
465         if( PO_vec == 0 ) {
466                 PilotOffsetInit();
467         }
468         sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData();
469         me -> adjust( me );
470         me -> stashVec();
471         FG_PUSH_PUI_DIALOG( me );
472 }
473
474 // external to get pilot offset vector for viewer
475 sgVec3 *PilotOffsetGet()
476 {
477         if( PO_vec == 0 ) {
478                 PilotOffsetInit();
479         }
480         sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData();
481         return( me -> getVec() );
482 }
483
484 // external function used to tie to FG properties
485 float PilotOffsetGetSetting(int opt)
486 {
487         float setting;
488         if( PO_vec == 0 ) {
489                 PilotOffsetInit();
490         }
491         sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData();
492         sgVec3 vec;
493         sgCopyVec3(vec, (float *) me->getVec());
494         if( opt == 0 ) setting = vec[0];
495         if( opt == 1 ) setting = vec[1];
496         if( opt == 2 ) setting = vec[2];
497         return( setting );
498 }
499
500 // external function used to tie to FG properties
501 void PilotOffsetSet(int opt, float setting)
502 {
503         if( PO_vec == 0 ) {
504                 PilotOffsetInit();
505         }
506         sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData();
507
508         sgVec3 HPR;
509         sgVec3 vec;
510         sgCopyVec3(vec, (float *) me->getVec());
511         if( opt == 0 ) vec[0] = setting;
512         if( opt == 1 ) vec[1] = setting;
513         if( opt == 2 ) vec[2] = setting;
514         HeadingPitchRadiusFromVec3 ( HPR, vec );
515         me -> getHS0() -> init( HPR[0] );
516         me -> getHS1() -> init( HPR[1] );
517         me -> getHS2() -> init( HPR[2] );
518         me -> stashVec();
519 }
520
521
522 // Calculate vector of point on sphere:
523 // input Heading == longitude of point on sphere
524 // input Pitch   == latitude of point on sphere
525 // input Radius  == radius of sphere
526
527 #define MIN_VIEW_OFFSET 0.001
528 void Vec3FromHeadingPitchRadius ( sgVec3 vec3, float heading, float pitch,
529 float radius )
530 {
531   double ch, sh, cp, sp;
532
533   if ( heading == SG_ZERO )
534   {
535     ch = SGD_ONE ;
536     sh = SGD_ZERO ;
537   }
538   else
539   {
540     sh = sin( (double)( heading * SG_DEGREES_TO_RADIANS )) ;
541     ch = cos( (double)( heading * SG_DEGREES_TO_RADIANS )) ;
542   }
543
544   if ( pitch == SG_ZERO )
545   {
546     cp = SGD_ONE ;
547     sp = SGD_ZERO ;
548   }
549   else
550   {
551     sp = sin( (double)( pitch * SG_DEGREES_TO_RADIANS )) ;
552     cp = cos( (double)( pitch * SG_DEGREES_TO_RADIANS )) ;
553   }
554
555   if ( radius < MIN_VIEW_OFFSET )
556           radius = MIN_VIEW_OFFSET ;
557
558   vec3[2] = (SGfloat)( ch * cp ) * radius ; // X
559   vec3[1] = (SGfloat)( sh * cp ) * radius ; // Y
560   vec3[0] = (SGfloat)(  sp ) * radius ; // Z
561 }
562
563 // Convert to speherical coordinates for the dials
564
565 void HeadingPitchRadiusFromVec3 ( sgVec3 hpr, sgVec3 vec3 )
566 {
567   double x = vec3[0];
568   double y = vec3[1];
569   double z = vec3[2];
570   double Zx;
571   double Pr;
572
573   if (z == 0.0f) {
574     hpr[0] = 0;
575     hpr[1] = 0;
576     hpr[2] = 0;
577   } else {
578     if (fabs(y) < 0.001f)
579       y = 0.001f;
580
581     Zx = sqrt(y*y + z*z);
582
583     hpr[2] = sqrt(x*x + y*y + z*z);
584
585     Pr = Zx / hpr[2];
586     if (Pr > 1.0f)
587       hpr[1] = 0.0f;
588     else 
589       hpr[1] = acos(Pr) * SGD_RADIANS_TO_DEGREES;
590     if (x < 0.0f) 
591       hpr[1] *= -SGD_ONE;
592
593     if (z < 0.0f) {
594       hpr[0] = (SGD_PI - asin(y/Zx)) * SGD_RADIANS_TO_DEGREES;
595     } else {
596       hpr[0] = asin(y/Zx) * SGD_RADIANS_TO_DEGREES;
597       if (hpr[0] > 180) {
598         hpr[0] = 180 - hpr[0];
599       }
600     }
601   }
602 }