1
0
Fork 0

Adding initial genapts 850 support

This commit is contained in:
PSadrozinski 2011-09-18 16:28:36 -04:00 committed by Christian Schmitt
parent 324e6fc30f
commit ef486df526
17 changed files with 5143 additions and 612 deletions

View file

@ -1,20 +1,17 @@
add_executable(genapts850
apt_surface.hxx apt_surface.cxx
build.cxx build.hxx
airport.hxx airport.cxx
apt_surface.hxx apt_surface.cxx
beznode.hxx
closedpoly.hxx closedpoly.cxx
convex_hull.hxx convex_hull.cxx
elevations.cxx elevations.hxx
global.hxx
heli_gen.cxx heli_gen.hxx
lights.hxx lights.cxx
main.cxx
linearfeature.hxx linearfeature.cxx
main.cxx
parser.hxx parser.cxx
point2d.cxx point2d.hxx
poly_extra.cxx poly_extra.hxx
runway.cxx runway.hxx
rwy_common.cxx rwy_common.hxx
rwy_gen.cxx rwy_gen.hxx
rwy_simple.cxx rwy_simple.hxx
taxiway.cxx taxiway.hxx
runway.cxx runway.hxx
texparams.hxx
)
@ -25,6 +22,7 @@ target_link_libraries(genapts850
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GPC_LIBRARY}
${NEWMAT_LIBRARY})
${NEWMAT_LIBRARY}
osg osgDB osgGA osgUtil osgViewer)
install(TARGETS genapts850 RUNTIME DESTINATION bin)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
#ifndef _AIRPORT_H_
#define _AIRPORT_H_
#include <stdio.h>
#include <stdlib.h>
#include "runway.hxx"
#include "closedpoly.hxx"
#include "linearfeature.hxx"
using std::string;
class Airport
{
public:
Airport( int c, char* def);
void AddRunway( Runway* runway )
{
runways.push_back( runway );
}
void AddPavement( ClosedPoly* pavement )
{
pavements.push_back( pavement );
}
void AddFeature( LinearFeature* feature )
{
features.push_back( feature );
}
void BuildOsg( osg::Group* airport );
void BuildBtg( const string& root, const string_list& elev_src );
private:
int code; // airport, heliport or sea port
int altitude; // in meters
string icao; // airport code
string description; // description
PavementList pavements;
FeatureList features;
RunwayList runways;
};
typedef std::vector <Airport *> AirportList;
#endif

View file

@ -0,0 +1,205 @@
#ifndef _BEZNODE_H_
#define _BEZNODE_H_
#include <string.h>
#include <float.h>
#include <iostream>
#include <osg/Vec3d>
#include <Geometry/point3d.hxx>
#include <simgear/debug/logstream.hxx>
// TODO: where to put this
inline osg::Vec3d SGPoint3DtoOSGVec3d( Point3D p )
{
return osg::Vec3d( p.x(), p.y(), p.z() );
}
// TEMP...
inline Point3D CalculateQuadraticLocation( Point3D p0, Point3D cp, Point3D p1, double t )
{
Point3D result;
double term1 = (1.0f - t) * (1.0f - t);
double term2 = 2 * (1.0f - t) * t;
double term3 = t * t;
result = (p0 * term1) + (cp * term2) + (p1 * term3);
return result;
}
// TODO: Should be in a math library
inline Point3D CalculateCubicLocation( Point3D p0, Point3D cp0, Point3D cp1, Point3D p1, double t )
{
Point3D result;
double term1 = (1.0f - t) * (1.0f - t) * (1.0f - t);
double term2 = 3 * (1.0f - t) * (1.0f - t) * t;
double term3 = 3 * (1.0f - t) * t * t;
double term4 = t * t * t;
result = (p0 * term1) + (cp0 * term2) + (cp1 * term3) + (p1 * term4);
return result;
}
inline double CalculateTheta( Point3D p0, Point3D p1, Point3D p2 )
{
Point3D u, v;
double udist, vdist, uv_dot, tmp;
// u . v = ||u|| * ||v|| * cos(theta)
u = p1 - p0;
udist = sqrt( u.x() * u.x() + u.y() * u.y() );
// printf("udist = %.6f\n", udist);
v = p1 - p2;
vdist = sqrt( v.x() * v.x() + v.y() * v.y() );
// printf("vdist = %.6f\n", vdist);
uv_dot = u.x() * v.x() + u.y() * v.y();
// printf("uv_dot = %.6f\n", uv_dot);
tmp = uv_dot / (udist * vdist);
// printf("tmp = %.6f\n", tmp);
return acos(tmp);
}
#define BEZIER_DETAIL (8)
#define LINE_WIDTH (0.75)
#define WIREFRAME (1)
#define CURVE_NONE (0)
#define CURVE_LINEAR (1)
#define CURVE_QUADRATIC (2)
#define CURVE_CUBIC (3)
class BezNode
{
public:
BezNode( Point3D l ) : prev_cp(0.0f, 0.0f, 0.0f), next_cp(0.0f, 0.0f, 0.0f)
{
loc = l;
mark = 0;
light = 0;
}
BezNode( double lat, double lon ) : prev_cp(0.0f, 0.0f, 0.0f), next_cp(0.0f, 0.0f, 0.0f)
{
loc = Point3D( lon, lat, 0.0f );
mark = 0;
light = 0;
}
BezNode( Point3D l, Point3D cp )
{
loc = l;
next_cp = cp;
prev_cp = Mirror(cp);
mark = 0;
light = 0;
}
BezNode( double lat, double lon, double cp_lat, double cp_lon )
{
loc = Point3D( lon, lat, 0.0f );
next_cp = Point3D( cp_lon, cp_lat, 0.0f );
prev_cp = Mirror( next_cp );
mark = 0;
light = 0;
}
Point3D Mirror( Point3D pt )
{
// mirror given point about our location
return (loc - (pt - loc));
}
void SetMarking( int m )
{
mark = m;
}
int GetMarking( )
{
return mark;
}
void SetLighting( int l )
{
light = l;
}
int GetLighting( )
{
return light;
}
bool IsAt( double lat, double lon )
{
return ( (loc.lat() == lat) && (loc.lon() == lon) );
}
bool HasPrevCp()
{
return ( (prev_cp.x() != 0.0f) && (prev_cp.y() != 0.0f) );
}
bool HasNextCp()
{
return ( (next_cp.x() != 0.0f) && (next_cp.y() != 0.0f) );
}
Point3D GetLoc()
{
return loc;
}
Point3D GetPrevCp()
{
return prev_cp;
}
Point3D GetNextCp()
{
return next_cp;
}
void ClearNextCp(void)
{
next_cp = Point3D(0.0f,0.0f, 0.0f);
}
void SetNextCp( double lat, double lon )
{
next_cp = Point3D(lon, lat, 0.0f);
}
// TODO: log levels and macros (does terragear have them?)
void Print()
{
SG_LOG(SG_GENERAL, SG_DEBUG,
"\tLoc(" << loc.x() << "," << loc.y() << ")" <<
"\tprev_cp(" << prev_cp.x() << "," << prev_cp.y() << ")" <<
"\tnext_cp(" << next_cp.x() << "," << next_cp.y() << ")" );
}
private:
Point3D loc;
Point3D prev_cp;
Point3D next_cp;
int mark;
int light;
};
// array of BezNodes make a contour
typedef std::vector <BezNode *> BezContour;
typedef std::vector <BezContour *> BezContourArray;
#endif

View file

