1
0
Fork 0

AirportBuilder to generate airports from apt.dat

This commit is contained in:
Stuart Buchanan 2020-07-01 20:57:15 +01:00
parent bb75d24fc0
commit c4942eaa69
13 changed files with 1030 additions and 181 deletions

View file

@ -0,0 +1,569 @@
// AirportBuilder.hxx -- Builder to create airports based on airport data for
// rendering in the scenery
//
// Written by Stuart Buchanan, started June 2020
//
// Copyright (C) 2020 Stuart Buchanan stuart13@gmail.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#include <algorithm>
#include <osgDB/Registry>
#include <osgUtil/Tessellator>
#include <osgUtil/DelaunayTriangulator>
#include "AirportBuilder.hxx"
#include <osg/Geode>
#include <osg/Geometry>
#include <simgear/scene/material/Effect.hxx>
#include <simgear/scene/material/EffectGeode.hxx>
#include "simgear/scene/model/ModelRegistry.hxx"
#include "simgear/scene/util/OsgMath.hxx"
#include "simgear/math/SGGeodesy.hxx"
#include "airport.hxx"
#include <Airports/apt_loader.hxx>
#include "runways.hxx"
#include "pavement.hxx"
namespace flightgear
{
AirportBuilder::AirportBuilder()
{
supportsExtension("icao", "Dummy name to build an airport from apt.dat");
}
AirportBuilder::~AirportBuilder()
{
}
const char* AirportBuilder::className() const
{
return "Airport Builder";
}
osgDB::ReaderWriter::ReadResult
AirportBuilder::readNode(const std::string& fileName,
const osgDB::Options* options) const
{
const SGPath aptFile = SGPath(fileName);
const string airportId = aptFile.file_base();
APTLoader aptLoader;
const FGAirport* airport = aptLoader.loadAirportFromFile(airportId, aptFile);
if (! airport) return ReadResult::FILE_NOT_HANDLED;;
std::cout << "AirportBuilder, building airport : " << airportId << " " << airport->getName() << "\n";
std::cout << "Elevation : " << airport->getElevation() << "ft\n";
std::cout << "Latitude : " << airport->getLatitude() << "ft\n";
std::cout << "Longitude : " << airport->getLongitude() << "ft\n";
std::cout << "Runways : " << airport->numRunways() << "\n";
std::cout << "Helipads : " << airport->numHelipads() << "\n";
std::cout << "Taxiways : " << airport->numTaxiways() << "\n";
std::cout << "Pavements : " << airport->numPavements() << "\n";
std::cout << "Line Features : " << airport->numLineFeatures() << "\n";
const SGVec3f center = SGVec3f::fromGeod(airport->geod());
const SGVec3f offset = SGVec3f::fromGeod(SGGeod::fromGeodM(airport->geod(), airport->geod().getElevationM() + 1.0));
const osg::Vec3f up = osg::Vec3f(toOsg(offset - center));
std::vector<osg::Node*> nodeList;
osg::Group* group = new osg::Group();
// Build the various components
auto runwaylist = airport->getRunways();
std::for_each( runwaylist.begin(),
runwaylist.end(),
[&, center] (FGRunwayRef p) { group->addChild(this->createRunway(center, up, p)); } );
// Build the pavements
auto pavementlist = airport->getPavements();
std::for_each( pavementlist.begin(),
pavementlist.end(),
[&, center, up] (FGPavementRef p) { group->addChild(this->createPavement(center, up, p)); } );
// Build the boundary
auto boundaryList = airport->getBoundary();
std::for_each( boundaryList.begin(),
boundaryList.end(),
[&, center] (FGPavementRef p) { group->addChild(this->createBoundary(center, up, p)); } );
// Build line features
auto lineList = airport->getLineFeatures();
std::for_each( lineList.begin(),
lineList.end(),
[&, center] (FGPavementRef p) { group->addChild(this->createLine(center, up, p)); } );
return group;
}
osg::Node* AirportBuilder::createRunway(const SGVec3f center, const osg::Vec3f up, const FGRunwayRef runway) const
{
std::vector<SGGeod> nodes;
nodes.push_back(runway->pointOffCenterline(0.0, -0.5 * runway->widthM()));
nodes.push_back(runway->pointOffCenterline(0.0, 0.5 * runway->widthM()));
nodes.push_back(runway->pointOffCenterline(runway->lengthM(), 0.5 * runway->widthM()));
nodes.push_back(runway->pointOffCenterline(runway->lengthM(), -0.5 * runway->widthM()));
osg::Vec3Array* points = new osg::Vec3Array;
points->reserve(nodes.size());
std::transform( nodes.begin(),
nodes.end(),
std::back_inserter(*points),
[center](SGGeod n) { return toOsg(SGVec3f::fromGeod(SGGeod::fromGeodM(n, n.getElevationM() + RUNWAY_OFFSET)) - center); }
);
osg::ref_ptr<osgUtil::DelaunayTriangulator> triangulator = new osgUtil::DelaunayTriangulator;
triangulator->setInputPointArray(points);
triangulator->triangulate();
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
geometry->setVertexArray(points);
geometry->addPrimitiveSet(triangulator->getTriangles()); // triangles with constraint cut
osg::Vec3Array* n = new osg::Vec3Array;
n->push_back(up);
osg::Vec4Array* c = new osg::Vec4Array;
c->push_back(osg::Vec4f(0.2f,0.2f,0.2f,1.0f));
geometry->setColorArray(c, osg::Array::BIND_OVERALL);
geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
simgear::EffectGeode* geode = new simgear::EffectGeode;
geode->addDrawable(geometry);
//geode->setEffect(_effect.get());
return geode;
}
osg::Node* AirportBuilder::createPavement(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const
{
const FGPavement::NodeList nodes = pavement->getNodeList();
if (nodes.size() == 0) return NULL;
osg::ref_ptr<osgUtil::Tessellator> tessellator = new osgUtil::Tessellator;
tessellator->setBoundaryOnly(false);
tessellator->beginTessellation();
tessellator->beginContour();
// Track the previous vertex for bezier curve generation.
osg::Vec3f* previous;
// Bezier control. Bezier curve is node n-1 -> n -> n+1 so need to store for
// handling the next node in addition to generating for the BezierNode itself.
bool bezier = false;
osg::Vec3f control;
auto itr = nodes.begin();
for (; itr < nodes.end(); ++itr) {
FGPavement::NodeBase* node = *itr;
// Create an offset so we can easily layer the boundary, pavement, lights and runways
SGGeod offset = SGGeod::fromGeodM(node->mPos, node->mPos.getElevationM() + PAVEMENT_OFFSET);
osg::Vec3f* v = new osg::Vec3f(toOsg(SGVec3f::fromGeod(offset) - center));
if (FGPavement::BezierNode *bez = dynamic_cast<FGPavement::BezierNode*>(node)) {
// Store the bezier control node for generation when we know the next node.
SGGeod controlGeod = SGGeod::fromGeodM(bez->mControl, bez->mControl.getElevationM() + PAVEMENT_OFFSET);
control = osg::Vec3f(toOsg(SGVec3f::fromGeod(controlGeod) - center));
bezier = true;
// Generate from the last node to this one, reflecting the control point
for (float t = 0.05f; t < 0.95f; t += 0.05f ) {
osg::Vec3f p0 = *previous;
osg::Vec3f p1 = *v + *v - control;
osg::Vec3f p2 = *v;
osg::Vec3f* b = new osg::Vec3f(p1 +
(p0 - p1)*(1.0f - t)*(1.0f - t) +
(p2 - p1)*t*t);
tessellator->addVertex(b);
}
tessellator->addVertex(v);
} else if (bezier) {
// Last node was a BezierNode, so generate the required bezier curve to this node.
for (float t = 0.05f; t < 0.95f; t += 0.05f ) {
osg::Vec3f p0 = *previous;
osg::Vec3f p1 = control;
osg::Vec3f p2 = *v;
osg::Vec3f* b = new osg::Vec3f(p1 +
(p0 - p1)*(1.0f - t)*(1.0f - t) +
(p2 - p1)*t*t);
tessellator->addVertex(b);
}
bezier = false;
tessellator->addVertex(v);
} else {
// SimpleNode
tessellator->addVertex(v);
}
previous = v;
if (node->mClose) {
tessellator->endContour();
tessellator->beginContour();
}
}
tessellator->endContour();
tessellator->endTessellation();
// Build the geometry based on the tessellation results.
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
auto primList = tessellator->getPrimList();
osg::Vec3Array* points = new osg::Vec3Array();
geometry->setVertexArray(points);
unsigned int idx = 0;
auto primItr = primList.begin();
for (; primItr < primList.end(); ++ primItr) {
auto vertices = (*primItr)->_vertices;
std::for_each( vertices.begin(),
vertices.end(),
[points](auto v) { points->push_back(*v); }
);
geometry->addPrimitiveSet(new osg::DrawArrays((*primItr)->_mode, idx, vertices.size()));
idx += vertices.size();
}
osg::Vec3Array* n = new osg::Vec3Array;
n->push_back(up);
osg::Vec4Array* c = new osg::Vec4Array;
c->push_back(osg::Vec4f(0.5f, 0.5f, 0.5f, 1.0f));
geometry->setColorArray(c, osg::Array::BIND_OVERALL);
geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
simgear::EffectGeode* geode = new simgear::EffectGeode;
geode->addDrawable(geometry);
//geode->setEffect(_effect.get());
return geode;
}
osg::Node* AirportBuilder::createBoundary(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const
{
const FGPavement::NodeList nodes = pavement->getNodeList();
if (nodes.size() == 0) return NULL;
osg::ref_ptr<osgUtil::Tessellator> tessellator = new osgUtil::Tessellator;
tessellator->setBoundaryOnly(false);
tessellator->beginTessellation();
tessellator->beginContour();
// Track the previous vertex for bezier curve generation.
osg::Vec3f* previous;
// Bezier control. Bezier curve is node n-1 -> n -> n+1 so need to store for
// handling the next node in addition to generating for the BezierNode itself.
bool bezier = false;
osg::Vec3f control;
auto itr = nodes.begin();
for (; itr < nodes.end(); ++itr) {
FGPavement::NodeBase* node = *itr;
// Create an offset so we can easily layer the boundary, pavement, lights and runways
SGGeod offset = SGGeod::fromGeodM(node->mPos, node->mPos.getElevationM() + BOUNDARY_OFFSET);
osg::Vec3f* v = new osg::Vec3f(toOsg(SGVec3f::fromGeod(offset) - center));
if (FGPavement::BezierNode *bez = dynamic_cast<FGPavement::BezierNode*>(node)) {
// Store the bezier control node for generation when we know the next node.
SGGeod controlGeod = SGGeod::fromGeodM(bez->mControl, bez->mControl.getElevationM() + BOUNDARY_OFFSET);
control = osg::Vec3f(toOsg(SGVec3f::fromGeod(controlGeod) - center));
bezier = true;
// Generate from the last node to this one, reflecting the control point
for (float t = 0.05f; t < 0.95f; t += 0.05f ) {
osg::Vec3f p0 = *previous;
osg::Vec3f p1 = *v + *v - control;
osg::Vec3f p2 = *v;
osg::Vec3f* b = new osg::Vec3f(p1 +
(p0 - p1)*(1.0f - t)*(1.0f - t) +
(p2 - p1)*t*t);
tessellator->addVertex(b);
}
tessellator->addVertex(v);
} else if (bezier) {
// Last node was a BezierNode, so generate the required bezier curve to this node.
for (float t = 0.05f; t < 0.95f; t += 0.05f ) {
osg::Vec3f p0 = *previous;
osg::Vec3f p1 = control;
osg::Vec3f p2 = *v;
osg::Vec3f* b = new osg::Vec3f(p1 +
(p0 - p1)*(1.0f - t)*(1.0f - t) +
(p2 - p1)*t*t);
tessellator->addVertex(b);
}
bezier = false;
tessellator->addVertex(v);
} else {
// SimpleNode
tessellator->addVertex(v);
}
previous = v;
if (node->mClose) {
tessellator->endContour();
tessellator->beginContour();
}
}
tessellator->endContour();
tessellator->endTessellation();
// Build the geometry based on the tessellation results.
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
auto primList = tessellator->getPrimList();
osg::Vec3Array* points = new osg::Vec3Array();
geometry->setVertexArray(points);
unsigned int idx = 0;
auto primItr = primList.begin();
for (; primItr < primList.end(); ++ primItr) {
auto vertices = (*primItr)->_vertices;
std::for_each( vertices.begin(),
vertices.end(),
[points](auto v) { points->push_back(*v); }
);
geometry->addPrimitiveSet(new osg::DrawArrays((*primItr)->_mode, idx, vertices.size()));
idx += vertices.size();
}
osg::Vec3Array* n = new osg::Vec3Array;
n->push_back(up);
osg::Vec4Array* c = new osg::Vec4Array;
c->push_back(osg::Vec4f(0.3f, 0.7f, 0.3f, 1.0f));
geometry->setColorArray(c, osg::Array::BIND_OVERALL);
geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
simgear::EffectGeode* geode = new simgear::EffectGeode;
geode->addDrawable(geometry);
//geode->setEffect(_effect.get());
return geode;
}
osg::Node* AirportBuilder::createLine(const SGVec3f center, const osg::Vec3f up, const FGPavementRef line) const
{
const FGPavement::NodeList nodes = line->getNodeList();
if (nodes.size() == 0) return NULL;
// Track the previous vertex for bezier curve generation.
osg::Vec3f previous;
// Track along the vertex list to create the correct Drawables
unsigned int idx = 0;
unsigned int length = 0;
// Track the last set line code
unsigned int paintCode = 0;
unsigned int lines = 0;
// Bezier control. Bezier curve is node n-1 -> n -> n+1 so need to store for
// handling the next node in addition to generating for the BezierNode itself.
bool bezier = false;
osg::Vec3f control;
osg::ref_ptr<osg::Geometry> geometry = new osg::Geometry;
osg::Vec3Array* points = new osg::Vec3Array();
geometry->setVertexArray(points);
osg::Vec3Array* n = new osg::Vec3Array;
n->push_back(up);
geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
osg::Vec4Array* c = new osg::Vec4Array;
geometry->setColorArray(c, osg::Array::BIND_PER_VERTEX);
auto itr = nodes.begin();
for (; itr < nodes.end(); ++itr) {
FGPavement::NodeBase* node = *itr;
// Create an offset so we can easily layer the boundary, pavement, lights and runways
SGGeod offset = SGGeod::fromGeodM(node->mPos, node->mPos.getElevationM() + MARKING_OFFSET);
osg::Vec3f v = osg::Vec3f(toOsg(SGVec3f::fromGeod(offset) - center));
if (node->mPaintCode != 0) paintCode = node->mPaintCode;
if (FGPavement::BezierNode *bez = dynamic_cast<FGPavement::BezierNode*>(node)) {
// Store the bezier control node for generation when we know the next node.
SGGeod controlGeod = SGGeod::fromGeodM(bez->mControl, bez->mControl.getElevationM() + MARKING_OFFSET);
control = osg::Vec3f(toOsg(SGVec3f::fromGeod(controlGeod) - center));
bezier = true;
// Generate from the last node to this one, reflecting the control point
for (float t = 0.05f; t < 0.95f; t += 0.05f ) {
osg::Vec3f p0 = previous;
osg::Vec3f p1 = v + v - control;
osg::Vec3f p2 = v;
osg::Vec3f b =
osg::Vec3f(p1 +
(p0 - p1)*(1.0f - t)*(1.0f - t) +
(p2 - p1)*t*t);
points->push_back(b);
c->push_back(getLineColor(paintCode));
length += 1;
}
points->push_back(v);
c->push_back(getLineColor(paintCode));
length += 1;
if (node->mClose && node->mLoop) {
// Special case if this is the end node and it loops back to the start.
// In this case there is not going to be a forward node to generate, so
// we need to generate the bezier curve now.
for (float t = 0.05f; t < 0.95f; t += 0.05f ) {
osg::Vec3f p0 = v;
osg::Vec3f p1 = control;
osg::Vec3f p2 = points->at(idx);
osg::Vec3f b =
osg::Vec3f(p1 +
(p0 - p1)*(1.0f - t)*(1.0f - t) +
(p2 - p1)*t*t);
points->push_back(b);
c->push_back(getLineColor(paintCode));
length += 1;
}
bezier = false;
}
} else if (bezier) {
// Last node was a BezierNode, so generate the required bezier curve to this node.
for (float t = 0.05f; t < 0.95f; t += 0.05f ) {
osg::Vec3f p0 = previous;
osg::Vec3f p1 = control;
osg::Vec3f p2 = v;
osg::Vec3f b =
osg::Vec3f(p1 +
(p0 - p1)*(1.0f - t)*(1.0f - t) +
(p2 - p1)*t*t);
points->push_back(b);
c->push_back(getLineColor(paintCode));
length += 1;
}
bezier = false;
} else {
// SimpleNode
points->push_back(v);
c->push_back(getLineColor(paintCode));
length += 1;
}
previous = v;
if (node->mClose) {
geometry->addPrimitiveSet(new osg::DrawArrays(
node->mLoop ? GL_LINE_LOOP : GL_LINE_STRIP,
idx,
length));
idx += length;
length = 0;
lines++;
}
}
simgear::EffectGeode* geode = new simgear::EffectGeode;
geode->addDrawable(geometry);
//geode->setEffect(_effect.get());
return geode;
}
osg::Vec4f AirportBuilder::getLineColor(const int aPaintCode) const {
if (aPaintCode == 1) return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f); // Solid yellow
if (aPaintCode == 2) return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f); // Broken yellow
if (aPaintCode == 3) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Double yellow
if (aPaintCode == 4) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Two broken yellow lines and two solid yellow lines. Broken line on left of string.
if (aPaintCode == 5) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Broken yellow line with parallel solid yellow line
if (aPaintCode == 6) return osg::Vec4f(0.5f, 0.5f, 0.0f, 1.0f); // Yellow cross-hatched
if (aPaintCode == 7) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Solid Yellow with broken yellow on each side
if (aPaintCode == 8) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Widely separated, broken yellow line
if (aPaintCode == 9) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Widely separated, broken double yellow line
// As above with black border
if (aPaintCode == 51) return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f); // Solid yellow
if (aPaintCode == 52) return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f); // Broken yellow
if (aPaintCode == 53) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Double yellow
if (aPaintCode == 54) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Two broken yellow lines and two solid yellow lines. Broken line on left of string.
if (aPaintCode == 55) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Broken yellow line with parallel solid yellow line
if (aPaintCode == 56) return osg::Vec4f(0.5f, 0.5f, 0.0f, 1.0f); // Yellow cross-hatched
if (aPaintCode == 57) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Solid Yellow with broken yellow on each side
if (aPaintCode == 58) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Widely separated, broken yellow line
if (aPaintCode == 59) return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f); // Widely separated, broken double yellow line
if (aPaintCode == 20) return osg::Vec4f(0.8f, 0.8f, 0.8f, 1.0f); // Solid White
if (aPaintCode == 21) return osg::Vec4f(0.7f, 0.7f, 0.7f, 1.0f); // White chequerboard
if (aPaintCode == 22) return osg::Vec4f(0.6f, 0.6f, 0.6f, 1.0f); // Broken white line
//std::cout << "Unknown line colour " << aPaintCode << "\n";
return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f); // Default (probably an error), so red
}
}
typedef simgear::ModelRegistryCallback<simgear::DefaultProcessPolicy, simgear::NoCachePolicy,
simgear::NoOptimizePolicy,
simgear::NoSubstitutePolicy, simgear::BuildGroupBVHPolicy>
AirportCallback;
namespace
{
osgDB::RegisterReaderWriterProxy<flightgear::AirportBuilder> g_readerAirportBuilder;
simgear::ModelRegistryCallbackProxy<AirportCallback> g_icaoCallbackProxy("icao");
}

