/** * sgVec3Slider.cxx * * Simple PUI wrapper around sgVec3 class * * Created by: Norman Vine [NHV] * nhv@yahoo.com, nhv@cape.com * * Revision History * ---------------- * Started 12:53 01/28/2001 * */ #include "sgVec3Slider.hxx" #include
#include static void setPilotXOffset (float value) { PilotOffsetSet(0, value); } static float getPilotXOffset () { return( PilotOffsetGetSetting(0) ); } static void setPilotYOffset (float value) { PilotOffsetSet(1, value); } static float getPilotYOffset () { return( PilotOffsetGetSetting(1) ); } static void setPilotZOffset (float value) { PilotOffsetSet(2, value); } static float getPilotZOffset () { return( PilotOffsetGetSetting(2) ); } class FloatSlider : public puSlider { protected: float maxValue; float minValue; float origValue; float Adjust; float MyValue; float TmpValue; float SaveValue; char buf[8]; char _title[32]; char _text[16]; public: FloatSlider ( int x, int y, int sz, float f, const char *title, float max = 100.0f, float min = 0.0f); ~FloatSlider () {;} static void adj( puObject *); void updateText() { sprintf( _text, "%05.2f", MyValue ); } float get() { return( MyValue ); } // calc actual "setting" by multiplying the pui fraction by highest value setable void set() { MyValue = maxValue * TmpValue; } float *getTmp() { return( &TmpValue ); } // adjust the TmpValue back to 0 to 1 range of pui widget void setTmp() { TmpValue += 0.0f; } void incTmp() { TmpValue += 0.0001f; setTmp(); } void decTmp() { TmpValue -= 0.0001f; setTmp(); } // adjust actual "setting" value back to fraction for pui widget void init( float f ) { if (f > maxValue) f = maxValue; if (f < minValue) f = minValue; Adjust = 1.0f / maxValue; setValue(f * Adjust); adj( this ); } void reinit() { init( origValue ); } void cancel() { MyValue = TmpValue; } void reset () { init( origValue ); } }; void FloatSlider::adj( puObject *hs ) { FloatSlider *slider = (FloatSlider *)hs; slider->getValue ( slider->getTmp() ); slider->setTmp(); slider->set(); slider->updateText(); } FloatSlider::FloatSlider ( int x, int y, int sz, float f, const char *title, float max, float min ) : puSlider( x, y, sz, FALSE ) { maxValue = max; minValue = min; origValue = f; init(f); setDelta ( 0.01 ); setCBMode ( PUSLIDER_DELTA ) ; strcpy ( _title, title); setLabel ( _title ); setLabelPlace ( PUPLACE_LEFT ); setLegend(_text); // setLegendPlace( PUPLACE_RIGHT ); } class FloatDial : public puDial { protected: float maxValue; float minValue; float origValue; float Adjust; float MyValue; float TmpValue; float SaveValue; char buf[8]; char _title[32]; char _text[16]; public: FloatDial ( int x, int y, int sz, float f, const char *title, float max = 180.0f, float min = -180.0f ); ~FloatDial () {;} static void adj( puObject *); void updateText() { sprintf( _text, "%05.2f", MyValue ); } float get() { return( MyValue ); } // calc actual "setting" by multiplying the pui fraction by highest value setable // in this case we're also turning a 0 to 1 range into a -.05 to +.05 before converting void set() { MyValue = ((2.0*maxValue) * (TmpValue - 0.5f)) - maxValue; } float *getTmp() { return( &TmpValue ); } // adjust the TmpValue back to 0 to 1 range of pui widget void setTmp() { TmpValue += 0.5f; } void incTmp() { TmpValue += 0.0001f; setTmp(); } void decTmp() { TmpValue -= 0.0001f; setTmp(); } // adjust actual "setting" value back to fraction for pui widget // double the range from -max <-> max void init( float f ) { if (f > maxValue) f = maxValue; if (f < minValue) f = minValue; Adjust = 0.5f / maxValue; setValue((f * Adjust) + 0.5f); adj( this ); } void reinit() { init( origValue ); } void cancel() { MyValue = TmpValue; } void reset () { init( origValue ); } }; void FloatDial::adj( puObject *hs ) { FloatDial *dial = (FloatDial *)hs; dial->getValue ( dial->getTmp() ); dial->setTmp(); dial->set(); dial->updateText(); } FloatDial::FloatDial ( int x, int y, int sz, float f, const char *title, float max, float min ) : puDial( x, y, sz ) { maxValue = max; minValue = min; origValue = f; init(f); setDelta ( 0.01 ); setCBMode ( PUSLIDER_DELTA ) ; strcpy ( _title, title); setLabel ( _title ); setLabelPlace ( PUPLACE_LEFT ); setLegend(_text); // setLegendPlace( PUPLACE_RIGHT ); } /***********************************************/ class sgVec3Slider : public puDialogBox { static void handle_arrow(puObject *p_obj); static void heading_adj(puObject *p_obj); static void pitch_adj(puObject *p_obj); static void radius_adj(puObject *p_obj); static void goAway(puObject *p_obj); static void reset(puObject *p_obj); static void cancel(puObject *p_obj); protected: char Label[64]; FloatDial *HS0; FloatDial *HS1; FloatSlider *HS2; puText *TitleText; puOneShot *OkButton; puOneShot *ResetButton; puOneShot *CancelButton; puArrowButton *right_arrow; puArrowButton *left_arrow; sgVec3 Vec, SaveVec; public: sgVec3Slider ( int x, int y, sgVec3 vec, const char *title = "Vector Adjuster", const char *Xtitle = "Heading", const char *Ytitle = "Pitch", const char *Ztitle = "Radius " ); ~sgVec3Slider () {;} // calc the property Vec with the actual point on sphere void setVec() { Vec3FromHeadingPitchRadius( Vec, HS0->get(), HS1->get(), HS2->get()); } // return the offset vector according to current widget values sgVec3 *getVec() { setVec(); return &Vec; }; // save the Vector before pushing dialog (for cancel button) sgVec3 *getStashVec() { return &SaveVec; } void stashVec() { SaveVec[2] = HS0->get(); SaveVec[1] = HS1->get(); SaveVec[0] = HS2->get(); } // functions to return pointers to protected pui widget instances FloatDial *getHS0() { return HS0; } FloatDial *getHS1() { return HS1; } FloatSlider *getHS2() { return HS2; } static void adjust(puObject *p_obj); }; // class constructor sgVec3Slider::sgVec3Slider ( int x, int y, sgVec3 cart, const char *title, const char *Xtitle, const char *Ytitle, const char *Ztitle ): puDialogBox ( x, y ) { puFont LegendFont, LabelFont; puGetDefaultFonts ( &LegendFont, &LabelFont ); int fudge = 20; HeadingPitchRadiusFromVec3( Vec, cart); sgVec3 vec; sgSetVec3(vec, Vec[0], Vec[1], Vec[2]); int labelW = LabelFont.getStringWidth(Xtitle); labelW = SG_MAX2( labelW, LabelFont.getStringWidth(Ytitle)); labelW = SG_MAX2( labelW, LabelFont.getStringWidth(Ztitle)); sgCopyVec3(SaveVec, vec); sgCopyVec3(Vec, vec); strcpy( Label, title ); int nSliders = 3; int slider_x = 70+fudge; int slider_y = 75; int slider_width = 270; int dialer_x = 70+fudge; int dialer_y = 115; int dialer_size = 100; int horiz_slider_height = LabelFont.getStringHeight() + LabelFont.getStringDescender() + PUSTR_TGAP + PUSTR_BGAP + 5; int DialogWidth = slider_width + 20 + fudge + labelW; int DialogHeight = dialer_size + 115 + nSliders * horiz_slider_height; // HACKS setUserData( this ); horiz_slider_height += 10; new puFrame ( 0, 0, DialogWidth, DialogHeight ); setLabelPlace( PUPLACE_DEFAULT /*PUPLACE_CENTERED*/ ); setLabel( Label ); /* heading */ HS0 = new FloatDial ( dialer_x, dialer_y, dialer_size, vec[0], Xtitle, 180.0f, -180.0f ); dialer_x = dialer_x + 170; HS0->setUserData (this); HS0->setCallback ( heading_adj ) ; /* pitch */ HS1 = new FloatDial ( dialer_x, dialer_y, dialer_size, vec[1], Ytitle, 89.99f, -89.99f ); HS1->setUserData (this); HS1->setCallback ( pitch_adj ) ; /* radius */ HS2 = new FloatSlider ( slider_x+20, slider_y, slider_width-40, vec[2], Ztitle, 100.0f, 0.0f ); HS2->setUserData (this); HS2->setCallback ( radius_adj ); right_arrow = new puArrowButton ( slider_x + slider_width - 20, slider_y + 1, slider_x + slider_width, slider_y+21, PUARROW_RIGHT ) ; right_arrow->setUserData ( HS2 ) ; right_arrow->setCallback ( handle_arrow ) ; left_arrow = new puArrowButton ( slider_x, slider_y + 1, slider_x+20, slider_y+21, PUARROW_LEFT ) ; left_arrow->setUserData ( HS2 ) ; left_arrow->setCallback ( handle_arrow ) ; TitleText = new puText( 130, DialogHeight - 40); TitleText->setLabel("Pilot Offset"); OkButton = new puOneShot ( 70+fudge, 20, 120+fudge, 50 ); OkButton-> setUserData( this ); OkButton-> setLegend ( gui_msg_OK ); OkButton-> makeReturnDefault ( TRUE ); OkButton-> setCallback ( goAway ); CancelButton = new puOneShot ( 130+fudge, 20, 210+fudge, 50 ); CancelButton-> setUserData( this ); CancelButton-> setLegend ( gui_msg_CANCEL ); CancelButton-> setCallback ( cancel ); // renabling this button requires binding in the sim/view[?]/config/?-offset-m values // ResetButton = new puOneShot ( 220+fudge, 20, 280+fudge, 50 ); // ResetButton-> setUserData( this ); // ResetButton-> setLegend ( gui_msg_RESET ); // ResetButton-> setCallback ( reset ); FG_FINALIZE_PUI_DIALOG( this ); } void sgVec3Slider::handle_arrow(puObject *arrow) { FloatSlider *slider = (FloatSlider *) arrow->getUserData(); if (((puArrowButton *)arrow)->getArrowType() == PUARROW_RIGHT) slider->incTmp(); else slider->decTmp(); slider->set(); slider->init( slider->get() ); sgVec3Slider *me = (sgVec3Slider *)slider->getUserData(); me->setVec(); }; void sgVec3Slider::heading_adj(puObject *p_obj) { sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData(); me->HS0->adj((puObject *)me ->HS0 ); me->setVec(); }; void sgVec3Slider::pitch_adj(puObject *p_obj) { sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData(); me->HS1->adj((puObject *)me ->HS1 ); me->setVec(); }; void sgVec3Slider::radius_adj(puObject *p_obj) { sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData(); me ->HS2-> adj((puObject *)me ->HS2 ); me->setVec(); }; void sgVec3Slider::goAway(puObject *p_obj) { sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData(); FG_POP_PUI_DIALOG( me ); }; void sgVec3Slider::reset(puObject *p_obj) { sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData(); me->HS0->reinit(); me->HS1->reinit(); me->HS2->reinit(); }; void sgVec3Slider::cancel(puObject *p_obj) { sgVec3 vec; sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData(); sgVec3 *pvec = me -> getStashVec(); sgCopyVec3( vec, *pvec ); me->HS0->init(vec[2]); me->HS1->init(vec[1]); me->HS2->init(vec[0]); me->setVec(); FG_POP_PUI_DIALOG( me ); }; void sgVec3Slider::adjust(puObject *p_obj) { sgVec3Slider *me = (sgVec3Slider *)p_obj->getUserData(); heading_adj( me ); pitch_adj( me ); radius_adj( me ); sgVec3 cart; sgSetVec3(cart, fgGetFloat("/sim/current-view/x-offset-m"), fgGetFloat("/sim/current-view/y-offset-m"), fgGetFloat("/sim/current-view/z-offset-m") ); HeadingPitchRadiusFromVec3( me->Vec, cart); me -> getHS0() -> init(me->Vec[0]); me -> getHS1() -> init(me->Vec[1]); me -> getHS2() -> init(me->Vec[2]); me -> getHS0() -> adj((puObject *)me -> getHS0()); me -> getHS1() -> adj((puObject *)me -> getHS1()); me -> getHS2() -> adj((puObject *)me -> getHS2()); me -> setVec(); }; void sgVec3SliderAdjust( puObject *p_obj ) { sgVec3Slider *me = (sgVec3Slider *)p_obj -> getUserData(); me -> adjust( me ); FG_PUSH_PUI_DIALOG( me ); } // These are globals for now static puObject *PO_vec = 0; void PilotOffsetInit() { sgVec3 cart; sgSetVec3(cart, fgGetFloat("/sim/current-view/x-offset-m"), fgGetFloat("/sim/current-view/y-offset-m"), fgGetFloat("/sim/current-view/z-offset-m") ); PilotOffsetInit(cart); } void PilotOffsetInit( sgVec3 cart ) { // Only one of these things for now if( PO_vec == 0 ) { sgVec3Slider *PO = new sgVec3Slider ( 200, 200, cart, "Pilot Offset" ); PO_vec = PO; // Bindings for Pilot Offset fgTie("/sim/current-view/x-offset-m", getPilotXOffset, setPilotXOffset); fgTie("/sim/current-view/y-offset-m", getPilotYOffset, setPilotYOffset); fgTie("/sim/current-view/z-offset-m", getPilotZOffset, setPilotZOffset); } } void PilotOffsetAdjust( puObject * ) { if( PO_vec == 0 ) { PilotOffsetInit(); } sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData(); me -> adjust( me ); me -> stashVec(); FG_PUSH_PUI_DIALOG( me ); } // external to get pilot offset vector for viewer sgVec3 *PilotOffsetGet() { if( PO_vec == 0 ) { PilotOffsetInit(); } sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData(); return( me -> getVec() ); } // external function used to tie to FG properties float PilotOffsetGetSetting(int opt) { float setting = 0.0; if( PO_vec == 0 ) { PilotOffsetInit(); } sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData(); sgVec3 vec; sgCopyVec3(vec, (float *) me->getVec()); if( opt == 0 ) setting = vec[0]; if( opt == 1 ) setting = vec[1]; if( opt == 2 ) setting = vec[2]; return( setting ); } // external function used to tie to FG properties void PilotOffsetSet(int opt, float setting) { if( PO_vec == 0 ) { PilotOffsetInit(); } sgVec3Slider *me = (sgVec3Slider *)PO_vec -> getUserData(); sgVec3 HPR; sgVec3 vec; sgCopyVec3(vec, (float *) me->getVec()); if( opt == 0 ) vec[0] = setting; if( opt == 1 ) vec[1] = setting; if( opt == 2 ) vec[2] = setting; HeadingPitchRadiusFromVec3 ( HPR, vec ); me -> getHS0() -> init( HPR[0] ); me -> getHS1() -> init( HPR[1] ); me -> getHS2() -> init( HPR[2] ); me -> stashVec(); } // Calculate vector of point on sphere: // input Heading == longitude of point on sphere // input Pitch == latitude of point on sphere // input Radius == radius of sphere #define MIN_VIEW_OFFSET 0.001 void Vec3FromHeadingPitchRadius ( sgVec3 vec3, float heading, float pitch, float radius ) { double ch, sh, cp, sp; if ( heading == SG_ZERO ) { ch = SGD_ONE ; sh = SGD_ZERO ; } else { sh = sin( (double)( heading * SG_DEGREES_TO_RADIANS )) ; ch = cos( (double)( heading * SG_DEGREES_TO_RADIANS )) ; } if ( pitch == SG_ZERO ) { cp = SGD_ONE ; sp = SGD_ZERO ; } else { sp = sin( (double)( pitch * SG_DEGREES_TO_RADIANS )) ; cp = cos( (double)( pitch * SG_DEGREES_TO_RADIANS )) ; } if ( radius < MIN_VIEW_OFFSET ) radius = MIN_VIEW_OFFSET ; vec3[2] = (SGfloat)( ch * cp ) * radius ; // X vec3[1] = (SGfloat)( sh * cp ) * radius ; // Y vec3[0] = (SGfloat)( sp ) * radius ; // Z } // Convert to speherical coordinates for the dials void HeadingPitchRadiusFromVec3 ( sgVec3 hpr, sgVec3 vec3 ) { double x = vec3[0]; double y = vec3[1]; double z = vec3[2]; double Zx; double Pr; if (z == 0.0f) { hpr[0] = 0; hpr[1] = 0; hpr[2] = 0; } else { if (fabs(y) < 0.001f) y = 0.001f; Zx = sqrt(y*y + z*z); hpr[2] = sqrt(x*x + y*y + z*z); Pr = Zx / hpr[2]; if (Pr > 1.0f) hpr[1] = 0.0f; else hpr[1] = acos(Pr) * SGD_RADIANS_TO_DEGREES; if (x < 0.0f) hpr[1] *= -SGD_ONE; if (z < 0.0f) { hpr[0] = (SGD_PI - asin(y/Zx)) * SGD_RADIANS_TO_DEGREES; } else { hpr[0] = asin(y/Zx) * SGD_RADIANS_TO_DEGREES; if (hpr[0] > 180) { hpr[0] = 180 - hpr[0]; } } } }