1
0
Fork 0

first work on reading apt.dat 8.50

This commit is contained in:
Christian Schmitt 2011-12-28 11:36:37 +01:00
parent 1eae25d17a
commit 0dddd26b91
36 changed files with 9430 additions and 1 deletions

View file

@ -3,4 +3,5 @@ include_directories(${PROJECT_SOURCE_DIR}/src/BuildTiles)
if (NEWMAT_FOUND)
add_subdirectory(GenAirports)
add_subdirectory(GenAirports850)
endif (NEWMAT_FOUND)

View file

@ -0,0 +1 @@
genapts850

View file

@ -0,0 +1,32 @@
add_executable(genapts850
apt_surface.hxx apt_surface.cxx
build.cxx build.hxx
convex_hull.cxx convex_hull.hxx
elevations.cxx elevations.hxx
global.hxx
lights.hxx lights.cxx
main.cxx
point2d.cxx point2d.hxx
poly_extra.cxx poly_extra.hxx
runway.cxx runway.hxx
rwy_common.cxx rwy_common.hxx
rwy_nonprec.cxx rwy_nonprec.hxx
rwy_gen.cxx rwy_gen.hxx
rwy_simple.cxx rwy_simple.hxx
rwy_visual.cxx rwy_visual.hxx
taxiway.cxx taxiway.hxx
texparams.hxx
)
target_link_libraries(genapts850
Polygon Geometry
Array Optimize Output poly2tri
TriangleJRS
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GPC_LIBRARY}
${NEWMAT_LIBRARY})
install(TARGETS genapts850 RUNTIME DESTINATION bin)

View file

@ -0,0 +1,477 @@
// apt_surface.cxx -- class to manage airport terrain surface
// approximation and smoothing
//
// Written by Curtis Olson, started March 2003.
//
// Copyright (C) 2003 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: apt_surface.cxx,v 1.31 2005-12-19 16:51:25 curt Exp $
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/compiler.h>
// libnewmat includes and defines
#define WANT_STREAM // include.h will get stream fns
#define WANT_MATH // include.h will get math fns
// newmatap.h will get include.h
#include <newmat/newmatap.h> // need matrix applications
#include <newmat/newmatio.h> // need matrix output routines
#include <simgear/constants.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/sg_types.hxx>
#include <simgear/debug/logstream.hxx>
#include <Array/array.hxx>
#include "elevations.hxx"
#include "global.hxx"
#include "apt_surface.hxx"
static bool limit_slope( SimpleMatrix *Pts, int i1, int j1, int i2, int j2,
double average_elev_m )
{
bool slope_error = false;
Point3D p1, p2;
p1 = Pts->element(i1,j1);
p2 = Pts->element(i2,j2);
double az1, az2, dist;
double slope;
geo_inverse_wgs_84( 0, p1.y(), p1.x(), p2.y(), p2.x(),
&az1, &az2, &dist );
slope = (p2.z() - p1.z()) / dist;
if ( fabs(slope) > (slope_max + slope_eps) ) {
// need to throttle slope, let's move the point
// furthest away from average towards the center.
slope_error = true;
SG_LOG( SG_GENERAL, SG_DEBUG, " (a) detected slope of "
<< slope << " dist = " << dist );
double e1 = fabs(average_elev_m - p1.z());
double e2 = fabs(average_elev_m - p2.z());
// cout << " z1 = " << p1.z() << " z2 = " << p2.z() << endl;
// cout << " e1 = " << e1 << " e2 = " << e2 << endl;
if ( e1 > e2 ) {
// cout << " p1 error larger" << endl;
if ( slope > 0 ) {
p1.setz( p2.z() - (dist * slope_max) );
} else {
p1.setz( p2.z() + (dist * slope_max) );
}
Pts->set(i1, j1, p1);
} else {
// cout << " p2 error larger" << endl;
if ( slope > 0 ) {
p2.setz( p1.z() + (dist * slope_max) );
} else {
p2.setz( p1.z() - (dist * slope_max) );
}
Pts->set(i2, j2, p2);
}
// cout << " z1 = " << p1.z() << " z2 = " << p2.z() << endl;
}
return slope_error;
}
// Constructor, specify min and max coordinates of desired area in
// lon/lat degrees
TGAptSurface::TGAptSurface( const string& path,
const string_list& elev_src,
Point3D _min_deg, Point3D _max_deg,
double _average_elev_m )
{
// Calculate desired size of grid
min_deg = _min_deg;
max_deg = _max_deg;
average_elev_m = _average_elev_m;
// cout << "min = " << min_deg << " max = " << max_deg
// << " ave = " << average_elev_m << endl;
// The following size calculations are for the purpose of
// determining grid divisions so it's not important that they be
// *exact*, just ball park.
double y_deg = max_deg.lat() - min_deg.lat();
double y_rad = y_deg * SG_DEGREES_TO_RADIANS;
double y_nm = y_rad * SG_RAD_TO_NM;
double y_m = y_nm * SG_NM_TO_METER;
double xfact = cos( min_deg.lat() * SG_DEGREES_TO_RADIANS );
double x_deg = max_deg.lon() - min_deg.lon();
double x_rad = x_deg * SG_DEGREES_TO_RADIANS;
double x_nm = x_rad * SG_RAD_TO_NM * xfact;
double x_m = x_nm * SG_NM_TO_METER;
SG_LOG( SG_GENERAL, SG_DEBUG,
"Area size = " << y_m << " x " << x_m << " (m)" );
int xdivs = (int)(x_m / coarse_grid) + 1;
int ydivs = (int)(y_m / coarse_grid) + 1;
// set an arbitrary minumum number of divisions to keep things
// interesting
if ( xdivs < 8 ) { xdivs = 8; }
if ( ydivs < 8 ) { ydivs = 8; }
SG_LOG(SG_GENERAL, SG_INFO, " M(" << ydivs << "," << xdivs << ")");
double dlon = x_deg / xdivs;
double dlat = y_deg / ydivs;
double dlon_h = dlon * 0.5;
double dlat_h = dlat * 0.5;
// Build the extra res input grid (shifted SW by half (dlon,dlat)
// with an added major row column on the NE sides.)
int mult = 10;
SimpleMatrix dPts( (xdivs + 1) * mult + 1, (ydivs + 1) * mult + 1 );
for ( int j = 0; j < dPts.rows(); ++j ) {
for ( int i = 0; i < dPts.cols(); ++i ) {
dPts.set(i, j, Point3D( min_deg.lon() - dlon_h
+ i * (dlon / (double)mult),
min_deg.lat() - dlat_h
+ j * (dlat / (double)mult),
-9999 )
);
}
}
// Lookup the elevations of all the grid points
tgCalcElevations( path, elev_src, dPts, 0.0 );
#ifdef DEBUG
for ( int j = 0; j < dPts.rows(); ++j ) {
for ( int i = 0; i < dPts.cols(); ++i ) {
printf("hr %.5f %.5f %.1f\n",
dPts.element(i,j).x(), dPts.element(i,j).y(),
dPts.element(i,j).z() );
}
}
#endif
// Clamp the elevations against the externally provided average
// elevation.
tgClampElevations( dPts, average_elev_m, max_clamp );
#ifdef DEBUG
for ( int j = 0; j < dPts.rows(); ++j ) {
for ( int i = 0; i < dPts.cols(); ++i ) {
printf("chr %.5f %.5f %.1f\n",
dPts.element(i,j).x(), dPts.element(i,j).y(),
dPts.element(i,j).z() );
}
}
#endif
// Build the normal res input grid from the double res version
Pts = new SimpleMatrix(xdivs + 1, ydivs + 1 );
double ave_divider = (mult+1) * (mult+1);
for ( int j = 0; j < Pts->rows(); ++j ) {
for ( int i = 0; i < Pts->cols(); ++i ) {
SG_LOG(SG_GENERAL, SG_DEBUG, i << "," << j);
double accum = 0.0;
double lon_accum = 0.0;
double lat_accum = 0.0;
for ( int jj = 0; jj <= mult; ++jj ) {
for ( int ii = 0; ii <= mult; ++ii ) {
double value = dPts.element(mult*i + ii, mult*j + jj).z();
SG_LOG( SG_GENERAL, SG_DEBUG, "value = " << value );
accum += value;
lon_accum += dPts.element(mult*i + ii, mult*j + jj).x();
lat_accum += dPts.element(mult*i + ii, mult*j + jj).y();
}
}
double val_ave = accum / ave_divider;
double lon_ave = lon_accum / ave_divider;
double lat_ave = lat_accum / ave_divider;
SG_LOG( SG_GENERAL, SG_DEBUG, " val_ave = " << val_ave );
Pts->set(i, j, Point3D( min_deg.lon() + i * dlon,
min_deg.lat() + j * dlat,
val_ave )
);
SG_LOG( SG_GENERAL, SG_DEBUG, "lon_ave = " << lon_ave
<< " lat_ave = " << lat_ave );
SG_LOG( SG_GENERAL, SG_DEBUG, "lon = " << min_deg.lon() + j * dlon
<< " lat = " << min_deg.lat() + i * dlat );
}
}
#ifdef DEBUG
for ( int j = 0; j < Pts->rows(); ++j ) {
for ( int i = 0; i < Pts->cols(); ++i ) {
printf("nr %.5f %.5f %.1f\n",
Pts->element(i,j).x(),
Pts->element(i,j).y(),
Pts->element(i,j).z() );
}
}
#endif
bool slope_error = true;
while ( slope_error ) {
SG_LOG( SG_GENERAL, SG_DEBUG, "start of slope processing pass" );
slope_error = false;
// Add some "slope" sanity to the resulting surface grid points
for ( int j = 0; j < Pts->rows() - 1; ++j ) {
for ( int i = 0; i < Pts->cols() - 1; ++i ) {
if ( limit_slope( Pts, i, j, i+1, j, average_elev_m ) ) {
slope_error = true;
}
if ( limit_slope( Pts, i, j, i, j+1, average_elev_m ) ) {
slope_error = true;
}
if ( limit_slope( Pts, i, j, i+1, j+1, average_elev_m ) ) {
slope_error = true;
}
}
}
}
#ifdef DEBUG
for ( int j = 0; j < Pts->rows(); ++j ) {
for ( int i = 0; i < Pts->cols(); ++i ) {
printf("%.5f %.5f %.1f\n",
Pts->element(i,j).x(), Pts->element(i,j).y(),
Pts->element(i,j).z() );
}
}
#endif
// compute an central offset point.
double clon = (min_deg.lon() + max_deg.lon()) / 2.0;
double clat = (min_deg.lat() + max_deg.lat()) / 2.0;
offset = Point3D( clon, clat, average_elev_m );
SG_LOG(SG_GENERAL, SG_DEBUG, "Central offset point = " << offset);
// Create the fitted surface
SG_LOG(SG_GENERAL, SG_DEBUG, "ready to create fitted surface");
fit();
SG_LOG(SG_GENERAL, SG_DEBUG, " fit process successful.");
#ifdef DEBUG
// For debugging only: output an array of surface points suitable
// for plotting with gnuplot. This is useful for comparing the
// approximated and smoothed surface to the original rough
// surface.
cout << "DEBUGGING TEST" << endl;
const int divs = 100;
double dx = x_deg / divs;
double dy = y_deg / divs;
for ( int j = 0; j < divs; ++j ) {
for ( int i = 0; i < divs; ++i ) {
double lon = min_deg.lon() + j * dx;
double lat = min_deg.lat() + i * dy;
printf("%.5f %.5f %.1f\n", lon, lat, query(lon, lat) );
}
}
#endif
}
TGAptSurface::~TGAptSurface() {
delete Pts;
}
static ColumnVector qr_method( Real* y,
Real* t1, Real* t2, Real* t3, Real* t4,
Real* t5, Real* t6, Real* t7, Real* t8,
Real* t9, Real* t10, Real* t11, Real* t12,
Real* t13, Real* t14, Real* t15,
int nobs, int npred )
{
cout << "QR triangularisation" << endl;;
// QR triangularisation method
// load data - 1s into col 1 of matrix
int npred1 = npred+1;
cout << "nobs = " << nobs << " npred1 = " << npred1 << endl;
Matrix X(nobs,npred1); ColumnVector Y(nobs);
X.column(1) = 1.0;
X.column(2) << t1;
X.column(3) << t2;
X.column(4) << t3;
X.column(5) << t4;
X.column(6) << t5;
X.column(7) << t6;
X.column(8) << t7;
X.column(9) << t8;
X.column(10) << t9;
X.column(11) << t10;
X.column(12) << t11;
X.column(13) << t12;
X.column(14) << t13;
X.column(15) << t14;
X.column(16) << t15;
Y << y;
// do Householder triangularisation
// no need to deal with constant term separately
Matrix X1 = X; // Want copy of matrix
ColumnVector Y1 = Y;
UpperTriangularMatrix U; ColumnVector M;
QRZ(X1, U); QRZ(X1, Y1, M); // Y1 now contains resids
ColumnVector A = U.i() * M;
ColumnVector Fitted = X * A;
Real ResVar = sum_square(Y1) / (nobs-npred1);
// get variances of estimates
U = U.i(); DiagonalMatrix D; D << U * U.t();
// Get diagonals of Hat matrix
DiagonalMatrix Hat; Hat << X1 * X1.t();
cout << "A vector = " << A << endl;
cout << "A rows = " << A.nrows() << endl;
// print out answers
cout << "\nEstimates and their standard errors\n\n";
ColumnVector SE(npred1);
for (int i=1; i<=npred1; i++) SE(i) = sqrt(D(i)*ResVar);
cout << setw(11) << setprecision(5) << (A | SE) << endl;
cout << "\nObservations, fitted value, residual value, hat value\n";
cout << setw(9) << setprecision(3) <<
(X.columns(2,4) | Y | Fitted | Y1 | Hat.as_column());
cout << "\n\n";
return A;
}
// Use a linear least squares method to fit a 3d polynomial to the
// sampled surface data
void TGAptSurface::fit() {
// the fit function is:
// f(x,y) = A1*x + A2*x*y + A3*y +
// A4*x*x + A5+x*x*y + A6*x*x*y*y + A7*y*y + A8*x*y*y +
// A9*x*x*x + A10*x*x*x*y + A11*x*x*x*y*y + A12*x*x*x*y*y*y +
// A13*y*y*y + A14*x*y*y*y + A15*x*x*y*y*y
int nobs = Pts->cols() * Pts->rows(); // number of observations
int npred = 15; // number of predictor values A[n]
vector<Real> tz(nobs);
vector<Real> t1(nobs);
vector<Real> t2(nobs);
vector<Real> t3(nobs);
vector<Real> t4(nobs);
vector<Real> t5(nobs);
vector<Real> t6(nobs);
vector<Real> t7(nobs);
vector<Real> t8(nobs);
vector<Real> t9(nobs);
vector<Real> t10(nobs);
vector<Real> t11(nobs);
vector<Real> t12(nobs);
vector<Real> t13(nobs);
vector<Real> t14(nobs);
vector<Real> t15(nobs);
// generate the required fit data
for ( int j = 0; j < Pts->rows(); j++ ) {
for ( int i = 0; i < Pts->cols(); i++ ) {
Point3D p = Pts->element( i, j );
int index = ( j * Pts->cols() ) + i;
Real x = p.x() - offset.x();
Real y = p.y() - offset.y();
Real z = p.z() - offset.z();
//cout << "pt = " << x << "," << y << "," << z << endl;
tz[index] = z;
t1[index] = x;
t2[index] = x*y;
t3[index] = y;
t4[index] = x*x;
t5[index] = x*x*y;
t6[index] = x*x*y*y;
t7[index] = y*y;
t8[index] = x*y*y;
t9[index] = x*x*x;
t10[index] = x*x*x*y;
t11[index] = x*x*x*y*y;
t12[index] = x*x*x*y*y*y;
t13[index] = y*y*y;
t14[index] = x*y*y*y;
t15[index] = x*x*y*y*y;
}
}
// we want to find the values of a,b,c to give the best
// fit
Try {
surface_coefficients
= qr_method( &tz[0],
&t1[0], &t2[0], &t3[0], &t4[0], &t5[0], &t6[0], &t7[0], &t8[0],
&t9[0], &t10[0], &t11[0], &t12[0], &t13[0], &t14[0], &t15[0],
nobs, npred
);
cout << "surface_coefficients size = " << surface_coefficients.nrows() << endl;
}
CatchAll { cout << BaseException::what(); }
}
// Query the elevation of a point, return -9999 if out of range
double TGAptSurface::query( double lon_deg, double lat_deg ) {
// sanity check
if ( lon_deg < min_deg.lon() || lon_deg > max_deg.lon() ||
lat_deg < min_deg.lat() || lat_deg > max_deg.lat() )
{
SG_LOG(SG_GENERAL, SG_WARN,
"Warning: query out of bounds for fitted surface!");
return -9999.0;
}
// compute the function with solved coefficients
// the fit function is:
// f(x,y) = A1*x + A2*x*y + A3*y +
// A4*x*x + A5+x*x*y + A6*x*x*y*y + A7*y*y + A8*x*y*y +
// A9*x*x*x + A10*x*x*x*y + A11*x*x*x*y*y + A12*x*x*x*y*y*y +
// A13*y*y*y + A14*x*y*y*y + A15*x*x*y*y*y
double x = lon_deg - offset.x();
double y = lat_deg - offset.y();
ColumnVector A = surface_coefficients;
double result = A(1) + A(2)*x + A(3)*x*y + A(4)*y + A(5)*x*x + A(6)*x*x*y
+ A(7)*x*x*y*y + A(8)*y*y + A(9)*x*y*y + A(10)*x*x*x + A(11)*x*x*x*y
+ A(12)*x*x*x*y*y + A(13)*x*x*x*y*y*y + A(14)*y*y*y + A(15)*x*y*y*y
+ A(16)*x*x*y*y*y;
result += offset.z();
printf("result = %.6f %.6f %.2f\n", lon_deg, lat_deg, result);
return result;
}

