AirportBuilder to generate airports from apt.dat
This commit is contained in:
parent
bb75d24fc0
commit
c4942eaa69
13 changed files with 1030 additions and 181 deletions
569
src/Airports/AirportBuilder.cxx
Normal file
569
src/Airports/AirportBuilder.cxx
Normal 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");
|
||||
}
|
59
src/Airports/AirportBuilder.hxx
Normal file
59
src/Airports/AirportBuilder.hxx
Normal 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;
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -15,11 +15,12 @@ set(SOURCES
|
|||
sidstar.cxx
|
||||
airport.cxx
|
||||
xmlloader.cxx
|
||||
airportdynamicsmanager.cxx
|
||||
airportdynamicsmanager.cxx
|
||||
AirportBuilder.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
airports_fwd.hxx
|
||||
airports_fwd.hxx
|
||||
apt_loader.hxx
|
||||
dynamicloader.hxx
|
||||
dynamics.hxx
|
||||
|
@ -34,7 +35,8 @@ set(HEADERS
|
|||
sidstar.hxx
|
||||
airport.hxx
|
||||
xmlloader.hxx
|
||||
airportdynamicsmanager.hxx
|
||||
airportdynamicsmanager.hxx
|
||||
AirportBuilder.hxx
|
||||
)
|
||||
|
||||
|
||||
flightgear_component(Airports "${SOURCES}" "${HEADERS}")
|
||||
|
|
|
@ -354,22 +354,52 @@ FGTaxiwayList FGAirport::getTaxiways() const
|
|||
//------------------------------------------------------------------------------
|
||||
unsigned int FGAirport::numPavements() const
|
||||
{
|
||||
loadTaxiways();
|
||||
return mPavements.size();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGPavementRef FGAirport::getPavementByIndex(unsigned int aIndex) const
|
||||
{
|
||||
loadTaxiways();
|
||||
return loadById<FGPavement>(mPavements, aIndex);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
FGPavementList FGAirport::getPavements() const
|
||||
{
|
||||
loadTaxiways();
|
||||
return loadAllById<FGPavement>(mPavements);
|
||||
return 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);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
@ -1001,7 +1031,7 @@ Transition *FGAirport::selectSIDByTransition(const FGRunway* runway, const stri
|
|||
for (auto sid : mSIDs) {
|
||||
if (runway && !sid->isForRunway(runway))
|
||||
continue;
|
||||
|
||||
|
||||
auto trans = sid->findTransitionByName(aIdent);
|
||||
if (trans) {
|
||||
return trans;
|
||||
|
@ -1028,7 +1058,7 @@ Transition *FGAirport::selectSTARByTransition(const FGRunway* runway, const stri
|
|||
for (auto star : mSTARs) {
|
||||
if (runway && !star->isForRunway(runway))
|
||||
continue;
|
||||
|
||||
|
||||
auto trans = star->findTransitionByName(aIdent);
|
||||
if (trans) {
|
||||
return trans;
|
||||
|
|
|
@ -94,7 +94,7 @@ class FGAirport : public FGPositioned
|
|||
FGRunwayRef getActiveRunwayForUsage() const;
|
||||
|
||||
FGAirportDynamicsRef getDynamics() const;
|
||||
|
||||
|
||||
FGGroundNetwork* groundNetwork() const;
|
||||
|
||||
unsigned int numRunways() const;
|
||||
|
@ -124,7 +124,7 @@ class FGAirport : public FGPositioned
|
|||
double ilsWeight;
|
||||
};
|
||||
FGRunwayRef findBestRunwayForHeading(double aHeading, struct FindBestRunwayForHeadingParams * parms = NULL ) const;
|
||||
|
||||
|
||||
/**
|
||||
* return the most likely target runway based on a position.
|
||||
* Specifically, return the runway for which the course from aPos
|
||||
|
@ -133,7 +133,7 @@ class FGAirport : public FGPositioned
|
|||
* aiming towards.
|
||||
*/
|
||||
FGRunwayRef findBestRunwayForPos(const SGGeod& aPos) const;
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve all runways at the airport, but excluding the reciprocal
|
||||
* runways. For example at KSFO this might return 1L, 1R, 28L and 28R,
|
||||
|
@ -151,7 +151,7 @@ class FGAirport : public FGPositioned
|
|||
* Retrieve all runways at the airport
|
||||
*/
|
||||
FGRunwayList getRunways() const;
|
||||
|
||||
|
||||
/**
|
||||
* Useful predicate for FMS/GPS/NAV displays and similar - check if this
|
||||
* aiport has a hard-surfaced runway of at least the specified length.
|
||||
|
@ -167,7 +167,17 @@ class FGAirport : public FGPositioned
|
|||
unsigned int numPavements() const;
|
||||
FGPavementRef getPavementByIndex(unsigned int aIndex) 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
|
||||
{
|
||||
public:
|
||||
|
@ -187,7 +197,7 @@ class FGAirport : public FGPositioned
|
|||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Filter which passes heliports and seaports in addition to airports
|
||||
*/
|
||||
|
@ -198,18 +208,18 @@ class FGAirport : public FGPositioned
|
|||
return SEAPORT;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class HardSurfaceFilter : public AirportFilter
|
||||
{
|
||||
public:
|
||||
HardSurfaceFilter(double minLengthFt = -1);
|
||||
|
||||
|
||||
virtual bool passAirport(FGAirport* aApt) const;
|
||||
|
||||
|
||||
private:
|
||||
double mMinLengthFt;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Filter which passes specified port type and in case of airport checks
|
||||
* if a runway larger the /sim/navdb/min-runway-lenght-ft exists.
|
||||
|
@ -234,11 +244,11 @@ class FGAirport : public FGPositioned
|
|||
double _min_runway_length_ft;
|
||||
};
|
||||
|
||||
|
||||
|
||||
void setProcedures(const std::vector<flightgear::SID*>& aSids,
|
||||
const std::vector<flightgear::STAR*>& aStars,
|
||||
const std::vector<flightgear::Approach*>& aApproaches);
|
||||
|
||||
|
||||
void addSID(flightgear::SID* aSid);
|
||||
void addSTAR(flightgear::STAR* aStar);
|
||||
void addApproach(flightgear::Approach* aApp);
|
||||
|
@ -247,7 +257,7 @@ class FGAirport : public FGPositioned
|
|||
flightgear::SID* getSIDByIndex(unsigned int aIndex) const;
|
||||
flightgear::SID* findSIDWithIdent(const std::string& aIdent) const;
|
||||
flightgear::SIDList getSIDs() const;
|
||||
|
||||
|
||||
flightgear::Transition* selectSIDByEnrouteTransition(FGPositioned* enroute) const;
|
||||
flightgear::Transition* selectSIDByTransition(const FGRunway* runway, const std::string& aIdent) const;
|
||||
|
||||
|
@ -255,7 +265,7 @@ class FGAirport : public FGPositioned
|
|||
flightgear::STAR* getSTARByIndex(unsigned int aIndex) const;
|
||||
flightgear::STAR* findSTARWithIdent(const std::string& aIdent) const;
|
||||
flightgear::STARList getSTARs() const;
|
||||
|
||||
|
||||
flightgear::Transition* selectSTARByEnrouteTransition(FGPositioned* enroute) const;
|
||||
flightgear::Transition* selectSTARByTransition(const FGRunway* runway, const std::string& aIdent) const;
|
||||
|
||||
|
@ -266,48 +276,48 @@ class FGAirport : public FGPositioned
|
|||
(
|
||||
flightgear::ProcedureType type = flightgear::PROCEDURE_INVALID
|
||||
) const;
|
||||
|
||||
|
||||
/**
|
||||
* Syntactic wrapper around FGPositioned::findClosest - find the closest
|
||||
* match for filter, and return it cast to FGAirport. The default filter
|
||||
* passes airports, but not seaports or heliports
|
||||
*/
|
||||
static FGAirportRef findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter = NULL);
|
||||
|
||||
|
||||
/**
|
||||
* Helper to look up an FGAirport instance by unique ident. Throws an
|
||||
* Helper to look up an FGAirport instance by unique ident. Throws an
|
||||
* exception if the airport could not be found - so callers can assume
|
||||
* the result is non-NULL.
|
||||
*/
|
||||
static FGAirportRef getByIdent(const std::string& aIdent);
|
||||
|
||||
|
||||
/**
|
||||
* Helper to look up an FGAirport instance by unique ident. Returns NULL
|
||||
* if the airport could not be found.
|
||||
*/
|
||||
static FGAirportRef findByIdent(const std::string& aIdent);
|
||||
|
||||
|
||||
/**
|
||||
* Specialised helper to implement the AirportList dialog. Performs a
|
||||
* case-insensitive search on airport names and ICAO codes, and returns
|
||||
* matches in a format suitable for use by a puaList.
|
||||
* matches in a format suitable for use by a puaList.
|
||||
*/
|
||||
static char** searchNamesAndIdents(const std::string& aFilter);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Sort an FGPositionedList of airports by size (number of runways + length)
|
||||
* this is meant to prioritise more important airports.
|
||||
*/
|
||||
static void sortBySize(FGPositionedList&);
|
||||
|
||||
|
||||
flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const;
|
||||
|
||||
|
||||
flightgear::CommStationList commStations() const;
|
||||
|
||||
|
||||
static void clearAirportsCache();
|
||||
|
||||
|
||||
|
||||
|
||||
#if defined(BUILDING_TESTSUITE)
|
||||
// helper to allow testing without needing a full Airports heirarchy
|
||||
void testSuiteInjectGroundnetXML(const SGPath& path);
|
||||
|
@ -318,29 +328,29 @@ private:
|
|||
// disable these
|
||||
FGAirport operator=(FGAirport &other);
|
||||
FGAirport(const FGAirport&);
|
||||
|
||||
|
||||
/**
|
||||
* helper to read airport data from the scenery XML files.
|
||||
*/
|
||||
void loadSceneryDefinitions() const;
|
||||
|
||||
|
||||
/**
|
||||
* Helpers to process property data loaded from an ICAO.threshold.xml file
|
||||
*/
|
||||
void readThresholdData(SGPropertyNode* aRoot);
|
||||
void processThreshold(SGPropertyNode* aThreshold);
|
||||
|
||||
|
||||
void readILSData(SGPropertyNode* aRoot);
|
||||
|
||||
|
||||
void validateTowerData() const;
|
||||
|
||||
|
||||
/**
|
||||
* Helper to parse property data loaded from an ICAO.twr.xml file
|
||||
*/
|
||||
void readTowerData(SGPropertyNode* aRoot);
|
||||
|
||||
|
||||
PositionedIDVec itemsOfType(FGPositioned::Type ty) const;
|
||||
|
||||
|
||||
std::string _name;
|
||||
bool _has_metar;
|
||||
|
||||
|
@ -348,11 +358,11 @@ private:
|
|||
void loadHelipads() const;
|
||||
void loadTaxiways() const;
|
||||
void loadProcedures() const;
|
||||
|
||||
|
||||
mutable bool mTowerDataLoaded;
|
||||
mutable bool mHasTower;
|
||||
mutable SGGeod mTowerPosition;
|
||||
|
||||
|
||||
mutable bool mRunwaysLoaded;
|
||||
mutable bool mHelipadsLoaded;
|
||||
mutable bool mTaxiwaysLoaded;
|
||||
|
@ -362,15 +372,17 @@ private:
|
|||
bool mILSDataLoaded;
|
||||
|
||||
mutable std::vector<FGRunwayRef> mRunways;
|
||||
|
||||
|
||||
mutable PositionedIDVec mHelipads;
|
||||
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::STAR> STARRef;
|
||||
typedef SGSharedPtr<flightgear::Approach> ApproachRef;
|
||||
|
||||
|
||||
std::vector<SIDRef> mSIDs;
|
||||
std::vector<STARRef> mSTARs;
|
||||
std::vector<ApproachRef> mApproaches;
|
||||
|
@ -385,5 +397,3 @@ const FGAirport *fgFindAirportID( const std::string& id);
|
|||
double fgGetAirportElev( const std::string& id );
|
||||
|
||||
#endif // _FG_SIMPLE_HXX
|
||||
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include <simgear/compiler.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <stdlib.h> // atof(), atoi()
|
||||
#include <string.h> // memchr()
|
||||
#include <ctype.h> // isspace()
|
||||
|
@ -225,74 +226,12 @@ void APTLoader::loadAirports()
|
|||
it != airportInfoMap.end(); it++) {
|
||||
// Full path to the apt.dat file this airport info comes from
|
||||
const string aptDat = it->second.file.utf8Str();
|
||||
last_apt_id = it->first; // this is just the current airport identifier
|
||||
// The first line for this airport was already split over whitespace, but
|
||||
// remains to be parsed for the most part.
|
||||
parseAirportLine(it->second.rowCode, it->second.firstLineTokens);
|
||||
const LinesList& lines = it->second.otherLines;
|
||||
|
||||
// Loop over the second and subsequent lines
|
||||
for (LinesList::const_iterator linesIt = lines.begin();
|
||||
linesIt != lines.end(); linesIt++) {
|
||||
// Beware that linesIt->str may end with an '\r' character, see above!
|
||||
unsigned int rowCode = linesIt->rowCode;
|
||||
// this is just the current airport identifier
|
||||
last_apt_id = it->first;
|
||||
RawAirportInfo rawinfo = it->second;
|
||||
|
||||
if ( rowCode == 10 ) { // Runway v810
|
||||
parseRunwayLine810(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 100 ) { // Runway v850
|
||||
parseRunwayLine850(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 101 ) { // Water Runway v850
|
||||
parseWaterRunwayLine850(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 102 ) { // Helipad v850
|
||||
parseHelipadLine850(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 18 ) {
|
||||
// beacon entry (ignore)
|
||||
} else if ( rowCode == 14 ) { // Viewpoint/control tower
|
||||
parseViewpointLine(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 19 ) {
|
||||
// windsock entry (ignore)
|
||||
} else if ( rowCode == 20 ) {
|
||||
// Taxiway sign (ignore)
|
||||
} else if ( rowCode == 21 ) {
|
||||
// lighting objects (ignore)
|
||||
} else if ( rowCode == 15 ) {
|
||||
// custom startup locations (ignore)
|
||||
} else if ( rowCode == 0 ) {
|
||||
// ??
|
||||
} else if ( rowCode >= 50 && rowCode <= 56) {
|
||||
parseCommLine(aptDat, linesIt->number, rowCode,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 110 ) {
|
||||
pavement = true;
|
||||
parsePavementLine850(simgear::strutils::split(linesIt->str, 0, 4));
|
||||
} else if ( rowCode >= 111 && rowCode <= 114 ) {
|
||||
if ( pavement )
|
||||
parsePavementNodeLine850(aptDat, linesIt->number, rowCode,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode >= 115 && rowCode <= 116 ) {
|
||||
// other pavement nodes (ignore)
|
||||
} else if ( rowCode == 120 ) {
|
||||
pavement = false;
|
||||
} else if ( rowCode == 130 ) {
|
||||
pavement = false;
|
||||
} else if ( rowCode >= 1000 ) {
|
||||
// airport traffic flow (ignore)
|
||||
} else {
|
||||
std::ostringstream oss;
|
||||
string cleanedLine = cleanLine(linesIt->str);
|
||||
oss << aptDat << ":" << linesIt->number << ": unknown row code " <<
|
||||
rowCode;
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, oss.str() << " (" << cleanedLine << ")" );
|
||||
throw sg_format_exception(oss.str(), cleanedLine);
|
||||
}
|
||||
} // of loop over the second and subsequent apt.dat lines for the airport
|
||||
|
||||
finishAirport(aptDat);
|
||||
loadAirport(aptDat, last_apt_id, &rawinfo);
|
||||
nbLoadedAirports++;
|
||||
|
||||
if ((nbLoadedAirports % 300) == 0) {
|
||||
|
@ -307,6 +246,140 @@ void APTLoader::loadAirports()
|
|||
"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
|
||||
// remains to be parsed for the most part.
|
||||
parseAirportLine(airport_info->rowCode, airport_info->firstLineTokens);
|
||||
const LinesList& lines = airport_info->otherLines;
|
||||
|
||||
NodeBlock current_block = None;
|
||||
|
||||
// Loop over the second and subsequent lines
|
||||
for (LinesList::const_iterator linesIt = lines.begin();
|
||||
linesIt != lines.end(); linesIt++) {
|
||||
// Beware that linesIt->str may end with an '\r' character, see above!
|
||||
unsigned int rowCode = linesIt->rowCode;
|
||||
|
||||
if ( rowCode == 10 ) { // Runway v810
|
||||
parseRunwayLine810(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 100 ) { // Runway v850
|
||||
parseRunwayLine850(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 101 ) { // Water Runway v850
|
||||
parseWaterRunwayLine850(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 102 ) { // Helipad v850
|
||||
parseHelipadLine850(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 18 ) {
|
||||
// beacon entry (ignore)
|
||||
} else if ( rowCode == 14 ) { // Viewpoint/control tower
|
||||
parseViewpointLine(aptDat, linesIt->number,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 19 ) {
|
||||
// windsock entry (ignore)
|
||||
} else if ( rowCode == 20 ) {
|
||||
// Taxiway sign (ignore)
|
||||
} else if ( rowCode == 21 ) {
|
||||
// lighting objects (ignore)
|
||||
} else if ( rowCode == 15 ) {
|
||||
// custom startup locations (ignore)
|
||||
} else if ( rowCode == 0 ) {
|
||||
// ??
|
||||
} else if ( rowCode >= 50 && rowCode <= 56) {
|
||||
parseCommLine(aptDat, linesIt->number, rowCode,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
} else if ( rowCode == 110 ) {
|
||||
current_block = Pavement;
|
||||
parsePavementLine850(simgear::strutils::split(linesIt->str, 0, 4));
|
||||
} else if ( rowCode >= 111 && rowCode <= 116 ) {
|
||||
switch(current_block) {
|
||||
case Pavement :
|
||||
parseNodeLine850(&pavements, aptDat, linesIt->number, rowCode,
|
||||
simgear::strutils::split(linesIt->str));
|
||||
break;
|
||||
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 ) {
|
||||
current_block = LinearFeature;
|
||||
} else if ( rowCode == 130 ) {
|
||||
current_block = AirportBoundary;
|
||||
} else if ( rowCode >= 1000 ) {
|
||||
// airport traffic flow (ignore)
|
||||
} else {
|
||||
std::ostringstream oss;
|
||||
string cleanedLine = cleanLine(linesIt->str);
|
||||
oss << aptDat << ":" << linesIt->number << ": unknown row code " <<
|
||||
rowCode;
|
||||
SG_LOG( SG_GENERAL, SG_ALERT, oss.str() << " (" << cleanedLine << ")" );
|
||||
throw sg_format_exception(oss.str(), cleanedLine);
|
||||
}
|
||||
} // of loop over the second and subsequent apt.dat lines for the airport
|
||||
|
||||
finishAirport(aptDat);
|
||||
|
||||
if (createFGAirport) {
|
||||
FGAirportRef airport = FGAirport::findByIdent(airportID);
|
||||
|
||||
std::for_each(
|
||||
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
|
||||
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() );
|
||||
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 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 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,
|
||||
currentAirportPosID, heading_1, length,
|
||||
width, displ_thresh1, stopway1,
|
||||
surface_code);
|
||||
width, displ_thresh1, stopway1, markings1,
|
||||
approach1, tdz1, reil1,
|
||||
surface_code, shoulder_code, smoothness,
|
||||
center_lights, edge_lights, distance_remaining);
|
||||
|
||||
PositionedID reciprocal = cache->insertRunway(
|
||||
FGPositioned::RUNWAY,
|
||||
rwy_no_2, pos_2,
|
||||
currentAirportPosID, heading_2, length,
|
||||
width, displ_thresh2, stopway2,
|
||||
surface_code);
|
||||
width, displ_thresh2, stopway2, markings2,
|
||||
approach2, tdz2, reil2,
|
||||
surface_code, shoulder_code, smoothness,
|
||||
center_lights, edge_lights, distance_remaining);
|
||||
|
||||
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_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,
|
||||
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(
|
||||
FGPositioned::RUNWAY,
|
||||
|
@ -602,10 +698,15 @@ void APTLoader::parseHelipadLine850(const string& aptDat, unsigned int lineNum,
|
|||
|
||||
const string& rwy_no(token[1]);
|
||||
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,
|
||||
currentAirportPosID, heading, length,
|
||||
width, 0.0, 0.0, surface_code);
|
||||
currentAirportPosID, heading, length,
|
||||
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,
|
||||
|
@ -636,12 +737,13 @@ void APTLoader::parsePavementLine850(const vector<string>& token)
|
|||
}
|
||||
}
|
||||
|
||||
void APTLoader::parsePavementNodeLine850(const string& aptDat,
|
||||
unsigned int lineNum, int rowCode,
|
||||
const vector<string>& token)
|
||||
void APTLoader::parseNodeLine850(NodeList *nodelist,
|
||||
const string& aptDat,
|
||||
unsigned int lineNum, int rowCode,
|
||||
const vector<string>& token)
|
||||
{
|
||||
static const unsigned int minNbTokens[] = {3, 5, 3, 5};
|
||||
assert(111 <= rowCode && rowCode <= 114);
|
||||
static const unsigned int minNbTokens[] = {3, 5, 3, 5, 3, 5};
|
||||
assert(111 <= rowCode && rowCode <= 116);
|
||||
|
||||
if (token.size() < minNbTokens[rowCode-111]) {
|
||||
SG_LOG( SG_GENERAL, SG_WARN,
|
||||
|
@ -656,20 +758,37 @@ void APTLoader::parsePavementNodeLine850(const string& aptDat,
|
|||
SGGeod pos(SGGeod::fromDegFt(lon, lat, 0.0));
|
||||
|
||||
FGPavement* pvt = 0;
|
||||
if ( !pavement_ident.empty() ) {
|
||||
if (( !pavement_ident.empty() ) || ( nodelist->size() == 0 )) {
|
||||
pvt = new FGPavement( 0, pavement_ident, pos );
|
||||
pavements.push_back( pvt );
|
||||
nodelist->push_back( pvt );
|
||||
pavement_ident = "";
|
||||
} 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 lon_b = atof( token[4].c_str() );
|
||||
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 {
|
||||
pvt->addNode(pos, rowCode == 113);
|
||||
pvt->addNode(pos, (rowCode == 113) || (rowCode == 115), (rowCode == 113), paintCode, lightCode);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include "airport.hxx"
|
||||
|
||||
#include <simgear/compiler.h>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
|
@ -58,6 +59,10 @@ public:
|
|||
// 'airportInfoMap' has only one entry per airport).
|
||||
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:
|
||||
struct Line
|
||||
{
|
||||
|
@ -88,10 +93,13 @@ private:
|
|||
|
||||
typedef std::unordered_map<std::string, RawAirportInfo> AirportInfoMapType;
|
||||
typedef SGSharedPtr<FGPavement> FGPavementPtr;
|
||||
typedef std::vector<FGPavementPtr> NodeList;
|
||||
|
||||
APTLoader(const APTLoader&); // disable copy constructor
|
||||
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
|
||||
bool isBlankOrCommentLine(const std::string& line);
|
||||
// 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,
|
||||
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::vector<std::string>& token);
|
||||
|
||||
void parseCommLine(
|
||||
const std::string& aptDat, unsigned int lineNum, unsigned int rowCode,
|
||||
const std::vector<std::string>& token);
|
||||
|
@ -130,12 +140,17 @@ private:
|
|||
SGGeod tower;
|
||||
|
||||
std::string pavement_ident;
|
||||
bool pavement;
|
||||
std::vector<FGPavementPtr> pavements;
|
||||
NodeList pavements;
|
||||
NodeList airport_boundary;
|
||||
NodeList linear_feature;
|
||||
|
||||
// Not an airport identifier in the sense of the apt.dat spec!
|
||||
PositionedID currentAirportPosID;
|
||||
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);
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// pavement.cxx - class to represent complex taxiway specified in v850 apt.dat
|
||||
// pavement.cxx - class to represent complex taxiway specified in v850 apt.dat
|
||||
//
|
||||
// Copyright (C) 2009 Frederic Bouvier
|
||||
//
|
||||
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
// pavement.hxx - class to represent complex taxiway specified in v850 apt.dat
|
||||
// pavement.hxx - class to represent complex taxiway specified in v850 apt.dat
|
||||
//
|
||||
// Copyright (C) 2009 Frederic Bouvier
|
||||
//
|
||||
|
@ -38,21 +38,30 @@ public:
|
|||
{
|
||||
SGGeod mPos;
|
||||
bool mClose;
|
||||
bool mLoop;
|
||||
int mPaintCode;
|
||||
int mLightCode;
|
||||
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;
|
||||
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;
|
||||
mClose = aClose;
|
||||
mLoop = aLoop;
|
||||
mControl = aCtrlPt;
|
||||
mPaintCode = aPaintCode;
|
||||
mLightCode = mLightCode;
|
||||
}
|
||||
SGGeod mControl;
|
||||
};
|
||||
|
@ -61,8 +70,8 @@ public:
|
|||
|
||||
FGPavement(PositionedID aGuid, const std::string& aIdent, const SGGeod& aPos);
|
||||
|
||||
void addNode(const SGGeod &aPos, bool aClose = false);
|
||||
void addBezierNode(const SGGeod &aPos, const SGGeod &aCtrlPt, 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, bool aLoop = false, int paintCode = 0, int lightCode = 0);
|
||||
|
||||
const NodeList &getNodeList() const { return mNodes; }
|
||||
|
||||
|
|
|
@ -79,7 +79,7 @@ GroundRadar::~GroundRadar()
|
|||
|
||||
void GroundRadar::update (double /* dt */)
|
||||
{
|
||||
|
||||
|
||||
}
|
||||
|
||||
void GroundRadar::valueChanged(SGPropertyNode*)
|
||||
|
@ -231,7 +231,7 @@ void GroundRadar::updateTexture()
|
|||
const double tower_lat = tower_location.getLatitudeDeg();
|
||||
const double tower_lon = tower_location.getLongitudeDeg();
|
||||
double scale = SG_METER_TO_NM * 200 / _range_node->getDoubleValue();
|
||||
|
||||
|
||||
const FGAirport* apt = fgFindAirportID(airport_name);
|
||||
assert(apt);
|
||||
|
||||
|
@ -248,10 +248,11 @@ void GroundRadar::updateTexture()
|
|||
osg::Geometry *pvt_geom = dynamic_cast<osg::Geometry *>(_geode->getDrawable(1));
|
||||
osg::Geometry::PrimitiveSetList &pvt_prim_list = pvt_geom->getPrimitiveSetList();
|
||||
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(pvt, tower_lat, tower_lon, scale);
|
||||
osg::ref_ptr<osg::Geometry> geom = addPavementGeometry(*pvtiter, tower_lat, tower_lon, scale);
|
||||
osg::Geometry::PrimitiveSetList &prim_list = geom->getPrimitiveSetList();
|
||||
osg::Vec3Array *vertices = dynamic_cast<osg::Vec3Array *>(geom->getVertexArray());
|
||||
size_t before = pvt_vertices->size(),
|
||||
|
|
|
@ -45,10 +45,10 @@ static double distanceToLineSegment(const QVector2D& p, const QVector2D& a,
|
|||
{
|
||||
QVector2D ab(b - a);
|
||||
QVector2D ac(p - a);
|
||||
|
||||
|
||||
// Squared length, to avoid a sqrt
|
||||
const qreal len2 = ab.lengthSquared();
|
||||
|
||||
|
||||
// Line null, the projection can't exist, we return the first point
|
||||
if (qIsNull(len2)) {
|
||||
if (outT) {
|
||||
|
@ -56,10 +56,10 @@ static double distanceToLineSegment(const QVector2D& p, const QVector2D& a,
|
|||
}
|
||||
return (p - a).length();
|
||||
}
|
||||
|
||||
|
||||
// Parametric value of the projection on the line
|
||||
const qreal t = (ac.x() * ab.x() + ac.y() * ab.y()) / len2;
|
||||
|
||||
|
||||
if (t < 0.0) {
|
||||
// Point is before the first point
|
||||
if (outT) {
|
||||
|
@ -76,11 +76,11 @@ static double distanceToLineSegment(const QVector2D& p, const QVector2D& a,
|
|||
if (outT) {
|
||||
*outT = t;
|
||||
}
|
||||
|
||||
|
||||
const QVector2D proj = a + t * ab;
|
||||
return (proj - p).length();
|
||||
}
|
||||
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
|
@ -345,13 +345,13 @@ void AirportDiagram::paintContents(QPainter* p)
|
|||
if ((r.runway == runwaySelection) || (r.runway->reciprocalRunway() == runwaySelection)) {
|
||||
color = Qt::yellow;
|
||||
}
|
||||
|
||||
|
||||
p->setTransform(t);
|
||||
|
||||
QPen pen(color);
|
||||
pen.setWidth(r.widthM);
|
||||
p->setPen(pen);
|
||||
|
||||
|
||||
p->drawLine(r.p1, r.p2);
|
||||
|
||||
// draw idents
|
||||
|
@ -361,7 +361,7 @@ void AirportDiagram::paintContents(QPainter* p)
|
|||
p->rotate(r.runway->headingDeg());
|
||||
// invert scaling factor so we can use screen pixel sizes here
|
||||
p->scale(1.0 / m_scale, 1.0/ m_scale);
|
||||
|
||||
|
||||
p->setPen((r.runway == runwaySelection) ? Qt::yellow : Qt::magenta);
|
||||
p->drawText(QRect(-100, 5, 200, 200), ident, Qt::AlignHCenter | Qt::AlignTop);
|
||||
|
||||
|
@ -657,8 +657,10 @@ void AirportDiagram::buildTaxiways()
|
|||
void AirportDiagram::buildPavements()
|
||||
{
|
||||
m_pavements.clear();
|
||||
for (unsigned int pIndex=0; pIndex < m_airport->numPavements(); ++pIndex) {
|
||||
FGPavementRef pave = m_airport->getPavementByIndex(pIndex);
|
||||
auto pavementlist = m_airport->getPavements();
|
||||
for (auto pvtiter = pavementlist.begin(); pvtiter != pavementlist.end(); ++pvtiter)
|
||||
{
|
||||
FGPavementRef pave = *pvtiter;
|
||||
if (pave->getNodeList().empty()) {
|
||||
continue;
|
||||
}
|
||||
|
|
|
@ -1816,7 +1816,9 @@ 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)
|
||||
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
|
||||
// or pavements
|
||||
|
@ -1831,10 +1833,31 @@ NavDataCache::insertRunway(FGPositioned::Type ty, const string& ident,
|
|||
sqlite3_bind_int(d->insertRunway, 5, surfaceCode);
|
||||
sqlite3_bind_double(d->insertRunway, 6, displacedThreshold);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
sqlite3_bind_int64(d->setRunwayReciprocal, 1, runway);
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace Octree {
|
|||
|
||||
class Airway;
|
||||
using AirwayRef = SGSharedPtr<Airway>;
|
||||
|
||||
|
||||
class NavDataCache
|
||||
{
|
||||
public:
|
||||
|
@ -160,10 +160,20 @@ public:
|
|||
PositionedID insertAirport(FGPositioned::Type ty, const std::string& ident,
|
||||
const std::string& name);
|
||||
void insertTower(PositionedID airportId, const SGGeod& pos);
|
||||
PositionedID insertRunway(FGPositioned::Type ty, const std::string& ident,
|
||||
const SGGeod& pos, PositionedID apt,
|
||||
double heading, double length, double width, double displacedThreshold,
|
||||
double stopway, int surfaceCode);
|
||||
|
||||
|
||||
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,
|
||||
double heading, double length, double width, double displacedThreshold,
|
||||
double stopway, int surfaceCode);
|
||||
|
||||
void setRunwayReciprocal(PositionedID runway, PositionedID recip);
|
||||
void setRunwayILS(PositionedID runway, PositionedID ils);
|
||||
|
||||
|
@ -291,9 +301,9 @@ public:
|
|||
* in an airway
|
||||
*/
|
||||
AirwayEdgeVec airwayEdgesFrom(int network, PositionedID pos);
|
||||
|
||||
|
||||
AirwayRef loadAirway(int airwayID);
|
||||
|
||||
|
||||
/**
|
||||
* Waypoints on the airway
|
||||
*/
|
||||
|
|
Loading…
Add table
Reference in a new issue