@ -0,0 +1,656 @@
#include <stdlib.h>
#include <list>
#include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <osg/Geode>
#include <osg/PolygonMode>
#include <osgUtil/Tessellator>
#include <Geometry/poly_support.hxx>
#include "beznode.hxx"
#include "convex_hull.hxx"
#include "closedpoly.hxx"
ClosedPoly::ClosedPoly( int st, float s, float th, char* desc )
{
surface_type = st;
smoothness = s;
texture_heading = th;
if ( desc )
{
strcpy( description, desc );
}
else
{
strcpy( description, "none" );
}
boundary = NULL;
cur_contour = NULL;
cur_feat = NULL;
cur_marking = 0;
}
void ClosedPoly::AddNode( BezNode* node )
{
// if this is the first node of the contour - create a new contour
if (!cur_contour)
{
cur_contour = new BezContour;
}
cur_contour->push_back( node );
SG_LOG(SG_GENERAL, SG_DEBUG, "CLOSEDPOLY::ADDNODE : (" << node->GetLoc().x() << "," << node->GetLoc().y() << ")");
// if recording a linear feature on the pavement, add this node
// to it as well
// TODO: just doing marking now, need lighting as well
if (cur_feat)
{
SG_LOG(SG_GENERAL, SG_DEBUG, " Adding node (" << node->GetLoc().x() << "," << node->GetLoc().y() << ") to current linear feature " << cur_marking);
cur_feat->AddNode( node );
// if it should end, end it, and add to feature list
if (cur_marking != node->GetMarking())
{
SG_LOG(SG_GENERAL, SG_DEBUG, " Node has marking " << node->GetMarking() << " end it");
features.push_back( cur_feat );
cur_feat = NULL;
cur_marking = 0;
}
}
// should we start a new feature here?
SG_LOG(SG_GENERAL, SG_DEBUG, " Node has marking " << node->GetMarking() << " cur marking is " << cur_marking);
if ( (cur_marking == 0) && (node->GetMarking()))
{
// Yes - create a new linear feature
// TODO: With offset, as all pavement markings should be
// a bit in from the edge
SG_LOG(SG_GENERAL, SG_DEBUG, " Starting a new linear feature");
cur_feat = new LinearFeature(NULL);
cur_feat->AddNode( node );
cur_marking = node->GetMarking();
}
}
void ClosedPoly::CreateConvexHull( void )
{
TGPolygon convexHull;
point_list nodes;
Point3D p;
int i;
for (i=0; i<boundary->size(); i++)
{
p = boundary->at(i)->GetLoc();
nodes.push_back( p );
}
convexHull = convex_hull( nodes );
hull = convexHull.get_contour(0);
}
int ClosedPoly::CloseCurContour()
{
SG_LOG(SG_GENERAL, SG_DEBUG, "Close Contour");
// if we are recording a pavement marking - it must be closed -
// add the first node of the poly
if (cur_feat)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "We still have an active linear feature - add the first node to close it");
cur_feat->AddNode( cur_contour->at(0) );
features.push_back( cur_feat );
cur_feat = NULL;
cur_marking = 0;
}
// add the contour to the poly - first one is the outer boundary
// subsequent contours are holes
if ( boundary == NULL )
{
boundary = cur_contour;
// generate the convex hull from the bezcontour node locations
CreateConvexHull();
cur_contour = NULL;
}
else
{
holes.push_back( cur_contour );
cur_contour = NULL;
}
}
void ClosedPoly::ConvertContour( BezContour* src, point_list *dst, bool reverse )
{
BezNode* prevNode;
BezNode* curNode;
BezNode* nextNode;
Point3D prevLoc;
Point3D curLoc;
Point3D nextLoc;
Point3D cp1;
Point3D cp2;
int start, end, inc;
int curve_type = CURVE_LINEAR;
int i;
SG_LOG(SG_GENERAL, SG_DEBUG, "Creating a contour with " << src->size() << " nodes");
// clear anything in this point list
dst->empty();
if (reverse)
{
start = src->size()-1;
end = -1;
inc = -1;
}
else
{
start = 0;
end = src->size();
inc = 1;
}
// iterate through each bezier node in the contour
for (i=0; i <= src->size()-1; i++)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "\nHandling Node " << i << "\n\n");
if (i == 0)
{
// set prev node to last in the contour, as all contours must be closed
prevNode = src->at( src->size()-1 );
}
else
{
// otherwise, it's just the previous index
prevNode = src->at( i-1 );
}
curNode = src->at(i);
if (i < src->size() - 1)
{
nextNode = src->at(i+1);
}
else
{
// for the last node, next is the first. as all contours are closed
nextNode = src->at(0);
}
// determine the type of curve from prev (just to get correct prev location)
// once we start drawing the curve from cur to next, we can just remember the prev loc
if (prevNode->HasNextCp())
{
// curve from prev is cubic or quadratic
if(curNode->HasPrevCp())
{
// curve from prev is cubic : calculate the last location on the curve
prevLoc = CalculateCubicLocation( prevNode->GetLoc(), prevNode->GetNextCp(), curNode->GetPrevCp(), curNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (BEZIER_DETAIL-1) );
}
else
{
// curve from prev is quadratic : use prev node next cp
prevLoc = CalculateQuadraticLocation( prevNode->GetLoc(), prevNode->GetNextCp(), curNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (BEZIER_DETAIL-1) );
}
}
else
{
// curve from prev is quadratic or linear
if( curNode->HasPrevCp() )
{
// curve from prev is quadratic : calculate the last location on the curve
prevLoc = CalculateQuadraticLocation( prevNode->GetLoc(), curNode->GetPrevCp(), curNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (BEZIER_DETAIL-1) );
}
else
{
// curve from prev is linear : just use prev node location
prevLoc = prevNode->GetLoc();
}
}
// now determine how we will iterate from current node to next node
if( curNode->HasNextCp() )
{
// next curve is cubic or quadratic
if( nextNode->HasPrevCp() )
{
// curve is cubic : need both control points
curve_type = CURVE_CUBIC;
cp1 = curNode->GetNextCp();
cp2 = nextNode->GetPrevCp();
}
else
{
// curve is quadratic using current nodes cp as the cp
curve_type = CURVE_QUADRATIC;
cp1 = curNode->GetNextCp();
}
}
else
{
// next curve is quadratic or linear
if( nextNode->HasPrevCp() )
{
// curve is quadratic using next nodes cp as the cp
curve_type = CURVE_QUADRATIC;
cp1 = nextNode->GetPrevCp();
}
else
{
// curve is linear
curve_type = CURVE_LINEAR;
}
}
// initialize current location
curLoc = curNode->GetLoc();
if (curve_type != CURVE_LINEAR)
{
for (int p=0; p<BEZIER_DETAIL; p++)
{
// calculate next location
if (curve_type == CURVE_QUADRATIC)
{
nextLoc = CalculateQuadraticLocation( curNode->GetLoc(), cp1, nextNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (p+1) );
}
else
{
nextLoc = CalculateCubicLocation( curNode->GetLoc(), cp1, cp2, nextNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (p+1) );
}
// add the pavement vertex
// convert from lat/lon to geo
// (maybe later) - check some simgear objects...
dst->push_back( curLoc );
if (p==0)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "adding Curve Anchor node (type " << curve_type << ") at (" << curLoc.x() << "," << curLoc.y() << ")");
}
else
{
SG_LOG(SG_GENERAL, SG_DEBUG, " add bezier node (type " << curve_type << ") at (" << curLoc.x() << "," << curLoc.y() << ")");
}
// now set set prev and cur locations for the next iteration
prevLoc = curLoc;
curLoc = nextLoc;
}
}
else
{
nextLoc = nextNode->GetLoc();
// just add the one vertex - linear
dst->push_back( curLoc );
SG_LOG(SG_GENERAL, SG_DEBUG, "adding Linear Anchor node at (" << curLoc.x() << "," << curLoc.y() << ")");
}
}
// Add the first point again?
// dst->push_back( src->at(0)->GetLoc() );
}
void ExpandPoint( Point3D *prev, Point3D *cur, Point3D *next, double expand_by, double *heading, double *offset )
{
int turn_direction;
bool reverse_dir = false;
double offset_dir;
double next_dir;
double az1, az2;
double dist;
SG_LOG(SG_GENERAL, SG_DEBUG, "Find average angle for contour: prev (" << *prev << "), "
"cur (" << *cur << "), "
"next (" << *next << ")" );
// first, find if the line turns left or right ar src
// for this, take the cross product of the vectors from prev to src, and src to next.
// if the cross product is negetive, we've turned to the left
// if the cross product is positive, we've turned to the right
// if the cross product is 0, then we need to use the direction passed in
SGVec3d dir1 = prev->toSGVec3d() - cur->toSGVec3d();
dir1 = normalize(dir1);
SGVec3d dir2 = next->toSGVec3d() - cur->toSGVec3d();
dir2 = normalize(dir2);
// Now find the average
SGVec3d avg = dir1 + dir2;
avg = normalize(avg);
// find the offset angle
geo_inverse_wgs_84( avg.y(), avg.x(), 0.0f, 0.0f, &offset_dir, &az2, &dist);
// find the direction to the next point
geo_inverse_wgs_84( cur->y(), cur->x(), next->y(), next->x(), &next_dir, &az2, &dist);
// calculate correct distance for the offset point
*offset = (expand_by)/sin(SGMiscd::deg2rad(offset_dir-next_dir));
*heading = offset_dir;
SG_LOG(SG_GENERAL, SG_DEBUG, "heading is " << *heading << " distance is " << *offset );
}
void ClosedPoly::ExpandContour( point_list& src, TGPolygon& dst, double dist )
{
point_list expanded_boundary;
Point3D prevPoint, curPoint, nextPoint;
double theta;
double expand_by;
double expanded_x, expanded_y;
Point3D expanded_point;
double h1, h2, h3;
double o1, o2, o3;
double az2;
int i;
// iterate through each bezier node in the contour
for (i=0; i<src.size(); i++)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "\nExpanding point " << i << "\n\n");
if (i == 0)
{
// set prev node to last in the contour, as all contours must be closed
prevPoint = src.at( src.size()-1 );
}
else
{
// otherwise, it's just the last index
prevPoint = src.at( i-1 );
}
curPoint = src.at(i);
if (i<src.size()-1)
{
nextPoint = src.at(i+1);
}
else
{
// for the last node, next is the first. as all contours are closed
nextPoint = src.at(0);
}
// calculate the angle between cur->prev and cur->next
theta = SGMiscd::rad2deg(CalculateTheta(prevPoint, curPoint, nextPoint));
if ( theta < 90.0 )
{
SG_LOG(SG_GENERAL, SG_DEBUG, "\nClosed POLY case 1 (theta < 90) " << description << ": theta is " << theta );
// calculate the expanded point heading and offset from current point
ExpandPoint( &prevPoint, &curPoint, &nextPoint, dist, &h1, &o1 );
if (o1 > dist*2.0)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "\ntheta is " << theta << " distance is " << o1 << " CLAMPING to " << dist*2 );
o1 = dist*2;
if (o1 > 100)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "\nClosed POLY " << description << ": theta is " << theta << " distance is " << o1 << " WHAT HAPPENED " );
exit(1);
}
}
geo_direct_wgs_84( curPoint.y(), curPoint.x(), h1, o1, &expanded_y, &expanded_x, &az2 );
expanded_point = Point3D( expanded_x, expanded_y, 0.0f );
expanded_boundary.push_back( expanded_point );
}
else if ( abs(theta - 180.0) < 0.1 )
{
SG_LOG(SG_GENERAL, SG_DEBUG, "\nClosed POLY case 2 (theta close to 180) " << description << ": theta is " << theta );
// calculate the expanded point heading and offset from current point
ExpandPoint( &prevPoint, &curPoint, &nextPoint, dist, &h1, &o1 );
// straight line blows up math - dist should be exactly as given
o1 = dist;
geo_direct_wgs_84( curPoint.y(), curPoint.x(), h1, o1, &expanded_y, &expanded_x, &az2 );
expanded_point = Point3D( expanded_x, expanded_y, 0.0f );
expanded_boundary.push_back( expanded_point );
}
else
{
SG_LOG(SG_GENERAL, SG_DEBUG, "\nClosed POLY case 3 (fall through) " << description << ": theta is " << theta );
// calculate the expanded point heading and offset from current point
ExpandPoint( &prevPoint, &curPoint, &nextPoint, dist, &h1, &o1 );
if (o1 > dist*2)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "\ntheta is " << theta << " distance is " << o1 << " WHAT HAPPENED " );
exit(1);
}
geo_direct_wgs_84( curPoint.y(), curPoint.x(), h1, o1, &expanded_y, &expanded_x, &az2 );
expanded_point = Point3D( expanded_x, expanded_y, 0.0f );
expanded_boundary.push_back( expanded_point );
}
}
dst.add_contour( expanded_boundary, 9 );
}
osg::DrawArrays* ClosedPoly::CreateOsgPrimitive( point_list contour, osg::Vec3Array* vpave )
{
int i;
Point3D p;
osg::DrawArrays* primitive;
int start_vert = vpave->size();
for (i=0; i<contour.size(); i++)
{
p = contour[i];
vpave->push_back( osg::Vec3d(p.x(), p.y(), 0.0) );
}
primitive = new osg::DrawArrays(osg::PrimitiveSet::POLYGON, start_vert, vpave->size()-start_vert);
return primitive;
}
// finish the poly - convert to TGPolygon, and tesselate
int ClosedPoly::Finish()
{
BezContour* src_contour;
point_list dst_contour;
BezNode* node;
// error handling
if (boundary == NULL)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "no boundary");
}
SG_LOG(SG_GENERAL, SG_DEBUG, "Converting a poly with " << holes.size() << " holes");
if (boundary != NULL)
{
// create the boundary
ConvertContour( boundary, &dst_contour, false );
// and add it to the geometry
pre_tess.add_contour( dst_contour, 0 );
// The convert the hole contours
for (int i=0; i<holes.size(); i++)
{
dst_contour.clear();
ConvertContour( holes[i], &dst_contour, false );
pre_tess.add_contour( dst_contour, 1 );
}
}
// save memory by deleting unneeded resources
delete boundary;
boundary = NULL;
// The convert the hole contours
holes.clear();
}
int ClosedPoly::BuildOsg( osg::Group* airport )
{
BezContour* contour;
BezNode* node;
osg::Geode* geode_pave; // has the stateset, and geometry for this poly
osg::Geometry* pavement;
osg::StateSet* ss_pave; // just a simple stateset for now
osg::PolygonMode* polymode;
osg::Vec4Array* col_pave; // just grey for now...
osg::Vec3Array* v_pave; // ALL verticies (boundary and holes)
osg::DrawArrays* primitive; // an index array for boundary / hole
int num_verts; // number of verticies in a contour
int i; // ?
if ( pre_tess.contours() )
{
// Setup a polygonmode for wireframe debuging
polymode = new osg::PolygonMode;
polymode->setMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
// Create a drawable for the pavement poly (boundary and holes)
pavement = new osg::Geometry;
// make pavement grey : do this when reading the poly
col_pave = new osg::Vec4Array;
col_pave->push_back(osg::Vec4(0.5f,0.5f,0.5f,1.0f));
pavement->setColorArray(col_pave);
pavement->setColorBinding(osg::Geometry::BIND_OVERALL);
// set up pavement stateset
geode_pave = new osg::Geode();
ss_pave = new osg::StateSet();
#if WIREFRAME
ss_pave->setAttribute( polymode );
#endif
geode_pave->setStateSet(ss_pave);
v_pave = new osg::Vec3Array;
pavement->setVertexArray(v_pave);
// create the boundary
SG_LOG(SG_GENERAL, SG_DEBUG, " Adding pavement boundary");
primitive = CreateOsgPrimitive( pre_tess.get_contour( 0 ), v_pave );
if (hull.size() > 0)
{
SG_LOG(SG_GENERAL, SG_DEBUG, " boundary has " << hull.size() << "verts" );
}
// add the hole contours
for (i=1; i<pre_tess.contours(); i++)
{
primitive = CreateOsgPrimitive( pre_tess.get_contour( i ), v_pave );
pavement->addPrimitiveSet(primitive);
}
osgUtil::Tessellator *tess = new osgUtil::Tessellator;
tess->setTessellationType(osgUtil::Tessellator::TESS_TYPE_GEOMETRY);
tess->retessellatePolygons(*pavement);
geode_pave->addDrawable(pavement);
airport->addChild(geode_pave);
#if 0 // debug ExpandPoly
TGPolygon base;
ExpandPoly( hull, base, 20 );
primitive = CreateOsgPrimitive( base.get_contour( 0 ), v_pave );
pavement->addPrimitiveSet(primitive);
#endif
geode_pave->addDrawable(pavement);
airport->addChild(geode_pave);
// add the pavement markings
#if 0
printf("ClosedPoly::Finish - Finish %d linear features\n", features.size());
for (int feat=0; feat<features.size(); feat++)
{
features.at(feat)->Finish(airport);
}
#endif
}
}
int ClosedPoly::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, TGPolygon* accum, TGPolygon* apt_base, TGPolygon* apt_clearing )
{
TGPolygon base, safe_base;
string material;
int j, k;
material = "pa_tiedown";
// verify the poly has been generated
if ( pre_tess.contours() )
{
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: original poly has " << pre_tess.contours() << " contours");
// do this before clipping and generating the base
pre_tess = remove_dups( pre_tess );
pre_tess = reduce_degeneracy( pre_tess );
for (int c=0; c<pre_tess.contours(); c++)
{
for (int pt=0; pt<pre_tess.contour_size(c); pt++)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: contour " << c << " pt " << pt << ": (" << pre_tess.get_pt(c, pt).x() << "," << pre_tess.get_pt(c, pt).y() << ")" );
}
}
TGSuperPoly sp;
TGTexParams tp;
TGPolygon clipped = tgPolygonDiff( pre_tess, *accum );
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: clipped poly has " << clipped.contours() << " contours");
TGPolygon split = tgPolygonSplitLongEdges( clipped, 400.0 );
SG_LOG(SG_GENERAL, SG_DEBUG, "BuildBtg: split poly has " << split.contours() << " contours");
sp.erase();
sp.set_poly( split );
sp.set_material( material );
rwy_polys->push_back( sp );
SG_LOG(SG_GENERAL, SG_DEBUG, "clipped = " << clipped.contours());
*accum = tgPolygonUnion( pre_tess, *accum );
tp = TGTexParams( pre_tess.get_pt(0,0), 20.0 /* TODO poly width */, 20.0 /* TODO poly length */, texture_heading );
texparams->push_back( tp );
ExpandContour( hull, base, 20.0 );
ExpandContour( hull, safe_base, 50.0 );
// add this to the airport clearing
*apt_clearing = tgPolygonUnion( safe_base, *apt_clearing);
// and add the clearing to the base
*apt_base = tgPolygonUnion( base, *apt_base );
}
// clean up to save ram : we're done here...
return 1;
}

View file

@ -0,0 +1,66 @@
#ifndef _BEZPOLY_H_
#define _BEZPOLY_H_
#include "beznode.hxx"
#include "linearfeature.hxx"
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include <Geometry/point3d.hxx>
#include "texparams.hxx"
#include <osg/Geometry>
#include <osg/Vec3d>
using std::string;
class ClosedPoly
{
public:
ClosedPoly( int st, float s, float th, char* desc );
void AddNode( BezNode* node );
int CloseCurContour();
int Finish();
int BuildOsg( osg::Group* airport );
int BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, TGPolygon* accum, TGPolygon* apt_base, TGPolygon* apt_clearing );
private:
//osg::DrawArrays* CreatePrimitive( BezContour* contour, osg::Vec3Array* v_pave );
// convert the BezierPoly to a normal Poly (adding nodes for the curves)
void CreateConvexHull( void );
void ConvertContour( BezContour* src, point_list *dst, bool reverse );
osg::DrawArrays* CreateOsgPrimitive( point_list contour, osg::Vec3Array* vpave );
void ExpandContour( point_list& src, TGPolygon& dst, double dist );
int surface_type;
float smoothness;
float texture_heading;
char description[64];
// outer boundary definition as bezier nodes
BezContour* boundary;
// holes
BezContourArray holes;
// contour that nodes will be added until done
BezContour* cur_contour;
// outer boundary as convex hull
point_list hull;
// Converted polygon after parsing complete
TGPolygon pre_tess;
// pavement definitions can have multiple linear features (markings)
LinearFeature* cur_feat;
FeatureList features;
int cur_marking;
};
typedef std::vector <ClosedPoly *> PavementList;
#endif