View file

@ -0,0 +1,148 @@
// apt_surface.hxx -- class to manage airport terrain surface
// approximation and smoothing
//
// Written by Curtis Olson, started March 2003.
//
// Copyright (C) 2003 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: apt_surface.hxx,v 1.9 2005-09-09 20:47:04 curt Exp $
//
#ifndef _APT_SURFACE_HXX
#define _APT_SURFACE_HXX
#include <string>
// libnewmat includes and defines
#define WANT_STREAM // include.h will get stream fns
#define WANT_MATH // include.h will get math fns
// newmatap.h will get include.h
#include <newmat/newmatap.h> // need matrix applications
#include <newmat/newmatio.h> // need matrix output routines
#include <Geometry/point3d.hxx>
/***
* A dirt simple matrix class for our convenience based on top of Point3D
*/
class SimpleMatrix {
private:
int _rows;
int _cols;
point_list m;
public:
inline SimpleMatrix( int columns, int rows ) {
_cols = columns;
_rows = rows;
m.resize( _cols * _rows );
}
inline Point3D element( int col, int row ) {
int index = ( row * _cols ) + col;
if ( col < 0 || col >= _cols ) {
cout << "column out of bounds on read (" << col << " >= " << _cols << ")"
<< endl;
int *p = 0; *p = 1; // force crash
} else if ( row < 0 || row >= _rows ) {
cout << "row out of bounds on read (" << row << " >= " << _rows << ")"
<< endl;
int *p = 0; *p = 1; // force crash
}
return m[index];
}
inline void set( int col, int row, Point3D p ) {
int index = ( row * _cols ) + col;
if ( col < 0 || col >= _cols ) {
cout << "column out of bounds on set (" << col << " >= " << _cols << ")"
<< endl;
int *p = 0; *p = 1; // force crash
} else if ( row < 0 || row >= _rows ) {
cout << "row out of bounds on set (" << row << " >= " << _rows << ")"
<< endl;
int *p = 0; *p = 1; // force crash
}
m[index] = p;
}
inline int cols() const { return _cols; }
inline int rows() const { return _rows; }
};
/***
* Note of explanation. When a TGAptSurface instance is created, you
* must specify a min and max lon/lat containing the entire airport
* area. The class will divide up that area into a reasonably sized
* regular grid. It will then look up the elevation of each point on
* the grid from the DEM/Array data. Finally it will fit do a linear
* least squares polygonal surface approximation from this grid. Each
* vertex of the actual airport model is drapped over this fitted
* surface rather than over the underlying terrain data. This
* provides a) smoothing of noisy terrain data and b) natural rises
* and dips in the airport surface.
*/
class TGAptSurface {
private:
// The actual nurbs surface approximation for the airport
SimpleMatrix *Pts;
ColumnVector surface_coefficients;
Point3D min_deg, max_deg;
// A central point in the airport area
Point3D offset;
// externally seeded average airport elevation
double average_elev_m;
public:
// Constructor, specify min and max coordinates of desired area in
// lon/lat degrees, also please specify an "average" airport
// elevations in meters.
TGAptSurface( const string &path, const string_list& elev_src,
Point3D _min_deg, Point3D _max_deg, double _average_elev_m );
// Destructor
~TGAptSurface();
// Use a linear least squares method to fit a 3d polynomial to the
// sampled surface data
void fit();
// Query the elevation of a point, return -9999 if out of range.
// This routine makes a simplistic assumption that X,Y space is
// proportional to u,v space on the nurbs surface which it isn't.
double query( double lon_deg, double lat_deg );
};
#endif // _APT_SURFACE_HXX

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,49 @@
// build.hxx -- routines to build polygon model of an airport from the runway
// definition
//
// Written by Curtis Olson, started September 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: build.hxx,v 1.10 2004-11-19 22:25:49 curt Exp $
//
#ifndef _BUILD_HXX
#define _BUILD_HXX
#include <list>
#include "global.hxx"
#include "point2d.hxx"
// build 3d airport
void build_airport( string airport_id, float alt_m,
string_list& runways_raw,
string_list& beacons_raw,
string_list& towers_raw,
string_list& windsocks_raw,
const string& root,
const string_list& elev_src );
#endif // _BUILD_HXX

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

