1
0
Fork 0

- Chased down a bug that caused threshold lighting to be omitted in some

situations

- Made the code a bit more robust and able to handle the handful of rare
  occasions when the least squares nurbs interpolator fails.

- Add airport surface bases for towers, windsocks, beacons, and vasi/papi
  lighting so they never are buried and never float.  (I'm considering the
  idea of doing this for the approach lighting too ...)
This commit is contained in:
curt 2004-11-11 15:05:13 +00:00
parent 696fa632b4
commit fb71b5876c
6 changed files with 121 additions and 42 deletions

View file

@ -132,8 +132,8 @@ TGAptSurface::TGAptSurface( const string& path,
#elif defined( _NURBS_LEAST_SQUARES ) #elif defined( _NURBS_LEAST_SQUARES )
// Minimum divs appears to need to be at least 5 before the // Minimum divs appears to need to be at least 5 before the
// leastsquares nurbs surface approximation stops crashing. // leastsquares nurbs surface approximation stops crashing.
if ( xdivs < 5 ) { xdivs = 5; } if ( xdivs < 6 ) { xdivs = 6; }
if ( ydivs < 5 ) { ydivs = 5; } if ( ydivs < 6 ) { ydivs = 6; }
#else #else
# error "Need to define _NURBS_GLOBAL_INTER or _NURBS_LEAST_SQUARES" # error "Need to define _NURBS_GLOBAL_INTER or _NURBS_LEAST_SQUARES"
#endif #endif
@ -269,8 +269,11 @@ TGAptSurface::TGAptSurface( const string& path,
// sanity check: I'm finding that leastSquares() can produce nan // sanity check: I'm finding that leastSquares() can produce nan
// surfaces. We test for this and fall back to globalInterp() if // surfaces. We test for this and fall back to globalInterp() if
// the least squares fails. // the least squares fails.
double result = query_solver( (min_deg.lon() + max_deg.lon()) / 2.0,
(min_deg.lat() + max_deg.lat()) / 2.0 );
Point3Dd p = apt_surf->pointAt( 0.5, 0.5 ); Point3Dd p = apt_surf->pointAt( 0.5, 0.5 );
if ( p.z() <= 0.0 || p.z() >= 0.0 ) {
if ( (result > -9000.0) && (p.z() <= 0.0 || p.z() >= 0.0) ) {
// ok, a valid number // ok, a valid number
} else { } else {
// no, sorry, a nan is not <= 0.0 or >= 0.0 // no, sorry, a nan is not <= 0.0 or >= 0.0
@ -278,7 +281,7 @@ TGAptSurface::TGAptSurface( const string& path,
"leastSquares() nurbs interpolation failed!!!"); "leastSquares() nurbs interpolation failed!!!");
char command[256]; char command[256];
sprintf( command, sprintf( command,
"least squares nurbs interpolation failed, using globalInterp() >> last_apt" ); "echo least squares nurbs interpolation failed, using globalInterp() >> last_apt" );
system( command ); system( command );
// we could fall back to globalInterp() rather than aborting // we could fall back to globalInterp() rather than aborting
@ -454,6 +457,13 @@ double TGAptSurface::query_solver( double lon_deg, double lat_deg ) {
} }
u = (max_u + min_u) / 2.0; u = (max_u + min_u) / 2.0;
if ( count > 100 ) {
// solver failed
cout << "binary solver failed..." << endl;
return -9999.0;
}
++count; ++count;
} }
@ -487,6 +497,12 @@ double TGAptSurface::query_solver( double lon_deg, double lat_deg ) {
} }
v = (max_v + min_v) / 2.0; v = (max_v + min_v) / 2.0;
if ( count > 100 ) {
// solver failed
cout << "binary solver failed..." << endl;
return -9999.0;
}
++count; ++count;
} }
@ -500,15 +516,7 @@ double TGAptSurface::query_solver( double lon_deg, double lat_deg ) {
// cout << " final query distance error = " << dist << endl; // cout << " final query distance error = " << dist << endl;
return p.z(); return p.z();
} }
gcount++;
if ( gcount % 100 == 0 ) {
cout << "query count = " << gcount << " dist = " << dx << ", "
<< dy << endl;
} }
}
cout << "binary solver failed..." << endl;
return p.z(); return p.z();
} }

View file