View file

@ -0,0 +1,252 @@
// convex_hull.cxx -- calculate the convex hull of a set of points
//
// Written by Curtis Olson, started September 1998.
//
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id: convex_hull.cxx,v 1.12 2004-11-19 22:25:49 curt Exp $
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <math.h>
#include <stdio.h>
#include <map>
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/structure/exception.hxx>
#include <simgear/constants.h>
#include "convex_hull.hxx"
#include "point2d.hxx"
using std::less;
using std::map;
// stl map typedefs
typedef map < double, double, less<double> > map_container;
typedef map_container::iterator map_iterator;
// Calculate theta of angle (a, b, c)
double calc_angle(Point3D a, Point3D b, Point3D c) {
Point3D u, v;
double udist, vdist, uv_dot, tmp;
// u . v = ||u|| * ||v|| * cos(theta)
u.setx( b.x() - a.x() );
u.sety( b.y() - a.y() );
udist = sqrt( u.x() * u.x() + u.y() * u.y() );
// printf("udist = %.6f\n", udist);
v.setx( b.x() - c.x() );
v.sety( b.y() - c.y() );
vdist = sqrt( v.x() * v.x() + v.y() * v.y() );
// printf("vdist = %.6f\n", vdist);
uv_dot = u.x() * v.x() + u.y() * v.y();
// printf("uv_dot = %.6f\n", uv_dot);
tmp = uv_dot / (udist * vdist);
// printf("tmp = %.6f\n", tmp);
return acos(tmp);
}
// Test to see if angle(Pa, Pb, Pc) < 180 degrees
bool test_point(Point3D Pa, Point3D Pb, Point3D Pc) {
double a1, a2;
Point3D origin( 0.0 );
Point3D a( cos(Pa.y()) * Pa.x(),
sin(Pa.y()) * Pa.x(), 0 );
Point3D b( cos(Pb.y()) * Pb.x(),
sin(Pb.y()) * Pb.x(), 0 );
Point3D c( cos(Pc.y()) * Pc.x(),
sin(Pc.y()) * Pc.x(), 0 );
// printf("a is %.6f %.6f\n", a.x, a.y);
// printf("b is %.6f %.6f\n", b.x, b.y);
// printf("c is %.6f %.6f\n", c.x, c.y);
a1 = calc_angle(a, b, origin);
a2 = calc_angle(origin, b, c);
// printf("a1 = %.2f a2 = %.2f\n", a1 * SGD_RADIANS_TO_DEGREES, a2 * SGD_RADIANS_TO_DEGREES);
return ( (a1 + a2) < SGD_PI );
}
// calculate the convex hull of a set of points, return as a list of
// point2d. The algorithm description can be found at:
// http://riot.ieor.berkeley.edu/riot/Applications/ConvexHull/CHDetails.html
TGPolygon convex_hull( const point_list& input_list ) {
int i;
map_iterator map_current, map_next, map_next_next, map_last;
// list of translated points
point_list trans_list;
// points sorted by radian degrees
map_container radians_map;
// will contain the convex hull
TGPolygon con_hull;
Point3D p, Pa, Pb, Pc, result;
double sum_x, sum_y;
int in_count, last_size;
// STEP ONE: Find an average midpoint of the input set of points
in_count = input_list.size();
sum_x = sum_y = 0.0;
for ( i = 0; i < in_count; ++i ) {
sum_x += input_list[i].x();
sum_y += input_list[i].y();
}
Point3D average( sum_x / in_count, sum_y / in_count, 0 );
// printf("Average center point is %.4f %.4f\n", average.x, average.y);
// STEP TWO: Translate input points so average is at origin
trans_list.clear();
for ( i = 0; i < in_count; ++i ) {
p = Point3D( input_list[i].x() - average.x(),
input_list[i].y() - average.y(), 0 );
// printf("%.6f %.6f\n", p.x, p.y);
trans_list.push_back( p );
}
// STEP THREE: convert to radians and sort by theta
radians_map.clear();
for ( i = 0; i < in_count; ++i ) {
p = cart_to_polar_2d( trans_list[i] );
if ( p.x() > radians_map[p.y()] ) {
radians_map[p.y()] = p.x();
}
}
/*
// printf("Sorted list\n");
map_current = radians_map.begin();
map_last = radians_map.end();
for ( ; map_current != map_last ; ++map_current ) {
p.setx( (*map_current).first );
p.sety( (*map_current).second );
printf("p is %.6f %.6f\n", p.x(), p.y());
}
*/
// STEP FOUR: traverse the sorted list and eliminate everything
// not on the perimeter.
// printf("Traversing list\n");
// double check list size ... this should never fail because a
// single runway will always generate four points.
if ( radians_map.size() < 3 ) {
throw sg_exception("convex hull not possible with < 3 points");
}
// ensure that we run the while loop at least once
last_size = radians_map.size() + 1;
while ( last_size > (int)radians_map.size() ) {
// printf("Running an iteration of the graham scan algorithm\n");
last_size = radians_map.size();
map_current = radians_map.begin();
while ( map_current != radians_map.end() ) {
// get first element
Pa.sety( (*map_current).first );
Pa.setx( (*map_current).second );
// get second element
map_next = map_current;
++map_next;
if ( map_next == radians_map.end() ) {
map_next = radians_map.begin();
}
Pb.sety( (*map_next).first );
Pb.setx( (*map_next).second );
// get third element
map_next_next = map_next;
++map_next_next;
if ( map_next_next == radians_map.end() ) {
map_next_next = radians_map.begin();
}
Pc.sety( (*map_next_next).first );
Pc.setx( (*map_next_next).second );
// printf("Pa is %.6f %.6f\n", Pa.y(), Pa.x());
// printf("Pb is %.6f %.6f\n", Pb.y(), Pb.x());
// printf("Pc is %.6f %.6f\n", Pc.y(), Pc.x());
if ( test_point(Pa, Pb, Pc) ) {
// printf("Accepted a point\n");
// accept point, advance Pa, Pb, and Pc.
++map_current;
} else {
// printf("REJECTED A POINT\n");
// reject point, delete it and advance only Pb and Pc
map_next = map_current;
++map_next;
if ( map_next == radians_map.end() ) {
map_next = radians_map.begin();
}
radians_map.erase( map_next );
}
}
}
// translate back to correct lon/lat
// printf("Final sorted convex hull\n");
con_hull.erase();
map_current = radians_map.begin();
map_last = radians_map.end();
for ( ; map_current != map_last ; ++map_current ) {
p.sety( (*map_current).first );
p.setx( (*map_current).second );
result.setx( cos(p.y()) * p.x() + average.x() );
result.sety( sin(p.y()) * p.x() + average.y() );
// printf("%.6f %.6f\n", result.x, result.y);
con_hull.add_node(0, result);
}
return con_hull;
}

View file

@ -0,0 +1,47 @@
// convex_hull.hxx -- calculate the convex hull of a set of points
//
// Written by Curtis Olson, started September 1998.
//
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id: convex_hull.hxx,v 1.5 2004-11-19 22:25:49 curt Exp $
//
#ifndef _CONVEX_HULL_HXX
#define _CONVEX_HULL_HXX
#include <list>
#include <simgear/math/sg_types.hxx>
#include <Polygon/polygon.hxx>
#include "point2d.hxx"
// calculate the convex hull of a set of points, return as a list of
// point2d. The algorithm description can be found at:
// http://riot.ieor.berkeley.edu/riot/Applications/ConvexHull/CHDetails.html
TGPolygon convex_hull( const point_list& input_list );
#endif // _CONVEX_HULL_HXX

View file

