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