@ -603,16 +603,45 @@ void build_airport( string airport_id, float alt_m,
} }
} }
// write_polygon( accum, "accum" ); // Now generate small surface for each beacon
if ( apt_base.total_size() == 0 ) { TGPolygon obj_base, obj_safe_base;
SG_LOG(SG_GENERAL, SG_ALERT, "no airport points generated"); double obj_hdg = runways[0].heading;
return; for ( i = 0; i < (int)beacons.size(); ++i ) {
obj_base = gen_wgs84_area( beacons[i], 20.0, 0.0, 0.0, 20.0,
obj_hdg, alt_m, false );
obj_safe_base = gen_wgs84_area( beacons[i], 40.0, 0.0, 0.0, 40.0,
obj_hdg, alt_m, false );
apt_base = tgPolygonUnion( obj_base, apt_base );
apt_clearing = tgPolygonUnion( obj_safe_base, apt_clearing );
}
// Now generate small surface for each tower
for ( i = 0; i < (int)towers.size(); ++i ) {
obj_base = gen_wgs84_area( towers[i], 20.0, 0.0, 0.0, 20.0,
obj_hdg, alt_m, false );
obj_safe_base = gen_wgs84_area( towers[i], 40.0, 0.0, 0.0, 40.0,
obj_hdg, alt_m, false );
apt_base = tgPolygonUnion( obj_base, apt_base );
apt_clearing = tgPolygonUnion( obj_safe_base, apt_clearing );
}
// Now generate small surface for each windsock
for ( i = 0; i < (int)windsocks.size(); ++i ) {
obj_base = gen_wgs84_area( windsocks[i], 20.0, 0.0, 0.0, 20.0,
obj_hdg, alt_m, false );
obj_safe_base = gen_wgs84_area( windsocks[i], 40.0, 0.0, 0.0, 40.0,
obj_hdg, alt_m, false );
apt_base = tgPolygonUnion( obj_base, apt_base );
apt_clearing = tgPolygonUnion( obj_safe_base, apt_clearing );
} }
// 5th pass: generate runway lights // 5th pass: generate runway lights
superpoly_list rwy_lights; rwy_lights.clear(); superpoly_list rwy_lights; rwy_lights.clear();
for ( i = 0; i < (int)runways.size(); ++i ) { for ( i = 0; i < (int)runways.size(); ++i ) {
gen_runway_lights( runways[i], alt_m, rwy_lights ); gen_runway_lights( runways[i], alt_m, rwy_lights, &apt_base );
} }
// 6th pass: generate all taxiway lights // 6th pass: generate all taxiway lights
@ -620,11 +649,19 @@ void build_airport( string airport_id, float alt_m,
gen_taxiway_lights( taxiways[i], alt_m, rwy_lights ); gen_taxiway_lights( taxiways[i], alt_m, rwy_lights );
} }
// write_polygon( accum, "accum" );
// write_polygon( apt_base, "base" );
// write_polygon( apt_clearing, "clear" );
if ( apt_base.total_size() == 0 ) {
SG_LOG(SG_GENERAL, SG_ALERT, "no airport points generated");
return;
}
// generate convex hull (no longer) // generate convex hull (no longer)
// TGPolygon hull = convex_hull(apt_pts); // TGPolygon hull = convex_hull(apt_pts);
TGPolygon filled_base = tgPolygonStripHoles( apt_base ); TGPolygon filled_base = tgPolygonStripHoles( apt_base );
// write_polygon( filled_base, "filled-base" ); // write_polygon( filled_base, "base" );
TGPolygon divided_base = tgPolygonSplitLongEdges( filled_base, 200.0 ); TGPolygon divided_base = tgPolygonSplitLongEdges( filled_base, 200.0 );
// write_polygon( divided_base, "divided-base" ); // write_polygon( divided_base, "divided-base" );
TGPolygon base_poly = tgPolygonDiff( divided_base, accum ); TGPolygon base_poly = tgPolygonDiff( divided_base, accum );

View file