@ -145,7 +145,6 @@ double tgAverageElevation( const string &root, const string_list elev_src,
// lookup node elevations for each point in the specified simple
// matrix. Returns average of all points.
void tgCalcElevations( const string &root, const string_list elev_src,
SimpleMatrix &Pts, const double average )
{
@ -252,7 +251,6 @@ void tgCalcElevations( const string &root, const string_list elev_src,
<< grid_average);
}
// clamp all elevations to the specified range
void tgClampElevations( SimpleMatrix &Pts,

View file

@ -48,9 +48,7 @@ double tgAverageElevation( const string &root, const string_list elev_src,
// lookup node elevations for each point in the specified nurbs++
// matrix.
void tgCalcElevations( const string &root, const string_list elev_src,
SimpleMatrix &Pts, double average );
void tgCalcElevations( const string &root, const string_list elev_src, SimpleMatrix &Pts, double average );
// clamp all elevations to the specified range
void tgClampElevations( SimpleMatrix &Pts,
double center_m, double max_clamp_m );
void tgClampElevations( SimpleMatrix &Pts, double center_m, double max_clamp_m );

View file

@ -0,0 +1,550 @@
#include "beznode.hxx"
#include "linearfeature.hxx"
#include "math.h"
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/SGVec3.hxx>
#include <simgear/math/SGMisc.hxx>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/PolygonMode>
#include <osg/PolygonOffset>
int LinearFeature::Finish( osg::Group* airport )
{
BezNode* node;
int i, j;
int prev_dir = 0;
double direction;
double dist1, dist2;
printf("Finish a %s Linear Feature with %d verticies\n", closed ? "closed" : "open", contour.size());
BezNode* prevNode;
BezNode* curNode;
BezNode* nextNode;
Point3D prevLoc;
Point3D curLoc;
Point3D nextLoc;
Point3D st_cur1;
Point3D st_cur2;
double st_curx, st_cury, az2;
// create a DrawElement for the stripe triangle strip
int stripe_idx = 0;
int cur_marking = 0;
osg::Vec3dArray* v_stripe = new osg::Vec3dArray;
for (i=0; i<contour.size(); i++)
{
printf("\nHandling Node %d\n\n", i );
if (i == 0)
{
// if closed, set prev node to last in the contour
if (closed)
{
prevNode = contour.at( contour.size()-1 );
}
else
{
prevNode = NULL;
}
}
else
{
prevNode = contour.at( i-1 );
}
curNode = contour.at(i);
if (i<contour.size()-1)
{
nextNode = contour.at(i+1);
}
else
{
// if closed, set next node to the first in the contour
if (closed)
{
nextNode = contour.at(0);
}
else
{
nextNode = NULL;
}
}
// determine the type of curve from prev (just to get correct prev location)
// once we start drawing the curve from cur to next, we can just remember the prev loc
if (prevNode)
{
if (prevNode->HasNextCp())
{
// curve from prev is cubic or quadratic
if(curNode->HasPrevCp())
{
// curve from prev is cubic : calculate the last location on the curve
prevLoc = CalculateCubicLocation( prevNode->GetLoc(), prevNode->GetNextCp(), curNode->GetPrevCp(), curNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (BEZIER_DETAIL-1) );
}
else
{
// curve from prev is quadratic : use prev node next cp
prevLoc = CalculateQuadraticLocation( prevNode->GetLoc(), prevNode->GetNextCp(), curNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (BEZIER_DETAIL-1) );
}
}
else
{
// curve from prev is quadratic or linear
if( curNode->HasPrevCp() )
{
// curve from prev is quadratic : calculate the last location on the curve
prevLoc = CalculateQuadraticLocation( prevNode->GetLoc(), curNode->GetPrevCp(), curNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (BEZIER_DETAIL-1) );
}
else
{
// curve from prev is linear : just use prev node location
prevLoc = prevNode->GetLoc();
}
}
}
else
{
prevLoc = Point3D(0.0f, 0.0f, 0.0f);
}
int curve_type = CURVE_LINEAR;
Point3D cp1;
Point3D cp2;
if ( nextNode)
{
// now determine how we will iterate through cur node to next node
if( curNode->HasNextCp() )
{
// next curve is cubic or quadratic
if( nextNode->HasPrevCp() )
{
// curve is cubic : need both control points
curve_type = CURVE_CUBIC;
cp1 = curNode->GetNextCp();
cp2 = nextNode->GetPrevCp();
}
else
{
// curve is quadratic using current nodes cp as the cp
curve_type = CURVE_QUADRATIC;
cp1 = curNode->GetNextCp();
}
}
else
{
// next curve is quadratic or linear
if( nextNode->HasPrevCp() )
{
// curve is quadratic using next nodes cp as the cp
curve_type = CURVE_QUADRATIC;
cp1 = nextNode->GetPrevCp();
}
else
{
// curve is linear
curve_type = CURVE_LINEAR;
}
}
}
else
{
curve_type = CURVE_NONE;
}
// initialize current location
curLoc = curNode->GetLoc();
switch( curve_type )
{
case CURVE_QUADRATIC:
case CURVE_CUBIC:
for (int p=0; p<BEZIER_DETAIL; p++)
{
// calculate next location
if (curve_type == CURVE_QUADRATIC)
{
nextLoc = CalculateQuadraticLocation( curNode->GetLoc(), cp1, nextNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (p+1) );
}
else
{
nextLoc = CalculateCubicLocation( curNode->GetLoc(), cp1, cp2, nextNode->GetLoc(), (1.0f/BEZIER_DETAIL) * (p+1) );
}
// set the verticies
// convert from lat/lon to geodisc
// (maybe later) - check some simgear objects...
// printf("Added vertex at %lf,%lf\n",
// add the pavement vertex
if (p==0)
{
printf("adding Curve Anchor node (type %d) at (%lf,%lf)\n", curve_type, curLoc.x(), curLoc.y());
}
else
{
printf(" add bezier node (type %d) at (%lf,%lf)\n", curve_type, curLoc.x(), curLoc.y());
}
// find the average direction at this vertex...
direction = CalcMarkingVerticies( &prevLoc, &curLoc, &nextLoc, -1, &prev_dir, &dist1, &dist2 );
printf("got dir for bezier : prev_dir %d, dist1 %lf, dist2 %lf\n", prev_dir, dist1, dist2);
// distance can't be constant - it's the hypotenous of a right triangler with a constant offset from the outer rim.
geo_direct_wgs_84( curLoc.x(), curLoc.y(), direction, dist1, &st_curx, &st_cury, &az2 );
st_cur1 = Point3D( st_curx, st_cury, 0.0f );
v_stripe->push_back( SGPoint3DtoOSGVec3d(st_cur1) );
geo_direct_wgs_84( curLoc.x(), curLoc.y(), direction, dist2, &st_curx, &st_cury, &az2 );
st_cur2 = Point3D( st_curx, st_cury, 0.0f );
v_stripe->push_back( SGPoint3DtoOSGVec3d(st_cur2) );
printf("node at (%lf,%lf) has stripe verticies (%lf,%lf) and (%lf,%lf)\n",
curLoc.x(), curLoc.y(),
st_cur1.x(), st_cur1.y(),
st_cur2.x(), st_cur2.y()
);
// now set set prev and cur locations for the next iteration
prevLoc = curLoc;
curLoc = nextLoc;
}
break;
case CURVE_LINEAR:
nextLoc = nextNode->GetLoc();
printf("adding Linear Anchor node at (%lf,%lf)\n", curLoc.x(), curLoc.y());
// find the average direction at this vertex...
direction = CalcMarkingVerticies( &prevLoc, &curLoc, &nextLoc, -1, &prev_dir, &dist1, &dist2 );
printf("got dir for linear : prev_dir %d, dist1 %lf, dist2 %lf\n", prev_dir, dist1, dist2);
// distance can't be constant - it's the hypotenous of a right triangler with a constant offset from the outer rim.
printf("calc direct: curLoc is (%lf,%lf), direction is %lf, dist is %lf\n", curLoc.x(), curLoc.y(), direction, dist1);
geo_direct_wgs_84( curLoc.x(), curLoc.y(), direction, dist1, &st_curx, &st_cury, &az2 );
st_cur1 = Point3D( st_curx, st_cury, 0.0f );
v_stripe->push_back( SGPoint3DtoOSGVec3d(st_cur1) );
geo_direct_wgs_84( curLoc.x(), curLoc.y(), direction, dist2, &st_curx, &st_cury, &az2 );
st_cur2 = Point3D( st_curx, st_cury, 0.0f );
v_stripe->push_back( SGPoint3DtoOSGVec3d(st_cur2) );
printf("node at (%lf,%lf) has stripe verticies (%lf,%lf) and (%lf,%lf)\n",
curLoc.x(), curLoc.y(),
st_cur1.x(), st_cur1.y(),
st_cur2.x(), st_cur2.y()
);
break;
case CURVE_NONE:
nextLoc = Point3D(0.0f, 0.0f, 0.0f);
// we need to add the last verticies based on cur and prev position.
// find the average direction at this vertex...
direction = CalcMarkingVerticies( &prevLoc, &curLoc, &nextLoc, -1, &prev_dir, &dist1, &dist2 );
printf("got dir for term points : prev_dir %lf, dist1 %lf, dist2 %lf\n", prev_dir, dist1, dist2);
// distance can't be constant - it's the hypotenous of a right triangler with a constant offset from the outer rim.
geo_direct_wgs_84( curLoc.x(), curLoc.y(), direction, dist1, &st_curx, &st_cury, &az2 );
st_cur1 = Point3D( st_curx, st_cury, 0.0f );
v_stripe->push_back( SGPoint3DtoOSGVec3d(st_cur1) );
geo_direct_wgs_84( curLoc.x(), curLoc.y(), direction, dist2, &st_curx, &st_cury, &az2 );
st_cur2 = Point3D( st_curx, st_cury, 0.0f );
v_stripe->push_back( SGPoint3DtoOSGVec3d(st_cur2) );
printf("node at (%lf,%lf) has stripe verticies (%lf,%lf) and (%lf,%lf)\n",
curLoc.x(), curLoc.y(),
st_cur1.x(), st_cur1.y(),
st_cur2.x(), st_cur2.y()
);
break;
}
}
printf("End feature %d \n", v_stripe->size() );
airport->addChild(FinishMarking( v_stripe ) );
}
int LinearFeature::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, TGPolygon* accum, TGPolygon* apt_base, TGPolygon* apt_clearing )
{
string material;
return 1;
}
// this should be in the class
// TODO: Should Be AddMidMarkingVerticies - and handle offset (used in LinearFeature::Finish only)
double CalcMiddleMarkingVerticies( Point3D *prev, Point3D *cur, Point3D *next, int wind, int *prev_dir, double *dist1, double *dist2 )
{
int turn_direction;
bool reverse_dir = false;
double offset_dir;
double next_dir;
double az1, az2;
double dist;
printf("Find averate angle for mark: prev (%lf,%lf), cur(%lf,%lf), next(%lf,%lf)\n", prev->x(), prev->y(), cur->x(), cur->y(), next->x(), next->y());
// first, find if the line turns left or right ar src
// for this, take the cross product of the vectors from prev to src, and src to next.
// if the cross product is negetive, we've turned to the left
// if the cross product is positive, we've turned to the right
// if the cross product is 0, then we need to use the direction passed in
SGVec3d dir1 = cur->toSGVec3d() - prev->toSGVec3d();
dir1 = normalize(dir1);
printf("normalized dir1 is (%lf,%lf)\n", dir1.x(), dir1.y());
SGVec3d dir2 = next->toSGVec3d() - cur->toSGVec3d();
dir2 = normalize(dir2);
printf("normalized dir2 is (%lf,%lf)\n", dir2.x(), dir2.y());
SGVec3d cp = cross(dir1,dir2);
if (cp.z() < 0.0)
{
turn_direction = -1;
}
else if (cp.z() > 0.0)
{
turn_direction = 1;
}
else
{
turn_direction = 0;
}
printf("turn direction is %d\n", turn_direction);
// Now find the average
SGVec3d avg = -dir1 + dir2;
printf("avg is (%lf,%lf)\n", avg.x(), avg.y());
// now determine which way the direction needs to point
if ((wind == -1) && (turn_direction == 1))
{
reverse_dir = true;
}
if ((wind == 1) && (turn_direction == -1))
{
reverse_dir = true;
}
printf("reverse dir is %d\n", reverse_dir);
// find the offset angle
geo_inverse_wgs_84( 0.0f, 0.0f, avg.x(), avg.y(), &offset_dir, &az2, &dist);
if (reverse_dir)
{
offset_dir += 180;
while (offset_dir >= 360.0)
{
offset_dir -= 360.0;
}
}
printf("offset direction is %lf\n", offset_dir);
// find the direction to the next point
geo_inverse_wgs_84( cur->x(), cur->y(), next->x(), next->y(), &next_dir, &az2, &dist);
printf("next direction is %lf\n", next_dir);
// calculate correct distance for the offset point
*dist1 = (-LINE_WIDTH)/sin(SGMiscd::deg2rad(next_dir-offset_dir));
*dist2 = (LINE_WIDTH)/sin(SGMiscd::deg2rad(next_dir-offset_dir));
return offset_dir;
}
// TODO: Should Be AddStartMarkingVerticies - and handle offset (used in LinearFeature::Finish only)
double CalcStartMarkingVerticies( Point3D *cur, Point3D *next, int wind, int *prev_dir, double *dist1, double *dist2 )
{
double offset_dir;
double az1, az2;
double dist;
printf("Find start angle for mark: cur(%lf,%lf), next(%lf,%lf)\n", cur->x(), cur->y(), next->x(), next->y());
// find the offset angle
geo_inverse_wgs_84( cur->x(), cur->y(), next->x(), next->y(), &offset_dir, &az2, &dist);
offset_dir -= 90;
if (offset_dir < 0)
{
offset_dir += 360;
}
printf("offset direction is %lf\n", offset_dir);
// calculate correct distance for the offset point
*dist1 = (-LINE_WIDTH);
*dist2 = (LINE_WIDTH);
return offset_dir;
}
// TODO: Should Be AddEndMarkingVerticies - and handle offset (used in LinearFeature::Finish only)
double CalcEndMarkingVerticies( Point3D *prev, Point3D *cur, int wind, int *prev_dir, double *dist1, double *dist2 )
{
double offset_dir;
double az1, az2;
double dist;
printf("Find end angle for mark: prev(%lf,%lf), cur(%lf,%lf)\n", prev->x(), prev->y(), cur->x(), cur->y());
// find the offset angle
geo_inverse_wgs_84( prev->x(), prev->y(), cur->x(), cur->y(), &offset_dir, &az2, &dist);
offset_dir -= 90;
if (offset_dir < 0)
{
offset_dir += 360;
}
printf("offset direction is %lf\n", offset_dir);
// calculate correct distance for the offset point
*dist1 = (-LINE_WIDTH);
*dist2 = (LINE_WIDTH);
return offset_dir;
}
// TODO: Should Be AddMarkingVerticies - and handle offset (used in LinearFeature::Finish only)
double CalcMarkingVerticies( Point3D *prev, Point3D *cur, Point3D *next, int wind, int *prev_dir, double *dist1, double *dist2 )
{
double offset_dir;
// first, we need to see if we want to average the directions (we have both prev, and next)
if ( (prev->x() == 0.0f) && (prev->y() == 0.0f) )
{
// direction is 90 degrees less than from current to next
offset_dir = CalcStartMarkingVerticies( cur, next, wind, prev_dir, dist1, dist2 );
printf("got dist 1: %lf, dist2: %lf\n", *dist1, *dist2);
}
else if ( (next->x() == 0.0f) && (next->y() == 0.0f) )
{
// direction is 90 degrees less than from current to next
offset_dir = CalcEndMarkingVerticies( prev, cur, wind, prev_dir, dist1, dist2 );
printf("got dist 1: %lf, dist2: %lf\n", *dist1, *dist2);
}
else
{
offset_dir = CalcMiddleMarkingVerticies( prev, cur, next, wind, prev_dir, dist1, dist2 );
printf("got dist 1: %lf, dist2: %lf\n", *dist1, *dist2);
}
printf("return from CalcMarkingVerticies: dirst1: %lf, dist2: %lf\n", *dist1, *dist2);
return offset_dir;
}
// need to refactor this stuff.
osg::Geode* FinishMarking( osg::Vec3dArray* verticies )
{
osg::Geometry* stripe = NULL;
osg::Geode* geode_stripe = NULL;
osg::StateSet* ss_stripe = NULL;
osg::PolygonMode* polymode = NULL;
osg::Vec4Array* col_stripe = NULL;
int j;
// set up polygon offset
osg::PolygonOffset* polyoffset = new osg::PolygonOffset;
polyoffset->setFactor(-1.00f);
polyoffset->setUnits(-1.00f);
polymode = new osg::PolygonMode;
polymode->setMode( osg::PolygonMode::FRONT_AND_BACK, osg::PolygonMode::LINE );
col_stripe = new osg::Vec4Array;
col_stripe->push_back(osg::Vec4(1.0f,1.0f,0.0f,1.0f));
// Create a new stripe geometry
stripe = new osg::Geometry;
stripe->setColorArray(col_stripe);
stripe->setColorBinding(osg::Geometry::BIND_OVERALL);
ss_stripe = new osg::StateSet();
ss_stripe->setAttributeAndModes(polyoffset,osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
#if WIREFRAME
ss_stripe->setAttributeAndModes(polymode,osg::StateAttribute::OVERRIDE|osg::StateAttribute::ON);
#endif
geode_stripe = new osg::Geode();
geode_stripe->setStateSet(ss_stripe);
stripe->setVertexArray(verticies);
// create the index array for the stripe
osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_TRIANGLE_STRIP,verticies->size()));
for (j=0; j<verticies->size(); j++)
{
drawElements[j] = j;
}
for (int k=0; k<j; k++)
{
printf("index %d is %d\n", k, drawElements[k]);
}
stripe->addPrimitiveSet(&drawElements);
geode_stripe->addDrawable(stripe);
return geode_stripe;
}
// TODO: Add this into Linear Feature
osg::Vec3dArray* StartMarking()
{
osg::Vec3dArray* v_marking = new osg::Vec3dArray;
return v_marking;
}
// TODO: move this into LinearFeature
osg::Vec3dArray* CheckMarking(int cur_marking, int new_marking, osg::Vec3dArray* v_marking, osg::Group* airport)
{
// check if we need to finish a marking
printf("Check Marking : current is %d, new is %d\n", cur_marking, new_marking);
if ( (v_marking != NULL) && (cur_marking != new_marking) )
{
printf("End current marking %d and start new marking %d : mark poly has %d verticies\n", cur_marking, new_marking, v_marking->size() );
for (int k=0; k<v_marking->size(); k++)
{
printf("vertex %d is (%lf, %lf)\n", k, v_marking->at(k).x(), v_marking->at(k).y());
}
// END THE CURRENT MARKING
airport->addChild(FinishMarking( v_marking ) );
v_marking = NULL;
}
// Start recording a new marking
if ( (v_marking == NULL) && (new_marking != 0) )
{
// start a new marking
printf("Start new marking %d\n", new_marking);
v_marking = StartMarking();
}
return v_marking;
}

View file

@ -0,0 +1,67 @@
#ifndef _LINEARFEATURE_H_
#define _LINEARFEATURE_H_
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include <Geometry/point3d.hxx>
#include "texparams.hxx"
#include <osg/Group>
using std::string;
class LinearFeature
{
public:
LinearFeature( char* desc )
{
if ( desc )
{
strcpy( description, desc );
}
else
{
strcpy( description, "none" );
}
offset = 0.0f;
closed = false;
}
void AddNode( BezNode* b )
{
contour.push_back( b );
}
void SetClosed()
{
closed = true;
}
int Finish( osg::Group* airport );
int BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, TGPolygon* accum, TGPolygon* apt_base, TGPolygon* apt_clearing );
private:
char description[256];
// contour definition
BezContour contour;
// TODO : Implement offset
double offset;
bool closed;
};
typedef std::vector <LinearFeature *> FeatureList;
// add this to the class
extern double CalcMarkingVerticies( Point3D *prev, Point3D *cur, Point3D *next, int wind, int *prev_dir, double *dist1, double *dist2 );
// don't know what to do with these
extern osg::Geode* FinishMarking( osg::Vec3dArray* verticies );
extern osg::Vec3dArray* CheckMarking(int cur_marking, int new_marking, osg::Vec3dArray* v_marking, osg::Group* airport);
#endif