@ -0,0 +1,282 @@
// elevations.cxx -- routines to help calculate DEM elevations for a
// set of points
//
// Written by Curtis Olson, started April 2004.
//
// Copyright (C) 2004 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: elevations.cxx,v 1.8 2005-12-19 16:51:25 curt Exp $
//
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
// libnewmat includes and defines
#define WANT_STREAM // include.h will get stream fns
#define WANT_MATH // include.h will get math fns
// newmatap.h will get include.h
#include <newmat/newmatap.h> // need matrix applications
#include <newmat/newmatio.h> // need matrix output routines
#include <simgear/constants.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/sg_types.hxx>
#include <simgear/debug/logstream.hxx>
#include <Array/array.hxx>
#include "global.hxx"
#include "apt_surface.hxx"
// lookup node elevations for each point in the point_list. Returns
// average of all points. Doesn't modify the original list.
double tgAverageElevation( const string &root, const string_list elev_src,
const point_list points_source )
{
bool done = false;
unsigned int i;
TGArray array;
// make a copy so our routine is non-destructive.
point_list points = points_source;
// just bail if no work to do
if ( points.size() == 0 ) {
return 0.0;
}
// set all elevations to -9999
for ( i = 0; i < points.size(); ++i ) {
points[i].setz( -9999.0 );
}
while ( !done ) {
// find first node with -9999 elevation
Point3D first(0.0);
bool found_one = false;
for ( i = 0; i < points.size(); ++i ) {
if ( points[i].z() < -9000.0 && !found_one ) {
first = points[i];
found_one = true;
}
}
if ( found_one ) {
SGBucket b( first.x(), first.y() );
string base = b.gen_base_path();
// try the various elevation sources
i = 0;
bool found_file = false;
while ( !found_file && i < elev_src.size() ) {
string array_path = root + "/" + elev_src[i] + "/" + base
+ "/" + b.gen_index_str();
if ( array.open(array_path) ) {
found_file = true;
SG_LOG( SG_GENERAL, SG_DEBUG, "Using array_path = "
<< array_path );
}
i++;
}
// this will fill in a zero structure if no array data
// found/opened
array.parse( b );
// this will do a hasty job of removing voids by inserting
// data from the nearest neighbor (sort of)
array.remove_voids();
// update all the non-updated elevations that are inside
// this array file
double elev;
done = true;
for ( i = 0; i < points.size(); ++i ) {
if ( points[i].z() < -9000.0 ) {
done = false;
elev = array.altitude_from_grid( points[i].lon() * 3600.0,
points[i].lat() * 3600.0 );
if ( elev > -9000 ) {
points[i].setz( elev );
// cout << "interpolating for " << p << endl;
// cout << p.x() << " " << p.y() << " " << p.z()
// << endl;
}
}
}
array.close();
} else {
done = true;
}
}
// now find the average height of the queried points
double total = 0.0;
int count = 0;
for ( i = 0; i < points.size(); ++i ) {
total += points[i].z();
count++;
}
double average = total / (double) count;
SG_LOG(SG_GENERAL, SG_DEBUG, "Average surface height of point list = "
<< average);
return average;
}
// 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 )
{
bool done = false;
int i, j;
TGArray array;
// just bail if no work to do
if ( Pts.rows() == 0 || Pts.cols() == 0 ) {
return;
}
// set all elevations to -9999
for ( j = 0; j < Pts.rows(); ++j ) {
for ( i = 0; i < Pts.cols(); ++i ) {
Point3D p = Pts.element(i, j);
p.setz( -9999.0 );
Pts.set(i, j, p);
}
}
while ( !done ) {
// find first node with -9999 elevation
Point3D first(0.0);
bool found_one = false;
for ( j = 0; j < Pts.rows(); ++j ) {
for ( i = 0; i < Pts.cols(); ++i ) {
Point3D p = Pts.element(i,j);
if ( p.z() < -9000.0 && !found_one ) {
first = p;
found_one = true;
}
}
}
if ( found_one ) {
SGBucket b( first.x(), first.y() );
string base = b.gen_base_path();
// try the various elevation sources
j = 0;
bool found_file = false;
while ( !found_file && j < (int)elev_src.size() ) {
string array_path = root + "/" + elev_src[j] + "/" + base
+ "/" + b.gen_index_str();
if ( array.open(array_path) ) {
found_file = true;
SG_LOG( SG_GENERAL, SG_DEBUG, "Using array_path = "
<< array_path );
}
j++;
}
// this will fill in a zero structure if no array data
// found/opened
array.parse( b );
// this will do a hasty job of removing voids by inserting
// data from the nearest neighbor (sort of)
array.remove_voids();
// update all the non-updated elevations that are inside
// this array file
double elev;
done = true;
for ( j = 0; j < Pts.rows(); ++j ) {
for ( i = 0; i < Pts.cols(); ++i ) {
Point3D p = Pts.element(i,j);
if ( p.z() < -9000.0 ) {
done = false;
elev = array.altitude_from_grid( p.x() * 3600.0,
p.y() * 3600.0 );
if ( elev > -9000 ) {
p.setz( elev );
Pts.set(i, j, p);
// cout << "interpolating for " << p << endl;
// cout << p.x() << " " << p.y() << " " << p.z()
// << endl;
}
}
}
}
array.close();
} else {
done = true;
}
}
// do some post processing for sanity's sake
// find the average height of the queried points
double total = 0.0;
int count = 0;
for ( j = 0; j < Pts.rows(); ++j ) {
for ( i = 0; i < Pts.cols(); ++i ) {
Point3D p = Pts.element(i,j);
total += p.z();
count++;
}
}
double grid_average = total / (double) count;
SG_LOG(SG_GENERAL, SG_DEBUG, "Average surface height of matrix = "
<< grid_average);
}
// clamp all elevations to the specified range
void tgClampElevations( SimpleMatrix &Pts,
double center_m, double max_clamp_m )
{
int i, j;
// go through the elevations and clamp all elevations to within
// +/-max_m of the center_m elevation.
for ( j = 0; j < Pts.rows(); ++j ) {
for ( i = 0; i < Pts.cols(); ++i ) {
Point3D p = Pts.element(i,j);
if ( p.z() < center_m - max_clamp_m ) {
SG_LOG(SG_GENERAL, SG_DEBUG, " clamping " << p.z()
<< " to " << center_m - max_clamp_m );
p.setz( center_m - max_clamp_m );
Pts.set(i, j, p);
}
if ( p.z() > center_m + max_clamp_m ) {
SG_LOG(SG_GENERAL, SG_DEBUG, " clamping " << p.z()
<< " to " << center_m + max_clamp_m );
p.setz( center_m + max_clamp_m );
Pts.set(i, j, p);
}
}
}
}

View file

@ -0,0 +1,56 @@
// elevations.hxx -- routines to help calculate DEM elevations for a
// set of points
//
// Written by Curtis Olson, started April 2004.
//
// Copyright (C) 2004 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: elevations.hxx,v 1.4 2005-09-09 15:05:15 curt Exp $
//
// libnewmat includes and defines
#define WANT_STREAM // include.h will get stream fns
#define WANT_MATH // include.h will get math fns
// newmatap.h will get include.h
#include <newmat/newmatap.h> // need matrix applications
#include <newmat/newmatio.h> // need matrix output routines
#include <simgear/constants.h>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/math/sg_types.hxx>
#include <simgear/debug/logstream.hxx>
#include <Array/array.hxx>
#include "global.hxx"
#include "apt_surface.hxx"
// lookup node elevations for each point in the point_list. Returns
// average of all points. Doesn't modify the original list.
double tgAverageElevation( const string &root, const string_list elev_src,
const point_list points_source );
// 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 );
// clamp all elevations to the specified range
void tgClampElevations( SimpleMatrix &Pts,
double center_m, double max_clamp_m );

View file

@ -0,0 +1,45 @@
// global.hxx -- kind of dumb but oh well...
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: global.hxx,v 1.9 2005-10-31 18:43:27 curt Exp $
//
#ifndef _GEN_AIRPORT_GLOBAL_HXX
#define _GEN_AIRPORT_GLOBAL_HXX
extern int nudge;
// Final grid size for airport surface (in meters)
const double coarse_grid = 300.0;
// compared to the average surface elevation, clamp all values within
// this many meters of the average
const double max_clamp = 100.0;
// maximum slope (rise/run) allowed on an airport surface
extern double slope_max; // = 0.02;
const double slope_eps = 0.00001;
// nurbs query/search epsilon
const double nurbs_eps = 0.0000001;
#endif // _GEN_AIRPORT_GLOBAL_HXX

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,44 @@
// lights.hxx -- Generate runway lighting
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: lights.hxx,v 1.8 2004-11-19 22:25:49 curt Exp $
//
#ifndef _RWY_LIGHTS_HXX
#define _RWY_LIGHTS_HXX
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include "runway.hxx"
#include "texparams.hxx"
// generate runway lighting
void gen_runway_lights( const TGRunway& rwy_info, float alt_m,
superpoly_list &lights, TGPolygon *apt_base );
// generate taxiway lighting
void gen_taxiway_lights( const TGRunway& taxiway_info, float alt_m,
superpoly_list &lights );
#endif // _RWY_LIGHTS_HXX

View file

