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
|
sidstar.cxx
|
||||||
airport.cxx
|
airport.cxx
|
||||||
xmlloader.cxx
|
xmlloader.cxx
|
||||||
airportdynamicsmanager.cxx
|
airportdynamicsmanager.cxx
|
||||||
|
AirportBuilder.cxx
|
||||||
)
|
)
|
||||||
|
|
||||||
set(HEADERS
|
set(HEADERS
|
||||||
airports_fwd.hxx
|
airports_fwd.hxx
|
||||||
apt_loader.hxx
|
apt_loader.hxx
|
||||||
dynamicloader.hxx
|
dynamicloader.hxx
|
||||||
dynamics.hxx
|
dynamics.hxx
|
||||||
|
@ -34,7 +35,8 @@ set(HEADERS
|
||||||
sidstar.hxx
|
sidstar.hxx
|
||||||
airport.hxx
|
airport.hxx
|
||||||
xmlloader.hxx
|
xmlloader.hxx
|
||||||
airportdynamicsmanager.hxx
|
airportdynamicsmanager.hxx
|
||||||
|
AirportBuilder.hxx
|
||||||
)
|
)
|
||||||
|
|
||||||
flightgear_component(Airports "${SOURCES}" "${HEADERS}")
|
flightgear_component(Airports "${SOURCES}" "${HEADERS}")
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------------------------------
|
//------------------------------------------------------------------------------
|
||||||
|
@ -1001,7 +1031,7 @@ Transition *FGAirport::selectSIDByTransition(const FGRunway* runway, const stri
|
||||||
for (auto sid : mSIDs) {
|
for (auto sid : mSIDs) {
|
||||||
if (runway && !sid->isForRunway(runway))
|
if (runway && !sid->isForRunway(runway))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto trans = sid->findTransitionByName(aIdent);
|
auto trans = sid->findTransitionByName(aIdent);
|
||||||
if (trans) {
|
if (trans) {
|
||||||
return trans;
|
return trans;
|
||||||
|
@ -1028,7 +1058,7 @@ Transition *FGAirport::selectSTARByTransition(const FGRunway* runway, const stri
|
||||||
for (auto star : mSTARs) {
|
for (auto star : mSTARs) {
|
||||||
if (runway && !star->isForRunway(runway))
|
if (runway && !star->isForRunway(runway))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
auto trans = star->findTransitionByName(aIdent);
|
auto trans = star->findTransitionByName(aIdent);
|
||||||
if (trans) {
|
if (trans) {
|
||||||
return trans;
|
return trans;
|
||||||
|
|
|
@ -94,7 +94,7 @@ class FGAirport : public FGPositioned
|
||||||
FGRunwayRef getActiveRunwayForUsage() const;
|
FGRunwayRef getActiveRunwayForUsage() const;
|
||||||
|
|
||||||
FGAirportDynamicsRef getDynamics() const;
|
FGAirportDynamicsRef getDynamics() const;
|
||||||
|
|
||||||
FGGroundNetwork* groundNetwork() const;
|
FGGroundNetwork* groundNetwork() const;
|
||||||
|
|
||||||
unsigned int numRunways() const;
|
unsigned int numRunways() const;
|
||||||
|
@ -124,7 +124,7 @@ class FGAirport : public FGPositioned
|
||||||
double ilsWeight;
|
double ilsWeight;
|
||||||
};
|
};
|
||||||
FGRunwayRef findBestRunwayForHeading(double aHeading, struct FindBestRunwayForHeadingParams * parms = NULL ) const;
|
FGRunwayRef findBestRunwayForHeading(double aHeading, struct FindBestRunwayForHeadingParams * parms = NULL ) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return the most likely target runway based on a position.
|
* return the most likely target runway based on a position.
|
||||||
* Specifically, return the runway for which the course from aPos
|
* Specifically, return the runway for which the course from aPos
|
||||||
|
@ -133,7 +133,7 @@ class FGAirport : public FGPositioned
|
||||||
* aiming towards.
|
* aiming towards.
|
||||||
*/
|
*/
|
||||||
FGRunwayRef findBestRunwayForPos(const SGGeod& aPos) const;
|
FGRunwayRef findBestRunwayForPos(const SGGeod& aPos) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve all runways at the airport, but excluding the reciprocal
|
* Retrieve all runways at the airport, but excluding the reciprocal
|
||||||
* runways. For example at KSFO this might return 1L, 1R, 28L and 28R,
|
* 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
|
* Retrieve all runways at the airport
|
||||||
*/
|
*/
|
||||||
FGRunwayList getRunways() const;
|
FGRunwayList getRunways() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Useful predicate for FMS/GPS/NAV displays and similar - check if this
|
* Useful predicate for FMS/GPS/NAV displays and similar - check if this
|
||||||
* aiport has a hard-surfaced runway of at least the specified length.
|
* aiport has a hard-surfaced runway of at least the specified length.
|
||||||
|
@ -167,7 +167,17 @@ 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
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -187,7 +197,7 @@ class FGAirport : public FGPositioned
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter which passes heliports and seaports in addition to airports
|
* Filter which passes heliports and seaports in addition to airports
|
||||||
*/
|
*/
|
||||||
|
@ -198,18 +208,18 @@ class FGAirport : public FGPositioned
|
||||||
return SEAPORT;
|
return SEAPORT;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class HardSurfaceFilter : public AirportFilter
|
class HardSurfaceFilter : public AirportFilter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
HardSurfaceFilter(double minLengthFt = -1);
|
HardSurfaceFilter(double minLengthFt = -1);
|
||||||
|
|
||||||
virtual bool passAirport(FGAirport* aApt) const;
|
virtual bool passAirport(FGAirport* aApt) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double mMinLengthFt;
|
double mMinLengthFt;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter which passes specified port type and in case of airport checks
|
* Filter which passes specified port type and in case of airport checks
|
||||||
* if a runway larger the /sim/navdb/min-runway-lenght-ft exists.
|
* 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;
|
double _min_runway_length_ft;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
void setProcedures(const std::vector<flightgear::SID*>& aSids,
|
void setProcedures(const std::vector<flightgear::SID*>& aSids,
|
||||||
const std::vector<flightgear::STAR*>& aStars,
|
const std::vector<flightgear::STAR*>& aStars,
|
||||||
const std::vector<flightgear::Approach*>& aApproaches);
|
const std::vector<flightgear::Approach*>& aApproaches);
|
||||||
|
|
||||||
void addSID(flightgear::SID* aSid);
|
void addSID(flightgear::SID* aSid);
|
||||||
void addSTAR(flightgear::STAR* aStar);
|
void addSTAR(flightgear::STAR* aStar);
|
||||||
void addApproach(flightgear::Approach* aApp);
|
void addApproach(flightgear::Approach* aApp);
|
||||||
|
@ -247,7 +257,7 @@ class FGAirport : public FGPositioned
|
||||||
flightgear::SID* getSIDByIndex(unsigned int aIndex) const;
|
flightgear::SID* getSIDByIndex(unsigned int aIndex) const;
|
||||||
flightgear::SID* findSIDWithIdent(const std::string& aIdent) const;
|
flightgear::SID* findSIDWithIdent(const std::string& aIdent) const;
|
||||||
flightgear::SIDList getSIDs() const;
|
flightgear::SIDList getSIDs() const;
|
||||||
|
|
||||||
flightgear::Transition* selectSIDByEnrouteTransition(FGPositioned* enroute) const;
|
flightgear::Transition* selectSIDByEnrouteTransition(FGPositioned* enroute) const;
|
||||||
flightgear::Transition* selectSIDByTransition(const FGRunway* runway, const std::string& aIdent) 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* getSTARByIndex(unsigned int aIndex) const;
|
||||||
flightgear::STAR* findSTARWithIdent(const std::string& aIdent) const;
|
flightgear::STAR* findSTARWithIdent(const std::string& aIdent) const;
|
||||||
flightgear::STARList getSTARs() const;
|
flightgear::STARList getSTARs() const;
|
||||||
|
|
||||||
flightgear::Transition* selectSTARByEnrouteTransition(FGPositioned* enroute) const;
|
flightgear::Transition* selectSTARByEnrouteTransition(FGPositioned* enroute) const;
|
||||||
flightgear::Transition* selectSTARByTransition(const FGRunway* runway, const std::string& aIdent) 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
|
flightgear::ProcedureType type = flightgear::PROCEDURE_INVALID
|
||||||
) const;
|
) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Syntactic wrapper around FGPositioned::findClosest - find the closest
|
* Syntactic wrapper around FGPositioned::findClosest - find the closest
|
||||||
* match for filter, and return it cast to FGAirport. The default filter
|
* match for filter, and return it cast to FGAirport. The default filter
|
||||||
* passes airports, but not seaports or heliports
|
* passes airports, but not seaports or heliports
|
||||||
*/
|
*/
|
||||||
static FGAirportRef findClosest(const SGGeod& aPos, double aCuttofNm, Filter* filter = NULL);
|
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
|
* exception if the airport could not be found - so callers can assume
|
||||||
* the result is non-NULL.
|
* the result is non-NULL.
|
||||||
*/
|
*/
|
||||||
static FGAirportRef getByIdent(const std::string& aIdent);
|
static FGAirportRef getByIdent(const std::string& aIdent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to look up an FGAirport instance by unique ident. Returns NULL
|
* Helper to look up an FGAirport instance by unique ident. Returns NULL
|
||||||
* if the airport could not be found.
|
* if the airport could not be found.
|
||||||
*/
|
*/
|
||||||
static FGAirportRef findByIdent(const std::string& aIdent);
|
static FGAirportRef findByIdent(const std::string& aIdent);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialised helper to implement the AirportList dialog. Performs a
|
* Specialised helper to implement the AirportList dialog. Performs a
|
||||||
* case-insensitive search on airport names and ICAO codes, and returns
|
* 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);
|
static char** searchNamesAndIdents(const std::string& aFilter);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sort an FGPositionedList of airports by size (number of runways + length)
|
* Sort an FGPositionedList of airports by size (number of runways + length)
|
||||||
* this is meant to prioritise more important airports.
|
* this is meant to prioritise more important airports.
|
||||||
*/
|
*/
|
||||||
static void sortBySize(FGPositionedList&);
|
static void sortBySize(FGPositionedList&);
|
||||||
|
|
||||||
flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const;
|
flightgear::CommStationList commStationsOfType(FGPositioned::Type aTy) const;
|
||||||
|
|
||||||
flightgear::CommStationList commStations() const;
|
flightgear::CommStationList commStations() const;
|
||||||
|
|
||||||
static void clearAirportsCache();
|
static void clearAirportsCache();
|
||||||
|
|
||||||
|
|
||||||
#if defined(BUILDING_TESTSUITE)
|
#if defined(BUILDING_TESTSUITE)
|
||||||
// helper to allow testing without needing a full Airports heirarchy
|
// helper to allow testing without needing a full Airports heirarchy
|
||||||
void testSuiteInjectGroundnetXML(const SGPath& path);
|
void testSuiteInjectGroundnetXML(const SGPath& path);
|
||||||
|
@ -318,29 +328,29 @@ private:
|
||||||
// disable these
|
// disable these
|
||||||
FGAirport operator=(FGAirport &other);
|
FGAirport operator=(FGAirport &other);
|
||||||
FGAirport(const FGAirport&);
|
FGAirport(const FGAirport&);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* helper to read airport data from the scenery XML files.
|
* helper to read airport data from the scenery XML files.
|
||||||
*/
|
*/
|
||||||
void loadSceneryDefinitions() const;
|
void loadSceneryDefinitions() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helpers to process property data loaded from an ICAO.threshold.xml file
|
* Helpers to process property data loaded from an ICAO.threshold.xml file
|
||||||
*/
|
*/
|
||||||
void readThresholdData(SGPropertyNode* aRoot);
|
void readThresholdData(SGPropertyNode* aRoot);
|
||||||
void processThreshold(SGPropertyNode* aThreshold);
|
void processThreshold(SGPropertyNode* aThreshold);
|
||||||
|
|
||||||
void readILSData(SGPropertyNode* aRoot);
|
void readILSData(SGPropertyNode* aRoot);
|
||||||
|
|
||||||
void validateTowerData() const;
|
void validateTowerData() const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper to parse property data loaded from an ICAO.twr.xml file
|
* Helper to parse property data loaded from an ICAO.twr.xml file
|
||||||
*/
|
*/
|
||||||
void readTowerData(SGPropertyNode* aRoot);
|
void readTowerData(SGPropertyNode* aRoot);
|
||||||
|
|
||||||
PositionedIDVec itemsOfType(FGPositioned::Type ty) const;
|
PositionedIDVec itemsOfType(FGPositioned::Type ty) const;
|
||||||
|
|
||||||
std::string _name;
|
std::string _name;
|
||||||
bool _has_metar;
|
bool _has_metar;
|
||||||
|
|
||||||
|
@ -348,11 +358,11 @@ private:
|
||||||
void loadHelipads() const;
|
void loadHelipads() const;
|
||||||
void loadTaxiways() const;
|
void loadTaxiways() const;
|
||||||
void loadProcedures() const;
|
void loadProcedures() const;
|
||||||
|
|
||||||
mutable bool mTowerDataLoaded;
|
mutable bool mTowerDataLoaded;
|
||||||
mutable bool mHasTower;
|
mutable bool mHasTower;
|
||||||
mutable SGGeod mTowerPosition;
|
mutable SGGeod mTowerPosition;
|
||||||
|
|
||||||
mutable bool mRunwaysLoaded;
|
mutable bool mRunwaysLoaded;
|
||||||
mutable bool mHelipadsLoaded;
|
mutable bool mHelipadsLoaded;
|
||||||
mutable bool mTaxiwaysLoaded;
|
mutable bool mTaxiwaysLoaded;
|
||||||
|
@ -362,15 +372,17 @@ private:
|
||||||
bool mILSDataLoaded;
|
bool mILSDataLoaded;
|
||||||
|
|
||||||
mutable std::vector<FGRunwayRef> mRunways;
|
mutable std::vector<FGRunwayRef> mRunways;
|
||||||
|
|
||||||
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;
|
||||||
typedef SGSharedPtr<flightgear::Approach> ApproachRef;
|
typedef SGSharedPtr<flightgear::Approach> ApproachRef;
|
||||||
|
|
||||||
std::vector<SIDRef> mSIDs;
|
std::vector<SIDRef> mSIDs;
|
||||||
std::vector<STARRef> mSTARs;
|
std::vector<STARRef> mSTARs;
|
||||||
std::vector<ApproachRef> mApproaches;
|
std::vector<ApproachRef> mApproaches;
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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,74 +226,12 @@ 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
|
|
||||||
// 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
|
// this is just the current airport identifier
|
||||||
for (LinesList::const_iterator linesIt = lines.begin();
|
last_apt_id = it->first;
|
||||||
linesIt != lines.end(); linesIt++) {
|
RawAirportInfo rawinfo = it->second;
|
||||||
// Beware that linesIt->str may end with an '\r' character, see above!
|
|
||||||
unsigned int rowCode = linesIt->rowCode;
|
|
||||||
|
|
||||||
if ( rowCode == 10 ) { // Runway v810
|
loadAirport(aptDat, last_apt_id, &rawinfo);
|
||||||
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);
|
|
||||||
nbLoadedAirports++;
|
nbLoadedAirports++;
|
||||||
|
|
||||||
if ((nbLoadedAirports % 300) == 0) {
|
if ((nbLoadedAirports % 300) == 0) {
|
||||||
|
@ -307,6 +246,140 @@ void APTLoader::loadAirports()
|
||||||
"Loaded data for " << nbLoadedAirports << " airports" );
|
"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
|
// 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,
|
||||||
unsigned int lineNum, int rowCode,
|
const string& aptDat,
|
||||||
const vector<string>& token)
|
unsigned int lineNum, int rowCode,
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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
|
// 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
|
// Copyright (C) 2009 Frederic Bouvier
|
||||||
//
|
//
|
||||||
|
@ -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; }
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ GroundRadar::~GroundRadar()
|
||||||
|
|
||||||
void GroundRadar::update (double /* dt */)
|
void GroundRadar::update (double /* dt */)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GroundRadar::valueChanged(SGPropertyNode*)
|
void GroundRadar::valueChanged(SGPropertyNode*)
|
||||||
|
@ -231,7 +231,7 @@ void GroundRadar::updateTexture()
|
||||||
const double tower_lat = tower_location.getLatitudeDeg();
|
const double tower_lat = tower_location.getLatitudeDeg();
|
||||||
const double tower_lon = tower_location.getLongitudeDeg();
|
const double tower_lon = tower_location.getLongitudeDeg();
|
||||||
double scale = SG_METER_TO_NM * 200 / _range_node->getDoubleValue();
|
double scale = SG_METER_TO_NM * 200 / _range_node->getDoubleValue();
|
||||||
|
|
||||||
const FGAirport* apt = fgFindAirportID(airport_name);
|
const FGAirport* apt = fgFindAirportID(airport_name);
|
||||||
assert(apt);
|
assert(apt);
|
||||||
|
|
||||||
|
@ -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(),
|
||||||
|
|
|
@ -45,10 +45,10 @@ static double distanceToLineSegment(const QVector2D& p, const QVector2D& a,
|
||||||
{
|
{
|
||||||
QVector2D ab(b - a);
|
QVector2D ab(b - a);
|
||||||
QVector2D ac(p - a);
|
QVector2D ac(p - a);
|
||||||
|
|
||||||
// Squared length, to avoid a sqrt
|
// Squared length, to avoid a sqrt
|
||||||
const qreal len2 = ab.lengthSquared();
|
const qreal len2 = ab.lengthSquared();
|
||||||
|
|
||||||
// Line null, the projection can't exist, we return the first point
|
// Line null, the projection can't exist, we return the first point
|
||||||
if (qIsNull(len2)) {
|
if (qIsNull(len2)) {
|
||||||
if (outT) {
|
if (outT) {
|
||||||
|
@ -56,10 +56,10 @@ static double distanceToLineSegment(const QVector2D& p, const QVector2D& a,
|
||||||
}
|
}
|
||||||
return (p - a).length();
|
return (p - a).length();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parametric value of the projection on the line
|
// Parametric value of the projection on the line
|
||||||
const qreal t = (ac.x() * ab.x() + ac.y() * ab.y()) / len2;
|
const qreal t = (ac.x() * ab.x() + ac.y() * ab.y()) / len2;
|
||||||
|
|
||||||
if (t < 0.0) {
|
if (t < 0.0) {
|
||||||
// Point is before the first point
|
// Point is before the first point
|
||||||
if (outT) {
|
if (outT) {
|
||||||
|
@ -76,11 +76,11 @@ static double distanceToLineSegment(const QVector2D& p, const QVector2D& a,
|
||||||
if (outT) {
|
if (outT) {
|
||||||
*outT = t;
|
*outT = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
const QVector2D proj = a + t * ab;
|
const QVector2D proj = a + t * ab;
|
||||||
return (proj - p).length();
|
return (proj - p).length();
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,13 +345,13 @@ void AirportDiagram::paintContents(QPainter* p)
|
||||||
if ((r.runway == runwaySelection) || (r.runway->reciprocalRunway() == runwaySelection)) {
|
if ((r.runway == runwaySelection) || (r.runway->reciprocalRunway() == runwaySelection)) {
|
||||||
color = Qt::yellow;
|
color = Qt::yellow;
|
||||||
}
|
}
|
||||||
|
|
||||||
p->setTransform(t);
|
p->setTransform(t);
|
||||||
|
|
||||||
QPen pen(color);
|
QPen pen(color);
|
||||||
pen.setWidth(r.widthM);
|
pen.setWidth(r.widthM);
|
||||||
p->setPen(pen);
|
p->setPen(pen);
|
||||||
|
|
||||||
p->drawLine(r.p1, r.p2);
|
p->drawLine(r.p1, r.p2);
|
||||||
|
|
||||||
// draw idents
|
// draw idents
|
||||||
|
@ -361,7 +361,7 @@ void AirportDiagram::paintContents(QPainter* p)
|
||||||
p->rotate(r.runway->headingDeg());
|
p->rotate(r.runway->headingDeg());
|
||||||
// invert scaling factor so we can use screen pixel sizes here
|
// invert scaling factor so we can use screen pixel sizes here
|
||||||
p->scale(1.0 / m_scale, 1.0/ m_scale);
|
p->scale(1.0 / m_scale, 1.0/ m_scale);
|
||||||
|
|
||||||
p->setPen((r.runway == runwaySelection) ? Qt::yellow : Qt::magenta);
|
p->setPen((r.runway == runwaySelection) ? Qt::yellow : Qt::magenta);
|
||||||
p->drawText(QRect(-100, 5, 200, 200), ident, Qt::AlignHCenter | Qt::AlignTop);
|
p->drawText(QRect(-100, 5, 200, 200), ident, Qt::AlignHCenter | Qt::AlignTop);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace Octree {
|
||||||
|
|
||||||
class Airway;
|
class Airway;
|
||||||
using AirwayRef = SGSharedPtr<Airway>;
|
using AirwayRef = SGSharedPtr<Airway>;
|
||||||
|
|
||||||
class NavDataCache
|
class NavDataCache
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -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,
|
|
||||||
const SGGeod& pos, PositionedID apt,
|
|
||||||
double heading, double length, double width, double displacedThreshold,
|
PositionedID insertRunway(FGPositioned::Type ty, const string& ident,
|
||||||
double stopway, int surfaceCode);
|
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 setRunwayReciprocal(PositionedID runway, PositionedID recip);
|
||||||
void setRunwayILS(PositionedID runway, PositionedID ils);
|
void setRunwayILS(PositionedID runway, PositionedID ils);
|
||||||
|
|
||||||
|
@ -291,9 +301,9 @@ public:
|
||||||
* in an airway
|
* in an airway
|
||||||
*/
|
*/
|
||||||
AirwayEdgeVec airwayEdgesFrom(int network, PositionedID pos);
|
AirwayEdgeVec airwayEdgesFrom(int network, PositionedID pos);
|
||||||
|
|
||||||
AirwayRef loadAirway(int airwayID);
|
AirwayRef loadAirway(int airwayID);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Waypoints on the airway
|
* Waypoints on the airway
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Add table
Reference in a new issue