X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FAIModel%2FAICarrier.cxx;h=b6487519d026c05ea55bc026423f093d30ce9375;hb=b4fbde72b275dc75e8ecf7b44261aba642e5da0f;hp=7fa08422b20fcc86864bacfb678d3e250982de03;hpb=c2d8dcc18baf88176ad48f0b7163dcb4aee51f90;p=flightgear.git diff --git a/src/AIModel/AICarrier.cxx b/src/AIModel/AICarrier.cxx index 7fa08422b..b6487519d 100644 --- a/src/AIModel/AICarrier.cxx +++ b/src/AIModel/AICarrier.cxx @@ -21,23 +21,20 @@ # include #endif +#include #include #include +#include #include -#include #include + #include #include
#include
#include "AICarrier.hxx" -/** Value of earth radius (meters) */ -#define RADIUS_M SG_EQUATORIAL_RADIUS_M - - - FGAICarrier::FGAICarrier() : FGAIShip(otCarrier) { } @@ -59,6 +56,8 @@ void FGAICarrier::readFromScenario(SGPropertyNode* scFileNode) { setMinLat(scFileNode->getDoubleValue("min-lat", 0)); setMaxLong(scFileNode->getDoubleValue("max-long", 0)); setMinLong(scFileNode->getDoubleValue("min-long", 0)); + setMPControl(scFileNode->getBoolValue("mp-control", false)); + setAIControl(scFileNode->getBoolValue("ai-control", false)); SGPropertyNode* flols = scFileNode->getChild("flols-pos"); if (flols) { @@ -71,29 +70,8 @@ void FGAICarrier::readFromScenario(SGPropertyNode* scFileNode) { } else flols_off = SGVec3d::zeros(); - std::vector props = scFileNode->getChildren("wire"); + std::vector props = scFileNode->getChildren("parking-pos"); std::vector::const_iterator it; - for (it = props.begin(); it != props.end(); ++it) { - std::string s = (*it)->getStringValue(); - if (!s.empty()) - wire_objects.push_back(s); - } - - props = scFileNode->getChildren("catapult"); - for (it = props.begin(); it != props.end(); ++it) { - std::string s = (*it)->getStringValue(); - if (!s.empty()) - catapult_objects.push_back(s); - } - - props = scFileNode->getChildren("solid"); - for (it = props.begin(); it != props.end(); ++it) { - std::string s = (*it)->getStringValue(); - if (!s.empty()) - solid_objects.push_back(s); - } - - props = scFileNode->getChildren("parking-pos"); for (it = props.begin(); it != props.end(); ++it) { string name = (*it)->getStringValue("name", "unnamed"); // Transform to the right coordinate frame, configuration is done in @@ -140,81 +118,54 @@ void FGAICarrier::setTACANChannelID(const string& id) { TACAN_channel_id = id; } -void FGAICarrier::getVelocityWrtEarth(sgdVec3& v, sgdVec3& omega, sgdVec3& pivot) { - sgdCopyVec3(v, vel_wrt_earth.sg() ); - sgdCopyVec3(omega, rot_wrt_earth.sg() ); - sgdCopyVec3(pivot, rot_pivot_wrt_earth.sg() ); +void FGAICarrier::setMPControl(bool c) { + MPControl = c; } -void FGAICarrier::update(double dt) { - // For computation of rotation speeds we just use finite differences here. - // That is perfectly valid since this thing is not driven by accelerations - // but by just apply discrete changes at its velocity variables. - // Update the velocity information stored in those nodes. - // Transform that one to the horizontal local coordinate system. - SGQuatd ec2hl = SGQuatd::fromLonLat(pos); - // The orientation of the carrier wrt the horizontal local frame - SGQuatd hl2body = SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll); - // and postrotate the orientation of the AIModel wrt the horizontal - // local frame - SGQuatd ec2body = ec2hl*hl2body; - // The cartesian position of the carrier in the wgs84 world - SGVec3d cartPos = SGVec3d::fromGeod(pos); - // Store for later use by the groundcache - rot_pivot_wrt_earth = cartPos; - - // Compute the velocity in m/s in the earth centered coordinate system axis - double v_north = 0.51444444*speed*cos(hdg * SGD_DEGREES_TO_RADIANS); - double v_east = 0.51444444*speed*sin(hdg * SGD_DEGREES_TO_RADIANS); - vel_wrt_earth = ec2hl.backTransform(SGVec3d(v_north, v_east, 0)); +void FGAICarrier::setAIControl(bool c) { + AIControl = c; +} +void FGAICarrier::update(double dt) { // Now update the position and heading. This will compute new hdg and // roll values required for the rotation speed computation. FGAIShip::update(dt); - //automatic turn into wind with a target wind of 25 kts otd - if(turn_to_launch_hdg){ - TurnToLaunch(); - } else if(OutsideBox() || returning) {// check that the carrier is inside the operating box - ReturnToBox(); - } else { - TurnToBase(); - } + //SG_LOG(SG_GENERAL, SG_ALERT, "AICarrier: MPControl " << MPControl << " AIControl " << AIControl); + if (!MPControl && AIControl){ + + if(turn_to_launch_hdg){ + TurnToLaunch(); + } else if(turn_to_recovery_hdg ){ + TurnToRecover(); + } else if(OutsideBox() || returning ) {// check that the carrier is inside + ReturnToBox(); // the operating box, + } else { + TurnToBase(); + } - // Only change these values if we are able to compute them safely - if (dt < DBL_MIN) - rot_wrt_earth = SGVec3d::zeros(); - else { - // Now here is the finite difference ... - - // Transform that one to the horizontal local coordinate system. - SGQuatd ec2hlNew = SGQuatd::fromLonLat(pos); - // compute the new orientation - SGQuatd hl2bodyNew = SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll); - // The rotation difference - SGQuatd dOr = inverse(ec2body)*ec2hlNew*hl2bodyNew; - SGVec3d dOrAngleAxis; - dOr.getAngleAxis(dOrAngleAxis); - // divided by the time difference provides a rotation speed vector - dOrAngleAxis /= dt; - - // now rotate the rotation speed vector back into the - // earth centered frames coordinates - dOrAngleAxis = ec2body.backTransform(dOrAngleAxis); -// dOrAngleAxis = hl2body.backTransform(dOrAngleAxis); -// dOrAngleAxis(1) = 0; -// dOrAngleAxis = ec2hl.backTransform(dOrAngleAxis); - rot_wrt_earth = dOrAngleAxis; + } else { + FGAIShip::TurnTo(tgt_heading); + FGAIShip::AccelTo(tgt_speed); } UpdateWind(dt); UpdateElevator(dt, transition_time); UpdateJBD(dt, jbd_transition_time); - // For the flols reuse some computations done above ... + + // Transform that one to the horizontal local coordinate system. + SGQuatd ec2hl = SGQuatd::fromLonLat(pos); + // The orientation of the carrier wrt the horizontal local frame + SGQuatd hl2body = SGQuatd::fromYawPitchRollDeg(hdg, pitch, roll); + // and postrotate the orientation of the AIModel wrt the horizontal + // local frame + SGQuatd ec2body = ec2hl*hl2body; + // The cartesian position of the carrier in the wgs84 world + SGVec3d cartPos = SGVec3d::fromGeod(pos); // The position of the eyepoint - at least near that ... - SGVec3d eyePos(globals->get_current_view()->get_absolute_view_pos()); + SGVec3d eyePos(globals->get_current_view()->get_view_pos()); // Add the position offset of the AIModel to gain the earth // centered position SGVec3d eyeWrtCarrier = eyePos - cartPos; @@ -222,10 +173,10 @@ void FGAICarrier::update(double dt) { eyeWrtCarrier = ec2body.transform(eyeWrtCarrier); // the eyepoints vector wrt the flols position SGVec3d eyeWrtFlols = eyeWrtCarrier - flols_off; - + // the distance from the eyepoint to the flols dist = norm(eyeWrtFlols); - + // now the angle, positive angles are upwards if (fabs(dist) < SGLimits::min()) { angle = 0; @@ -234,7 +185,7 @@ void FGAICarrier::update(double dt) { sAngle = SGMiscd::min(1, SGMiscd::max(-1, sAngle)); angle = SGMiscd::rad2deg(asin(sAngle)); } - + // set the value of source if ( angle <= 4.35 && angle > 4.01 ) source = 1; @@ -252,26 +203,10 @@ void FGAICarrier::update(double dt) { source = 0; } //end update -bool FGAICarrier::init() { - if (!FGAIShip::init()) +bool FGAICarrier::init(bool search_in_AI_path) { + if (!FGAIShip::init(search_in_AI_path)) return false; - // process the 3d model here - // mark some objects solid, mark the wires ... - - // The model should be used for altitude computations. - // To avoid that every detail in a carrier 3D model will end into - // the aircraft local cache, only set the HOT traversal bit on - // selected objects. - ssgEntity *sel = aip.getSceneGraph(); - // Clear the HOT traversal flag - mark_nohot(sel); - // Selectively set that flag again for wires/cats/solid objects. - // Attach a pointer to this carrier class to those objects. - mark_wires(sel, wire_objects); - mark_cat(sel, catapult_objects); - mark_solid(sel, solid_objects); - _longitude_node = fgGetNode("/position/longitude-deg", true); _latitude_node = fgGetNode("/position/latitude-deg", true); _altitude_node = fgGetNode("/position/altitude-ft", true); @@ -285,13 +220,16 @@ bool FGAICarrier::init() { turn_to_launch_hdg = false; + turn_to_recovery_hdg = false; + turn_to_base_course = true; returning = false; + in_to_wind = false; mOpBoxPos = pos; base_course = hdg; base_speed = speed; - pos_norm = 0; + pos_norm = raw_pos_norm = 0; elevators = false; transition_time = 150; time_constant = 0.005; @@ -325,8 +263,10 @@ void FGAICarrier::bind() { SGRawValueMethods(pos, &SGGeod::getLatitudeDeg)); props->tie("controls/start-pos-long-deg", SGRawValueMethods(pos, &SGGeod::getLongitudeDeg)); - props->tie("velocities/speed-kts", - SGRawValuePointer(&speed)); + props->tie("controls/mp-control", + SGRawValuePointer(&MPControl)); + props->tie("controls/ai-control", + SGRawValuePointer(&AIControl)); props->tie("environment/surface-wind-speed-true-kts", SGRawValuePointer(&wind_speed_kts)); props->tie("environment/surface-wind-from-true-degs", @@ -337,24 +277,31 @@ void FGAICarrier::bind() { SGRawValuePointer(&rel_wind)); props->tie("environment/rel-wind-speed-kts", SGRawValuePointer(&rel_wind_speed_kts)); - props->tie("controls/flols/wave-off-lights", - SGRawValuePointer(&wave_off_lights)); + props->tie("environment/in-to-wind", + SGRawValuePointer(&in_to_wind)); + //props->tie("controls/flols/wave-off-lights", + // SGRawValuePointer(&wave_off_lights)); props->tie("controls/elevators", SGRawValuePointer(&elevators)); props->tie("surface-positions/elevators-pos-norm", SGRawValuePointer(&pos_norm)); - props->tie("controls/elevators-trans-time-s", + props->tie("controls/constants/elevators/trans-time-s", SGRawValuePointer(&transition_time)); - props->tie("controls/elevators-time-constant", + props->tie("controls/constants/elevators/time-constant", SGRawValuePointer(&time_constant)); props->tie("controls/jbd", SGRawValuePointer(&jbd)); props->tie("surface-positions/jbd-pos-norm", SGRawValuePointer(&jbd_pos_norm)); - props->tie("controls/jbd-trans-time-s", + props->tie("controls/constants/jbd/trans-time-s", SGRawValuePointer(&jbd_transition_time)); - props->tie("controls/jbd-time-constant", + props->tie("controls/constants/jbd/time-constant", SGRawValuePointer(&jbd_time_constant)); + props->tie("controls/turn-to-recovery-hdg", + SGRawValuePointer(&turn_to_recovery_hdg)); + props->tie("controls/turn-to-base-course", + SGRawValuePointer(&turn_to_base_course)); + props->setBoolValue("controls/flols/cut-lights", false); props->setBoolValue("controls/flols/wave-off-lights", false); @@ -362,6 +309,8 @@ void FGAICarrier::bind() { props->setBoolValue("controls/crew", false); props->setStringValue("navaids/tacan/channel-ID", TACAN_channel_id.c_str()); props->setStringValue("sign", sign.c_str()); + props->setBoolValue("controls/lighting/deck-lights", false); + props->setDoubleValue("controls/lighting/flood-lights-red-norm", 0); } @@ -373,21 +322,24 @@ void FGAICarrier::unbind() { props->untie("controls/flols/distance-m"); props->untie("controls/flols/angle-degs"); props->untie("controls/turn-to-launch-hdg"); - props->untie("velocities/speed-kts"); props->untie("environment/wind-speed-true-kts"); props->untie("environment/wind-from-true-degs"); props->untie("environment/rel-wind-from-degs"); props->untie("environment/rel-wind-speed-kts"); - props->untie("controls/flols/wave-off-lights"); + props->untie("environment/in-to-wind"); + //props->untie("controls/flols/wave-off-lights"); props->untie("controls/elevators"); props->untie("surface-positions/elevators-pos-norm"); - props->untie("controls/elevators-trans-time-secs"); - props->untie("controls/elevators-time-constant"); + props->untie("controls/constants/elevators/trans-time-secs"); + props->untie("controls/constants/elevators/time-constant"); props->untie("controls/jbd"); - props->untie("surface-positions/jbd-pos-norm"); - props->untie("controls/jbd-trans-time-s"); + props->untie("surface-positions/jbd/pos-norm"); + props->untie("controls/constants/jbd/trans-time-s"); props->untie("controls/jbd-time-constant"); - + props->untie("controls/mp-control"); + props->untie("controls/ai-control"); + props->untie("controls/turn-to-recovery-hdg"); + props->untie("controls/turn-to-base-course"); } @@ -416,201 +368,9 @@ bool FGAICarrier::getParkPosition(const string& id, SGGeod& geodPos, return false; } - -void FGAICarrier::mark_nohot(ssgEntity* e) { - if (e->isAKindOf(ssgTypeBranch())) { - ssgBranch* br = (ssgBranch*)e; - ssgEntity* kid; - for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() ) - mark_nohot(kid); - - br->clrTraversalMaskBits(SSGTRAV_HOT); - - } else if (e->isAKindOf(ssgTypeLeaf())) { - - e->clrTraversalMaskBits(SSGTRAV_HOT); - } -} - - -bool FGAICarrier::mark_wires(ssgEntity* e, const list& wire_objects, bool mark) { - bool found = false; - if (e->isAKindOf(ssgTypeBranch())) { - ssgBranch* br = (ssgBranch*)e; - ssgEntity* kid; - - list::const_iterator it; - for (it = wire_objects.begin(); it != wire_objects.end(); ++it) - mark = mark || (e->getName() && (*it) == e->getName()); - - for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() ) - found = mark_wires(kid, wire_objects, mark) || found; - - if (found) - br->setTraversalMaskBits(SSGTRAV_HOT); - - } else if (e->isAKindOf(ssgTypeLeaf())) { - list::const_iterator it; - for (it = wire_objects.begin(); it != wire_objects.end(); ++it) { - if (mark || (e->getName() && (*it) == e->getName())) { - e->setTraversalMaskBits(SSGTRAV_HOT); - ssgBase* ud = e->getUserData(); - if (ud) { - FGAICarrierHardware* ch = dynamic_cast(ud); - if (ch) { - SG_LOG(SG_GENERAL, SG_WARN, - "AICarrier: Carrier hardware gets marked twice!\n" - " You have probably a whole branch marked as" - " a wire which also includes other carrier hardware."); - } else { - SG_LOG(SG_GENERAL, SG_ALERT, - "AICarrier: Found user data attached to a leaf node which " - "should be marked as a wire!\n ****Skipping!****"); - } - } else { - e->setUserData( FGAICarrierHardware::newWire( this ) ); - ssgLeaf *l = (ssgLeaf*)e; - if ( l->getNumLines() != 1 ) { - SG_LOG(SG_GENERAL, SG_ALERT, - "AICarrier: Found wires not modeled with exactly one line!"); - } - found = true; - } - } - } - } - return found; -} - - -bool FGAICarrier::mark_solid(ssgEntity* e, const list& solid_objects, bool mark) { - bool found = false; - if (e->isAKindOf(ssgTypeBranch())) { - ssgBranch* br = (ssgBranch*)e; - ssgEntity* kid; - - list::const_iterator it; - for (it = solid_objects.begin(); it != solid_objects.end(); ++it) - mark = mark || (e->getName() && (*it) == e->getName()); - - for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() ) - found = mark_solid(kid, solid_objects, mark) || found; - - if (found) - br->setTraversalMaskBits(SSGTRAV_HOT); - - } else if (e->isAKindOf(ssgTypeLeaf())) { - list::const_iterator it; - for (it = solid_objects.begin(); it != solid_objects.end(); ++it) { - if (mark || (e->getName() && (*it) == e->getName())) { - e->setTraversalMaskBits(SSGTRAV_HOT); - ssgBase* ud = e->getUserData(); - - if (ud) { - FGAICarrierHardware* ch = dynamic_cast(ud); - if (ch) { - SG_LOG(SG_GENERAL, SG_WARN, - "AICarrier: Carrier hardware gets marked twice!\n" - " You have probably a whole branch marked solid" - " which also includes other carrier hardware."); - } else { - SG_LOG(SG_GENERAL, SG_ALERT, - "AICarrier: Found user data attached to a leaf node which " - "should be marked solid!\n ****Skipping!****"); - } - } else { - e->setUserData( FGAICarrierHardware::newSolid( this ) ); - found = true; - } - } - } - } - return found; -} - - -bool FGAICarrier::mark_cat(ssgEntity* e, const list& cat_objects, bool mark) { - bool found = false; - if (e->isAKindOf(ssgTypeBranch())) { - ssgBranch* br = (ssgBranch*)e; - ssgEntity* kid; - - list::const_iterator it; - for (it = cat_objects.begin(); it != cat_objects.end(); ++it) - mark = mark || (e->getName() && (*it) == e->getName()); - - for ( kid = br->getKid(0); kid != NULL ; kid = br->getNextKid() ) - found = mark_cat(kid, cat_objects, mark) || found; - - if (found) - br->setTraversalMaskBits(SSGTRAV_HOT); - - } else if (e->isAKindOf(ssgTypeLeaf())) { - list::const_iterator it; - for (it = cat_objects.begin(); it != cat_objects.end(); ++it) { - if (mark || (e->getName() && (*it) == e->getName())) { - e->setTraversalMaskBits(SSGTRAV_HOT); - ssgBase* ud = e->getUserData(); - if (ud) { - FGAICarrierHardware* ch = dynamic_cast(ud); - if (ch) { - SG_LOG(SG_GENERAL, SG_WARN, - "AICarrier: Carrier hardware gets marked twice!\n" - "You have probably a whole branch marked as" - "a catapult which also includes other carrier hardware."); - } else { - SG_LOG(SG_GENERAL, SG_ALERT, - "AICarrier: Found user data attached to a leaf node which " - "should be marked as a catapult!\n ****Skipping!****"); - } - } else { - e->setUserData( FGAICarrierHardware::newCatapult( this ) ); - ssgLeaf *l = (ssgLeaf*)e; - if ( l->getNumLines() != 1 ) { - SG_LOG(SG_GENERAL, SG_ALERT, - "AICarrier: Found a cat not modeled with exactly " - "one line!"); - } else { - // Now some special code to make sure the cat points in the right - // direction. The 0 index must be the backward end, the 1 index - // the forward end. - // Forward is positive x-direction in our 3D model, also the model - // as such is flattened when it is loaded, so we do not need to - // care for transforms ... - short v[2]; - l->getLine(0, v, v+1 ); - SGVec3f ends[2]; - for (int k=0; k<2; ++k) - sgCopyVec3( ends[k].sg(), l->getVertex( v[k] ) ); - - // When the 1 end is behind the 0 end, swap the coordinates. - if (ends[0][0] < ends[1][0]) { - sgCopyVec3( l->getVertex( v[0] ), ends[1].sg() ); - sgCopyVec3( l->getVertex( v[1] ), ends[0].sg() ); - } - found = true; - } - } - } - } - } - return found; -} - // find relative wind void FGAICarrier::UpdateWind( double dt) { - double recip; - - //calculate the reciprocal hdg - - if (hdg >= 180) - recip = hdg - 180; - else - recip = hdg + 180; - - //cout <<" heading: " << hdg << "recip: " << recip << endl; - //get the surface wind speed and direction wind_from_deg = _surface_wind_from_deg_node->getDoubleValue(); wind_speed_kts = _surface_wind_speed_node->getDoubleValue(); @@ -632,27 +392,21 @@ void FGAICarrier::UpdateWind( double dt) { + (rel_wind_speed_from_north_kts * rel_wind_speed_from_north_kts)); //calculate the relative wind direction - rel_wind_from_deg = atan(rel_wind_speed_from_east_kts/rel_wind_speed_from_north_kts) + rel_wind_from_deg = atan2(rel_wind_speed_from_east_kts, rel_wind_speed_from_north_kts) * SG_RADIANS_TO_DEGREES; - // rationalise the output - if (rel_wind_speed_from_north_kts <= 0) { - rel_wind_from_deg = 180 + rel_wind_from_deg; - } else { - if(rel_wind_speed_from_east_kts <= 0) - rel_wind_from_deg = 360 + rel_wind_from_deg; - } - //calculate rel wind rel_wind = rel_wind_from_deg - hdg; - if (rel_wind > 180) - rel_wind -= 360; + SG_NORMALIZE_RANGE(rel_wind, -180.0, 180.0); + + //set in to wind property + InToWind(); //switch the wave-off lights - if (InToWind()) - wave_off_lights = false; - else - wave_off_lights = true; + //if (InToWind()) + // wave_off_lights = false; + //else + // wave_off_lights = true; // cout << "rel wind: " << rel_wind << endl; @@ -661,18 +415,52 @@ void FGAICarrier::UpdateWind( double dt) { void FGAICarrier::TurnToLaunch(){ + // calculate tgt heading + if (wind_speed_kts < 3){ + tgt_heading = base_course; + } else { + tgt_heading = wind_from_deg; + } + //calculate tgt speed double tgt_speed = 25 - wind_speed_kts; if (tgt_speed < 10) tgt_speed = 10; //turn the carrier - FGAIShip::TurnTo(wind_from_deg); + FGAIShip::TurnTo(tgt_heading); FGAIShip::AccelTo(tgt_speed); } +void FGAICarrier::TurnToRecover(){ + + //these are the rules for adjusting heading to provide a relative wind + //down the angled flightdeck + + if (wind_speed_kts < 3){ + tgt_heading = base_course + 60; + } else if (rel_wind < -9 && rel_wind >= -180){ + tgt_heading = wind_from_deg; + } else if (rel_wind > -7 && rel_wind < 45){ + tgt_heading = wind_from_deg + 60; + } else if (rel_wind >=45 && rel_wind < 180){ + tgt_heading = wind_from_deg + 45; + } else + tgt_heading = hdg; + SG_NORMALIZE_RANGE(tgt_heading, 0.0, 360.0); + + //calculate tgt speed + double tgt_speed = 26 - wind_speed_kts; + if (tgt_speed < 10) + tgt_speed = 10; + + //turn the carrier + FGAIShip::TurnTo(tgt_heading); + FGAIShip::AccelTo(tgt_speed); + +} void FGAICarrier::TurnToBase(){ //turn the carrier @@ -746,16 +534,13 @@ bool FGAICarrier::OutsideBox() { //returns true if the carrier is outside operat } // end OutsideBox -// return the distance to the horizon, given the altitude and the radius of the earth -float FGAICarrier::Horizon(float h) { - return RADIUS_M * acos(RADIUS_M / (RADIUS_M + h)); -} - - bool FGAICarrier::InToWind() { - if ( fabs(rel_wind) < 5 ) - return true; + in_to_wind = false; + if ( fabs(rel_wind) < 10 ){ + in_to_wind = true; + return true; + } return false; } @@ -835,7 +620,3 @@ void FGAICarrier::UpdateJBD(double dt, double jbd_transition_time) { return; } // end UpdateJBD - - -int FGAICarrierHardware::unique_id = 1; -