View file

@ -0,0 +1,59 @@
// AirportBuilder.hxx -- Builder to create airports based on airport data for
// rendering in the scenery
//
// Written by Stuart Buchanan, started June 2020
//
// Copyright (C) 2020 Stuart Buchanan stuart13@gmail.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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
// $Id$
#include <osgDB/Registry>
#include "airport.hxx"
namespace flightgear
{
static const float RUNWAY_OFFSET = 3.0;
class AirportBuilder : public osgDB::ReaderWriter {
public:
// The different layers are offset to avoid z-buffering issues. As they
// are viewed from above only, this doesn't cause any problems visually.
const float MARKING_OFFSET = 2.0;
const float PAVEMENT_OFFSET = 1.0;
const float BOUNDARY_OFFSET = 0.0;
AirportBuilder();
virtual ~AirportBuilder();
virtual const char* className() const;
virtual ReadResult readNode(const std::string& fileName,
const osgDB::Options* options)
const;
private:
osg::Node* createAirport(const std::string airportId) const;
osg::Node* createRunway(const SGVec3f center, const osg::Vec3f up, const FGRunwayRef runway) const;
osg::Node* createPavement(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const;
osg::Node* createBoundary(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const;
osg::Node* createLine(const SGVec3f center, const osg::Vec3f up, const FGPavementRef pavement) const;
osg::Vec4f getLineColor(const int aPaintCode) const;
};
}

View file

@ -16,6 +16,7 @@ set(SOURCES
airport.cxx airport.cxx
xmlloader.cxx xmlloader.cxx
airportdynamicsmanager.cxx airportdynamicsmanager.cxx
AirportBuilder.cxx
) )
set(HEADERS set(HEADERS
@ -35,6 +36,7 @@ set(HEADERS
airport.hxx airport.hxx
xmlloader.hxx xmlloader.hxx
airportdynamicsmanager.hxx airportdynamicsmanager.hxx
AirportBuilder.hxx
) )
flightgear_component(Airports "${SOURCES}" "${HEADERS}") flightgear_component(Airports "${SOURCES}" "${HEADERS}")

View file

@ -354,22 +354,52 @@ FGTaxiwayList FGAirport::getTaxiways() const
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
unsigned int FGAirport::numPavements() const unsigned int FGAirport::numPavements() const
{ {
loadTaxiways();
return mPavements.size(); return mPavements.size();
} }
//------------------------------------------------------------------------------
FGPavementRef FGAirport::getPavementByIndex(unsigned int aIndex) const
{
loadTaxiways();
return loadById<FGPavement>(mPavements, aIndex);
}
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
FGPavementList FGAirport::getPavements() const FGPavementList FGAirport::getPavements() const
{ {
loadTaxiways(); return mPavements;
return loadAllById<FGPavement>(mPavements); }
void FGAirport::addPavement(FGPavementRef pavement)
{
mPavements.push_back(pavement);
}
//------------------------------------------------------------------------------
unsigned int FGAirport::numBoundary() const
{
return mBoundary.size();
}
//------------------------------------------------------------------------------
FGPavementList FGAirport::getBoundary() const
{
return mBoundary;
}
void FGAirport::addBoundary(FGPavementRef boundary)
{
mBoundary.push_back(boundary);
}
//------------------------------------------------------------------------------
unsigned int FGAirport::numLineFeatures() const
{
return mLineFeatures.size();
}
//------------------------------------------------------------------------------
FGPavementList FGAirport::getLineFeatures() const
{
return mLineFeatures;
}
void FGAirport::addLineFeature(FGPavementRef linefeature)
{
mLineFeatures.push_back(linefeature);
} }
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------

View file

@ -167,6 +167,16 @@ class FGAirport : public FGPositioned
unsigned int numPavements() const; unsigned int numPavements() const;
FGPavementRef getPavementByIndex(unsigned int aIndex) const; FGPavementRef getPavementByIndex(unsigned int aIndex) const;
FGPavementList getPavements() const; FGPavementList getPavements() const;
void addPavement(FGPavementRef pavement);
unsigned int numBoundary() const;
FGPavementRef getBoundaryIndex(unsigned int aIndex) const;
FGPavementList getBoundary() const;
void addBoundary(FGPavementRef boundary);
unsigned int numLineFeatures() const;
FGPavementList getLineFeatures() const;
void addLineFeature(FGPavementRef linefeature);
class AirportFilter : public Filter class AirportFilter : public Filter
{ {
@ -365,7 +375,9 @@ private:
mutable PositionedIDVec mHelipads; mutable PositionedIDVec mHelipads;
mutable PositionedIDVec mTaxiways; mutable PositionedIDVec mTaxiways;
PositionedIDVec mPavements; std::vector<FGPavementRef> mPavements;
std::vector<FGPavementRef> mBoundary;
std::vector<FGPavementRef> mLineFeatures;
typedef SGSharedPtr<flightgear::SID> SIDRef; typedef SGSharedPtr<flightgear::SID> SIDRef;
typedef SGSharedPtr<flightgear::STAR> STARRef; typedef SGSharedPtr<flightgear::STAR> STARRef;
@ -385,5 +397,3 @@ const FGAirport *fgFindAirportID( const std::string& id);
double fgGetAirportElev( const std::string& id ); double fgGetAirportElev( const std::string& id );
#endif // _FG_SIMPLE_HXX #endif // _FG_SIMPLE_HXX

View file

@ -30,6 +30,7 @@
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <algorithm>
#include <stdlib.h> // atof(), atoi() #include <stdlib.h> // atof(), atoi()
#include <string.h> // memchr() #include <string.h> // memchr()
#include <ctype.h> // isspace() #include <ctype.h> // isspace()
@ -225,11 +226,46 @@ void APTLoader::loadAirports()
it != airportInfoMap.end(); it++) { it != airportInfoMap.end(); it++) {
// Full path to the apt.dat file this airport info comes from // Full path to the apt.dat file this airport info comes from
const string aptDat = it->second.file.utf8Str(); const string aptDat = it->second.file.utf8Str();
last_apt_id = it->first; // this is just the current airport identifier
// this is just the current airport identifier
last_apt_id = it->first;
RawAirportInfo rawinfo = it->second;
loadAirport(aptDat, last_apt_id, &rawinfo);
nbLoadedAirports++;
if ((nbLoadedAirports % 300) == 0) {
// Every 300 airports
unsigned int percent = nbLoadedAirports * 100 / nbAirports;
cache->setRebuildPhaseProgress(NavDataCache::REBUILD_LOADING_AIRPORTS,
percent);
}
} // of loop over 'airportInfoMap'
SG_LOG( SG_GENERAL, SG_INFO,
"Loaded data for " << nbLoadedAirports << " airports" );
}
// Parse and return specific apt.dat file containing a single airport.
const FGAirport* APTLoader::loadAirportFromFile(std::string id, const SGPath& aptdb_file)
{
std::size_t bytesReadSoFar = 10;
std::size_t totalSizeOfAllAptDatFiles = 100;
readAptDatFile(aptdb_file.str(), bytesReadSoFar, totalSizeOfAllAptDatFiles);
RawAirportInfo rawInfo = airportInfoMap[id];
return loadAirport(aptdb_file.c_str(), id, &rawInfo, true);
}
const FGAirport* APTLoader::loadAirport(const string aptDat, const std::string airportID, RawAirportInfo* airport_info, bool createFGAirport)
{
// The first line for this airport was already split over whitespace, but // The first line for this airport was already split over whitespace, but
// remains to be parsed for the most part. // remains to be parsed for the most part.
parseAirportLine(it->second.rowCode, it->second.firstLineTokens); parseAirportLine(airport_info->rowCode, airport_info->firstLineTokens);
const LinesList& lines = it->second.otherLines; const LinesList& lines = airport_info->otherLines;
NodeBlock current_block = None;
// Loop over the second and subsequent lines // Loop over the second and subsequent lines
for (LinesList::const_iterator linesIt = lines.begin(); for (LinesList::const_iterator linesIt = lines.begin();
@ -268,18 +304,36 @@ void APTLoader::loadAirports()
parseCommLine(aptDat, linesIt->number, rowCode, parseCommLine(aptDat, linesIt->number, rowCode,
simgear::strutils::split(linesIt->str)); simgear::strutils::split(linesIt->str));
} else if ( rowCode == 110 ) { } else if ( rowCode == 110 ) {
pavement = true; current_block = Pavement;
parsePavementLine850(simgear::strutils::split(linesIt->str, 0, 4)); parsePavementLine850(simgear::strutils::split(linesIt->str, 0, 4));
} else if ( rowCode >= 111 && rowCode <= 114 ) { } else if ( rowCode >= 111 && rowCode <= 116 ) {
if ( pavement ) switch(current_block) {
parsePavementNodeLine850(aptDat, linesIt->number, rowCode, case Pavement :
parseNodeLine850(&pavements, aptDat, linesIt->number, rowCode,
simgear::strutils::split(linesIt->str)); simgear::strutils::split(linesIt->str));
} else if ( rowCode >= 115 && rowCode <= 116 ) { break;
// other pavement nodes (ignore) case AirportBoundary :
parseNodeLine850(&airport_boundary, aptDat, linesIt->number, rowCode,
simgear::strutils::split(linesIt->str));
break;
case LinearFeature :
parseNodeLine850(&linear_feature, aptDat, linesIt->number, rowCode,
simgear::strutils::split(linesIt->str));
break;
default :
case None :
std::ostringstream oss;
string cleanedLine = cleanLine(linesIt->str);
oss << aptDat << ":" << linesIt->number << ": unexpected row code " <<
rowCode;
SG_LOG( SG_GENERAL, SG_ALERT, oss.str() << " (" << cleanedLine << ")" );
throw sg_format_exception(oss.str(), cleanedLine);
break;
}
} else if ( rowCode == 120 ) { } else if ( rowCode == 120 ) {
pavement = false; current_block = LinearFeature;
} else if ( rowCode == 130 ) { } else if ( rowCode == 130 ) {
pavement = false; current_block = AirportBoundary;
} else if ( rowCode >= 1000 ) { } else if ( rowCode >= 1000 ) {
// airport traffic flow (ignore) // airport traffic flow (ignore)
} else { } else {
@ -293,19 +347,38 @@ void APTLoader::loadAirports()
} // of loop over the second and subsequent apt.dat lines for the airport } // of loop over the second and subsequent apt.dat lines for the airport
finishAirport(aptDat); finishAirport(aptDat);
nbLoadedAirports++;
if ((nbLoadedAirports % 300) == 0) { if (createFGAirport) {
// Every 300 airports FGAirportRef airport = FGAirport::findByIdent(airportID);
unsigned int percent = nbLoadedAirports * 100 / nbAirports;
cache->setRebuildPhaseProgress(NavDataCache::REBUILD_LOADING_AIRPORTS,
percent);
}
} // of loop over 'airportInfoMap'
SG_LOG( SG_GENERAL, SG_INFO, std::for_each(
"Loaded data for " << nbLoadedAirports << " airports" ); pavements.begin(),
pavements.end(),
[airport] (FGPavementRef p) { airport->addPavement(p); } );
std::for_each(
airport_boundary.begin(),
airport_boundary.end(),
[airport] (FGPavementRef p) { airport->addBoundary(p); } );
std::for_each(
linear_feature.begin(),
linear_feature.end(),
[airport] (FGPavementRef p) { airport->addLineFeature(p); } );
pavements.clear();
airport_boundary.clear();
linear_feature.clear();
return airport;
} else {
// No FGAirport requested
return NULL;
} }
}
// Tell whether an apt.dat line is blank or a comment line // Tell whether an apt.dat line is blank or a comment line
bool APTLoader::isBlankOrCommentLine(const std::string& line) bool APTLoader::isBlankOrCommentLine(const std::string& line)
@ -482,6 +555,11 @@ void APTLoader::parseRunwayLine850(const string& aptDat, unsigned int lineNum,
double width = atof( token[1].c_str() ); double width = atof( token[1].c_str() );
int surface_code = atoi( token[2].c_str() ); int surface_code = atoi( token[2].c_str() );
int shoulder_code = atoi( token[3].c_str() );
float smoothness = atof( token[4].c_str() );
int center_lights = atoi( token[5].c_str() );
int edge_lights = atoi( token[6].c_str() );
int distance_remaining = atoi( token[7].c_str() );
double lat_1 = atof( token[9].c_str() ); double lat_1 = atof( token[9].c_str() );
double lon_1 = atof( token[10].c_str() ); double lon_1 = atof( token[10].c_str() );
@ -513,17 +591,33 @@ void APTLoader::parseRunwayLine850(const string& aptDat, unsigned int lineNum,
double stopway1 = atof( token[12].c_str() ); double stopway1 = atof( token[12].c_str() );
double stopway2 = atof( token[21].c_str() ); double stopway2 = atof( token[21].c_str() );
int markings1 = atoi( token[13].c_str() );
int markings2 = atoi( token[22].c_str() );
int approach1 = atoi( token[14].c_str() );
int approach2 = atoi( token[23].c_str() );
int tdz1 = atoi( token[15].c_str() );
int tdz2 = atoi( token[24].c_str() );
int reil1 = atoi( token[16].c_str() );
int reil2 = atoi( token[25].c_str() );
PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1, PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1,
currentAirportPosID, heading_1, length, currentAirportPosID, heading_1, length,
width, displ_thresh1, stopway1, width, displ_thresh1, stopway1, markings1,
surface_code); approach1, tdz1, reil1,
surface_code, shoulder_code, smoothness,
center_lights, edge_lights, distance_remaining);
PositionedID reciprocal = cache->insertRunway( PositionedID reciprocal = cache->insertRunway(
FGPositioned::RUNWAY, FGPositioned::RUNWAY,
rwy_no_2, pos_2, rwy_no_2, pos_2,
currentAirportPosID, heading_2, length, currentAirportPosID, heading_2, length,
width, displ_thresh2, stopway2, width, displ_thresh2, stopway2, markings2,
surface_code); approach2, tdz2, reil2,
surface_code, shoulder_code, smoothness,
center_lights, edge_lights, distance_remaining);
cache->setRunwayReciprocal(rwy, reciprocal); cache->setRunwayReciprocal(rwy, reciprocal);
} }
@ -563,9 +657,11 @@ void APTLoader::parseWaterRunwayLine850(const string& aptDat,
const string& rwy_no_1(token[3]); const string& rwy_no_1(token[3]);
const string& rwy_no_2(token[6]); const string& rwy_no_2(token[6]);
// For water runways we overload the edge_lights to indicate use of buoys,
// as they too will be objects. Also, water runways don't have edge lights.
PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1, PositionedID rwy = cache->insertRunway(FGPositioned::RUNWAY, rwy_no_1, pos_1,
currentAirportPosID, heading_1, length, currentAirportPosID, heading_1, length,
width, 0.0, 0.0, 13); width, 0.0, 0.0, 0, 0, 0, 0, 13, 0, 1.0, 0, 1, 0);
PositionedID reciprocal = cache->insertRunway( PositionedID reciprocal = cache->insertRunway(
FGPositioned::RUNWAY, FGPositioned::RUNWAY,
@ -602,10 +698,15 @@ void APTLoader::parseHelipadLine850(const string& aptDat, unsigned int lineNum,
const string& rwy_no(token[1]); const string& rwy_no(token[1]);
int surface_code = atoi( token[7].c_str() ); int surface_code = atoi( token[7].c_str() );
int markings = atoi( token[8].c_str() );
int shoulder_code = atoi( token[9].c_str() );
float smoothness = atof( token[10].c_str() );
int edge_lights = atoi( token[11].c_str() );
cache->insertRunway(FGPositioned::HELIPAD, rwy_no, pos, cache->insertRunway(FGPositioned::HELIPAD, rwy_no, pos,
currentAirportPosID, heading, length, currentAirportPosID, heading, length,
width, 0.0, 0.0, surface_code); width, 0.0, 0.0, markings, 0, 0, 0,
surface_code, shoulder_code, smoothness, 0, edge_lights, 0);
} }
void APTLoader::parseViewpointLine(const string& aptDat, unsigned int lineNum, void APTLoader::parseViewpointLine(const string& aptDat, unsigned int lineNum,
@ -636,12 +737,13 @@ void APTLoader::parsePavementLine850(const vector<string>& token)
} }
} }
void APTLoader::parsePavementNodeLine850(const string& aptDat, void APTLoader::parseNodeLine850(NodeList *nodelist,
const string& aptDat,
unsigned int lineNum, int rowCode, unsigned int lineNum, int rowCode,
const vector<string>& token) const vector<string>& token)
{ {
static const unsigned int minNbTokens[] = {3, 5, 3, 5}; static const unsigned int minNbTokens[] = {3, 5, 3, 5, 3, 5};
assert(111 <= rowCode && rowCode <= 114); assert(111 <= rowCode && rowCode <= 116);
if (token.size() < minNbTokens[rowCode-111]) { if (token.size() < minNbTokens[rowCode-111]) {
SG_LOG( SG_GENERAL, SG_WARN, SG_LOG( SG_GENERAL, SG_WARN,
@ -656,20 +758,37 @@ void APTLoader::parsePavementNodeLine850(const string& aptDat,
SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0)); SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0));
FGPavement* pvt = 0; FGPavement* pvt = 0;
if ( !pavement_ident.empty() ) { if (( !pavement_ident.empty() ) || ( nodelist->size() == 0 )) {
pvt = new FGPavement( 0, pavement_ident, pos ); pvt = new FGPavement( 0, pavement_ident, pos );
pavements.push_back( pvt ); nodelist->push_back( pvt );
pavement_ident = ""; pavement_ident = "";
} else { } else {
pvt = pavements.back(); pvt = nodelist->back();
} }
if ( rowCode == 112 || rowCode == 114 ) {
int paintCode = 0;
int lightCode = 0;
// Line information. The 2nd last token is the painted line type. Last token
// is the light type of the segment. Only applicable to codes 111-114.
if ((rowCode < 115) && (token.size() == (minNbTokens[rowCode-111] + 1))) {
// We've got a line paint code but no lighting code
paintCode = atoi(token[minNbTokens[rowCode-111]].c_str());
}
if ((rowCode < 115) && (token.size() == (minNbTokens[rowCode-111] + 2))) {
// We've got a line paint code and a lighting code
paintCode = atoi(token[minNbTokens[rowCode-111] -1].c_str());
lightCode = atoi(token[minNbTokens[rowCode-111]].c_str());
}
if ((rowCode == 112) || (rowCode == 114) || (rowCode == 116)) {
double lat_b = atof( token[3].c_str() ); double lat_b = atof( token[3].c_str() );
double lon_b = atof( token[4].c_str() ); double lon_b = atof( token[4].c_str() );
SGGeod pos_b(SGGeod::fromDegFt(lon_b, lat_b, 0.0)); SGGeod pos_b(SGGeod::fromDegFt(lon_b, lat_b, 0.0));
pvt->addBezierNode(pos, pos_b, rowCode == 114); pvt->addBezierNode(pos, pos_b, (rowCode == 114) || (rowCode == 116), (rowCode == 114), paintCode, lightCode);
} else { } else {
pvt->addNode(pos, rowCode == 113); pvt->addNode(pos, (rowCode == 113) || (rowCode == 115), (rowCode == 113), paintCode, lightCode);
} }
} }

View file

@ -28,6 +28,7 @@
#include <string> #include <string>
#include <vector> #include <vector>
#include <unordered_map> #include <unordered_map>
#include "airport.hxx"
#include <simgear/compiler.h> #include <simgear/compiler.h>
#include <simgear/structure/SGSharedPtr.hxx> #include <simgear/structure/SGSharedPtr.hxx>
@ -58,6 +59,10 @@ public:
// 'airportInfoMap' has only one entry per airport). // 'airportInfoMap' has only one entry per airport).
void loadAirports(); void loadAirports();
// Load a specific airport defined in aptdb_file, and return a "rich" view
// of the airport including taxiways, pavement and line features.
const FGAirport* loadAirportFromFile(std::string id, const SGPath& aptdb_file);
private: private:
struct Line struct Line
{ {
@ -88,10 +93,13 @@ private:
typedef std::unordered_map<std::string, RawAirportInfo> AirportInfoMapType; typedef std::unordered_map<std::string, RawAirportInfo> AirportInfoMapType;
typedef SGSharedPtr<FGPavement> FGPavementPtr; typedef SGSharedPtr<FGPavement> FGPavementPtr;
typedef std::vector<FGPavementPtr> NodeList;
APTLoader(const APTLoader&); // disable copy constructor APTLoader(const APTLoader&); // disable copy constructor
APTLoader& operator=(const APTLoader&); // disable copy-assignment operator APTLoader& operator=(const APTLoader&); // disable copy-assignment operator
const FGAirport* loadAirport(const string aptDat, const std::string airportID, RawAirportInfo* airport_info, bool createFGAirport=false);
// Tell whether an apt.dat line is blank or a comment line // Tell whether an apt.dat line is blank or a comment line
bool isBlankOrCommentLine(const std::string& line); bool isBlankOrCommentLine(const std::string& line);
// Return a copy of 'line' with trailing '\r' char(s) removed // Return a copy of 'line' with trailing '\r' char(s) removed
@ -112,9 +120,11 @@ private:
void parseViewpointLine(const std::string& aptDat, unsigned int lineNum, void parseViewpointLine(const std::string& aptDat, unsigned int lineNum,
const std::vector<std::string>& token); const std::vector<std::string>& token);
void parsePavementLine850(const std::vector<std::string>& token); void parsePavementLine850(const std::vector<std::string>& token);
void parsePavementNodeLine850( void parseNodeLine850(
NodeList *nodelist,
const std::string& aptDat, unsigned int lineNum, int rowCode, const std::string& aptDat, unsigned int lineNum, int rowCode,
const std::vector<std::string>& token); const std::vector<std::string>& token);
void parseCommLine( void parseCommLine(
const std::string& aptDat, unsigned int lineNum, unsigned int rowCode, const std::string& aptDat, unsigned int lineNum, unsigned int rowCode,
const std::vector<std::string>& token); const std::vector<std::string>& token);
@ -130,12 +140,17 @@ private:
SGGeod tower; SGGeod tower;
std::string pavement_ident; std::string pavement_ident;
bool pavement; NodeList pavements;
std::vector<FGPavementPtr> pavements; NodeList airport_boundary;
NodeList linear_feature;
// Not an airport identifier in the sense of the apt.dat spec! // Not an airport identifier in the sense of the apt.dat spec!
PositionedID currentAirportPosID; PositionedID currentAirportPosID;
NavDataCache* cache; NavDataCache* cache;
// Enum to keep track of whether we are tracking a pavement, airport boundary
// or linear feature when parsing the file.
enum NodeBlock { None, Pavement, AirportBoundary, LinearFeature};
}; };
bool metarDataLoad(const SGPath& path); bool metarDataLoad(const SGPath& path);

View file

@ -29,12 +29,12 @@ FGPavement::FGPavement(PositionedID aGuid, const std::string& aIdent, const SGGe
{ {
} }
void FGPavement::addNode(const SGGeod &aPos, bool aClose) void FGPavement::addNode(const SGGeod &aPos, bool aClose, bool aLoop, int aPaintCode, int aLightCode)
{ {
mNodes.push_back(new SimpleNode(aPos, aClose)); mNodes.push_back(new SimpleNode(aPos, aClose, aLoop, aPaintCode, aLightCode));
} }
void FGPavement::addBezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, bool aClose) void FGPavement::addBezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, bool aClose, bool aLoop, int aPaintCode, int aLightCode)
{ {
mNodes.push_back(new BezierNode(aPos, aCtrlPt, aClose)); mNodes.push_back(new BezierNode(aPos, aCtrlPt, aClose, aLoop, aPaintCode, aLightCode));
} }