@ -0,0 +1,491 @@
// 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 $
//
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <simgear/compiler.h>
#include <simgear/structure/exception.hxx>
#include <simgear/misc/sg_path.hxx>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#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/sgstream.hxx>
#include <simgear/misc/strutils.hxx>
#include <Polygon/index.hxx>
#include <Geometry/util.hxx>
#include "build.hxx"
#include "convex_hull.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 );
// Display usage
static void usage( int argc, char **argv ) {
SG_LOG(SG_GENERAL, SG_ALERT,
"Usage " << argv[0] << " --input=<apt_file> "
<< "--work=<work_dir> [ --start-id=abcd ] [ --nudge=n ] "
<< "[--min-lon=<deg>] [--max-lon=<deg>] [--min-lat=<deg>] [--max-lat=<deg>] "
<< "[--clear-dem-path] [--dem-path=<path>] [--max-slope=<decimal>] "
<< "[ --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" );
elev_src.push_back( "SRTM2-Eurasia-3" );
elev_src.push_back( "SRTM2-Islands-3" );
elev_src.push_back( "SRTM2-North_America-3" );
elev_src.push_back( "SRTM2-South_America-3" );
elev_src.push_back( "DEM-USGS-3" );
elev_src.push_back( "SRTM-1" );
elev_src.push_back( "SRTM-3" );
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 );
}
// reads the apt_full file and extracts and processes the individual
// airport records
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;
string_list elev_src;
elev_src.clear();
setup_default_elevation_sources(elev_src);
sglog().setLogLevels( SG_GENERAL, SG_INFO );
// parse arguments
string work_dir = "";
string input_file = "";
string start_id = "";
string airport_id = "";
int arg_pos;
for (arg_pos = 1; arg_pos < argc; arg_pos++) {
string arg = argv[arg_pos];
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 ) {
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);
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 ) {
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);
}
}
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 ) {
SG_LOG(SG_GENERAL, SG_INFO, " " << work_dir << "/" << elev_src[i] );
}
SG_LOG(SG_GENERAL, SG_INFO, "Work directory = " << work_dir);
SG_LOG(SG_GENERAL, SG_INFO, "Nudge = " << nudge);
SG_LOG(SG_GENERAL, SG_INFO, "Longitude = " << min_lon << ':' << max_lon);
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) {
SG_LOG(SG_GENERAL, SG_ALERT, "Bad longitude or latitude");
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);
}
// make work directory
string airportareadir=work_dir+"/AirportArea";
SGPath sgp( airportareadir );
sgp.append( "dummy" );
sgp.create_dir( 0755 );
string lastaptfile = work_dir+"/last_apt";
// initialize persistant polygon counter
string counter_file = airportareadir+"/poly_counter";
poly_index_init( counter_file );
sg_gzifstream in( input_file );
if ( !in.is_open() ) {
SG_LOG( SG_GENERAL, SG_ALERT, "Cannot open file: " << input_file );
exit(-1);
}
string_list runways_list;
string_list beacon_list;
string_list tower_list;
string_list windsock_list;
vector<string> token;
string last_apt_id = "";
string last_apt_info = "";
string last_apt_type = "";
string line;
char tmp[2048];
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();
}
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.)
// 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 */ ) {
// 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 );
if ( !last_apt_id.empty()) {
if ( runways_list.size() ) {
vector<string> rwy_token
= simgear::strutils::split( runways_list[0] );
rwy = token[8];
lat = atof( token[9].c_str() );
lon = atof( token[10].c_str() );
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;
}
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 */ ||
last_apt_type == "17" /* Heliport */ ) {
// skip building heliports and
// 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,
beacon_list,
tower_list,
windsock_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);
}
}
}
last_apt_id = id;
last_apt_info = line;
last_apt_type = token[0];
// clear runway list for start of next airport
runways_list.clear();
beacon_list.clear();
tower_list.clear();
windsock_list.clear();
} else if ( token[0] == "100" ) {
// runway entry
runways_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" ) {
// light object
} 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 {
SG_LOG( SG_GENERAL, SG_ALERT,
"Unknown line in file: " << line );
exit(-1);
}
}
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 */ ||
last_apt_type == "17" /* Heliport */ ) {
// skip building heliports and
// 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,
beacon_list,
tower_list,
windsock_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]");
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,38 @@
// point2d.cxx -- 2d coordinate routines
//
// 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: point2d.cxx,v 1.2 2004-11-19 22:25:49 curt Exp $
//
#include <math.h>
#include "point2d.hxx"
// convert a point from cartesian to polar coordinates
Point3D cart_to_polar_2d(const Point3D& in) {
Point3D result( sqrt(in.x() * in.x() + in.y() * in.y()),
atan2(in.y(), in.x()),
0 );
return result;
}

View file

@ -0,0 +1,39 @@
// point2d.hxx -- define a 2d point class
//
// Written by Curtis Olson, started February 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: point2d.hxx,v 1.4 2004-11-19 22:25:49 curt Exp $
//
#ifndef _POINT2D_HXX
#define _POINT2D_HXX
#include <simgear/math/sg_types.hxx>
#include <Geometry/point3d.hxx>
// convert a point from cartesian to polar coordinates
Point3D cart_to_polar_2d(const Point3D& in);
#endif // _POINT2D_HXX

View file

@ -0,0 +1,117 @@
// poly_extra.cxx -- Extra polygon manipulation routines
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: poly_extra.cxx,v 1.9 2004-11-19 22:25:49 curt Exp $
//
#include <stdio.h>
#include <simgear/compiler.h>
#include <simgear/debug/logstream.hxx>
#include <Geometry/poly_support.hxx>
#include "poly_extra.hxx"
// Divide segment if there are other existing points on it, return the
// new polygon
void add_intermediate_nodes( int contour, const Point3D& start,
const Point3D& end, const TGTriNodes& tmp_nodes,
TGPolygon *result )
{
point_list nodes = tmp_nodes.get_node_list();
// SG_LOG(SG_GENERAL, SG_DEBUG, " add_intermediate_nodes()");
char buf[200];
snprintf(buf, 199, " %.7f %.7f %.7f <=> %.7f %.7f %.7f\n",
start.x(), start.y(), start.z(), end.x(), end.y(), end.z() );
SG_LOG(SG_GENERAL, SG_BULK, buf);
Point3D new_pt;
bool found_extra = find_intermediate_node( start, end, nodes, &new_pt );
if ( found_extra ) {
// recurse with two sub segments
// SG_LOG(SG_GENERAL, SG_DEBUG, "dividing " << p0 << " " << nodes[extra_index]
// << " " << p1);
add_intermediate_nodes( contour, start, new_pt, tmp_nodes,
result );
result->add_node( contour, new_pt );
SG_LOG(SG_GENERAL, SG_BULK, " adding = " << new_pt);
add_intermediate_nodes( contour, new_pt, end, tmp_nodes,
result );
} else {
// this segment does not need to be divided
}
}
// Search each segment for additional vertex points that may have been
// created elsewhere that lie on the segment and split it there to
// avoid "T" intersections.
TGPolygon add_nodes_to_poly( const TGPolygon& poly,
const TGTriNodes& tmp_nodes ) {
int i, j;
TGPolygon result; result.erase();
Point3D p0, p1;
// SG_LOG(SG_GENERAL, SG_DEBUG, "add_nodes_to_poly");
for ( i = 0; i < poly.contours(); ++i ) {
// SG_LOG(SG_GENERAL, SG_DEBUG, "contour = " << i);
for ( j = 0; j < poly.contour_size(i) - 1; ++j ) {
p0 = poly.get_pt( i, j );
p1 = poly.get_pt( i, j + 1 );
// add start of segment
result.add_node( i, p0 );
// add intermediate points
add_intermediate_nodes( i, p0, p1, tmp_nodes, &result );
// end of segment is beginning of next segment
}
p0 = poly.get_pt( i, poly.contour_size(i) - 1 );
p1 = poly.get_pt( i, 0 );
// add start of segment
result.add_node( i, p0 );
// add intermediate points
add_intermediate_nodes( i, p0, p1, tmp_nodes, &result );
// end of segment is beginning of next segment
// 5/9/2000 CLO - this results in duplicating the last point
// of a contour so I have removed this line.
// result.add_node( i, p1 );
// maintain original hole flag setting
result.set_hole_flag( i, poly.get_hole_flag( i ) );
}
return result;
}

View file

@ -0,0 +1,50 @@
// poly_extra.hxx -- Extra polygon manipulation routines
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: poly_extra.hxx,v 1.5 2004-11-19 22:25:49 curt Exp $
//
#ifndef _POLY_EXTRA_HXX
#define _POLY_EXTRA_HXX
#include <Geometry/point3d.hxx>
#include <Geometry/trinodes.hxx>
#include <Polygon/polygon.hxx>
// Divide segment if there are other existing points on it, return the
// new polygon
void add_intermediate_nodes( int contour, const Point3D& start,
const Point3D& end, const TGTriNodes& tmp_nodes,
TGPolygon *result );
// Search each segment for additional vertex points that may have been
// created elsewhere that lie on the segment and split it there to
// avoid "T" intersections.
TGPolygon add_nodes_to_poly( const TGPolygon& poly,
const TGTriNodes& tmp_nodes );
#endif // _POLY_EXTRA_HXX

View file

@ -0,0 +1,73 @@
#!/usr/bin/perl
# this is a sad testament to building your software off of other
# libraries that have bugs (or perhaps less than disired features.)
# Unfortunatley I don't know enough about the functionality they
# provide to go fix them. Maybe someday.
# At any rate. This script is a wrapper around the main airport
# generation utility. It run it until it finishes or crashes. If it
# finishes without saying, yup I'm all done, a crash is assumed. We
# re-run the airport generate from the crash point with a different
# nudge factor in a sorry attempt to work around the bug.
# yes, I know this is a really ugly hack, I apologize in advance to
# those who might have trouble running these tools on non-unix
# platforms, but I'm not sure what else to do at this point. If
# someone can fix the polygon clipping library so it doesn't leave
# tiny shards of polygons or cracks, I'd be very grateful.
# So here we go, children under 13 years of age should probably have
# parental supervision if playing with something this ugly.
# Edit the following values to set up your preferences:
$workdir = "/stage/fgfs04/curt/Work";
$inputfile = "./default.apt";
$binary = "./genapts";
$startid = "";
# end of user configurable section
$done = 0;
$nudge = 0;
while ( ! $done ) {
# update the nudge value
$nudge += 5;
if ( $nudge > 40 ) {
$nudge = 5;
}
# launch the airport generator
$command = "$binary --input=$inputfile --work=$workdir --nudge=$nudge";
if ( $startid ne "" ) {
$command .= " --start-id=$startid";
}
print "Executing $command\n";
open( PIPE, "$command |" ) || die "Cannot run $command\n";
while ( <PIPE> ) {
if ( m/Id portion/ ) {
# print $_;
}
if ( m/\[FINISHED CORRECTLY\]/ ) {
$done = 1;
print "FINISHED!\n";
}
}
close ( PIPE );
if ( ! $done ) {
$startid = `cat last_apt`; chop( $startid );
print "Restarting at $startid.\n";
}
}

View file

@ -0,0 +1,13 @@
#! /bin/bash
# Previously Skipped: EBPP
# Manually removed: NZSP (led to a runway around the world)
# Fixed: YSAR (was marked as land airport, but was a heliport)
WORKDIR=$HOME/workdirs/world_scenery
#APTDAT="/home/martin/GIT/fgdata/Airports/apt.dat.gz"
#APTDAT="/home/rgerlich/rawdata/apt.dat.gz"
APTDAT="/home/rgerlich/rawdata/apt.helidat.gz"
SPAT="--nudge=20"
exec /usr/bin/time genapts --input=$APTDAT --work=$WORKDIR $SPAT > genapts.log 2>&1

View file

