1
0
Fork 0

Some additional changes to ensure that FlightGear at least compiles after configuring with --disable-atcdcl. Some substitution code is added in ATC/atcutils.cxx and ATC/atcutils.hxx. Note that the new code doesn't run properly yet. Instead, it is just meant to identify which parts need replacement. Getting that to work will be the next step.

This commit is contained in:
durk 2010-01-05 20:04:54 +00:00 committed by Tim Moore
parent 8114d1d899
commit d8ae90801a
7 changed files with 586 additions and 23 deletions

View file

@ -1,6 +1,7 @@
noinst_LIBRARIES = libATC.a
libATC_a_SOURCES = \
atcutils.cxx atcutils.hxx \
trafficcontrol.cxx trafficcontrol.hxx
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src

372
src/ATC/atcutils.cxx Normal file
View file

@ -0,0 +1,372 @@
// commlist.cxx -- comm frequency lookup class
//
// Written by David Luff and Alexander Kappes, started Jan 2003.
// Based on navlist.cxx by Curtis Olson, started April 2000.
//
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/bucket/newbucket.hxx>
#include <Airports/simple.hxx>
#include "atcutils.hxx"
#if !ENABLE_ATCDCL
FGCommList *current_commlist;
// Constructor
FGCommList::FGCommList( void ) {
sg_srandom_time();
}
// Destructor
FGCommList::~FGCommList( void ) {
}
// load the navaids and build the map
bool FGCommList::init( const SGPath& path ) {
/*
SGPath temp = path;
commlist_freq.erase(commlist_freq.begin(), commlist_freq.end());
commlist_bck.erase(commlist_bck.begin(), commlist_bck.end());
temp.append( "ATC/default.atis" );
LoadComms(temp);
temp = path;
temp.append( "ATC/default.tower" );
LoadComms(temp);
temp = path;
temp.append( "ATC/default.ground" );
LoadComms(temp);
temp = path;
temp.append( "ATC/default.approach" );
LoadComms(temp);
return true;*/
}
bool FGCommList::LoadComms(const SGPath& path) {
/*
sg_gzifstream fin( path.str() );
if ( !fin.is_open() ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << path.str() );
exit(-1);
}
// read in each line of the file
fin >> skipcomment;
while ( !fin.eof() ) {
ATCData a;
fin >> a;
if(a.type == INVALID) {
SG_LOG(SG_GENERAL, SG_DEBUG, "WARNING - INVALID type found in " << path.str() << '\n');
} else {
// Push all stations onto frequency map
commlist_freq[a.freq].push_back(a);
// Push non-atis stations onto bucket map as well
// In fact, push all stations onto bucket map for now so FGATCMgr::GetFrequency() works.
//if(a.type != ATIS and/or AWOS?) {
// get bucket number
SGBucket bucket(a.geod);
int bucknum = bucket.gen_index();
commlist_bck[bucknum].push_back(a);
//}
}
fin >> skipcomment;
}
fin.close();
return true;
*/
}
// query the database for the specified frequency, lon and lat are in
// degrees, elev is in meters
// If no atc_type is specified, it returns true if any non-invalid type is found
// If atc_type is specifed, returns true only if the specified type is found
bool FGCommList::FindByFreq(const SGGeod& aPos, double freq,
ATCData* ad, atc_type tp )
{
/*
comm_list_type stations;
stations = commlist_freq[kHz10(freq)];
comm_list_iterator current = stations.begin();
comm_list_iterator last = stations.end();
// double az1, az2, s;
SGVec3d aircraft = SGVec3d::fromGeod(aPos);
const double orig_max_d = 1e100;
double max_d = orig_max_d;
double d;
// TODO - at the moment this loop returns the first match found in range
// We want to return the closest match in the event of a frequency conflict
for ( ; current != last ; ++current ) {
d = distSqr(aircraft, current->cart);
//cout << " dist = " << sqrt(d)
// << " range = " << current->range * SG_NM_TO_METER << endl;
// TODO - match up to twice the published range so we can model
// reduced signal strength
// NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
if ( d < (current->range * SG_NM_TO_METER
* current->range * SG_NM_TO_METER ) ) {
//cout << "matched = " << current->ident << endl;
if((tp == INVALID) || (tp == (*current).type)) {
if(d < max_d) {
max_d = d;
*ad = *current;
}
}
}
}
if(max_d < orig_max_d) {
return true;
} else {
return false;
}
*/
}
int FGCommList::FindByPos(const SGGeod& aPos, double range, comm_list_type* stations, atc_type tp)
{
/*
// number of relevant stations found within range
int found = 0;
stations->erase(stations->begin(), stations->end());
// get bucket number for plane position
SGBucket buck(aPos);
// get neigboring buckets
int bx = (int)( range*SG_NM_TO_METER / buck.get_width_m() / 2) + 1;
int by = (int)( range*SG_NM_TO_METER / buck.get_height_m() / 2 ) + 1;
// loop over bucket range
for ( int i=-bx; i<=bx; i++) {
for ( int j=-by; j<=by; j++) {
buck = sgBucketOffset(aPos.getLongitudeDeg(), aPos.getLatitudeDeg(), i, j);
long int bucket = buck.gen_index();
comm_map_const_iterator Fstations = commlist_bck.find(bucket);
if (Fstations == commlist_bck.end()) continue;
comm_list_const_iterator current = Fstations->second.begin();
comm_list_const_iterator last = Fstations->second.end();
// double az1, az2, s;
SGVec3d aircraft = SGVec3d::fromGeod(aPos);
double d;
for(; current != last; ++current) {
if((current->type == tp) || (tp == INVALID)) {
d = distSqr(aircraft, current->cart);
// NOTE The below is squared since we match to distance3Dsquared (above) to avoid a sqrt.
if ( d < (current->range * SG_NM_TO_METER
* current->range * SG_NM_TO_METER ) ) {
stations->push_back(*current);
++found;
}
}
}
}
}
return found;
*/
}
// Returns the distance in meters to the closest station of a given type,
// with the details written into ATCData& ad. If no type is specifed simply
// returns the distance to the closest station of any type.
// Returns -9999 if no stations found within max_range in nautical miles (default 100 miles).
// Note that the search algorithm starts at 10 miles and multiplies by 10 thereafter, so if
// say 300 miles is specifed 10, then 100, then 1000 will be searched, breaking at first result
// and giving up after 1000.
double FGCommList::FindClosest(const SGGeod& aPos, ATCData& ad, atc_type tp, double max_range) {
/*
int num_stations = 0;
int range = 10;
comm_list_type stations;
comm_list_iterator itr;
double distance = -9999.0;
while(num_stations == 0) {
num_stations = FindByPos(aPos, range, &stations, tp);
if(num_stations) {
double closest = max_range * SG_NM_TO_METER;
double tmp;
for(itr = stations.begin(); itr != stations.end(); ++itr) {
ATCData ad2 = *itr;
const FGAirport *a = fgFindAirportID(ad2.ident);
if (a) {
tmp = dclGetHorizontalSeparation(ad2.geod, aPos);
if(tmp <= closest) {
closest = tmp;
distance = tmp;
ad = *itr;
}
}
}
//cout << "Closest station is " << ad.ident << " at a range of " << distance << " meters\n";
return(distance);
}
if(range > max_range) {
break;
}
range *= 10;
}
return(-9999.0);
*/
}
// Find by Airport code.
// This is basically a wrapper for a call to the airport database to get the airport
// position followed by a call to FindByPos(...)
bool FGCommList::FindByCode( const string& ICAO, ATCData& ad, atc_type tp ) {
/*
const FGAirport *a = fgFindAirportID( ICAO);
if ( a) {
comm_list_type stations;
int found = FindByPos(a->geod(), 10.0, &stations, tp);
if(found) {
comm_list_iterator itr = stations.begin();
while(itr != stations.end()) {
if(((*itr).ident == ICAO) && ((*itr).type == tp)) {
ad = *itr;
//cout << "FindByCode returns " << ICAO
// << " type: " << tp
// << " freq: " << itr->freq
// << endl;
return true;
}
++itr;
}
}
}
return false;
*/
}
// TODO - this function should move somewhere else eventually!
// Return an appropriate sequence number for an ATIS transmission.
// Return sequence number + 2600 if sequence is unchanged since
// last time.
int FGCommList::GetAtisSequence( const string& apt_id,
const double tstamp, const int interval, const int special)
{
/*
atis_transmission_type tran;
if(atislog.find(apt_id) == atislog.end()) { // New station
tran.tstamp = tstamp - interval;
// Random number between 0 and 25 inclusive, i.e. 26 equiprobable outcomes:
tran.sequence = int(sg_random() * LTRS);
atislog[apt_id] = tran;
//cout << "New ATIS station: " << apt_id << " seq-1: "
// << tran.sequence << endl;
}
// calculate the appropriate identifier and update the log
tran = atislog[apt_id];
int delta = int((tstamp - tran.tstamp) / interval);
tran.tstamp += delta * interval;
if (special && !delta) delta++; // a "special" ATIS update is required
tran.sequence = (tran.sequence + delta) % LTRS;
atislog[apt_id] = tran;
//if (delta) cout << "New ATIS sequence: " << tran.sequence
// << " Delta: " << delta << endl;
return(tran.sequence + (delta ? 0 : LTRS*1000));
*/
}
/*****************************************************************************
* FGKln89AlignedProjection
****************************************************************************/
FGKln89AlignedProjection::FGKln89AlignedProjection() {
_origin.setLatitudeRad(0);
_origin.setLongitudeRad(0);
_origin.setElevationM(0);
_correction_factor = cos(_origin.getLatitudeRad());
}
FGKln89AlignedProjection::FGKln89AlignedProjection(const SGGeod& centre, double heading) {
_origin = centre;
_theta = heading * SG_DEGREES_TO_RADIANS;
_correction_factor = cos(_origin.getLatitudeRad());
}
FGKln89AlignedProjection::~FGKln89AlignedProjection() {
}
void FGKln89AlignedProjection::Init(const SGGeod& centre, double heading) {
_origin = centre;
_theta = heading * SG_DEGREES_TO_RADIANS;
_correction_factor = cos(_origin.getLatitudeRad());
}
SGVec3d FGKln89AlignedProjection::ConvertToLocal(const SGGeod& pt) {
// convert from lat/lon to orthogonal
double delta_lat = pt.getLatitudeRad() - _origin.getLatitudeRad();
double delta_lon = pt.getLongitudeRad() - _origin.getLongitudeRad();
double y = sin(delta_lat) * SG_EQUATORIAL_RADIUS_M;
double x = sin(delta_lon) * SG_EQUATORIAL_RADIUS_M * _correction_factor;
// Align
if(_theta != 0.0) {
double xbar = x;
x = x*cos(_theta) - y*sin(_theta);
y = (xbar*sin(_theta)) + (y*cos(_theta));
}
return SGVec3d(x, y, pt.getElevationM());
}
SGGeod FGKln89AlignedProjection::ConvertFromLocal(const SGVec3d& pt) {
// de-align
double thi = _theta * -1.0;
double x = pt.x()*cos(thi) - pt.y()*sin(thi);
double y = (pt.x()*sin(thi)) + (pt.y()*cos(thi));
// convert from orthogonal to lat/lon
double delta_lat = asin(y / SG_EQUATORIAL_RADIUS_M);
double delta_lon = asin(x / SG_EQUATORIAL_RADIUS_M) / _correction_factor;
return SGGeod::fromRadM(_origin.getLongitudeRad()+delta_lon, _origin.getLatitudeRad()+delta_lat, pt.z());
}
#endif // #ENABLE_ATCDCL

