fi
])
+
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+#
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+#
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+# this or PKG_CHECK_MODULES is called, or make sure to call
+# PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_ifval([$2], [$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ ifelse([$4], , [AC_MSG_ERROR(dnl
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT
+])],
+ [AC_MSG_RESULT([no])
+ $4])
+elif test $pkg_failed = untried; then
+ ifelse([$4], , [AC_MSG_FAILURE(dnl
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])],
+ [$4])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ ifelse([$3], , :, [$3])
+fi[]dnl
+])# PKG_CHECK_MODULES
glversion - returns the version number of OpenGL
extension-supported - returns true if an OpenGL extension is supported
property - returns the boolean value of a property
+float-property - returns the float value of a property, useful inside equal, less or less-equal nodes
shader-language - returns the version of GLSL supported, or 0 if there is none.
The proper way to test whether to enable a shader-based technique is:
+ <predicate>
+ <and>
+ <property>/sim/rendering/shader-effects</property>
+ <less-equal>
+ <value type="float">1.0</value>
+ <shader-language/>
+ </less-equal>
+ </and>
+ </predicate>
+
+There is also a property set by the user to indicate what is the level
+of quality desired. This level of quality can be checked in the predicate
+like this :
<predicate>
<and>
<property>/sim/rendering/shader-effects</property>
- <less-equal>
- <value type="float">1.0</value>
- <shader-language/>
- </less-equal>
+ <less-equal>
+ <value type="float">2.0</value>
+ <float-property>/sim/rendering/quality-level</float-property>
+ </less-equal>
+ <!-- other predicate conditions -->
</and>
</predicate>
-
+
+The range of /sim/rendering/quality-level is [0..5]
+ * 2.0 is the threshold for relief mapping effects,
+ * 4.0 is the threshold for geometry shader usage.
A technique can consist of several passes. A pass is basically an Open
Scene Graph StateSet. Ultimately all OpenGL and OSG modes and state
effect. For example, effects that support transparent and opaque
geometry could have as part of a technique:
- <blend>
- <active><use>blend/active</use></active>
- <source>src-alpha</source>
- <destination>one-minus-src-alpha</destination>
- </blend>
+ <blend>
+ <active><use>blend/active</use></active>
+ <source>src-alpha</source>
+ <destination>one-minus-src-alpha</destination>
+ </blend>
So if the blend/active parameter is true blending will be activated
using the usual blending equation; otherwise blending is disabled.
Values are assigned to technique properties in several ways:
* They can appear directly in the techniques section as a
- constant. For example:
- <uniform>
- <name>ColorsTex</name>
- <type>sampler-1d</type>
- <value type="int">2</value>
- </uniform>
- * The name of a property in the parameters section can be
- referenced using a "use" clause. For example, in the technique
- section:
- <material>
- <ambient><use>material/ambient</use></ambient>
- </material>
- Then, in the parameters section of the effect:
- <parameters>
- <material>
- <ambient type="vec4d">
- 0.2 .2 0.2 1.0
- </ambient>
- </material>
- </parameters>
-
- It's worth pointing out that the "material" property in a
- technique specifies part of OpenGL's state, whereas "material"
- in the parameters section is just a name, part of a
- hierarchical namespace.
-
- * A property in the parameters section doesn't need to contain
- a constant value; it can also contain a "use" property. Here
- the value of the use clause is the name of a node in an
- external property tree which will be used as the source of a
- value. If the name begins with '/', the node is in
- FlightGear's global property tree; otherwise, it is in a local
- property tree, usually belonging to a model [NOT IMPLEMENTED
- YET]. For example:
- <parameters>
- <chrome-light><use>/rendering/scene/chrome-light</use></chrome-light>
- </parameters>
- The type is determined by what is expected by the technique
- attribute that will ultimately receive the value. [There is
- no way to get vector values out of the main property system
- yet; this will be fixed shortly.] Values that are declared
- this way are dynamically updated if the property node
- changes.
+ constant. For example:
+ <uniform>
+ <name>ColorsTex</name>
+ <type>sampler-1d</type>
+ <value type="int">2</value>
+ </uniform>
+ * The name of a property in the parameters section can be
+ referenced using a "use" clause. For example, in the technique
+ section:
+ <material>
+ <ambient><use>material/ambient</use></ambient>
+ </material>
+ Then, in the parameters section of the effect:
+ <parameters>
+ <material>
+ <ambient type="vec4d">0.2 0.2 0.2 1.0</ambient>
+ </material>
+ </parameters>
+
+ It's worth pointing out that the "material" property in a
+ technique specifies part of OpenGL's state, whereas "material"
+ in the parameters section is just a name, part of a
+ hierarchical namespace.
+
+ * A property in the parameters section doesn't need to contain
+ a constant value; it can also contain a "use" property. Here
+ the value of the use clause is the name of a node in an
+ external property tree which will be used as the source of a
+ value. If the name begins with '/', the node is in
+ FlightGear's global property tree; otherwise, it is in a local
+ property tree, usually belonging to a model [NOT IMPLEMENTED
+ YET]. For example:
+ <parameters>
+ <chrome-light><use>/rendering/scene/chrome-light</use></chrome-light>
+ </parameters>
+ The type is determined by what is expected by the technique
+ attribute that will ultimately receive the value. [There is
+ no way to get vector values out of the main property system
+ yet; this will be fixed shortly.] Values that are declared
+ this way are dynamically updated if the property node
+ changes.
OpenGL Attributes
-----------------
The following attributes are currently implemented in techiques:
alpha-test - children: active, comparison, reference
- Valid values for comparision:
- never, less, equal, lequal, greater, notequal, gequal,
- always
+ Valid values for comparision:
+ never, less, equal, lequal, greater, notequal, gequal,
+ always
blend - children: active, source, destination, source-rgb,
- source-alpha, destination-rgb, destination-alpha
- Each operand can have the following values:
- dst-alpha, dst-color, one, one-minus-dst-alpha,
- one-minus-dst-color, one-minus-src-alpha,
- one-minus-src-color, src-alpha, src-alpha-saturate,
- src-color, constant-color, one-minus-constant-color,
- constant-alpha, one-minus-constant-alpha, zero
+ source-alpha, destination-rgb, destination-alpha
+ Each operand can have the following values:
+ dst-alpha, dst-color, one, one-minus-dst-alpha,
+ one-minus-dst-color, one-minus-src-alpha,
+ one-minus-src-color, src-alpha, src-alpha-saturate,
+ src-color, constant-color, one-minus-constant-color,
+ constant-alpha, one-minus-constant-alpha, zero
cull-face - front, back, front-back
lighting - true, false
material - children: active, ambient, ambient-front, ambient-back, diffuse,
- diffuse-front, diffuse-back, specular, specular-front,
- specular-back, emissive, emissive-front, emissive-back, shininess,
- shininess-front, shininess-back, color-mode
+ diffuse-front, diffuse-back, specular, specular-front,
+ specular-back, emissive, emissive-front, emissive-back, shininess,
+ shininess-front, shininess-back, color-mode
polygon-mode - children: front, back
- Valid values:
- fill, line, point
+ Valid values:
+ fill, line, point
program
- vertex-shader
- fragment-shader
+ vertex-shader
+ geometry-shader
+ fragment-shader
+ attribute
+ geometry-vertices-out: integer, max number of vertices emitted by geometry shader
+ geometry-input-type - points, lines, lines-adjacency, triangles, triangles-adjacency
+ geometry-output-type - points, line-strip, triangle-strip
render-bin - (OSG) children: bin-number, bin-name
texture-unit - has several child properties:
unit - The number of an OpenGL texture unit
- type - This is either an OpenGL texture type or the name of a
- builtin texture. Currently supported OpenGL types are 1d, 2d,
- 3d which have the following common parameters:
+ type - This is either an OpenGL texture type or the name of a
+ builtin texture. Currently supported OpenGL types are 1d, 2d,
+ 3d which have the following common parameters:
image (file name)
- filter
- mag-filter
- wrap-s
- wrap-t
- wrap-r
- The following builtin types are supported:
- white - 1 pixel white texture
- noise - a 3d noise texture
- environment
- mode
- color
+ filter
+ mag-filter
+ wrap-s
+ wrap-t
+ wrap-r
+ The following built-in types are supported:
+ white - 1 pixel white texture
+ noise - a 3d noise texture
+ environment
+ mode
+ color
uniform
- name
- type - float, float-vec3, float-vec4, sampler-1d, sampler-2d,
- sampler-3d
+ name
+ type - float, float-vec3, float-vec4, sampler-1d, sampler-2d,
+ sampler-3d
vertex-program-two-side - true, false
overrides any default values that might be in the base effect's
parameters section.
+Generate
+--------
+
+Often shader effects need tangent vectors to work properly. These
+tangent vectors, usually called tangent and binormal, are computed
+on the CPU and given to the shader as vertex attributes. These
+vectors are computed on demand on the geometry using the effect if
+the 'generate' clause is present in the effect file. Exemple :
+
+ <generate>
+ <tangent type="int">6</tangent>
+ <binormal type="int">7</binormal>
+ <normal type="int">8</normal>
+ </generate>
+
+Valid subnodes of 'generate' are 'tangent', 'binormal' or 'normal'.
+The integer value of these subnode is the index of the attribute
+that will hold the value of the vec3 vector.
+
+The generate clause is located under PropertyList in the xml file.
+
+In order to be available for the vertex shader, these data should
+be bound to an attribute in the program clause, like this :
+
+ <program>
+ <vertex-shader>my_vertex_shader</vertex-shader>
+ <attribute>
+ <name>my_tangent_attribute</name>
+ <index>6</index>
+ </attribute>
+ <attribute>
+ <name>my_binormal_attribute</name>
+ <index>7</index>
+ </attribute>
+ </program>
+
+attribute names are whatever the shader use. The index is the one
+declared in the 'generate' clause. So because generate/tangent has
+value 6 and my_tangent_attribute has index 6, my_tangent_attribute
+holds the tangent value for the vertex.
+
Default Effects in Terrain Materials and Models
----------------------------------------
+-----------------------------------------------
Effects for terrain work in this way: for each material type in
materials.xml an effect is created that inherits from a single default
system. The parameters created are:
* material active, ambient, diffuse, specular, emissive,
- shininess, color mode
- * blend active, source, destination
- * shade-model
- * cull-face
- * rendering-hint
- * texture type, image, filter, wrap-s, wrap-t
+ shininess, color mode
+ * blend active, source, destination
+ * shade-model
+ * cull-face
+ * rendering-hint
+ * texture type, image, filter, wrap-s, wrap-t
Specifying Custom Effects
-------------------------
The Effects directory contains the effects definitions; look there for
examples. Effects/crop.eff is a good example of a complex effect.
+
+Application
+-----------
+
+To apply an effect to a model or part of a model use:
+
+ <effect>
+ <inherits-from>Effects/light-cone</inherits-from>
+ <object-name>Cone</object-name>
+ </effect>
+
+where <inherits-from> </inherits-from> contains the path to the effect you want to apply.
+The effect does not need the file extension.
+
+NOTE:
+
+Chrome, although now implemented as an effect, still retains the old method of application:
+
+ <animation>
+ <type>shader</type>
+ <shader>chrome</shader>
+ <texture>glass_shader.png</texture>
+ <object-name>windscreen</object-name>
+ </animation>
+
+in order to maintain backward compatibility.
+
headingError = 0;
holdPos = false;
+ needsTaxiClearance = false;
_performance = 0; //TODO initialize to JET_TRANSPORT from PerformanceDB
dt = 0;
//cerr << trafficRef->getCallSign() << " has passed waypoint " << prev->name << " at speed " << speed << endl;
if (prev->name == "PushBackPoint") {
dep->getDynamics()->releaseParking(fp->getGate());
- time_t holdUntil = now + 120;
- fp->setTime(holdUntil);
- //cerr << _getCallsign() << "Holding at pushback point" << endl;
+ AccelTo(0.0);
+ setTaxiClearanceRequest(true);
}
// This is the last taxi waypoint, and marks the the end of the flight plan
void announcePositionToController(); //TODO have to be public?
void processATC(FGATCInstruction instruction);
+ void setTaxiClearanceRequest(bool arg) { needsTaxiClearance = arg; };
+ bool getTaxiClearanceRequest() { return needsTaxiClearance; };
FGAISchedule * getTrafficRef() { return trafficRef; };
virtual const char* getTypeString(void) const { return "aircraft"; }
const char * _getTransponderCode() const;
bool reachedWaypoint;
+ bool needsTaxiClearance;
time_t timeElapsed;
PerformanceData* _performance; // the performance data for this aircraft
alt = 0;
}
+
bool FGATCInstruction::hasInstruction()
{
return (holdPattern || holdPosition || changeSpeed || changeHeading || changeAltitude || resolveCircularWait);
}
+/***************************************************************************
+ * FGATCController
+ *
+ **************************************************************************/
+
+
+
+
+FGATCController::FGATCController()
+{
+ dt_count = 0;
+ available = true;
+ lastTransmission = 0;
+}
+
string FGATCController::getGateName(FGAIAircraft *ref)
{
return ref->atGate();
//double commFreqD;
sender = rec->getAircraft()->getTrafficRef()->getCallSign();
+ //cerr << "transmitting for: " << sender << "Leg = " << rec->getLeg() << endl;
switch (rec->getLeg()) {
case 2:
case 3:
taxiFreqStr = formatATCFrequency3_2(taxiFreq);
text = receiver + ". Switching to " + taxiFreqStr + ". " + sender;
break;
+ case MSG_INITIATE_CONTACT:
+ text = receiver + ". With you. " + sender;
+ break;
+ case MSG_ACKNOWLEDGE_INITIATE_CONTACT:
+ text = receiver + ". Roger. " + sender;
+ break;
case MSG_REQUEST_PUSHBACK_CLEARANCE:
text = receiver + ". Request push-back. " + sender;
break;
break;
case MSG_HOLD_PUSHBACK_CLEARANCE:
text = receiver + ". Standby. " + sender;
- break;
- default:
- text = sender + ". Transmitting unknown Message";
+ break;
+ case MSG_REQUEST_TAXI_CLEARANCE:
+ text = receiver + ". Ready to Taxi. " + sender;
+ break;
+ case MSG_ISSUE_TAXI_CLEARANCE:
+ text = receiver + ". Cleared to taxi. " + sender;
+ break;
+ case MSG_ACKNOWLEDGE_TAXI_CLEARANCE:
+ text = receiver + ". Cleared to taxi. " + sender;
+ break;
+ case MSG_HOLD_POSITION:
+ text = receiver + ". Hold Position. " + sender;
+ break;
+ case MSG_ACKNOWLEDGE_HOLD_POSITION:
+ text = receiver + ". Holding Position. " + sender;
+ break;
+ case MSG_RESUME_TAXI:
+ text = receiver + ". Resume Taxiing. " + sender;
+ break;
+ case MSG_ACKNOWLEDGE_RESUME_TAXI:
+ text = receiver + ". Continuing Taxi. " + sender;
+ break;
+ default:
+ text = text + sender + ". Transmitting unknown Message";
break;
}
double onBoardRadioFreq0 = fgGetDouble("/instrumentation/comm[0]/frequencies/selected-mhz");
FGStartupController::FGStartupController() :
FGATCController()
{
- available = false;
- lastTransmission = 0;
}
void FGStartupController::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
available = false;
}
}
- // Note: The next two stages are only necessesary when Startup control is
+ // Note: The next four stages are only necessesary when Startup control is
// on a different frequency, compared to ground control
if ((state == 4) && available){
if (now > startTime+130) {
available = false;
}
}
+ if ((state == 5) && available){
+ if (now > startTime+140) {
+ transmit(&(*i), MSG_INITIATE_CONTACT, ATC_AIR_TO_GROUND);
+ i->updateState();
+ lastTransmission = now;
+ available = false;
+ }
+ }
+ if ((state == 6) && available){
+ if (now > startTime+150) {
+ transmit(&(*i), MSG_ACKNOWLEDGE_INITIATE_CONTACT, ATC_GROUND_TO_AIR);
+ i->updateState();
+ lastTransmission = now;
+ available = false;
+ }
+ }
// TODO: Switch to APRON control and request pushback Clearance.
// Get Push back clearance
- if ((state == 5) && available){
- if (now > startTime+160) {
+ if ((state == 7) && available){
+ if (now > startTime+180) {
transmit(&(*i), MSG_REQUEST_PUSHBACK_CLEARANCE, ATC_AIR_TO_GROUND);
i->updateState();
lastTransmission = now;
available = false;
}
}
- if ((state == 6) && available){
- if (now > startTime+180) {
+ if ((state == 8) && available){
+ if (now > startTime+200) {
if (i->pushBackAllowed()) {
i->allowRepeatedTransmissions();
transmit(&(*i), MSG_PERMIT_PUSHBACK_CLEARANCE, ATC_GROUND_TO_AIR);
available = false;
}
}
- if ((state == 6) && available){
+ if ((state == 9) && available){
i->setHoldPosition(false);
}
}
void setLeg(int lg) { leg = lg;};
int getId() { return id;};
int getState() { return state;};
+ void setState(int s) { state = s;}
FGATCInstruction getInstruction() { return instruction;};
bool hasInstruction() { return instruction.hasInstruction(); };
void setPositionAndHeading(double lat, double lon, double hdg, double spd, double alt);
*************************************************************************************/
class FGATCController
{
-private:
+protected:
+ bool available;
+ time_t lastTransmission;
+
double dt_count;
public:
typedef enum {
MSG_ANNOUNCE_ENGINE_START,
- MSG_REQUEST_ENGINE_START,
+ MSG_REQUEST_ENGINE_START,
MSG_PERMIT_ENGINE_START,
MSG_DENY_ENGINE_START,
MSG_ACKNOWLEDGE_ENGINE_START,
MSG_REQUEST_PUSHBACK_CLEARANCE,
- MSG_PERMIT_PUSHBACK_CLEARANCE,
+ MSG_PERMIT_PUSHBACK_CLEARANCE,
MSG_HOLD_PUSHBACK_CLEARANCE,
- MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY } AtcMsgId;
+ MSG_ACKNOWLEDGE_SWITCH_GROUND_FREQUENCY,
+ MSG_INITIATE_CONTACT,
+ MSG_ACKNOWLEDGE_INITIATE_CONTACT,
+ MSG_REQUEST_TAXI_CLEARANCE,
+ MSG_ISSUE_TAXI_CLEARANCE,
+ MSG_ACKNOWLEDGE_TAXI_CLEARANCE,
+ MSG_HOLD_POSITION,
+ MSG_ACKNOWLEDGE_HOLD_POSITION,
+ MSG_RESUME_TAXI,
+ MSG_ACKNOWLEDGE_RESUME_TAXI } AtcMsgId;
typedef enum {
ATC_AIR_TO_GROUND,
ATC_GROUND_TO_AIR } AtcMsgDir;
- FGATCController() { dt_count = 0;};
+ FGATCController();
virtual ~FGATCController() {};
virtual void announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentRoute,
double lat, double lon,
{
private:
TrafficVector activeTraffic;
- bool available;
- time_t lastTransmission;
//ActiveRunwayVec activeRunways;
public:
{
SGSoundMgr *smgr = globals->get_soundmgr();
_sgr = smgr->find("atc", true);
+ _sgr->tie_to_listener();
_volume = fgGetNode("/sim/sound/atc/volume", true);
_enabled = fgGetNode("/sim/sound/atc/enabled", true);
FGATCMgr::FGATCMgr() :
initDone(false),
atc_list(new atc_list_type),
- last_in_range(false)
+#ifdef ENABLE_AUDIO_SUPPORT
+ voiceOK(false),
+ voice(true),
+#else
+ voice(false),
+#endif
+ last_in_range(false),
+ v1(0)
{
}
// Is this still true after the reorganization of the event managar??
// -EMH-
-#ifdef ENABLE_AUDIO_SUPPORT
- // Load all available voices.
- // For now we'll do one hardwired one
-
- v1 = new FGATCVoice;
- try {
- voiceOK = v1->LoadVoice("default");
- voice = true;
- } catch ( sg_io_exception & e) {
- voiceOK = false;
- SG_LOG(SG_ATC, SG_ALERT, "Unable to load default voice : " << e.getFormattedMessage().c_str());
- voice = false;
- delete v1;
- v1 = 0;
- }
-
- /* I've loaded the voice even if /sim/sound/pause is true
- * since I know no way of forcing load of the voice if the user
- * subsequently switches /sim/sound/audible to true.
- * (which is the right thing to do -- CLO) :-) */
-#else
- voice = false;
-#endif
-
// Initialise the ATC Dialogs
//cout << "Initing Transmissions..." << endl;
SG_LOG(SG_ATC, SG_INFO, " ATC Transmissions");
if(voice) {
switch(type) {
case ATIS: case AWOS:
+#ifdef ENABLE_AUDIO_SUPPORT
+ // Delayed loading fo all available voices, needed because the
+ // soundmanager might not be initialized (at all) at this point.
+ // For now we'll do one hardwired one
+
+ /* I've loaded the voice even if /sim/sound/pause is true
+ * since I know no way of forcing load of the voice if the user
+ * subsequently switches /sim/sound/audible to true.
+ * (which is the right thing to do -- CLO) :-)
+ */
+ if (!voiceOK && fgGetBool("/sim/sound/working")) {
+ v1 = new FGATCVoice;
+ try {
+ voiceOK = v1->LoadVoice("default");
+ voice = voiceOK;
+ } catch ( sg_io_exception & e) {
+ voiceOK = false;
+ SG_LOG(SG_ATC, SG_ALERT, "Unable to load default voice : "
+ << e.getFormattedMessage().c_str());
+ voice = false;
+ delete v1;
+ v1 = 0;
+ }
+ }
+#endif
if(voiceOK) {
return(v1);
}
timingInfo.clear();
stamp("begin");
static SGPropertyNode *replay_master
- = fgGetNode( "/sim/freeze/replay", true );
+ = fgGetNode( "/sim/freeze/replay-state", true );
if( disable_replay->getBoolValue() ) {
- if( sim_time != 0.0 ) {
+ if ( sim_time != 0.0 ) {
// we were recording data
init();
}
return;
}
//stamp("point_01");
- if ( replay_master->getBoolValue() ) {
+ if ( replay_master->getIntValue() > 0 ) {
// don't record the replay session
return;
}
r = new FGReplayData;
stamp("Replay_02");
} else {
- r = recycler.front();
- recycler.pop_front();
- //stamp("point_04be");
+ r = recycler.front();
+ recycler.pop_front();
+ //stamp("point_04be");
}
r->sim_time = sim_time;
//r->ctrls = c;
SGGeod pos(SGGeod::fromDegFt(lon, lat, last_apt_elev));
FGAirport* apt = new FGAirport(last_apt_id, pos, tower, last_apt_name, false,
fptypeFromRobinType(atoi(last_apt_type.c_str())));
-
apt->setRunwaysAndTaxiways(runways, taxiways, pavements);
}
#include "simple.hxx"
#include "dynamics.hxx"
-FGAirportDynamics::FGAirportDynamics(FGAirport* ap) :
- _ap(ap), rwyPrefs(ap), SIDs(ap) {
- lastUpdate = 0;
+FGAirportDynamics::FGAirportDynamics(FGAirport * ap):
+_ap(ap), rwyPrefs(ap), SIDs(ap)
+{
+ lastUpdate = 0;
- // For testing only. This needs to be refined when we move ATIS functionality over.
- atisInformation = "Sierra";
+ // For testing only. This needs to be refined when we move ATIS functionality over.
+ atisInformation = "Sierra";
}
// Note that the ground network should also be copied
-FGAirportDynamics::FGAirportDynamics(const FGAirportDynamics& other) :
- rwyPrefs(other.rwyPrefs),
- SIDs(other.SIDs)
+FGAirportDynamics::
+FGAirportDynamics(const FGAirportDynamics & other):rwyPrefs(other.
+ rwyPrefs),
+SIDs(other.SIDs)
{
- for (FGParkingVecConstIterator ip= other.parkings.begin(); ip != other.parkings.end(); ip++)
- parkings.push_back(*(ip));
- // rwyPrefs = other.rwyPrefs;
- lastUpdate = other.lastUpdate;
-
- stringVecConstIterator il;
- for (il = other.landing.begin(); il != other.landing.end(); il++)
- landing.push_back(*il);
- for (il = other.takeoff.begin(); il != other.takeoff.end(); il++)
- takeoff.push_back(*il);
- lastUpdate = other.lastUpdate;
- atisInformation = other.atisInformation;
+ for (FGParkingVecConstIterator ip = other.parkings.begin();
+ ip != other.parkings.end(); ip++)
+ parkings.push_back(*(ip));
+ // rwyPrefs = other.rwyPrefs;
+ lastUpdate = other.lastUpdate;
+
+ stringVecConstIterator il;
+ for (il = other.landing.begin(); il != other.landing.end(); il++)
+ landing.push_back(*il);
+ for (il = other.takeoff.begin(); il != other.takeoff.end(); il++)
+ takeoff.push_back(*il);
+ lastUpdate = other.lastUpdate;
+ atisInformation = other.atisInformation;
}
// Destructor
// Initialization required after XMLRead
-void FGAirportDynamics::init()
+void FGAirportDynamics::init()
{
- // This may seem a bit weird to first randomly shuffle the parkings
- // and then sort them again. However, parkings are sorted here by ascending
- // radius. Since many parkings have similar radii, with each radius class they will
- // still be allocated relatively systematically. Randomizing prior to sorting will
- // prevent any initial orderings to be destroyed, leading (hopefully) to a more
- // naturalistic gate assignment.
- random_shuffle(parkings.begin(), parkings.end());
- sort(parkings.begin(), parkings.end());
- // add the gate positions to the ground network.
- groundNetwork.addNodes(&parkings);
- groundNetwork.init();
- groundNetwork.setTowerController(&towerController);
- groundNetwork.setParent(_ap);
+ // This may seem a bit weird to first randomly shuffle the parkings
+ // and then sort them again. However, parkings are sorted here by ascending
+ // radius. Since many parkings have similar radii, with each radius class they will
+ // still be allocated relatively systematically. Randomizing prior to sorting will
+ // prevent any initial orderings to be destroyed, leading (hopefully) to a more
+ // naturalistic gate assignment.
+ random_shuffle(parkings.begin(), parkings.end());
+ sort(parkings.begin(), parkings.end());
+ // add the gate positions to the ground network.
+ groundNetwork.addNodes(&parkings);
+ groundNetwork.init();
+ groundNetwork.setTowerController(&towerController);
+ groundNetwork.setParent(_ap);
}
-bool FGAirportDynamics::getAvailableParking(double *lat, double *lon, double *heading, int *gateId, double rad, const string &flType, const string &acType, const string &airline)
+bool FGAirportDynamics::getAvailableParking(double *lat, double *lon,
+ double *heading, int *gateId,
+ double rad,
+ const string & flType,
+ const string & acType,
+ const string & airline)
{
- bool found = false;
- bool available = false;
- //string gateType;
-
- FGParkingVecIterator i;
-// if (flType == "cargo")
-// {
-// gateType = "RAMP_CARGO";
-// }
-// else if (flType == "ga")
-// {
-// gateType = "RAMP_GA";
-// }
-// else gateType = "GATE";
-
- if (parkings.begin() == parkings.end())
- {
- //cerr << "Could not find parking spot at " << _ap->getId() << endl;
- *lat = _ap->getLatitude();
- *lon = _ap->getLongitude();
- *heading = 0;
- found = true;
+ bool found = false;
+ bool available = false;
+
+
+ FGParkingVecIterator i;
+ if (parkings.begin() == parkings.end()) {
+ //cerr << "Could not find parking spot at " << _ap->getId() << endl;
+ *lat = _ap->getLatitude();
+ *lon = _ap->getLongitude();
+ *heading = 0;
+ found = true;
+ } else {
+ // First try finding a parking with a designated airline code
+ for (i = parkings.begin(); !(i == parkings.end() || found); i++) {
+ available = true;
+ // Taken by another aircraft
+ if (!(i->isAvailable())) {
+ available = false;
+ continue;
+ }
+ // No airline codes, so skip
+ if (i->getCodes().empty()) {
+ available = false;
+ continue;
+ } else { // Airline code doesn't match
+ //cerr << "Code = " << airline << ": Codes " << i->getCodes();
+ if (i->getCodes().find(airline, 0) == string::npos) {
+ available = false;
+ //cerr << "Unavailable" << endl;
+ continue;
+ } else {
+ //cerr << "Available" << endl;
+ }
+ }
+ // Type doesn't match
+ if (i->getType() != flType) {
+ available = false;
+ continue;
+ }
+ // too small
+ if (i->getRadius() < rad) {
+ available = false;
+ continue;
+ }
+
+ if (available) {
+ *lat = i->getLatitude();
+ *lon = i->getLongitude();
+ *heading = i->getHeading();
+ *gateId = i->getIndex();
+ i->setAvailable(false);
+ found = true;
+ }
+ }
+ // then try again for those without codes.
+ for (i = parkings.begin(); !(i == parkings.end() || found); i++) {
+ available = true;
+ if (!(i->isAvailable())) {
+ available = false;
+ continue;
+ }
+ if (!(i->getCodes().empty())) {
+ if ((i->getCodes().find(airline, 0) == string::npos)) {
+ available = false;
+ continue;
+ }
+ }
+ if (i->getType() != flType) {
+ available = false;
+ continue;
+ }
+
+ if (i->getRadius() < rad) {
+ available = false;
+ continue;
+ }
+
+ if (available) {
+ *lat = i->getLatitude();
+ *lon = i->getLongitude();
+ *heading = i->getHeading();
+ *gateId = i->getIndex();
+ i->setAvailable(false);
+ found = true;
+ }
+ }
+ // And finally once more if that didn't work. Now ignore the airline codes, as a last resort
+ for (i = parkings.begin(); !(i == parkings.end() || found); i++) {
+ available = true;
+ if (!(i->isAvailable())) {
+ available = false;
+ continue;
+ }
+ if (i->getType() != flType) {
+ available = false;
+ continue;
+ }
+
+ if (i->getRadius() < rad) {
+ available = false;
+ continue;
+ }
+
+ if (available) {
+ *lat = i->getLatitude();
+ *lon = i->getLongitude();
+ *heading = i->getHeading();
+ *gateId = i->getIndex();
+ i->setAvailable(false);
+ found = true;
+ }
+ }
}
- else
- {
- // First try finding a parking with a designated airline code
- for (i = parkings.begin(); !(i == parkings.end() || found); i++)
- {
- //cerr << "Gate Id: " << i->getIndex()
- // << " Type : " << i->getType()
- // << " Codes : " << i->getCodes()
- // << " Radius: " << i->getRadius()
- // << " Name : " << i->getName()
- // << " Available: " << i->isAvailable() << endl;
- available = true;
- // Taken by another aircraft
- if (!(i->isAvailable()))
- {
- available = false;
- continue;
- }
- // No airline codes, so skip
- if (i->getCodes().empty())
- {
- available = false;
- continue;
- }
- else // Airline code doesn't match
- {
- //cerr << "Code = " << airline << ": Codes " << i->getCodes();
- if (i->getCodes().find(airline, 0) == string::npos)
- {
- available = false;
- //cerr << "Unavailable" << endl;
- continue;
- }
- else
- {
- //cerr << "Available" << endl;
- }
- }
- // Type doesn't match
- if (i->getType() != flType)
- {
- available = false;
- continue;
- }
- // too small
- if (i->getRadius() < rad)
- {
- available = false;
- continue;
- }
-
- if (available)
- {
- *lat = i->getLatitude ();
- *lon = i->getLongitude();
- *heading = i->getHeading ();
- *gateId = i->getIndex ();
- i->setAvailable(false);
- found = true;
- }
- }
- // then try again for those without codes.
- for (i = parkings.begin(); !(i == parkings.end() || found); i++)
- {
- available = true;
- if (!(i->isAvailable()))
- {
- available = false;
- continue;
- }
- if (!(i->getCodes().empty()))
- {
- if ((i->getCodes().find(airline,0) == string::npos))
- {
- available = false;
- continue;
- }
- }
- if (i->getType() != flType)
- {
- available = false;
- continue;
- }
-
- if (i->getRadius() < rad)
- {
- available = false;
- continue;
- }
-
- if (available)
- {
- *lat = i->getLatitude ();
- *lon = i->getLongitude();
- *heading = i->getHeading ();
- *gateId = i->getIndex ();
- i->setAvailable(false);
- found = true;
- }
- }
- // And finally once more if that didn't work. Now ignore the airline codes, as a last resort
- for (i = parkings.begin(); !(i == parkings.end() || found); i++)
- {
- available = true;
- if (!(i->isAvailable()))
- {
- available = false;
- continue;
- }
- if (i->getType() != flType)
- {
- available = false;
- continue;
- }
-
- if (i->getRadius() < rad)
- {
- available = false;
- continue;
- }
-
- if (available)
- {
- *lat = i->getLatitude ();
- *lon = i->getLongitude();
- *heading = i->getHeading ();
- *gateId = i->getIndex ();
- i->setAvailable(false);
- found = true;
- }
- }
+ if (!found) {
+ //cerr << "Traffic overflow at" << _ap->getId()
+ // << ". flType = " << flType
+ // << ". airline = " << airline
+ // << " Radius = " <<rad
+ // << endl;
+ *lat = _ap->getLatitude();
+ *lon = _ap->getLongitude();
+ *heading = 0;
+ *gateId = -1;
+ //exit(1);
}
- if (!found)
- {
- //cerr << "Traffic overflow at" << _ap->getId()
- // << ". flType = " << flType
- // << ". airline = " << airline
- // << " Radius = " <<rad
- // << endl;
- *lat = _ap->getLatitude();
- *lon = _ap->getLongitude();
- *heading = 0;
- *gateId = -1;
- //exit(1);
- }
- return found;
+ return found;
}
-void FGAirportDynamics::getParking (int id, double *lat, double* lon, double *heading)
+void FGAirportDynamics::getParking(int id, double *lat, double *lon,
+ double *heading)
{
- if (id < 0)
- {
- *lat = _ap->getLatitude();
- *lon = _ap->getLongitude();
- *heading = 0;
- }
- else
- {
- FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++)
- {
- if (id == i->getIndex())
- {
- *lat = i->getLatitude();
- *lon = i->getLongitude();
- *heading = i->getHeading();
- }
- }
+ if (id < 0) {
+ *lat = _ap->getLatitude();
+ *lon = _ap->getLongitude();
+ *heading = 0;
+ } else {
+ FGParkingVecIterator i = parkings.begin();
+ for (i = parkings.begin(); i != parkings.end(); i++) {
+ if (id == i->getIndex()) {
+ *lat = i->getLatitude();
+ *lon = i->getLongitude();
+ *heading = i->getHeading();
+ }
+ }
}
-}
+}
-FGParking *FGAirportDynamics::getParking(int id)
-{
+FGParking *FGAirportDynamics::getParking(int id)
+{
FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++)
- {
- if (id == i->getIndex()) {
- return &(*i);
- }
+ for (i = parkings.begin(); i != parkings.end(); i++) {
+ if (id == i->getIndex()) {
+ return &(*i);
}
+ }
return 0;
}
-string FGAirportDynamics::getParkingName(int id)
-{
+
+string FGAirportDynamics::getParkingName(int id)
+{
FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++)
- {
- if (id == i->getIndex()) {
- return i->getName();
- }
+ for (i = parkings.begin(); i != parkings.end(); i++) {
+ if (id == i->getIndex()) {
+ return i->getName();
}
+ }
return string("overflow");
}
+
void FGAirportDynamics::releaseParking(int id)
{
- if (id >= 0)
- {
-
- FGParkingVecIterator i = parkings.begin();
- for (i = parkings.begin(); i != parkings.end(); i++)
- {
- if (id == i->getIndex())
- {
- i -> setAvailable(true);
- }
- }
+ if (id >= 0) {
+
+ FGParkingVecIterator i = parkings.begin();
+ for (i = parkings.begin(); i != parkings.end(); i++) {
+ if (id == i->getIndex()) {
+ i->setAvailable(true);
+ }
+ }
}
}
-
-void FGAirportDynamics::setRwyUse(const FGRunwayPreference& ref)
+
+void FGAirportDynamics::setRwyUse(const FGRunwayPreference & ref)
{
- rwyPrefs = ref;
- //cerr << "Exiting due to not implemented yet" << endl;
- //exit(1);
+ rwyPrefs = ref;
+ //cerr << "Exiting due to not implemented yet" << endl;
+ //exit(1);
}
-bool FGAirportDynamics::innerGetActiveRunway(const string &trafficType, int action, string &runway, double heading)
+bool FGAirportDynamics::innerGetActiveRunway(const string & trafficType,
+ int action, string & runway,
+ double heading)
{
-double windSpeed;
- double windHeading;
- double maxTail;
- double maxCross;
- string name;
- string type;
-
- if (!rwyPrefs.available()) {
- return false;
- }
-
- RunwayGroup *currRunwayGroup = 0;
- int nrActiveRunways = 0;
- time_t dayStart = fgGetLong("/sim/time/utc/day-seconds");
- if ((abs((long)(dayStart - lastUpdate)) > 600) || trafficType != prevTrafficType)
- {
- landing.clear();
- takeoff.clear();
- lastUpdate = dayStart;
- prevTrafficType = trafficType;
-
- FGEnvironment
- stationweather = ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
- ->getEnvironment(getLatitude(),
- getLongitude(),
- getElevation());
-
- windSpeed = stationweather.get_wind_speed_kt();
- windHeading = stationweather.get_wind_from_heading_deg();
- string scheduleName;
- //cerr << "finding active Runway for" << _ap->getId() << endl;
- //cerr << "Nr of seconds since day start << " << dayStart << endl;
-
- ScheduleTime *currSched;
- //cerr << "A"<< endl;
- currSched = rwyPrefs.getSchedule(trafficType.c_str());
- if (!(currSched))
- return false;
- //cerr << "B"<< endl;
- scheduleName = currSched->getName(dayStart);
- maxTail = currSched->getTailWind ();
- maxCross = currSched->getCrossWind ();
- //cerr << "SChedule anme = " << scheduleName << endl;
- if (scheduleName.empty())
- return false;
- //cerr << "C"<< endl;
- currRunwayGroup = rwyPrefs.getGroup(scheduleName);
- //cerr << "D"<< endl;
- if (!(currRunwayGroup))
- return false;
- nrActiveRunways = currRunwayGroup->getNrActiveRunways();
+ double windSpeed;
+ double windHeading;
+ double maxTail;
+ double maxCross;
+ string name;
+ string type;
+
+ if (!rwyPrefs.available()) {
+ return false;
+ }
+
+ RunwayGroup *currRunwayGroup = 0;
+ int nrActiveRunways = 0;
+ time_t dayStart = fgGetLong("/sim/time/utc/day-seconds");
+ if ((abs((long) (dayStart - lastUpdate)) > 600)
+ || trafficType != prevTrafficType) {
+ landing.clear();
+ takeoff.clear();
+ lastUpdate = dayStart;
+ prevTrafficType = trafficType;
+
+ FGEnvironment
+ stationweather =
+ ((FGEnvironmentMgr *) globals->get_subsystem("environment"))
+ ->getEnvironment(getLatitude(), getLongitude(),
+ getElevation());
+
+ windSpeed = stationweather.get_wind_speed_kt();
+ windHeading = stationweather.get_wind_from_heading_deg();
+ string scheduleName;
+ //cerr << "finding active Runway for" << _ap->getId() << endl;
+ //cerr << "Nr of seconds since day start << " << dayStart << endl;
+
+ ScheduleTime *currSched;
+ //cerr << "A"<< endl;
+ currSched = rwyPrefs.getSchedule(trafficType.c_str());
+ if (!(currSched))
+ return false;
+ //cerr << "B"<< endl;
+ scheduleName = currSched->getName(dayStart);
+ maxTail = currSched->getTailWind();
+ maxCross = currSched->getCrossWind();
+ //cerr << "SChedule anme = " << scheduleName << endl;
+ if (scheduleName.empty())
+ return false;
+ //cerr << "C"<< endl;
+ currRunwayGroup = rwyPrefs.getGroup(scheduleName);
+ //cerr << "D"<< endl;
+ if (!(currRunwayGroup))
+ return false;
+ nrActiveRunways = currRunwayGroup->getNrActiveRunways();
// Keep a history of the currently active runways, to ensure
// that an already established selection of runways will not
// be overridden once a more preferred selection becomes
// available as that can lead to random runway swapping.
- if (trafficType == "com") {
- currentlyActive = &comActive;
+ if (trafficType == "com") {
+ currentlyActive = &comActive;
} else if (trafficType == "gen") {
- currentlyActive = &genActive;
+ currentlyActive = &genActive;
} else if (trafficType == "mil") {
- currentlyActive = &milActive;
+ currentlyActive = &milActive;
} else if (trafficType == "ul") {
- currentlyActive = &ulActive;
+ currentlyActive = &ulActive;
+ }
+
+ currRunwayGroup->setActive(_ap,
+ windSpeed,
+ windHeading,
+ maxTail, maxCross, currentlyActive);
+
+ // Note that I SHOULD keep multiple lists in memory, one for
+ // general aviation, one for commercial and one for military
+ // traffic.
+ currentlyActive->clear();
+ nrActiveRunways = currRunwayGroup->getNrActiveRunways();
+ //cerr << "Choosing runway for " << trafficType << endl;
+ for (int i = 0; i < nrActiveRunways; i++) {
+ type = "unknown"; // initialize to something other than landing or takeoff
+ currRunwayGroup->getActive(i, name, type);
+ if (type == "landing") {
+ landing.push_back(name);
+ currentlyActive->push_back(name);
+ //cerr << "Landing " << name << endl;
+ }
+ if (type == "takeoff") {
+ takeoff.push_back(name);
+ currentlyActive->push_back(name);
+ //cerr << "takeoff " << name << endl;
+ }
}
- //
- currRunwayGroup->setActive(_ap,
- windSpeed,
- windHeading,
- maxTail,
- maxCross,
- currentlyActive);
-
- // Note that I SHOULD keep multiple lists in memory, one for
- // general aviation, one for commercial and one for military
- // traffic.
- currentlyActive->clear();
- nrActiveRunways = currRunwayGroup->getNrActiveRunways();
- //cerr << "Choosing runway for " << trafficType << endl;
- for (int i = 0; i < nrActiveRunways; i++)
- {
- type = "unknown"; // initialize to something other than landing or takeoff
- currRunwayGroup->getActive(i, name, type);
- if (type == "landing")
- {
- landing.push_back(name);
- currentlyActive->push_back(name);
- //cerr << "Landing " << name << endl;
- }
- if (type == "takeoff")
- {
- takeoff.push_back(name);
- currentlyActive->push_back(name);
- //cerr << "takeoff " << name << endl;
- }
- }
- //cerr << endl;
- }
-
- if (action == 1) // takeoff
- {
- int nr = takeoff.size();
- if (nr)
- {
- // Note that the randomization below, is just a placeholder to choose between
- // multiple active runways for this action. This should be
- // under ATC control.
- runway = chooseRwyByHeading (takeoff, heading);
- }
- else
- { // Fallback
- runway = chooseRunwayFallback();
- }
- }
-
- if (action == 2) // landing
- {
- int nr = landing.size();
- if (nr)
- {
- runway = chooseRwyByHeading (landing, heading);
- }
- else
- { //fallback
- runway = chooseRunwayFallback();
- }
- }
-
- return true;
+ //cerr << endl;
+ }
+
+ if (action == 1) // takeoff
+ {
+ int nr = takeoff.size();
+ if (nr) {
+ // Note that the randomization below, is just a placeholder to choose between
+ // multiple active runways for this action. This should be
+ // under ATC control.
+ runway = chooseRwyByHeading(takeoff, heading);
+ } else { // Fallback
+ runway = chooseRunwayFallback();
+ }
+ }
+
+ if (action == 2) // landing
+ {
+ int nr = landing.size();
+ if (nr) {
+ runway = chooseRwyByHeading(landing, heading);
+ } else { //fallback
+ runway = chooseRunwayFallback();
+ }
+ }
+
+ return true;
}
-string FGAirportDynamics::chooseRwyByHeading(stringVec rwys, double heading) {
- double bestError = 360.0;
- double rwyHeading, headingError;
- string runway;
- for (stringVecIterator i = rwys.begin(); i != rwys.end(); i++) {
- FGRunway *rwy = _ap->getRunwayByIdent((*i));
- rwyHeading = rwy->headingDeg();
- headingError = fabs(heading - rwyHeading);
+string FGAirportDynamics::chooseRwyByHeading(stringVec rwys,
+ double heading)
+{
+ double bestError = 360.0;
+ double rwyHeading, headingError;
+ string runway;
+ for (stringVecIterator i = rwys.begin(); i != rwys.end(); i++) {
+ FGRunway *rwy = _ap->getRunwayByIdent((*i));
+ rwyHeading = rwy->headingDeg();
+ headingError = fabs(heading - rwyHeading);
if (headingError > 180)
headingError = fabs(headingError - 360);
if (headingError < bestError) {
runway = (*i);
bestError = headingError;
}
- }
- //cerr << "Using active runway " << runway << " for heading " << heading << endl;
- return runway;
+ }
+ //cerr << "Using active runway " << runway << " for heading " << heading << endl;
+ return runway;
}
-void FGAirportDynamics::getActiveRunway(const string &trafficType, int action, string &runway, double heading)
+void FGAirportDynamics::getActiveRunway(const string & trafficType,
+ int action, string & runway,
+ double heading)
{
- bool ok = innerGetActiveRunway(trafficType, action, runway, heading);
- if (!ok) {
- runway = chooseRunwayFallback();
- }
+ bool ok = innerGetActiveRunway(trafficType, action, runway, heading);
+ if (!ok) {
+ runway = chooseRunwayFallback();
+ }
}
string FGAirportDynamics::chooseRunwayFallback()
-{
- FGRunway* rwy = _ap->getActiveRunwayForUsage();
- return rwy->ident();
+{
+ FGRunway *rwy = _ap->getActiveRunwayForUsage();
+ return rwy->ident();
}
-void FGAirportDynamics::addParking(FGParking& park) {
- parkings.push_back(park);
+void FGAirportDynamics::addParking(FGParking & park)
+{
+ parkings.push_back(park);
}
-double FGAirportDynamics::getLatitude() const {
- return _ap->getLatitude();
+double FGAirportDynamics::getLatitude() const
+{
+ return _ap->getLatitude();
}
-double FGAirportDynamics::getLongitude() const {
- return _ap->getLongitude();
+double FGAirportDynamics::getLongitude() const
+{
+ return _ap->getLongitude();
}
-double FGAirportDynamics::getElevation() const {
- return _ap->getElevation();
+double FGAirportDynamics::getElevation() const
+{
+ return _ap->getElevation();
}
-const string& FGAirportDynamics::getId() const {
- return _ap->getId();
+const string & FGAirportDynamics::getId() const
+{
+ return _ap->getId();
}
// Experimental: Return a different ground frequency depending on the leg of the
// so that at least I can start working on assigning different frequencies to different
// operations.
-int FGAirportDynamics::getGroundFrequency(unsigned leg) {
- //return freqGround.size() ? freqGround[0] : 0; };
- int groundFreq = 0;
- if (leg < 2) {
- SG_LOG(SG_ATC, SG_ALERT, "Leg value is smaller than two at " << SG_ORIGIN);
- }
- if (freqGround.size() == 0) {
- return 0;
- }
- if ((freqGround.size() > leg-1) && (leg > 1)) {
- groundFreq = freqGround[leg-1];
- }
- if ((freqGround.size() < leg-1) && (leg > 1)) {
- groundFreq = (freqGround.size() < (leg-1)) ? freqGround[freqGround.size()-1] : freqGround[leg-2];
- }
- if ((freqGround.size() >= leg-1) && (leg > 1)) {
- groundFreq = freqGround[leg-2];
- }
+int FGAirportDynamics::getGroundFrequency(unsigned leg)
+{
+ //return freqGround.size() ? freqGround[0] : 0; };
+ int groundFreq = 0;
+ if (leg < 2) {
+ SG_LOG(SG_ATC, SG_ALERT,
+ "Leg value is smaller than two at " << SG_ORIGIN);
+ }
+ if (freqGround.size() == 0) {
+ return 0;
+ }
+ if ((freqGround.size() > leg - 1) && (leg > 1)) {
+ groundFreq = freqGround[leg - 1];
+ }
+ if ((freqGround.size() < leg - 1) && (leg > 1)) {
+ groundFreq =
+ (freqGround.size() <
+ (leg - 1)) ? freqGround[freqGround.size() -
+ 1] : freqGround[leg - 2];
+ }
+ if ((freqGround.size() >= leg - 1) && (leg > 1)) {
+ groundFreq = freqGround[leg - 2];
+ }
return groundFreq;
}
-FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway, double heading)
+FGAIFlightPlan *FGAirportDynamics::getSID(string activeRunway,
+ double heading)
{
- return SIDs.getBest(activeRunway, heading);
+ return SIDs.getBest(activeRunway, heading);
}
#include <Airports/dynamics.hxx>
+#include <AIModel/AIAircraft.hxx>
#include <AIModel/AIFlightPlan.hxx>
#include "groundnetwork.hxx"
* FGTaxiSegment
**************************************************************************/
-void FGTaxiSegment::setStart(FGTaxiNodeVector *nodes)
+void FGTaxiSegment::setStart(FGTaxiNodeVector * nodes)
{
- FGTaxiNodeVectorIterator i = nodes->begin();
- while (i != nodes->end())
- {
- //cerr << "Scanning start node index" << (*i)->getIndex() << endl;
- if ((*i)->getIndex() == startNode)
- {
- start = (*i)->getAddress();
- (*i)->addSegment(this);
- return;
- }
- i++;
- }
- SG_LOG(SG_GENERAL, SG_ALERT, "Could not find start node " << startNode << endl);
+ FGTaxiNodeVectorIterator i = nodes->begin();
+ while (i != nodes->end()) {
+ //cerr << "Scanning start node index" << (*i)->getIndex() << endl;
+ if ((*i)->getIndex() == startNode) {
+ start = (*i)->getAddress();
+ (*i)->addSegment(this);
+ return;
+ }
+ i++;
+ }
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "Could not find start node " << startNode << endl);
}
-void FGTaxiSegment::setEnd(FGTaxiNodeVector *nodes)
+void FGTaxiSegment::setEnd(FGTaxiNodeVector * nodes)
{
- FGTaxiNodeVectorIterator i = nodes->begin();
- while (i != nodes->end())
- {
- //cerr << "Scanning end node index" << (*i)->getIndex() << endl;
- if ((*i)->getIndex() == endNode)
- {
- end = (*i)->getAddress();
- return;
- }
- i++;
- }
- SG_LOG(SG_GENERAL, SG_ALERT, "Could not find end node " << endNode << endl);
+ FGTaxiNodeVectorIterator i = nodes->begin();
+ while (i != nodes->end()) {
+ //cerr << "Scanning end node index" << (*i)->getIndex() << endl;
+ if ((*i)->getIndex() == endNode) {
+ end = (*i)->getAddress();
+ return;
+ }
+ i++;
+ }
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "Could not find end node " << endNode << endl);
}
// doing this.
void FGTaxiSegment::setTrackDistance()
{
- length = SGGeodesy::distanceM(start->getGeod(), end->getGeod());
+ length = SGGeodesy::distanceM(start->getGeod(), end->getGeod());
}
void FGTaxiSegment::setCourseDiff(double crse)
{
- headingDiff = fabs(course-crse);
-
- if (headingDiff > 180)
- headingDiff = fabs(headingDiff - 360);
+ headingDiff = fabs(course - crse);
+
+ if (headingDiff > 180)
+ headingDiff = fabs(headingDiff - 360);
}
/***************************************************************************
* FGTaxiRoute
**************************************************************************/
-bool FGTaxiRoute::next(int *nde)
-{
- //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
- // cerr << "FGTaxiRoute contains : " << *(i) << endl;
- //cerr << "Offset from end: " << nodes.end() - currNode << endl;
- //if (currNode != nodes.end())
- // cerr << "true" << endl;
- //else
- // cerr << "false" << endl;
- //if (nodes.size() != (routes.size()) +1)
- // cerr << "ALERT: Misconfigured TaxiRoute : " << nodes.size() << " " << routes.size() << endl;
-
- if (currNode == nodes.end())
- return false;
- *nde = *(currNode);
- if (currNode != nodes.begin()) // make sure route corresponds to the end node
- currRoute++;
- currNode++;
- return true;
+bool FGTaxiRoute::next(int *nde)
+{
+ //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
+ // cerr << "FGTaxiRoute contains : " << *(i) << endl;
+ //cerr << "Offset from end: " << nodes.end() - currNode << endl;
+ //if (currNode != nodes.end())
+ // cerr << "true" << endl;
+ //else
+ // cerr << "false" << endl;
+ //if (nodes.size() != (routes.size()) +1)
+ // cerr << "ALERT: Misconfigured TaxiRoute : " << nodes.size() << " " << routes.size() << endl;
+
+ if (currNode == nodes.end())
+ return false;
+ *nde = *(currNode);
+ if (currNode != nodes.begin()) // make sure route corresponds to the end node
+ currRoute++;
+ currNode++;
+ return true;
};
-bool FGTaxiRoute::next(int *nde, int *rte)
-{
- //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
- // cerr << "FGTaxiRoute contains : " << *(i) << endl;
- //cerr << "Offset from end: " << nodes.end() - currNode << endl;
- //if (currNode != nodes.end())
- // cerr << "true" << endl;
- //else
- // cerr << "false" << endl;
- if (nodes.size() != (routes.size()) +1) {
- SG_LOG(SG_GENERAL, SG_ALERT, "ALERT: Misconfigured TaxiRoute : " << nodes.size() << " " << routes.size());
- exit(1);
- }
- if (currNode == nodes.end())
- return false;
- *nde = *(currNode);
- //*rte = *(currRoute);
- if (currNode != nodes.begin()) // Make sure route corresponds to the end node
- {
- *rte = *(currRoute);
- currRoute++;
+bool FGTaxiRoute::next(int *nde, int *rte)
+{
+ //for (intVecIterator i = nodes.begin(); i != nodes.end(); i++)
+ // cerr << "FGTaxiRoute contains : " << *(i) << endl;
+ //cerr << "Offset from end: " << nodes.end() - currNode << endl;
+ //if (currNode != nodes.end())
+ // cerr << "true" << endl;
+ //else
+ // cerr << "false" << endl;
+ if (nodes.size() != (routes.size()) + 1) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "ALERT: Misconfigured TaxiRoute : " << nodes.
+ size() << " " << routes.size());
+ exit(1);
}
- else
+ if (currNode == nodes.end())
+ return false;
+ *nde = *(currNode);
+ //*rte = *(currRoute);
+ if (currNode != nodes.begin()) // Make sure route corresponds to the end node
{
- // If currNode points to the first node, this means the aircraft is not on the taxi node
- // yet. Make sure to return a unique identifyer in this situation though, because otherwise
- // the speed adjust AI code may be unable to resolve whether two aircraft are on the same
- // taxi route or not. the negative of the preceding route seems a logical choice, as it is
- // unique for any starting location.
- // Note that this is probably just a temporary fix until I get Parking / tower control working.
- *rte = -1 * *(currRoute);
- }
- currNode++;
- return true;
+ *rte = *(currRoute);
+ currRoute++;
+ } else {
+ // If currNode points to the first node, this means the aircraft is not on the taxi node
+ // yet. Make sure to return a unique identifyer in this situation though, because otherwise
+ // the speed adjust AI code may be unable to resolve whether two aircraft are on the same
+ // taxi route or not. the negative of the preceding route seems a logical choice, as it is
+ // unique for any starting location.
+ // Note that this is probably just a temporary fix until I get Parking / tower control working.
+ *rte = -1 * *(currRoute);
+ }
+ currNode++;
+ return true;
};
void FGTaxiRoute::rewind(int route)
{
- int currPoint;
- int currRoute;
- first();
- do {
- if (!(next(&currPoint, &currRoute))) {
- SG_LOG(SG_GENERAL,SG_ALERT, "Error in rewinding TaxiRoute: current" << currRoute
- << " goal " << route);
- }
- } while (currRoute != route);
+ int currPoint;
+ int currRoute;
+ first();
+ do {
+ if (!(next(&currPoint, &currRoute))) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "Error in rewinding TaxiRoute: current" << currRoute <<
+ " goal " << route);
+ }
+ } while (currRoute != route);
}
/***************************************************************************
* FGGroundNetwork()
**************************************************************************/
-bool compare_nodes(FGTaxiNode *a, FGTaxiNode *b) {
-return (*a) < (*b);
+bool compare_nodes(FGTaxiNode * a, FGTaxiNode * b)
+{
+ return (*a) < (*b);
}
-bool compare_segments(FGTaxiSegment *a, FGTaxiSegment *b) {
-return (*a) < (*b);
+bool compare_segments(FGTaxiSegment * a, FGTaxiSegment * b)
+{
+ return (*a) < (*b);
}
FGGroundNetwork::FGGroundNetwork()
{
- hasNetwork = false;
- foundRoute = false;
- totalDistance = 0;
- maxDistance = 0;
- //maxDepth = 1000;
- count = 0;
- currTraffic = activeTraffic.begin();
+ hasNetwork = false;
+ foundRoute = false;
+ totalDistance = 0;
+ maxDistance = 0;
+ //maxDepth = 1000;
+ count = 0;
+ currTraffic = activeTraffic.begin();
}
FGGroundNetwork::~FGGroundNetwork()
{
- for (FGTaxiNodeVectorIterator node = nodes.begin();
- node != nodes.end();
- node++)
- {
- delete (*node);
+ for (FGTaxiNodeVectorIterator node = nodes.begin();
+ node != nodes.end(); node++) {
+ delete(*node);
}
- nodes.clear();
- pushBackNodes.clear();
- for (FGTaxiSegmentVectorIterator seg = segments.begin();
- seg != segments.end();
- seg++)
- {
- delete (*seg);
+ nodes.clear();
+ pushBackNodes.clear();
+ for (FGTaxiSegmentVectorIterator seg = segments.begin();
+ seg != segments.end(); seg++) {
+ delete(*seg);
}
- segments.clear();
+ segments.clear();
}
-void FGGroundNetwork::addSegment(const FGTaxiSegment &seg)
+void FGGroundNetwork::addSegment(const FGTaxiSegment & seg)
{
- segments.push_back(new FGTaxiSegment(seg));
+ segments.push_back(new FGTaxiSegment(seg));
}
-void FGGroundNetwork::addNode(const FGTaxiNode &node)
+void FGGroundNetwork::addNode(const FGTaxiNode & node)
{
- nodes.push_back(new FGTaxiNode(node));
+ nodes.push_back(new FGTaxiNode(node));
}
-void FGGroundNetwork::addNodes(FGParkingVec *parkings)
+void FGGroundNetwork::addNodes(FGParkingVec * parkings)
{
- FGTaxiNode n;
- FGParkingVecIterator i = parkings->begin();
- while (i != parkings->end())
- {
- n.setIndex(i->getIndex());
- n.setLatitude(i->getLatitude());
- n.setLongitude(i->getLongitude());
- nodes.push_back(new FGTaxiNode(n));
-
- i++;
+ FGTaxiNode n;
+ FGParkingVecIterator i = parkings->begin();
+ while (i != parkings->end()) {
+ n.setIndex(i->getIndex());
+ n.setLatitude(i->getLatitude());
+ n.setLongitude(i->getLongitude());
+ nodes.push_back(new FGTaxiNode(n));
+
+ i++;
}
}
void FGGroundNetwork::init()
{
- hasNetwork = true;
- int index = 1;
- sort(nodes.begin(), nodes.end(), compare_nodes);
- //sort(segments.begin(), segments.end(), compare_segments());
- FGTaxiSegmentVectorIterator i = segments.begin();
- while(i != segments.end()) {
- (*i)->setStart(&nodes);
- (*i)->setEnd (&nodes);
- (*i)->setTrackDistance();
- (*i)->setIndex(index);
- if ((*i)->isPushBack()) {
- pushBackNodes.push_back((*i)->getEnd());
- }
- //SG_LOG(SG_GENERAL, SG_BULK, "initializing segment " << (*i)->getIndex() << endl);
- //SG_LOG(SG_GENERAL, SG_BULK, "Track distance = " << (*i)->getLength() << endl);
- //SG_LOG(SG_GENERAL, SG_BULK, "Track runs from " << (*i)->getStart()->getIndex() << " to "
- // << (*i)->getEnd()->getIndex() << endl);
- i++;
- index++;
- }
-
- i = segments.begin();
- while(i != segments.end()) {
- FGTaxiSegmentVectorIterator j = (*i)->getEnd()->getBeginRoute();
- while (j != (*i)->getEnd()->getEndRoute())
- {
- if ((*j)->getEnd()->getIndex() == (*i)->getStart()->getIndex())
- {
-// int start1 = (*i)->getStart()->getIndex();
-// int end1 = (*i)->getEnd() ->getIndex();
-// int start2 = (*j)->getStart()->getIndex();
-// int end2 = (*j)->getEnd()->getIndex();
-// int oppIndex = (*j)->getIndex();
- //cerr << "Opposite of " << (*i)->getIndex() << " (" << start1 << "," << end1 << ") "
- // << "happens to be " << oppIndex << " (" << start2 << "," << end2 << ") " << endl;
- (*i)->setOpposite(*j);
- break;
- }
- j++;
- }
- i++;
- }
- //FGTaxiNodeVectorIterator j = nodes.begin();
- //while (j != nodes.end()) {
- // if ((*j)->getHoldPointType() == 3) {
- // pushBackNodes.push_back((*j));
- // }
- // j++;
- //}
- //cerr << "Done initializing ground network" << endl;
- //exit(1);
+ hasNetwork = true;
+ int index = 1;
+ sort(nodes.begin(), nodes.end(), compare_nodes);
+ //sort(segments.begin(), segments.end(), compare_segments());
+ FGTaxiSegmentVectorIterator i = segments.begin();
+ while (i != segments.end()) {
+ (*i)->setStart(&nodes);
+ (*i)->setEnd(&nodes);
+ (*i)->setTrackDistance();
+ (*i)->setIndex(index);
+ if ((*i)->isPushBack()) {
+ pushBackNodes.push_back((*i)->getEnd());
+ }
+ //SG_LOG(SG_GENERAL, SG_BULK, "initializing segment " << (*i)->getIndex() << endl);
+ //SG_LOG(SG_GENERAL, SG_BULK, "Track distance = " << (*i)->getLength() << endl);
+ //SG_LOG(SG_GENERAL, SG_BULK, "Track runs from " << (*i)->getStart()->getIndex() << " to "
+ // << (*i)->getEnd()->getIndex() << endl);
+ i++;
+ index++;
+ }
+
+ i = segments.begin();
+ while (i != segments.end()) {
+ FGTaxiSegmentVectorIterator j = (*i)->getEnd()->getBeginRoute();
+ while (j != (*i)->getEnd()->getEndRoute()) {
+ if ((*j)->getEnd()->getIndex() == (*i)->getStart()->getIndex()) {
+// int start1 = (*i)->getStart()->getIndex();
+// int end1 = (*i)->getEnd() ->getIndex();
+// int start2 = (*j)->getStart()->getIndex();
+// int end2 = (*j)->getEnd()->getIndex();
+// int oppIndex = (*j)->getIndex();
+ //cerr << "Opposite of " << (*i)->getIndex() << " (" << start1 << "," << end1 << ") "
+ // << "happens to be " << oppIndex << " (" << start2 << "," << end2 << ") " << endl;
+ (*i)->setOpposite(*j);
+ break;
+ }
+ j++;
+ }
+ i++;
+ }
+ //FGTaxiNodeVectorIterator j = nodes.begin();
+ //while (j != nodes.end()) {
+ // if ((*j)->getHoldPointType() == 3) {
+ // pushBackNodes.push_back((*j));
+ // }
+ // j++;
+ //}
+ //cerr << "Done initializing ground network" << endl;
+ //exit(1);
}
-int FGGroundNetwork::findNearestNode(const SGGeod& aGeod)
+int FGGroundNetwork::findNearestNode(const SGGeod & aGeod)
{
- double minDist = HUGE_VAL;
- int index = -1;
-
- for (FGTaxiNodeVectorIterator itr = nodes.begin(); itr != nodes.end(); itr++)
- {
- double d = SGGeodesy::distanceM(aGeod, (*itr)->getGeod());
- if (d < minDist)
- {
- minDist = d;
- index = (*itr)->getIndex();
- //cerr << "Minimum distance of " << minDist << " for index " << index << endl;
+ double minDist = HUGE_VAL;
+ int index = -1;
+
+ for (FGTaxiNodeVectorIterator itr = nodes.begin(); itr != nodes.end();
+ itr++) {
+ double d = SGGeodesy::distanceM(aGeod, (*itr)->getGeod());
+ if (d < minDist) {
+ minDist = d;
+ index = (*itr)->getIndex();
+ //cerr << "Minimum distance of " << minDist << " for index " << index << endl;
+ }
}
- }
-
- return index;
+
+ return index;
}
int FGGroundNetwork::findNearestNode(double lat, double lon)
{
- return findNearestNode(SGGeod::fromDeg(lon, lat));
+ return findNearestNode(SGGeod::fromDeg(lon, lat));
}
FGTaxiNode *FGGroundNetwork::findNode(unsigned idx)
-{ /*
- for (FGTaxiNodeVectorIterator
- itr = nodes.begin();
- itr != nodes.end(); itr++)
- {
- if (itr->getIndex() == idx)
- return itr->getAddress();
- }*/
-
- if ((idx >= 0) && (idx < nodes.size()))
- return nodes[idx]->getAddress();
- else
- return 0;
+{ /*
+ for (FGTaxiNodeVectorIterator
+ itr = nodes.begin();
+ itr != nodes.end(); itr++)
+ {
+ if (itr->getIndex() == idx)
+ return itr->getAddress();
+ } */
+
+ if ((idx >= 0) && (idx < nodes.size()))
+ return nodes[idx]->getAddress();
+ else
+ return 0;
}
FGTaxiSegment *FGGroundNetwork::findSegment(unsigned idx)
-{/*
- for (FGTaxiSegmentVectorIterator
- itr = segments.begin();
- itr != segments.end(); itr++)
- {
- if (itr->getIndex() == idx)
- return itr->getAddress();
- }
- */
- if ((idx > 0) && (idx <= segments.size()))
- return segments[idx-1]->getAddress();
- else
- {
- //cerr << "Alert: trying to find invalid segment " << idx << endl;
- return 0;
+{ /*
+ for (FGTaxiSegmentVectorIterator
+ itr = segments.begin();
+ itr != segments.end(); itr++)
+ {
+ if (itr->getIndex() == idx)
+ return itr->getAddress();
+ }
+ */
+ if ((idx > 0) && (idx <= segments.size()))
+ return segments[idx - 1]->getAddress();
+ else {
+ //cerr << "Alert: trying to find invalid segment " << idx << endl;
+ return 0;
}
}
-FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end, bool fullSearch)
+FGTaxiRoute FGGroundNetwork::findShortestRoute(int start, int end,
+ bool fullSearch)
{
//implements Dijkstra's algorithm to find shortest distance route from start to end
//taken from http://en.wikipedia.org/wiki/Dijkstra's_algorithm
int nParkings = parent->getDynamics()->getNrOfParkings();
FGTaxiNodeVector *currNodesSet;
if (fullSearch) {
- currNodesSet = &nodes;
+ currNodesSet = &nodes;
} else {
- currNodesSet = &pushBackNodes;
+ currNodesSet = &pushBackNodes;
}
for (FGTaxiNodeVectorIterator
- itr = currNodesSet->begin();
- itr != currNodesSet->end(); itr++) {
- (*itr)->setPathScore(HUGE_VAL); //infinity by all practical means
- (*itr)->setPreviousNode(0); //
- (*itr)->setPreviousSeg (0); //
- }
+ itr = currNodesSet->begin(); itr != currNodesSet->end(); itr++) {
+ (*itr)->setPathScore(HUGE_VAL); //infinity by all practical means
+ (*itr)->setPreviousNode(0); //
+ (*itr)->setPreviousSeg(0); //
+ }
FGTaxiNode *firstNode = findNode(start);
firstNode->setPathScore(0);
- FGTaxiNode *lastNode = findNode(end);
+ FGTaxiNode *lastNode = findNode(end);
- FGTaxiNodeVector unvisited(*currNodesSet); // working copy
+ FGTaxiNodeVector unvisited(*currNodesSet); // working copy
while (!unvisited.empty()) {
- FGTaxiNode* best = *(unvisited.begin());
+ FGTaxiNode *best = *(unvisited.begin());
for (FGTaxiNodeVectorIterator
- itr = unvisited.begin();
- itr != unvisited.end(); itr++) {
- if ((*itr)->getPathScore() < best->getPathScore())
- best = (*itr);
+ itr = unvisited.begin(); itr != unvisited.end(); itr++) {
+ if ((*itr)->getPathScore() < best->getPathScore())
+ best = (*itr);
}
- FGTaxiNodeVectorIterator newend = remove(unvisited.begin(), unvisited.end(), best);
+ FGTaxiNodeVectorIterator newend =
+ remove(unvisited.begin(), unvisited.end(), best);
unvisited.erase(newend, unvisited.end());
-
+
if (best == lastNode) { // found route or best not connected
break;
} else {
seg = best->getBeginRoute();
seg != best->getEndRoute(); seg++) {
if (fullSearch || (*seg)->isPushBack()) {
- FGTaxiNode* tgt = (*seg)->getEnd();
- double alt = best->getPathScore() + (*seg)->getLength() + (*seg)->getPenalty(nParkings);
- if (alt < tgt->getPathScore()) { // Relax (u,v)
+ FGTaxiNode *tgt = (*seg)->getEnd();
+ double alt =
+ best->getPathScore() + (*seg)->getLength() +
+ (*seg)->getPenalty(nParkings);
+ if (alt < tgt->getPathScore()) { // Relax (u,v)
tgt->setPathScore(alt);
tgt->setPreviousNode(best);
- tgt->setPreviousSeg(*seg); //
- }
+ tgt->setPreviousSeg(*seg); //
+ }
} else {
- // // cerr << "Skipping TaxiSegment " << (*seg)->getIndex() << endl;
+ // // cerr << "Skipping TaxiSegment " << (*seg)->getIndex() << endl;
}
}
}
if (lastNode->getPathScore() == HUGE_VAL) {
// no valid route found
- if (fullSearch) {
- SG_LOG( SG_GENERAL, SG_ALERT, "Failed to find route from waypoint " << start << " to " << end << " at " <<
- parent->getId());
+ if (fullSearch) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "Failed to find route from waypoint " << start << " to "
+ << end << " at " << parent->getId());
}
- FGTaxiRoute empty;
- return empty;
+ FGTaxiRoute empty;
+ return empty;
//exit(1); //TODO exit more gracefully, no need to stall the whole sim with broken GN's
} else {
// assemble route from backtrace information
intVec nodes, routes;
- FGTaxiNode* bt = lastNode;
+ FGTaxiNode *bt = lastNode;
while (bt->getPreviousNode() != 0) {
nodes.push_back(bt->getIndex());
routes.push_back(bt->getPreviousSegment()->getIndex());
}
}
-int FGTaxiSegment::getPenalty(int nGates) {
- int penalty = 0;
- if (end->getIndex() < nGates) {
- penalty += 10000;
- }
- if (end->getIsOnRunway()) { // For now. In future versions, need to find out whether runway is active.
- penalty += 1000;
- }
- return penalty;
+int FGTaxiSegment::getPenalty(int nGates)
+{
+ int penalty = 0;
+ if (end->getIndex() < nGates) {
+ penalty += 10000;
+ }
+ if (end->getIsOnRunway()) { // For now. In future versions, need to find out whether runway is active.
+ penalty += 1000;
+ }
+ return penalty;
}
/* ATC Related Functions */
-void FGGroundNetwork::announcePosition(int id, FGAIFlightPlan *intendedRoute, int currentPosition,
- double lat, double lon, double heading,
- double speed, double alt, double radius, int leg,
- FGAIAircraft *aircraft)
+void FGGroundNetwork::announcePosition(int id,
+ FGAIFlightPlan * intendedRoute,
+ int currentPosition, double lat,
+ double lon, double heading,
+ double speed, double alt,
+ double radius, int leg,
+ FGAIAircraft * aircraft)
{
- TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id alread has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
- if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- // Add a new TrafficRecord if no one exsists for this aircraft.
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- FGTrafficRecord rec;
- rec.setId(id);
- rec.setPositionAndIntentions(currentPosition, intendedRoute);
- rec.setPositionAndHeading(lat, lon, heading, speed, alt);
- rec.setRadius(radius); // only need to do this when creating the record.
- rec.setAircraft(aircraft);
- activeTraffic.push_back(rec);
- } else {
- i->setPositionAndIntentions(currentPosition, intendedRoute);
- i->setPositionAndHeading(lat, lon, heading, speed, alt);
- }
+ TrafficVectorIterator i = activeTraffic.begin();
+ // Search search if the current id alread has an entry
+ // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ }
+ // Add a new TrafficRecord if no one exsists for this aircraft.
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ FGTrafficRecord rec;
+ rec.setId(id);
+ rec.setLeg(leg);
+ rec.setPositionAndIntentions(currentPosition, intendedRoute);
+ rec.setPositionAndHeading(lat, lon, heading, speed, alt);
+ rec.setRadius(radius); // only need to do this when creating the record.
+ rec.setAircraft(aircraft);
+ activeTraffic.push_back(rec);
+ } else {
+ i->setPositionAndIntentions(currentPosition, intendedRoute);
+ i->setPositionAndHeading(lat, lon, heading, speed, alt);
+ }
}
-void FGGroundNetwork::signOff(int id) {
- TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id alread has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
- if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Aircraft without traffic record is signing off");
- } else {
- i = activeTraffic.erase(i);
- }
+void FGGroundNetwork::signOff(int id)
+{
+ TrafficVectorIterator i = activeTraffic.begin();
+ // Search search if the current id alread has an entry
+ // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ }
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: Aircraft without traffic record is signing off");
+ } else {
+ i = activeTraffic.erase(i);
+ }
}
-void FGGroundNetwork::update(int id, double lat, double lon, double heading, double speed, double alt,
- double dt) {
- // Check whether aircraft are on hold due to a preceding pushback. If so, make sure to
- // Transmit air-to-ground "Ready to taxi request:
- // Transmit ground to air approval / hold
- // Transmit confirmation ...
- // Probably use a status mechanism similar to the Engine start procedure in the startup controller.
-
-
- TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
- TrafficVectorIterator current, closest;
- if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- // update position of the current aircraft
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: updating aircraft without traffic record");
- } else {
- i->setPositionAndHeading(lat, lon, heading, speed, alt);
- current = i;
- }
-
- setDt(getDt() + dt);
-
- // Update every three secs, but add some randomness
- // to prevent all IA objects doing this in synchrony
- //if (getDt() < (3.0) + (rand() % 10))
- // return;
- //else
- // setDt(0);
- current->clearResolveCircularWait();
- current->setWaitsForId(0);
- checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
- checkHoldPosition (id, lat, lon, heading, speed, alt);
- if (checkForCircularWaits(id)) {
- i->setResolveCircularWait();
- }
+void FGGroundNetwork::update(int id, double lat, double lon,
+ double heading, double speed, double alt,
+ double dt)
+{
+ // Check whether aircraft are on hold due to a preceding pushback. If so, make sure to
+ // Transmit air-to-ground "Ready to taxi request:
+ // Transmit ground to air approval / hold
+ // Transmit confirmation ...
+ // Probably use a status mechanism similar to the Engine start procedure in the startup controller.
+
+
+ TrafficVectorIterator i = activeTraffic.begin();
+ // Search search if the current id has an entry
+ // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ TrafficVectorIterator current, closest;
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ }
+ // update position of the current aircraft
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: updating aircraft without traffic record");
+ } else {
+ i->setPositionAndHeading(lat, lon, heading, speed, alt);
+ current = i;
+ }
+
+ setDt(getDt() + dt);
+
+ // Update every three secs, but add some randomness
+ // to prevent all IA objects doing this in synchrony
+ //if (getDt() < (3.0) + (rand() % 10))
+ // return;
+ //else
+ // setDt(0);
+ current->clearResolveCircularWait();
+ current->setWaitsForId(0);
+ checkSpeedAdjustment(id, lat, lon, heading, speed, alt);
+ checkHoldPosition(id, lat, lon, heading, speed, alt);
+ if (checkForCircularWaits(id)) {
+ i->setResolveCircularWait();
+ }
+ bool needsTaxiClearance = current->getAircraft()->getTaxiClearanceRequest();
+ int state = current->getState();
+ time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+ if ((now - lastTransmission) > 15) {
+ available = true;
+ }
+ if (needsTaxiClearance && available) {
+ transmit(&(*current), MSG_REQUEST_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
+ current->getAircraft()->setTaxiClearanceRequest(false);
+ current->setState(3);
+ lastTransmission = now;
+ available = false;
+ }
+ if ((state == 3) && available) {
+ transmit(&(*current), MSG_ISSUE_TAXI_CLEARANCE, ATC_GROUND_TO_AIR);
+ current->setState(4);
+ lastTransmission = now;
+ available = false;
+ }
+ if ((state == 4) && available) {
+ transmit(&(*current), MSG_ACKNOWLEDGE_TAXI_CLEARANCE, ATC_AIR_TO_GROUND);
+ current->setState(0);
+ lastTransmission = now;
+ available = false;
+ }
}
/**
not addressed yet, but should be.
*/
-void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
- double lon, double heading,
- double speed, double alt)
+void FGGroundNetwork::checkSpeedAdjustment(int id, double lat,
+ double lon, double heading,
+ double speed, double alt)
{
-
- TrafficVectorIterator current, closest;
- TrafficVectorIterator i = activeTraffic.begin();
- bool otherReasonToSlowDown = false;
- bool previousInstruction;
- if (activeTraffic.size())
- {
- //while ((i->getId() != id) && (i != activeTraffic.end()))
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- else
- {
- return;
- }
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkSpeedAdjustment");
- }
- current = i;
- //closest = current;
-
- previousInstruction = current->getSpeedAdjustment();
- double mindist = HUGE_VAL;
- if (activeTraffic.size())
- {
- double course, dist, bearing, minbearing, az2;
- SGGeod curr(SGGeod::fromDegM(lon, lat, alt));
- //TrafficVector iterator closest;
- closest = current;
- for (TrafficVectorIterator i = activeTraffic.begin();
- i != activeTraffic.end(); i++)
- {
- if (i == current) {
- continue;
- }
-
- SGGeod other(SGGeod::fromDegM(i->getLongitude(),
- i->getLatitude(), i->getAltitude()));
- SGGeodesy::inverse(curr, other, course, az2, dist);
- bearing = fabs(heading-course);
- if (bearing > 180)
- bearing = 360-bearing;
- if ((dist < mindist) && (bearing < 60.0))
- {
- mindist = dist;
- closest = i;
- minbearing = bearing;
- }
- }
- //Check traffic at the tower controller
- if (towerController->hasActiveTraffic())
- {
- for (TrafficVectorIterator i = towerController->getActiveTraffic().begin();
- i != towerController->getActiveTraffic().end(); i++)
- {
- //cerr << "Comparing " << current->getId() << " and " << i->getId() << endl;
- SGGeod other(SGGeod::fromDegM(i->getLongitude(),
- i->getLatitude(),
- i->getAltitude()));
- SGGeodesy::inverse(curr, other, course, az2, dist);
- bearing = fabs(heading-course);
- if (bearing > 180)
- bearing = 360-bearing;
- if ((dist < mindist) && (bearing < 60.0))
- {
- mindist = dist;
- closest = i;
- minbearing = bearing;
- otherReasonToSlowDown = true;
- }
- }
- }
- // Finally, check UserPosition
- double userLatitude = fgGetDouble("/position/latitude-deg");
- double userLongitude = fgGetDouble("/position/longitude-deg");
- SGGeod user(SGGeod::fromDeg(userLongitude,userLatitude));
- SGGeodesy::inverse(curr, user, course, az2, dist);
-
- bearing = fabs(heading-course);
- if (bearing > 180)
- bearing = 360-bearing;
- if ((dist < mindist) && (bearing < 60.0))
- {
- mindist = dist;
- //closest = i;
- minbearing = bearing;
- otherReasonToSlowDown = true;
- }
-
- current->clearSpeedAdjustment();
-
- if (current->checkPositionAndIntentions(*closest) || otherReasonToSlowDown)
- {
- double maxAllowableDistance = (1.1*current->getRadius()) + (1.1*closest->getRadius());
- if (mindist < 2*maxAllowableDistance)
- {
- if (current->getId() == closest->getWaitsForId())
- return;
- else
- current->setWaitsForId(closest->getId());
- if (closest->getId() != current->getId())
- current->setSpeedAdjustment(closest->getSpeed()* (mindist/100));
- else
- current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest
- if (mindist < maxAllowableDistance)
- {
- //double newSpeed = (maxAllowableDistance-mindist);
- //current->setSpeedAdjustment(newSpeed);
- //if (mindist < 0.5* maxAllowableDistance)
- // {
- current->setSpeedAdjustment(0);
- // }
- }
- }
- }
+
+ TrafficVectorIterator current, closest;
+ TrafficVectorIterator i = activeTraffic.begin();
+ bool otherReasonToSlowDown = false;
+ bool previousInstruction;
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && (i != activeTraffic.end()))
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ } else {
+ return;
+ }
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkSpeedAdjustment");
+ }
+ current = i;
+ //closest = current;
+
+ previousInstruction = current->getSpeedAdjustment();
+ double mindist = HUGE_VAL;
+ if (activeTraffic.size()) {
+ double course, dist, bearing, minbearing, az2;
+ SGGeod curr(SGGeod::fromDegM(lon, lat, alt));
+ //TrafficVector iterator closest;
+ closest = current;
+ for (TrafficVectorIterator i = activeTraffic.begin();
+ i != activeTraffic.end(); i++) {
+ if (i == current) {
+ continue;
+ }
+
+ SGGeod other(SGGeod::fromDegM(i->getLongitude(),
+ i->getLatitude(),
+ i->getAltitude()));
+ SGGeodesy::inverse(curr, other, course, az2, dist);
+ bearing = fabs(heading - course);
+ if (bearing > 180)
+ bearing = 360 - bearing;
+ if ((dist < mindist) && (bearing < 60.0)) {
+ mindist = dist;
+ closest = i;
+ minbearing = bearing;
+ }
+ }
+ //Check traffic at the tower controller
+ if (towerController->hasActiveTraffic()) {
+ for (TrafficVectorIterator i =
+ towerController->getActiveTraffic().begin();
+ i != towerController->getActiveTraffic().end(); i++) {
+ //cerr << "Comparing " << current->getId() << " and " << i->getId() << endl;
+ SGGeod other(SGGeod::fromDegM(i->getLongitude(),
+ i->getLatitude(),
+ i->getAltitude()));
+ SGGeodesy::inverse(curr, other, course, az2, dist);
+ bearing = fabs(heading - course);
+ if (bearing > 180)
+ bearing = 360 - bearing;
+ if ((dist < mindist) && (bearing < 60.0)) {
+ mindist = dist;
+ closest = i;
+ minbearing = bearing;
+ otherReasonToSlowDown = true;
+ }
+ }
+ }
+ // Finally, check UserPosition
+ double userLatitude = fgGetDouble("/position/latitude-deg");
+ double userLongitude = fgGetDouble("/position/longitude-deg");
+ SGGeod user(SGGeod::fromDeg(userLongitude, userLatitude));
+ SGGeodesy::inverse(curr, user, course, az2, dist);
+
+ bearing = fabs(heading - course);
+ if (bearing > 180)
+ bearing = 360 - bearing;
+ if ((dist < mindist) && (bearing < 60.0)) {
+ mindist = dist;
+ //closest = i;
+ minbearing = bearing;
+ otherReasonToSlowDown = true;
+ }
+
+ current->clearSpeedAdjustment();
+
+ if (current->checkPositionAndIntentions(*closest)
+ || otherReasonToSlowDown) {
+ double maxAllowableDistance =
+ (1.1 * current->getRadius()) +
+ (1.1 * closest->getRadius());
+ if (mindist < 2 * maxAllowableDistance) {
+ if (current->getId() == closest->getWaitsForId())
+ return;
+ else
+ current->setWaitsForId(closest->getId());
+ if (closest->getId() != current->getId())
+ current->setSpeedAdjustment(closest->getSpeed() *
+ (mindist / 100));
+ else
+ current->setSpeedAdjustment(0); // This can only happen when the user aircraft is the one closest
+ if (mindist < maxAllowableDistance) {
+ //double newSpeed = (maxAllowableDistance-mindist);
+ //current->setSpeedAdjustment(newSpeed);
+ //if (mindist < 0.5* maxAllowableDistance)
+ // {
+ current->setSpeedAdjustment(0);
+ // }
+ }
+ }
+ }
}
}
3) For crossing or merging taxiroutes.
*/
-void FGGroundNetwork::checkHoldPosition(int id, double lat,
- double lon, double heading,
- double speed, double alt)
+void FGGroundNetwork::checkHoldPosition(int id, double lat,
+ double lon, double heading,
+ double speed, double alt)
{
-
- TrafficVectorIterator current;
- TrafficVectorIterator i = activeTraffic.begin();
- if (activeTraffic.size())
- {
- //while ((i->getId() != id) && i != activeTraffic.end())
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- else
- {
- return ;
- }
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkHoldPosition");
- }
- current = i;
- current->setHoldPosition(false);
- SGGeod curr(SGGeod::fromDegM(lon, lat, alt));
-
- for (i = activeTraffic.begin();
- i != activeTraffic.end(); i++)
- {
- if (i->getId() != current->getId())
- {
- int node = current->crosses(this, *i);
- if (node != -1)
- {
- FGTaxiNode* taxiNode = findNode(node);
-
- // Determine whether it's save to continue or not.
- // If we have a crossing route, there are two possibilities:
- // 1) This is an interestion
- // 2) This is oncoming two-way traffic, using the same taxiway.
- //cerr << "Hold check 1 : " << id << " has common node " << node << endl;
-
- SGGeod other(SGGeod::fromDegM(i->getLongitude(), i->getLatitude(), i->getAltitude()));
- bool needsToWait;
- bool opposing;
- if (current->isOpposing(this, *i, node))
- {
- needsToWait = true;
- opposing = true;
- //cerr << "Hold check 2 : " << node << " has opposing segment " << endl;
- // issue a "Hold Position" as soon as we're close to the offending node
- // For now, I'm doing this as long as the other aircraft doesn't
- // have a hold instruction as soon as we're within a reasonable
- // distance from the offending node.
- // This may be a bit of a conservative estimate though, as it may
- // be well possible that both aircraft can both continue to taxi
- // without crashing into each other.
- }
- else
- {
- opposing = false;
- if (SGGeodesy::distanceM(other, taxiNode->getGeod()) > 200) // 2.0*i->getRadius())
- {
- needsToWait = false;
- //cerr << "Hold check 3 : " << id <<" Other aircraft approaching node is still far away. (" << dist << " nm). Can safely continue "
- // << endl;
- }
- else
- {
- needsToWait = true;
- //cerr << "Hold check 4: " << id << " Would need to wait for other aircraft : distance = " << dist << " meters" << endl;
- }
- }
-
- double dist = SGGeodesy::distanceM(curr, taxiNode->getGeod());
- if (!(i->hasHoldPosition()))
- {
-
- if ((dist < 200) && //2.5*current->getRadius()) &&
- (needsToWait) &&
- (i->onRoute(this, *current)) &&
- //((i->onRoute(this, *current)) || ((!(i->getSpeedAdjustment())))) &&
- (!(current->getId() == i->getWaitsForId())))
- //(!(i->getSpeedAdjustment()))) // &&
- //(!(current->getSpeedAdjustment())))
-
- {
- current->setHoldPosition(true);
- current->setWaitsForId(i->getId());
- //cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") "
- // << dist << " meters. Waiting for " << i->getCallSign();
- //if (opposing)
- //cerr <<" [opposing] " << endl;
- //else
- // cerr << "[non-opposing] " << endl;
- //if (i->hasSpeefAdjustment())
- // {
- // cerr << " (which in turn waits for ) " << i->
- }
- else
- {
- //cerr << "Hold check 6: " << id << " No need to hold yet: Distance to node : " << dist << " nm"<< endl;
- }
- }
- }
- }
+ TrafficVectorIterator current;
+ TrafficVectorIterator i = activeTraffic.begin();
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && i != activeTraffic.end())
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ } else {
+ return;
+ }
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkHoldPosition");
+ }
+ current = i;
+ bool origStatus = current->hasHoldPosition();
+ current->setHoldPosition(false);
+ SGGeod curr(SGGeod::fromDegM(lon, lat, alt));
+
+ for (i = activeTraffic.begin(); i != activeTraffic.end(); i++) {
+ if (i->getId() != current->getId()) {
+ int node = current->crosses(this, *i);
+ if (node != -1) {
+ FGTaxiNode *taxiNode = findNode(node);
+
+ // Determine whether it's save to continue or not.
+ // If we have a crossing route, there are two possibilities:
+ // 1) This is an interestion
+ // 2) This is oncoming two-way traffic, using the same taxiway.
+ //cerr << "Hold check 1 : " << id << " has common node " << node << endl;
+
+ SGGeod other(SGGeod::
+ fromDegM(i->getLongitude(), i->getLatitude(),
+ i->getAltitude()));
+ bool needsToWait;
+ bool opposing;
+ if (current->isOpposing(this, *i, node)) {
+ needsToWait = true;
+ opposing = true;
+ //cerr << "Hold check 2 : " << node << " has opposing segment " << endl;
+ // issue a "Hold Position" as soon as we're close to the offending node
+ // For now, I'm doing this as long as the other aircraft doesn't
+ // have a hold instruction as soon as we're within a reasonable
+ // distance from the offending node.
+ // This may be a bit of a conservative estimate though, as it may
+ // be well possible that both aircraft can both continue to taxi
+ // without crashing into each other.
+ } else {
+ opposing = false;
+ if (SGGeodesy::distanceM(other, taxiNode->getGeod()) > 200) // 2.0*i->getRadius())
+ {
+ needsToWait = false;
+ //cerr << "Hold check 3 : " << id <<" Other aircraft approaching node is still far away. (" << dist << " nm). Can safely continue "
+ // << endl;
+ } else {
+ needsToWait = true;
+ //cerr << "Hold check 4: " << id << " Would need to wait for other aircraft : distance = " << dist << " meters" << endl;
+ }
+ }
+
+ double dist =
+ SGGeodesy::distanceM(curr, taxiNode->getGeod());
+ if (!(i->hasHoldPosition())) {
+
+ if ((dist < 200) && //2.5*current->getRadius()) &&
+ (needsToWait) && (i->onRoute(this, *current)) &&
+ //((i->onRoute(this, *current)) || ((!(i->getSpeedAdjustment())))) &&
+ (!(current->getId() == i->getWaitsForId())))
+ //(!(i->getSpeedAdjustment()))) // &&
+ //(!(current->getSpeedAdjustment())))
+
+ {
+ current->setHoldPosition(true);
+ current->setWaitsForId(i->getId());
+ //cerr << "Hold check 5: " << current->getCallSign() <<" Setting Hold Position: distance to node (" << node << ") "
+ // << dist << " meters. Waiting for " << i->getCallSign();
+ //if (opposing)
+ //cerr <<" [opposing] " << endl;
+ //else
+ // cerr << "[non-opposing] " << endl;
+ //if (i->hasSpeefAdjustment())
+ // {
+ // cerr << " (which in turn waits for ) " << i->
+ } else {
+ //cerr << "Hold check 6: " << id << " No need to hold yet: Distance to node : " << dist << " nm"<< endl;
+ }
+ }
+ }
+ }
+ }
+ bool currStatus = current->hasHoldPosition();
+
+ // Either a Hold Position or a resume taxi transmission has been issued
+ time_t now = time(NULL) + fgGetLong("/sim/time/warp");
+ if ((now - lastTransmission) > 2) {
+ available = true;
+ }
+ if ((origStatus != currStatus) && available) {
+ //cerr << "Issueing hold short instrudtion " << currStatus << " " << available << endl;
+ if (currStatus == true) { // No has a hold short instruction
+ transmit(&(*current), MSG_HOLD_POSITION, ATC_GROUND_TO_AIR);
+ //cerr << "Transmittin hold short instrudtion " << currStatus << " " << available << endl;
+ current->setState(1);
+ } else {
+ transmit(&(*current), MSG_RESUME_TAXI, ATC_GROUND_TO_AIR);
+ //cerr << "Transmittig resume instrudtion " << currStatus << " " << available << endl;
+ current->setState(2);
+ }
+ lastTransmission = now;
+ available = false;
+ // Don't act on the changed instruction until the transmission is confirmed
+ // So set back to original status
+ current->setHoldPosition(origStatus);
+ //cerr << "Current state " << current->getState() << endl;
+ } else {
+ }
+ int state = current->getState();
+ if ((state == 1) && (available)) {
+ //cerr << "ACKNOWLEDGE HOLD" << endl;
+ transmit(&(*current), MSG_ACKNOWLEDGE_HOLD_POSITION, ATC_AIR_TO_GROUND);
+ current->setState(0);
+ current->setHoldPosition(true);
+ lastTransmission = now;
+ available = false;
+
+ }
+ if ((state == 2) && (available)) {
+ //cerr << "ACKNOWLEDGE RESUME" << endl;
+ transmit(&(*current), MSG_ACKNOWLEDGE_RESUME_TAXI, ATC_AIR_TO_GROUND);
+ current->setState(0);
+ current->setHoldPosition(false);
+ lastTransmission = now;
+ available = false;
}
}
*/
bool FGGroundNetwork::checkForCircularWaits(int id)
-{
- //cerr << "Performing Wait check " << id << endl;
- int target = 0;
- TrafficVectorIterator current, other;
- TrafficVectorIterator i = activeTraffic.begin();
- int trafficSize = activeTraffic.size();
- if (trafficSize) {
+{
+ //cerr << "Performing Wait check " << id << endl;
+ int target = 0;
+ TrafficVectorIterator current, other;
+ TrafficVectorIterator i = activeTraffic.begin();
+ int trafficSize = activeTraffic.size();
+ if (trafficSize) {
while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- else {
- return false;
- }
- if (i == activeTraffic.end() || (trafficSize == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkForCircularWaits");
- }
-
- current = i;
- target = current->getWaitsForId();
- //bool printed = false; // Note that this variable is for debugging purposes only.
- int counter = 0;
-
- if (id == target) {
- //cerr << "aircraft waits for user" << endl;
- return false;
- }
-
-
- while ((target > 0) && (target != id) && counter++ < trafficSize) {
- //printed = true;
- TrafficVectorIterator i = activeTraffic.begin();
- if (trafficSize) {
- //while ((i->getId() != id) && i != activeTraffic.end())
- while (i != activeTraffic.end()) {
- if (i->getId() == target) {
- break;
- }
- i++;
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
}
- }
- else {
+ } else {
return false;
- }
+ }
if (i == activeTraffic.end() || (trafficSize == 0)) {
- //cerr << "[Waiting for traffic at Runway: DONE] " << endl << endl;;
- // The target id is not found on the current network, which means it's at the tower
- //SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkForCircularWaits");
- return false;
- }
- other = i;
- target = other->getWaitsForId();
-
- // actually this trap isn't as impossible as it first seemed:
- // the setWaitsForID(id) is set to current when the aircraft
- // is waiting for the user controlled aircraft.
- //if (current->getId() == other->getId()) {
- // cerr << "Caught the impossible trap" << endl;
- // cerr << "Current = " << current->getId() << endl;
- // cerr << "Other = " << other ->getId() << endl;
- // for (TrafficVectorIterator at = activeTraffic.begin();
- // at != activeTraffic.end();
- // at++) {
- // cerr << "currently active aircraft : " << at->getCallSign() << " with Id " << at->getId() << " waits for " << at->getWaitsForId() << endl;
- // }
- // exit(1);
- if (current->getId() == other->getId())
- return false;
- //}
- //cerr << current->getCallSign() << " (" << current->getId() << ") " << " -> " << other->getCallSign()
- // << " (" << other->getId() << "); " << endl;;
- //current = other;
- }
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkForCircularWaits");
+ }
+
+ current = i;
+ target = current->getWaitsForId();
+ //bool printed = false; // Note that this variable is for debugging purposes only.
+ int counter = 0;
+
+ if (id == target) {
+ //cerr << "aircraft waits for user" << endl;
+ return false;
+ }
+
+
+ while ((target > 0) && (target != id) && counter++ < trafficSize) {
+ //printed = true;
+ TrafficVectorIterator i = activeTraffic.begin();
+ if (trafficSize) {
+ //while ((i->getId() != id) && i != activeTraffic.end())
+ while (i != activeTraffic.end()) {
+ if (i->getId() == target) {
+ break;
+ }
+ i++;
+ }
+ } else {
+ return false;
+ }
+ if (i == activeTraffic.end() || (trafficSize == 0)) {
+ //cerr << "[Waiting for traffic at Runway: DONE] " << endl << endl;;
+ // The target id is not found on the current network, which means it's at the tower
+ //SG_LOG(SG_GENERAL, SG_ALERT, "AI error: Trying to access non-existing aircraft in FGGroundNetwork::checkForCircularWaits");
+ return false;
+ }
+ other = i;
+ target = other->getWaitsForId();
+
+ // actually this trap isn't as impossible as it first seemed:
+ // the setWaitsForID(id) is set to current when the aircraft
+ // is waiting for the user controlled aircraft.
+ //if (current->getId() == other->getId()) {
+ // cerr << "Caught the impossible trap" << endl;
+ // cerr << "Current = " << current->getId() << endl;
+ // cerr << "Other = " << other ->getId() << endl;
+ // for (TrafficVectorIterator at = activeTraffic.begin();
+ // at != activeTraffic.end();
+ // at++) {
+ // cerr << "currently active aircraft : " << at->getCallSign() << " with Id " << at->getId() << " waits for " << at->getWaitsForId() << endl;
+ // }
+ // exit(1);
+ if (current->getId() == other->getId())
+ return false;
+ //}
+ //cerr << current->getCallSign() << " (" << current->getId() << ") " << " -> " << other->getCallSign()
+ // << " (" << other->getId() << "); " << endl;;
+ //current = other;
+ }
- //if (printed)
- // cerr << "[done] " << endl << endl;;
- if (id == target) {
- SG_LOG(SG_GENERAL, SG_WARN, "Detected circular wait condition: Id = " << id << "target = " << target);
- return true;
- } else {
- return false;
- }
+ //if (printed)
+ // cerr << "[done] " << endl << endl;;
+ if (id == target) {
+ SG_LOG(SG_GENERAL, SG_WARN,
+ "Detected circular wait condition: Id = " << id <<
+ "target = " << target);
+ return true;
+ } else {
+ return false;
+ }
}
// Note that this function is probably obsolete...
bool FGGroundNetwork::hasInstruction(int id)
{
TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
- if (activeTraffic.size())
- {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: checking ATC instruction for aircraft without traffic record");
- } else {
- return i->hasInstruction();
- }
- return false;
+ // Search search if the current id has an entry
+ // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ }
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: checking ATC instruction for aircraft without traffic record");
+ } else {
+ return i->hasInstruction();
+ }
+ return false;
}
FGATCInstruction FGGroundNetwork::getInstruction(int id)
{
- TrafficVectorIterator i = activeTraffic.begin();
- // Search search if the current id has an entry
- // This might be faster using a map instead of a vector, but let's start by taking a safe route
- if (activeTraffic.size()) {
- //while ((i->getId() != id) && i != activeTraffic.end()) {
- while (i != activeTraffic.end()) {
- if (i->getId() == id) {
- break;
- }
- i++;
- }
- }
- if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
- SG_LOG(SG_GENERAL, SG_ALERT, "AI error: requesting ATC instruction for aircraft without traffic record");
- } else {
- return i->getInstruction();
- }
- return FGATCInstruction();
+ TrafficVectorIterator i = activeTraffic.begin();
+ // Search search if the current id has an entry
+ // This might be faster using a map instead of a vector, but let's start by taking a safe route
+ if (activeTraffic.size()) {
+ //while ((i->getId() != id) && i != activeTraffic.end()) {
+ while (i != activeTraffic.end()) {
+ if (i->getId() == id) {
+ break;
+ }
+ i++;
+ }
+ }
+ if (i == activeTraffic.end() || (activeTraffic.size() == 0)) {
+ SG_LOG(SG_GENERAL, SG_ALERT,
+ "AI error: requesting ATC instruction for aircraft without traffic record");
+ } else {
+ return i->getInstruction();
+ }
+ return FGATCInstruction();
}
-
-
void init();
bool exists() { return hasNetwork; };
void setTowerController(FGTowerController *twrCtrlr) { towerController = twrCtrlr; };
-
+
int findNearestNode(double lat, double lon);
int findNearestNode(const SGGeod& aGeod);
-
+
FGTaxiNode *findNode(unsigned idx);
FGTaxiSegment *findSegment(unsigned idx);
FGTaxiRoute findShortestRoute(int start, int end, bool fullSearch=true);
validSelection = true;
for (int j = 0; j < activeRwys; j++)
{
- rwy = airport->getRunwayByIdent(rwyList[j].getRwyList(i));
+ string ident(rwyList[j].getRwyList(i));
+ if (!airport->hasRunwayWithIdent(ident)) {
+ SG_LOG(SG_GENERAL, SG_WARN, "no such runway:" << ident << " at " << airport->ident());
+ continue;
+ }
+
+ rwy = airport->getRunwayByIdent(ident);
//cerr << "Succes" << endl;
hdgDiff = fabs(windHeading - rwy->headingDeg());
using std::cout;
using std::endl;
+using simgear::PropertyList;
+
FGPeriodicalValue::FGPeriodicalValue( SGPropertyNode_ptr root )
{
SGPropertyNode_ptr minNode = root->getChild( "min" );
void FGXMLAutopilotGroup::init()
{
- vector<SGPropertyNode_ptr> autopilotNodes = fgGetNode( "/sim/systems", true )->getChildren("autopilot");
+ PropertyList autopilotNodes = fgGetNode( "/sim/systems", true )->getChildren("autopilot");
if( autopilotNodes.size() == 0 ) {
SG_LOG( SG_ALL, SG_WARN, "No autopilot configuration specified for this model!");
return;
}
- for( vector<SGPropertyNode_ptr>::size_type i = 0; i < autopilotNodes.size(); i++ ) {
+ for( PropertyList::size_type i = 0; i < autopilotNodes.size(); i++ ) {
SGPropertyNode_ptr pathNode = autopilotNodes[i]->getNode( "path" );
if( pathNode == NULL ) {
SG_LOG( SG_ALL, SG_WARN, "No autopilot configuration file specified for this autopilot!");
class FGXMLAutoComponent : public SGReferenced {
private:
- std::vector <SGPropertyNode_ptr> output_list;
+ simgear::PropertyList output_list;
SGSharedPtr<const SGCondition> _condition;
SGPropertyNode_ptr enable_prop;
// helpful for things like flight directors which position
// their vbars from the autopilot computations.
if ( honor_passive && passive_mode->getBoolValue() ) return;
- for( std::vector <SGPropertyNode_ptr>::iterator it = output_list.begin(); it != output_list.end(); ++it)
+ for( simgear::PropertyList::iterator it = output_list.begin();
+ it != output_list.end(); ++it)
(*it)->setDoubleValue( clamp( value ) );
}
// helpful for things like flight directors which position
// their vbars from the autopilot computations.
if ( honor_passive && passive_mode->getBoolValue() ) return;
- for( std::vector <SGPropertyNode_ptr>::iterator it = output_list.begin(); it != output_list.end(); ++it)
+ for( simgear::PropertyList::iterator it = output_list.begin();
+ it != output_list.end(); ++it)
(*it)->setBoolValue( value ); // don't use clamp here, bool is clamped anyway
}
wind_from_down_fps = 0;
thermal_lift_fps = 0;
ridge_lift_fps= 0;
+ local_weather_lift_fps=0;
altitude_half_to_sun_m = 1000;
altitude_tropo_top_m = 10000;
#ifdef USING_TABLES
wind_from_down_fps = env.wind_from_down_fps;
thermal_lift_fps = env.thermal_lift_fps;
ridge_lift_fps= env.ridge_lift_fps;
+ local_weather_lift_fps = env.local_weather_lift_fps;
turbulence_magnitude_norm = env.turbulence_magnitude_norm;
turbulence_rate_hz = env.turbulence_rate_hz;
}
maybe_copy_value(this, node, "turbulence/rate-hz",
&FGEnvironment::set_turbulence_rate_hz);
+
// calculate derived properties here to avoid duplicate expensive computations
_recalc_ne();
_recalc_alt_pt();
return ridge_lift_fps;
}
+double
+FGEnvironment::get_local_weather_lift_fps () const
+{
+ return local_weather_lift_fps;
+}
+
double
FGEnvironment::get_turbulence_magnitude_norm () const
{
ridge_lift_fps = ri;
if( live_update ) {
_recalc_updraft();
+ }
}
+
+void
+FGEnvironment::set_local_weather_lift_fps (double lwl)
+{
+ local_weather_lift_fps = lwl;
+ if( live_update ) {
+ _recalc_updraft();
+ }
}
void
void
FGEnvironment::_recalc_updraft ()
{
- wind_from_down_fps = thermal_lift_fps + ridge_lift_fps ;
+ wind_from_down_fps = thermal_lift_fps + ridge_lift_fps + local_weather_lift_fps ;
}
// Intended to help with the interpretation of METAR data,
virtual double get_wind_from_down_fps () const;
virtual double get_thermal_lift_fps () const;
virtual double get_ridge_lift_fps () const;
+ virtual double get_local_weather_lift_fps () const;
virtual double get_turbulence_magnitude_norm () const;
virtual double get_turbulence_rate_hz () const;
virtual void set_wind_from_down_fps (double d);
virtual void set_thermal_lift_fps (double th);
virtual void set_ridge_lift_fps (double ri);
+ virtual void set_local_weather_lift_fps (double lwl);
virtual void set_turbulence_magnitude_norm (double t);
virtual void set_turbulence_rate_hz (double t);
double wind_from_down_fps;
double thermal_lift_fps;
double ridge_lift_fps;
+ double local_weather_lift_fps;
bool live_update;
fgSetArchivable("/environment/thermal-lift-fps");
fgTie("/environment/ridge-lift-fps", _environment,
&FGEnvironment::get_ridge_lift_fps,
- &FGEnvironment::set_ridge_lift_fps);
+ &FGEnvironment::set_ridge_lift_fps);
fgSetArchivable("/environment/ridge-lift-fps");
-
+
+ fgTie("/environment/local-weather-lift", _environment,
+ &FGEnvironment::get_local_weather_lift_fps); //read-only
+
fgTie("/environment/turbulence/magnitude-norm", _environment,
&FGEnvironment::get_turbulence_magnitude_norm,
&FGEnvironment::set_turbulence_magnitude_norm);
fgUntie("/environment/thermal-lift-fps");
fgUntie("/environment/ridge-lift-fps");
+ fgUntie("/environment/local-weather-lift");
fgUntie("/environment/atmosphere/altitude-half-to-sun");
fgUntie("/environment/atmosphere/altitude-troposphere-top");
_environment->get_wind_from_east_fps(),
_environment->get_wind_from_down_fps());
_environment->set_elevation_ft(fgGetDouble("/position/altitude-ft"));
+ _environment->set_local_weather_lift_fps(fgGetDouble("/local-weather/current/thermal-lift"));
osg::Vec3 windVec(-_environment->get_wind_from_north_fps(),
-_environment->get_wind_from_east_fps(),
_environment->get_wind_from_down_fps());
#define NOMINMAX 1
+#define HAVE_CULLSETTINGS_CLEAR_MASK 1
+
#ifndef ENABLE_AUDIO_SUPPORT
#define ENABLE_AUDIO_SUPPORT
#endif
#include <simgear/math/SGMath.hxx>
+using simgear::PropertyList;
+
void FGCommonInput::read_bindings (const SGPropertyNode * node, binding_list_t * binding_list, int modifiers, const string & module )
{
SG_LOG(SG_INPUT, SG_DEBUG, "Reading all bindings");
- vector<SGPropertyNode_ptr> bindings = node->getChildren("binding");
+ PropertyList bindings = node->getChildren("binding");
static string nasal = "nasal";
for (unsigned int i = 0; i < bindings.size(); i++) {
const char *cmd = bindings[i]->getStringValue("command");
#include <simgear/props/props_io.hxx>
#include <Main/globals.hxx>
+using simgear::PropertyList;
+
FGDeviceConfigurationMap::FGDeviceConfigurationMap( const char * relative_path, SGPropertyNode_ptr aBase, const char * aChildname ) :
base(aBase),
childname(aChildname)
int index = 1000;
scan_dir( path, &index);
- vector<SGPropertyNode_ptr> childNodes = base->getChildren(childname);
+ PropertyList childNodes = base->getChildren(childname);
for (int k = (int)childNodes.size() - 1; k >= 0; k--) {
SGPropertyNode *n = childNodes[k];
- vector<SGPropertyNode_ptr> names = n->getChildren("name");
+ PropertyList names = n->getChildren("name");
if (names.size() ) // && (n->getChildren("axis").size() || n->getChildren("button").size()))
for (unsigned int j = 0; j < names.size(); j++)
(*this)[names[j]->getStringValue()] = n;
#include <simgear/io/sg_file.hxx>
#include <Scripting/NasalSys.hxx>
+using simgear::PropertyList;
+
FGEventSetting::FGEventSetting( SGPropertyNode_ptr base ) :
value(0.0)
{
read_bindings( node, bindings, KEYMOD_NONE, device->GetNasalModule() );
- vector<SGPropertyNode_ptr> settingNodes = node->getChildren("setting");
- for( vector<SGPropertyNode_ptr>::iterator it = settingNodes.begin(); it != settingNodes.end(); it++ )
+ PropertyList settingNodes = node->getChildren("setting");
+ for( PropertyList::iterator it = settingNodes.begin(); it != settingNodes.end(); it++ )
settings.push_back( new FGEventSetting( *it ) );
}
nasalModule = string("__event:") + GetName();
- vector<SGPropertyNode_ptr> eventNodes = deviceNode->getChildren( "event" );
- for( vector<SGPropertyNode_ptr>::iterator it = eventNodes.begin(); it != eventNodes.end(); it++ )
+ PropertyList eventNodes = deviceNode->getChildren( "event" );
+ for( PropertyList::iterator it = eventNodes.begin(); it != eventNodes.end(); it++ )
AddHandledEvent( FGInputEvent::NewObject( this, *it ) );
debugEvents = deviceNode->getBoolValue("debug-events", debugEvents );
#include <Main/fg_props.hxx>
#include <Scripting/NasalSys.hxx>
+using simgear::PropertyList;
+
FGJoystickInput::axis::axis ()
: last_value(9999999),
tolerance(0.002),
string module = str.str();
nasalsys->createModule(module.c_str(), module.c_str(), "", 0);
- vector<SGPropertyNode_ptr> nasal = js_node->getChildren("nasal");
+ PropertyList nasal = js_node->getChildren("nasal");
unsigned int j;
for (j = 0; j < nasal.size(); j++) {
nasal[j]->setStringValue("module", module.c_str());
//
// Initialize the axes.
//
- vector<SGPropertyNode_ptr> axes = js_node->getChildren("axis");
+ PropertyList axes = js_node->getChildren("axis");
size_t nb_axes = axes.size();
for (j = 0; j < nb_axes; j++ ) {
const SGPropertyNode * axis_node = axes[j];
//
// Initialize the buttons.
//
- vector<SGPropertyNode_ptr> buttons = js_node->getChildren("button");
+ PropertyList buttons = js_node->getChildren("button");
char buf[32];
for (j = 0; j < buttons.size() && j < nbuttons; j++) {
const SGPropertyNode * button_node = buttons[j];
#include <Scripting/NasalSys.hxx>
#include <plib/pu.h>
+using simgear::PropertyList;
+
static int getModifiers ()
{
return fgGetKeyModifiers() >> 1;
}
FGNasalSys *nasalsys = (FGNasalSys *)globals->get_subsystem("nasal");
- vector<SGPropertyNode_ptr> nasal = key_nodes->getChildren("nasal");
+ PropertyList nasal = key_nodes->getChildren("nasal");
for (unsigned int j = 0; j < nasal.size(); j++) {
nasal[j]->setStringValue("module", module.c_str());
nasalsys->handleCommand(nasal[j]);
}
- vector<SGPropertyNode_ptr> keys = key_nodes->getChildren("key");
+ PropertyList keys = key_nodes->getChildren("key");
for (unsigned int i = 0; i < keys.size(); i++) {
int index = keys[i]->getIndex();
SG_LOG(SG_INPUT, SG_DEBUG, "Binding key " << index);
#include "jsinput.h"
+using simgear::PropertyList;
bool confirmAnswer() {
char answer;
cout << e.getFormattedMessage ();
}
- vector<SGPropertyNode_ptr> axes = templatetree->getChildren("axis");
- for(vector<SGPropertyNode_ptr>::iterator iter = axes.begin(); iter != axes.end(); iter++) {
+ PropertyList axes = templatetree->getChildren("axis");
+ for(PropertyList::iterator iter = axes.begin(); iter != axes.end(); iter++) {
cout << "Move the control you wish to use for " << (*iter)->getStringValue("desc")
<< " " << (*iter)->getStringValue("direction") << endl;
cout << "Pressing a button skips this axis" << endl;
cout << endl;
}
- vector<SGPropertyNode_ptr> buttons = templatetree->getChildren("button");
- for(vector<SGPropertyNode_ptr>::iterator iter = buttons.begin(); iter != buttons.end(); iter++) {
+ PropertyList buttons = templatetree->getChildren("button");
+ for(PropertyList::iterator iter = buttons.begin(); iter != buttons.end(); iter++) {
cout << "Press the button you wish to use for " << (*iter)->getStringValue("desc") << endl;
cout << "Moving a joystick axis skips this button" << endl;
fflush( stdout );
#include "airspeed_indicator.hxx"
#include <Main/fg_props.hxx>
#include <Main/util.hxx>
+#include <Environment/environment_mgr.hxx>
+#include <Environment/environment.hxx>
// A higher number means more responsive.
_name(node->getStringValue("name", "airspeed-indicator")),
_num(node->getIntValue("number", 0)),
_total_pressure(node->getStringValue("total-pressure", "/systems/pitot/total-pressure-inhg")),
- _static_pressure(node->getStringValue("static-pressure", "/systems/static/pressure-inhg"))
+ _static_pressure(node->getStringValue("static-pressure", "/systems/static/pressure-inhg")),
+ _has_overspeed(node->getBoolValue("has-overspeed-indicator",false)),
+ _pressure_alt_source(node->getStringValue("pressure-alt-source", "/instrumentation/altimeter/pressure-alt-ft")),
+ _ias_limit(node->getDoubleValue("ias-limit", 248.0)),
+ _mach_limit(node->getDoubleValue("mach-limit", 0.48)),
+ _alt_threshold(node->getDoubleValue("alt-threshold", 13200))
{
+ _environmentManager = NULL;
}
AirspeedIndicator::~AirspeedIndicator ()
_static_pressure_node = fgGetNode(_static_pressure.c_str(), true);
_density_node = fgGetNode("/environment/density-slugft3", true);
_speed_node = node->getChild("indicated-speed-kt", 0, true);
+ _tas_node = node->getChild("true-speed-kt", 0, true);
+ _mach_node = node->getChild("indicated-mach", 0, true);
+
+ // overspeed-indicator properties
+ if (_has_overspeed) {
+ _ias_limit_node = node->getNode("ias-limit",0, true);
+ _mach_limit_node = node->getNode("mach-limit",0, true);
+ _alt_threshold_node = node->getNode("alt-threshold",0, true);
+
+ if (!_ias_limit_node->hasValue()) {
+ _ias_limit_node->setDoubleValue(_ias_limit);
+ }
+
+ if (!_mach_limit_node->hasValue()) {
+ _mach_limit_node->setDoubleValue(_mach_limit);
+ }
+
+ if (!_alt_threshold_node->hasValue()) {
+ _alt_threshold_node->setDoubleValue(_alt_threshold);
+ }
+
+ _airspeed_limit = node->getChild("airspeed-limit-kt", 0, true);
+ _pressure_alt = fgGetNode(_pressure_alt_source.c_str(), true);
+ }
+
+ _environmentManager = (FGEnvironmentMgr*) globals->get_subsystem("environment");
}
#ifndef FPSTOKTS
void
AirspeedIndicator::update (double dt)
{
- if (_serviceable_node->getBoolValue()) {
- double pt = _total_pressure_node->getDoubleValue() * INHGTOPSF;
- double p = _static_pressure_node->getDoubleValue() * INHGTOPSF;
- double r = _density_node->getDoubleValue();
- double q = ( pt - p ); // dynamic pressure
-
- // Now, reverse the equation (normalize dynamic pressure to
- // avoid "nan" results from sqrt)
- if ( q < 0 ) { q = 0.0; }
- double v_fps = sqrt((2 * q) / r);
-
- // Publish the indicated airspeed
- double last_speed_kt = _speed_node->getDoubleValue();
- double current_speed_kt = v_fps * FPSTOKTS;
- _speed_node->setDoubleValue(fgGetLowPass(last_speed_kt,
- current_speed_kt,
- dt * RESPONSIVENESS));
+ if (!_serviceable_node->getBoolValue()) {
+ return;
+ }
+
+ double pt = _total_pressure_node->getDoubleValue() * INHGTOPSF;
+ double p = _static_pressure_node->getDoubleValue() * INHGTOPSF;
+ double r = _density_node->getDoubleValue();
+ double q = ( pt - p ); // dynamic pressure
+
+ // Now, reverse the equation (normalize dynamic pressure to
+ // avoid "nan" results from sqrt)
+ if ( q < 0 ) { q = 0.0; }
+ double v_fps = sqrt((2 * q) / r);
+
+ // Publish the indicated airspeed
+ double last_speed_kt = _speed_node->getDoubleValue();
+ double current_speed_kt = v_fps * FPSTOKTS;
+ double filtered_speed = fgGetLowPass(last_speed_kt,
+ current_speed_kt,
+ dt * RESPONSIVENESS);
+ _speed_node->setDoubleValue(filtered_speed);
+ computeMach(filtered_speed);
+
+ if (!_has_overspeed) {
+ return;
+ }
+
+ double lmt = _ias_limit_node->getDoubleValue();
+ if (_pressure_alt->getDoubleValue() > _alt_threshold_node->getDoubleValue()) {
+ double mmo = _mach_limit_node->getDoubleValue();
+ lmt = (filtered_speed/_mach_node->getDoubleValue())* mmo;
}
+
+ _airspeed_limit->setDoubleValue(lmt);
+}
+
+void
+AirspeedIndicator::computeMach(double ias)
+{
+ if (!_environmentManager) {
+ return;
+ }
+
+ FGEnvironment env(_environmentManager->getEnvironment());
+
+ // derived from http://williams.best.vwh.net/avform.htm#Mach
+ // names here are picked to be consistent with those formulae!
+
+ double oatK = env.get_temperature_degc() + 273.15; // OAT in Kelvin
+ double CS = 38.967854 * sqrt(oatK); // speed-of-sound in knots at altitude
+ double CS_0 = 661.4786; // speed-of-sound in knots at sea-level
+ double P_0 = env.get_pressure_sea_level_inhg();
+ double P = _static_pressure_node->getDoubleValue();
+
+ double DP = P_0 * (pow(1 + 0.2*pow(ias/CS_0, 2), 3.5) - 1);
+ double mach = pow(5 * ( pow(DP/P + 1, 2.0/7.0) -1) , 0.5);
+
+ // publish Mach and TAS
+ _mach_node->setDoubleValue(mach);
+ _tas_node->setDoubleValue(CS * mach);
}
// end of airspeed_indicator.cxx
#include <simgear/props/props.hxx>
#include <simgear/structure/subsystem_mgr.hxx>
+// forward decls
+class FGEnvironmentMgr;
/**
* Model an airspeed indicator tied to the pitot and static ports.
virtual void update (double dt);
private:
+ void computeMach(double ias);
string _name;
unsigned int _num;
string _total_pressure;
string _static_pressure;
+ bool _has_overspeed;
+ string _pressure_alt_source;
+ double _ias_limit;
+ double _mach_limit;
+ double _alt_threshold;
+
+ SGPropertyNode_ptr _ias_limit_node;
+ SGPropertyNode_ptr _mach_limit_node;
+ SGPropertyNode_ptr _alt_threshold_node;
SGPropertyNode_ptr _serviceable_node;
SGPropertyNode_ptr _total_pressure_node;
SGPropertyNode_ptr _static_pressure_node;
SGPropertyNode_ptr _density_node;
SGPropertyNode_ptr _speed_node;
+ SGPropertyNode_ptr _airspeed_limit;
+ SGPropertyNode_ptr _pressure_alt;
+ SGPropertyNode_ptr _mach_node;
+ SGPropertyNode_ptr _tas_node;
+ FGEnvironmentMgr* _environmentManager;
};
#endif // __INSTRUMENTS_AIRSPEED_INDICATOR_HXX
_time_before_search_sec = 0;
_last_frequency_mhz = frequency_mhz;
}
+ _frequency_node->setDoubleValue(frequency_mhz);
// Get the aircraft position
double longitude_rad =
camera->setProjectionMatrix(projectionMatrix);
camera->setCullMask(camera->getCullMask()
| simgear::BACKGROUND_BIT);
- camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
farCamera->setNodeMask(0);
} else {
Matrix nearProj, farProj;
* boundary and aloft environment layers.
*/
static bool
-do_set_sea_level_degc (const SGPropertyNode * arg)
+do_set_sea_level_degc ( double temp_sea_level_degc)
{
- double temp_sea_level_degc = arg->getDoubleValue("temp-degc", 15.0);
-
SGPropertyNode *node, *child;
// boundary layers
return true;
}
+static bool
+do_set_sea_level_degc (const SGPropertyNode * arg)
+{
+ return do_set_sea_level_degc( arg->getDoubleValue("temp-degc", 15.0) );
+}
+
/**
* Set the outside air temperature at the "current" altitude by first
static bool
do_set_oat_degc (const SGPropertyNode * arg)
{
- const string &temp_str = arg->getStringValue("temp-degc", "15.0");
-
+ double oat_degc = arg->getDoubleValue("temp-degc", 15.0);
// check for an altitude specified in the arguments, otherwise use
// current aircraft altitude.
const SGPropertyNode *altitude_ft = arg->getChild("altitude-ft");
FGEnvironment dummy; // instantiate a dummy so we can leech a method
dummy.set_elevation_ft( altitude_ft->getDoubleValue() );
- dummy.set_temperature_degc( atof( temp_str.c_str() ) );
- double temp_sea_level_degc = dummy.get_temperature_sea_level_degc();
-
- //cout << "Altitude = " << altitude_ft->getDoubleValue() << endl;
- //cout << "Temp at alt (C) = " << atof( temp_str.c_str() ) << endl;
- //cout << "Temp sea level (C) = " << temp_sea_level_degc << endl;
-
- SGPropertyNode *node, *child;
-
- // boundary layers
- node = fgGetNode( "/environment/config/boundary" );
- if ( node != NULL ) {
- int i = 0;
- while ( ( child = node->getNode( "entry", i ) ) != NULL ) {
- child->setDoubleValue( "temperature-sea-level-degc",
- temp_sea_level_degc );
- ++i;
- }
- }
-
- // aloft layers
- node = fgGetNode( "/environment/config/aloft" );
- if ( node != NULL ) {
- int i = 0;
- while ( ( child = node->getNode( "entry", i ) ) != NULL ) {
- child->setDoubleValue( "temperature-sea-level-degc",
- temp_sea_level_degc );
- ++i;
- }
- }
-
- return true;
+ dummy.set_temperature_degc( oat_degc );
+ return do_set_sea_level_degc( dummy.get_temperature_sea_level_degc());
}
/**
* boundary and aloft environment layers.
*/
static bool
-do_set_dewpoint_sea_level_degc (const SGPropertyNode * arg)
+do_set_dewpoint_sea_level_degc (double dewpoint_sea_level_degc)
{
- double dewpoint_sea_level_degc = arg->getDoubleValue("dewpoint-degc", 5.0);
SGPropertyNode *node, *child;
return true;
}
+static bool
+do_set_dewpoint_sea_level_degc (const SGPropertyNode * arg)
+{
+ return do_set_dewpoint_sea_level_degc(arg->getDoubleValue("dewpoint-degc", 5.0));
+}
/**
* Set the outside air dewpoint at the "current" altitude by first
static bool
do_set_dewpoint_degc (const SGPropertyNode * arg)
{
- const string &dewpoint_str = arg->getStringValue("dewpoint-degc", "5.0");
+ double dewpoint_degc = arg->getDoubleValue("dewpoint-degc", 5.0);
// check for an altitude specified in the arguments, otherwise use
// current aircraft altitude.
FGEnvironment dummy; // instantiate a dummy so we can leech a method
dummy.set_elevation_ft( altitude_ft->getDoubleValue() );
- dummy.set_dewpoint_degc( atof( dewpoint_str.c_str() ) );
- double dewpoint_sea_level_degc = dummy.get_dewpoint_sea_level_degc();
-
- //cout << "Altitude = " << altitude_ft->getDoubleValue() << endl;
- //cout << "Dewpoint at alt (C) = " << atof( dewpoint_str.c_str() ) << endl;
- //cout << "Dewpoint at sea level (C) = " << dewpoint_sea_level_degc << endl;
-
- SGPropertyNode *node, *child;
-
- // boundary layers
- node = fgGetNode( "/environment/config/boundary" );
- if ( node != NULL ) {
- int i = 0;
- while ( ( child = node->getNode( "entry", i ) ) != NULL ) {
- child->setDoubleValue( "dewpoint-sea-level-degc",
- dewpoint_sea_level_degc );
- ++i;
- }
- }
-
- // aloft layers
- node = fgGetNode( "/environment/config/aloft" );
- if ( node != NULL ) {
- int i = 0;
- while ( ( child = node->getNode( "entry", i ) ) != NULL ) {
- child->setDoubleValue( "dewpoint-sea-level-degc",
- dewpoint_sea_level_degc );
- ++i;
- }
- }
-
- return true;
+ dummy.set_dewpoint_degc( dewpoint_degc );
+ return do_set_dewpoint_sea_level_degc(dummy.get_dewpoint_sea_level_degc());
}
/**
// is processing the scenery (doubled the frame-rate for me) -EMH-
#ifdef ENABLE_AUDIO_SUPPORT
static bool smgr_init = true;
+ static SGPropertyNode *sound_working = fgGetNode("/sim/sound/working");
if (smgr_init == true) {
- static SGPropertyNode *sound_working = fgGetNode("/sim/sound/working");
if (sound_working->getBoolValue() == true) {
fgInitSoundManager();
smgr_init = false;
static SGSoundMgr *smgr = globals->get_soundmgr();
static bool smgr_enabled = true;
+ if (sound_working->getBoolValue() == false) { // request to reinit
+ smgr->reinit();
+ smgr->resume();
+ sound_working->setBoolValue(true);
+ }
+
if (smgr_enabled != sound_enabled->getBoolValue()) {
if (smgr_enabled == true) { // request to suspend
smgr->suspend();
_roll_deg(0),
_pitch_deg(0),
_heading_deg(0),
- _damp_sync(0),
- _damp_roll(0),
- _damp_pitch(0),
- _damp_heading(0),
_scaling_type(FG_SCALING_MAX),
_aspect_ratio(0),
_cameraGroup(CameraGroup::getDefault())
_internal = internal;
+ _dampFactor = SGVec3d::zeros();
+ _dampOutput = SGVec3d::zeros();
+ _dampTarget = SGVec3d::zeros();
+
if (damp_roll > 0.0)
- _damp_roll = 1.0 / pow(10.0, fabs(damp_roll));
+ _dampFactor[0] = 1.0 / pow(10.0, fabs(damp_roll));
if (damp_pitch > 0.0)
- _damp_pitch = 1.0 / pow(10.0, fabs(damp_pitch));
+ _dampFactor[1] = 1.0 / pow(10.0, fabs(damp_pitch));
if (damp_heading > 0.0)
- _damp_heading = 1.0 / pow(10.0, fabs(damp_heading));
+ _dampFactor[2] = 1.0 / pow(10.0, fabs(damp_heading));
_offset_m.x() = x_offset_m;
_offset_m.y() = y_offset_m;
double roll = _roll_deg;
if ( !_from_model ) {
// update from our own data...
- dampEyeData(roll, pitch, head);
+ setDampTarget(roll, pitch, head);
+ getDampOutput(roll, pitch, head);
}
// The rotation rotating from the earth centerd frame to
_target_roll_deg = placement->getRollDeg();
} else {
// if not model then calculate our own target position...
- dampEyeData(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
-
+ setDampTarget(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
+ getDampOutput(_target_roll_deg, _target_pitch_deg, _target_heading_deg);
}
SGQuatd geodTargetOr = SGQuatd::fromYawPitchRollDeg(_target_heading_deg,
- _target_pitch_deg,
- _target_roll_deg);
+ _target_pitch_deg,
+ _target_roll_deg);
SGQuatd geodTargetHlOr = SGQuatd::fromLonLat(_target);
_roll_deg = placement->getRollDeg();
} else {
// update from our own data, just the rotation here...
- dampEyeData(_roll_deg, _pitch_deg, _heading_deg);
+ setDampTarget(_roll_deg, _pitch_deg, _heading_deg);
+ getDampOutput(_roll_deg, _pitch_deg, _heading_deg);
}
- SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg,
- _pitch_deg,
- _roll_deg);
+ SGQuatd geodEyeOr = SGQuatd::fromYawPitchRollDeg(_heading_deg, _pitch_deg, _roll_deg);
SGQuatd geodEyeHlOr = SGQuatd::fromLonLat(_position);
// the rotation offset, don't know why heading is negative here ...
}
void
-FGViewer::dampEyeData(double &roll_deg, double &pitch_deg, double &heading_deg)
+FGViewer::setDampTarget(double roll, double pitch, double heading)
{
- const double interval = 0.01;
+ _dampTarget = SGVec3d(roll, pitch, heading);
+}
+
+void
+FGViewer::getDampOutput(double& roll, double& pitch, double& heading)
+{
+ roll = _dampOutput[0];
+ pitch = _dampOutput[1];
+ heading = _dampOutput[2];
+}
+
+void
+FGViewer::updateDampOutput(double dt)
+{
static FGViewer *last_view = 0;
- if (last_view != this) {
- _damp_sync = 0.0;
- _damped_roll_deg = roll_deg;
- _damped_pitch_deg = pitch_deg;
- _damped_heading_deg = heading_deg;
+ if ((last_view != this) || (dt > 1.0)) {
+ _dampOutput = _dampTarget;
last_view = this;
return;
}
-
- if (_damp_sync < interval) {
- if (_damp_roll > 0.0)
- roll_deg = _damped_roll_deg;
- if (_damp_pitch > 0.0)
- pitch_deg = _damped_pitch_deg;
- if (_damp_heading > 0.0)
- heading_deg = _damped_heading_deg;
- return;
- }
-
- while (_damp_sync >= interval) {
- _damp_sync -= interval;
-
- double d;
- if (_damp_roll > 0.0) {
- d = _damped_roll_deg - roll_deg;
- if (d >= 180.0)
- _damped_roll_deg -= 360.0;
- else if (d < -180.0)
- _damped_roll_deg += 360.0;
- roll_deg = _damped_roll_deg = roll_deg * _damp_roll + _damped_roll_deg * (1 - _damp_roll);
- }
-
- if (_damp_pitch > 0.0) {
- d = _damped_pitch_deg - pitch_deg;
- if (d >= 180.0)
- _damped_pitch_deg -= 360.0;
- else if (d < -180.0)
- _damped_pitch_deg += 360.0;
- pitch_deg = _damped_pitch_deg = pitch_deg * _damp_pitch + _damped_pitch_deg * (1 - _damp_pitch);
- }
-
- if (_damp_heading > 0.0) {
- d = _damped_heading_deg - heading_deg;
- if (d >= 180.0)
- _damped_heading_deg -= 360.0;
- else if (d < -180.0)
- _damped_heading_deg += 360.0;
- heading_deg = _damped_heading_deg = heading_deg * _damp_heading + _damped_heading_deg * (1 - _damp_heading);
- }
- }
+
+ const double interval = 0.01;
+ while (dt > interval) {
+
+ for (unsigned int i=0; i<3; ++i) {
+ if (_dampFactor[i] <= 0.0) {
+ // axis is un-damped, set output to target directly
+ _dampOutput[i] = _dampTarget[i];
+ continue;
+ }
+
+ double d = _dampOutput[i] - _dampTarget[i];
+ if (d > 180.0) {
+ _dampOutput[i] -= 360.0;
+ } else if (d < -180.0) {
+ _dampOutput[i] += 360.0;
+ }
+
+ _dampOutput[i] = (_dampTarget[i] * _dampFactor[i]) +
+ (_dampOutput[i] * (1.0 - _dampFactor[i]));
+ } // of axis iteration
+
+ dt -= interval;
+ } // of dt subdivision by interval
}
double
void
FGViewer::update (double dt)
{
- _damp_sync += dt;
-
+ updateDampOutput(dt);
+
int i;
int dt_ms = int(dt * 1000);
for ( i = 0; i < dt_ms; i++ ) {
double _target_pitch_deg;
double _target_heading_deg;
- double _damp_sync;
- double _damp_roll;
- double _damp_pitch;
- double _damp_heading;
-
- double _damped_roll_deg;
- double _damped_pitch_deg;
- double _damped_heading_deg;
-
+ SGVec3d _dampTarget; ///< current target value we are damping towards
+ SGVec3d _dampOutput; ///< current output of damping filter
+ SGVec3d _dampFactor; ///< weighting of the damping filter
+
// Position offsets from FDM origin. The X axis is positive
// out the tail, Y is out the right wing, and Z is positive up.
// distance in meters
void recalc ();
void recalcLookFrom();
void recalcLookAt();
- void dampEyeData(double &roll_deg, double &pitch_deg, double &heading_deg);
+ void setDampTarget(double h, double p, double r);
+ void getDampOutput(double& roll, double& pitch, double& heading);
+
+ void updateDampOutput(double dt);
+
// add to _heading_offset_deg
inline void incHeadingOffset_deg( double amt ) {
set_dirty();
{1100, "sim/model/variant", simgear::props::INT},
{1101, "sim/model/livery/file", simgear::props::STRING},
+ {1200, "environment/wildfire/data", simgear::props::STRING},
+
{10001, "sim/multiplay/transmission-freq-hz", simgear::props::STRING},
{10002, "sim/multiplay/chat", simgear::props::STRING},
#include <simgear/debug/logstream.hxx>
#include <simgear/io/iochannel.hxx>
+#include <simgear/misc/stdint.hxx>
#include <Aircraft/aircraft.hxx>
#include <Main/fg_props.hxx>
if ( io->get_type() == sgFileType ) {
if ( io->read( (char *)(& buf), length ) == length ) {
SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
- long int *msg;
- msg = (long int *)buf;
+ int32_t *msg = (int32_t *)buf;
for( int i = 0; i < 4; ++i )
{
axis[i] = ((double)msg[i] / 2147483647.0);
} else {
while ( io->read( (char *)(& buf), length ) == length ) {
SG_LOG( SG_IO, SG_DEBUG, "Success reading data." );
- long int *msg;
- msg = (long int *)buf;
+ int32_t *msg = (int32_t *)buf;
SG_LOG( SG_IO, SG_DEBUG, "ax0 = " << msg[0] << " ax1 = "
<< msg[1] << "ax2 = " << msg[2] << "ax3 = " << msg[3]);
for( int i = 0; i < 4; ++i )
if (firstRun) {
if (fgGetBool("/sim/traffic-manager/instantaneous-action") == true) {
- deptime = now + rand() % 300; // Wait up to 5 minutes until traffic starts moving to prevent too many aircraft
+ deptime = now; // + rand() % 300; // Wait up to 5 minutes until traffic starts moving to prevent too many aircraft
// from cluttering the gate areas.
}
firstRun = false;
}
FGScheduledFlight* flight = flights.front();
- if (!deptime)
+ if (!deptime) {
deptime = flight->getDepartureTime();
+ //cerr << "Settiing departure time " << deptime << endl;
+ }
if (AIManagerRef) {
// Check if this aircraft has been released.
}
sz = strlen(opt);
- if (!strncmp(opt, "-help", sz)) {
- printf("usage:\n normalmap [-c=contrast] [-b=brightness]");
- printf(" --t=file [--o=file]\n");
- exit(0);
- }
if (!strncmp(opt, "-contrast", sz)) {
contrast = atof(arg);
return ret;
normalmap_file = strdup(arg);
return ret;
}
+ if (!strncmp(opt, "-help", sz)) {
+ printf("usage:\n normalmap [-c=contrast] [-b=brightness]");
+ printf(" --i=file [--o=file]\n\n");
+ exit(0);
+ }
return 1;
}
if ( !texture_file )
{
- printf("Error: texture file not specified\n");
+ printf("Error: texture file not specified.\n");
+ printf("usage:\n normalmap [-c=contrast] [-b=brightness]");
+ printf(" --i=file [--o=file]\n\n");
return -1;
}
if ( !texture.texture() )
{
printf("Error: unable to process input file: %s\n", texture_file);
- printf(" (%s)\n", texture.err_str());
+ printf(" (%s)\n\n", texture.err_str());
return -2;
}
int yp1 = (y < (texture_height-1)) ? y+1 : 0;
int posxp1 = (xp1 + ytw)*num_colors;
int posyp1 = (x + yp1*texture_width)*num_colors;
+ float fx,fy;
GLubyte c = texture_data[dpos];
GLubyte cx1 = texture_data[posxp1];
map[mpos+3] = a;
}
- map[mpos+0] = (128+(cx1-c)/2);
- map[mpos+1] = (128+(cy1-c)/2);
+ fx = asin((c/256.0-cx1/256.0))/1.57079633;
+ fy = asin((cy1/256.0-c/256.0))/1.57079633;
+
+ map[mpos+0] = (GLuint)(fx*256.0)-128;
+ map[mpos+1] = (GLuint)(fy*256.0)-128;
map[mpos+2] = 127+int(brightness*128); // 255-c/2;
mpos += colors;
#ifdef __MINGW32__
#include <time.h>
#include <unistd.h>
+#elif defined(_MSC_VER)
+#include <io.h>
#endif
#include <stdlib.h> // atoi() atof() abs() system()
+#include <signal.h> // signal()
#include <simgear/compiler.h>
}
-std::deque<std::string> waitingTiles;
-typedef std::map<std::string,time_t> CompletedTiles;
+deque<string> waitingTiles;
+typedef map<string,time_t> CompletedTiles;
CompletedTiles completedTiles;
+netSocket theSocket;
#ifdef HAVE_SVN_CLIENT_H
}
}
+#ifdef _MSC_VER
+typedef void (__cdecl * sighandler_t)(int);
+#elif defined( __APPLE__ )
+typedef sig_t sighandler_t;
+#endif
+
+bool terminating = false;
+sighandler_t prior_signal_handlers[32];
+int termination_triggering_signals[] = {
+#ifndef _MSC_VER
+ SIGHUP, SIGINT, SIGQUIT, SIGKILL,
+#else
+ SIGINT, SIGILL, SIGFPE, SIGSEGV, SIGTERM, SIGBREAK, SIGABRT,
+#endif
+ 0}; // zero terminated
+
+void terminate_request_handler(int param) {
+ char msg[] = "\nReceived signal XX, intend to exit soon.\n"
+ "repeat the signal to force immediate termination.\n";
+ msg[17] = '0' + param / 10;
+ msg[18] = '0' + param % 10;
+ write(1, msg, sizeof(msg) - 1);
+ terminating = true;
+ signal(param, prior_signal_handlers[param]);
+ theSocket.close();
+}
+
const int nowhere = -9999;
+
// parse message
static void parse_message( const string &msg, int *lat, int *lon ) {
double dlat, dlon;
string::size_type pos = text.find( "$GPGGA" );
if ( pos == string::npos )
{
- *lat = -9999.0;
- *lon = -9999.0;
+ *lat = nowhere;
+ *lon = nowhere;
return;
}
string tmp = text.substr( pos + 7 );
void getWaitingTile() {
while ( !waitingTiles.empty() ) {
- CompletedTiles::iterator ii = completedTiles.find( waitingTiles.front() );
+ CompletedTiles::iterator ii =
+ completedTiles.find( waitingTiles.front() );
time_t now = time(0);
if ( ii == completedTiles.end() || ii->second + 600 < now ) {
sync_tree(waitingTiles.front().c_str());
int main( int argc, char **argv ) {
int port = 5501;
- char host[256] = ""; // accept messages from anyone
+ char host[256] = "localhost";
bool testing = false;
bool do_checkout(true);
int verbose(0);
// Must call this before any other net stuff
netInit( &argc,argv );
- netSocket s;
-
- if ( ! s.open( false ) ) { // open a UDP socket
+ if ( ! theSocket.open( false ) ) { // open a UDP socket
printf("error opening socket\n");
return -1;
}
- if ( s.bind( host, port ) == -1 ) {
+ if ( theSocket.bind( host, port ) == -1 ) {
printf("error binding to port %d\n", port);
return -1;
}
}
- while ( true ) { // main loop
+ for (int* sigp=termination_triggering_signals; *sigp; sigp++) {
+ prior_signal_handlers[*sigp] =
+ signal(*sigp, *terminate_request_handler);
+ if (verbose) cout << "Intercepted signal " << *sigp << endl;
+ }
+
+ while ( !terminating ) {
+ // main loop
recv_msg = false;
if ( testing ) {
// No FGFS communications
lon = -123;
recv_msg = (lat != last_lat) || (lon != last_lon);
} else {
- s.setBlocking(waitingTiles.empty());
- len = s.recv(msg, maxlen, 0);
+ if (verbose && waitingTiles.empty()) {
+ cout << "Idle; waiting for FlightGear position\n";
+ }
+ theSocket.setBlocking(waitingTiles.empty());
+ len = theSocket.recv(msg, maxlen, 0);
if (len >= 0) {
msg[len] = '\0';
recv_msg = true;
// Ignore messages where the location does not change
if ( lat != last_lat || lon != last_lon ) {
cout << "pos in msg = " << lat << "," << lon << endl;
- std::deque<std::string> oldRequests;
+ deque<string> oldRequests;
oldRequests.swap( waitingTiles );
int lat_dir, lon_dir, dist;
if ( last_lat == nowhere || last_lon == nowhere ) {
}
else if ( testing ) {
- exit( 0 );
+ terminating = true;
} else
ulSleep( 1 );
- } // while true
+ } // while !terminating
return 0;
}
ax = new float [ numaxes ] ;
activeaxes = numaxes;
- if( numaxes < 4 )
+ if( numaxes > 4 )
{
printf("max 4 axes joysticks supported at the moment, however %i axes were detected\nWill only use the first 4 axes!\n", numaxes);
activeaxes = 4;
js->read( &b, ax );
for ( axis = 0 ; axis < activeaxes ; axis++ )
{
- long axisvalue = (long int)(ax[axis]*2147483647.0);
- printf("axisval=%li\n", axisvalue);
- memcpy(packet+len, &axisvalue, 4);
- len+=4;
+ int32_t axisvalue = (int32_t)(ax[axis]*2147483647.0);
+ printf("axisval=%li\n", (long)axisvalue);
+ memcpy(packet+len, &axisvalue, sizeof(axisvalue));
+ len+=sizeof(axisvalue);
}
// fill emtpy values into packes when less than 4 axes
for( ; axis < 4; axis++ )
{
- long axisvalue = 0;
- memcpy(packet+len, &axisvalue, 4);
- len+=4;
+ int32_t axisvalue = 0;
+ memcpy(packet+len, &axisvalue, sizeof(axisvalue));
+ len+=sizeof(axisvalue);
}
- long int b_l = b;
- memcpy(packet+len, &b_l, 4);
- len+=4;
+ int32_t b_l = b;
+ memcpy(packet+len, &b_l, sizeof(b_l));
+ len+=sizeof(b_l);
- char termstr[5] = "\0\0\r\n";
- memcpy(packet+len, &termstr, 4);
+ const char * termstr = "\0\0\r\n";
+ memcpy(packet+len, termstr, 4);
len += 4;
c.send( packet, len, 0 );