@ -0,0 +1,191 @@
// 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/debug/logstream.hxx>
#include <simgear/math/sg_types.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include "runway.hxx"
#include "point2d.hxx"
// 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 )
{
TGPolygon result_list;
double length_hdg = heading_deg;
double left_hdg = length_hdg - 90.0;
if ( left_hdg < 0 ) { left_hdg += 360.0; }
// move to the +l end/center of the runway
Point3D ref = origin;
double lon, lat, r;
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), length_hdg,
length_m / 2.0 - displ2, &lat, &lon, &r );
ref = Point3D( lon, lat, 0.0 );
// move to the l,-w corner (then we add points in a clockwise direction)
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), left_hdg,
-width_m / 2.0, &lat, &lon, &r );
Point3D p = Point3D( lon, lat, 0.0 );
result_list.add_node( 0, p );
// move to the l,w corner
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), left_hdg,
width_m / 2.0, &lat, &lon, &r );
p = Point3D( lon, lat, 0.0 );
result_list.add_node( 0, p );
if ( add_mid ) {
// move to the 0,w point (then we add points in a clockwise direction)
ref = origin;
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), left_hdg,
width_m / 2.0, &lat, &lon, &r );
p = Point3D( lon, lat, 0.0 );
result_list.add_node( 0, p );
}
// move to the -l end/center of the runway
ref = origin;
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), length_hdg,
displ1 - length_m/2.0, &lat, &lon, &r );
ref = Point3D( lon, lat, 0.0 );
// move to the -l,w corner (then we add points in a clockwise direction)
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), left_hdg,
width_m / 2.0, &lat, &lon, &r );
p = Point3D( lon, lat, 0.0 );
result_list.add_node( 0, p );
// move to the -l,-w corner
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), left_hdg,
-width_m / 2.0, &lat, &lon, &r );
p = Point3D( lon, lat, 0.0 );
result_list.add_node( 0, p );
if ( add_mid ) {
// move to the 0,-w point (then we add points in a clockwise direction)
ref = origin;
geo_direct_wgs_84 ( alt_m, ref.lat(), ref.lon(), left_hdg,
-width_m / 2.0, &lat, &lon, &r );
p = Point3D( lon, lat, 0.0 );
result_list.add_node( 0, p );
}
return result_list;
}
// 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 * SG_FEET_TO_METER,
0.0, 0.0,
runway.width*width_scale * SG_FEET_TO_METER,
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 result_list;
Point3D origin(runway.lon, runway.lat, 0);
result_list
= gen_wgs84_area( origin,
runway.length*SG_FEET_TO_METER + 2.0*length_extend,
displ1, displ2,
runway.width*SG_FEET_TO_METER + 2.0*width_extend,
runway.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 ) {
SG_LOG(SG_GENERAL, SG_DEBUG, " " << result_list.get_pt(0, i));
}
return result_list;
}
// 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 result_list;
Point3D origin(runway.lon, runway.lat, 0);
result_list = gen_wgs84_area( origin,
runway.length * SG_FEET_TO_METER
+ 2.0*length_extend_m,
0.0, 0.0,
runway.width * SG_FEET_TO_METER
+ 2.0 * width_extend_m,
runway.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 ) {
SG_LOG(SG_GENERAL, SG_DEBUG, " " << result_list.get_pt(0, i));
}
return result_list;
}

View file

@ -0,0 +1,111 @@
// 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_HXX
#define _RUNWAY_HXX
#include <string>
#include <vector>
#include <Geometry/point3d.hxx>
#include <Polygon/polygon.hxx>
struct TGRunway {
std::string rwy_no;
double lon;
double lat;
double heading;
double length;
double width;
double disp_thresh1;
double disp_thresh2;
double stopway1;
double stopway2;
std::string lighting_flags;
int surface_code;
std::string shoulder_code;
int marking_code;
double smoothness;
bool dist_remaining;
double gs_angle1;
double gs_angle2;
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 really_taxiway;
bool generated;
};
typedef std::vector < TGRunway > runway_list;
typedef runway_list::iterator 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
// 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

View file

@ -0,0 +1,327 @@
// rwy_common.cxx -- Common runway generation routines
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_common.cxx,v 1.12 2004-11-19 22:25:49 curt Exp $
//
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
#include "global.hxx"
#include "poly_extra.hxx"
#include "rwy_common.hxx"
#include <stdlib.h>
using std::string;
void gen_number_block( const TGRunway& rwy_info,
const string& material,
TGPolygon poly, double heading, int num,
double start_pct, double end_pct,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum )
{
char tex1[32]; tex1[0] = '\0';
char tex2[32]; tex2[0] = '\0';
SG_LOG(SG_GENERAL, SG_DEBUG, "Runway num = " << num);
if ( num == 0 ) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Ack! Someone passed in a runway number of '0'" );
exit(-1);
}
if ( num == 11 ) {
sprintf( tex1, "11" );
} else if ( num < 10 ) {
sprintf( tex1, "%dc", num );
} else {
sprintf( tex1, "%dl", num / 10 );
sprintf( tex2, "%dr", num - (num / 10 * 10));
}
// printf("tex1 = '%s' tex2 = '%s'\n", tex1, tex2);
if ( num < 10 ) {
gen_runway_section( rwy_info, poly,
start_pct, end_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
heading,
material, tex1,
rwy_polys, texparams, accum );
} else if ( num == 11 ) {
gen_runway_section( rwy_info, poly,
start_pct, end_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
heading,
material, tex1,
rwy_polys, texparams, accum );
} else {
gen_runway_section( rwy_info, poly,
start_pct, end_pct,
0.0, 0.5,
0.0, 1.0, 0.0, 1.0,
heading,
material, tex1,
rwy_polys, texparams, accum );
gen_runway_section( rwy_info, poly,
start_pct, end_pct,
0.5, 1.0,
0.0, 1.0, 0.0, 1.0,
heading,
material, tex2,
rwy_polys, texparams, accum );
}
}
// generate the runway stopway
void gen_runway_stopway( const TGRunway& rwy_info,
const TGPolygon& runway_a,
const TGPolygon& runway_b,
const string& prefix,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon* accum ) {
const float length = rwy_info.length / 2.0 + 2.0;
double start1_pct = 0.0;
double start2_pct = 0.0;
double end1_pct = 0.0;
double end2_pct = 0.0;
double part_len = 0.0;
int count=0;
int i=0;
if (rwy_info.stopway1 > 0.0) {
/* Generate approach end stopway */
count = (int) (rwy_info.stopway1 * 2.0/ rwy_info.width);
if(count < 1) count = 1;
part_len = rwy_info.stopway1 / (double) count;
for(i=0;i<count;i++)
{
start1_pct=end1_pct;
end1_pct = start1_pct + ( part_len / length );
gen_runway_section( rwy_info,
runway_b,
- end1_pct, -start1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0, //last number is lengthwise
rwy_info.heading + 180.0,
prefix,
"stopway",
rwy_polys,
texparams,
accum);
}
}
if (rwy_info.stopway2 > 0.0) {
/* Generate reciprocal end stopway */
count = (int) (rwy_info.stopway2 * 2.0 / rwy_info.width);
if(count < 1) count = 1;
part_len = rwy_info.stopway2 / (double) count;
for(i=0;i<count;i++)
{
start2_pct=end2_pct;
end2_pct = start2_pct + ( part_len / length );
gen_runway_section( rwy_info,
runway_a,
- end2_pct, -start2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
prefix,
"stopway",
rwy_polys,
texparams,
accum);
}
}
}
// generate a section of runway
void gen_runway_section( const TGRunway& rwy_info,
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 ) {
int j, k;
Point3D a0 = runway.get_pt(0, 1);
Point3D a1 = runway.get_pt(0, 2);
Point3D a2 = runway.get_pt(0, 0);
Point3D a3 = runway.get_pt(0, 3);
if ( startl_pct > 0.0 ) {
startl_pct -= nudge * SG_EPSILON;
}
if ( endl_pct < 1.0 ) {
endl_pct += nudge * SG_EPSILON;
}
if ( endl_pct > 1.0 ) {
endl_pct = 1.0;
}
// partial "w" percentages could introduce "T" intersections which
// we compensate for later, but could still cause problems now
// with our polygon clipping code. This attempts to compensate
// for that by nudging the areas a bit bigger so we don't end up
// with polygon slivers.
if ( startw_pct > 0.0 || endw_pct < 1.0 ) {
if ( startw_pct > 0.0 ) {
startw_pct -= nudge * SG_EPSILON;
}
if ( endw_pct < 1.0 ) {
endw_pct += nudge * SG_EPSILON;
}
}
SG_LOG(SG_GENERAL, SG_DEBUG, "start len % = " << startl_pct
<< " end len % = " << endl_pct);
double dlx, dly;
dlx = a1.x() - a0.x();
dly = a1.y() - a0.y();
Point3D t0 = Point3D( a0.x() + dlx * startl_pct,
a0.y() + dly * startl_pct, 0);
Point3D t1 = Point3D( a0.x() + dlx * endl_pct,
a0.y() + dly * endl_pct, 0);
dlx = a3.x() - a2.x();
dly = a3.y() - a2.y();
Point3D t2 = Point3D( a2.x() + dlx * startl_pct,
a2.y() + dly * startl_pct, 0);
Point3D t3 = Point3D( a2.x() + dlx * endl_pct,
a2.y() + dly * endl_pct, 0);
SG_LOG(SG_GENERAL, SG_DEBUG, "start wid % = " << startw_pct
<< " end wid % = " << endw_pct);
double dwx, dwy;
dwx = t0.x() - t2.x();
dwy = t0.y() - t2.y();
Point3D p0 = Point3D( t2.x() + dwx * startw_pct,
t2.y() + dwy * startw_pct, 0);
Point3D p1 = Point3D( t2.x() + dwx * endw_pct,
t2.y() + dwy * endw_pct, 0);
dwx = t1.x() - t3.x();
dwy = t1.y() - t3.y();
Point3D p2 = Point3D( t3.x() + dwx * startw_pct,
t3.y() + dwy * startw_pct, 0);
Point3D p3 = Point3D( t3.x() + dwx * endw_pct,
t3.y() + dwy * endw_pct, 0);
TGPolygon section;
section.erase();
section.add_node( 0, p2 );
section.add_node( 0, p0 );
section.add_node( 0, p1 );
section.add_node( 0, p3 );
// print runway points
SG_LOG(SG_GENERAL, SG_DEBUG, "pre clipped runway pts " << prefix << material);
for ( j = 0; j < section.contours(); ++j ) {
for ( k = 0; k < section.contour_size( j ); ++k ) {
Point3D p = section.get_pt(j, k);
SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p);
}
}
// Clip the new polygon against what ever has already been created.
TGPolygon clipped = tgPolygonDiff( section, *accum );
// Split long edges to create an object that can better flow with
// the surface terrain
TGPolygon split = tgPolygonSplitLongEdges( clipped, 400.0 );
// Create the final output and push on to the runway super_polygon
// list
TGSuperPoly sp;
sp.erase();
sp.set_poly( split );
sp.set_material( prefix + material );
rwy_polys->push_back( sp );
SG_LOG(SG_GENERAL, SG_DEBUG, "section = " << clipped.contours());
*accum = tgPolygonUnion( section, *accum );
// Store away what we need to know for texture coordinate
// calculation. (CLO 10/20/02: why can't we calculate texture
// coordinates here? Oh, becuase later we need to massage the
// polygons to avoid "T" intersections and clean up other
// potential artifacts and we may add or remove points and need to
// do new texture coordinate calcs later.
// we add 2' to the length for texture overlap. This puts the
// lines on the texture back to the edge of the runway where they
// belong.
double len = rwy_info.length / 2.0 + 2;
double sect_len = len * ( endl_pct - startl_pct );
// we add 2' to both sides of the runway (4' total) for texture
// overlap. This puts the lines on the texture back to the edge
// of the runway where they belong.
double wid = rwy_info.width + 4;
double sect_wid = wid * ( endw_pct - startw_pct );
TGTexParams tp;
tp = TGTexParams( p0,
sect_wid * SG_FEET_TO_METER,
sect_len * SG_FEET_TO_METER,
heading );
tp.set_minu( minu );
tp.set_maxu( maxu );
tp.set_minv( minv );
tp.set_maxv( maxv );
texparams->push_back( tp );
// print runway points
SG_LOG(SG_GENERAL, SG_DEBUG, "clipped runway pts " << prefix + material);
for ( j = 0; j < clipped.contours(); ++j ) {
for ( k = 0; k < clipped.contour_size( j ); ++k ) {
Point3D p = clipped.get_pt(j, k);
SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p);
}
}
}

View file

