10#include <osgDB/Registry>
11#include <osgUtil/Tessellator>
12#include <osgUtil/DelaunayTriangulator>
15#include <osg/Geometry>
16#include <osgTerrain/Terrain>
17#include <osgTerrain/TerrainTechnique>
19#include <simgear/scene/material/Effect.hxx>
20#include <simgear/scene/material/EffectGeode.hxx>
21#include <simgear/scene/model/BoundingVolumeBuildVisitor.hxx>
22#include <simgear/scene/model/ModelRegistry.hxx>
23#include <simgear/scene/tgdb/VPBTechnique.hxx>
24#include <simgear/scene/util/OsgMath.hxx>
25#include <simgear/scene/util/SGReaderWriterOptions.hxx>
26#include <simgear/scene/util/SGNodeMasks.hxx>
45 supportsExtension(
"icao",
"Dummy name to build an airport from apt.dat");
54 return "Airport Builder";
58 const osgDB::Options*
options)
const
60 SGPath aptFile = SGPath(fileName);
62 if (! aptFile.isFile()) {
64 auto pathList =
options->getDatabasePathList();
65 for(
auto itr = pathList.begin(); itr != pathList.end(); ++itr) {
66 aptFile = SGPath(*itr, fileName);
67 if (aptFile.isFile())
break;
71 if (! aptFile.isFile())
return ReadResult::FILE_NOT_HANDLED;;
73 const std::string airportId = aptFile.file_base();
77 airportId, {aptFile, SGPath()});
78 if (! airport)
return ReadResult::FILE_NOT_HANDLED;
80 SG_LOG( SG_TERRAIN, SG_DEBUG,
"Building airport : " << airportId <<
" " << airport->
getName());
82 SG_LOG( SG_TERRAIN, SG_DEBUG,
"Elevation : " << airport->
getElevation());
83 SG_LOG( SG_TERRAIN, SG_DEBUG,
"Runways : " << airport->
numRunways());
84 SG_LOG( SG_TERRAIN, SG_DEBUG,
"Helipads : " << airport->
numHelipads());
85 SG_LOG( SG_TERRAIN, SG_DEBUG,
"Taxiways : " << airport->
numTaxiways());
86 SG_LOG( SG_TERRAIN, SG_DEBUG,
"Pavements : " << airport->
numPavements());
87 SG_LOG( SG_TERRAIN, SG_DEBUG,
"Line Features : " << airport->
numLineFeatures());
91 const SGVec3f center = SGVec3f::fromGeod(zeroAltitudeCenter);
96 osg::Matrixd mat = osg::Matrix(toOsg(SGQuatd::fromLonLat(zeroAltitudeCenter)));
97 mat.preMultRotate(osg::Quat(0.0, 1.0, 0.0, 0.0));
99 std::vector<osg::Node*> nodeList;
100 osg::Group* group =
new osg::Group();
104 std::for_each( boundaryList.begin(),
106 [&, mat, center,
options] (
FGPavementRef p) { group->addChild(this->createBoundary(mat, center, p, options)); } );
110 std::for_each( pavementlist.begin(),
112 [&, mat, center,
options] (
FGPavementRef p) { group->addChild(this->createPavement(mat, center, p, options)); } );
116 std::for_each( runwaylist.begin(),
118 [&, mat, center,
options] (
FGRunwayRef p) { group->addChild(this->createRunway(mat, center, p, options)); } );
122 std::for_each( lineList.begin(),
124 [&, mat, center,
options] (
FGPavementRef p) { group->addChild(this->createLine(mat, center, p, options)); } );
128 osg::MatrixTransform* matrixTransform;
129 matrixTransform =
new osg::MatrixTransform(matrix);
130 matrixTransform->setDataVariance(osg::Object::STATIC);
131 matrixTransform->addChild(group);
133 return matrixTransform;
136osg::Node* AirportBuilder::createRunway(
const osg::Matrixd mat,
const SGVec3f center,
const FGRunwayRef runway,
const osgDB::Options*
options)
const
138 std::vector<SGGeod> nodes;
139 nodes.push_back(runway->pointOffCenterline(0.0, -0.5 * runway->widthM()));
140 nodes.push_back(runway->pointOffCenterline(0.0, 0.5 * runway->widthM()));
141 nodes.push_back(runway->pointOffCenterline(runway->lengthM(), 0.5 * runway->widthM()));
142 nodes.push_back(runway->pointOffCenterline(runway->lengthM(), -0.5 * runway->widthM()));
144 osg::Vec3Array* points =
new osg::Vec3Array;
145 points->reserve(nodes.size());
146 std::transform( nodes.begin(),
148 std::back_inserter(*points),
149 [mat, center](SGGeod n) {
150 return mat * toOsg(SGVec3f::fromGeod(n) - center) + osg::Vec3f(0,0, RUNWAY_OFFSET);
154 osg::ref_ptr<osgUtil::DelaunayTriangulator> triangulator =
new osgUtil::DelaunayTriangulator;
155 triangulator->setInputPointArray(points);
156 triangulator->triangulate();
158 osg::ref_ptr<osg::Geometry> geometry =
new osg::Geometry;
159 geometry->setVertexArray(points);
160 geometry->addPrimitiveSet(triangulator->getTriangles());
162 osg::Vec3Array* n =
new osg::Vec3Array;
163 n->push_back(osg::Vec3f(0.0f, 0.0f, 1.0f));
165 osg::Vec4Array* c =
new osg::Vec4Array;
166 c->push_back(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
168 geometry->setColorArray(c, osg::Array::BIND_OVERALL);
169 geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
171 EffectGeode* geode =
new EffectGeode;
172 ref_ptr<Effect> effect = getMaterialEffect(
"pa_rest",
options);
173 geode->setEffect(effect.get());
174 geode->addDrawable(geometry);
179osg::Node* AirportBuilder::createPavement(
const osg::Matrixd mat,
const SGVec3f center,
const FGPavementRef pavement,
const osgDB::Options*
options)
const
182 if (nodes.size() < 2)
return NULL;
184 osg::ref_ptr<osgUtil::Tessellator> tessellator =
new osgUtil::Tessellator;
185 tessellator->setBoundaryOnly(
false);
186 tessellator->beginTessellation();
187 tessellator->beginContour();
190 osg::Vec3f* previous = NULL;
197 auto itr = nodes.begin();
198 for (; itr < nodes.end(); ++itr) {
201 osg::Vec3f* v =
new osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(node->
mPos) - center) + osg::Vec3f(0,0,
PAVEMENT_OFFSET));
205 control = mat * toOsg(SGVec3f::fromGeod(bez->mControl) - center) + osg::Vec3f(0,0,
PAVEMENT_OFFSET);
209 for (
float t = 0.05f; t < 0.95f; t += 0.05f ) {
211 osg::Vec3f p0 = osg::Vec3f();
212 if (previous != NULL) p0 = *previous;
213 osg::Vec3f p1 = *v + *v - control;
216 osg::Vec3f* b =
new osg::Vec3f(p1 +
217 (p0 - p1)*(1.0f - t)*(1.0f - t) +
220 tessellator->addVertex(b);
223 tessellator->addVertex(v);
227 for (
float t = 0.05f; t < 0.95f; t += 0.05f ) {
228 osg::Vec3f p0 = *previous;
229 osg::Vec3f p1 = control;
232 osg::Vec3f* b =
new osg::Vec3f(p1 +
233 (p0 - p1)*(1.0f - t)*(1.0f - t) +
236 tessellator->addVertex(b);
240 tessellator->addVertex(v);
243 tessellator->addVertex(v);
247 tessellator->endContour();
248 tessellator->beginContour();
252 tessellator->endContour();
253 tessellator->endTessellation();
257 osg::ref_ptr<osg::Geometry> geometry =
new osg::Geometry;
258 auto primList = tessellator->getPrimList();
259 osg::Vec3Array* points =
new osg::Vec3Array();
260 osg::Vec3Array* normals =
new osg::Vec3Array();
261 osg::Vec2Array* texCoords =
new osg::Vec2Array();
262 geometry->setVertexArray(points);
263 unsigned int idx = 0;
264 auto primItr = primList.begin();
265 for (; primItr < primList.end(); ++ primItr) {
266 auto vertices = (*primItr)->_vertices;
267 std::for_each( vertices.begin(),
269 [points, texCoords, normals](
auto v) {
270 points->push_back(*v);
271 texCoords->push_back(osg::Vec2f(v->x(), v->y()));
272 normals->push_back(osg::Vec3f(0.0, 0.0, 1.0));
276 geometry->addPrimitiveSet(
new osg::DrawArrays((*primItr)->_mode, idx, vertices.size()));
277 idx += vertices.size();
280 osg::Vec4Array* c =
new osg::Vec4Array;
281 c->push_back(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
283 geometry->setColorArray(c, osg::Array::BIND_OVERALL);
284 geometry->setNormalArray(normals, osg::Array::BIND_PER_VERTEX);
285 geometry->setTexCoordArray(0, texCoords, osg::Array::BIND_PER_VERTEX);
287 EffectGeode* geode =
new EffectGeode;
288 ref_ptr<Effect> effect = getMaterialEffect(
"Asphalt",
options);
289 geode->setEffect(effect.get());
290 geode->addDrawable(geometry);
295osg::Node* AirportBuilder::createBoundary(
const osg::Matrixd mat,
const SGVec3f center,
const FGPavementRef pavement,
const osgDB::Options*
options)
const
299 if (nodes.size() == 0)
return NULL;
301 osg::ref_ptr<osgUtil::Tessellator> tessellator =
new osgUtil::Tessellator;
302 tessellator->setBoundaryOnly(
false);
303 tessellator->beginTessellation();
304 tessellator->beginContour();
307 osg::Vec3f* previous = NULL;
314 auto itr = nodes.begin();
315 for (; itr < nodes.end(); ++itr) {
316 FGPavement::NodeBase* node = *itr;
318 osg::Vec3f* v =
new osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(node->
mPos) - center) + osg::Vec3f(0,0,
BOUNDARY_OFFSET));
320 if (FGPavement::BezierNode *bez =
dynamic_cast<FGPavement::BezierNode*
>(node)) {
322 control = osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(bez->mControl) - center) + osg::Vec3f(0,0,
BOUNDARY_OFFSET));
326 for (
float t = 0.05f; t < 0.95f; t += 0.05f ) {
327 osg::Vec3f p0 = osg::Vec3f();
328 if (previous != NULL) p0 = *previous;
329 osg::Vec3f p1 = *v + *v - control;
332 osg::Vec3f* b =
new osg::Vec3f(p1 +
333 (p0 - p1)*(1.0f - t)*(1.0f - t) +
336 tessellator->addVertex(b);
339 tessellator->addVertex(v);
343 for (
float t = 0.05f; t < 0.95f; t += 0.05f ) {
344 osg::Vec3f p0 = *previous;
345 osg::Vec3f p1 = control;
348 osg::Vec3f* b =
new osg::Vec3f(p1 +
349 (p0 - p1)*(1.0f - t)*(1.0f - t) +
352 tessellator->addVertex(b);
356 tessellator->addVertex(v);
359 tessellator->addVertex(v);
364 tessellator->endContour();
365 tessellator->beginContour();
369 tessellator->endContour();
370 tessellator->endTessellation();
373 osg::ref_ptr<osg::Geometry> geometry =
new osg::Geometry;
374 auto primList = tessellator->getPrimList();
375 osg::Vec3Array* points =
new osg::Vec3Array();
376 geometry->setVertexArray(points);
377 unsigned int idx = 0;
378 auto primItr = primList.begin();
379 for (; primItr < primList.end(); ++ primItr) {
380 auto vertices = (*primItr)->_vertices;
381 std::for_each( vertices.begin(),
383 [points](
auto v) { points->push_back(*v); }
386 geometry->addPrimitiveSet(
new osg::DrawArrays((*primItr)->_mode, idx, vertices.size()));
387 idx += vertices.size();
390 osg::Vec3Array* n =
new osg::Vec3Array;
391 n->push_back(osg::Vec3f(0.0, 0.0, 1.0));
393 osg::Vec4Array* c =
new osg::Vec4Array;
394 c->push_back(osg::Vec4f(1.0f, 1.0f, 1.0f, 1.0f));
396 geometry->setColorArray(c, osg::Array::BIND_OVERALL);
397 geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
399 EffectGeode* geode =
new EffectGeode;
400 ref_ptr<Effect> effect = getMaterialEffect(
"Default",
options);
401 geode->setEffect(effect.get());
402 geode->addDrawable(geometry);
407osg::Node* AirportBuilder::createLine(
const osg::Matrixd mat,
const SGVec3f center,
const FGPavementRef line,
const osgDB::Options*
options)
const
411 if (nodes.size() == 0)
return NULL;
417 unsigned int idx = 0;
418 unsigned int length = 0;
421 unsigned int paintCode = 0;
423 unsigned int lines = 0;
430 osg::ref_ptr<osg::Geometry> geometry =
new osg::Geometry;
431 osg::Vec3Array* points =
new osg::Vec3Array();
432 geometry->setVertexArray(points);
434 osg::Vec3Array* n =
new osg::Vec3Array;
435 n->push_back(osg::Vec3f(0.0, 0.0, 1.0));
436 geometry->setNormalArray(n, osg::Array::BIND_OVERALL);
438 osg::Vec4Array* c =
new osg::Vec4Array;
439 geometry->setColorArray(c, osg::Array::BIND_PER_VERTEX);
441 auto itr = nodes.begin();
442 for (; itr < nodes.end(); ++itr) {
443 FGPavement::NodeBase* node = *itr;
444 osg::Vec3f v = osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(node->
mPos) - center) + osg::Vec3f(0,0,
MARKING_OFFSET));
448 if (FGPavement::BezierNode *bez =
dynamic_cast<FGPavement::BezierNode*
>(node)) {
450 control = osg::Vec3f(mat * toOsg(SGVec3f::fromGeod(bez->mControl) - center) + osg::Vec3f(0,0,
MARKING_OFFSET));
454 for (
float t = 0.05f; t < 0.95f; t += 0.05f ) {
455 osg::Vec3f p0 = previous;
456 osg::Vec3f p1 = v + v - control;
461 (p0 - p1)*(1.0f - t)*(1.0f - t) +
464 points->push_back(b);
465 c->push_back(getLineColor(paintCode));
469 points->push_back(v);
470 c->push_back(getLineColor(paintCode));
478 for (
float t = 0.05f; t < 0.95f; t += 0.05f ) {
480 osg::Vec3f p1 = control;
481 osg::Vec3f
p2 = points->at(idx);
485 (p0 - p1)*(1.0f - t)*(1.0f - t) +
488 points->push_back(b);
489 c->push_back(getLineColor(paintCode));
498 for (
float t = 0.05f; t < 0.95f; t += 0.05f ) {
499 osg::Vec3f p0 = previous;
500 osg::Vec3f p1 = control;
505 (p0 - p1)*(1.0f - t)*(1.0f - t) +
508 points->push_back(b);
509 c->push_back(getLineColor(paintCode));
516 points->push_back(v);
517 c->push_back(getLineColor(paintCode));
524 geometry->addPrimitiveSet(
new osg::DrawArrays(
525 node->
mLoop ? GL_LINE_LOOP : GL_LINE_STRIP,
537 EffectGeode* geode =
new EffectGeode;
538 ref_ptr<Effect> effect = getMaterialEffect(
"lf_sng_solid_yellow",
options);
539 geode->setEffect(effect.get());
540 geode->addDrawable(geometry);
546osg::Vec4f AirportBuilder::getLineColor(
const int aPaintCode)
const
548 if (aPaintCode == 1)
return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f);
549 if (aPaintCode == 2)
return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f);
550 if (aPaintCode == 3)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
551 if (aPaintCode == 4)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
552 if (aPaintCode == 5)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
553 if (aPaintCode == 6)
return osg::Vec4f(0.5f, 0.5f, 0.0f, 1.0f);
554 if (aPaintCode == 7)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
555 if (aPaintCode == 8)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
556 if (aPaintCode == 9)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
559 if (aPaintCode == 51)
return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f);
560 if (aPaintCode == 52)
return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f);
561 if (aPaintCode == 53)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
562 if (aPaintCode == 54)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
563 if (aPaintCode == 55)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
564 if (aPaintCode == 56)
return osg::Vec4f(0.5f, 0.5f, 0.0f, 1.0f);
565 if (aPaintCode == 57)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
566 if (aPaintCode == 58)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
567 if (aPaintCode == 59)
return osg::Vec4f(0.9f, 0.9f, 0.3f, 1.0f);
569 if (aPaintCode == 20)
return osg::Vec4f(0.8f, 0.8f, 0.8f, 1.0f);
570 if (aPaintCode == 21)
return osg::Vec4f(0.7f, 0.7f, 0.7f, 1.0f);
571 if (aPaintCode == 22)
return osg::Vec4f(0.6f, 0.6f, 0.6f, 1.0f);
573 return osg::Vec4f(0.7f, 0.7f, 0.3f, 1.0f);
576osg::ref_ptr<Effect> AirportBuilder::getMaterialEffect(std::string material,
const osgDB::Options*
options)
const
578 ref_ptr<Effect> effect;
579 SGPropertyNode_ptr effectProp =
new SGPropertyNode();
581 osg::ref_ptr<SGReaderWriterOptions> sgOpts(SGReaderWriterOptions::copyOrCreate(
options));
583 if (sgOpts->getMaterialLib()) {
584 const SGGeod loc = SGGeod(sgOpts->getLocation());
585 SGMaterialCache* matcache = sgOpts->getMaterialLib()->generateMatCache(loc, sgOpts);
586 SGMaterial* mat = matcache->find(material);
590 return mat->get_effect();
594 SG_LOG( SG_TERRAIN, SG_ALERT,
"Unable to get effect for " << material);
595 makeChild(effectProp,
"inherits-from")->setStringValue(
"Effects/terrain-default");
596 effectProp->addChild(
"default")->setBoolValue(
true);
597 effect = makeEffect(effectProp,
true, sgOpts);
603typedef simgear::ModelRegistryCallback<simgear::DefaultProcessPolicy, simgear::NoCachePolicy,
604 simgear::NoOptimizePolicy,
605 simgear::NoSubstitutePolicy, simgear::BuildGroupBVHPolicy>
610 osgDB::RegisterReaderWriterProxy<flightgear::AirportBuilder> g_readerAirportBuilder;
611 simgear::ModelRegistryCallbackProxy<AirportCallback> g_icaoCallbackProxy(
"icao");
simgear::ModelRegistryCallback< simgear::DefaultProcessPolicy, simgear::NoCachePolicy, simgear::NoOptimizePolicy, simgear::NoSubstitutePolicy, simgear::BuildGroupBVHPolicy > AirportCallback
bool options(int, char **)
SGSharedPtr< FGPavement > FGPavementRef
SGSharedPtr< FGRunway > FGRunwayRef
unsigned int numRunways() const
FGPavementList getLineFeatures() const
unsigned int numTaxiways() const
double getElevation() const
double getLatitude() const
double getLongitude() const
FGPavementList getPavements() const
unsigned int numLineFeatures() const
unsigned int numHelipads() const
FGPavementList getBoundary() const
unsigned int numPavements() const
FGRunwayList getRunways() const
Retrieve all runways at the airport.
const std::string & getName() const
std::vector< SGSharedPtr< NodeBase > > NodeList
const FGAirport * loadAirportFromFile(const std::string &id, const NavDataCache::SceneryLocation &sceneryLocation)
virtual const char * className() const
const float MARKING_OFFSET
const float BOUNDARY_OFFSET
const float PAVEMENT_OFFSET
virtual ReadResult readNode(const std::string &fileName, const osgDB::Options *options) const
virtual ~AirportBuilder()
FlightPlan.hxx - defines a full flight-plan object, including departure, cruise, arrival information ...