View file

@ -38,21 +38,30 @@ public:
{ {
SGGeod mPos; SGGeod mPos;
bool mClose; bool mClose;
bool mLoop;
int mPaintCode;
int mLightCode;
virtual ~NodeBase(){} // To enable RTTI virtual ~NodeBase(){} // To enable RTTI
}; };
struct SimpleNode : public NodeBase //111,113 struct SimpleNode : public NodeBase //111,113,115
{ {
SimpleNode(const SGGeod &aPos, bool aClose) { SimpleNode(const SGGeod &aPos, bool aClose, bool aLoop, int aPaintCode, int aLightCode) {
mPos = aPos; mPos = aPos;
mClose = aClose; mClose = aClose;
mLoop = aLoop;
mPaintCode = aPaintCode;
mLightCode = aLightCode;
} }
}; };
struct BezierNode : public NodeBase //112,114 struct BezierNode : public NodeBase //112,114,116
{ {
BezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, bool aClose) { BezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, bool aClose, bool aLoop, int aPaintCode, int aLightCode) {
mPos = aPos; mPos = aPos;
mClose = aClose; mClose = aClose;
mLoop = aLoop;
mControl = aCtrlPt; mControl = aCtrlPt;
mPaintCode = aPaintCode;
mLightCode = mLightCode;
} }
SGGeod mControl; SGGeod mControl;
}; };
@ -61,8 +70,8 @@ public:
FGPavement(PositionedID aGuid, const std::string& aIdent, const SGGeod& aPos); FGPavement(PositionedID aGuid, const std::string& aIdent, const SGGeod& aPos);
void addNode(const SGGeod &aPos, bool aClose = false); void addNode(const SGGeod &aPos, bool aClose = false, bool aLoop = false, int paintCode = 0, int lightCode = 0);
void addBezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, bool aClose = false); void addBezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, bool aClose = false, bool aLoop = false, int paintCode = 0, int lightCode = 0);
const NodeList &getNodeList() const { return mNodes; } const NodeList &getNodeList() const { return mNodes; }