@ -0,0 +1,67 @@
// rwy_common.hxx -- Common runway generation routines
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_common.hxx,v 1.5 2004-11-19 22:25:49 curt Exp $
//
#ifndef _RWY_COMMON_HXX
#define _RWY_COMMON_HXX
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include "runway.hxx"
#include "texparams.hxx"
void gen_number_block( const TGRunway& rwy_info,
const std::string& material,
TGPolygon poly, double heading, int num,
double start_pct, double end_pct,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum );
// generate the runway stopway
void gen_runway_stopway( const TGRunway& rwy_info,
const TGPolygon& runway_a,
const TGPolygon& runway_b,
const std::string& prefix,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon* accum );
// generate a section of runway
void gen_runway_section( const TGRunway& rwy_info,
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 std::string& prefix,
const std::string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum );
#endif // _RWY_COMMON_HXX

View file

@ -0,0 +1,619 @@
// rwy_prec.cxx -- Build a precision runway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_prec.cxx,v 1.18 2004-11-19 22:25:49 curt Exp $
//
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
#include "rwy_common.hxx"
#include "rwy_nonprec.hxx"
#include <stdlib.h>
using std::string;
// generate a precision approach runway. The routine modifies
// rwy_polys, texparams, and accum. For specific details and
// dimensions of precision runway markings, please refer to FAA
// document AC 150/5340-1H
void gen_precision_rwy( const TGRunway& rwy_info,
double alt_m,
const string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum )
{
SG_LOG( SG_GENERAL, SG_INFO, "Building runway = " << rwy_info.rwy_no );
//
// Generate the basic runway outlines
//
int i;
TGPolygon runway = gen_runway_w_mid( rwy_info, alt_m,
2 * SG_FEET_TO_METER,
2 * SG_FEET_TO_METER );
// runway half "a" (actually the reverse half)
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" (actually the forward half)
TGPolygon runway_b;
runway_b.erase();
runway_b.add_node( 0, runway.get_pt(0, 3) );
runway_b.add_node( 0, runway.get_pt(0, 4) );
runway_b.add_node( 0, runway.get_pt(0, 5) );
runway_b.add_node( 0, runway.get_pt(0, 2) );
Point3D p;
SG_LOG(SG_GENERAL, SG_DEBUG, "raw runway pts (a half)");
for ( i = 0; i < runway_a.contour_size( 0 ); ++i ) {
p = runway_a.get_pt(0, i);
SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p);
}
SG_LOG(SG_GENERAL, SG_DEBUG, "raw runway pts (b half)");
for ( i = 0; i < runway_b.contour_size( 0 ); ++i ) {
p = runway_b.get_pt(0, i);
SG_LOG(SG_GENERAL, SG_DEBUG, " point = " << p);
}
//
// Setup some variables and values to help us chop up the runway
// into its various sections
//
TGSuperPoly sp;
TGTexParams tp;
// we add 2' to the length for texture overlap. This puts the
// lines on the texture back to the edge of the runway where they
// belong.
double length = rwy_info.length / 2.0 + 2.0;
if ( length < 3075 ) {
SG_LOG( SG_GENERAL, SG_ALERT,
"Runway " << rwy_info.rwy_no << " is not long enough ("
<< rwy_info.length << ") for precision markings!");
}
double start1_pct = 0.0;
double start2_pct = 0.0;
double end1_pct = 0.0;
double end2_pct = 0.0;
//
// Displaced threshold if it exists
//
if ( rwy_info.disp_thresh1 > 0.0 ) {
SG_LOG( SG_GENERAL, SG_INFO, "Forward displaced threshold = "
<< rwy_info.disp_thresh1 );
// reserve 90' for final arrows
double thresh = rwy_info.disp_thresh1 - 90.0;
// number of full center arrows
int count = (int)(thresh / 200.0);
// length of starting partial arrow
double part_len = thresh - ( count * 200.0 );
double tex_pct = (200.0 - part_len) / 200.0;
// starting (possibly partial chunk)
start2_pct = end2_pct;
end2_pct = start2_pct + ( part_len / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, tex_pct, 1.0,
rwy_info.heading + 180.0,
material, "dspl_thresh",
rwy_polys, texparams, accum );
// main chunks
for ( i = 0; i < count; ++i ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "dspl_thresh",
rwy_polys, texparams, accum );
}
// final arrows
start2_pct = end2_pct;
end2_pct = start2_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "dspl_arrows",
rwy_polys, texparams, accum );
}
if ( rwy_info.disp_thresh2 > 0.0 ) {
SG_LOG( SG_GENERAL, SG_INFO, "Reverse displaced threshold = "
<< rwy_info.disp_thresh2 );
// reserve 90' for final arrows
double thresh = rwy_info.disp_thresh2 - 90.0;
// number of full center arrows
int count = (int)(thresh / 200.0);
// length of starting partial arrow
double part_len = thresh - ( count * 200.0 );
double tex_pct = (200.0 - part_len) / 200.0;
// starting (possibly partial chunk)
start1_pct = end1_pct;
end1_pct = start1_pct + ( part_len / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, tex_pct, 1.0,
rwy_info.heading,
material, "dspl_thresh",
rwy_polys, texparams, accum );
// main chunks
for ( i = 0; i < count; ++i ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "dspl_thresh",
rwy_polys, texparams, accum );
}
// final arrows
start1_pct = end1_pct;
end1_pct = start1_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "dspl_arrows",
rwy_polys, texparams, accum );
}
//
// Threshold
//
start1_pct = end1_pct;
end1_pct = start1_pct + ( 202.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "threshold",
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 202.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "threshold",
rwy_polys, texparams, accum );
//
// Runway designation letter
//
int len = rwy_info.rwy_no.length();
string letter = "";
string rev_letter = "";
for ( i = 0; i < len; ++i ) {
string tmp = rwy_info.rwy_no.substr(i, 1);
if ( tmp == "L" ) {
letter = "L";
rev_letter = "R";
} else if ( tmp == "R" ) {
letter = "R";
rev_letter = "L";
} else if ( tmp == "C" ) {
letter = "C";
rev_letter = "C";
}
}
SG_LOG(SG_GENERAL, SG_DEBUG, "Runway designation = " << rwy_info.rwy_no);
SG_LOG(SG_GENERAL, SG_DEBUG, "Runway designation letter = " << letter);
if ( !letter.empty() ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, rev_letter,
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, letter,
rwy_polys, texparams, accum );
}
//
// Runway designation number(s)
//
len = rwy_info.rwy_no.length();
string snum = rwy_info.rwy_no;
for ( i = 0; i < len; ++i ) {
string tmp = rwy_info.rwy_no.substr(i, 1);
if ( tmp == "L" || tmp == "R" || tmp == "C" || tmp == " " ) {
snum = rwy_info.rwy_no.substr(0, i);
}
}
SG_LOG(SG_GENERAL, SG_INFO, "Runway num = '" << snum << "'");
int num = atoi( snum.c_str() );
while ( num <= 0 ) {
num += 36;
}
start2_pct = end2_pct;
end2_pct = start2_pct + ( 80.0 / length );
gen_number_block( rwy_info, material, runway_b, rwy_info.heading + 180.0,
num, start2_pct, end2_pct, rwy_polys, texparams, accum );
num += 18;
while ( num > 36 ) {
num -= 36;
}
start1_pct = end1_pct;
end1_pct = start1_pct + ( 80.0 / length );
gen_number_block( rwy_info, material, runway_a, rwy_info.heading,
num, start1_pct, end1_pct, rwy_polys, texparams, accum );
//
// Touch down zone x3
//
start1_pct = end1_pct;
end1_pct = start1_pct + ( 380 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "tz_three",
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 380 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "tz_three",
rwy_polys, texparams, accum );
// add a section of center stripe
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "rest",
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "rest",
rwy_polys, texparams, accum );
//
// Aiming point
//
start1_pct = end1_pct;
end1_pct = start1_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "aim",
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "aim",
rwy_polys, texparams, accum );
//
// Touch down zone x2 (first)
//
if ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "tz_two_a",
rwy_polys, texparams, accum );
}
if ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "tz_two_a",
rwy_polys, texparams, accum );
}
// add a section of center stripe
if ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "rest",
rwy_polys, texparams, accum );
}
if ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "rest",
rwy_polys, texparams, accum );
}
//
// Touch down zone x2 (second)
//
if ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "tz_two_b",
rwy_polys, texparams, accum );
}
if ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "tz_two_b",
rwy_polys, texparams, accum );
}
// add a section of center stripe
if ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "rest",
rwy_polys, texparams, accum );
}
if ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "rest",
rwy_polys, texparams, accum );
}
//
// Touch down zone x1 (first)
//
if ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "tz_one_a",
rwy_polys, texparams, accum );
}
if ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "tz_one_a",
rwy_polys, texparams, accum );
}
// add a section of center stripe
if ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "rest",
rwy_polys, texparams, accum );
}
if ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "rest",
rwy_polys, texparams, accum );
}
//
// Touch down zone x1 (second)
//
if ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "tz_one_b",
rwy_polys, texparams, accum );
}
if ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "tz_one_b",
rwy_polys, texparams, accum );
}
//
// The rest ...
//
// fit the 'rest' texture in as many times as will go evenly into
// the remaining distance so we don't end up with a super short
// section at the end.
double ideal_rest_inc = ( 200.0 / length );
int divs = (int)((1.0 - end1_pct) / ideal_rest_inc) + 1;
double rest1_inc = (1.0 - end1_pct) / divs;
while ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + rest1_inc;
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "rest",
rwy_polys, texparams, accum );
}
ideal_rest_inc = ( 200.0 / length );
divs = (int)((1.0 - end2_pct) / ideal_rest_inc) + 1;
double rest2_inc = (1.0 - end2_pct) / divs;
while ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + rest2_inc;
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "rest",
rwy_polys, texparams, accum );
}
gen_runway_stopway( rwy_info, runway_a, runway_b,
material,
rwy_polys, texparams, accum );
}

View file

@ -0,0 +1,49 @@
// rwy_prec.hxx -- Build a precision runway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_prec.hxx,v 1.5 2004-11-19 22:25:49 curt Exp $
//
#ifndef _RWY_PREC_HXX
#define _RWY_PREC_HXX
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include "runway.hxx"
#include "texparams.hxx"
// generate a precision approach runway. The routine modifies
// rwy_polys, texparams, and accum. For specific details and
// dimensions of precision runway markings, please refer to FAA
// document AC 150/5340-1H
void gen_precision_rwy( const TGRunway& rwy_info,
double alt_m,
const std::string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum );
#endif // _RWY_PREC_HXX

View file