View file

@ -1,67 +1,85 @@
// main.cxx -- main loop
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id: main.cxx,v 1.37 2005/12/19 15:53:21 curt Exp $
//
/* OpenSceneGraph example, osgshaderterrain.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include <osg/AlphaFunc>
#include <osg/Billboard>
#include <osg/BlendFunc>
#include <osg/Depth>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <osg/GL2Extensions>
#include <osg/Material>
#include <osg/Math>
#include <osg/MatrixTransform>
#include <osg/PolygonMode>
#include <osg/PolygonOffset>
#include <osg/Program>
#include <osg/Projection>
#include <osg/Shader>
#include <osg/ShapeDrawable>
#include <osg/StateSet>
#include <osg/Switch>
#include <osg/Texture2D>
#include <osg/Uniform>
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <osgDB/ReadFile>
#include <osgDB/FileUtils>
#include <simgear/compiler.h>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sg_path.hxx>
#include <osgUtil/Tessellator>
#include <osgUtil/SmoothingVisitor>
#include <osgText/Text>
#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgUtil/Optimizer>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <osgGA/TrackballManipulator>
#include <osgGA/FlightManipulator>
#include <osgGA/TerrainManipulator>
#include <osgGA/StateSetManipulator>
#include <list>
#include <vector>
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
#include <simgear/constants.h>
#include <simgear/bucket/newbucket.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sgstream.hxx>
#include <simgear/misc/strutils.hxx>
//#include <simgear/misc/strutils.hxx>
#include <Polygon/index.hxx>
#include <Geometry/util.hxx>
#include "build.hxx"
#include "beznode.hxx"
#include "closedpoly.hxx"
#include "linearfeature.hxx"
#include "parser.hxx"
using std::vector;
using std::cout;
using std::endl;
int nudge = 10;
double slope_max = 0.2;
static int is_in_range( string_list & runway_list, float min_lat, float max_lat, float min_lon, float max_lon );
// TODO : Modularize this function
// IDEAS
// 1) Start / Stop MarkStyle
// 2) Start / Stop LightStyle
// 3) holes
// 4) CreatePavementSS(pavement type)
// 5) CreateMarkingSS(marking type)
// 6) CalcStripeOffsets should be AddMarkingVerticies, and take the 2 distances from pavement edge...
// SCRAP ALL IDEAS - Markings are encapsulated in LinearFeature class.
// Start creates a new object
// End closes the object (and should add it to a list - either in the parser, or ClosedPoly)
// Display usage
static void usage( int argc, char **argv ) {
@ -73,6 +91,7 @@ static void usage( int argc, char **argv ) {
<< "[ --airport=abcd ] [--tile=<tile>] [--chunk=<chunk>] [--verbose] [--help]");
}
void setup_default_elevation_sources(string_list& elev_src) {
elev_src.push_back( "SRTM2-Africa-3" );
elev_src.push_back( "SRTM2-Australia-3" );
@ -86,58 +105,29 @@ void setup_default_elevation_sources(string_list& elev_src) {
elev_src.push_back( "SRTM-30" );
}
// Display help and usage
static void help( int argc, char **argv, const string_list& elev_src ) {
cout << "genapts generates airports for use in generating scenery for the FlightGear flight simulator. ";
cout << "Airport, runway, and taxiway vector data and attributes are input, and generated 3D airports ";
cout << "are output for further processing by the TerraGear scenery creation tools. ";
cout << "\n\n";
cout << "The standard input file is runways.dat.gz which is found in $FG_ROOT/Airports. ";
cout << "This file is periodically generated for the FlightGear project by Robin Peel, who ";
cout << "maintains an airport database for both the X-Plane and FlightGear simulators. ";
cout << "The format of this file is documented on the FlightGear web site. ";
cout << "Any other input file corresponding to this format may be used as input to genapts. ";
cout << "Input files may be gzipped or left as plain text as required. ";
cout << "\n\n";
cout << "Processing all the world's airports takes a *long* time. To cut down processing time ";
cout << "when only some airports are required, you may refine the input selection either by airport ";
cout << "or by area. By airport, either one airport can be specified using --airport=abcd, where abcd is ";
cout << "a valid airport code eg. --airport-id=KORD, or a starting airport can be specified using --start-id=abcd ";
cout << "where once again abcd is a valid airport code. In this case, all airports in the file subsequent to the ";
cout << "start-id are done. This is convienient when re-starting after a previous error. ";
cout << "\nAn input area may be specified by lat and lon extent using min and max lat and lon. ";
cout << "Alternatively, you may specify a chunk (10 x 10 degrees) or tile (1 x 1 degree) using a string ";
cout << "such as eg. w080n40, e000s27. ";
cout << "\nAn input file containing only a subset of the world's ";
cout << "airports may of course be used.";
cout << "\n\n";
cout << "It is necessary to generate the elevation data for the area of interest PRIOR TO GENERATING THE AIRPORTS. ";
cout << "Failure to do this will result in airports being generated with an elevation of zero. ";
cout << "The following subdirectories of the work-dir will be searched for elevation files:\n\n";
string_list::const_iterator elev_src_it;
for (elev_src_it = elev_src.begin(); elev_src_it != elev_src.end(); elev_src_it++) {
cout << *elev_src_it << "\n";
}
cout << "\n";
usage( argc, argv );
}
// TODO: where do these belong
int nudge = 10;
double slope_max = 0.2;
// reads the apt_full file and extracts and processes the individual
// airport records
int main( int argc, char **argv ) {
int main(int argc, char **argv)
{
float min_lon = -180;
float max_lon = 180;
float min_lat = -90;
float max_lat = 90;
bool ready_to_go = true;
bool ready_to_go = true;
bool view_osg = false;
string_list elev_src;
elev_src.clear();
setup_default_elevation_sources(elev_src);
sglog().setLogLevels( SG_GENERAL, SG_INFO );
// Set verbose
sglog().setLogLevels( SG_GENERAL, SG_BULK );
// sglog().setLogLevels( SG_GENERAL, SG_INFO );
SG_LOG(SG_GENERAL, SG_INFO, "Run genapt");
// parse arguments
string work_dir = "";
@ -145,63 +135,109 @@ int main( int argc, char **argv ) {
string start_id = "";
string airport_id = "";
int arg_pos;
for (arg_pos = 1; arg_pos < argc; arg_pos++) {
for (arg_pos = 1; arg_pos < argc; arg_pos++)
{
string arg = argv[arg_pos];
if ( arg.find("--work=") == 0 ) {
if ( arg.find("--work=") == 0 )
{
work_dir = arg.substr(7);
} else if ( arg.find("--input=") == 0 ) {
input_file = arg.substr(8);
} else if ( arg.find("--terrain=") == 0 ) {
}
else if ( arg.find("--input=") == 0 )
{
input_file = arg.substr(8);
}
else if ( arg.find("--terrain=") == 0 )
{
elev_src.push_back( arg.substr(10) );
} else if ( arg.find("--start-id=") == 0 ) {
start_id = arg.substr(11);
ready_to_go = false;
} else if ( arg.find("--nudge=") == 0 ) {
nudge = atoi( arg.substr(8).c_str() );
} else if ( arg.find("--min-lon=") == 0 ) {
min_lon = atof( arg.substr(10).c_str() );
} else if ( arg.find("--max-lon=") == 0 ) {
max_lon = atof( arg.substr(10).c_str() );
} else if ( arg.find("--min-lat=") == 0 ) {
min_lat = atof( arg.substr(10).c_str() );
} else if ( arg.find("--max-lat=") == 0 ) {
max_lat = atof( arg.substr(10).c_str() );
} else if ( arg.find("--chunk=") == 0 ) {
tg::Rectangle rectangle = tg::parseChunk(arg.substr(8).c_str(),
10.0);
}
else if ( arg.find("--start-id=") == 0 )
{
start_id = arg.substr(11);
ready_to_go = false;
}
else if ( arg.find("--nudge=") == 0 )
{
nudge = atoi( arg.substr(8).c_str() );
}
else if ( arg.find("--min-lon=") == 0 )
{
min_lon = atof( arg.substr(10).c_str() );
}
else if ( arg.find("--max-lon=") == 0 )
{
max_lon = atof( arg.substr(10).c_str() );
}
else if ( arg.find("--min-lat=") == 0 )
{
min_lat = atof( arg.substr(10).c_str() );
}
else if ( arg.find("--max-lat=") == 0 )
{
max_lat = atof( arg.substr(10).c_str() );
}
#if 0
else if ( arg.find("--chunk=") == 0 )
{
tg::Rectangle rectangle = tg::parseChunk(arg.substr(8).c_str(), 10.0);
min_lon = rectangle.getMin().x();
min_lat = rectangle.getMin().y();
max_lon = rectangle.getMax().x();
max_lat = rectangle.getMax().y();
} else if ( arg.find("--tile=") == 0 ) {
}
else if ( arg.find("--tile=") == 0 )
{
tg::Rectangle rectangle = tg::parseTile(arg.substr(7).c_str());
min_lon = rectangle.getMin().x();
min_lat = rectangle.getMin().y();
max_lon = rectangle.getMax().x();
max_lat = rectangle.getMax().y();
} else if ( arg.find("--airport=") == 0 ) {
airport_id = arg.substr(10).c_str();
ready_to_go = false;
} else if ( arg == "--clear-dem-path" ) {
elev_src.clear();
} else if ( arg.find("--dem-path=") == 0 ) {
elev_src.push_back( arg.substr(11) );
} else if ( (arg.find("--verbose") == 0) || (arg.find("-v") == 0) ) {
sglog().setLogLevels( SG_GENERAL, SG_BULK );
} else if ( (arg.find("--max-slope=") == 0) ) {
slope_max = atof( arg.substr(12).c_str() );
} else if ( (arg.find("--help") == 0) || (arg.find("-h") == 0) ) {
help( argc, argv, elev_src );
exit(-1);
} else {
usage( argc, argv );
exit(-1);
}
}
#endif
else if ( arg.find("--airport=") == 0 )
{
airport_id = arg.substr(10).c_str();
ready_to_go = false;
}
else if ( arg == "--clear-dem-path" )
{
elev_src.clear();
}
else if ( arg.find("--dem-path=") == 0 )
{
elev_src.push_back( arg.substr(11) );
}
else if ( (arg.find("--verbose") == 0) || (arg.find("-v") == 0) )
{
sglog().setLogLevels( SG_GENERAL, SG_BULK );
}
else if ( arg.find("--view") == 0 )
{
SG_LOG(SG_GENERAL, SG_INFO, "Found --view : view OSG model" );
view_osg = true;
}
else if ( (arg.find("--max-slope=") == 0) )
{
slope_max = atof( arg.substr(12).c_str() );
}
#if 0
else if ( (arg.find("--help") == 0) || (arg.find("-h") == 0) )
{
help( argc, argv, elev_src );
exit(-1);
}
#endif
else
{
usage( argc, argv );
exit(-1);
}
}
SG_LOG(SG_GENERAL, SG_INFO, "Input file = " << input_file);
SG_LOG(SG_GENERAL, SG_INFO, "Terrain sources = ");
for ( unsigned int i = 0; i < elev_src.size(); ++i ) {
for ( unsigned int i = 0; i < elev_src.size(); ++i )
{
SG_LOG(SG_GENERAL, SG_INFO, " " << work_dir << "/" << elev_src[i] );
}
SG_LOG(SG_GENERAL, SG_INFO, "Work directory = " << work_dir);
@ -210,26 +246,29 @@ int main( int argc, char **argv ) {
SG_LOG(SG_GENERAL, SG_INFO, "Latitude = " << min_lat << ':' << max_lat);
if (max_lon < min_lon || max_lat < min_lat ||
min_lat < -90 || max_lat > 90 ||
min_lon < -180 || max_lon > 180) {
min_lat < -90 || max_lat > 90 ||
min_lon < -180 || max_lon > 180)
{
SG_LOG(SG_GENERAL, SG_ALERT, "Bad longitude or latitude");
exit(1);
exit(1);
}
if ( work_dir == "" ) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Error: no work directory specified." );
usage( argc, argv );
exit(-1);
if ( work_dir == "" )
{
SG_LOG( SG_GENERAL, SG_ALERT, "Error: no work directory specified." );
usage( argc, argv );
exit(-1);
}
if ( input_file == "" ) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Error: no input file." );
exit(-1);
if ( input_file == "" )
{
SG_LOG( SG_GENERAL, SG_ALERT, "Error: no input file." );
exit(-1);
}
// make work directory
SG_LOG(SG_GENERAL, SG_INFO, "Creating airportarea directory");
string airportareadir=work_dir+"/AirportArea";
SGPath sgp( airportareadir );
sgp.append( "dummy" );
@ -242,264 +281,60 @@ int main( int argc, char **argv ) {
poly_index_init( counter_file );
sg_gzifstream in( input_file );
if ( !in.is_open() ) {
if ( !in.is_open() )
{
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << input_file );
exit(-1);
}
string_list runways_list;
string_list water_rw_list;
string_list beacon_list;
string_list tower_list;
string_list windsock_list;
string_list light_list;
SG_LOG(SG_GENERAL, SG_INFO, "Creating parser");
vector<string> token;
string last_apt_id = "";
string last_apt_info = "";
string last_apt_type = "";
string line;
char tmp[2048];
// Create the parser...
Parser* parser = new Parser(input_file);
while ( ! in.eof() ) {
in.getline(tmp, 2048);
line = tmp;
SG_LOG( SG_GENERAL, SG_DEBUG, "-> '" << line << "'" );
if ( line.length() ) {
token = simgear::strutils::split( line );
if ( token.size() ) {
SG_LOG( SG_GENERAL, SG_DEBUG, "token[0] " << token[0] );
}
} else {
token.clear();
}
SG_LOG(SG_GENERAL, SG_INFO, "Parse katl");
parser->Parse((char*)"katl");
if ( !line.length() || !token.size() ) {
// empty line, skip
} else if ( (token[0] == "#") || (token[0] == "//") ) {
// comment, skip
} else if ( token[0] == "I" ) {
// First line, indicates IBM (i.e. DOS line endings I
// believe.)
if (view_osg)
{
// just view in OSG
osg::Group* airportNode;
// move past this line and read and discard the next line
// which is the version and copyright information
in.getline(tmp, 2048);
vector<string> vers_token = simgear::strutils::split( tmp );
SG_LOG( SG_GENERAL, SG_INFO, "Data version = " << vers_token[0] );
} else if ( token[0] == "1" /* Airport */ ||
token[0] == "16" /* Seaplane base */ ||
token[0] == "17" /* Heliport */ ) {
SG_LOG(SG_GENERAL, SG_INFO, "View OSG");
airportNode = parser->CreateOsgGroup();
// extract some airport runway info
string rwy;
float lat, lon;
string id = token[4];
int elev = atoi( token[1].c_str() );
SG_LOG( SG_GENERAL, SG_INFO, "Next airport = " << id << " " << elev );
// construct the viewer.
osgViewer::Viewer viewer;
if ( !last_apt_id.empty()) {
if ( runways_list.size() ) {
vector<string> rwy_token
= simgear::strutils::split( runways_list[0] );
if ( token[0] == "100" ){
rwy = token[8];
lat = atof( token[9].c_str() );
lon = atof( token[10].c_str() );
}
// add the thread model handler
viewer.addEventHandler(new osgViewer::ThreadingHandler);
if ( airport_id.length() && airport_id == last_apt_id ) {
ready_to_go = true;
} else if ( start_id.length() && start_id == last_apt_id ) {
ready_to_go = true;
}
// add the window size toggle handler
viewer.addEventHandler(new osgViewer::WindowSizeHandler);
if ( ready_to_go ) {
// check point our location
char command[256];
sprintf( command,
"echo before building %s >> %s",
last_apt_id.c_str(),
lastaptfile.c_str() );
system( command );
// add model to viewer.
viewer.setSceneData( airportNode );
viewer.setUpViewAcrossAllScreens();
// process previous record
// process_airport(last_apt_id, runways_list, argv[2]);
try {
if ( last_apt_type == "16" /* Seaplane base */ ) {
// skip building seaplane bases
} else {
if( is_in_range( runways_list, min_lat, max_lat, min_lon, max_lon ) ) {
build_airport( last_apt_id,
elev * SG_FEET_TO_METER,
runways_list,
water_rw_list,
beacon_list,
tower_list,
windsock_list,
light_list,
work_dir, elev_src );
}
}
} catch (sg_exception &e) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Failed to build airport = "
<< last_apt_id );
SG_LOG( SG_GENERAL, SG_ALERT, "Exception: "
<< e.getMessage() );
exit(-1);
}
if ( airport_id.length() ) {
ready_to_go = false;
}
}
} else {
if(!airport_id.length()) {
SG_LOG(SG_GENERAL, SG_INFO,
"ERRO: No runways, skipping = " << id);
}
}
}
// create the windows and run the threads.
viewer.realize();
viewer.setCameraManipulator(new osgGA::TrackballManipulator());
last_apt_id = id;
last_apt_info = line;
last_apt_type = token[0];
osgUtil::Optimizer optimzer;
optimzer.optimize(airportNode);
// clear runway list for start of next airport
runways_list.clear();
water_rw_list.clear();
beacon_list.clear();
tower_list.clear();
windsock_list.clear();
light_list.clear();
} else if ( token[0] == "100" || token[0] == "102") {
// runway entry (Land or heli)
runways_list.push_back(line);
} else if ( token[0] == "101" ) {
// Water runway. Here we don't have to create any textures.
// Only place some buoys
water_rw_list.push_back(line);
} else if ( token[0] == "18" ) {
// beacon entry
beacon_list.push_back(line);
} else if ( token[0] == "14" ) {
// control tower entry
tower_list.push_back(line);
} else if ( token[0] == "19" ) {
// windsock entry
windsock_list.push_back(line);
} else if ( token[0] == "21" ) {
// PAPI / VASI list
light_list.push_back(line);
} else if ( token[0] == "15" ) {
// ignore custom startup locations
} else if ( token[0] == "50" || token[0] == "51" || token[0] == "52"
|| token[0] == "53" || token[0] == "54" || token[0] == "55"
|| token[0] == "56" )
{
// ignore frequency entries
} else if ( token[0] == "99" ) {
SG_LOG( SG_GENERAL, SG_ALERT, "End of file reached" );
} else if ( token[0] == "00" ) {
// ??
} else if ( token[0] >= "110" ) {
//ignore taxiways for now
} else if ( token[0] == "10" ) {
//ignore old taxiways for now
} else {
SG_LOG( SG_GENERAL, SG_ALERT,
"Unknown line in file: " << line );
exit(-1);
}
viewer.run();
}
else
{
// write a .btg file....
SG_LOG(SG_GENERAL, SG_INFO, "Write BTG");
parser->WriteBtg(work_dir, elev_src);
}
cout << "last_apt_id.length() = " << last_apt_id.length() << endl;
if ( !last_apt_id.empty()) {
char ctmp, tmpid[32], rwy[32];
string id;
float lat, lon;
int elev = 0;
if ( runways_list.size() ) {
sscanf( runways_list[0].c_str(), "%c %s %s %f %f",
&ctmp, tmpid, rwy, &lat, &lon );
}
if ( start_id.length() && start_id == last_apt_id ) {
ready_to_go = true;
}
if ( ready_to_go ) {
// check point our location
char command[256];
sprintf( command,
"echo before building %s >> %s",
last_apt_id.c_str(),
lastaptfile.c_str() );
system( command );
// process previous record
// process_airport(last_apt_id, runways_list, argv[2]);
try {
if ( last_apt_type == "16" /* Seaplane base */ ) {
// skip building seaplane bases
} else {
if( is_in_range( runways_list, min_lat, max_lat, min_lon, max_lon ) ) {
build_airport( last_apt_id, elev * SG_FEET_TO_METER,
runways_list,
water_rw_list,
beacon_list,
tower_list,
windsock_list,
light_list,
work_dir, elev_src );
}
}
} catch (sg_exception &e) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Failed to build airport = "
<< last_apt_id );
SG_LOG( SG_GENERAL, SG_ALERT, "Exception: "
<< e.getMessage() );
exit(-1);
}
} else {
SG_LOG(SG_GENERAL, SG_INFO, "Skipping airport " << id);
}
}
SG_LOG(SG_GENERAL, SG_INFO, "[FINISHED CORRECTLY]");
SG_LOG(SG_GENERAL, SG_INFO, "Done");
return 0;
}
static int is_in_range( string_list & runways_raw, float min_lat, float max_lat, float min_lon, float max_lon )
{
int i;
int rwy_count = 0;
double apt_lon = 0.0, apt_lat = 0.0;
for ( i = 0; i < (int)runways_raw.size(); ++i ) {
++rwy_count;
string rwy_str = runways_raw[i];
vector<string> token = simgear::strutils::split( rwy_str );
apt_lat += atof( token[1].c_str() );
apt_lon += atof( token[2].c_str() );
}
if( rwy_count > 0 ) {
apt_lat /= rwy_count;
apt_lon /= rwy_count;
}
if( apt_lat >= min_lat && apt_lat <= max_lat &&
apt_lon >= min_lon && apt_lon <= max_lon ) {
return 1;
}
return 0;
}

