1
0
Fork 0

- Build runway shoulders at the same time as runway segments

- hook up --dump-rwy=x to shapefile generation for debugging runway
and shoulder polys using qgis
This commit is contained in:
Peter Sadrozinski 2012-04-07 18:58:39 -04:00
parent a83bf32c2c
commit a7e6f7fa1b
6 changed files with 401 additions and 219 deletions

View file

@ -255,6 +255,96 @@ static TGPolygon rwy_section_tex_coords( const TGPolygon& in_poly, const TGTexPa
return result; return result;
} }
static TGPolygon shoulder_tex_coords( const TGPolygon& in_poly, const TGTexParams& tp )
{
int i, j;
TGPolygon result;
result.erase();
Point3D ref = tp.get_ref();
double width = tp.get_width();
double length = tp.get_length();
double heading = tp.get_heading();
double minu = tp.get_minu();
double maxu = tp.get_maxu();
double minv = tp.get_minv();
double maxv = tp.get_maxv();
SG_LOG( SG_GENERAL, SG_DEBUG, "section ref = " << ref );
SG_LOG( SG_GENERAL, SG_DEBUG, " width = " << width );
SG_LOG( SG_GENERAL, SG_DEBUG, " length = " << length );
SG_LOG( SG_GENERAL, SG_DEBUG, " heading = " << heading );
SG_LOG( SG_GENERAL, SG_DEBUG, " minv = " << minv );
SG_LOG( SG_GENERAL, SG_DEBUG, " maxv = " << maxv );
SG_LOG( SG_GENERAL, SG_DEBUG, " heading = " << heading );
Point3D p, t;
double x, y, tx, ty;
for ( i = 0; i < in_poly.contours(); ++i )
{
for ( j = 0; j < in_poly.contour_size( i ); ++j )
{
p = in_poly.get_pt( i, j );
SG_LOG(SG_GENERAL, SG_DEBUG, "tex coords for contour " << i << "point " << j << ": " << p );
//
// 1. Calculate distance and bearing from the center of
// the feature
//
// given alt, lat1, lon1, lat2, lon2, calculate starting
// and ending az1, az2 and distance (s). Lat, lon, and
// azimuth are in degrees. distance in meters
double az1, az2, dist;
geo_inverse_wgs_84( 0, ref.y(), ref.x(), p.y(), p.x(),
&az1, &az2, &dist );
SG_LOG(SG_GENERAL, SG_DEBUG, "basic course from ref = " << az2);
//
// 2. Rotate this back into a coordinate system where Y
// runs the length of the runway and X runs crossways.
//
double course = az2 - heading;
while ( course < -360 ) { course += 360; }
while ( course > 360 ) { course -= 360; }
SG_LOG( SG_GENERAL, SG_DEBUG,
" course = " << course << " dist = " << dist );
//
// 3. Convert from polar to cartesian coordinates
//
x = sin( course * SGD_DEGREES_TO_RADIANS ) * dist;
y = cos( course * SGD_DEGREES_TO_RADIANS ) * dist;
SG_LOG(SG_GENERAL, SG_DEBUG, " x = " << x << " y = " << y);
//
// 4. Map x, y point into texture coordinates
//
double tmp;
tmp = x / width;
tx = tmp * (maxu - minu) + minu;
if ( tx < 0.00 ) { tx = 0.0; }
if ( tx > 1.00 ) { tx = 1.0; }
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ")");
ty = (y/length) + minv;
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << ty << ")");
t = Point3D( tx, ty, 0 );
SG_LOG(SG_GENERAL, SG_DEBUG, " (" << tx << ", " << ty << ")");
result.add_node( i, t );
}
}
return result;
}
// TODO: add to linear feature class // TODO: add to linear feature class
static TGPolygon linear_feature_tex_coords( const TGPolygon& in_poly, const TGTexParams& tp ) static TGPolygon linear_feature_tex_coords( const TGPolygon& in_poly, const TGTexParams& tp )
{ {
@ -546,13 +636,21 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
if ( runways[i]->IsPrecision() ) if ( runways[i]->IsPrecision() )
{ {
if ( (dbg_rwy_poly > 0) && (i == (unsigned int)dbg_rwy_poly-1) ) {
SG_LOG(SG_GENERAL, SG_INFO, "Problem runway poly (" << i << ")");
make_shapefiles = true;
} else {
make_shapefiles = false;
}
if (boundary) if (boundary)
{ {
runways[i]->BuildBtg( &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, NULL, NULL ); runways[i]->BuildBtg( &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, NULL, NULL, make_shapefiles );
} }
else else
{ {
runways[i]->BuildBtg( &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, &apt_base, &apt_clearing ); runways[i]->BuildBtg( &rwy_polys, &rwy_tps, &rwy_lights, &accum, slivers, &apt_base, &apt_clearing, make_shapefiles );
} }
} }
@ -633,7 +731,6 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
SG_LOG( SG_GENERAL, SG_ALERT, "Finished building Pavements for " << icao << " at " << ctime(&log_time) ); SG_LOG( SG_GENERAL, SG_ALERT, "Finished building Pavements for " << icao << " at " << ctime(&log_time) );
// Build runway shoulders here // Build runway shoulders here
#if 0
for ( unsigned int i=0; i<runways.size(); i++ ) for ( unsigned int i=0; i<runways.size(); i++ )
{ {
SG_LOG(SG_GENERAL, SG_INFO, "Build Runway shoulder " << i + 1 << " of " << runways.size()); SG_LOG(SG_GENERAL, SG_INFO, "Build Runway shoulder " << i + 1 << " of " << runways.size());
@ -641,14 +738,21 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
if ( runways[i]->GetsShoulder() ) if ( runways[i]->GetsShoulder() )
{ {
slivers.clear(); slivers.clear();
runways[i]->BuildShoulder( &rwy_polys, &rwy_tps, &accum, slivers, &apt_base, &apt_clearing );
if (boundary)
{
runways[i]->BuildShoulder( &rwy_polys, &rwy_tps, &accum, slivers, NULL, NULL );
}
else
{
runways[i]->BuildShoulder( &rwy_polys, &rwy_tps, &accum, slivers, &apt_base, &apt_clearing );
}
// Now try to merge any slivers we found // Now try to merge any slivers we found
merge_slivers( rwy_polys, slivers ); merge_slivers( rwy_polys, slivers );
merge_slivers( pvmt_polys, slivers ); merge_slivers( pvmt_polys, slivers );
} }
} }
#endif
// build the base and clearing if there's a boundary // build the base and clearing if there's a boundary
if (boundary) if (boundary)
@ -850,7 +954,14 @@ void Airport::BuildBtg(const string& root, const string_list& elev_src )
SG_LOG(SG_GENERAL, SG_DEBUG, "total size after = " << tri.total_size()); SG_LOG(SG_GENERAL, SG_DEBUG, "total size after = " << tri.total_size());
TGPolygon tc; TGPolygon tc;
tc = rwy_section_tex_coords( tri, rwy_tps[i], true ); if (rwy_polys[i].get_flag() == "shoulder")
{
tc = shoulder_tex_coords( tri, rwy_tps[i] );
}
else
{
tc = rwy_section_tex_coords( tri, rwy_tps[i], true );
}
rwy_polys[i].set_tris( tri ); rwy_polys[i].set_tris( tri );
rwy_polys[i].set_texcoords( tc ); rwy_polys[i].set_texcoords( tc );

View file

@ -553,8 +553,6 @@ Point3D midpoint( Point3D p0, Point3D p1 )
return Point3D( (p0.x() + p1.x()) / 2, (p0.y() + p1.y()) / 2, (p0.z() + p1.z()) / 2 ); return Point3D( (p0.x() + p1.x()) / 2, (p0.y() + p1.y()) / 2, (p0.z() + p1.z()) / 2 );
} }
#define DEBUG_LF (0)
int LinearFeature::Finish( bool closed, unsigned int idx ) int LinearFeature::Finish( bool closed, unsigned int idx )
{ {
TGPolygon poly; TGPolygon poly;
@ -573,16 +571,6 @@ int LinearFeature::Finish( bool closed, unsigned int idx )
double light_delta = 0; double light_delta = 0;
double pt_x = 0, pt_y = 0; double pt_x = 0, pt_y = 0;
#if DEBUG_LF
void* ds_id;
void* l_id;
// Create a datasource for each linear feature
char ds_name[128];
sprintf(ds_name, "./lf_debug/%04d_%s", idx, description.c_str());
ds_id = tgShapefileOpenDatasource( ds_name );
#endif
// create the inner and outer boundaries to generate polys // create the inner and outer boundaries to generate polys
// this generates 2 point lists for the contours, and remembers // this generates 2 point lists for the contours, and remembers
// the start stop points for markings and lights // the start stop points for markings and lights
@ -710,13 +698,6 @@ int LinearFeature::Finish( bool closed, unsigned int idx )
exit(1); exit(1);
} }
#if DEBUG_LF
// Create a new layer in the datasource for each Mark
char layer_name[128];
sprintf( layer_name, "%04d_%s", i, material.c_str() );
l_id = tgShapefileOpenLayer( ds_id, layer_name );
#endif
last_end_v = 0.0f; last_end_v = 0.0f;
for (unsigned int j = marks[i]->start_idx; j <= marks[i]->end_idx; j++) for (unsigned int j = marks[i]->start_idx; j <= marks[i]->end_idx; j++)
{ {
@ -755,12 +736,6 @@ int LinearFeature::Finish( bool closed, unsigned int idx )
poly.add_node( 0, cur_inner ); poly.add_node( 0, cur_inner );
poly = snap( poly, gSnap ); poly = snap( poly, gSnap );
#if DEBUG_LF
char feature_name[128];
sprintf( feature_name, "%04d", j);
tgShapefileCreateFeature( ds_id, l_id, poly, feature_name );
#endif
sp.erase(); sp.erase();
sp.set_poly( poly ); sp.set_poly( poly );
sp.set_material( material ); sp.set_material( material );
@ -779,11 +754,6 @@ int LinearFeature::Finish( bool closed, unsigned int idx )
} }
} }
#if DEBUG_LF
// Close the datasource
tgShapefileCloseDatasource( ds_id );
#endif
// now generate the supoerpoly list for lights with constant distance between lights (depending on feature type) // now generate the supoerpoly list for lights with constant distance between lights (depending on feature type)
for (unsigned int i=0; i<lights.size(); i++) for (unsigned int i=0; i<lights.size(); i++)
{ {
@ -916,7 +886,7 @@ int LinearFeature::BuildBtg(float alt_m, superpoly_list* line_polys, texparams_l
if ( make_shapefiles ) { if ( make_shapefiles ) {
char ds_name[128]; char ds_name[128];
sprintf(ds_name, "./lf_debug/problem"); sprintf(ds_name, "./lf_debug");
ds_id = tgShapefileOpenDatasource( ds_name ); ds_id = tgShapefileOpenDatasource( ds_name );
} }

View file

@ -80,7 +80,7 @@ TGPolygon WaterRunway::GetNodes()
} }
int Runway::BuildBtg( superpoly_list* rwy_polys, texparams_list* texparams, superpoly_list* rwy_lights, ClipPolyType* accum, poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing ) int Runway::BuildBtg( superpoly_list* rwy_polys, texparams_list* texparams, superpoly_list* rwy_lights, ClipPolyType* accum, poly_list& slivers, TGPolygon* apt_base, TGPolygon* apt_clearing, bool make_shapefiles )
{ {
TGPolygon base, safe_base; TGPolygon base, safe_base;
@ -128,7 +128,7 @@ int Runway::BuildBtg( superpoly_list* rwy_polys, texparams_list* texparams, supe
case 1: // asphalt: case 1: // asphalt:
case 2: // concrete case 2: // concrete
SG_LOG( SG_GENERAL, SG_DEBUG, "Build Runway: asphalt or concrete" << rwy.surface); SG_LOG( SG_GENERAL, SG_DEBUG, "Build Runway: asphalt or concrete" << rwy.surface);
gen_rwy( rwy_polys, texparams, accum, slivers ); gen_rwy( rwy_polys, texparams, accum, slivers, make_shapefiles );
gen_runway_lights( rwy_lights ); gen_runway_lights( rwy_lights );
break; break;
@ -163,8 +163,6 @@ int Runway::BuildBtg( superpoly_list* rwy_polys, texparams_list* texparams, supe
if (apt_base) if (apt_base)
{ {
// If we have shoulders, we need to grow even further...
// generate area around runways // generate area around runways
base = gen_runway_area_w_extend( 20.0, -rwy.overrun[0], -rwy.overrun[1], 20.0 ); base = gen_runway_area_w_extend( 20.0, -rwy.overrun[0], -rwy.overrun[1], 20.0 );
base = snap( base, gSnap ); base = snap( base, gSnap );

View file

@ -41,9 +41,7 @@ public:
bool GetsShoulder() bool GetsShoulder()
{ {
if (rwy.surface < 3 || rwy.shoulder > 0) return (rwy.surface < 3) ? true : false;
return true;
else return false;
} }
int BuildBtg( superpoly_list* rwy_polys, int BuildBtg( superpoly_list* rwy_polys,
@ -52,7 +50,8 @@ public:
ClipPolyType* accum, ClipPolyType* accum,
poly_list& slivers, poly_list& slivers,
TGPolygon* apt_base, TGPolygon* apt_base,
TGPolygon* apt_clearing ); TGPolygon* apt_clearing,
bool make_shapefiles );
void BuildShoulder( superpoly_list *rwy_polys, void BuildShoulder( superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
@ -91,6 +90,11 @@ private:
TGRunway rwy; TGRunway rwy;
std::string material_prefix; std::string material_prefix;
// storage for Shoulders - The superpolys are generated during rwy construction,
// but not clipped until shoulder construction.
superpoly_list shoulder_polys;
texparams_list shoulder_tps;
// Build Helpers: // Build Helpers:
// generate an area for a runway and include midpoints // generate an area for a runway and include midpoints
TGPolygon gen_runway_w_mid( double length_extend_m, double width_extend_m ) TGPolygon gen_runway_w_mid( double length_extend_m, double width_extend_m )
@ -110,7 +114,8 @@ private:
superpoly_list* rwy_polys, superpoly_list* rwy_polys,
texparams_list* texparams, texparams_list* texparams,
ClipPolyType* accum, ClipPolyType* accum,
poly_list& slivers ); poly_list& slivers,
bool make_shapefiles );
// generate a section of runway // generate a section of runway
void gen_runway_section( const TGPolygon& runway, void gen_runway_section( const TGPolygon& runway,
@ -121,15 +126,28 @@ private:
const string& material, const string& material,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
superpoly_list *shoulder_polys,
texparams_list *shoulder_tps,
ClipPolyType *accum, ClipPolyType *accum,
poly_list& slivers ); poly_list& slivers,
bool make_shapefiles );
// generate a section of shoulder
void gen_shoulder_section( Point3D p0, Point3D p1,
Point3D t0, Point3D t1,
int side,
double heading,
double width,
std::string surface,
TGSuperPoly& sp, TGTexParams& tp );
void gen_simple_rwy( superpoly_list *rwy_polys, texparams_list *texparams, ClipPolyType *accum, poly_list& slivers ); void gen_simple_rwy( superpoly_list *rwy_polys, texparams_list *texparams, ClipPolyType *accum, poly_list& slivers );
void gen_rwy( superpoly_list* rwy_polys, void gen_rwy( superpoly_list* rwy_polys,
texparams_list* texparams, texparams_list* texparams,
ClipPolyType* accum, ClipPolyType* accum,
poly_list& slivers ); poly_list& slivers,
bool make_shapefiles );
void gen_runway_lights( superpoly_list* lights ); void gen_runway_lights( superpoly_list* lights );

View file

@ -88,6 +88,63 @@ static const struct sections nprec[] = {
}; };
void Runway::gen_shoulder_section( Point3D p0, Point3D p1, Point3D t0, Point3D t1, int side, double heading, double width, std::string surface, TGSuperPoly& sp, TGTexParams& tp )
{
Point3D s0, s1, s2, s3;
TGPolygon poly;
double wid_hdg = 0.0f;
double az2 = 0.0f;
double dist = 0.0f;
double pt_x = 0.0f;
double pt_y = 0.0f;
// calc heading from p1 to p0
geo_inverse_wgs_84( p0.y(), p0.x(), p1.y(), p1.x(), &wid_hdg, &az2, &dist);
// s0 is width away from t1 in wid_hdg direction
geo_direct_wgs_84( t1.y(), t1.x(), wid_hdg, width, &pt_y, &pt_x, &az2 );
s0 = Point3D( pt_x, pt_y, 0.0f );
// s1 is width away from t0 in wid_hdg direction
geo_direct_wgs_84( t0.y(), t0.x(), wid_hdg, width, &pt_y, &pt_x, &az2 );
s1 = Point3D( pt_x, pt_y, 0.0f );
// s2 is nudge away from t0 in -wid_hdg direction
geo_direct_wgs_84( t0.y(), t0.x(), wid_hdg, -0.01, &pt_y, &pt_x, &az2 );
s2 = Point3D( pt_x, pt_y, 0.0f );
// s3 is nudge away from t1 in -wid_hdg direction
geo_direct_wgs_84( t1.y(), t1.x(), wid_hdg, -0.01, &pt_y, &pt_x, &az2 );
s3 = Point3D( pt_x, pt_y, 0.0f );
// Generate a poly
poly.erase();
poly.add_node( 0, s0 );
poly.add_node( 0, s1 );
poly.add_node( 0, s2 );
poly.add_node( 0, s3 );
poly = snap( poly, gSnap );
sp.erase();
sp.set_poly( poly );
sp.set_material( surface );
sp.set_flag( "shoulder" );
if (side == 0) {
tp = TGTexParams( poly.get_pt(0,2), width, dist, heading );
tp.set_minu(0);
tp.set_maxu(1);
} else {
tp = TGTexParams( poly.get_pt(0,1), width, dist, heading );
tp.set_minu(1);
tp.set_maxu(0);
}
tp.set_minv(0);
tp.set_maxv(1);
}
// generate a section of texture // generate a section of texture
void Runway::gen_runway_section( const TGPolygon& runway, void Runway::gen_runway_section( const TGPolygon& runway,
double startl_pct, double endl_pct, double startl_pct, double endl_pct,
@ -97,12 +154,22 @@ void Runway::gen_runway_section( const TGPolygon& runway,
const string& material, const string& material,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
superpoly_list *shoulder_polys,
texparams_list *shoulder_tps,
ClipPolyType *accum, ClipPolyType *accum,
poly_list& slivers ) poly_list& slivers,
bool make_shapefiles )
{ {
int j, k; int j, k;
double width = rwy.width; double width = rwy.width;
double length = rwy.length; double length = rwy.length;
double lshoulder_width = 0.0f;
double rshoulder_width = 0.0f;
std::string shoulder_surface = "";
void* ds_id = NULL; // If we are going to build shapefiles
void* l_id = NULL; // datasource and layer IDs
static int poly_id = 0; // for naming
Point3D a0 = runway.get_pt(0, 1); Point3D a0 = runway.get_pt(0, 1);
Point3D a1 = runway.get_pt(0, 2); Point3D a1 = runway.get_pt(0, 2);
@ -115,11 +182,48 @@ void Runway::gen_runway_section( const TGPolygon& runway,
if ( endl_pct < 1.0 ) { if ( endl_pct < 1.0 ) {
endl_pct += nudge * SG_EPSILON; endl_pct += nudge * SG_EPSILON;
} }
if ( endl_pct > 1.0 ) { if ( endl_pct > 1.0 ) {
endl_pct = 1.0; endl_pct = 1.0;
} }
if ( make_shapefiles ) {
char ds_name[128];
sprintf(ds_name, "./rwy_debug");
ds_id = tgShapefileOpenDatasource( ds_name );
}
// calculate if we are going to be creating shoulder polys
if ( (rwy.shoulder > 0) && (rwy.surface < 3) ){
if (rwy.shoulder == 1){
shoulder_surface = "pa_shoulder";
} else if (rwy.shoulder == 2){
shoulder_surface = "pc_shoulder";
}
if ( startw_pct == 0.0f ) {
lshoulder_width = 11.0;
}
if ( endw_pct == 1.0f ) {
rshoulder_width = 11.0;
}
} else {
// We add a fake shoulder if the runway has an asphalt or concrete surface
if ( (rwy.surface == 1) || (rwy.surface == 2) ) {
if (rwy.surface == 1) {
shoulder_surface = "pa_shoulder_f";
} else if (rwy.surface == 2){
shoulder_surface = "pc_shoulder_f";
}
if ( startw_pct == 0.0f ) {
lshoulder_width = 1.0;
}
if ( endw_pct == 1.0f ) {
rshoulder_width = 1.0;
}
}
}
// partial "w" percentages could introduce "T" intersections which // partial "w" percentages could introduce "T" intersections which
// we compensate for later, but could still cause problems now // we compensate for later, but could still cause problems now
// with our polygon clipping code. This attempts to compensate // with our polygon clipping code. This attempts to compensate
@ -170,6 +274,29 @@ void Runway::gen_runway_section( const TGPolygon& runway,
Point3D p1 = Point3D( t2.x() + dwx * endw_pct, Point3D p1 = Point3D( t2.x() + dwx * endw_pct,
t2.y() + dwy * endw_pct, 0); t2.y() + dwy * endw_pct, 0);
// check for left shoulder
if ( lshoulder_width > 0.0f ) {
TGSuperPoly sp;
TGTexParams tp;
gen_shoulder_section( p0, p1, t0, t1, 0, heading, lshoulder_width, shoulder_surface, sp, tp );
shoulder_polys->push_back( sp );
shoulder_tps->push_back( tp );
/* If debugging this runway, write the shoulder poly */
if (ds_id) {
poly_id++;
char layer_name[128];
sprintf( layer_name, "lshoulder_%d", poly_id );
l_id = tgShapefileOpenLayer( ds_id, layer_name );
char feature_name[128];
sprintf( feature_name, "lshoulder_%d", poly_id);
tgShapefileCreateFeature( ds_id, l_id, sp.get_poly(), feature_name );
}
}
dwx = t1.x() - t3.x(); dwx = t1.x() - t3.x();
dwy = t1.y() - t3.y(); dwy = t1.y() - t3.y();
@ -179,6 +306,29 @@ void Runway::gen_runway_section( const TGPolygon& runway,
Point3D p3 = Point3D( t3.x() + dwx * endw_pct, Point3D p3 = Point3D( t3.x() + dwx * endw_pct,
t3.y() + dwy * endw_pct, 0); t3.y() + dwy * endw_pct, 0);
// check for right shoulder
if ( rshoulder_width > 0.0f ) {
TGSuperPoly sp;
TGTexParams tp;
gen_shoulder_section( p1, p0, t2, t3, 1, heading, rshoulder_width, shoulder_surface, sp, tp );
shoulder_polys->push_back( sp );
shoulder_tps->push_back( tp );
/* If debugging this runway, write the shoulder poly */
if (ds_id) {
poly_id++;
char layer_name[128];
sprintf( layer_name, "rshoulder_%d", poly_id );
l_id = tgShapefileOpenLayer( ds_id, layer_name );
char feature_name[128];
sprintf( feature_name, "rshoulder_%d", poly_id);
tgShapefileCreateFeature( ds_id, l_id, sp.get_poly(), feature_name );
}
}
TGPolygon section; TGPolygon section;
section.erase(); section.erase();
@ -188,6 +338,18 @@ void Runway::gen_runway_section( const TGPolygon& runway,
section.add_node( 0, p3 ); section.add_node( 0, p3 );
section = snap( section, gSnap ); section = snap( section, gSnap );
/* If debugging this runway, write the shoulder poly */
if (ds_id) {
char layer_name[128];
sprintf( layer_name, "poly_%d", poly_id );
l_id = tgShapefileOpenLayer( ds_id, layer_name );
char feature_name[128];
sprintf( feature_name, "section_%d", poly_id);
tgShapefileCreateFeature( ds_id, l_id, section, feature_name );
}
// print runway points // print runway points
SG_LOG(SG_GENERAL, SG_DEBUG, "pre clipped runway pts " << material_prefix << material); SG_LOG(SG_GENERAL, SG_DEBUG, "pre clipped runway pts " << material_prefix << material);
for ( j = 0; j < section.contours(); ++j ) { for ( j = 0; j < section.contours(); ++j ) {
@ -212,6 +374,7 @@ void Runway::gen_runway_section( const TGPolygon& runway,
sp.set_poly( split ); sp.set_poly( split );
sp.set_material( material_prefix + material ); sp.set_material( material_prefix + material );
rwy_polys->push_back( sp ); rwy_polys->push_back( sp );
SG_LOG(SG_GENERAL, SG_DEBUG, "section = " << clipped.contours()); SG_LOG(SG_GENERAL, SG_DEBUG, "section = " << clipped.contours());
*accum = tgPolygonUnionClipper( section, *accum ); *accum = tgPolygonUnionClipper( section, *accum );
@ -246,6 +409,10 @@ void Runway::gen_runway_section( const TGPolygon& runway,
SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p); SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p);
} }
} }
if (ds_id) {
tgShapefileCloseDatasource( ds_id );
}
} }
void Runway::gen_rw_designation( TGPolygon poly, double heading, string rwname, void Runway::gen_rw_designation( TGPolygon poly, double heading, string rwname,
@ -253,7 +420,8 @@ void Runway::gen_rw_designation( TGPolygon poly, double heading, string rwname,
superpoly_list *rwy_polys, superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType *accum, ClipPolyType *accum,
poly_list& slivers ) poly_list& slivers,
bool make_shapefiles )
{ {
if (rwname != "XX") { /* Do not create a designation block if the runway name is set to none */ if (rwname != "XX") { /* Do not create a designation block if the runway name is set to none */
string letter = ""; string letter = "";
@ -277,7 +445,10 @@ void Runway::gen_rw_designation( TGPolygon poly, double heading, string rwname,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
letter, letter,
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
} }
@ -304,14 +475,20 @@ void Runway::gen_rw_designation( TGPolygon poly, double heading, string rwname,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
tex1, tex1,
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
gen_runway_section( poly, gen_runway_section( poly,
start_pct, end_pct, start_pct, end_pct,
0.5, 1.0, 0.5, 1.0,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
tex2, tex2,
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
} else if (rwname.length() == 1) { } else if (rwname.length() == 1) {
sprintf( tex1, "%c%c", rwname[0], 'c'); sprintf( tex1, "%c%c", rwname[0], 'c');
@ -322,7 +499,10 @@ void Runway::gen_rw_designation( TGPolygon poly, double heading, string rwname,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
tex1, tex1,
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
} }
} }
} }
@ -334,7 +514,8 @@ void Runway::gen_rw_designation( TGPolygon poly, double heading, string rwname,
void Runway::gen_rwy( superpoly_list *rwy_polys, void Runway::gen_rwy( superpoly_list *rwy_polys,
texparams_list *texparams, texparams_list *texparams,
ClipPolyType *accum, ClipPolyType *accum,
poly_list& slivers ) poly_list& slivers,
bool make_shapefiles )
{ {
SG_LOG( SG_GENERAL, SG_DEBUG, "Building runway = " << rwy.rwnum[0] << " / " << rwy.rwnum[1]); SG_LOG( SG_GENERAL, SG_DEBUG, "Building runway = " << rwy.rwnum[0] << " / " << rwy.rwnum[1]);
@ -429,7 +610,10 @@ void Runway::gen_rwy( superpoly_list *rwy_polys,
0.0, 1.0, tex_pct, 1.0, 0.0, 1.0, tex_pct, 1.0,
heading, heading,
"dspl_thresh", "dspl_thresh",
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
// main chunks // main chunks
for ( int i = 0; i < count; ++i ) { for ( int i = 0; i < count; ++i ) {
@ -441,7 +625,10 @@ void Runway::gen_rwy( superpoly_list *rwy_polys,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
"dspl_thresh", "dspl_thresh",
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
} }
// final arrows // final arrows
@ -453,7 +640,10 @@ void Runway::gen_rwy( superpoly_list *rwy_polys,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
"dspl_arrows", "dspl_arrows",
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
} }
if (rwy.marking[rwhalf] == 0) { if (rwy.marking[rwhalf] == 0) {
@ -466,7 +656,10 @@ void Runway::gen_rwy( superpoly_list *rwy_polys,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
"no_threshold", "no_threshold",
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
} else { } else {
// Thresholds for all others // Thresholds for all others
start1_pct = end1_pct; start1_pct = end1_pct;
@ -477,13 +670,17 @@ void Runway::gen_rwy( superpoly_list *rwy_polys,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
"threshold", "threshold",
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
} }
// Runway designation block // Runway designation block
gen_rw_designation( runway_half, heading, gen_rw_designation( runway_half, heading,
rwname, start1_pct, end1_pct, rwname, start1_pct, end1_pct,
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams, accum, slivers,
make_shapefiles );
// Generate remaining markings depending on type of runway // Generate remaining markings depending on type of runway
if (rwy.marking[rwhalf] > 1) { if (rwy.marking[rwhalf] > 1) {
@ -521,7 +718,10 @@ void Runway::gen_rwy( superpoly_list *rwy_polys,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
rw_marking_list[i].tex, rw_marking_list[i].tex,
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
} }
} }
} }
@ -547,7 +747,10 @@ void Runway::gen_rwy( superpoly_list *rwy_polys,
0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0,
heading, heading,
"rest", "rest",
rwy_polys, texparams, accum, slivers ); rwy_polys, texparams,
&shoulder_polys, &shoulder_tps,
accum, slivers,
make_shapefiles );
} }
start1_pct = 0.0; start1_pct = 0.0;
@ -574,10 +777,10 @@ void Runway::gen_rwy( superpoly_list *rwy_polys,
0.0, 1.0, 0.0, 1.0, //last number is lengthwise 0.0, 1.0, 0.0, 1.0, //last number is lengthwise
heading, heading,
"stopway", "stopway",
rwy_polys, rwy_polys, texparams,
texparams, &shoulder_polys, &shoulder_tps,
accum, accum, slivers,
slivers ); make_shapefiles );
} }
} }
} }
@ -591,157 +794,36 @@ void Runway::BuildShoulder( superpoly_list *rwy_polys,
TGPolygon* apt_clearing ) TGPolygon* apt_clearing )
{ {
TGPolygon base, safe_base; TGPolygon base, safe_base;
TGPolygon shoulder;
string shoulder_surface = ""; for (unsigned int i=0; i<shoulder_polys.size(); i++) {
double shoulder_width = 0.0f; shoulder = shoulder_polys[i].get_poly();
if (rwy.shoulder > 0){ // Clip the new polygon against what ever has already been created.
// Add a shoulder to the runway TGPolygon clipped = tgPolygonDiffClipper( shoulder, *accum );
shoulder_width = 11.0f; tgPolygonFindSlivers( clipped, slivers );
if (rwy.shoulder == 1){ // Split long edges to create an object that can better flow with
shoulder_surface = "pa_shoulder"; // the surface terrain
} else if (rwy.shoulder == 2){ TGPolygon split = tgPolygonSplitLongEdges( clipped, 400.0 );
shoulder_surface = "pc_shoulder"; shoulder_polys[i].set_poly( split );
} else {
SG_LOG(SG_GENERAL, SG_ALERT, "Unknown shoulder surface code = " << rwy.shoulder ); rwy_polys->push_back( shoulder_polys[i] );
texparams->push_back( shoulder_tps[i] );
*accum = tgPolygonUnionClipper( shoulder, *accum );
if (apt_base)
{
// also clear a safe area around the runway
base = tgPolygonExpand( shoulder, 20.0);
safe_base = tgPolygonExpand( shoulder, 50.0);
// add this to the airport clearing
*apt_clearing = tgPolygonUnionClipper( safe_base, *apt_clearing );
// and add the clearing to the base
*apt_base = tgPolygonUnionClipper( base, *apt_base );
} }
} else {
// We add a fake shoulder if the runway has an asphalt or concrete surface
shoulder_width = 1.0;
if (rwy.surface == 1){
shoulder_surface = "pa_shoulder_f";
} else if (rwy.surface == 2){
shoulder_surface = "pc_shoulder_f";
}
}
SG_LOG(SG_GENERAL, SG_DEBUG, "Shoulder width = " << shoulder_width );
SG_LOG(SG_GENERAL, SG_DEBUG, "Shoulder surface is: " << shoulder_surface );
if (shoulder_width > 0.0f) {
// we need to break these shoulders up into managable pieces, as we're asked to triangulate
// 3-4 km long by 1m wide strips - jrs-can't handle it.
double max_dist = (double)shoulder_width * 25.0f;
if (max_dist > 100.0f) {
max_dist = 100.0f;
}
int numSegs = (rwy.length / max_dist) + 1;
double dist = rwy.length / numSegs;
TGPolygon poly;
TGSuperPoly sp;
TGTexParams tp;
double lat = 0.0f;
double lon = 0.0f;
double r = 0.0f;
Point3D inner_start, inner_end;
Point3D outer_start, outer_end;
Point3D curInnerLoc, nextInnerLoc;
Point3D curOuterLoc, nextOuterLoc;
// Create two paralell lines from start position to end position, and interpolate in between
// many airports line the taxiway directly to the corner of the runway. This can create problems,
// so extend the shoulders 0.5 meters past each end of the runway
for (int i=0; i<2; i++) {
double rev_hdg = rwy.heading - 180.0;
if ( rev_hdg < 0 ) { rev_hdg += 360.0; }
if (i == 0) {
// left side
double left_hdg = rwy.heading - 90.0;
if ( left_hdg < 0 ) { left_hdg += 360.0; }
geo_direct_wgs_84 ( 0, rwy.lat[0], rwy.lon[0], left_hdg, rwy.width*.5, &lat, &lon, &r );
geo_direct_wgs_84 ( 0, lat, lon, rev_hdg, 0.5f, &lat, &lon, &r );
inner_start = Point3D( lon, lat, 0.0f );
geo_direct_wgs_84 ( 0, lat, lon, rwy.heading, rwy.length+1.0f, &lat, &lon, &r );
inner_end = Point3D( lon, lat, 0.0f );
geo_direct_wgs_84 ( 0, rwy.lat[0], rwy.lon[0], left_hdg, rwy.width*.5 + shoulder_width, &lat, &lon, &r );
geo_direct_wgs_84 ( 0, lat, lon, rev_hdg, 0.5f, &lat, &lon, &r );
outer_start = Point3D( lon, lat, 0.0f );
geo_direct_wgs_84 ( 0, lat, lon, rwy.heading, rwy.length+1.0f, &lat, &lon, &r );
outer_end = Point3D( lon, lat, 0.0f );
} else {
// right side
double right_hdg = rwy.heading + 90.0;
if ( right_hdg > 360 ) { right_hdg -= 360.0; }
geo_direct_wgs_84 ( 0, rwy.lat[0], rwy.lon[0], right_hdg, rwy.width*.5, &lat, &lon, &r );
geo_direct_wgs_84 ( 0, lat, lon, rev_hdg, 0.5f, &lat, &lon, &r );
inner_start = Point3D( lon, lat, 0.0f );
geo_direct_wgs_84 ( 0, lat, lon, rwy.heading, rwy.length+1.0f, &lat, &lon, &r );
inner_end = Point3D( lon, lat, 0.0f );
geo_direct_wgs_84 ( 0, rwy.lat[0], rwy.lon[0], right_hdg, rwy.width*.5 + shoulder_width, &lat, &lon, &r );
geo_direct_wgs_84 ( 0, lat, lon, rev_hdg, 0.5f, &lat, &lon, &r );
outer_start = Point3D( lon, lat, 0.0f );
geo_direct_wgs_84 ( 0, lat, lon, rwy.heading, rwy.length+1.0f, &lat, &lon, &r );
outer_end = Point3D( lon, lat, 0.0f );
}
curInnerLoc = inner_start;
curOuterLoc = outer_start;
for (int p=0; p<numSegs; p++)
{
// calculate next locations
nextInnerLoc = CalculateLinearLocation( inner_start, inner_end, (1.0f/numSegs) * (p+1) );
nextOuterLoc = CalculateLinearLocation( outer_start, outer_end, (1.0f/numSegs) * (p+1) );
// Generate a poly
poly.erase();
if (i == 0 ) {
poly.add_node( 0, curInnerLoc );
poly.add_node( 0, nextInnerLoc );
poly.add_node( 0, nextOuterLoc );
poly.add_node( 0, curOuterLoc );
} else {
poly.add_node( 0, curOuterLoc );
poly.add_node( 0, nextOuterLoc );
poly.add_node( 0, nextInnerLoc );
poly.add_node( 0, curInnerLoc );
}
TGPolygon clipped = tgPolygonDiffClipper( poly, *accum );
tgPolygonFindSlivers( clipped, slivers );
sp.erase();
sp.set_poly( clipped );
sp.set_material( shoulder_surface );
rwy_polys->push_back( sp );
*accum = tgPolygonUnionClipper( poly, *accum );
tp = TGTexParams( poly.get_pt(0,0), shoulder_width, dist, rwy.heading );
tp.set_maxv(dist);
// reverse u direction for right side
if ( i == 1 ) {
tp.set_maxu(0);
tp.set_minu(1);
}
texparams->push_back( tp );
// Add to base / safe base
base = tgPolygonExpand( poly, 20.0f );
safe_base = tgPolygonExpand( poly, 50.0f );
// add this to the airport clearing
*apt_clearing = tgPolygonUnionClipper(safe_base, *apt_clearing);
// and add the clearing to the base
*apt_base = tgPolygonUnionClipper( base, *apt_base );
// now set cur locations for the next iteration
curInnerLoc = nextInnerLoc;
curOuterLoc = nextOuterLoc;
}
}
} }
} }

View file

@ -90,7 +90,9 @@ void Runway::gen_simple_rwy( superpoly_list *rwy_polys,
heading, heading,
"", "",
rwy_polys, texparams, rwy_polys, texparams,
accum, slivers ); NULL, NULL,
accum, slivers,
false );
} }
// Generate runway // Generate runway
@ -101,7 +103,8 @@ void Runway::gen_simple_rwy( superpoly_list *rwy_polys,
heading, heading,
"", "",
rwy_polys, texparams, rwy_polys, texparams,
accum, slivers ); NULL, NULL,
accum, slivers,
false );
} }
} }