@ -0,0 +1,417 @@
// rwy_nonprec.cxx -- Build a non-precision runway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_nonprec.cxx,v 1.16 2004-11-19 22:25:49 curt Exp $
//
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
#include "rwy_common.hxx"
#include "rwy_nonprec.hxx"
#include <stdlib.h>
using std::string;
// generate a non-precision approach runway. The routine modifies
// rwy_polys, texparams, and accum. For specific details and
// dimensions of precision runway markings, please refer to FAA
// document AC 150/5340-1H
void gen_non_precision_rwy( const TGRunway& rwy_info,
double alt_m,
const string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum )
{
int i, j;
//
// Generate the basic runway outlines
//
TGPolygon runway = gen_runway_w_mid( rwy_info, alt_m,
2 * SG_FEET_TO_METER,
2 * SG_FEET_TO_METER );
// 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, 3) );
runway_b.add_node( 0, runway.get_pt(0, 4) );
runway_b.add_node( 0, runway.get_pt(0, 5) );
runway_b.add_node( 0, runway.get_pt(0, 2) );
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);
}
//
// Setup some variables and values to help us chop up the runway
// into its various sections
//
TGSuperPoly sp;
TGTexParams tp;
// we add 2' to the length for texture overlap. This puts the
// lines on the texture back to the edge of the runway where they
// belong.
double length = rwy_info.length / 2.0 + 2.0;
if ( length < 1150 ) {
SG_LOG(SG_GENERAL, SG_ALERT,
"This runway is not long enough for non-precision markings!");
}
double start1_pct = 0.0;
double start2_pct = 0.0;
double end1_pct = 0.0;
double end2_pct = 0.0;
//
// Displaced threshold if it exists
//
if ( rwy_info.disp_thresh1 > 0.0 ) {
SG_LOG( SG_GENERAL, SG_INFO, "Forward displaced threshold = "
<< rwy_info.disp_thresh1 );
// reserve 90' for final arrows
double thresh = rwy_info.disp_thresh1 - 90.0;
// number of full center arrows
int count = (int)(thresh / 200.0);
// length of starting partial arrow
double part_len = thresh - ( count * 200.0 );
double tex_pct = (200.0 - part_len) / 200.0;
// starting (possibly partial chunk)
start2_pct = end2_pct;
end2_pct = start2_pct + ( part_len / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, tex_pct, 1.0,
rwy_info.heading + 180.0,
material, "dspl_thresh",
rwy_polys, texparams, accum );
// main chunks
for ( i = 0; i < count; ++i ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "dspl_thresh",
rwy_polys, texparams, accum );
}
// final arrows
start2_pct = end2_pct;
end2_pct = start2_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "dspl_arrows",
rwy_polys, texparams, accum );
}
if ( rwy_info.disp_thresh2 > 0.0 ) {
SG_LOG( SG_GENERAL, SG_INFO, "Reverse displaced threshold = "
<< rwy_info.disp_thresh2 );
// reserve 90' for final arrows
double thresh = rwy_info.disp_thresh2 - 90.0;
// number of full center arrows
int count = (int)(thresh / 200.0);
// length of starting partial arrow
double part_len = thresh - ( count * 200.0 );
double tex_pct = (200.0 - part_len) / 200.0;
// starting (possibly partial chunk)
start1_pct = end1_pct;
end1_pct = start1_pct + ( part_len / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, tex_pct, 1.0,
rwy_info.heading,
material, "dspl_thresh",
rwy_polys, texparams, accum );
// main chunks
for ( i = 0; i < count; ++i ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "dspl_thresh",
rwy_polys, texparams, accum );
}
// final arrows
start1_pct = end1_pct;
end1_pct = start1_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "dspl_arrows",
rwy_polys, texparams, accum );
}
//
// Threshold
//
start1_pct = end1_pct;
end1_pct = start1_pct + ( 202.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "threshold",
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 202.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "threshold",
rwy_polys, texparams, accum );
//
// Runway designation letter
//
int len = rwy_info.rwy_no.length();
string letter = "";
string rev_letter = "";
for ( i = 0; i < len; ++i ) {
string tmp = rwy_info.rwy_no.substr(i, 1);
if ( tmp == "L" ) {
letter = "L";
rev_letter = "R";
} else if ( tmp == "R" ) {
letter = "R";
rev_letter = "L";
} else if ( tmp == "C" ) {
letter = "C";
rev_letter = "C";
}
}
SG_LOG(SG_GENERAL, SG_DEBUG, "Runway designation = " << rwy_info.rwy_no);
SG_LOG(SG_GENERAL, SG_DEBUG, "Runway designation letter = " << letter);
if ( !letter.empty() ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, rev_letter,
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, letter,
rwy_polys, texparams, accum );
}
//
// Runway designation number(s)
//
len = rwy_info.rwy_no.length();
string snum = rwy_info.rwy_no;
for ( i = 0; i < len; ++i ) {
string tmp = rwy_info.rwy_no.substr(i, 1);
if ( tmp == "L" || tmp == "R" || tmp == "C" || tmp == " " ) {
snum = rwy_info.rwy_no.substr(0, i);
}
}
SG_LOG(SG_GENERAL, SG_INFO, "Runway num = '" << snum << "'");
int num = atoi( snum.c_str() );
while ( num <= 0 ) {
num += 36;
}
start2_pct = end2_pct;
end2_pct = start2_pct + ( 80.0 / length );
gen_number_block( rwy_info, material, runway_b, rwy_info.heading + 180.0,
num, start2_pct, end2_pct, rwy_polys, texparams, accum );
num += 18;
while ( num > 36 ) {
num -= 36;
}
start1_pct = end1_pct;
end1_pct = start1_pct + ( 80.0 / length );
gen_number_block( rwy_info, material, runway_a, rwy_info.heading,
num, start1_pct, end1_pct, rwy_polys, texparams, accum );
if ( true ) {
//
// Intermediate area before aiming point ...
//
for ( i = 0; i < 3; ++i ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "centerline",
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "centerline",
rwy_polys, texparams, accum );
}
//
// Aiming point
//
if ( end1_pct >= 1.0 ) {
return;
}
start1_pct = end1_pct;
end1_pct = start1_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "aim",
rwy_polys, texparams, accum );
if ( end2_pct >= 1.0 ) {
return;
}
start2_pct = end2_pct;
end2_pct = start2_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "aim",
rwy_polys, texparams, accum );
}
//
// The rest ...
//
// fit the 'rest' texture in as many times as will go evenly into
// the remaining distance so we don't end up with a super short
// section at the end.
double ideal_rest_inc = ( 200.0 / length );
int divs = (int)((1.0 - end1_pct) / ideal_rest_inc) + 1;
double rest1_inc = (1.0 - end1_pct) / divs;
while ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + rest1_inc;
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "rest",
rwy_polys, texparams, accum );
}
ideal_rest_inc = ( 200.0 / length );
divs = (int)((1.0 - end2_pct) / ideal_rest_inc) + 1;
double rest2_inc = (1.0 - end2_pct) / divs;
while ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + rest2_inc;
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "rest",
rwy_polys, texparams, accum );
}
gen_runway_stopway( rwy_info, runway_a, runway_b,
material,
rwy_polys, texparams, accum );
}

View file

@ -0,0 +1,49 @@
// rwy_nonprec.hxx -- Build a non-precision runway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_nonprec.hxx,v 1.5 2004-11-19 22:25:49 curt Exp $
//
#ifndef _RWY_NONPREC_HXX
#define _RWY_NONPREC_HXX
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include "runway.hxx"
#include "texparams.hxx"
// generate a non-precision approach runway. The routine modifies
// rwy_polys, texparams, and accum. For specific details and
// dimensions of precision runway markings, please refer to FAA
// document AC 150/5340-1H
void gen_non_precision_rwy( const TGRunway& rwy_info,
double alt_m,
const std::string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum );
#endif // _RWY_NONPREC_HXX

View file

@ -0,0 +1,139 @@
// rwy_simple.cxx -- Build a simple (non-marked) runway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_simple.cxx,v 1.12 2004-11-19 22:25:49 curt Exp $
//
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
#include "poly_extra.hxx"
#include "rwy_common.hxx"
#include "texparams.hxx"
#include "rwy_nonprec.hxx"
using std::string;
// generate a simple runway. The routine modifies rwy_polys,
// texparams, and accum
void gen_simple_rwy( const TGRunway& rwy_info,
double alt_m,
const string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum )
{
int j, k;
TGPolygon runway = gen_runway_w_mid( rwy_info, 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),
rwy_info.width * SG_FEET_TO_METER,
rwy_info.length * SG_FEET_TO_METER / 2.0,
rwy_info.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),
rwy_info.width * SG_FEET_TO_METER,
rwy_info.length * SG_FEET_TO_METER / 2.0,
rwy_info.heading + 180.0 );
texparams->push_back( tp );
#if 0
// after clip, but before removing T intersections
char tmpa[256], tmpb[256];
sprintf( tmpa, "a%d", i );
sprintf( tmpb, "b%d", i );
write_polygon( clipped_a, tmpa );
write_polygon( clipped_b, tmpb );
#endif
// 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);
}
}
gen_runway_stopway( rwy_info, runway_a, runway_b,
material,
rwy_polys, texparams, accum );
}

View file

@ -0,0 +1,46 @@
// rwy_simple.hxx -- Build a simple (non-marked) runway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_simple.hxx,v 1.5 2004-11-19 22:25:49 curt Exp $
//
#ifndef _RWY_SIMPLE_HXX
#define _RWY_SIMPLE_HXX
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include "runway.hxx"
#include "texparams.hxx"
// generate a simple runway. The routine modifies rwy_polys,
// texparams, and accum
void gen_simple_rwy( const TGRunway& rwy_info,
double alt_m,
const std::string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum );
#endif // _RWY_SIMPLE_HXX

View file