@ -681,7 +681,7 @@ static TGSuperPoly gen_touchdown_zone_lights( const TGRunway& rwy_info,
// generate a simple 2 bar VASI for a 3 degree approach // generate a simple 2 bar VASI for a 3 degree approach
static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m, static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
bool recip ) bool recip, TGPolygon *apt_base )
{ {
point_list lights; lights.clear(); point_list lights; lights.clear();
point_list normals; normals.clear(); point_list normals; normals.clear();
@ -768,14 +768,21 @@ static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
lights.push_back( pt1 ); lights.push_back( pt1 );
normals.push_back( normal ); normals.push_back( normal );
// grass base
Point3D base_pt = (ref + pt1) / 2.0;
TGPolygon obj_base = gen_wgs84_area( base_pt, 15.0, 0.0, 0.0, 15.0,
length_hdg, alt_m, false );
*apt_base = tgPolygonUnion( obj_base, *apt_base );
// upwind bar // upwind bar
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), length_hdg,
700 * SG_FEET_TO_METER, &lat, &lon, &r );
ref = Point3D( lon, lat, 0.0 );
normal = gen_runway_light_vector( rwy_info, 3.0, recip ); normal = gen_runway_light_vector( rwy_info, 3.0, recip );
// unit1 // unit1
pt1 = ref; pt1 = ref;
geo_direct_wgs_84 ( alt_m, pt1.lat(), pt1.lon(), length_hdg,
700 * SG_FEET_TO_METER, &lat, &lon, &r );
pt1 = Point3D( lon, lat, 0.0 );
lights.push_back( pt1 ); lights.push_back( pt1 );
normals.push_back( normal ); normals.push_back( normal );
geo_direct_wgs_84 ( alt_m, pt1.lat(), pt1.lon(), left_hdg, geo_direct_wgs_84 ( alt_m, pt1.lat(), pt1.lon(), left_hdg,
@ -808,6 +815,12 @@ static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
lights.push_back( pt1 ); lights.push_back( pt1 );
normals.push_back( normal ); normals.push_back( normal );
// grass base
base_pt = (ref + pt1) / 2.0;
obj_base = gen_wgs84_area( base_pt, 15.0, 0.0, 0.0, 15.0,
length_hdg, alt_m, false );
*apt_base = tgPolygonUnion( obj_base, *apt_base );
TGPolygon lights_poly; lights_poly.erase(); TGPolygon lights_poly; lights_poly.erase();
TGPolygon normals_poly; normals_poly.erase(); TGPolygon normals_poly; normals_poly.erase();
lights_poly.add_contour( lights, false ); lights_poly.add_contour( lights, false );
@ -826,7 +839,7 @@ static TGSuperPoly gen_vasi( const TGRunway& rwy_info, float alt_m,
// generate a simple PAPI for a 3 degree approach // generate a simple PAPI for a 3 degree approach
static TGSuperPoly gen_papi( const TGRunway& rwy_info, float alt_m, static TGSuperPoly gen_papi( const TGRunway& rwy_info, float alt_m,
bool recip ) bool recip, TGPolygon *apt_base )
{ {
point_list lights; lights.clear(); point_list lights; lights.clear();
point_list normals; normals.clear(); point_list normals; normals.clear();
@ -908,6 +921,12 @@ static TGSuperPoly gen_papi( const TGRunway& rwy_info, float alt_m,
normal = gen_runway_light_vector( rwy_info, 2.5, recip ); normal = gen_runway_light_vector( rwy_info, 2.5, recip );
normals.push_back( normal ); normals.push_back( normal );
// grass base
Point3D base_pt = (ref + pt1) / 2.0;
TGPolygon obj_base = gen_wgs84_area( base_pt, 15.0, 0.0, 0.0, 30.0,
length_hdg, alt_m, false );
*apt_base = tgPolygonUnion( obj_base, *apt_base );
TGPolygon lights_poly; lights_poly.erase(); TGPolygon lights_poly; lights_poly.erase();
TGPolygon normals_poly; normals_poly.erase(); TGPolygon normals_poly; normals_poly.erase();
lights_poly.add_contour( lights, false ); lights_poly.add_contour( lights, false );
@ -2563,7 +2582,7 @@ static superpoly_list gen_malsx( const TGRunway& rwy_info,
// top level runway light generator // top level runway light generator
void gen_runway_lights( const TGRunway& rwy_info, float alt_m, void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
superpoly_list &lights ) { superpoly_list &lights, TGPolygon *apt_base ) {
string lighting_flags = rwy_info.lighting_flags; string lighting_flags = rwy_info.lighting_flags;
SG_LOG( SG_GENERAL, SG_DEBUG, "gen runway lights " << rwy_info.rwy_no << " " SG_LOG( SG_GENERAL, SG_DEBUG, "gen runway lights " << rwy_info.rwy_no << " "
@ -2632,17 +2651,17 @@ void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
// VASI/PAPI lighting // VASI/PAPI lighting
if ( vasi1 == 2 /* Has VASI */ ) { if ( vasi1 == 2 /* Has VASI */ ) {
TGSuperPoly s = gen_vasi( rwy_info, alt_m, false ); TGSuperPoly s = gen_vasi( rwy_info, alt_m, false, apt_base );
lights.push_back( s ); lights.push_back( s );
} else if ( vasi1 == 3 /* Has PAPI */ ) { } else if ( vasi1 == 3 /* Has PAPI */ ) {
TGSuperPoly s = gen_papi( rwy_info, alt_m, false ); TGSuperPoly s = gen_papi( rwy_info, alt_m, false, apt_base );
lights.push_back( s ); lights.push_back( s );
} }
if ( vasi2 == 2 /* Has VASI */ ) { if ( vasi2 == 2 /* Has VASI */ ) {
TGSuperPoly s = gen_vasi( rwy_info, alt_m, true ); TGSuperPoly s = gen_vasi( rwy_info, alt_m, true, apt_base );
lights.push_back( s ); lights.push_back( s );
} else if ( vasi2 == 3 /* Has PAPI */ ) { } else if ( vasi2 == 3 /* Has PAPI */ ) {
TGSuperPoly s = gen_papi( rwy_info, alt_m, true ); TGSuperPoly s = gen_papi( rwy_info, alt_m, true, apt_base );
lights.push_back( s ); lights.push_back( s );
} }
@ -2853,26 +2872,30 @@ void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
// Many aproach lighting systems define the threshold lighting // Many aproach lighting systems define the threshold lighting
// needed, but for those that don't (i.e. REIL, ODALS, or Edge // needed, but for those that don't (i.e. REIL, ODALS, or Edge
// lights defined but no approach lights.) // lights defined but no approach lights)
// Make threshold lighting // make threshold lighting
cout << "rwylt1 = " << rwylt1 << " app1 = " << app1 << endl;
if ( rwylt1 >= 3 /* Has REIL lighting */ if ( rwylt1 >= 3 /* Has REIL lighting */
|| app1 == 6 /* ODALS Omni-directional approach light system */ || app1 == 6 /* ODALS Omni-directional approach light system */
|| ( rwylt1 >= 2 /* Has edge lighting */ || ( rwylt1 >= 2 && app1 <= 1 ) /* Has edge lighting, but no
&& app1 == 0 /* No approach lighting */ ) ) approach lighting */ )
{ {
// forward direction // forward direction
cout << "threshold lights for forward direction" << endl;
superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1, superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1,
alt_m, false ); alt_m, false );
for ( i = 0; i < s.size(); ++i ) { for ( i = 0; i < s.size(); ++i ) {
lights.push_back( s[i] ); lights.push_back( s[i] );
} }
} }
cout << "rwylt2 = " << rwylt2 << " app2 = " << app2 << endl;
if ( rwylt2 >= 3 /* Has REIL lighting */ if ( rwylt2 >= 3 /* Has REIL lighting */
|| app2 == 6 /* ODALS Omni-directional approach light system */ || app2 == 6 /* ODALS Omni-directional approach light system */
|| ( rwylt2 >= 2 /* Has edge lighting */ || ( rwylt2 >= 2 && app2 <= 1 ) /* Has edge lighting, but no
&& app2 == 0 /* No approach lighting */ ) ) approach lighting */ )
{ {
// reverse direction // reverse direction
cout << "threshold lights for reverse direction" << endl;
superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1, superpoly_list s = gen_runway_threshold_lights( rwy_info, rwylt1,
alt_m, true ); alt_m, true );
for ( i = 0; i < s.size(); ++i ) { for ( i = 0; i < s.size(); ++i ) {

View file

@ -35,7 +35,7 @@
// generate runway lighting // generate runway lighting
void gen_runway_lights( const TGRunway& rwy_info, float alt_m, void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
superpoly_list &lights ); superpoly_list &lights, TGPolygon *apt_base );
// generate taxiway lighting // generate taxiway lighting
void gen_taxiway_lights( const TGRunway& taxiway_info, float alt_m, void gen_taxiway_lights( const TGRunway& taxiway_info, float alt_m,

View file

@ -37,7 +37,7 @@
// given a runway center point, length, width, and heading, and // given a runway center point, length, width, and heading, and
// altitude (meters) generate the lon and lat 4 corners using wgs84 // altitude (meters) generate the lon and lat 4 corners using wgs84
// math. // math.
static TGPolygon gen_wgs84_area( Point3D origin, TGPolygon gen_wgs84_area( Point3D origin,
double length_m, double length_m,
double displ1, double displ2, double displ1, double displ2,
double width_m, double width_m,

View file

@ -71,6 +71,17 @@ typedef runway_list::iterator runway_list_iterator;
typedef runway_list::const_iterator const_runway_list_iterator; typedef runway_list::const_iterator const_runway_list_iterator;
// 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 // generate an area for a runway with expantion specified as a scale
// factor (return result points in degrees) // factor (return result points in degrees)
TGPolygon gen_runway_area_w_scale( const TGRunway& runway, TGPolygon gen_runway_area_w_scale( const TGRunway& runway,