185
src/ATC/atcutils.hxx Normal file
View file

@ -0,0 +1,185 @@
// atcutils.hxx
//
// This file contains a collection of classes from David Luff's
// AI/ATC code that are shared by non-AI parts of FlightGear.
// more specifcially, it contains implementations of FGCommList and
// FGATCAlign
//
// Written by David Luff and Alexander Kappes, started Jan 2003.
// Based on navlist.hxx by Curtis Olson, started April 2000.
//
// Copyright (C) 2000 Curtis L. Olson - http://www.flightgear.org/~curt
//
// 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
/*****************************************************************
*
* FGCommList is used to store communication frequency information
* for the ATC and AI subsystems. Two maps are maintained - one
* searchable by location and one searchable by frequency. The
* data structure returned from the search is the ATCData struct
* defined in ATC.hxx, containing location, frequency, name, range
* and type of the returned station.
*
******************************************************************/
#ifndef _FG_ATCUTILS_HXX
#define _FG_ATCUTILS_HXX
#include <simgear/compiler.h>
#include <map>
#include <list>
#include <string>
//#include "ATC.hxx"
//#include "atis.hxx"
#if !ENABLE_ATCDCL
class SGPath;
class ATCData;
// Possible types of ATC type that the radios may be tuned to.
// INVALID implies not tuned in to anything.
enum atc_type {
AWOS,
ATIS,
GROUND,
TOWER,
APPROACH,
DEPARTURE,
ENROUTE,
INVALID /* must be last element; see ATC_NUM_TYPES */
};
// A list of ATC stations
typedef std::list < ATCData > comm_list_type;
typedef comm_list_type::iterator comm_list_iterator;
typedef comm_list_type::const_iterator comm_list_const_iterator;
// A map of ATC station lists
typedef std::map < int, comm_list_type > comm_map_type;
typedef comm_map_type::iterator comm_map_iterator;
typedef comm_map_type::const_iterator comm_map_const_iterator;
class FGCommList {
public:
FGCommList();
~FGCommList();
// load all comm frequencies and build the map
bool init( const SGPath& path );
// query the database for the specified frequency, lon and lat are
// If no atc_type is specified, it returns true if any non-invalid type is found.
// If atc_type is specifed, returns true only if the specified type is found.
// Returns the station closest to the supplied position.
// The data found is written into the passed-in ATCData structure.
bool FindByFreq(const SGGeod& aPos, double freq, ATCData* ad, atc_type tp = INVALID );
// query the database by location, lon and lat are in degrees, elev is in meters, range is in nautical miles.
// Returns the number of stations of the specified atc_type tp that are in range of the position defined by
// lon, lat and elev, and pushes them into stations.
// If no atc_type is specifed, returns the number of all stations in range, and pushes them into stations
// ** stations is erased before use **
int FindByPos(const SGGeod& aPos, double range, comm_list_type* stations, atc_type tp = INVALID );
// Returns the distance in meters to the closest station of a given type,
// with the details written into ATCData& ad. If no type is specifed simply
// returns the distance to the closest station of any type.
// Returns -9999 if no stations found within max_range in nautical miles (default 100 miles).
// Note that the search algorithm starts at 10 miles and multiplies by 10 thereafter, so if
// say 300 miles is specifed 10, then 100, then 1000 will be searched, breaking at first result
// and giving up after 1000.
// !!!Be warned that searching anything over 100 miles will pause the sim unacceptably!!!
// (The ability to search longer ranges should be used during init only).
double FindClosest(const SGGeod& aPos, ATCData& ad, atc_type tp = INVALID, double max_range = 100.0 );
// Find by Airport code.
bool FindByCode( const std::string& ICAO, ATCData& ad, atc_type tp = INVALID );
// Return the sequence letter for an ATIS transmission given transmission time and airport id
// This maybe should get moved somewhere else!!
int GetAtisSequence( const std::string& apt_id, const double tstamp,
const int interval, const int flush=0);
// Comm stations mapped by frequency
//comm_map_type commlist_freq;
// Comm stations mapped by bucket
//comm_map_type commlist_bck;
// Load comms from a specified path (which must include the filename)
private:
bool LoadComms(const SGPath& path);
//----------- This stuff is left over from atislist.[ch]xx and maybe should move somewhere else
// Add structure and map for storing a log of atis transmissions
// made in this session of FlightGear. This allows the callsign
// to be allocated correctly wrt time.
//typedef struct {
// double tstamp;
// int sequence;
//} atis_transmission_type;
//typedef std::map < std::string, atis_transmission_type > atis_log_type;
//typedef atis_log_type::iterator atis_log_iterator;
//typedef atis_log_type::const_iterator atis_log_const_iterator;
//atis_log_type atislog;
//-----------------------------------------------------------------------------------------------
};
extern FGCommList *current_commlist;
// FGATCAlignedProjection - a class to project an area local to a runway onto an orthogonal co-ordinate system
// with the origin at the threshold and the runway aligned with the y axis.
class FGKln89AlignedProjection {
public:
FGKln89AlignedProjection();
FGKln89AlignedProjection(const SGGeod& centre, double heading);
~FGKln89AlignedProjection();
void Init(const SGGeod& centre, double heading);
// Convert a lat/lon co-ordinate (degrees) to the local projection (meters)
SGVec3d ConvertToLocal(const SGGeod& pt);
// Convert a local projection co-ordinate (meters) to lat/lon (degrees)
SGGeod ConvertFromLocal(const SGVec3d& pt);
private:
SGGeod _origin; // lat/lon of local area origin (the threshold)
double _theta; // the rotation angle for alignment in radians
double _correction_factor; // Reduction in surface distance per degree of longitude due to latitude. Saves having to do a cos() every call.
};
#endif // #if ENABLE_ATCDCL
#endif // _FG_ATCUTILS_HXX