@ -0,0 +1,426 @@
// rwy_visual.cxx -- Build a visual approach runway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_visual.cxx,v 1.18 2004-11-19 22:25:49 curt Exp $
//
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
#include "rwy_common.hxx"
#include "rwy_visual.hxx"
#include <stdlib.h>
using std::string;
// generate a visual approach runway. The routine modifies rwy_polys,
// texparams, and accum. For specific details and dimensions of
// precision runway markings, please refer to FAA document AC
// 150/5340-1H
void gen_visual_rwy( const TGRunway& rwy_info,
double alt_m,
const string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum )
{
int i, j;
//
// Generate the basic runway outlines
//
TGPolygon runway = gen_runway_w_mid( rwy_info, alt_m,
2 * SG_FEET_TO_METER,
2 * SG_FEET_TO_METER );
// 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, 3) );
runway_b.add_node( 0, runway.get_pt(0, 4) );
runway_b.add_node( 0, runway.get_pt(0, 5) );
runway_b.add_node( 0, runway.get_pt(0, 2) );
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);
}
//
// Setup some variables and values to help us chop up the runway
// into its various sections
//
TGSuperPoly sp;
TGTexParams tp;
// we add 2' to the length for texture overlap. This puts the
// lines on the texture back to the edge of the runway where they
// belong.
double length = rwy_info.length / 2.0 + 2.0;
if ( length < 1150 ) {
SG_LOG(SG_GENERAL, SG_ALERT,
"This runway is not long enough for visual markings = "
<< rwy_info.length );
}
double start1_pct = 0.0;
double start2_pct = 0.0;
double end1_pct = 0.0;
double end2_pct = 0.0;
//
// Displaced threshold if it exists
//
if ( rwy_info.disp_thresh1 > 0.0 ) {
SG_LOG( SG_GENERAL, SG_INFO, "Forward displaced threshold = "
<< rwy_info.disp_thresh1 );
// reserve 90' for final arrows
double thresh = rwy_info.disp_thresh1 - 90.0;
// number of full center arrows
int count = (int)(thresh / 200.0);
// length of starting partial arrow
double part_len = thresh - ( count * 200.0 );
double tex_pct = (200.0 - part_len) / 200.0;
// starting (possibly partial chunk)
start2_pct = end2_pct;
end2_pct = start2_pct + ( part_len / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, tex_pct, 1.0,
rwy_info.heading + 180.0,
material, "dspl_thresh",
rwy_polys, texparams, accum );
// main chunks
for ( i = 0; i < count; ++i ) {
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "dspl_thresh",
rwy_polys, texparams, accum );
}
// final arrows
start2_pct = end2_pct;
end2_pct = start2_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "dspl_arrows",
rwy_polys, texparams, accum );
}
if ( rwy_info.disp_thresh2 > 0.0 ) {
SG_LOG( SG_GENERAL, SG_INFO, "Reverse displaced threshold = "
<< rwy_info.disp_thresh2 );
// reserve 90' for final arrows
double thresh = rwy_info.disp_thresh2 - 90.0;
// number of full center arrows
int count = (int)(thresh / 200.0);
// length of starting partial arrow
double part_len = thresh - ( count * 200.0 );
double tex_pct = (200.0 - part_len) / 200.0;
// starting (possibly partial chunk)
start1_pct = end1_pct;
end1_pct = start1_pct + ( part_len / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, tex_pct, 1.0,
rwy_info.heading,
material, "dspl_thresh",
rwy_polys, texparams, accum );
// main chunks
for ( i = 0; i < count; ++i ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "dspl_thresh",
rwy_polys, texparams, accum );
}
// final arrows
start1_pct = end1_pct;
end1_pct = start1_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "dspl_arrows",
rwy_polys, texparams, accum );
}
//
// Threshold
//
// mini threshold
// starting (possibly partial chunk)
start1_pct = end1_pct;
end1_pct = start1_pct + ( 14 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 0.07,
rwy_info.heading,
material, "threshold",
rwy_polys, texparams, accum );
// starting (possibly partial chunk)
start2_pct = end2_pct;
end2_pct = start2_pct + ( 14 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 0.07,
rwy_info.heading + 180.0,
material, "threshold",
rwy_polys, texparams, accum );
//
// Runway designation letter
//
int len = rwy_info.rwy_no.length();
string letter = "";
string rev_letter = "";
for ( i = 0; i < len; ++i ) {
string tmp = rwy_info.rwy_no.substr(i, 1);
if ( tmp == "L" ) {
letter = "L";
rev_letter = "R";
} else if ( tmp == "R" ) {
letter = "R";
rev_letter = "L";
} else if ( tmp == "C" ) {
letter = "C";
rev_letter = "C";
}
}
SG_LOG(SG_GENERAL, SG_DEBUG, "Runway designation = " << rwy_info.rwy_no);
SG_LOG(SG_GENERAL, SG_DEBUG, "Runway designation letter = " << letter);
if ( !letter.empty() ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, rev_letter,
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 90.0 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, letter,
rwy_polys, texparams, accum );
}
//
// Runway designation number(s)
//
len = rwy_info.rwy_no.length();
string snum = rwy_info.rwy_no;
for ( i = 0; i < len; ++i ) {
string tmp = rwy_info.rwy_no.substr(i, 1);
if ( tmp == "L" || tmp == "R" || tmp == "C" || tmp == " " ) {
snum = rwy_info.rwy_no.substr(0, i);
}
}
SG_LOG(SG_GENERAL, SG_DEBUG, "Runway num = '" << snum << "'");
int num = atoi( snum.c_str() );
while ( num <= 0 ) {
num += 36;
}
start2_pct = end2_pct;
end2_pct = start2_pct + ( 80.0 / length );
gen_number_block( rwy_info, material, runway_b, rwy_info.heading + 180.0,
num, start2_pct, end2_pct, rwy_polys, texparams, accum );
num += 18;
while ( num > 36 ) {
num -= 36;
}
start1_pct = end1_pct;
end1_pct = start1_pct + ( 80.0 / length );
gen_number_block( rwy_info, material, runway_a, rwy_info.heading,
num, start1_pct, end1_pct, rwy_polys, texparams, accum );
if ( false ) {
//
// Intermediate area before aiming point ...
//
for ( i = 0; i < 3; ++i ) {
start1_pct = end1_pct;
end1_pct = start1_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "centerline",
rwy_polys, texparams, accum );
start2_pct = end2_pct;
end2_pct = start2_pct + ( 200 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "centerline",
rwy_polys, texparams, accum );
}
//
// Aiming point
//
if ( end1_pct >= 1.0 ) {
return;
}
start1_pct = end1_pct;
end1_pct = start1_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "aim",
rwy_polys, texparams, accum );
if ( end2_pct >= 1.0 ) {
return;
}
start2_pct = end2_pct;
end2_pct = start2_pct + ( 400 / length );
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "aim",
rwy_polys, texparams, accum );
}
//
// The rest ...
//
// fit the 'rest' texture in as many times as will go evenly into
// the remaining distance so we don't end up with a super short
// section at the end.
double ideal_rest_inc = ( 200.0 / length );
int divs = (int)((1.0 - end1_pct) / ideal_rest_inc) + 1;
double rest1_inc = (1.0 - end1_pct) / divs;
while ( end1_pct < 1.0 ) {
start1_pct = end1_pct;
end1_pct = start1_pct + rest1_inc;
SG_LOG(SG_GENERAL, SG_DEBUG, "start1 = " << start1_pct << " end1 = " << end1_pct);
gen_runway_section( rwy_info, runway_a,
start1_pct, end1_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading,
material, "rest",
rwy_polys, texparams, accum );
}
ideal_rest_inc = ( 200.0 / length );
divs = (int)((1.0 - end2_pct) / ideal_rest_inc) + 1;
double rest2_inc = (1.0 - end2_pct) / divs;
while ( end2_pct < 1.0 ) {
start2_pct = end2_pct;
end2_pct = start2_pct + rest2_inc;
gen_runway_section( rwy_info, runway_b,
start2_pct, end2_pct,
0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
rwy_info.heading + 180.0,
material, "rest",
rwy_polys, texparams, accum );
}
gen_runway_stopway( rwy_info, runway_a, runway_b,
material,
rwy_polys, texparams, accum );
}

View file

@ -0,0 +1,49 @@
// rwy_visual.hxx -- Build a visual approach runway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: rwy_visual.hxx,v 1.5 2004-11-19 22:25:49 curt Exp $
//
#ifndef _RWY_VISUAL_HXX
#define _RWY_VISUAL_HXX
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include "runway.hxx"
#include "texparams.hxx"
// generate a visual approach runway. The routine modifies rwy_polys,
// texparams, and accum. For specific details and dimensions of
// precision runway markings, please refer to FAA document AC
// 150/5340-1H
void gen_visual_rwy( const TGRunway& rwy_info,
double alt_m,
const std::string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum );
#endif // _RWY_VISUAL_HXX

View file

@ -0,0 +1,151 @@
// taxiway.cxx -- Build a taxiway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: taxiway.cxx,v 1.13 2004-11-19 22:25:49 curt Exp $
//
#include <simgear/compiler.h>
#include <simgear/constants.h>
#include <simgear/debug/logstream.hxx>
#include "poly_extra.hxx"
#include "rwy_common.hxx"
#include "texparams.hxx"
#include "taxiway.hxx"
using std::string;
// generate a taxiway. The routine modifies rwy_polys, texparams, and
// accum
void gen_taxiway( const TGRunway& rwy_info,
double alt_m,
const string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum )
{
int j, k;
TGPolygon runway = gen_runway_w_mid( rwy_info, 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;
SG_LOG(SG_GENERAL, SG_DEBUG, "len = " << rwy_info.length);
SG_LOG(SG_GENERAL, SG_DEBUG, "width = " << rwy_info.width);
double twid;
if ( rwy_info.width <= 150 ) {
// narrower taxiways are more likely directional
twid = rwy_info.width;
} else {
// wider taxiways are more likely large / non-directional
// concrete areas
twid = 250.0;
}
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 );
sp.set_flag( "taxi" ); // mark as a taxiway
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),
twid * SG_FEET_TO_METER,
250 * SG_FEET_TO_METER,
rwy_info.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,0),
twid * SG_FEET_TO_METER,
250 * SG_FEET_TO_METER,
rwy_info.heading + 180.0 );
texparams->push_back( tp );
#if 0
// after clip, but before removing T intersections
char tmpa[256], tmpb[256];
sprintf( tmpa, "a%d", i );
sprintf( tmpb, "b%d", i );
write_polygon( clipped_a, tmpa );
write_polygon( clipped_b, tmpb );
#endif
// 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);
}
}
}

View file

@ -0,0 +1,46 @@
// taxiway.hxx -- Build a taxiway
//
// Written by Curtis Olson, started February 2002.
//
// Copyright (C) 2002 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: taxiway.hxx,v 1.5 2004-11-19 22:25:49 curt Exp $
//
#ifndef _TAXIWAY_HXX
#define _TAXIWAY_HXX
#include <Polygon/polygon.hxx>
#include <Polygon/superpoly.hxx>
#include "runway.hxx"
#include "texparams.hxx"
// generate a taxiway. The routine modifies rwy_polys, texparams, and
// accum
void gen_taxiway( const TGRunway& rwy_info,
double alt_m,
const std::string& material,
superpoly_list *rwy_polys,
texparams_list *texparams,
TGPolygon *accum );
#endif // _TAXIWAY_HXX

View file

@ -0,0 +1,100 @@
// texparams.hxx -- A simple class to hold texture application
// parameters for sections of the runway
//
// Written by Curtis Olson, started August 2000.
//
// Copyright (C) 2000 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: texparams.hxx,v 1.7 2004-11-19 22:25:49 curt Exp $
#ifndef _TEXPARAMS_HXX
#define _TEXPARAMS_HXX
#ifndef __cplusplus
# error This library requires C++
#endif
#include <simgear/compiler.h>
#include <simgear/math/sg_types.hxx>
#include <vector>
class TGTexParams {
private:
Point3D ref;
double width;
double length;
double heading;
double minu;
double maxu;
double minv;
double maxv;
public:
// Constructor and destructor
inline TGTexParams( void ) { }
inline TGTexParams( const Point3D &r, const double w, const double l,
const double h ) {
ref = r;
width = w;
length = l;
heading = h;
minu = minv = 0.0;
maxu = maxv = 1.0;
}
inline ~TGTexParams( void ) { }
inline Point3D get_ref() const { return ref; }
inline void set_ref( const Point3D &r ) { ref = r; }
inline double get_width() const { return width; }
inline void set_width( const double w ) { width = w; }
inline double get_length() const { return length; }
inline void set_length( const double l ) { length = l; }
inline double get_heading() const { return heading; }
inline void set_heading( const double h ) { heading = h; }
inline double get_minu() const { return minu; }
inline void set_minu( const double x ) { minu = x; }
inline double get_maxu() const { return maxu; }
inline void set_maxu( const double x ) { maxu = x; }
inline double get_minv() const { return minv; }
inline void set_minv( const double x ) { minv = x; }
inline double get_maxv() const { return maxv; }
inline void set_maxv( const double x ) { maxv = x; }
};
typedef std::vector < TGTexParams > texparams_list;
typedef texparams_list::iterator texparams_list_iterator;
typedef texparams_list::const_iterator const_texparams_list_iterator;
#endif // _TEXPARAMS_HXX