diff --git a/src/AIModel/AIStorm.cxx b/src/AIModel/AIStorm.cxx index 4e10f811b..f7022e996 100644 --- a/src/AIModel/AIStorm.cxx +++ b/src/AIModel/AIStorm.cxx @@ -18,25 +18,21 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -#ifdef HAVE_CONFIG_H -# include -#endif +#include +#include +#include +#include #include
#include
#include -#include -#include -#include -#include using std::string; #include "AIStorm.hxx" -FGAIStorm::FGAIStorm() : - FGAIBase(otStorm, false) +FGAIStorm::FGAIStorm() : FGAIBase(otStorm, false) { delay = 3.6; subflashes = 1; @@ -61,9 +57,6 @@ FGAIStorm::FGAIStorm() : } -FGAIStorm::~FGAIStorm() { -} - void FGAIStorm::readFromScenario(SGPropertyNode* scFileNode) { if (!scFileNode) return; @@ -83,15 +76,12 @@ void FGAIStorm::update(double dt) { void FGAIStorm::Run(double dt) { - double speed_north_deg_sec; double speed_east_deg_sec; // convert speed to degrees per second - speed_north_deg_sec = cos( hdg / SG_RADIANS_TO_DEGREES ) - * speed * 1.686 / ft_per_deg_lat; - speed_east_deg_sec = sin( hdg / SG_RADIANS_TO_DEGREES ) - * speed * 1.686 / ft_per_deg_lon; + speed_north_deg_sec = cos(hdg / SG_RADIANS_TO_DEGREES) * speed * 1.686 / ft_per_deg_lat; + speed_east_deg_sec = sin(hdg / SG_RADIANS_TO_DEGREES) * speed * 1.686 / ft_per_deg_lon; // set new position pos.setLatitudeDeg( pos.getLatitudeDeg() + speed_north_deg_sec * dt); @@ -132,8 +122,7 @@ void FGAIStorm::Run(double dt) { timer = 0.0; flashed = 0; } - } - else { + } else { timer += dt; } @@ -151,7 +140,6 @@ void FGAIStorm::Run(double dt) { user_altitude < height) { turb_mag_node->setDoubleValue(strength_norm); turb_rate_node->setDoubleValue(0.5); - } - + } } diff --git a/src/AIModel/AIStorm.hxx b/src/AIModel/AIStorm.hxx index 731df0c0d..31e67987c 100644 --- a/src/AIModel/AIStorm.hxx +++ b/src/AIModel/AIStorm.hxx @@ -20,22 +20,22 @@ #pragma once +#include + #include "AIManager.hxx" #include "AIBase.hxx" -#include - class FGAIStorm : public FGAIBase { public: - FGAIStorm(); - ~FGAIStorm(); + virtual ~FGAIStorm() = default; + const char* getTypeString(void) const override { return "thunderstorm"; } void readFromScenario(SGPropertyNode* scFileNode) override; - void update(double dt) override; + inline void setStrengthNorm( double s ) { strength_norm = s; }; inline void setDiameter( double d ) { diameter = d; }; inline void setHeight( double h ) { height = h; }; @@ -43,12 +43,11 @@ public: inline double getDiameter() const { return diameter; }; inline double getHeight() const { return height; }; - const char* getTypeString(void) const override { return "thunderstorm"; } - private: - double diameter; // diameter of turbulence zone, in nm - double height; // top of turbulence zone, in feet MSL - double strength_norm; // strength of turbulence + double diameter = 0.0; // diameter of turbulence zone, in nm + double height = 0.0; // top of turbulence zone, in feet MSL + double strength_norm = 0.0; // strength of turbulence + void Run(double dt); // lightning stuff @@ -65,5 +64,4 @@ private: // turbulence stuff SGPropertyNode_ptr turb_mag_node; SGPropertyNode_ptr turb_rate_node; - }; diff --git a/src/AIModel/AIThermal.cxx b/src/AIModel/AIThermal.cxx index fcff08bea..8d1503692 100644 --- a/src/AIModel/AIThermal.cxx +++ b/src/AIModel/AIThermal.cxx @@ -20,35 +20,30 @@ // along with this program; if not, write to the Free Software // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -#ifdef HAVE_CONFIG_H -# include -#endif +#include +#include #include
#include
#include -#include -#include using std::string; #include "AIThermal.hxx" -FGAIThermal::FGAIThermal() : - FGAIBase(otThermal, false) +FGAIThermal::FGAIThermal() : FGAIBase(otThermal, false) { - max_strength = 6.0; - diameter = 0.5; - strength = factor = 0.0; - cycle_timer = 60*(rand()%31); // some random in the birth time - ground_elev_ft = 0.0; - dt_count=0.9; - alt=0.0; + altitude_agl_ft = 0.0; + max_strength = 6.0; + diameter = 0.5; + strength = factor = 0.0; + cycle_timer = 60*(rand()%31); // some random in the birth time + ground_elev_ft = 0.0; + dt_count=0.9; + alt=0.0; } -FGAIThermal::~FGAIThermal() { -} void FGAIThermal::readFromScenario(SGPropertyNode* scFileNode) { if (!scFileNode) @@ -72,28 +67,20 @@ bool FGAIThermal::init(ModelSearchOrder searchOrder) { fgGetNode("/environment/config/aloft/entry[2]/wind-from-heading-deg", true); _aloft_wind_speed_node = fgGetNode("/environment/config/aloft/entry[2]/wind-speed-kt", true); - do_agl_calc = 1; + do_agl_calc = true; return FGAIBase::init(searchOrder); } void FGAIThermal::bind() { FGAIBase::bind(); - tie("position/altitude-agl-ft", // for debug and tweak - SGRawValuePointer(&altitude_agl_ft)); - tie("alt-rel", // for debug and tweak - SGRawValuePointer(&alt_rel)); - tie("time", // for debug and tweak - SGRawValuePointer(&time)); - tie("xx", // for debug and tweak - SGRawValuePointer(&xx)); - tie("is-forming", // for debug abd tweak - SGRawValuePointer(&is_forming)); - tie("is-formed", // for debug abd tweak - SGRawValuePointer(&is_formed)); - tie("is-dying", // for debug abd tweak - SGRawValuePointer(&is_dying)); - tie("is-dead", // for debug abd tweak - SGRawValuePointer(&is_dead)); + tie("position/altitude-agl-ft", SGRawValuePointer(&altitude_agl_ft)); + tie("alt-rel", SGRawValuePointer(&alt_rel)); + tie("time", SGRawValuePointer(&time)); + tie("xx", SGRawValuePointer(&xx)); + tie("is-forming", SGRawValuePointer(&is_forming)); + tie("is-formed", SGRawValuePointer(&is_formed)); + tie("is-dying", SGRawValuePointer(&is_dying)); + tie("is-dead", SGRawValuePointer(&is_dead)); } void FGAIThermal::update(double dt) { @@ -103,29 +90,25 @@ void FGAIThermal::update(double dt) { } - //the formula to get the available portion of VUpMax depending on altitude //returns a double between 0 and 1 double FGAIThermal::get_strength_fac(double alt_frac) { + double PI = 4.0 * atan(1.0); + double fac = 0.0; -double PI = 4.0 * atan(1.0); -double fac = 0.0; -if ( alt_frac <=0.0 ) { // do submarines get thermals ? - fac = 0.0; - } -else if ( ( alt_frac>0.0 ) && (alt_frac<=0.1) ) { // ground layer - fac = ( 0.1*( pow( (10.0*alt_frac),10.0) ) ); - } -else if ( ( alt_frac>0.1 ) && (alt_frac<=1.0) ) { // main body of the thermal - fac = 0.4175 - 0.5825* ( cos ( PI* (1.0-sqrt(alt_frac) ) +PI) ) ; - } -else if ( ( alt_frac >1.0 ) && (alt_frac < 1.1 ) ) { //above the ceiling, but not above the cloud - fac = (0.5 * ( 1.0 + cos ( PI*( (-2.0*alt_frac)*5.0 ) ) ) ); - } -else if ( alt_frac >= 1.1 ) { //above the cloud - fac = 0.0; - } -return fac; + if ( alt_frac <=0.0 ) { // do submarines get thermals ? + fac = 0.0; + } else if ((alt_frac > 0.0) && (alt_frac <= 0.1)) { // ground layer + fac = ( 0.1*( pow( (10.0*alt_frac),10.0) ) ); + } else if ((alt_frac > 0.1) && (alt_frac <= 1.0)) { // main body of the thermal + fac = 0.4175 - 0.5825* ( cos ( PI* (1.0-sqrt(alt_frac) ) +PI) ) ; + } else if ((alt_frac > 1.0) && (alt_frac < 1.1)) { //above the ceiling, but not above the cloud + fac = (0.5 * ( 1.0 + cos ( PI*( (-2.0*alt_frac)*5.0 ) ) ) ); + } else if (alt_frac >= 1.1) { //above the cloud + fac = 0.0; + } + + return fac; } @@ -156,14 +139,12 @@ double t4 = tmin4/tmin3; // the time elapsed since the thermal was born, in a 0-1 fraction of tmin3 time = cycle_timer/alive_cycle_time; -//comment above and -//uncomment below to freeze the time cycle - time=0.5; +// comment above and uncomment below to freeze the time cycle +// time=0.5; if ( time >= t4) { - cycle_timer = 60*(rand()%31); - } - + cycle_timer = 60*(rand()%31); +} //the position of the thermal 'top' double thermal_foot_lat = (pos.getLatitudeDeg()); @@ -199,27 +180,22 @@ double dist_center; double slice_center_lon; double slice_center_lat; - - //we need to know the thermal foot AGL altitude - //we could do this only once, as thermal don't move //but then agl info is lost on user reset //so we only do this every 10 seconds to save cpu dt_count += dt; if (dt_count >= 10.0 ) { - //double alt; if (getGroundElevationM(SGGeod::fromGeodM(pos, 20000), alt, 0)) { ground_elev_ft = alt * SG_METER_TO_FEET; - do_agl_calc = 0; + do_agl_calc = false; altitude_agl_ft = height - ground_elev_ft ; dt_count = 0.0; } } //user altitude relative to the thermal height, seen AGL from the thermal foot - double user_altitude = globals->get_aircraft_position().getElevationFt(); if ( user_altitude < 1.0 ) { user_altitude = 1.0 ;}; // an ugly way to avoid NaNs for users at alt 0 @@ -227,7 +203,6 @@ double user_altitude_agl= ( user_altitude - ground_elev_ft ) ; alt_rel = user_altitude_agl / altitude_agl_ft; - //the updraft user feels ! double Vup; @@ -255,43 +230,49 @@ double PI = 4.0 * atan(1.0); //we get the max strenght proportion we can expect at the time and altitude, formuled between 0 and 1 //double xx; if (time <= t1) { - xx= ( time / t1 ); - maxstrengthavail = xx* get_strength_fac ( alt_rel / xx ); + xx = ( time / t1 ); + maxstrengthavail = xx* get_strength_fac ( alt_rel / xx ); - is_forming=1;is_formed=0;is_dying=0;is_dead=0; + is_forming = true; + is_formed = false; + is_dying = false; + is_dead = false; - } -else if ( (time > t1) && (time <= t2) ) { - maxstrengthavail = get_strength_fac ( (alt_rel) ); +} else if ((time > t1) && (time <= t2)) { + maxstrengthavail = get_strength_fac ( (alt_rel) ); - is_forming=0;is_formed=1;is_dying=0;is_dead=0; + is_forming = false; + is_formed = true; + is_dying = false; + is_dead = false; - } -else if ( (time > t2) && (time <= t3) ) { - xx= ( ( time - t2) / (1.0 - t2) ) ; - maxstrengthavail = get_strength_fac ( alt_rel - xx ); +} else if ((time > t2) && (time <= t3)) { + xx= ( ( time - t2) / (1.0 - t2) ) ; + maxstrengthavail = get_strength_fac ( alt_rel - xx ); - is_forming=0;is_formed=0;is_dying=1;is_dead=0; + is_forming = false; + is_formed = false; + is_dying = true; + is_dead = false; - } -else { - maxstrengthavail = 0.0; - is_forming=0;is_formed=0;is_dying=0;is_dead=1; - - } +} else { + maxstrengthavail = 0.0; + is_forming = false; + is_formed = false; + is_dying = false; + is_dead = true; +} //we get the diameter of the thermal slice at the user altitude //the thermal has a slight conic shape -if ( (alt_rel >= 0.0) && (alt_rel < 1.0 ) ) { - Rsink = ( shaping*Rmax ) + ( ( (1.0-shaping)*Rmax*alt_rel ) / altitude_agl_ft ); // in the main thermal body - } -else if ( (alt_rel >=1.0) && (alt_rel < 1.1) ) { - Rsink = (Rmax/2.0) * ( 1.0+ cos ( (10.0*PI*alt_rel)-(2.0*PI) ) ); // above the ceiling - } -else { - Rsink = 0.0; // above the cloud - } +if ((alt_rel >= 0.0) && (alt_rel < 1.0)) { + Rsink = (shaping * Rmax) + (((1.0 - shaping) * Rmax * alt_rel) / altitude_agl_ft); // in the main thermal body +} else if ((alt_rel >= 1.0) && (alt_rel < 1.1)) { + Rsink = (Rmax / 2.0) * (1.0 + cos((10.0 * PI * alt_rel) - (2.0 * PI))); // above the ceiling +} else { + Rsink = 0.0; // above the cloud +} //we get the portion of the diameter that produces lift Rup = r_up_frac * Rsink ; @@ -343,42 +324,39 @@ dist_center = SGGeodesy::distanceNm(SGGeod::fromDeg(slice_center_lon, slice_cent // Now we can calculate Vup -if ( max_strength >=0.0 ) { // this is a thermal +if (max_strength >= 0.0) { // this is a thermal - if ( ( dist_center >= 0.0 ) && ( dist_center < Rup ) ) { //user is in the updraft area - Vup = v_up_max * cos ( dist_center* PI/(2.0*Rup) ); - } - else if ( ( dist_center > Rup ) && ( dist_center <= ((Rup+Rsink)/2.0) ) ) { //user in the 1st half of the sink area - Vup = v_up_min * cos (( dist_center - ( Rup+Rsink)/2.0 ) * PI / ( 2.0* ( ( Rup+Rsink)/2.0 -Rup ))); - } - else if ( ( dist_center > ((Rup+Rsink)/2.0) ) && dist_center <= Rsink ) { // user in the 2nd half of the sink area - Vup = ( global_sink + v_up_min )/2.0 + ( global_sink - v_up_min )/2.0 *cos ( (dist_center-Rsink) *PI/ ( (Rsink-Rup )/2.0) ); - } - else { // outside the thermal - Vup = global_sink; - } - } + if ((dist_center >= 0.0) && (dist_center < Rup)) { //user is in the updraft area + Vup = v_up_max * cos(dist_center * PI / (2.0 * Rup)); + } else if ((dist_center > Rup) && (dist_center <= ((Rup + Rsink) / 2.0))) { //user in the 1st half of the sink area + Vup = v_up_min * cos((dist_center - (Rup + Rsink) / 2.0) * PI / (2.0 * ((Rup + Rsink) / 2.0 - Rup))); + } else if ((dist_center > ((Rup + Rsink) / 2.0)) && dist_center <= Rsink) { // user in the 2nd half of the sink area + Vup = (global_sink + v_up_min) / 2.0 + (global_sink - v_up_min) / 2.0 * cos((dist_center - Rsink) * PI / ((Rsink - Rup) / 2.0)); + } else { // outside the thermal + Vup = global_sink; + } +} else { // this is a sink, we don't want updraft on the sides, nor do we want to feel sink near or above ceiling and ground - if ( alt_rel <=1.1 ) { - double fac = ( 1.0 - ( 1.0 - 1.815*alt_rel)*( 1.0 - 1.815*alt_rel) ); - Vup = fac * (global_sink + ( ( v_up_max - global_sink )/2.0 ) * ( 1.0+cos ( dist_center* PI / Rmax ) )) ; - } - else { Vup = global_sink; } + if (alt_rel <= 1.1) { + double fac = (1.0 - (1.0 - 1.815 * alt_rel) * (1.0 - 1.815 * alt_rel)); + Vup = fac * (global_sink + ((v_up_max - global_sink) / 2.0) * (1.0 + cos(dist_center * PI / Rmax))); + } else { + Vup = global_sink; + } } //correct for no global sink above clouds and outside thermals if ( ( (alt_rel > 1.0) && (alt_rel <1.1)) && ( dist_center > Rsink ) ) { - Vup = global_sink * ( 11.0 -10.0 * alt_rel ); - } + Vup = global_sink * ( 11.0 -10.0 * alt_rel ); +} + if ( alt_rel >= 1.1 ) { - Vup = 0.0; - } + Vup = 0.0; +} strength = Vup; range = dist_center; } - - diff --git a/src/AIModel/AIThermal.hxx b/src/AIModel/AIThermal.hxx index a5a398306..16a0ec5b9 100644 --- a/src/AIModel/AIThermal.hxx +++ b/src/AIModel/AIThermal.hxx @@ -32,11 +32,12 @@ class FGAIThermal : public FGAIBase { public: FGAIThermal(); - ~FGAIThermal(); + virtual ~FGAIThermal() = default; + const char* getTypeString(void) const override { return "thermal"; } void readFromScenario(SGPropertyNode* scFileNode) override; - bool init(ModelSearchOrder searchOrder) override; + bool init(ModelSearchOrder searchOrder) override; void bind() override; void update(double dt) override; @@ -54,36 +55,36 @@ public: inline double getV_up_min() const { return v_up_min; }; inline double getR_up_frac() const { return r_up_frac; }; - const char* getTypeString(void) const override { return "thermal"; } void getGroundElev(double dt); private: void Run(double dt); + double get_strength_fac(double alt_frac); double max_strength; double strength; double diameter; - double height; + double height = 0.0; double factor; - double alt_rel; + double alt_rel = 0.0; double alt; - double v_up_max; - double v_up_min; - double r_up_frac; + double v_up_max = 0.0; + double v_up_min = 0.0; + double r_up_frac = 0.0; double cycle_timer; double dt_count; - double time; - double xx; + double time = 0.0; + double xx = 0.0; double ground_elev_ft; // ground level in ft - double altitude_agl_ft; // altitude above ground in feet - bool do_agl_calc; - bool is_forming; - bool is_formed; - bool is_dying; - bool is_dead; + + bool do_agl_calc = false; + bool is_forming = false; + bool is_formed = false; + bool is_dying = false; + bool is_dead = false; + SGPropertyNode_ptr _surface_wind_from_deg_node; SGPropertyNode_ptr _surface_wind_speed_node; SGPropertyNode_ptr _aloft_wind_from_deg_node; SGPropertyNode_ptr _aloft_wind_speed_node; - };