View file

@ -0,0 +1,451 @@
#include <simgear/debug/logstream.hxx>
#include <simgear/misc/sgstream.hxx>
#include "parser.hxx"
#if 0
int Parser::ParseBoundry(char* line)
{
return 0;
}
#endif
int Parser::Parse( char* icao )
{
string line;
char tmp[2048];
sg_gzifstream in( filename );
if ( !in.is_open() )
{
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << filename );
exit(-1);
}
while ( !in.eof() )
{
in.getline(tmp, 2048);
line = tmp;
// Parse the line
ParseLine(tmp);
}
return 1;
}
BezNode* Parser::ParseNode( int type, char* line, BezNode* prevNode )
{
double lat, lon;
double ctrl_lat, ctrl_lon;
int mark_type, light_type;
BezNode *curNode = NULL;
bool hasCtrl;
bool close;
bool term;
bool hasMarking = false;
bool hasLighting = false;
int numParams;
switch(type)
{
case NODE_CODE:
hasCtrl = false;
close = false;
term = false;
break;
case BEZIER_NODE_CODE:
hasCtrl = true;
close = false;
term = false;
break;
case CLOSE_NODE_CODE:
hasCtrl = false;
close = true;
term = false;
break;
case CLOSE_BEZIER_NODE_CODE:
hasCtrl = true;
close = true;
term = false;
break;
case TERM_NODE_CODE:
hasCtrl = false;
close = false;
term = true;
break;
case TERM_BEZIER_NODE_CODE:
hasCtrl = true;
close = false;
term = true;
break;
}
// parse the line
if (hasCtrl)
{
numParams = sscanf(line, "%lf %lf %lf %lf %d %d", &lat, &lon, &ctrl_lat, &ctrl_lon, &mark_type, &light_type);
if (numParams > 4)
{
hasMarking = true;
}
if (numParams > 5)
{
hasLighting = true;
}
}
else
{
numParams = sscanf(line, "%lf %lf %d %d", &lat, &lon, &mark_type, &light_type);
if (numParams > 2)
{
hasMarking = true;
}
if (numParams > 3)
{
hasLighting = true;
}
}
if ( (prevNode) && (prevNode->IsAt( lat, lon )) )
{
curNode = prevNode;
// editing already existent node
if (hasCtrl)
{
// we have ctrl info -> set it
curNode->SetNextCp(ctrl_lat,ctrl_lon);
}
else
{
// no control info - make sure we clear anything in next
curNode->ClearNextCp();
}
}
// if this is a new node, add it - as first part never has prev cp
if (curNode == NULL)
{
if (hasCtrl)
{
curNode = new BezNode(lat, lon, ctrl_lat, ctrl_lon);
}
else
{
curNode = new BezNode(lat, lon);
}
}
if (hasMarking)
{
curNode->SetMarking( mark_type );
}
if (hasLighting)
{
curNode->SetLighting( light_type );
}
return curNode;
}
LinearFeature* Parser::ParseFeature( char* line )
{
LinearFeature* feature;
if (strlen( line ))
{
feature = new LinearFeature(line);
}
else
{
feature = new LinearFeature(NULL);
}
SG_LOG(SG_GENERAL, SG_DEBUG, "Creating Linear Feature with desription \"" << line << "\"");
return feature;
}
ClosedPoly* Parser::ParsePavement( char* line )
{
ClosedPoly* poly;
int st = 0;
float s = 0.0f;
float th = 0.0f;
char desc[256];
char *d = NULL;
int numParams;
numParams = sscanf(line, "%d %f %f %ls", &st, &s, &th, desc);
if (numParams == 4)
{
d = strstr(line,desc);
}
SG_LOG(SG_GENERAL, SG_DEBUG, "Creating Closed Poly with st " << st << " smoothness " << s << " thexture heading " << th << " and description " << d);
poly = new ClosedPoly(st, s, th, d);
return poly;
}
int Parser::SetState( int state )
{
// if we are currently parsing pavement, the oly way we know we are done
// is when we get a non-node line to parse
if ( cur_airport && cur_state == STATE_PARSE_PAVEMENT )
{
SG_LOG(SG_GENERAL, SG_DEBUG, "Closing and Adding pavement");
cur_pavement->Finish();
cur_airport->AddPavement( cur_pavement );
cur_pavement = NULL;
}
cur_state = state;
}
// TODO: This should be a loop here, and main should just pass the file name and airport code...
int Parser::ParseLine(char* line)
{
char* tok;
int code;
BezNode* cur_node = NULL;
// Get the number code
tok = strtok(line, " \t\r\n");
if (tok)
{
line += strlen(tok)+1;
code = atoi(tok);
switch(code)
{
case LAND_AIRPORT_CODE:
case SEA_AIRPORT_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing land airport: " << line);
cur_airport = new Airport( code, line );
airports.push_back( cur_airport );
break;
case HELIPORT_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing heliport: " << line);
break;
case LAND_RUNWAY_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing runway: " << line);
cur_runway = new Runway(line);
if (cur_airport)
{
cur_airport->AddRunway( cur_runway );
}
break;
case WATER_RUNWAY_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing water runway: " << line);
break;
case HELIPAD_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing helipad: " << line);
break;
case PAVEMENT_CODE:
SetState( STATE_PARSE_PAVEMENT );
cur_pavement = ParsePavement( line );
break;
case LINEAR_FEATURE_CODE:
SetState( STATE_PARSE_FEATURE );
cur_feat = ParseFeature( line );
break;
case BOUNDRY_CODE:
SetState( STATE_PARSE_BOUNDARY );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing airport boundary: " << line);
// ParseBoundry(line);
break;
case NODE_CODE:
case BEZIER_NODE_CODE:
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing node: " << line);
cur_node = ParseNode( code, line, prev_node );
if ( prev_node && (cur_node != prev_node) )
{
// prev node is done - process it\n");
if ( cur_state == STATE_PARSE_PAVEMENT )
{
cur_pavement->AddNode( prev_node );
}
else if ( cur_state == STATE_PARSE_FEATURE )
{
cur_feat->AddNode( prev_node );
}
}
prev_node = cur_node;
break;
case CLOSE_NODE_CODE:
case CLOSE_BEZIER_NODE_CODE:
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing close loop node: " << line);
cur_node = ParseNode( code, line, prev_node );
if ( cur_state == STATE_PARSE_PAVEMENT )
{
if (cur_node != prev_node)
{
cur_pavement->AddNode( prev_node );
cur_pavement->AddNode( cur_node );
}
else
{
cur_pavement->AddNode( cur_node );
}
cur_pavement->CloseCurContour();
}
else if ( cur_state == STATE_PARSE_FEATURE )
{
if (cur_node != prev_node)
{
cur_feat->AddNode( prev_node );
cur_feat->AddNode( cur_node );
}
else
{
cur_feat->AddNode( cur_node );
}
if (cur_airport)
{
cur_airport->AddFeature( cur_feat );
}
SetState( STATE_NONE );
}
prev_node = NULL;
cur_node = NULL;
break;
case TERM_NODE_CODE:
case TERM_BEZIER_NODE_CODE:
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing termination node: " << line);
cur_node = ParseNode( code, line, prev_node );
if ( cur_state == STATE_PARSE_FEATURE )
{
if (cur_node != prev_node)
{
cur_feat->AddNode( prev_node );
cur_feat->AddNode( cur_node );
}
else
{
cur_feat->AddNode( cur_node );
}
if (cur_airport)
{
cur_airport->AddFeature( cur_feat );
}
SetState( STATE_NONE );
}
prev_node = NULL;
cur_node = NULL;
break;
case AIRPORT_VIEWPOINT_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing viewpoint: " << line);
break;
case AIRPLANE_STARTUP_LOCATION_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing airplane startup location: " << line);
break;
case LIGHT_BEACON_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing light beacon: " << line);
break;
case WINDSOCK_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing windsock: " << line);
break;
case TAXIWAY_SIGN:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing taxiway sign: " << line);
break;
case LIGHTING_OBJECT:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing lighting object: " << line);
break;
case COMM_FREQ1_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing commfreq 1: " << line);
break;
case COMM_FREQ2_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing commfreq 2: " << line);
break;
case COMM_FREQ3_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing commfreq 3: " << line);
break;
case COMM_FREQ4_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing commfreq 4: " << line);
break;
case COMM_FREQ5_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing commfreq 5: " << line);
break;
case COMM_FREQ6_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing commfreq 6: " << line);
break;
case COMM_FREQ7_CODE:
SetState( STATE_PARSE_SIMPLE );
SG_LOG(SG_GENERAL, SG_DEBUG, "Parsing commfreq 7: " << line);
break;
case END_OF_FILE :
SG_LOG(SG_GENERAL, SG_DEBUG, "Reached end of file");
SetState( STATE_DONE );
break;
}
}
return 0;
}
void Parser::WriteBtg( const string& root, const string_list& elev_src )
{
int i;
for (i=0; i<airports.size(); i++)
{
airports[i]->BuildBtg( root, elev_src );
}
}
osg::Group* Parser::CreateOsgGroup( void )
{
osg::Group* airportNode = new osg::Group();
int i;
for (i=0; i<airports.size(); i++)
{
SG_LOG(SG_GENERAL, SG_DEBUG, "Add airport " << i << " to node");
airports[i]->BuildOsg( airportNode );
}
return airportNode;
}