View file

@ -47,6 +47,8 @@
#include "pavement.hxx"
#if ENABLE_ATCDCL
# include <ATCDCL/commlist.hxx>
#else
#include <ATC/atcutils.hxx>
#endif
#include <iostream>
@ -78,11 +80,8 @@ public:
{}
#ifdef ENABLE_ATCDCL
void parseAPT(const string &aptdb_file, FGCommList *comm_list)
#else
void parseAPT(const string &aptdb_file)
#endif
{
sg_gzifstream in( aptdb_file );
@ -162,7 +161,9 @@ public:
} else if ( line_id == 0 ) {
// ??
} else if ( line_id == 50 ) {
parseATISLine(comm_list, simgear::strutils::split(line));
} else if ( line_id >= 51 && line_id <= 56 ) {
// other frequency entries (ignore)
} else if ( line_id == 110 ) {
@ -468,7 +469,7 @@ private:
pvt->addNode(pos, num == 113);
}
}
#if ENABLE_ATCDCL
void parseATISLine(FGCommList *comm_list, const vector<string>& token)
{
if ( rwy_count <= 0 ) {
@ -485,6 +486,7 @@ private:
// 50 11770 AWOS 3
// This code parallels code found in "operator>>" in ATC.hxx;
// FIXME: unify the code.
#if ENABLE_ATCDCL
ATCData a;
a.geod = SGGeod::fromDegFt(rwy_lon_accum / (double)rwy_count,
rwy_lat_accum / (double)rwy_count, last_apt_elev);
@ -503,6 +505,8 @@ private:
SGBucket bucket(a.geod);
int bucknum = bucket.gen_index();
comm_list->commlist_bck[bucknum].push_back(a);
#else
#endif
#if 0
SG_LOG( SG_GENERAL, SG_ALERT,
"Loaded ATIS/AWOS for airport: " << a.ident
@ -512,7 +516,7 @@ private:
<< " type: " << a.type );
#endif
}
#endif
};
@ -520,19 +524,11 @@ private:
// metar file is used to mark the airports as having metar available
// or not.
bool fgAirportDBLoad( const string &aptdb_file,
#if ENABLE_ATCDCL
FGCommList *comm_list, const std::string &metar_file )
#else
const std::string &metar_file )
#endif
{
APTLoader ld;
#if ENABLE_ATCDCL
ld.parseAPT(aptdb_file, comm_list);
#else
ld.parseAPT(aptdb_file);
#endif
//
// Load the metar.dat file and update apt db with stations that
// have metar data.

View file

@ -35,8 +35,8 @@ class FGCommList;
// Load the airport data base from the specified aptdb file. The
// metar file is used to mark the airports as having metar available
// or not.
bool fgAirportDBLoad( const std::string &aptdb_file,
FGCommList *comm_list, const std::string &metar_file );
#endif // _FG_APT_LOADER_HXX

View file

@ -43,7 +43,12 @@
#include "kln89_symbols.hxx"
#include <iostream>
#if ENABLE_ATCDCL
#include <ATCDCL/ATCProjection.hxx>
#else
#include "kln89_align.hxx"
#endif
#include <Main/fg_props.hxx>
#include <simgear/math/SGMath.hxx>
#include <simgear/structure/commands.hxx>
@ -676,13 +681,18 @@ void KLN89::DrawMap(bool draw_avs) {
double mapScaleMeters = _mapScale * (_mapScaleUnits == 0 ? SG_NM_TO_METER : 1000);
// TODO - use an aligned projection when either DTK or TK up!
#if ENABLE_ATCDCL
FGATCAlignedProjection mapProj(SGGeod::fromRad(_gpsLon, _gpsLat), _mapHeading);
#else
FGKln89AlignedProjection mapProj(SGGeod::fromRad(_gpsLon, _gpsLat), _mapHeading);
#endif
double meter_per_pix = (_mapOrientation == 0 ? mapScaleMeters / 20.0f : mapScaleMeters / 29.0f);
SGGeod bottomLeft = mapProj.ConvertFromLocal(SGVec3d(gps_max(-57.0 * meter_per_pix, -50000), gps_max((_mapOrientation == 0 ? -20.0 * meter_per_pix : -11.0 * meter_per_pix), -25000), 0.0));
SGGeod topRight = mapProj.ConvertFromLocal(SGVec3d(gps_min(54.0 * meter_per_pix, 50000), gps_min((_mapOrientation == 0 ? 20.0 * meter_per_pix : 29.0 * meter_per_pix), 25000), 0.0));
// Draw Airport labels first (but not one's that are waypoints)
// Draw Airports first (but not one's that are waypoints)
// Ditto for VORs (not sure if SUA/VOR/Airport ordering is important or not).

View file

@ -78,6 +78,8 @@
# include <ATCDCL/ATCmgr.hxx>
# include <ATCDCL/AIMgr.hxx>
# include "ATCDCL/commlist.hxx"
#else
# include "ATC/atcutils.hxx"
#endif
#include <Autopilot/route_mgr.hxx>
@ -982,13 +984,9 @@ fgInitNav ()
#if ENABLE_ATCDCL
current_commlist = new FGCommList;
current_commlist->init( globals->get_fg_root() );
fgAirportDBLoad( aptdb.str(), current_commlist, p_metar.str() );
#else
fgAirportDBLoad( aptdb.str(), p_metar.str() );
#endif
FGNavList *navlist = new FGNavList;
FGNavList *loclist = new FGNavList;
@ -1623,6 +1621,7 @@ bool fgInitSubsystems() {
// Initialise the ATC Manager
////////////////////////////////////////////////////////////////////
#if ENABLE_ATCDCL
SG_LOG(SG_GENERAL, SG_INFO, " ATC Manager");
globals->set_ATC_mgr(new FGATCMgr);
globals->get_ATC_mgr()->init();
@ -1634,7 +1633,7 @@ bool fgInitSubsystems() {
SG_LOG(SG_GENERAL, SG_INFO, " AI Manager");
globals->set_AI_mgr(new FGAIMgr);
globals->get_AI_mgr()->init();
#endif
////////////////////////////////////////////////////////////////////
// Initialise the AI Model Manager
////////////////////////////////////////////////////////////////////