View file

@ -248,10 +248,11 @@ void GroundRadar::updateTexture()
osg::Geometry *pvt_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(1)); osg::Geometry *pvt_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(1));
osg::Geometry::PrimitiveSetList &pvt_prim_list = pvt_geom->getPrimitiveSetList(); osg::Geometry::PrimitiveSetList &pvt_prim_list = pvt_geom->getPrimitiveSetList();
pvt_prim_list.clear(); pvt_prim_list.clear();
for (unsigned int i=0; i<apt->numPavements(); ++i)
auto pavementlist = airport->getPavements();
for (auto pvtiter = pavementlist.begin(); pvtiter != pavementlist.end(); ++pvtiter)
{ {
FGPavement* pvt(apt->getPavementByIndex(i)); osg::ref_ptr<osg::Geometry> geom = addPavementGeometry(*pvtiter, tower_lat, tower_lon, scale);
osg::ref_ptr<osg::Geometry> geom = addPavementGeometry(pvt, tower_lat, tower_lon, scale);
osg::Geometry::PrimitiveSetList &prim_list = geom->getPrimitiveSetList(); osg::Geometry::PrimitiveSetList &prim_list = geom->getPrimitiveSetList();
osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array *>(geom->getVertexArray()); osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array *>(geom->getVertexArray());
size_t before = pvt_vertices->size(), size_t before = pvt_vertices->size(),

View file

@ -657,8 +657,10 @@ void AirportDiagram::buildTaxiways()
void AirportDiagram::buildPavements() void AirportDiagram::buildPavements()
{ {
m_pavements.clear(); m_pavements.clear();
for (unsigned int pIndex=0; pIndex < m_airport->numPavements(); ++pIndex) { auto pavementlist = m_airport->getPavements();
FGPavementRef pave = m_airport->getPavementByIndex(pIndex); for (auto pvtiter = pavementlist.begin(); pvtiter != pavementlist.end(); ++pvtiter)
{
FGPavementRef pave = *pvtiter;
if (pave->getNodeList().empty()) { if (pave->getNodeList().empty()) {
continue; continue;
} }

View file

@ -1816,7 +1816,9 @@ PositionedID
NavDataCache::insertRunway(FGPositioned::Type ty, const string& ident, NavDataCache::insertRunway(FGPositioned::Type ty, const string& ident,
const SGGeod& pos, PositionedID apt, const SGGeod& pos, PositionedID apt,
double heading, double length, double width, double displacedThreshold, double heading, double length, double width, double displacedThreshold,
double stopway, int surfaceCode) double stopway, int markings, int approach, int tdz, int reil,
int surfaceCode, int shoulder_code, float smoothness, int center_lights,
int edge_lights, int distance_remaining)
{ {
// only runways are spatially indexed; don't bother indexing taxiways // only runways are spatially indexed; don't bother indexing taxiways
// or pavements // or pavements
@ -1831,10 +1833,31 @@ NavDataCache::insertRunway(FGPositioned::Type ty, const string& ident,
sqlite3_bind_int(d->insertRunway, 5, surfaceCode); sqlite3_bind_int(d->insertRunway, 5, surfaceCode);
sqlite3_bind_double(d->insertRunway, 6, displacedThreshold); sqlite3_bind_double(d->insertRunway, 6, displacedThreshold);
sqlite3_bind_double(d->insertRunway, 7, stopway); sqlite3_bind_double(d->insertRunway, 7, stopway);
sqlite3_bind_int(d->insertRunway, 8, markings);
sqlite3_bind_int(d->insertRunway, 9, approach);
sqlite3_bind_int(d->insertRunway, 10, tdz);
sqlite3_bind_int(d->insertRunway, 11, reil);
sqlite3_bind_int(d->insertRunway, 12, shoulder_code);
sqlite3_bind_double(d->insertRunway, 13, smoothness);
sqlite3_bind_int(d->insertRunway, 14, center_lights);
sqlite3_bind_int(d->insertRunway, 15, edge_lights);
sqlite3_bind_int(d->insertRunway, 116, distance_remaining);
return d->execInsert(d->insertRunway); return d->execInsert(d->insertRunway);
} }
PositionedID
NavDataCache::insertRunway(FGPositioned::Type ty, const string& ident,
const SGGeod& pos, PositionedID apt,
double heading, double length, double width, double displacedThreshold,
double stopway, int surfaceCode)
{
return insertRunway(ty, ident, pos, apt,
heading, length, width, displacedThreshold,
stopway, 0, 0, 0, 0,
surfaceCode, 0, 0.0f, 0, 0, 0);
}
void NavDataCache::setRunwayReciprocal(PositionedID runway, PositionedID recip) void NavDataCache::setRunwayReciprocal(PositionedID runway, PositionedID recip)
{ {
sqlite3_bind_int64(d->setRunwayReciprocal, 1, runway); sqlite3_bind_int64(d->setRunwayReciprocal, 1, runway);

View file

@ -160,10 +160,20 @@ public:
PositionedID insertAirport(FGPositioned::Type ty, const std::string& ident, PositionedID insertAirport(FGPositioned::Type ty, const std::string& ident,
const std::string& name); const std::string& name);
void insertTower(PositionedID airportId, const SGGeod& pos); void insertTower(PositionedID airportId, const SGGeod& pos);
PositionedID insertRunway(FGPositioned::Type ty, const std::string& ident,
PositionedID insertRunway(FGPositioned::Type ty, const string& ident,
const SGGeod& pos, PositionedID apt,
double heading, double length, double width, double displacedThreshold,
double stopway, int markings, int approach, int tdz, int reil,
int surfaceCode, int shoulder_code, float smoothness, int center_lights,
int edge_lights, int distance_remaining);
PositionedID insertRunway(FGPositioned::Type ty, const string& ident,
const SGGeod& pos, PositionedID apt, const SGGeod& pos, PositionedID apt,
double heading, double length, double width, double displacedThreshold, double heading, double length, double width, double displacedThreshold,
double stopway, int surfaceCode); double stopway, int surfaceCode);
void setRunwayReciprocal(PositionedID runway, PositionedID recip); void setRunwayReciprocal(PositionedID runway, PositionedID recip);
void setRunwayILS(PositionedID runway, PositionedID ils); void setRunwayILS(PositionedID runway, PositionedID ils);