View file

@ -0,0 +1,99 @@
#ifndef _PARSER_H_
#define _PARSER_H_
#include "beznode.hxx"
#include "closedpoly.hxx"
#include "linearfeature.hxx"
#include "runway.hxx"
#include "airport.hxx"
#define STATE_NONE (0)
#define STATE_PARSE_SIMPLE (1)
#define STATE_PARSE_BOUNDARY (2)
#define STATE_PARSE_PAVEMENT (3)
#define STATE_PARSE_FEATURE (4)
#define STATE_DONE (10)
#define MAXLINE (256)
#define LAND_AIRPORT_CODE (1)
#define SEA_AIRPORT_CODE (16)
#define HELIPORT_CODE (17)
#define LAND_RUNWAY_CODE (100)
#define WATER_RUNWAY_CODE (101)
#define HELIPAD_CODE (102)
#define PAVEMENT_CODE (110)
#define LINEAR_FEATURE_CODE (120)
#define BOUNDRY_CODE (130)
#define NODE_CODE (111)
#define BEZIER_NODE_CODE (112)
#define CLOSE_NODE_CODE (113)
#define CLOSE_BEZIER_NODE_CODE (114)
#define TERM_NODE_CODE (115)
#define TERM_BEZIER_NODE_CODE (116)
#define AIRPORT_VIEWPOINT_CODE (14)
#define AIRPLANE_STARTUP_LOCATION_CODE (15)
#define LIGHT_BEACON_CODE (18)
#define WINDSOCK_CODE (19)
#define TAXIWAY_SIGN (20)
#define LIGHTING_OBJECT (21)
#define COMM_FREQ1_CODE (50)
#define COMM_FREQ2_CODE (51)
#define COMM_FREQ3_CODE (52)
#define COMM_FREQ4_CODE (53)
#define COMM_FREQ5_CODE (54)
#define COMM_FREQ6_CODE (55)
#define COMM_FREQ7_CODE (56)
#define END_OF_FILE (99)
class Parser
{
public:
Parser(string& f)
{
filename = f;
cur_airport = NULL;
cur_pavement = NULL;
cur_feat = NULL;
prev_node = NULL;
cur_state = STATE_NONE;
}
int Parse( char* icao );
void WriteBtg( const string& root, const string_list& elev_src );
osg::Group* CreateOsgGroup( void );
private:
int SetState( int state );
BezNode* ParseNode( int type, char* line, BezNode* prevNode );
LinearFeature* ParseFeature( char* line );
ClosedPoly* ParsePavement( char* line );
osg::Geode* ParseRunway(char* line );
int ParseLine( char* line );
// int ParseBoundry(char* line, Node* airport);
string filename;
// a polygon conists of an array of contours
// (first is outside boundry, remaining are holes)
Airport* cur_airport;
Runway* cur_runway;
ClosedPoly* cur_pavement;
LinearFeature* cur_feat;
BezNode* prev_node;
AirportList airports;
int cur_state;
};
#endif

View file

@ -1,49 +1,113 @@
// area.c -- routines to assist with inserting "areas" into FG terrain
//
// Written by Curtis Olson, started March 1998.
//
// Copyright (C) 1998 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id: runway.cxx,v 1.18 2004-11-19 22:25:49 curt Exp $
//
#include <math.h>
#include <stdio.h>
#include <simgear/constants.h>
#include <simgear/compiler.h>
#include <simgear/structure/exception.hxx>
#include <simgear/debug/logstream.hxx>
#include <simgear/math/sg_types.hxx>
#include <simgear/bucket/newbucket.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <osg/Geode>
#include <osg/Geometry>
#include <osg/Group>
#include <Polygon/polygon.hxx>
#include "beznode.hxx"
#include "runway.hxx"
#include "point2d.hxx"
extern int nudge;
// given a runway center point, length, width, and heading, and
// altitude (meters) generate the lon and lat 4 corners using wgs84
// math.
TGPolygon gen_wgs84_area( Point3D origin,
double length_m,
double displ1, double displ2,
double width_m,
double heading_deg,
double alt_m,
bool add_mid )
Runway::Runway(char* definition)
{
double az2;
// format:
// runway width surface shoulder smoothness centerline lights edge lighting distance remaining signs
// 100 46.02 2 1 0.00 1 2 1
//
// runway number runway end lat runway end long threshold overrun markings approach lighting
// 09L 33.63470475 -084.44798671 0.00 120.09 3 7
//
// touchdown zone lighting runway end identifier lights
// 0 1
//
// runway number runway end lat runway end long threshold overrun markings approach lighting
// 27R 33.63469907 -084.40893004 0.00 120.09 3 6
//
// touchdown zone lighting runway end identifier lights
// 0 1
// Parse the line
// 46.02 2 1 0.00 1 2 1 09L 33.63470475 -084.44798671 0.00 120.09 3 7 0 1 27R 33.63469907 -084.40893004 0.00 120.09 3 6 0 1
// int fscanf(FILE *stream, const char *format, ...);
sscanf(definition, "%lf %d %d %lf %d %d %d %s %lf %lf %lf %lf %d %d %d %d %s %lf %lf %lf %lf %d %d %d %d",
&width, &surface, &shoulder, &smoothness, &centerline_lights, &edge_lights, &dist_remain_signs,
rwnum[0], &lat[0], &lon[0], &threshold[0], &overrun[0], &marking[0], &approach_lights[0], &tz_lights[0], &reil[0],
rwnum[1], &lat[1], &lon[1], &threshold[1], &overrun[1], &marking[1], &approach_lights[1], &tz_lights[1], &reil[1]
);
// calculate runway heading and length (used a lot)
geo_inverse_wgs_84( lat[0], lon[0], lat[1], lon[1], &heading, &az2, &length );
SG_LOG(SG_GENERAL, SG_DEBUG, "Read runway: (" << lon[0] << "," << lat[0] << ") to (" << lon[1] << "," << lat[1] << ") heading: " << heading << " length: " << length << " width: " << width );
}
int Runway::BuildOsg ( osg::Group* airport )
{
// calculated distance, and azimuths
double az1, az2, dist;
// rectangle verticies
double v0_lat, v0_lon, v1_lat, v1_lon, v2_lat, v2_lon, v3_lat, v3_lon;
// Create a node for the runway
osg::Geode* geode = new osg::Geode();
osg::Geometry* geometry = new osg::Geometry;
osg::Vec3dArray& v = *(new osg::Vec3dArray(4));
// first, find the runway direction vector
// static int geo_inverse_wgs_84( double lat1, double lon1, double lat2, double lon2, double *az1, double *az2, double *s )
geo_inverse_wgs_84( lat[0], lon[0], lat[1], lon[1], &az1, &az2, &dist);
// now, need to caculate the 4 verticies
// static int geo_direct_wgs_84( double lat1, double lon1, double az1, double s, double *lat2, double *lon2, double *az2 )
geo_direct_wgs_84( lat[0], lon[0], az1+90, width/2, &v0_lat, &v0_lon, &az2 );
geo_direct_wgs_84( v0_lat, v0_lon, az1, dist, &v1_lat, &v1_lon, &az2 );
geo_direct_wgs_84( v1_lat, v1_lon, az1-90, width, &v2_lat, &v2_lon, &az2 );
geo_direct_wgs_84( v2_lat, v2_lon, az1+180, dist, &v3_lat, &v3_lon, &az2 );
// convert from lat/lon to geodisc
// (maybe later) - check some simgear objects...
v[0].set(v0_lat, v0_lon, 0.0f);
v[1].set(v1_lat, v1_lon, 0.0f);
v[2].set(v2_lat, v2_lon, 0.0f);
v[3].set(v3_lat, v3_lon, 0.0f);
geometry->setVertexArray(&v);
osg::DrawElementsUShort& drawElements = *(new osg::DrawElementsUShort(GL_TRIANGLE_STRIP,4));
geometry->addPrimitiveSet(&drawElements);
drawElements[0] = 3;
drawElements[1] = 0;
drawElements[2] = 2;
drawElements[3] = 1;
geode->addDrawable(geometry);
airport->addChild( geode );
return 0;
}
TGPolygon Runway::gen_wgs84_area( Point3D origin,
double length_m,
double displ1, double displ2,
double width_m,
double heading_deg,
double alt_m,
bool add_mid )
{
TGPolygon result_list;
double length_hdg = heading_deg;
@ -111,53 +175,19 @@ TGPolygon gen_wgs84_area( Point3D origin,
}
// generate an area for a runway with expantion specified as a scale
// factor (return result points in degrees)
TGPolygon gen_runway_area_w_scale( const TGRunway& runway,
double alt_m,
double length_scale,
double width_scale ) {
TGPolygon result_list;
Point3D origin(runway.lon, runway.lat, 0);
result_list = gen_wgs84_area( origin,
runway.length*length_scale,
0.0, 0.0,
runway.width*width_scale,
runway.heading, alt_m, false );
// display points
SG_LOG(SG_GENERAL, SG_DEBUG, "Results w/ scale (new way)");
for ( int i = 0; i < result_list.contour_size( 0 ); ++i ) {
SG_LOG(SG_GENERAL, SG_DEBUG, " " << result_list.get_pt(0, i));
}
return result_list;
}
// generate an area for a runway with expansion specified in meters
// (return result points in degrees)
TGPolygon gen_runway_area_w_extend( const TGRunway& runway,
double alt_m,
double length_extend,
double displ1, double displ2,
double width_extend ) {
TGPolygon Runway::gen_runway_area_w_extend( double alt_m, double length_extend, double displ1, double displ2, double width_extend )
{
TGPolygon result_list;
Point3D origin(runway.lon, runway.lat, 0);
Point3D origin = GetMidpoint();
result_list
= gen_wgs84_area( origin,
runway.length + 2.0*length_extend,
displ1, displ2,
runway.width + 2.0*width_extend,
runway.heading, alt_m, false );
result_list = gen_wgs84_area( origin, length + 2.0*length_extend, displ1, displ2, width + 2.0*width_extend, heading, alt_m, false );
// display points
SG_LOG(SG_GENERAL, SG_DEBUG, "Results w/ extend (new way)");
for ( int i = 0; i < result_list.contour_size( 0 ); ++i ) {
for ( int i = 0; i < result_list.contour_size( 0 ); ++i )
{
SG_LOG(SG_GENERAL, SG_DEBUG, " " << result_list.get_pt(0, i));
}
@ -166,26 +196,253 @@ TGPolygon gen_runway_area_w_extend( const TGRunway& runway,
// generate an area for a runway and include midpoints
TGPolygon gen_runway_w_mid( const TGRunway& runway,
double alt_m,
double length_extend_m,
double width_extend_m ) {
TGPolygon Runway::gen_runway_w_mid( double alt_m, double length_extend_m, double width_extend_m )
{
TGPolygon result_list;
Point3D origin(runway.lon, runway.lat, 0);
Point3D origin = GetMidpoint();
result_list = gen_wgs84_area( origin,
runway.length
+ 2.0*length_extend_m,
0.0, 0.0,
runway.width
+ 2.0 * width_extend_m,
runway.heading, alt_m, true );
result_list = gen_wgs84_area( origin, length + 2.0*length_extend_m, 0.0, 0.0, width + 2.0 * width_extend_m, heading, alt_m, true );
// display points
SG_LOG(SG_GENERAL, SG_DEBUG, "Results w/ mid (new way)");
for ( int i = 0; i < result_list.contour_size( 0 ); ++i ) {
for ( int i = 0; i < result_list.contour_size( 0 ); ++i )
{
SG_LOG(SG_GENERAL, SG_DEBUG, " " << result_list.get_pt(0, i));
}
return result_list;
}
#if 0
void Runway::gen_simple_rwy( double alt_m, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, TGPolygon *accum )
{
Point3D mp, end[2];
int i;
// create the runway in two halves, as markings may be different in each direction
end[0] = GetStart();
mp = GetMidpoint();
end[1] = GetEnd();
for (i=0; i<2; i++)
{
gen_simple_half( alt_m, mp, end[i], material, rwy_polys, texparams, accum );
}
}
#endif
void Runway::gen_simple_rwy( double alt_m, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, TGPolygon *accum )
{
int j, k;
TGPolygon runway = gen_runway_w_mid( alt_m, 0.0, 0.0 );
// runway half "a"
TGPolygon runway_a;
runway_a.erase();
runway_a.add_node( 0, runway.get_pt(0, 0) );
runway_a.add_node( 0, runway.get_pt(0, 1) );
runway_a.add_node( 0, runway.get_pt(0, 2) );
runway_a.add_node( 0, runway.get_pt(0, 5) );
// runway half "b"
TGPolygon runway_b;
runway_b.erase();
runway_b.add_node( 0, runway.get_pt(0, 5) );
runway_b.add_node( 0, runway.get_pt(0, 2) );
runway_b.add_node( 0, runway.get_pt(0, 3) );
runway_b.add_node( 0, runway.get_pt(0, 4) );
Point3D p;
SG_LOG(SG_GENERAL, SG_DEBUG, "raw runway pts (a half)");
for ( j = 0; j < runway_a.contour_size( 0 ); ++j )
{
p = runway_a.get_pt(0, j);
SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p);
}
SG_LOG(SG_GENERAL, SG_DEBUG, "raw runway pts (b half)");
for ( j = 0; j < runway_b.contour_size( 0 ); ++j )
{
p = runway_b.get_pt(0, j);
SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p);
}
TGSuperPoly sp;
TGTexParams tp;
TGPolygon clipped_a = tgPolygonDiff( runway_a, *accum );
TGPolygon split_a = tgPolygonSplitLongEdges( clipped_a, 400.0 );
sp.erase();
sp.set_poly( split_a );
sp.set_material( material );
rwy_polys->push_back( sp );
SG_LOG(SG_GENERAL, SG_DEBUG, "clipped_a = " << clipped_a.contours());
*accum = tgPolygonUnion( runway_a, *accum );
tp = TGTexParams( runway_a.get_pt(0,0), width, length/2.0, heading );
texparams->push_back( tp );
TGPolygon clipped_b = tgPolygonDiff( runway_b, *accum );
TGPolygon split_b = tgPolygonSplitLongEdges( clipped_b, 400.0 );
sp.erase();
sp.set_poly( split_b );
sp.set_material( material );
rwy_polys->push_back( sp );
SG_LOG(SG_GENERAL, SG_DEBUG, "clipped_b = " << clipped_b.contours());
*accum = tgPolygonUnion( runway_b, *accum );
tp = TGTexParams( runway_b.get_pt(0,2), width, length/2.0, heading+180.0 );
texparams->push_back( tp );
// print runway points
SG_LOG(SG_GENERAL, SG_DEBUG, "clipped runway pts (a)");
for ( j = 0; j < clipped_a.contours(); ++j )
{
for ( k = 0; k < clipped_a.contour_size( j ); ++k )
{
p = clipped_a.get_pt(j, k);
SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p);
}
}
// print runway points
SG_LOG(SG_GENERAL, SG_DEBUG, "clipped runway pts (b)");
for ( j = 0; j < clipped_b.contours(); ++j )
{
for ( k = 0; k < clipped_b.contour_size( j ); ++k )
{
p = clipped_b.get_pt(j, k);
SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p);
}
}
#if 0
gen_runway_stopway( rwy_info, runway_a, runway_b,
material,
rwy_polys, texparams, accum );
#endif
}
#if 0
void Runway::gen_marked_rwy( double alt_m, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, TGPolygon *accum )
{
Point3D mp, end[2];
int i;
// create the runway in two halves, as markings may be different in each direction
end[0] = GetStart();
mp = GetMidpoint();
end[1] = GetEnd();
for (i=0; i<2; i++)
{
// first, create half 'a'
switch( marking[i] )
{
case 0:
case 1: // Visual
SG_LOG( SG_GENERAL, SG_ALERT, "Half " << i << ": has Visual marking");
gen_visual_half( alt_m, mp, end[i], material, rwy_polys, texparams, accum );
break;
case 2: // non-precision
SG_LOG( SG_GENERAL, SG_ALERT, "Half " << i << ": has Non Precision marking");
gen_non_precision_half( alt_m, mp, end[i], material, rwy_polys, texparams, accum );
break;
case 3: // precision
SG_LOG( SG_GENERAL, SG_ALERT, "Half " << i << ": has Precision marking");
//gen_precision_half( alt_m, mp, end[i], material, rwy_polys, texparams, accum );
gen_simple_half( alt_m, mp, end[i], material, rwy_polys, texparams, accum );
break;
default: // unknown
SG_LOG( SG_GENERAL, SG_ALERT, "Half " << i << ": has unknown marking");
break;
}
}
}
#endif
int Runway::BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, TGPolygon* accum, TGPolygon* apt_base, TGPolygon* apt_clearing )
{
TGPolygon base, safe_base;
string material;
if ( surface == 1 /* Asphalt */ )
{
material = "pa_tiedown";
}
else if ( surface == 2 /* Concrete */ )
{
material = "pc_tiedown";
}
else if ( surface == 3 /* Turf/Grass */ )
{
material = "grass_rwy";
}
else if ( surface == 4 /* Dirt */ || surface == 5 /* Gravel */ )
{
material = "dirt_rwy";
}
else if ( surface == 12 /* Dry Lakebed */ )
{
material = "dirt_rwy";
}
else if ( surface == 13 /* Water runway (buoy's?) */ )
{
// water
}
else
{
SG_LOG(SG_GENERAL, SG_WARN, "surface_code = " << surface);
throw sg_exception("unknown runway type!");
}
// first, check the surface type - anything but concrete and asphalt are easy
switch( surface )
{
case 1: // asphalt:
case 2: // concrete
SG_LOG( SG_GENERAL, SG_ALERT, "Build Runway: asphalt or concrete" << surface);
gen_simple_rwy( alt_m, material, rwy_polys, texparams, accum );
break;
case 3: // Grass
case 4: // Dirt
case 5: // Gravel
SG_LOG( SG_GENERAL, SG_ALERT, "Build Runway: Turf, Dirt or Gravel" << surface );
gen_simple_rwy( alt_m, material, rwy_polys, texparams, accum );
break;
case 12: // dry lakebed
SG_LOG( SG_GENERAL, SG_ALERT, "Build Runway: Dry Lakebed");
break;
case 13: // water
SG_LOG( SG_GENERAL, SG_ALERT, "Build Runway: Water");
break;
case 14: // snow
SG_LOG( SG_GENERAL, SG_ALERT, "Build Runway: Snow");
break;
case 15: // transparent
SG_LOG( SG_GENERAL, SG_ALERT, "Build Runway: transparent");
break;
default: // unknown
SG_LOG( SG_GENERAL, SG_ALERT, "Build Runway: unknown" << surface);
break;
}
// generate area around runways
base = gen_runway_area_w_extend( 0.0, 20.0, -overrun[0], -overrun[1], 20.0 );
// also clear a safe area around the runway
safe_base = gen_runway_area_w_extend( 0.0, 180.0, -overrun[0], -overrun[1], 50.0 );
// add this to the airport clearing
*apt_clearing = tgPolygonUnion(safe_base, *apt_clearing);
// and add the clearing to the base
*apt_base = tgPolygonUnion( base, *apt_base );
}

View file

@ -1,129 +1,84 @@
// runway.hxx -- class to store runway info
//
// Written by Curtis Olson, started November 1999.
//
// Copyright (C) 1999 Curtis L. Olson - http://www.flightgear.org/~curt
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id: runway.hxx,v 1.16 2005-04-20 18:20:15 curt Exp $
//
#ifndef _RUNWAY_H_
#define _RUNWAY_H_
#ifndef _RUNWAY_HXX
#define _RUNWAY_HXX
#include <string>
#include <vector>
#include <Geometry/point3d.hxx>
#include <stdio.h>
#include <stdlib.h>
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include <Geometry/point3d.hxx>
#include "texparams.hxx"
struct TGRunway {
int type;
std::string rwy_no1;
std::string rwy_no2;
#include <osg/Group>
double lon;
double lat;
double heading;
double length;
double width;
double disp_thresh1;
double disp_thresh2;
double stopway1;
double stopway2;
using std::string;
int surface_code;
int shoulder_code;
double smoothness;
bool centre_lights;
int edge_lights;
int marking_code1;
int marking_code2;
int alc1_flag;
int alc2_flag;
bool has_tdz1;
bool has_tdz2;
int reil1;
int reil2;
class Runway
{
public:
Runway(char* def);
bool dist_remaining;
bool IsPrecision()
{
return true;
}
TGPolygon threshold;
TGPolygon tens, tens_margin, ones, ones_margin;
TGPolygon letter, letter_margin_left, letter_margin_right;
TGPolygon pre_td_zone;
TGPolygon td3_zone, td2_zone, td1a_zone, td1b_zone;
TGPolygon aim_point;
bool generated;
Point3D GetStart(void)
{
return ( Point3D( lon[0], lat[0], 0.0f ));
}
Point3D GetEnd(void)
{
return ( Point3D( lon[1], lat[1], 0.0f ));
}
Point3D GetMidpoint(void)
{
return ( Point3D( (lon[0]+lon[1])/2.0f, (lat[0]+lat[1])/2.0f, 0.0f) );
}
int BuildOsg( osg::Group* airport );
int BuildBtg( float alt_m, superpoly_list* rwy_polys, texparams_list* texparams, TGPolygon* accum, TGPolygon* apt_base, TGPolygon* apt_clearing );
private:
// data for whole runway
int surface;
int shoulder;
int centerline_lights;
int edge_lights;
int dist_remain_signs;
double width;
double length;
double heading;
double smoothness;
// data for each end
char rwnum[2][16];
double lat[2];
double lon[2];
double threshold[2];
double overrun[2];
int marking[2];
int approach_lights[2];
int tz_lights[2];
int reil[2];
// Build Helpers
TGPolygon gen_wgs84_area( Point3D origin, double length_m, double displ1, double displ2, double width_m, double heading_deg, double alt_m, bool add_mid );
TGPolygon gen_runway_w_mid( double alt_m, double length_extend_m, double width_extend_m );
// void gen_runway_section( const TGPolygon& runway, double startl_pct, double endl_pct, double startw_pct, double endw_pct, double minu, double maxu, double minv, double maxv, double heading,
// const string& prefix, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, TGPolygon *accum );
// void gen_runway_stopway( const TGPolygon& runway_a, const TGPolygon& runway_b, const string& prefix, superpoly_list *rwy_polys, texparams_list *texparams, TGPolygon* accum );
TGPolygon gen_runway_area_w_extend( double alt_m, double length_extend, double displ1, double displ2, double width_extend );
void gen_simple_rwy( double alt_m, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, TGPolygon *accum );
void gen_marked_rwy( double alt_m, const string& material, superpoly_list *rwy_polys, texparams_list *texparams, TGPolygon *accum );
};
typedef std::vector < TGRunway > runway_list;
typedef runway_list::iterator runway_list_iterator;
typedef runway_list::const_iterator const_runway_list_iterator;
struct TGLightobj {
double lon;
double lat;
int type;
double heading;
double glideslope;
std::string rwy_name;
};
typedef std::vector < TGLightobj > light_list;
typedef light_list::iterator light_list_iterator;
typedef light_list::const_iterator const_light_list_iterator;
typedef std::vector <Runway *> RunwayList;
// given a runway center point, length, width, and heading, and
// altitude (meters) generate the lon and lat 4 corners using wgs84
// math.
TGPolygon gen_wgs84_area( Point3D origin,
double length_m,
double displ1, double displ2,
double width_m,
double heading_deg,
double alt_m,
bool add_mid );
// generate an area for a runway with expantion specified as a scale
// factor (return result points in degrees)
TGPolygon gen_runway_area_w_scale( const TGRunway& runway,
double alt_m,
double length_scale = 1.0,
double width_scale = 1.0 );
// generate an area for a runway with expansion specified in meters
// (return result points in degrees)
TGPolygon gen_runway_area_w_extend( const TGRunway& runway,
double alt_m,
double length_extend,
double displ1, double displ2,
double width_extend );
// generate an area for half a runway
TGPolygon gen_runway_w_mid( const TGRunway& runway,
double alt_m,
double length_extend_m,
double width_extend_m );
#endif // _RUNWAY_HXX
#endif