1
0
Fork 0

Remove old libs and tools that have better counterparts in GDAL/GRASS nowdays. genapts810 has to go as well

This commit is contained in:
Christian Schmitt 2012-10-11 09:13:11 +02:00
parent 8a092947da
commit a1a331db7c
160 changed files with 3 additions and 33855 deletions

View file

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

View file

@ -1 +0,0 @@
genapts

View file

@ -1,29 +0,0 @@
include_directories(${NEWMAT_INCLUDE_DIR})
add_executable(genapts
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
runway.cxx runway.hxx
rwy_common.cxx rwy_common.hxx
rwy_nonprec.cxx rwy_nonprec.hxx
rwy_prec.cxx rwy_prec.hxx
rwy_simple.cxx rwy_simple.hxx
rwy_visual.cxx rwy_visual.hxx
taxiway.cxx taxiway.hxx
)
target_link_libraries(genapts
Polygon Geometry
Array Output poly2tri
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}
${GDAL_LIBRARY}
${NEWMAT_LIBRARY})
install(TARGETS genapts RUNTIME DESTINATION bin)

View file

@ -1,477 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,148 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,50 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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"
using std::string;
// 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

@ -1,252 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,47 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,282 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,56 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,45 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,44 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <Polygon/texparams.hxx>
#include "runway.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

@ -1,490 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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.02;
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[3];
lat = atof( token[1].c_str() );
lon = atof( token[2].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] == "10" ) {
// 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] == "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

@ -1,38 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,39 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,73 +0,0 @@
#!/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

@ -1,13 +0,0 @@
#! /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

@ -1,191 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,111 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,328 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <Geometry/poly_support.hxx>
#include "global.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 );
section = snap( section, 0.00000001 );
// 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

@ -1,67 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <Polygon/texparams.hxx>
#include "runway.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

@ -1,417 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,49 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <Polygon/texparams.hxx>
#include "runway.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

@ -1,619 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,49 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <Polygon/texparams.hxx>
#include "runway.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

@ -1,137 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 "rwy_common.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

@ -1,46 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <Polygon/texparams.hxx>
#include "runway.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

@ -1,426 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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

@ -1,49 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <Polygon/texparams.hxx>
#include "runway.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

@ -1,153 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <Geometry/poly_support.hxx>
#include "rwy_common.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_a = snap( runway_a, 0.00000001 );
// 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) );
runway_b = snap( runway_b, 0.00000001 );
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

@ -1,46 +0,0 @@
// 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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 <Polygon/texparams.hxx>
#include "runway.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

@ -24,7 +24,7 @@ add_executable(genapts850
target_link_libraries(genapts850
Polygon Geometry
Array Output poly2tri
Array Output
${POCO_FOUNDATION}
${POCO_NET}
${GDAL_LIBRARY}

View file

@ -28,7 +28,7 @@ set_target_properties(tg-construct PROPERTIES
target_link_libraries(tg-construct
Polygon Geometry
Array landcover poly2tri
Array landcover
${GDAL_LIBRARY}
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES}

View file

@ -6,8 +6,4 @@ add_subdirectory(Geometry)
add_subdirectory(HGT)
add_subdirectory(Output)
add_subdirectory(Polygon)
add_subdirectory(e00)
add_subdirectory(landcover)
add_subdirectory(poly2tri)
add_subdirectory(shapelib)
add_subdirectory(vpf)

View file

@ -44,7 +44,6 @@
#include <simgear/structure/exception.hxx>
#include <Geometry/trinodes.hxx>
#include <poly2tri/interface.h>
#include "polygon.hxx"

View file

@ -1 +0,0 @@
teste00

View file

@ -1,12 +0,0 @@
add_library(e00 STATIC
e00.hxx e00.cxx
)
add_executable(teste00 teste00.cxx)
target_link_libraries(teste00
e00
${SIMGEAR_CORE_LIBRARIES}
${SIMGEAR_CORE_LIBRARY_DEPENDENCIES})

View file

@ -1,732 +0,0 @@
// e00.cxx: implementation of ArcInfo (e00) reader.
#include <simgear/compiler.h>
#include "e00.hxx"
#include <vector>
#include <map>
#include <string>
#include <iostream>
#include <cctype>
#include <stdio.h>
#include <stdlib.h>
using std::vector;
using std::map;
using std::string;
using std::istream;
using std::cerr;
using std::endl;
using std::getline;
////////////////////////////////////////////////////////////////////////
// Static helper functions.
////////////////////////////////////////////////////////////////////////
/**
* Append an integer to a string.
*/
static void
strAppend (string &s, int i)
{
char buf[128];
sprintf(buf, "%d", i);
s += buf;
}
#if 0 /* UNUSED */
/**
* Append a double-precision real to a string.
*/
static void
strAppend (string &s, double f)
{
char buf[128];
sprintf(buf, "%f", f);
s += buf;
}
#endif
/**
* Skip newlines.
*
* This function is used only by readIFO. It has to track line
* position because info records must be padded to 80 characters
* (really!) -- another reason to hate E00 format.
*/
static void
skipNewlines (istream &input, int * line_pos)
{
char c;
input.get(c);
// Doesn't seem to be needed.
// while (isspace(c)) {
// input.get(c);
// }
while (c == '\n' || c == '\r') {
input.get(c);
*line_pos = 0;
}
input.putback(c);
}
/**
* Read a fixed-width item from the input stream.
*
* This function is used only by readIFO, where info records follow
* declared widths. It has to track line position and pad up to
* 80 characters where necessary (actually, 79, since the newline
* is excluded); this matters mainly when a string field crosses
* record boundaries, as is common in DCW point coverages.
*/
static void
readItem (istream &input, string &line, int width, int * line_pos)
{
char c;
line.resize(0);
for (int i = 0; i < width; i++) {
input.get(c);
(*line_pos)++;
if (c == '\n' || c == '\r') { // premature termination
(*line_pos)--;
i--;
while (*line_pos < 80 && i < width) {
line += ' ';
(*line_pos)++;
i++;
}
if (*line_pos == 80)
*line_pos = 0;
else
input.putback(c);
} else {
line += c;
}
}
}
/**
* Check that a precision is known, or throw an exception.
*/
static void
checkPrecision (istream &input)
{
int i;
input >> i;
if (i != 2 && i != 3)
throw E00Exception("Unknown precision");
}
/**
* Check that six zeros appear where expected, or throw an exception.
*/
static void
checkZeros (istream &input)
{
int i, j;
for (i = 0; i < 6; i++) {
input >> j;
if (j != 0)
throw E00Exception("Expected -1 followed by six zeros");
}
}
/**
* Check that the expected integer appears, or throw an exception.
*/
static void
expect (istream &input, int i)
{
int in;
input >> in;
if (in != i) {
string message = "Expected ";
strAppend(message, i);
throw E00Exception(message.c_str());
}
}
#if 0 /* UNUSED */
/**
* Check that the expected real number appears, or throw an exception.
*/
static void
expect (istream &input, double f)
{
double in;
input >> in;
if (in != f) {
string message = "Expected ";
strAppend(message, f);
throw E00Exception(message.c_str());
}
}
#endif
/**
* Check that the expected string appears, or throw an exception.
*/
static void
expect (istream &input, const char *s)
{
string in;
input >> in;
if (in != string(s)) {
string message = "Expected ";
message += s;
throw E00Exception(message.c_str());
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of E00
////////////////////////////////////////////////////////////////////////
E00::E00 ()
: _input(0)
{
}
E00::~E00 ()
{
}
////////////////////////////////////////////////////////////////////////
// Reader.
////////////////////////////////////////////////////////////////////////
void
E00::readE00 (istream &input)
{
string token;
_input = &input;
readHeader();
while (!_input->eof()) {
*_input >> token;
cerr << "Reading " << token << " section" << endl;
if (token == "ARC") {
readARC();
} else if (token == "CNT") {
readCNT();
} else if (token == "LAB") {
readLAB();
} else if (token == "LOG") {
readLOG();
} else if (token == "PAL") {
readPAL();
} else if (token == "PRJ") {
readPRJ();
} else if (token == "SIN") {
readSIN();
} else if (token == "TOL") {
readTOL();
} else if (token == "IFO") {
readIFO();
} else if (token == "TX6") {
readTX6();
} else if (token == "TX7") {
readTX7();
} else if (token == "RXP") {
readRXP();
} else if (token == "RPL") {
readRPL();
} else if (token == "EOS") {
postProcess();
return;
} else {
cerr << "Skipping unknown section type " << token << endl;
readUnknown();
}
}
throw E00Exception("File ended without EOS line");
_input = 0;
}
/**
* Read the header of an E00 file.
*/
void
E00::readHeader ()
{
expect(*_input, "EXP");
expect(*_input, 0);
*_input >> pathName;
}
/**
* Read the ARC section of an E00 file.
*/
void
E00::readARC ()
{
ARC arc;
Coord coord;
checkPrecision(*_input);
*_input >> arc.coverageNum;
while (arc.coverageNum != -1) {
*_input >> arc.coverageId;
*_input >> arc.fromNode;
*_input >> arc.toNode;
*_input >> arc.leftPolygon;
*_input >> arc.rightPolygon;
*_input >> arc.numberOfCoordinates;
arc.coordinates.resize(0);
for (int i = 0; i < arc.numberOfCoordinates; i++) {
*_input >> coord.x;
*_input >> coord.y;
arc.coordinates.push_back(coord);
}
arc.in_polygon = false; // we'll check later
arc_section.push_back(arc);
*_input >> arc.coverageNum;
}
checkZeros(*_input);
}
/**
* Read the CNT section of an E00 file.
*/
void
E00::readCNT ()
{
int numLabels;
int label;
checkPrecision(*_input);
*_input >> numLabels;
while (numLabels != -1) {
CNT cnt;
cnt.numLabels = numLabels;
*_input >> cnt.centroid.x;
*_input >> cnt.centroid.y;
for (int i = 0; i < cnt.numLabels; i++) {
*_input >> label;
cnt.labels.push_back(label);
}
cnt_section.push_back(cnt);
*_input >> numLabels;
}
checkZeros(*_input);
}
void
E00::readLAB ()
{
LAB lab;
checkPrecision(*_input);
*_input >> lab.coverageId;
*_input >> lab.enclosingPolygon;
*_input >> lab.coord.x;
*_input >> lab.coord.y;
while (lab.coverageId != -1) {
*_input >> lab.box1.x; // obsolete
*_input >> lab.box1.y; // obsolete
*_input >> lab.box2.x; // obsolete
*_input >> lab.box2.y; // obsolete
lab_section.push_back(lab);
*_input >> lab.coverageId;
*_input >> lab.enclosingPolygon;
*_input >> lab.coord.x;
*_input >> lab.coord.y;
}
}
void
E00::readLOG ()
{
LOG log;
string line;
checkPrecision(*_input);
getline(*_input, line);
while (line.find("EOL") != 0) {
if (line[0] == '~') {
log_section.push_back(log);
log.lines.resize(0);
} else {
log.lines.push_back(line);
}
getline(*_input, line);
}
}
void
E00::readPAL ()
{
PAL pal;
PAL::ARCref arc;
int count = 1;
checkPrecision(*_input);
*_input >> pal.numArcs;
while (pal.numArcs != -1) {
*_input >> pal.min.x;
*_input >> pal.min.y;
*_input >> pal.max.x;
*_input >> pal.max.y;
pal.arcs.resize(0);
for (int i = 0; i < pal.numArcs; i++) {
*_input >> arc.arcNum;
if (count > 1) {
if (arc.arcNum > 0)
_getARC(arc.arcNum).in_polygon = true;
else
_getARC(0-arc.arcNum).in_polygon = true;
}
int num = (arc.arcNum < 0 ? 0 - arc.arcNum : arc.arcNum);
if (num != 0 &&
getARC(num).leftPolygon != count &&
getARC(num).rightPolygon != count) {
cerr << "Polygon " << count << " includes arc " << num
<< " which doesn't reference it" << endl;
}
*_input >> arc.nodeNum;
*_input >> arc.polygonNum;
pal.arcs.push_back(arc);
}
pal_section.push_back(pal);
*_input >> pal.numArcs;
count++;
}
checkZeros(*_input);
}
void
E00::readPRJ ()
{
PRJ prj;
string line;
checkPrecision(*_input);
getline(*_input, line);
while (line.find("EOP") != 0) {
if (line[0] == '~') {
prj_section.push_back(prj);
prj.lines.resize(0);
} else {
prj.lines.push_back(line);
}
getline(*_input, line);
}
}
void
E00::readSIN ()
{
string line;
checkPrecision(*_input);
getline(*_input, line);
while (line.find("EOX") != 0) {
getline(*_input, line);
}
}
void
E00::readTOL ()
{
TOL tol;
checkPrecision(*_input);
*_input >> tol.type;
while (tol.type != -1) {
*_input >> tol.status;
*_input >> tol.value;
tol_section.push_back(tol);
*_input >> tol.type;
}
checkZeros(*_input);
}
void
E00::readTX6 ()
{
string dummy;
*_input >> dummy;
// FIXME: will fail if "JABBERWOCKY" appears
// in the text annotation itself
while (dummy != string("JABBERWOCKY"))
*_input >> dummy;
}
void
E00::readTX7 ()
{
string dummy;
*_input >> dummy;
// FIXME: will fail if "JABBERWOCKY" appears
// in the text annotation itself
while (dummy != string("JABBERWOCKY"))
*_input >> dummy;
}
void
E00::readRXP ()
{
string dummy;
*_input >> dummy;
// FIXME: will fail if "JABBERWOCKY" appears
// in the text annotation itself
while (dummy != string("JABBERWOCKY"))
*_input >> dummy;
}
void
E00::readRPL ()
{
string dummy;
*_input >> dummy;
// FIXME: will fail if "JABBERWOCKY" appears
// in the text annotation itself
while (dummy != string("JABBERWOCKY"))
*_input >> dummy;
}
//
// This method relies heavily on the readItem and skipNewlines
// static functions defined above; it needs to be able to read
// fixed-width fields, padding line length up to 80 where necessary.
//
void
E00::readIFO ()
{
int line_pos = 0;
string line = "";
checkPrecision(*_input);
while (line == "")
*_input >> line;
while (line != string("EOI")) {
int i;
// Start of a new IFO file.
IFO ifo;
IFO::Entry entry;
ifo.fileName = line;
// cout << "Reading IFO file " << line << endl;
// 'XX' may be absent
*_input >> ifo.isArcInfo;
if (ifo.isArcInfo == "XX") {
*_input >> ifo.numItems;
} else {
ifo.numItems = atoi(ifo.isArcInfo.c_str());
ifo.isArcInfo = "";
}
*_input >> ifo.altNumItems;
*_input >> ifo.dataRecordLength;
*_input >> ifo.numDataRecords;
// Read the item definitions
ifo.defs.resize(0);
for (i = 0; i < ifo.numItems; i++) {
IFO::ItemDef def;
*_input >> def.itemName;
*_input >> def.itemWidth;
expect(*_input, -1);
*_input >> def.itemStartPos;
expect(*_input, -1);
def.itemStartPos -= 4;
def.itemStartPos /= 10;
*_input >> def.itemOutputFormat[0];
*_input >> def.itemOutputFormat[1];
*_input >> def.itemType;
expect(*_input, -1);
expect(*_input, -1);
expect(*_input, -1);
*_input >> def.seqId;
ifo.defs.push_back(def);
getline(*_input, line);
}
// Read the data records
ifo.entries.resize(0);
for (i = 0; i < ifo.numDataRecords; i++) {
// cout << " Reading entry " << i << endl;
entry.resize(0);
line_pos = 0;
skipNewlines(*_input, &line_pos);
for (int j = 0; j < ifo.numItems; j++) {
line.resize(0);
string &type = ifo.defs[j].itemType;
if (type == "10-1") { // date
readItem(*_input, line, 8, &line_pos);
}
else if (type == "20-1") { // character field
readItem(*_input, line, ifo.defs[j].itemOutputFormat[0], &line_pos);
}
else if (type == "30-1") { // fixed-width integer
readItem(*_input, line, ifo.defs[j].itemOutputFormat[0], &line_pos);
}
else if (type == "40-1") { // single-precision float
readItem(*_input, line, 14, &line_pos);
}
else if (type == "50-1") { // integer
if (ifo.defs[j].itemWidth == 2) {
readItem(*_input, line, 6, &line_pos);
} else if (ifo.defs[j].itemWidth == 4) {
readItem(*_input, line, 11, &line_pos);
} else {
cerr << "Unexpected width " << ifo.defs[j].itemWidth
<< " for item of type 50-1" << endl;
exit(1);
}
}
else if (type == "60-1") { // real number
if (ifo.defs[j].itemWidth == 4) {
readItem(*_input, line, 14, &line_pos);
} else if (ifo.defs[j].itemWidth == 8) {
readItem(*_input, line, 24, &line_pos);
} else {
cerr << "Unexpected width " << ifo.defs[j].itemWidth
<< " for item of type 60-1" << endl;
exit(1);
}
}
else { // assume integer
cerr << "Unknown IFO item type " << type
<< " assuming integer" << endl;
exit(1);
}
// cout << " Read item " << j << ": '" << line << '\'' << endl;
entry.push_back(line);
}
ifo.entries.push_back(entry);
}
ifo_section.push_back(ifo);
line = "";
while (line == "")
*_input >> line;
}
}
void
E00::readUnknown ()
{
string line;
getline(*_input, line);
while (line.find("EOX") != 0) {
getline(*_input, line);
}
}
void
E00::postProcess ()
{
// TODO
}
////////////////////////////////////////////////////////////////////////
// Other access methods.
////////////////////////////////////////////////////////////////////////
const E00::IFO *
E00::getIFO (const string &fileName) const
{
for (int i = 0; i < (int)ifo_section.size(); i++) {
if (ifo_section[i].fileName == fileName)
return &(ifo_section[i]);
}
return 0;
}
const string *
E00::getIFOItem (const string &fileName, int entry,
const string &itemName) const
{
const IFO * ifo = getIFO(fileName);
if (ifo == 0)
return 0;
int pos = -1;
for (int i = 0; i < (int)ifo->defs.size(); i++) {
if (ifo->defs[i].itemName == itemName)
pos = i;
}
if (pos == -1)
return 0;
return &(ifo->entries[entry-1][pos]);
}
const string *
E00::getIFOItemType (const string &fileName, const string &itemName) const
{
const IFO * ifo = getIFO(fileName);
if (ifo == 0)
return 0;
// int pos = -1;
for (int i = 0; i < (int)ifo->defs.size(); i++) {
if (ifo->defs[i].itemName == itemName)
return &(ifo->defs[i].itemType);
}
return 0;
}
// end of e00.cxx

View file

@ -1,224 +0,0 @@
// e00.hxx - declarations for E00 file processing.
#ifndef __E00_HXX
#define __E00_HXX 1
#include <simgear/compiler.h>
#include <vector>
#include <string>
#include <iostream>
// An exception reading an E00 file.
class E00Exception
{
public:
E00Exception (const std::string &message) : _message(message) {}
virtual const std::string &getMessage () const { return _message; }
private:
std::string _message;
};
// ARCInfo file
class E00 {
public:
//////////////////////////////////////////////////////////////////////
// Data structures for internal use.
//////////////////////////////////////////////////////////////////////
// A coordinate in two-dimensional space.
struct Coord
{
virtual ~Coord () {}
double x;
double y;
};
// Arc co-ordinates and topology.
struct ARC
{
virtual ~ARC () {}
int coverageNum;
int coverageId;
int fromNode;
int toNode;
int leftPolygon;
int rightPolygon;
int numberOfCoordinates;
std::vector<Coord> coordinates;
bool in_polygon;
};
// Polygon Centroid Coordinates
struct CNT
{
virtual ~CNT () {}
int numLabels;
Coord centroid;
std::vector<int> labels;
};
// Label Point Coordinates and Topology
struct LAB
{
virtual ~LAB () {}
int coverageId;
int enclosingPolygon;
Coord coord;
Coord box1; // obsolete
Coord box2; // obsolete
};
// Coverage History
struct LOG
{
virtual ~LOG () {}
std::vector<std::string> lines;
};
// Polygon Topology
struct PAL
{
virtual ~PAL () {}
struct ARCref
{
int arcNum;
int nodeNum;
int polygonNum;
};
int numArcs;
Coord min;
Coord max;
std::vector<ARCref> arcs;
};
// Projection Parameters
struct PRJ
{
virtual ~PRJ () {}
std::vector<std::string> lines;
};
// Tolerance Type
struct TOL
{
virtual ~TOL () {}
int type;
int status;
double value;
};
// Info Files
struct IFO
{
virtual ~IFO () {}
struct ItemDef
{
std::string itemName;
int itemWidth; // followed by -1
int itemStartPos; // followed by 4-1
int itemOutputFormat[2];
std::string itemType;
// -1
// -1-1
std::string seqId;
};
typedef std::vector<std::string> Entry;
std::string fileName;
std::string isArcInfo;
int numItems;
int altNumItems;
int dataRecordLength;
int numDataRecords;
std::vector<ItemDef> defs;
std::vector<Entry> entries;
};
E00 ();
virtual ~E00 ();
virtual void readE00 (std::istream &input);
virtual std::string getPathName () const { return pathName; }
virtual int nPoints () const { return lab_section.size(); }
virtual int nLines () const { return arc_section.size(); }
virtual int nPolygons () const { return pal_section.size(); }
virtual int nInfoFiles () const { return ifo_section.size(); }
virtual const ARC &getARC (int i) const { return arc_section[i-1]; }
virtual const LAB &getLAB (int i) const { return lab_section[i-1]; }
virtual const PAL &getPAL (int i) const { return pal_section[i-1]; }
virtual const IFO &getIFO (int i) const { return ifo_section[i-1]; }
virtual const IFO * getIFO (const std::string &name) const;
virtual const std::string * getIFOItem (const std::string &fileName, int entry,
const std::string &itemName) const;
virtual const std::string * getIFOItemType (const std::string &fileName,
const std::string &itemName) const;
private:
virtual ARC &_getARC (int i) { return arc_section[i-1]; }
std::string pathName;
std::vector<ARC> arc_section;
std::vector<CNT> cnt_section;
std::vector<LAB> lab_section;
std::vector<LOG> log_section;
std::vector<PAL> pal_section;
std::vector<PRJ> prj_section;
std::vector<TOL> tol_section;
std::vector<IFO> ifo_section;
mutable std::istream * _input;
void postProcess ();
void readHeader ();
void readARC ();
void readCNT ();
void readLAB ();
void readLOG ();
void readPAL ();
void readPRJ ();
void readSIN ();
void readTOL ();
void readTX6 ();
void readTX7 ();
void readRXP ();
void readRPL ();
void readIFO ();
void readUnknown ();
};
#endif // __E00_HXX
// end of e00.hxx

View file

@ -1,90 +0,0 @@
// teste00.cxx - test the E00 parsing routines and dump some results.
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <simgear/misc/sgstream.hxx>
#include "e00.hxx"
using std::cerr;
using std::cout;
using std::endl;
int main (int ac, const char ** av)
{
int i, j, k;
for (i = 1; i < ac; i++) {
cerr << "Reading " << av[i] << endl;
sg_gzifstream input(av[i]);
E00 data;
try {
data.readE00(input);
} catch (E00Exception &e) {
cerr << "Reading " << av[i] << " failed with exception "
<< e.getMessage() << endl;
exit(1);
}
cout << "Read " << av[i] << " successfully" << endl;
cout << "Read " << data.nPoints() << " point(s)" << endl;
cout << "Read " << data.nLines() << " line segment(s)" << endl;
cout << "Read " << data.nPolygons() << " polygon(s)" << endl;
cout << " (including enclosing polygon)" << endl;
// for (j = 1; j <= data.nInfoFiles(); j++) {
// const E00::IFO &ifo = data.getIFO(j);
// cout << "IFO file: " << ifo.fileName << endl;
// for (k = 0; k < ifo.numItems; k++) {
// cout << " " << ifo.defs[k].itemName << endl;
// }
// }
// Go over the polygons
cout << "Looking for largest polygon..." << endl;
int maxPolySize = 0;
for (j = 2; j <= data.nPolygons(); j++) {
int size = 0;
const E00::PAL &pal = data.getPAL(j);
for (k = 0; k < pal.numArcs; k++) {
int arcNum = pal.arcs[k].arcNum;
if (arcNum == 0) {
// contour boundary; do nothing
} else if (arcNum < 0) {
const E00::ARC &arc = data.getARC(0-arcNum);
size += arc.numberOfCoordinates;
} else {
const E00::ARC &arc = data.getARC(arcNum);
size += arc.numberOfCoordinates;
}
}
if (size > maxPolySize)
maxPolySize = size;
if (size > 1000) {
cout << "** Large polygon " << j << ": " << size << " points" << endl;
}
}
cout << "Largest polygon (excluding enclosing polygon) has "
<< maxPolySize << " points" << endl;
// Go over the line segments
cout << "Looking for longest line segment..." << endl;
int maxLineSize = 0;
for (j = 1; j <= data.nLines(); j++) {
const E00::ARC &arc = data.getARC(j);
if (arc.numberOfCoordinates > maxLineSize)
maxLineSize = arc.numberOfCoordinates;
}
cout << "Largest line segment (outside of polygon) has "
<< maxLineSize << " points" << endl;
}
return 0;
}
// end of teste00.cxx

View file

@ -1,11 +0,0 @@
add_library(poly2tri STATIC
construct.c
interface.h
misc.c
monotone.c
tri.c
triangulate.h
)

View file

@ -1,96 +0,0 @@
This program is an implementation of a fast polygon
triangulation algorithm based on the paper "A simple and fast
incremental randomized algorithm for computing trapezoidal
decompositions and for triangulating polygons" by Raimund Seidel.
(A copy of the implementation report is available as
http://www.cs.unc.edu/~manocha/CODE/GEM/chapter.html)
The algorithm handles simple polygons with holes. The input is
specified as contours. The outermost contour is anti-clockwise, while
all the inner contours must be clockwise. No point should be repeated
in the input. A sample input file 'data_1' is provided.
The output is a list of triangles. Each triangle gives a pair
(i, j, k) where i, j, and k are indices of the vertices specified in
the input array. (The index numbering starts from 1, since the first
location v[0] in the input array of vertices is unused). The number of
output triangles produced for a polygon with n points is,
(n - 2) + 2*(#holes)
The algorithm also generates a qyery structure which can be
used to answer point-location queries very fast.
int triangulate_polygon(...)
Time for triangulation: O(n log*n)
int is_point_inside_polygon(...)
Time for query : O(log n)
Both the routines are defined in 'tri.c'. See that file for
interfacing details. If not used stand_alone, include the header file
"interface.h" which contains the declarations for these
functions. Inclusion of "triangulation.h" is not necessary.
The implementation uses statically allocated arrays. Choose
appropriate value for SEGSIZE /* in triangulate.h */ depending on
input size.
There sould not be any compilation problem. If log2() is not
defined in your math library, you will have to supply the definition.
USAGE:
triangulate <filename> /* For standalone */
------------------------------------------------------------------
Bibliography:
@article{Sei91,
AUTHOR = "R. Seidel",
TITLE = "A simple and Fast Randomized Algorithm for Computing Trapezoidal Decompositions and for Triangulating Polygons",
JOURNAL = "Computational Geometry Theory \& Applications",
PAGES = "51-64",
NUMBER = 1,
YEAR = 1991,
VOLUME = 1 }
@book{o-cgc-94
, author = "J. O'Rourke"
, title = "Computational Geometry in {C}"
, publisher = "Cambridge University Press"
, year = 1994
, note = "ISBN 0-521-44592-2/Pb \$24.95,
ISBN 0-521-44034-3/Hc \$49.95.
Cambridge University Press
40 West 20th Street
New York, NY 10011-4211
1-800-872-7423
346+xi pages, 228 exercises, 200 figures, 219 references"
, update = "94.05 orourke, 94.01 orourke"
, annote = "Textbook"
}
Implementation report: Narkhede A. and Manocha D., Fast polygon
triangulation algorithm based on Seidel's Algorithm, UNC-CH, 1994.
-------------------------------------------------------------------
UNC-CH GIVES NO WARRANTY, EXPRESSED OR IMPLIED, FOR THE SOFTWARE
AND/OR DOCUMENTATION PROVIDED, INCLUDING, WITHOUT LIMITATION, WARRANTY
OF MERCHANTABILITY AND WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE.
This software is for non-commercial use only.
- Atul Narkhede (narkhede@cs.unc.edu)

View file

@ -1,940 +0,0 @@
#include "triangulate.h"
#include <math.h>
#include <string.h>
#ifdef _MSC_VER
# include <memory.h>
#endif
node_t qs[QSIZE]; /* Query structure */
trap_t tr[TRSIZE]; /* Trapezoid structure */
segment_t seg[SEGSIZE]; /* Segment table */
static int q_idx;
static int tr_idx;
/* Return a new node to be added into the query tree */
static int newnode()
{
if (q_idx < QSIZE)
return q_idx++;
else{
fprintf(stderr, "newnode: Query-table overflow\n");
return -1;
}
}
/* Return a free trapezoid */
static int newtrap()
{
if (tr_idx < TRSIZE) {
tr[tr_idx].lseg = -1;
tr[tr_idx].rseg = -1;
tr[tr_idx].state = ST_VALID;
return tr_idx++;
}else {
fprintf(stderr, "newtrap: Trapezoid-table overflow\n");
return -1;
}
}
/* Return the maximum of the two points into the yval structure */
static int _max(yval, v0, v1)
point_t * yval;
point_t *v0;
point_t *v1;
{
if (v0->y > v1->y + C_EPS)
*yval = *v0;
else if (FP_EQUAL(v0->y, v1->y)) {
if (v0->x > v1->x + C_EPS)
*yval = *v0;
else
*yval = *v1;
}else
*yval = *v1;
return 0;
}
/* Return the minimum of the two points into the yval structure */
static int _min(yval, v0, v1)
point_t * yval;
point_t *v0;
point_t *v1;
{
if (v0->y < v1->y - C_EPS)
*yval = *v0;
else if (FP_EQUAL(v0->y, v1->y)) {
if (v0->x < v1->x)
*yval = *v0;
else
*yval = *v1;
}else
*yval = *v1;
return 0;
}
int _greater_than(v0, v1)
point_t * v0;
point_t *v1;
{
if (v0->y > v1->y + C_EPS)
return TRUE;
else if (v0->y < v1->y - C_EPS)
return FALSE;
else
return v0->x > v1->x;
}
int _equal_to(v0, v1)
point_t * v0;
point_t *v1;
{
return FP_EQUAL(v0->y, v1->y) && FP_EQUAL(v0->x, v1->x);
}
int _greater_than_equal_to(v0, v1)
point_t * v0;
point_t *v1;
{
if (v0->y > v1->y + C_EPS)
return TRUE;
else if (v0->y < v1->y - C_EPS)
return FALSE;
else
return v0->x >= v1->x;
}
int _less_than(v0, v1)
point_t * v0;
point_t *v1;
{
if (v0->y < v1->y - C_EPS)
return TRUE;
else if (v0->y > v1->y + C_EPS)
return FALSE;
else
return v0->x < v1->x;
}
/* Initilialise the query structure (Q) and the trapezoid table (T)
* when the first segment is added to start the trapezoidation. The
* query-tree starts out with 4 trapezoids, one S-node and 2 Y-nodes
*
* 4
* -----------------------------------
* \
* 1 \ 2
* \
* -----------------------------------
* 3
*/
static int init_query_structure(segnum)
int segnum;
{
int i1, i2, i3, i4, i5, i6, i7, root;
int t1, t2, t3, t4;
segment_t *s = &seg[segnum];
q_idx = tr_idx = 1;
memset((void*)tr, 0, sizeof(tr));
memset((void*)qs, 0, sizeof(qs));
i1 = newnode();
qs[i1].nodetype = T_Y;
_max(&qs[i1].yval, &s->v0, &s->v1); /* root */
root = i1;
qs[i1].right = i2 = newnode();
qs[i2].nodetype = T_SINK;
qs[i2].parent = i1;
qs[i1].left = i3 = newnode();
qs[i3].nodetype = T_Y;
_min(&qs[i3].yval, &s->v0, &s->v1); /* root */
qs[i3].parent = i1;
qs[i3].left = i4 = newnode();
qs[i4].nodetype = T_SINK;
qs[i4].parent = i3;
qs[i3].right = i5 = newnode();
qs[i5].nodetype = T_X;
qs[i5].segnum = segnum;
qs[i5].parent = i3;
qs[i5].left = i6 = newnode();
qs[i6].nodetype = T_SINK;
qs[i6].parent = i5;
qs[i5].right = i7 = newnode();
qs[i7].nodetype = T_SINK;
qs[i7].parent = i5;
t1 = newtrap(); /* middle left */
t2 = newtrap(); /* middle right */
t3 = newtrap(); /* bottom-most */
t4 = newtrap(); /* topmost */
tr[t1].hi = tr[t2].hi = tr[t4].lo = qs[i1].yval;
tr[t1].lo = tr[t2].lo = tr[t3].hi = qs[i3].yval;
tr[t4].hi.y = (double)(INFINITY);
tr[t4].hi.x = (double)(INFINITY);
tr[t3].lo.y = (double)-1 * (INFINITY);
tr[t3].lo.x = (double)-1 * (INFINITY);
tr[t1].rseg = tr[t2].lseg = segnum;
tr[t1].u0 = tr[t2].u0 = t4;
tr[t1].d0 = tr[t2].d0 = t3;
tr[t4].d0 = tr[t3].u0 = t1;
tr[t4].d1 = tr[t3].u1 = t2;
tr[t1].sink = i6;
tr[t2].sink = i7;
tr[t3].sink = i4;
tr[t4].sink = i2;
tr[t1].state = tr[t2].state = ST_VALID;
tr[t3].state = tr[t4].state = ST_VALID;
qs[i2].trnum = t4;
qs[i4].trnum = t3;
qs[i6].trnum = t1;
qs[i7].trnum = t2;
s->is_inserted = TRUE;
return root;
}
/* Retun TRUE if the vertex v is to the left of line segment no.
* segnum. Takes care of the degenerate cases when both the vertices
* have the same y--cood, etc.
*/
static int is_left_of(segnum, v)
int segnum;
point_t *v;
{
segment_t *s = &seg[segnum];
double area;
if (_greater_than(&s->v1, &s->v0)) { /* seg. going upwards */
if (FP_EQUAL(s->v1.y, v->y)) {
if (v->x < s->v1.x)
area = 1.0;
else
area = -1.0;
} else if (FP_EQUAL(s->v0.y, v->y)) {
if (v->x < s->v0.x)
area = 1.0;
else
area = -1.0;
} else
area = CROSS(s->v0, s->v1, (*v));
}else { /* v0 > v1 */
if (FP_EQUAL(s->v1.y, v->y)) {
if (v->x < s->v1.x)
area = 1.0;
else
area = -1.0;
} else if (FP_EQUAL(s->v0.y, v->y)) {
if (v->x < s->v0.x)
area = 1.0;
else
area = -1.0;
} else
area = CROSS(s->v1, s->v0, (*v));
}
if (area > 0.0)
return TRUE;
else
return FALSE;
}
/* Returns true if the corresponding endpoint of the given segment is */
/* already inserted into the segment tree. Use the simple test of */
/* whether the segment which shares this endpoint is already inserted */
static int inserted(segnum, whichpt)
int segnum;
int whichpt;
{
if (whichpt == FIRSTPT)
return seg[seg[segnum].prev].is_inserted;
else
return seg[seg[segnum].next].is_inserted;
}
/* This is query routine which determines which trapezoid does the
* point v lie in. The return value is the trapezoid number.
*/
int locate_endpoint(v, vo, r)
point_t * v;
point_t *vo;
int r;
{
node_t *rptr = &qs[r];
switch (rptr->nodetype) {
case T_SINK:
return rptr->trnum;
case T_Y:
if (_greater_than(v, &rptr->yval)) /* above */
return locate_endpoint(v, vo, rptr->right);
else if (_equal_to(v, &rptr->yval)) { /* the point is already */
/* inserted. */
if (_greater_than(vo, &rptr->yval)) /* above */
return locate_endpoint(v, vo, rptr->right);
else
return locate_endpoint(v, vo, rptr->left); /* below */
} else
return locate_endpoint(v, vo, rptr->left); /* below */
case T_X:
if (_equal_to(v, &seg[rptr->segnum].v0) ||
_equal_to(v, &seg[rptr->segnum].v1)) {
if (FP_EQUAL(v->y, vo->y)) { /* horizontal segment */
if (vo->x < v->x)
return locate_endpoint(v, vo, rptr->left); /* left */
else
return locate_endpoint(v, vo, rptr->right); /* right */
}else if (is_left_of(rptr->segnum, vo))
return locate_endpoint(v, vo, rptr->left); /* left */
else
return locate_endpoint(v, vo, rptr->right); /* right */
} else if (is_left_of(rptr->segnum, v))
return locate_endpoint(v, vo, rptr->left); /* left */
else
return locate_endpoint(v, vo, rptr->right); /* right */
default:
fprintf(stderr, "Haggu !!!!!\n");
break;
}
return -1;
}
/* Thread in the segment into the existing trapezoidation. The
* limiting trapezoids are given by tfirst and tlast (which are the
* trapezoids containing the two endpoints of the segment. Merges all
* possible trapezoids which flank this segment and have been recently
* divided because of its insertion
*/
static int merge_trapezoids(segnum, tfirst, tlast, side)
int segnum;
int tfirst;
int tlast;
int side;
{
int t, tnext, cond;
int ptnext;
/* First merge polys on the LHS */
t = tfirst;
while ((t > 0) && _greater_than_equal_to(&tr[t].lo, &tr[tlast].lo)) {
if (side == S_LEFT)
cond = ((((tnext = tr[t].d0) > 0) && (tr[tnext].rseg == segnum)) ||
(((tnext = tr[t].d1) > 0) && (tr[tnext].rseg == segnum)));
else
cond = ((((tnext = tr[t].d0) > 0) && (tr[tnext].lseg == segnum)) ||
(((tnext = tr[t].d1) > 0) && (tr[tnext].lseg == segnum)));
if (cond) {
if ((tr[t].lseg == tr[tnext].lseg) &&
(tr[t].rseg == tr[tnext].rseg)) { /* good neighbours */
/* merge them */
/* Use the upper node as the new node i.e. t */
ptnext = qs[tr[tnext].sink].parent;
if (qs[ptnext].left == tr[tnext].sink)
qs[ptnext].left = tr[t].sink;
else
qs[ptnext].right = tr[t].sink; /* redirect parent */
/* Change the upper neighbours of the lower trapezoids */
if ((tr[t].d0 = tr[tnext].d0) > 0) {
if (tr[tr[t].d0].u0 == tnext)
tr[tr[t].d0].u0 = t;
else if (tr[tr[t].d0].u1 == tnext)
tr[tr[t].d0].u1 = t;
}
if ((tr[t].d1 = tr[tnext].d1) > 0) {
if (tr[tr[t].d1].u0 == tnext)
tr[tr[t].d1].u0 = t;
else if (tr[tr[t].d1].u1 == tnext)
tr[tr[t].d1].u1 = t;
}
tr[t].lo = tr[tnext].lo;
tr[tnext].state = ST_INVALID; /* invalidate the lower */
/* trapezium */
}else /* not good neighbours */
t = tnext;
} else /* do not satisfy the outer if */
t = tnext;
} /* end-while */
return 0;
}
/* Add in the new segment into the trapezoidation and update Q and T
* structures. First locate the two endpoints of the segment in the
* Q-structure. Then start from the topmost trapezoid and go down to
* the lower trapezoid dividing all the trapezoids in between .
*/
static int add_segment(segnum)
int segnum;
{
segment_t s;
int tu, tl, sk, tfirst, tlast;
int tfirstr = -1, tlastr = -1, tfirstl = -1, tlastl = -1;
int i1, i2, t, tn;
point_t tpt;
int tritop = 0, tribot = 0, is_swapped = 0;
int tmptriseg;
s = seg[segnum];
if (_greater_than(&s.v1, &s.v0)) { /* Get higher vertex in v0 */
int tmp;
tpt = s.v0;
s.v0 = s.v1;
s.v1 = tpt;
tmp = s.root0;
s.root0 = s.root1;
s.root1 = tmp;
is_swapped = TRUE;
}
if ((is_swapped) ? !inserted(segnum, LASTPT) :
!inserted(segnum, FIRSTPT)) { /* insert v0 in the tree */
int tmp_d;
tu = locate_endpoint(&s.v0, &s.v1, s.root0);
tl = newtrap(); /* tl is the new lower trapezoid */
tr[tl].state = ST_VALID;
tr[tl] = tr[tu];
tr[tu].lo.y = tr[tl].hi.y = s.v0.y;
tr[tu].lo.x = tr[tl].hi.x = s.v0.x;
tr[tu].d0 = tl;
tr[tu].d1 = 0;
tr[tl].u0 = tu;
tr[tl].u1 = 0;
if (((tmp_d = tr[tl].d0) > 0) && (tr[tmp_d].u0 == tu))
tr[tmp_d].u0 = tl;
if (((tmp_d = tr[tl].d0) > 0) && (tr[tmp_d].u1 == tu))
tr[tmp_d].u1 = tl;
if (((tmp_d = tr[tl].d1) > 0) && (tr[tmp_d].u0 == tu))
tr[tmp_d].u0 = tl;
if (((tmp_d = tr[tl].d1) > 0) && (tr[tmp_d].u1 == tu))
tr[tmp_d].u1 = tl;
/* Now update the query structure and obtain the sinks for the */
/* two trapezoids */
i1 = newnode(); /* Upper trapezoid sink */
i2 = newnode(); /* Lower trapezoid sink */
sk = tr[tu].sink;
qs[sk].nodetype = T_Y;
qs[sk].yval = s.v0;
qs[sk].segnum = segnum; /* not really reqd ... maybe later */
qs[sk].left = i2;
qs[sk].right = i1;
qs[i1].nodetype = T_SINK;
qs[i1].trnum = tu;
qs[i1].parent = sk;
qs[i2].nodetype = T_SINK;
qs[i2].trnum = tl;
qs[i2].parent = sk;
tr[tu].sink = i1;
tr[tl].sink = i2;
tfirst = tl;
}else { /* v0 already present */
/* Get the topmost intersecting trapezoid */
tfirst = locate_endpoint(&s.v0, &s.v1, s.root0);
tritop = 1;
}
if ((is_swapped) ? !inserted(segnum, FIRSTPT) :
!inserted(segnum, LASTPT)) { /* insert v1 in the tree */
int tmp_d;
tu = locate_endpoint(&s.v1, &s.v0, s.root1);
tl = newtrap(); /* tl is the new lower trapezoid */
tr[tl].state = ST_VALID;
tr[tl] = tr[tu];
tr[tu].lo.y = tr[tl].hi.y = s.v1.y;
tr[tu].lo.x = tr[tl].hi.x = s.v1.x;
tr[tu].d0 = tl;
tr[tu].d1 = 0;
tr[tl].u0 = tu;
tr[tl].u1 = 0;
if (((tmp_d = tr[tl].d0) > 0) && (tr[tmp_d].u0 == tu))
tr[tmp_d].u0 = tl;
if (((tmp_d = tr[tl].d0) > 0) && (tr[tmp_d].u1 == tu))
tr[tmp_d].u1 = tl;
if (((tmp_d = tr[tl].d1) > 0) && (tr[tmp_d].u0 == tu))
tr[tmp_d].u0 = tl;
if (((tmp_d = tr[tl].d1) > 0) && (tr[tmp_d].u1 == tu))
tr[tmp_d].u1 = tl;
/* Now update the query structure and obtain the sinks for the */
/* two trapezoids */
i1 = newnode(); /* Upper trapezoid sink */
i2 = newnode(); /* Lower trapezoid sink */
sk = tr[tu].sink;
qs[sk].nodetype = T_Y;
qs[sk].yval = s.v1;
qs[sk].segnum = segnum; /* not really reqd ... maybe later */
qs[sk].left = i2;
qs[sk].right = i1;
qs[i1].nodetype = T_SINK;
qs[i1].trnum = tu;
qs[i1].parent = sk;
qs[i2].nodetype = T_SINK;
qs[i2].trnum = tl;
qs[i2].parent = sk;
tr[tu].sink = i1;
tr[tl].sink = i2;
tlast = tu;
}else { /* v1 already present */
/* Get the lowermost intersecting trapezoid */
tlast = locate_endpoint(&s.v1, &s.v0, s.root1);
tribot = 1;
}
/* Thread the segment into the query tree creating a new X-node */
/* First, split all the trapezoids which are intersected by s into */
/* two */
t = tfirst; /* topmost trapezoid */
while ((t > 0) &&
_greater_than_equal_to(&tr[t].lo, &tr[tlast].lo)) {
/* traverse from top to bot */
int t_sav, tn_sav;
sk = tr[t].sink;
i1 = newnode(); /* left trapezoid sink */
i2 = newnode(); /* right trapezoid sink */
qs[sk].nodetype = T_X;
qs[sk].segnum = segnum;
qs[sk].left = i1;
qs[sk].right = i2;
qs[i1].nodetype = T_SINK; /* left trapezoid (use existing one) */
qs[i1].trnum = t;
qs[i1].parent = sk;
qs[i2].nodetype = T_SINK; /* right trapezoid (allocate new) */
qs[i2].trnum = tn = newtrap();
tr[tn].state = ST_VALID;
qs[i2].parent = sk;
if (t == tfirst)
tfirstr = tn;
if (_equal_to(&tr[t].lo, &tr[tlast].lo))
tlastr = tn;
tr[tn] = tr[t];
tr[t].sink = i1;
tr[tn].sink = i2;
t_sav = t;
tn_sav = tn;
/* error */
if ((tr[t].d0 <= 0) && (tr[t].d1 <= 0)) { /* case cannot arise */
fprintf(stderr, "add_segment: error\n");
break;
}
/* only one trapezoid below. partition t into two and make the */
/* two resulting trapezoids t and tn as the upper neighbours of */
/* the sole lower trapezoid */
else if ((tr[t].d0 > 0) && (tr[t].d1 <= 0)) { /* Only one trapezoid below */
if ((tr[t].u0 > 0) && (tr[t].u1 > 0)) { /* continuation of a chain from abv. */
if (tr[t].usave > 0) { /* three upper neighbours */
if (tr[t].uside == S_LEFT) {
tr[tn].u0 = tr[t].u1;
tr[t].u1 = -1;
tr[tn].u1 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[tn].u0].d0 = tn;
tr[tr[tn].u1].d0 = tn;
}else { /* intersects in the right */
tr[tn].u1 = -1;
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[t].u0;
tr[t].u0 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[t].u1].d0 = t;
tr[tr[tn].u0].d0 = tn;
}
tr[t].usave = tr[tn].usave = 0;
} else{ /* No usave.... simple case */
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d0 = tn;
}
}else { /* fresh seg. or upward cusp */
int tmp_u = tr[t].u0;
int td0, td1;
if (((td0 = tr[tmp_u].d0) > 0) &&
((td1 = tr[tmp_u].d1) > 0)) { /* upward cusp */
if ((tr[td0].rseg > 0) &&
!is_left_of(tr[td0].rseg, &s.v1)) {
tr[t].u0 = tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d1 = tn;
}else { /* cusp going leftwards */
tr[tn].u0 = tr[tn].u1 = tr[t].u1 = -1;
tr[tr[t].u0].d0 = t;
}
} else{ /* fresh segment */
tr[tr[t].u0].d0 = t;
tr[tr[t].u0].d1 = tn;
}
}
if (FP_EQUAL(tr[t].lo.y, tr[tlast].lo.y) &&
FP_EQUAL(tr[t].lo.x, tr[tlast].lo.x) && tribot) { /* bottom forms a triangle */
if (is_swapped)
tmptriseg = seg[segnum].prev;
else
tmptriseg = seg[segnum].next;
if ((tmptriseg > 0) && is_left_of(tmptriseg, &s.v0)) {
/* L-R downward cusp */
tr[tr[t].d0].u0 = t;
tr[tn].d0 = tr[tn].d1 = -1;
} else{
/* R-L downward cusp */
tr[tr[tn].d0].u1 = tn;
tr[t].d0 = tr[t].d1 = -1;
}
}else {
if ((tr[tr[t].d0].u0 > 0) && (tr[tr[t].d0].u1 > 0)) {
if (tr[tr[t].d0].u0 == t) { /* passes thru LHS */
tr[tr[t].d0].usave = tr[tr[t].d0].u1;
tr[tr[t].d0].uside = S_LEFT;
}else {
tr[tr[t].d0].usave = tr[tr[t].d0].u0;
tr[tr[t].d0].uside = S_RIGHT;
}
}
tr[tr[t].d0].u0 = t;
tr[tr[t].d0].u1 = tn;
}
t = tr[t].d0;
} else if ((tr[t].d0 <= 0) && (tr[t].d1 > 0)) { /* Only one trapezoid below */
if ((tr[t].u0 > 0) && (tr[t].u1 > 0)) { /* continuation of a chain from abv. */
if (tr[t].usave > 0) { /* three upper neighbours */
if (tr[t].uside == S_LEFT) {
tr[tn].u0 = tr[t].u1;
tr[t].u1 = -1;
tr[tn].u1 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[tn].u0].d0 = tn;
tr[tr[tn].u1].d0 = tn;
}else { /* intersects in the right */
tr[tn].u1 = -1;
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[t].u0;
tr[t].u0 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[t].u1].d0 = t;
tr[tr[tn].u0].d0 = tn;
}
tr[t].usave = tr[tn].usave = 0;
} else{ /* No usave.... simple case */
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d0 = tn;
}
}else { /* fresh seg. or upward cusp */
int tmp_u = tr[t].u0;
int td0, td1;
if (((td0 = tr[tmp_u].d0) > 0) &&
((td1 = tr[tmp_u].d1) > 0)) { /* upward cusp */
if ((tr[td0].rseg > 0) &&
!is_left_of(tr[td0].rseg, &s.v1)) {
tr[t].u0 = tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d1 = tn;
}else {
tr[tn].u0 = tr[tn].u1 = tr[t].u1 = -1;
tr[tr[t].u0].d0 = t;
}
} else{ /* fresh segment */
tr[tr[t].u0].d0 = t;
tr[tr[t].u0].d1 = tn;
}
}
if (FP_EQUAL(tr[t].lo.y, tr[tlast].lo.y) &&
FP_EQUAL(tr[t].lo.x, tr[tlast].lo.x) && tribot) { /* bottom forms a triangle */
int tmptriseg;
if (is_swapped)
tmptriseg = seg[segnum].prev;
else
tmptriseg = seg[segnum].next;
if ((tmptriseg > 0) && is_left_of(tmptriseg, &s.v0)) {
/* L-R downward cusp */
tr[tr[t].d1].u0 = t;
tr[tn].d0 = tr[tn].d1 = -1;
} else{
/* R-L downward cusp */
tr[tr[tn].d1].u1 = tn;
tr[t].d0 = tr[t].d1 = -1;
}
}else {
if ((tr[tr[t].d1].u0 > 0) && (tr[tr[t].d1].u1 > 0)) {
if (tr[tr[t].d1].u0 == t) { /* passes thru LHS */
tr[tr[t].d1].usave = tr[tr[t].d1].u1;
tr[tr[t].d1].uside = S_LEFT;
}else {
tr[tr[t].d1].usave = tr[tr[t].d1].u0;
tr[tr[t].d1].uside = S_RIGHT;
}
}
tr[tr[t].d1].u0 = t;
tr[tr[t].d1].u1 = tn;
}
t = tr[t].d1;
}
/* two trapezoids below. Find out which one is intersected by */
/* this segment and proceed down that one */
else{
double y0, yt;
point_t tmppt;
int tnext, i_d0, i_d1;
i_d0 = i_d1 = FALSE;
if (FP_EQUAL(tr[t].lo.y, s.v0.y)) {
if (tr[t].lo.x > s.v0.x)
i_d0 = TRUE;
else
i_d1 = TRUE;
}else {
tmppt.y = y0 = tr[t].lo.y;
yt = (y0 - s.v0.y) / (s.v1.y - s.v0.y);
tmppt.x = s.v0.x + yt * (s.v1.x - s.v0.x);
if (_less_than(&tmppt, &tr[t].lo))
i_d0 = TRUE;
else
i_d1 = TRUE;
}
/* check continuity from the top so that the lower-neighbour */
/* values are properly filled for the upper trapezoid */
if ((tr[t].u0 > 0) && (tr[t].u1 > 0)) { /* continuation of a chain from abv. */
if (tr[t].usave > 0) { /* three upper neighbours */
if (tr[t].uside == S_LEFT) {
tr[tn].u0 = tr[t].u1;
tr[t].u1 = -1;
tr[tn].u1 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[tn].u0].d0 = tn;
tr[tr[tn].u1].d0 = tn;
}else { /* intersects in the right */
tr[tn].u1 = -1;
tr[tn].u0 = tr[t].u1;
tr[t].u1 = tr[t].u0;
tr[t].u0 = tr[t].usave;
tr[tr[t].u0].d0 = t;
tr[tr[t].u1].d0 = t;
tr[tr[tn].u0].d0 = tn;
}
tr[t].usave = tr[tn].usave = 0;
} else{ /* No usave.... simple case */
tr[tn].u0 = tr[t].u1;
tr[tn].u1 = -1;
tr[t].u1 = -1;
tr[tr[tn].u0].d0 = tn;
}
}else { /* fresh seg. or upward cusp */
int tmp_u = tr[t].u0;
int td0, td1;
if (((td0 = tr[tmp_u].d0) > 0) &&
((td1 = tr[tmp_u].d1) > 0)) { /* upward cusp */
if ((tr[td0].rseg > 0) &&
!is_left_of(tr[td0].rseg, &s.v1)) {
tr[t].u0 = tr[t].u1 = tr[tn].u1 = -1;
tr[tr[tn].u0].d1 = tn;
}else {
tr[tn].u0 = tr[tn].u1 = tr[t].u1 = -1;
tr[tr[t].u0].d0 = t;
}
} else{ /* fresh segment */
tr[tr[t].u0].d0 = t;
tr[tr[t].u0].d1 = tn;
}
}
if (FP_EQUAL(tr[t].lo.y, tr[tlast].lo.y) &&
FP_EQUAL(tr[t].lo.x, tr[tlast].lo.x) && tribot) {
/* this case arises only at the lowest trapezoid.. i.e.
tlast, if the lower endpoint of the segment is
already inserted in the structure */
tr[tr[t].d0].u0 = t;
tr[tr[t].d0].u1 = -1;
tr[tr[t].d1].u0 = tn;
tr[tr[t].d1].u1 = -1;
tr[tn].d0 = tr[t].d1;
tr[t].d1 = tr[tn].d1 = -1;
tnext = tr[t].d1;
}else if (i_d0) {
/* intersecting d0 */
tr[tr[t].d0].u0 = t;
tr[tr[t].d0].u1 = tn;
tr[tr[t].d1].u0 = tn;
tr[tr[t].d1].u1 = -1;
/* new code to determine the bottom neighbours of the */
/* newly partitioned trapezoid */
tr[t].d1 = -1;
tnext = tr[t].d0;
}else { /* intersecting d1 */
tr[tr[t].d0].u0 = t;
tr[tr[t].d0].u1 = -1;
tr[tr[t].d1].u0 = t;
tr[tr[t].d1].u1 = tn;
/* new code to determine the bottom neighbours of the */
/* newly partitioned trapezoid */
tr[tn].d0 = tr[t].d1;
tr[tn].d1 = -1;
tnext = tr[t].d1;
}
t = tnext;
}
tr[t_sav].rseg = tr[tn_sav].lseg = segnum;
} /* end-while */
/* Now combine those trapezoids which share common segments. We can */
/* use the pointers to the parent to connect these together. This */
/* works only because all these new trapezoids have been formed */
/* due to splitting by the segment, and hence have only one parent */
tfirstl = tfirst;
tlastl = tlast;
merge_trapezoids(segnum, tfirstl, tlastl, S_LEFT);
merge_trapezoids(segnum, tfirstr, tlastr, S_RIGHT);
seg[segnum].is_inserted = TRUE;
return 0;
}
/* Update the roots stored for each of the endpoints of the segment.
* This is done to speed up the location-query for the endpoint when
* the segment is inserted into the trapezoidation subsequently
*/
static int find_new_roots(segnum)
int segnum;
{
segment_t *s = &seg[segnum];
if (s->is_inserted)
return 0;
s->root0 = locate_endpoint(&s->v0, &s->v1, s->root0);
s->root0 = tr[s->root0].sink;
s->root1 = locate_endpoint(&s->v1, &s->v0, s->root1);
s->root1 = tr[s->root1].sink;
return 0;
}
/* Main routine to perform trapezoidation */
int construct_trapezoids(nseg)
int nseg;
{
register int i;
int root, h;
/* Add the first segment and get the query structure and trapezoid */
/* list initialised */
root = init_query_structure(choose_segment());
for (i = 1; i <= nseg; i++)
seg[i].root0 = seg[i].root1 = root;
for (h = 1; h <= math_logstar_n(nseg); h++) {
for (i = math_N(nseg, h - 1) + 1; i <= math_N(nseg, h); i++)
add_segment(choose_segment());
/* Find a new root for each of the segment endpoints */
for (i = 1; i <= nseg; i++)
find_new_roots(i);
}
for (i = math_N(nseg, math_logstar_n(nseg)) + 1; i <= nseg; i++)
add_segment(choose_segment());
return 0;
}

View file

@ -1,24 +0,0 @@
4
4
0.0 0.0
6.0 0.0
6.0 6.0
0.0 6.0
3
0.5 1.0
1.0 2.0
2.0 1.5
3
0.5 4.0
1.0 5.0
2.0 4.5
3
3.0 3.0
5.0 3.5
5.0 2.5

View file

@ -1,18 +0,0 @@
#ifndef __interface_h
#define __interface_h
#define TRUE 1
#define FALSE 0
#if defined ( __cplusplus )
extern "C" {
#endif
extern int triangulate_polygon(int, int *, double (*)[2], int (*)[3]);
extern int is_point_inside_polygon(double *);
#if defined ( __cplusplus )
}
#endif
#endif /* __interface_h */

View file

@ -1,29 +0,0 @@
inclpath = .
CC=gcc
CFLAGS= -UDEBUG -DSTANDALONE -UCLOCK\
-I$(inclpath) -L/lib/pa1.1 -g
# DEBUG: turn on debugging output
#
# STANDALONE: run as a separate program. read data from file.
# If this flag is False, then use the interface procedure
# triangulate_polygon() instead.
LDFLAGS= -lm
objects= construct.o misc.o monotone.o tri.o
executable = triangulate
$(executable): $(objects)
rm -f $(executable)
$(CC) $(CFLAGS) $(objects) $(LDFLAGS) -o $(executable)
$(objects): $(inclpath)/triangulate.h
clean:
rm -f $(objects)

View file

@ -1,174 +0,0 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include "triangulate.h"
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
#else
# include <time.h>
#endif
#include <math.h>
#if defined( __CYGWIN__ ) || defined( __CYGWIN32__ )
#define lrand48() rand()
#define srand48(x) srand(x)
#endif
static int choose_idx;
static int permute[SEGSIZE];
/* Generate a random permutation of the segments 1..n */
int generate_random_ordering(n)
int n;
{
register int i;
int m, st[SEGSIZE], *p;
#ifdef _MSC_VER
time_t ltime;
time( &ltime );
srand( ltime );
#else
struct timeval tval;
struct timezone tzone;
choose_idx = 1;
gettimeofday(&tval, &tzone);
srand48(tval.tv_sec);
#endif
for (i = 0; i <= n; i++)
st[i] = i;
p = st;
for (i = 1; i <= n; i++, p++)
{
#ifdef _MSC_VER
m = rand() % ( n + 1 - i ) + 1;
#else
m = lrand48() % ( n + 1 - i ) + 1;
#endif
permute[i] = p[m];
if (m != 1)
p[m] = p[1];
}
return 0;
}
/* Return the next segment in the generated random ordering of all the */
/* segments in S */
int choose_segment()
{
#ifdef DEBUG
fprintf(stderr, "choose_segment: %d\n", permute[choose_idx]);
#endif
return permute[choose_idx++];
}
#ifdef STANDALONE
/* Read in the list of vertices from infile */
int read_segments(filename, genus)
char *filename;
int *genus;
{
FILE *infile;
int ccount;
register int i;
int ncontours, npoints, first, last;
if ((infile = fopen(filename, "r")) == NULL)
{
perror(filename);
return -1;
}
fscanf(infile, "%d", &ncontours);
if (ncontours <= 0)
return -1;
/* For every contour, read in all the points for the contour. The */
/* outer-most contour is read in first (points specified in */
/* anti-clockwise order). Next, the inner contours are input in */
/* clockwise order */
ccount = 0;
i = 1;
while (ccount < ncontours)
{
int j;
fscanf(infile, "%d", &npoints);
first = i;
last = first + npoints - 1;
for (j = 0; j < npoints; j++, i++)
{
fscanf(infile, "%lf%lf", &seg[i].v0.x, &seg[i].v0.y);
if (i == last)
{
seg[i].next = first;
seg[i].prev = i-1;
seg[i-1].v1 = seg[i].v0;
}
else if (i == first)
{
seg[i].next = i+1;
seg[i].prev = last;
seg[last].v1 = seg[i].v0;
}
else
{
seg[i].prev = i-1;
seg[i].next = i+1;
seg[i-1].v1 = seg[i].v0;
}
seg[i].is_inserted = FALSE;
}
ccount++;
}
*genus = ncontours - 1;
return i-1;
}
#endif
/* Get log*n for given n */
int math_logstar_n(n)
int n;
{
register int i;
double v;
for (i = 0, v = (double) n; v >= 1; i++) {
/* v = log2(v); */
v = log(v) / log(2.0);
}
return (i - 1);
}
int math_N(n, h)
int n;
int h;
{
register int i;
double v;
for (i = 0, v = (int) n; i < h; i++) {
/* v = log2(v); */
v = log(v) / log(2.0);
}
return (int) ceil((double) 1.0*n/v);
}

View file

@ -1,741 +0,0 @@
#include "triangulate.h"
#include <math.h>
#include <string.h>
#ifdef _MSC_VER
# include <memory.h>
#endif
#define CROSS_SINE(v0, v1) ((v0).x * (v1).y - (v1).x * (v0).y)
#define LENGTH(v0) (sqrt((v0).x * (v0).x + (v0).y * (v0).y))
static monchain_t mchain[TRSIZE]; /* Table to hold all the monotone */
/* polygons . Each monotone polygon */
/* is a circularly linked list */
static vertexchain_t vert[SEGSIZE]; /* chain init. information. This */
/* is used to decide which */
/* monotone polygon to split if */
/* there are several other */
/* polygons touching at the same */
/* vertex */
static int mon[SEGSIZE]; /* contains position of any vertex in */
/* the monotone chain for the polygon */
static int visited[TRSIZE];
static int chain_idx, op_idx, mon_idx;
static int triangulate_single_polygon(int, int, int, int (*)[3]);
static int traverse_polygon(int, int, int, int);
/* Function returns TRUE if the trapezoid lies inside the polygon */
static int inside_polygon(t)
trap_t *t;
{
int rseg = t->rseg;
if (t->state == ST_INVALID)
return 0;
if ((t->lseg <= 0) || (t->rseg <= 0))
return 0;
if (((t->u0 <= 0) && (t->u1 <= 0)) ||
((t->d0 <= 0) && (t->d1 <= 0))) /* triangle */
return (_greater_than(&seg[rseg].v1, &seg[rseg].v0));
return 0;
}
/* return a new mon structure from the table */
static int newmon()
{
return ++mon_idx;
}
/* return a new chain element from the table */
static int new_chain_element()
{
return ++chain_idx;
}
static double get_angle(vp0, vpnext, vp1)
point_t *vp0;
point_t *vpnext;
point_t *vp1;
{
point_t v0, v1;
v0.x = vpnext->x - vp0->x;
v0.y = vpnext->y - vp0->y;
v1.x = vp1->x - vp0->x;
v1.y = vp1->y - vp0->y;
if (CROSS_SINE(v0, v1) >= 0) /* sine is positive */
return DOT(v0, v1)/LENGTH(v0)/LENGTH(v1);
else
return (-1.0 * DOT(v0, v1)/LENGTH(v0)/LENGTH(v1) - 2);
}
/* (v0, v1) is the new diagonal to be added to the polygon. Find which */
/* chain to use and return the positions of v0 and v1 in p and q */
static int get_vertex_positions(v0, v1, ip, iq)
int v0;
int v1;
int *ip;
int *iq;
{
vertexchain_t *vp0, *vp1;
register int i;
double angle, temp;
int tp, tq;
vp0 = &vert[v0];
vp1 = &vert[v1];
/* p is identified as follows. Scan from (v0, v1) rightwards till */
/* you hit the first segment starting from v0. That chain is the */
/* chain of our interest */
angle = -4.0;
for (i = 0; i < 4; i++)
{
if (vp0->vnext[i] <= 0)
continue;
if ((temp = get_angle(&vp0->pt, &(vert[vp0->vnext[i]].pt),
&vp1->pt)) > angle)
{
angle = temp;
tp = i;
}
}
*ip = tp;
/* Do similar actions for q */
angle = -4.0;
for (i = 0; i < 4; i++)
{
if (vp1->vnext[i] <= 0)
continue;
if ((temp = get_angle(&vp1->pt, &(vert[vp1->vnext[i]].pt),
&vp0->pt)) > angle)
{
angle = temp;
tq = i;
}
}
*iq = tq;
return 0;
}
/* v0 and v1 are specified in anti-clockwise order with respect to
* the current monotone polygon mcur. Split the current polygon into
* two polygons using the diagonal (v0, v1)
*/
static int make_new_monotone_poly(mcur, v0, v1)
int mcur;
int v0;
int v1;
{
int p, q, ip, iq;
int mnew = newmon();
int i, j, nf0, nf1;
vertexchain_t *vp0, *vp1;
vp0 = &vert[v0];
vp1 = &vert[v1];
get_vertex_positions(v0, v1, &ip, &iq);
p = vp0->vpos[ip];
q = vp1->vpos[iq];
/* At this stage, we have got the positions of v0 and v1 in the */
/* desired chain. Now modify the linked lists */
i = new_chain_element(); /* for the new list */
j = new_chain_element();
mchain[i].vnum = v0;
mchain[j].vnum = v1;
mchain[i].next = mchain[p].next;
mchain[mchain[p].next].prev = i;
mchain[i].prev = j;
mchain[j].next = i;
mchain[j].prev = mchain[q].prev;
mchain[mchain[q].prev].next = j;
mchain[p].next = q;
mchain[q].prev = p;
nf0 = vp0->nextfree;
nf1 = vp1->nextfree;
vp0->vnext[ip] = v1;
vp0->vpos[nf0] = i;
vp0->vnext[nf0] = mchain[mchain[i].next].vnum;
vp1->vpos[nf1] = j;
vp1->vnext[nf1] = v0;
vp0->nextfree++;
vp1->nextfree++;
#ifdef DEBUG
fprintf(stderr, "make_poly: mcur = %d, (v0, v1) = (%d, %d)\n",
mcur, v0, v1);
fprintf(stderr, "next posns = (p, q) = (%d, %d)\n", p, q);
#endif
mon[mcur] = p;
mon[mnew] = i;
return mnew;
}
/* Main routine to get monotone polygons from the trapezoidation of
* the polygon.
*/
int monotonate_trapezoids(n)
int n;
{
register int i;
int tr_start;
memset((void *)vert, 0, sizeof(vert));
memset((void *)visited, 0, sizeof(visited));
memset((void *)mchain, 0, sizeof(mchain));
memset((void *)mon, 0, sizeof(mon));
/* First locate a trapezoid which lies inside the polygon */
/* and which is triangular */
for (i = 0; i < TRSIZE; i++)
if (inside_polygon(&tr[i]))
break;
tr_start = i;
/* Initialise the mon data-structure and start spanning all the */
/* trapezoids within the polygon */
#if 0
for (i = 1; i <= n; i++)
{
mchain[i].prev = i - 1;
mchain[i].next = i + 1;
mchain[i].vnum = i;
vert[i].pt = seg[i].v0;
vert[i].vnext[0] = i + 1; /* next vertex */
vert[i].vpos[0] = i; /* locn. of next vertex */
vert[i].nextfree = 1;
}
mchain[1].prev = n;
mchain[n].next = 1;
vert[n].vnext[0] = 1;
vert[n].vpos[0] = n;
chain_idx = n;
mon_idx = 0;
mon[0] = 1; /* position of any vertex in the first */
/* chain */
#else
for (i = 1; i <= n; i++)
{
mchain[i].prev = seg[i].prev;
mchain[i].next = seg[i].next;
mchain[i].vnum = i;
vert[i].pt = seg[i].v0;
vert[i].vnext[0] = seg[i].next; /* next vertex */
vert[i].vpos[0] = i; /* locn. of next vertex */
vert[i].nextfree = 1;
}
chain_idx = n;
mon_idx = 0;
mon[0] = 1; /* position of any vertex in the first */
/* chain */
#endif
/* traverse the polygon */
if (tr[tr_start].u0 > 0)
traverse_polygon(0, tr_start, tr[tr_start].u0, TR_FROM_UP);
else if (tr[tr_start].d0 > 0)
traverse_polygon(0, tr_start, tr[tr_start].d0, TR_FROM_DN);
/* return the number of polygons created */
return newmon();
}
/* recursively visit all the trapezoids */
static int traverse_polygon(mcur, trnum, from, dir)
int mcur;
int trnum;
int from;
int dir;
{
trap_t *t = &tr[trnum];
int mnew;
int v0, v1;
int retval = 0;
int do_switch = FALSE;
if ((trnum <= 0) || visited[trnum])
return 0;
visited[trnum] = TRUE;
/* We have much more information available here. */
/* rseg: goes upwards */
/* lseg: goes downwards */
/* Initially assume that dir = TR_FROM_DN (from the left) */
/* Switch v0 and v1 if necessary afterwards */
/* special cases for triangles with cusps at the opposite ends. */
/* take care of this first */
if ((t->u0 <= 0) && (t->u1 <= 0))
{
if ((t->d0 > 0) && (t->d1 > 0)) /* downward opening triangle */
{
v0 = tr[t->d1].lseg;
v1 = t->lseg;
if (from == t->d1)
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
}
else
{
retval = SP_NOSPLIT; /* Just traverse all neighbours */
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
}
}
else if ((t->d0 <= 0) && (t->d1 <= 0))
{
if ((t->u0 > 0) && (t->u1 > 0)) /* upward opening triangle */
{
v0 = t->rseg;
v1 = tr[t->u0].rseg;
if (from == t->u1)
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
}
}
else
{
retval = SP_NOSPLIT; /* Just traverse all neighbours */
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
}
}
else if ((t->u0 > 0) && (t->u1 > 0))
{
if ((t->d0 > 0) && (t->d1 > 0)) /* downward + upward cusps */
{
v0 = tr[t->d1].lseg;
v1 = tr[t->u0].rseg;
retval = SP_2UP_2DN;
if (((dir == TR_FROM_DN) && (t->d1 == from)) ||
((dir == TR_FROM_UP) && (t->u1 == from)))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
}
else /* only downward cusp */
{
if (_equal_to(&t->lo, &seg[t->lseg].v1))
{
v0 = tr[t->u0].rseg;
v1 = seg[t->lseg].next;
retval = SP_2UP_LEFT;
if ((dir == TR_FROM_UP) && (t->u0 == from))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
}
}
else
{
v0 = t->rseg;
v1 = tr[t->u0].rseg;
retval = SP_2UP_RIGHT;
if ((dir == TR_FROM_UP) && (t->u1 == from))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
}
}
}
}
else if ((t->u0 > 0) || (t->u1 > 0)) /* no downward cusp */
{
if ((t->d0 > 0) && (t->d1 > 0)) /* only upward cusp */
{
if (_equal_to(&t->hi, &seg[t->lseg].v0))
{
v0 = tr[t->d1].lseg;
v1 = t->lseg;
retval = SP_2DN_LEFT;
if (!((dir == TR_FROM_DN) && (t->d0 == from)))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
}
else
{
v0 = tr[t->d1].lseg;
v1 = seg[t->rseg].next;
retval = SP_2DN_RIGHT;
if ((dir == TR_FROM_DN) && (t->d1 == from))
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
}
}
}
else /* no cusp */
{
if (_equal_to(&t->hi, &seg[t->lseg].v0) &&
_equal_to(&t->lo, &seg[t->rseg].v0))
{
v0 = t->rseg;
v1 = t->lseg;
retval = SP_SIMPLE_LRDN;
if (dir == TR_FROM_UP)
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
}
}
else if (_equal_to(&t->hi, &seg[t->rseg].v1) &&
_equal_to(&t->lo, &seg[t->lseg].v1))
{
v0 = seg[t->rseg].next;
v1 = seg[t->lseg].next;
retval = SP_SIMPLE_LRUP;
if (dir == TR_FROM_UP)
{
do_switch = TRUE;
mnew = make_new_monotone_poly(mcur, v1, v0);
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->d0, trnum, TR_FROM_UP);
}
else
{
mnew = make_new_monotone_poly(mcur, v0, v1);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mnew, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mnew, t->u1, trnum, TR_FROM_DN);
}
}
else /* no split possible */
{
retval = SP_NOSPLIT;
traverse_polygon(mcur, t->u0, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d0, trnum, TR_FROM_UP);
traverse_polygon(mcur, t->u1, trnum, TR_FROM_DN);
traverse_polygon(mcur, t->d1, trnum, TR_FROM_UP);
}
}
}
return retval;
}
/* For each monotone polygon, find the ymax and ymin (to determine the */
/* two y-monotone chains) and pass on this monotone polygon for greedy */
/* triangulation. */
/* Take care not to triangulate duplicate monotone polygons */
int triangulate_monotone_polygons(nvert, nmonpoly, op)
int nvert;
int nmonpoly;
int op[][3];
{
register int i;
point_t ymax, ymin;
int p, vfirst, posmax, posmin, v;
int vcount, processed;
#ifdef DEBUG
for (i = 0; i < nmonpoly; i++)
{
fprintf(stderr, "\n\nPolygon %d: ", i);
vfirst = mchain[mon[i]].vnum;
p = mchain[mon[i]].next;
fprintf (stderr, "%d ", mchain[mon[i]].vnum);
while (mchain[p].vnum != vfirst)
{
fprintf(stderr, "%d ", mchain[p].vnum);
p = mchain[p].next;
}
}
fprintf(stderr, "\n");
#endif
op_idx = 0;
for (i = 0; i < nmonpoly; i++)
{
vcount = 1;
processed = FALSE;
vfirst = mchain[mon[i]].vnum;
ymax = ymin = vert[vfirst].pt;
posmax = posmin = mon[i];
mchain[mon[i]].marked = TRUE;
p = mchain[mon[i]].next;
while ((v = mchain[p].vnum) != vfirst)
{
if (mchain[p].marked)
{
processed = TRUE;
break; /* break from while */
}
else
mchain[p].marked = TRUE;
if (_greater_than(&vert[v].pt, &ymax))
{
ymax = vert[v].pt;
posmax = p;
}
if (_less_than(&vert[v].pt, &ymin))
{
ymin = vert[v].pt;
posmin = p;
}
p = mchain[p].next;
vcount++;
}
if (processed) /* Go to next polygon */
continue;
if (vcount == 3) /* already a triangle */
{
op[op_idx][0] = mchain[p].vnum;
op[op_idx][1] = mchain[mchain[p].next].vnum;
op[op_idx][2] = mchain[mchain[p].prev].vnum;
op_idx++;
}
else /* triangulate the polygon */
{
v = mchain[mchain[posmax].next].vnum;
if (_equal_to(&vert[v].pt, &ymin))
{ /* LHS is a single line */
triangulate_single_polygon(nvert, posmax, TRI_LHS, op);
}
else
triangulate_single_polygon(nvert, posmax, TRI_RHS, op);
}
}
#ifdef DEBUG
for (i = 0; i < op_idx; i++)
fprintf(stderr, "tri #%d: (%d, %d, %d)\n", i, op[i][0], op[i][1],
op[i][2]);
#endif
return op_idx;
}
/* A greedy corner-cutting algorithm to triangulate a y-monotone
* polygon in O(n) time.
* Joseph O-Rourke, Computational Geometry in C.
*/
static int triangulate_single_polygon(nvert, posmax, side, op)
int nvert;
int posmax;
int side;
int op[][3];
{
register int v;
int rc[SEGSIZE], ri = 0; /* reflex chain */
int endv, tmp, vpos;
if (side == TRI_RHS) /* RHS segment is a single segment */
{
rc[0] = mchain[posmax].vnum;
tmp = mchain[posmax].next;
rc[1] = mchain[tmp].vnum;
ri = 1;
vpos = mchain[tmp].next;
v = mchain[vpos].vnum;
if ((endv = mchain[mchain[posmax].prev].vnum) == 0)
endv = nvert;
}
else /* LHS is a single segment */
{
tmp = mchain[posmax].next;
rc[0] = mchain[tmp].vnum;
tmp = mchain[tmp].next;
rc[1] = mchain[tmp].vnum;
ri = 1;
vpos = mchain[tmp].next;
v = mchain[vpos].vnum;
endv = mchain[posmax].vnum;
}
while ((v != endv) || (ri > 1))
{
if (ri > 0) /* reflex chain is non-empty */
{
if (CROSS(vert[v].pt, vert[rc[ri - 1]].pt,
vert[rc[ri]].pt) > 0)
{ /* convex corner: cut if off */
op[op_idx][0] = rc[ri - 1];
op[op_idx][1] = rc[ri];
op[op_idx][2] = v;
op_idx++;
ri--;
}
else /* non-convex */
{ /* add v to the chain */
ri++;
rc[ri] = v;
vpos = mchain[vpos].next;
v = mchain[vpos].vnum;
}
}
else /* reflex-chain empty: add v to the */
{ /* reflex chain and advance it */
rc[++ri] = v;
vpos = mchain[vpos].next;
v = mchain[vpos].vnum;
}
} /* end-while */
/* reached the bottom vertex. Add in the triangle formed */
op[op_idx][0] = rc[ri - 1];
op[op_idx][1] = rc[ri];
op[op_idx][2] = v;
op_idx++;
ri--;
return 0;
}

View file

@ -1,170 +0,0 @@
#include "triangulate.h"
#include <string.h>
/* #include <sys/time.h> */
#ifdef _MSC_VER
# include <memory.h>
#endif
static int initialise(n)
int n;
{
register int i;
for (i = 1; i <= n; i++)
seg[i].is_inserted = FALSE;
generate_random_ordering(n);
return 0;
}
#ifdef STANDALONE
int main(argc, argv)
int argc;
char *argv[];
{
int n, nmonpoly, genus;
int op[SEGSIZE][3], i, ntriangles;
if ((argc < 2) || ((n = read_segments(argv[1], &genus)) < 0))
{
fprintf(stderr, "usage: triangulate <filename>\n");
exit(1);
}
initialise(n);
construct_trapezoids(n);
nmonpoly = monotonate_trapezoids(n);
ntriangles = triangulate_monotone_polygons(n, nmonpoly, op);
for (i = 0; i < ntriangles; i++)
printf("triangle #%d: %d %d %d\n", i,
op[i][0], op[i][1], op[i][2]);
return 0;
}
#else /* Not standalone. Use this as an interface routine */
/* Input specified as contours.
* Outer contour must be anti-clockwise.
* All inner contours must be clockwise.
*
* Every contour is specified by giving all its points in order. No
* point shoud be repeated. i.e. if the outer contour is a square,
* only the four distinct endpoints shopudl be specified in order.
*
* ncontours: #contours
* cntr: An array describing the number of points in each
* contour. Thus, cntr[i] = #points in the i'th contour.
* vertices: Input array of vertices. Vertices for each contour
* immediately follow those for previous one. Array location
* vertices[0] must NOT be used (i.e. i/p starts from
* vertices[1] instead. The output triangles are
* specified w.r.t. the indices of these vertices.
* triangles: Output array to hold triangles.
*
* Enough space must be allocated for all the arrays before calling
* this routine
*/
int triangulate_polygon(ncontours, cntr, vertices, triangles)
int ncontours;
int cntr[];
double (*vertices)[2];
int (*triangles)[3];
{
register int i;
int nmonpoly, ccount, npoints, genus;
int n, ntriangles;
memset((void *)seg, 0, sizeof(seg));
ccount = 0;
i = 1;
while (ccount < ncontours)
{
int j;
int first, last;
npoints = cntr[ccount];
first = i;
last = first + npoints - 1;
for (j = 0; j < npoints; j++, i++)
{
seg[i].v0.x = vertices[i][0];
seg[i].v0.y = vertices[i][1];
if (i == last)
{
seg[i].next = first;
seg[i].prev = i-1;
seg[i-1].v1 = seg[i].v0;
}
else if (i == first)
{
seg[i].next = i+1;
seg[i].prev = last;
seg[last].v1 = seg[i].v0;
}
else
{
seg[i].prev = i-1;
seg[i].next = i+1;
seg[i-1].v1 = seg[i].v0;
}
seg[i].is_inserted = FALSE;
}
ccount++;
}
genus = ncontours - 1;
n = i-1;
initialise(n);
construct_trapezoids(n);
nmonpoly = monotonate_trapezoids(n);
ntriangles = triangulate_monotone_polygons(n, nmonpoly, triangles);
return ntriangles;
}
/* This function returns TRUE or FALSE depending upon whether the
* vertex is inside the polygon or not. The polygon must already have
* been triangulated before this routine is called.
* This routine will always detect all the points belonging to the
* set (polygon-area - polygon-boundary). The return value for points
* on the boundary is not consistent!!!
*/
int is_point_inside_polygon(vertex)
double vertex[2];
{
point_t v;
int trnum, rseg;
trap_t *t;
v.x = vertex[0];
v.y = vertex[1];
trnum = locate_endpoint(&v, &v, 1);
t = &tr[trnum];
if (t->state == ST_INVALID)
return FALSE;
if ((t->lseg <= 0) || (t->rseg <= 0))
return FALSE;
rseg = t->rseg;
return _greater_than_equal_to(&seg[rseg].v1, &seg[rseg].v0);
}
#endif /* STANDALONE */

View file

@ -1,159 +0,0 @@
#ifndef _triangulate_h
#define _triangulate_h
#include <sys/types.h>
#include <stdlib.h>
#include <stdio.h>
typedef struct {
double x, y;
} point_t, vector_t;
/* Segment attributes */
typedef struct {
point_t v0, v1; /* two endpoints */
int is_inserted; /* inserted in trapezoidation yet ? */
int root0, root1; /* root nodes in Q */
int next; /* Next logical segment */
int prev; /* Previous segment */
} segment_t;
/* Trapezoid attributes */
typedef struct {
int lseg, rseg; /* two adjoining segments */
point_t hi, lo; /* max/min y-values */
int u0, u1;
int d0, d1;
int sink; /* pointer to corresponding in Q */
int usave, uside; /* I forgot what this means */
int state;
} trap_t;
/* Node attributes for every node in the query structure */
typedef struct {
int nodetype; /* Y-node or S-node */
int segnum;
point_t yval;
int trnum;
int parent; /* doubly linked DAG */
int left, right; /* children */
} node_t;
typedef struct {
int vnum;
int next; /* Circularly linked list */
int prev; /* describing the monotone */
int marked; /* polygon */
} monchain_t;
typedef struct {
point_t pt;
int vnext[4]; /* next vertices for the 4 chains */
int vpos[4]; /* position of v in the 4 chains */
int nextfree;
} vertexchain_t;
/* Node types */
#define T_X 1
#define T_Y 2
#define T_SINK 3
#define SEGSIZE 200 /* max# of segments. Determines how */
/* many points can be specified as */
/* input. If your datasets have large */
/* number of points, increase this */
/* value accordingly. */
#define QSIZE 8*SEGSIZE /* maximum table sizes */
#define TRSIZE 4*SEGSIZE /* max# trapezoids */
#define TRUE 1
#define FALSE 0
#define FIRSTPT 1 /* checking whether pt. is inserted */
#define LASTPT 2
#define INFINITY 1<<30
#define C_EPS 1.0e-7 /* tolerance value: Used for making */
/* all decisions about collinearity or */
/* left/right of segment. Decrease */
/* this value if the input points are */
/* spaced very close together */
#define S_LEFT 1 /* for merge-direction */
#define S_RIGHT 2
#define ST_VALID 1 /* for trapezium state */
#define ST_INVALID 2
#define SP_SIMPLE_LRUP 1 /* for splitting trapezoids */
#define SP_SIMPLE_LRDN 2
#define SP_2UP_2DN 3
#define SP_2UP_LEFT 4
#define SP_2UP_RIGHT 5
#define SP_2DN_LEFT 6
#define SP_2DN_RIGHT 7
#define SP_NOSPLIT -1
#define TR_FROM_UP 1 /* for traverse-direction */
#define TR_FROM_DN 2
#define TRI_LHS 1
#define TRI_RHS 2
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define CROSS(v0, v1, v2) (((v1).x - (v0).x)*((v2).y - (v0).y) - \
((v1).y - (v0).y)*((v2).x - (v0).x))
#define DOT(v0, v1) ((v0).x * (v1).x + (v0).y * (v1).y)
#define FP_EQUAL(s, t) (fabs(s - t) <= C_EPS)
/* Global variables */
extern node_t qs[QSIZE]; /* Query structure */
extern trap_t tr[TRSIZE]; /* Trapezoid structure */
extern segment_t seg[SEGSIZE]; /* Segment table */
/* Functions */
extern int monotonate_trapezoids(int);
extern int triangulate_monotone_polygons(int, int, int (*)[3]);
extern int _greater_than(point_t *, point_t *);
extern int _equal_to(point_t *, point_t *);
extern int _greater_than_equal_to(point_t *, point_t *);
extern int _less_than(point_t *, point_t *);
extern int locate_endpoint(point_t *, point_t *, int);
extern int construct_trapezoids(int);
extern int generate_random_ordering(int);
extern int choose_segment(void);
extern int read_segments(char *, int *);
extern int math_logstar_n(int);
extern int math_N(int, int);
#endif /* triangulate_h */

Binary file not shown.

View file

@ -1,8 +0,0 @@
dbfadd
dbfcreate
dbfdump
shpadd
shpcreate
shpdump
shptest
shputils

View file

@ -1,22 +0,0 @@
add_library(shape STATIC
dbfopen.c shpopen.c shapefil.h
)
foreach( c
shpcreate
shpadd
shpdump
shputils
shptest
dbfdump
dbfadd
dbfcreate
)
add_executable(${c} ${c}.c)
target_link_libraries(${c} shape)
endforeach( c )

View file

@ -1,204 +0,0 @@
2003-04-07 Frank Warmerdam <warmerdam@pobox.com>
* Issue 1.2.10 Release.
2003-03-10 Frank Warmerdam <warmerdam@pobox.com>
* dbfopen.c: modified DBFWriteAttribute call so that it returns FALSE
if it has to truncate the input value.
2003-01-28 Frank Warmerdam <warmerdam@pobox.com>
* shptree.c: avoid build warnings.
2002-05-07 Frank Warmerdam <warmerdam@pobox.com>
* dbfopen.c: Added DBFWriteAttributeDirectly() from the AVCE00
distribution to simplify AVC integration in GDAL.
* shptree.c: added use of qsort() in place of bubble sort as
submitted by Bernhard Herzog.
2002-04-10 Frank Warmerdam <warmerdam@pobox.com>
* shpopen.c: Added SHPRewindObject() to correct ring winding.
* shprewind.c: New utility program.
2002-03-12 Frank Warmerdam <warmerdam@pobox.com>
* shapelib.def: added DBFWriteNULLAttribute.
2002-01-17 Frank Warmerdam <warmerdam@pobox.com>
* contrib/ShapeFileII.pas: Contributed Delphi Pascal interface
to Shapelib.
2002-01-15 Frank Warmerdam <warmerdam@pobox.com>
* shapelib.h: Added support for SHAPELIB_DLLEXPORT macro, and write
up material attempting to explain the use of SHPAPI_CALL macros.
* dbfopen.c: Compute nHeaderLength in DBFCloneEmpty() instead of
copying it from the source file so we don't have quirks when copying
from files with extra bytes of spacers in the header that don't
themselves get copied properly.
2001-12-07 Frank Warmerdam <warmerdam@pobox.com>
* shpopen.c: Fix fclose() of SHX file if SHX file fails to open.
Should be closing SHP file. Reported by Ben Discoe.
2001-11-28 Frank Warmerdam <warmerdam@pobox.com>
* dbfopen.c: two fixes for compiler warnings as suggested by
Richard Hash.
2001-11-01 Frank Warmerdam <warmerdam@pobox.com>
* shpopen.c/shapefil.h: Move record buffer into SHPInfo so that
different threads can safely access separate files. Other threading
issues may remain.
2001-08-28 Frank Warmerdam <warmerdam@pobox.com>
* Issue Shapelib 1.2.9
* shputils.c: DBFAddField() call should check for -1 return value
for failure.
2001-07-03 Frank Warmerdam <warmerdam@pobox.com>
* shpopen.c: cleanup better if SHX missing, provided by
Riccardo Cohen.
2001-06-21 Frank Warmerdam <warmerdam@pobox.com>
* dbfopen.c: Fixed NULL support with patches from Jim Matthews.
* shpopen.c: Be more careful of establishing initial file bounds in
face of possible NULL shapes.
2001-06-01 Frank Warmerdam <warmerdam@pobox.com>
* dbfopen.c: ensure binary mode open.
2001-05-31 Frank Warmerdam <warmerdam@pobox.com>
* shpopen.c: Add support for writing null shapes.
* dbfopen.c: added DBFGetFieldIndex(), contributed by Jim Matthews.
* dbfopen.c/shapefil.h/dbf_api.h: added support for NULL fields
in .dbf files.
2001-05-28 Frank Warmerdam <warmerdam@pobox.com>
* shpopen.c: add some checking on the record count to ensure it
is reasonable.
2001-05-23 Frank Warmerdam <warmerdam@pobox.com>
* shapefile.h, shpopen.c, dbfopen.c, shptree.c: added the SHPAPI_CALL
macro to allow compilation with _stdcall conventions.
2001-02-06 Frank Warmerdam <warmerdam@pobox.com>
* Fixed a few memory leaks when SHPOpen() fails.
2000-12-05 Frank Warmerdam <warmerdam@pobox.com>
* Fix from Craig Bruce (Cubewerx) for DBFReadAttribute() for
the white space trimming code to avoid reading outside allocated
memory.
2000-11-02 Frank Warmerdam <warmerda@cs46980-c>
* Checked in upgraded shputils.c from Bill Miller.
2000-10-05 Frank Warmerdam <warmerda@cs46980-c>
* Fixed DBFWriteAttribute() to ensure we can't overwrite the
end of the szSField buffer even if the width is set large.
Bug report by Kirk Benell <kirk@rsinc.com>.
2000-09-25 Frank Warmerdam <warmerda@cs46980-c>
* Added DBFGetNativeFieldType() (contributed by Daniel) to dbfopen.c.
2000-07-18 Frank Warmerdam <warmerda@cs46980-c>
* added better enforcement of -1 for append in SHPWriteObject().
2000-07-07 Frank Warmerdam <warmerda@cs46980-c>
* Added stdlib.h and string.h where needed, and removed lots of
unused variables, mainly from example mainlines at the suggestion
of Bill Hughes.
2000-05-24 Frank Warmerdam <warmerda@cs46980-c>
* Added logic to shpadd to grow vertex lists at the suggestion of
Santiago Nullo <sn@softhome.net>.
2000-05-23 Frank Warmerdam <warmerda@cs46980-c>
* Added checks in dbfopen.c on return result of fseek() and fread().
* Avoid crashing in DBReadIntegerAttribute() or DBFReadDoubleAttribte()
if the field or record are out of range.
2000-03-28 Frank Warmerdam <warmerda@cs46980-c>
* Release as 1.2.8.
* Incorporated a -version-info fix and added mkinstalldirs from Jan.
2000-03-17 Frank Warmerdam <warmerda@cs46980-c>
* Added shared library hack to Makefile.
* Fixed up test scripts to look in ./ for executables.
Wed Feb 16 11:20:29 2000 Frank Warmerdam <warmerda@gdal.velocet.ca>
* Release 1.2.7.
* Modified SHPReadObject() so that will return NULL (type 0) shapes
in a sort of sensible way.
Wed Dec 15 08:49:53 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
* Fixed record size written at beginning of records in .shp
file. It was 4 bytes to long (thanks to Mikko Syrja of 3D-system Oy)
* Use atof() instead of sscanf() in dbfopen.c, and add stdlib.h.
Mon Dec 13 12:29:01 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
* Added support for uppercase .DBF extention c/o
Dennis Christopher <dennis@avenza.com>
Fri Nov 5 09:12:31 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
* Updated license headers to include the option of use of the code
under the LGPL.
1999-09-15 <warmerda@CS46980-B>
* Added shapelib.dll target to makefile.vc.
Mon May 10 23:19:42 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
* Added candrsn's improvements to extension handling in dbfopen.c
* Added ``raw tuple'' api to dbfopen.c, still not in dbf_api.html.
From candrsn.
Tue May 4 11:04:31 1999 Frank Warmerdam <warmerda@gdal.velocet.ca>
* Prepare 1.2.5 release.
* Added support for 'F' fields.

View file

@ -1,408 +0,0 @@
<html>
<head>
<title>Attribute (.DBF) API</title>
</head>
<body>
<h1>Attribute (.DBF) API</h1>
The Attribute (DBF) API uses DBFHandle to represent a handle for access
to one .dbf file. The contents of the DBFHandle are visible (see shapefil.h)
but should be ignored by the application. It is intended that all information
be accessed by API functions. Note that there should be exactly one record
in the .dbf file for each shape in the .shp/.shx files. This constraint
must be maintained by the application.<p>
<!-------------------------------------------------------------------------->
<h2>DBFOpen()</h2>
<pre>
DBFHandle DBFOpen( const char * pszDBFFile, const char * pszAccess );
pszDBFFile: The name of the xBase (.dbf) file to access.
pszAccess: The fopen() style access string. At this time only
"rb" (read-only binary) and "rb+" (read/write binary)
should be used.
</pre>
The DBFOpen() function should be used to establish access to an existing
xBase format table file. The returned DBFHandle is passed to other
access functions, and DBFClose() should be invoked to recover resources, and
flush changes to disk when complete. The DBFCreate() function should
called to create new xBase files. As a convenience, DBFOpen() can be
called with the name of a .shp or .shx file, and it will figure out the
name of the related .dbf file.<p>
<!-------------------------------------------------------------------------->
<h2>DBFCreate()</h2>
<pre>
DBFHandle DBFCreate( const char * pszDBFFile );
pszDBFFile: The name of the xBase (.dbf) file to create.
</pre>
The DBFCreate() function creates a new xBase format file with the given
name, and returns an access handle that can be used with other DBF functions.
The newly created file will have no fields, and no records. Fields should
be added with DBFAddField() before any records add written.
<!-------------------------------------------------------------------------->
<h2>DBFGetFieldCount()</h2>
<pre>
int DBFGetFieldCount( DBFHandle hDBF );
hDBF: The access handle for the file to be queried, as returned
by DBFOpen(), or DBFCreate().
</pre>
The DBFGetFieldCount() function returns the number of fields currently
defined for the indicated xBase file.
<!-------------------------------------------------------------------------->
<h2>DBFGetRecordCount()</h2>
<pre>
int DBFGetRecordCount( DBFHandle hDBF );
hDBF: The access handle for the file to be queried, as returned by
DBFOpen(), or DBFCreate().
</pre>
The DBFGetRecordCount() function returns the number of records that
exist on the xBase file currently. Note that with shape files one xBase
record exists for each shape in the .shp/.shx files.<p>
<!-------------------------------------------------------------------------->
<h2>DBFGetFieldIndex()</h2>
<pre>
int DBFGetFieldIndex( DBFHandle hDBF, const char *pszFieldName );
hDBF: The access handle for the file to be queried, as returned by
DBFOpen(), or DBFCreate().
pszFieldName: Name of the field to search for.
</pre>
Returns the index of the field matching this name, or -1 on failure. The
comparison is case insensitive. However, lengths must match exactly.<p>
<!-------------------------------------------------------------------------->
<h2>DBFGetFieldInfo()</h2>
<pre>
DBFFieldType DBFGetFieldInfo( DBFHandle hDBF, int iField, char * pszFieldName,
int * pnWidth, int * pnDecimals );
hDBF: The access handle for the file to be queried, as returned by
DBFOpen(), or DBFCreate().
iField: The field to be queried. This should be a number between
0 and n-1, where n is the number fields on the file, as
returned by DBFGetFieldCount().
pszFieldName: If this pointer is not NULL the name of the requested field
will be written to this location. The pszFieldName buffer
should be at least 12 character is size in order to hold
the longest possible field name of 11 characters plus a
terminating zero character.
pnWidth: If this pointer is not NULL, the width of the requested field
will be returned in the int pointed to by pnWidth. This is
the width in characters.
pnDecimals: If this pointer is not NULL, the number of decimal places
precision defined for the field will be returned. This is
zero for integer fields, or non-numeric fields.
</pre>
The DBFGetFieldInfo() returns the type of the requested field, which is
one of the DBFFieldType enumerated values. As well, the field name, and
field width information can optionally be returned. The field type returned
does not correspond one to one with the xBase field types. For instance
the xBase field type for Date will just be returned as being FTInteger. <p>
<pre>
typedef enum {
FTString, /* fixed length string field */
FTInteger, /* numeric field with no decimals */
FTDouble, /* numeric field with decimals */
FTLogical, /* logical field. */
FTInvalid /* not a recognised field type */
} DBFFieldType;
</pre>
<!-------------------------------------------------------------------------->
<h2>DBFAddField()</h2>
<pre>
int DBFAddField( DBFHandle hDBF, const char * pszFieldName,
DBFFieldType eType, int nWidth, int nDecimals );
hDBF: The access handle for the file to be updated, as returned by
DBFOpen(), or DBFCreate().
pszFieldName: The name of the new field. At most 11 character will be used.
In order to use the xBase file in some packages it may be
necessary to avoid some special characters in the field names
such as spaces, or arithmetic operators.
eType: One of FTString, FTInteger or FTDouble in order to establish
the type of the new field. Note that some valid xBase field
types cannot be created such as date fields.
nWidth: The width of the field to be created. For FTString fields this
establishes the maximum length of string that can be stored.
For FTInteger this establishes the number of digits of the
largest number that can
be represented. For FTDouble fields this in combination
with the nDecimals value establish the size, and precision
of the created field.
nDecimals: The number of decimal places to reserve for FTDouble fields.
For all other field types this should be zero. For instance
with nWidth=7, and nDecimals=3 numbers would be formatted
similarly to `123.456'.
</pre>
The DBFAddField() function is used to add new fields to an existing xBase
file opened with DBFOpen(), or created with DBFCreate(). Note that fields
can only be added to xBase files with no records, though this is limitation
of this API, not of the file format.<p>
The DBFAddField() return value is the field number of the new field, or
-1 if the addition of the field failed.<p>
<!-------------------------------------------------------------------------->
<h2>DBFReadIntegerAttribute()</h2>
<pre>
int DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
hDBF: The access handle for the file to be queried, as returned by
DBFOpen(), or DBFCreate().
iShape: The record number (shape number) from which the field value
should be read.
iField: The field within the selected record that should be read.
</pre>
The DBFReadIntegerAttribute() will read the value of one field and return
it as an integer. This can be used even with FTString fields, though the
returned value will be zero if not interpretable as a number.<p>
<!-------------------------------------------------------------------------->
<h2>DBFReadDoubleAttribute()</h2>
<pre>
double DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
hDBF: The access handle for the file to be queried, as returned by
DBFOpen(), or DBFCreate().
iShape: The record number (shape number) from which the field value
should be read.
iField: The field within the selected record that should be read.
</pre>
The DBFReadDoubleAttribute() will read the value of one field and return
it as a double. This can be used even with FTString fields, though the
returned value will be zero if not interpretable as a number.<p>
<!-------------------------------------------------------------------------->
<h2>DBFReadStringAttribute()</h2>
<pre>
const char *DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
hDBF: The access handle for the file to be queried, as returned by
DBFOpen(), or DBFCreate().
iShape: The record number (shape number) from which the field value
should be read.
iField: The field within the selected record that should be read.
</pre>
The DBFReadStringAttribute() will read the value of one field and return
it as a string. This function may be used on any field type (including
FTInteger and FTDouble) and will return the string representation stored
in the .dbf file. The returned pointer is to an internal buffer
which is only valid untill the next DBF function call. It's contents may
be copied with normal string functions such as strcpy(), or strdup(). If
the TRIM_DBF_WHITESPACE macro is defined in shapefil.h (it is by default)
then all leading and trailing space (ASCII 32) characters will be stripped
before the string is returned.<p>
<!-------------------------------------------------------------------------->
<h2>DBFIsAttributeNULL()</h2>
<pre>
int DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );
hDBF: The access handle for the file to be queried, as returned by
DBFOpen(), or DBFCreate().
iShape: The record number (shape number) from which the field value
should be read.
iField: The field within the selected record that should be read.
</pre>
This function will return TRUE if the indicated field is NULL valued
otherwise FALSE. Note that NULL fields are represented in the .dbf file
as having all spaces in the field. Reading NULL fields will result in
a value of 0.0 or an empty string with the other DBFRead*Attribute()
functions.<p>
<!-------------------------------------------------------------------------->
<h2>DBFWriteIntegerAttribute</h2>
<pre>
int DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
int nFieldValue );
hDBF: The access handle for the file to be written, as returned by
DBFOpen(), or DBFCreate().
iShape: The record number (shape number) to which the field value
should be written.
iField: The field within the selected record that should be written.
nFieldValue: The integer value that should be written.
</pre>
The DBFWriteIntegerAttribute() function is used to write a value to a numeric
field (FTInteger, or FTDouble). If the write succeeds the value TRUE will
be returned, otherwise FALSE will be returned. If the value is too large to
fit in the field, it will be truncated and FALSE returned.<p>
<!-------------------------------------------------------------------------->
<h2>DBFWriteDoubleAttribute()</h2>
<pre>
int DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
double dFieldValue );
hDBF: The access handle for the file to be written, as returned by
DBFOpen(), or DBFCreate().
iShape: The record number (shape number) to which the field value
should be written.
iField: The field within the selected record that should be written.
dFieldValue: The floating point value that should be written.
</pre>
The DBFWriteDoubleAttribute() function is used to write a value to a numeric
field (FTInteger, or FTDouble). If the write succeeds the value TRUE will
be returned, otherwise FALSE will be returned. If the value is too large to
fit in the field, it will be truncated and FALSE returned.<p>
<!-------------------------------------------------------------------------->
<h2>DBFWriteStringAttribute()</h2>
<pre>
int DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField,
const char * pszFieldValue );
hDBF: The access handle for the file to be written, as returned by
DBFOpen(), or DBFCreate().
iShape: The record number (shape number) to which the field value
should be written.
iField: The field within the selected record that should be written.
pszFieldValue: The string to be written to the field.
</pre>
The DBFWriteStringAttribute() function is used to write a value to a string
field (FString). If the write succeeds the value TRUE willbe returned,
otherwise FALSE will be returned. If the value is too large to
fit in the field, it will be truncated and FALSE returned.<p>
<!-------------------------------------------------------------------------->
<h2>DBFWriteNULLAttribute()</h2>
<pre>
int DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField );
hDBF: The access handle for the file to be written, as returned by
DBFOpen(), or DBFCreate().
iShape: The record number (shape number) to which the field value
should be written.
iField: The field within the selected record that should be written.
</pre>
The DBFWriteNULLAttribute() function is used to clear the indicated field
to a NULL value. In the .dbf file this is represented by setting the entire
field to spaces. If the write succeeds the value TRUE willbe returned,
otherwise FALSE will be returned.<p>
<!-------------------------------------------------------------------------->
<h2>DBFClose()</h2>
<pre>
void DBFClose( DBFHandle hDBF );
hDBF: The access handle for the file to be closed.
</pre>
The DBFClose() function will close the indicated xBase file (opened with
DBFOpen(), or DBFCreate()), flushing out all information to the file on
disk, and recovering any resources associated with having the file open.
The file handle (hDBF) should not be used again with the DBF API after
calling DBFClose().<p>
<!-------------------------------------------------------------------------->
<h2>DBFGetNativeFieldType()</h2>
<pre>
char DBFGetNativeFieldType( DBFHandle hDBF, int iField );
hDBF: The access handle for the file.
iField: The field index to query.
</pre>
This function returns the DBF type code of the indicated field. It will
be one of:<p>
<ul>
<li> 'C' (String)
<li> 'D' (Date)
<li> 'F' (Float)
<li> 'N' (Numeric, with or without decimal)
<li> 'L' (Logical)
<li> 'M' (Memo: 10 digits .DBT block ptr)
<li> ' ' (field out of range)
</ul>
</body>
</html>

View file

@ -1,123 +0,0 @@
/******************************************************************************
* $Id: dbfadd.c,v 1.7 2002/01/15 14:36:07 warmerda Exp $
*
* Project: Shapelib
* Purpose: Sample application for adding a record to an existing .dbf file.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: dbfadd.c,v $
* Revision 1.7 2002/01/15 14:36:07 warmerda
* updated email address
*
* Revision 1.6 2001/05/31 18:15:40 warmerda
* Added support for NULL fields in DBF files
*
* Revision 1.5 1999/11/05 14:12:04 warmerda
* updated license terms
*
* Revision 1.4 1998/12/03 16:36:06 warmerda
* Added stdlib.h and math.h to get atof() prototype.
*
* Revision 1.3 1995/10/21 03:13:23 warmerda
* Use binary mode..
*
* Revision 1.2 1995/08/04 03:15:59 warmerda
* Added header.
*
*/
static char rcsid[] =
"$Id: dbfadd.c,v 1.7 2002/01/15 14:36:07 warmerda Exp $";
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include "shapefil.h"
int main( int argc, char ** argv )
{
DBFHandle hDBF;
int i, iRecord;
/* -------------------------------------------------------------------- */
/* Display a usage message. */
/* -------------------------------------------------------------------- */
if( argc < 3 )
{
printf( "dbfadd xbase_file field_values\n" );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Create the database. */
/* -------------------------------------------------------------------- */
hDBF = DBFOpen( argv[1], "r+b" );
if( hDBF == NULL )
{
printf( "DBFOpen(%s,\"rb+\") failed.\n", argv[1] );
exit( 2 );
}
/* -------------------------------------------------------------------- */
/* Do we have the correct number of arguments? */
/* -------------------------------------------------------------------- */
if( DBFGetFieldCount( hDBF ) != argc - 2 )
{
printf( "Got %d fields, but require %d\n",
argc - 2, DBFGetFieldCount( hDBF ) );
exit( 3 );
}
iRecord = DBFGetRecordCount( hDBF );
/* -------------------------------------------------------------------- */
/* Loop assigning the new field values. */
/* -------------------------------------------------------------------- */
for( i = 0; i < DBFGetFieldCount(hDBF); i++ )
{
if( strcmp( argv[i+2], "" ) == 0 )
DBFWriteNULLAttribute(hDBF, iRecord, i );
else if( DBFGetFieldInfo( hDBF, i, NULL, NULL, NULL ) == FTString )
DBFWriteStringAttribute(hDBF, iRecord, i, argv[i+2] );
else
DBFWriteDoubleAttribute(hDBF, iRecord, i, atof(argv[i+2]) );
}
/* -------------------------------------------------------------------- */
/* Close and cleanup. */
/* -------------------------------------------------------------------- */
DBFClose( hDBF );
return( 0 );
}

View file

@ -1,124 +0,0 @@
/******************************************************************************
* $Id: dbfcreate.c,v 1.6 2002/01/15 14:36:07 warmerda Exp $
*
* Project: Shapelib
* Purpose: Sample application for creating a new .dbf file.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: dbfcreate.c,v $
* Revision 1.6 2002/01/15 14:36:07 warmerda
* updated email address
*
* Revision 1.5 2000/07/07 13:39:45 warmerda
* removed unused variables, and added system include files
*
* Revision 1.4 1999/11/05 14:12:04 warmerda
* updated license terms
*
* Revision 1.3 1999/04/01 18:47:44 warmerda
* Fixed DBFAddField() call convention.
*
* Revision 1.2 1995/08/04 03:17:11 warmerda
* Added header.
*
*/
static char rcsid[] =
"$Id: dbfcreate.c,v 1.6 2002/01/15 14:36:07 warmerda Exp $";
#include <stdlib.h>
#include <string.h>
#include "shapefil.h"
int main( int argc, char ** argv )
{
DBFHandle hDBF;
int i;
/* -------------------------------------------------------------------- */
/* Display a usage message. */
/* -------------------------------------------------------------------- */
if( argc < 2 )
{
printf( "dbfcreate xbase_file [[-s field_name width],[-n field_name width decimals]]...\n" );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Create the database. */
/* -------------------------------------------------------------------- */
hDBF = DBFCreate( argv[1] );
if( hDBF == NULL )
{
printf( "DBFCreate(%s) failed.\n", argv[1] );
exit( 2 );
}
/* -------------------------------------------------------------------- */
/* Loop over the field definitions adding new fields. */
/* -------------------------------------------------------------------- */
for( i = 2; i < argc; i++ )
{
if( strcmp(argv[i],"-s") == 0 && i < argc-2 )
{
if( DBFAddField( hDBF, argv[i+1], FTString, atoi(argv[i+2]), 0 )
== -1 )
{
printf( "DBFAddField(%s,FTString,%d,0) failed.\n",
argv[i+1], atoi(argv[i+2]) );
exit( 4 );
}
i = i + 2;
}
else if( strcmp(argv[i],"-n") == 0 && i < argc-3 )
{
if( DBFAddField( hDBF, argv[i+1], FTDouble, atoi(argv[i+2]),
atoi(argv[i+3]) ) == -1 )
{
printf( "DBFAddField(%s,FTDouble,%d,%d) failed.\n",
argv[i+1], atoi(argv[i+2]), atoi(argv[i+3]) );
exit( 4 );
}
i = i + 3;
}
else
{
printf( "Argument incomplete, or unrecognised:%s\n", argv[i] );
exit( 3 );
}
}
DBFClose( hDBF );
return( 0 );
}

View file

@ -1,271 +0,0 @@
/******************************************************************************
* $Id: dbfdump.c,v 1.9 2002/01/15 14:36:07 warmerda Exp $
*
* Project: Shapelib
* Purpose: Sample application for dumping .dbf files to the terminal.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: dbfdump.c,v $
* Revision 1.9 2002/01/15 14:36:07 warmerda
* updated email address
*
* Revision 1.8 2001/05/31 18:15:40 warmerda
* Added support for NULL fields in DBF files
*
* Revision 1.7 2000/09/20 13:13:55 warmerda
* added break after default:
*
* Revision 1.6 2000/07/07 13:39:45 warmerda
* removed unused variables, and added system include files
*
* Revision 1.5 1999/11/05 14:12:04 warmerda
* updated license terms
*
* Revision 1.4 1998/12/31 15:30:13 warmerda
* Added -m, -r, and -h commandline options.
*
* Revision 1.3 1995/10/21 03:15:01 warmerda
* Changed to use binary file access.
*
* Revision 1.2 1995/08/04 03:16:22 warmerda
* Added header.
*
*/
static char rcsid[] =
"$Id: dbfdump.c,v 1.9 2002/01/15 14:36:07 warmerda Exp $";
#include <stdlib.h>
#include <string.h>
#include "shapefil.h"
int main( int argc, char ** argv )
{
DBFHandle hDBF;
int *panWidth, i, iRecord;
char szFormat[32], *pszFilename = NULL;
int nWidth, nDecimals;
int bHeader = 0;
int bRaw = 0;
int bMultiLine = 0;
char szTitle[12];
/* -------------------------------------------------------------------- */
/* Handle arguments. */
/* -------------------------------------------------------------------- */
for( i = 1; i < argc; i++ )
{
if( strcmp(argv[i],"-h") == 0 )
bHeader = 1;
else if( strcmp(argv[i],"-r") == 0 )
bRaw = 1;
else if( strcmp(argv[i],"-m") == 0 )
bMultiLine = 1;
else
pszFilename = argv[i];
}
/* -------------------------------------------------------------------- */
/* Display a usage message. */
/* -------------------------------------------------------------------- */
if( pszFilename == NULL )
{
printf( "dbfdump [-h] [-r] [-m] xbase_file\n" );
printf( " -h: Write header info (field descriptions)\n" );
printf( " -r: Write raw field info, numeric values not reformatted\n" );
printf( " -m: Multiline, one line per field.\n" );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Open the file. */
/* -------------------------------------------------------------------- */
hDBF = DBFOpen( pszFilename, "rb" );
if( hDBF == NULL )
{
printf( "DBFOpen(%s,\"r\") failed.\n", argv[1] );
exit( 2 );
}
/* -------------------------------------------------------------------- */
/* If there is no data in this file let the user know. */
/* -------------------------------------------------------------------- */
if( DBFGetFieldCount(hDBF) == 0 )
{
printf( "There are no fields in this table!\n" );
exit( 3 );
}
/* -------------------------------------------------------------------- */
/* Dump header definitions. */
/* -------------------------------------------------------------------- */
if( bHeader )
{
for( i = 0; i < DBFGetFieldCount(hDBF); i++ )
{
DBFFieldType eType;
const char *pszTypeName;
eType = DBFGetFieldInfo( hDBF, i, szTitle, &nWidth, &nDecimals );
if( eType == FTString )
pszTypeName = "String";
else if( eType == FTInteger )
pszTypeName = "Integer";
else if( eType == FTDouble )
pszTypeName = "Double";
else if( eType == FTInvalid )
pszTypeName = "Invalid";
printf( "Field %d: Type=%s, Title=`%s', Width=%d, Decimals=%d\n",
i, pszTypeName, szTitle, nWidth, nDecimals );
}
}
/* -------------------------------------------------------------------- */
/* Compute offsets to use when printing each of the field */
/* values. We make each field as wide as the field title+1, or */
/* the field value + 1. */
/* -------------------------------------------------------------------- */
panWidth = (int *) malloc( DBFGetFieldCount( hDBF ) * sizeof(int) );
for( i = 0; i < DBFGetFieldCount(hDBF) && !bMultiLine; i++ )
{
DBFFieldType eType;
eType = DBFGetFieldInfo( hDBF, i, szTitle, &nWidth, &nDecimals );
if( strlen(szTitle) > nWidth )
panWidth[i] = strlen(szTitle);
else
panWidth[i] = nWidth;
if( eType == FTString )
sprintf( szFormat, "%%-%ds ", panWidth[i] );
else
sprintf( szFormat, "%%%ds ", panWidth[i] );
printf( szFormat, szTitle );
}
printf( "\n" );
/* -------------------------------------------------------------------- */
/* Read all the records */
/* -------------------------------------------------------------------- */
for( iRecord = 0; iRecord < DBFGetRecordCount(hDBF); iRecord++ )
{
if( bMultiLine )
printf( "Record: %d\n", iRecord );
for( i = 0; i < DBFGetFieldCount(hDBF); i++ )
{
DBFFieldType eType;
eType = DBFGetFieldInfo( hDBF, i, szTitle, &nWidth, &nDecimals );
if( bMultiLine )
{
printf( "%s: ", szTitle );
}
/* -------------------------------------------------------------------- */
/* Print the record according to the type and formatting */
/* information implicit in the DBF field description. */
/* -------------------------------------------------------------------- */
if( !bRaw )
{
if( DBFIsAttributeNULL( hDBF, iRecord, i ) )
{
if( eType == FTString )
sprintf( szFormat, "%%-%ds", nWidth );
else
sprintf( szFormat, "%%%ds", nWidth );
printf( szFormat, "(NULL)" );
}
else
{
switch( eType )
{
case FTString:
sprintf( szFormat, "%%-%ds", nWidth );
printf( szFormat,
DBFReadStringAttribute( hDBF, iRecord, i ) );
break;
case FTInteger:
sprintf( szFormat, "%%%dd", nWidth );
printf( szFormat,
DBFReadIntegerAttribute( hDBF, iRecord, i ) );
break;
case FTDouble:
sprintf( szFormat, "%%%d.%dlf", nWidth, nDecimals );
printf( szFormat,
DBFReadDoubleAttribute( hDBF, iRecord, i ) );
break;
default:
break;
}
}
}
/* -------------------------------------------------------------------- */
/* Just dump in raw form (as formatted in the file). */
/* -------------------------------------------------------------------- */
else
{
sprintf( szFormat, "%%-%ds", nWidth );
printf( szFormat,
DBFReadStringAttribute( hDBF, iRecord, i ) );
}
/* -------------------------------------------------------------------- */
/* Write out any extra spaces required to pad out the field */
/* width. */
/* -------------------------------------------------------------------- */
if( !bMultiLine )
{
sprintf( szFormat, "%%%ds", panWidth[i] - nWidth + 1 );
printf( szFormat, "" );
}
if( bMultiLine )
printf( "\n" );
fflush( stdout );
}
printf( "\n" );
}
DBFClose( hDBF );
return( 0 );
}

File diff suppressed because it is too large Load diff

View file

@ -1,21 +0,0 @@
#!/bin/sh
#
# Use example programs to create a very simple dataset that
# should display in ARCView II.
#
shpcreate test polygon
dbfcreate test.dbf -s Description 30 -n TestInt 6 0 -n TestDouble 16 5
shpadd test 0 0 100 0 100 100 0 100 0 0 + 20 20 20 30 30 30 20 20
dbfadd test.dbf "Square with triangle missing" 1.5 2.5
shpadd test 150 150 160 150 180 170 150 150
dbfadd test.dbf "Smaller triangle" 100 1000.25
shpadd test 150 150 160 150 180 170 150 150
dbfadd test.dbf "" "" ""
shpdump test.shp
dbfdump test.dbf

View file

@ -1,18 +0,0 @@
Shapefile Specification Errata
------------------------------
1) The table on page 23 (Multipatch Record Contents) shows ShapeType
being 15 when it should be 31.
2) The example file brklinz.shp does not seem to initialize the
ZMin, ZMax values in the header of the .shp file (at byte 68-83).
Is there a reason?
3) The table on page 15 for PointZ type does not show the Measure value
as being optional, yet the masspntz.shp example dataset doesn't have
the measure values implying that it must be optional.
4) The sample file, 3dpoints.shp/shx/dbf seems to be corrupt. In particular
the record offsets in the .shx file are all over the place, leading to
some of the shapes reading improperly.

View file

@ -1,484 +0,0 @@
#ifndef _SHAPEFILE_H_INCLUDED
#define _SHAPEFILE_H_INCLUDED
/******************************************************************************
* $Id: shapefil.h,v 1.26 2002/09/29 00:00:08 warmerda Exp $
*
* Project: Shapelib
* Purpose: Primary include file for Shapelib.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: shapefil.h,v $
* Revision 1.26 2002/09/29 00:00:08 warmerda
* added FTLogical and logical attribute read/write calls
*
* Revision 1.25 2002/05/07 13:46:30 warmerda
* added DBFWriteAttributeDirectly().
*
* Revision 1.24 2002/04/10 16:59:54 warmerda
* added SHPRewindObject
*
* Revision 1.23 2002/01/15 14:36:07 warmerda
* updated email address
*
* Revision 1.22 2002/01/15 14:32:00 warmerda
* try to improve SHPAPI_CALL docs
*
* Revision 1.21 2001/11/01 16:29:55 warmerda
* move pabyRec into SHPInfo for thread safety
*
* Revision 1.20 2001/07/20 13:06:02 warmerda
* fixed SHPAPI attribute for SHPTreeFindLikelyShapes
*
* Revision 1.19 2001/05/31 19:20:13 warmerda
* added DBFGetFieldIndex()
*
* Revision 1.18 2001/05/31 18:15:40 warmerda
* Added support for NULL fields in DBF files
*
* Revision 1.17 2001/05/23 13:36:52 warmerda
* added use of SHPAPI_CALL
*
* Revision 1.16 2000/09/25 14:15:59 warmerda
* added DBFGetNativeFieldType()
*
* Revision 1.15 2000/02/16 16:03:51 warmerda
* added null shape support
*
* Revision 1.14 1999/11/05 14:12:05 warmerda
* updated license terms
*
* Revision 1.13 1999/06/02 18:24:21 warmerda
* added trimming code
*
* Revision 1.12 1999/06/02 17:56:12 warmerda
* added quad'' subnode support for trees
*
* Revision 1.11 1999/05/18 19:11:11 warmerda
* Added example searching capability
*
* Revision 1.10 1999/05/18 17:49:38 warmerda
* added initial quadtree support
*
* Revision 1.9 1999/05/11 03:19:28 warmerda
* added new Tuple api, and improved extension handling - add from candrsn
*
* Revision 1.8 1999/03/23 17:22:27 warmerda
* Added extern "C" protection for C++ users of shapefil.h.
*
* Revision 1.7 1998/12/31 15:31:07 warmerda
* Added the TRIM_DBF_WHITESPACE and DISABLE_MULTIPATCH_MEASURE options.
*
* Revision 1.6 1998/12/03 15:48:15 warmerda
* Added SHPCalculateExtents().
*
* Revision 1.5 1998/11/09 20:57:16 warmerda
* Altered SHPGetInfo() call.
*
* Revision 1.4 1998/11/09 20:19:33 warmerda
* Added 3D support, and use of SHPObject.
*
* Revision 1.3 1995/08/23 02:24:05 warmerda
* Added support for reading bounds.
*
* Revision 1.2 1995/08/04 03:17:39 warmerda
* Added header.
*
*/
#include <stdio.h>
#ifdef USE_DBMALLOC
#include <dbmalloc.h>
#endif
#ifdef __cplusplus
extern "C" {
#endif
/************************************************************************/
/* Configuration options. */
/************************************************************************/
/* -------------------------------------------------------------------- */
/* Should the DBFReadStringAttribute() strip leading and */
/* trailing white space? */
/* -------------------------------------------------------------------- */
#define TRIM_DBF_WHITESPACE
/* -------------------------------------------------------------------- */
/* Should we write measure values to the Multipatch object? */
/* Reportedly ArcView crashes if we do write it, so for now it */
/* is disabled. */
/* -------------------------------------------------------------------- */
#define DISABLE_MULTIPATCH_MEASURE
/* -------------------------------------------------------------------- */
/* SHPAPI_CALL */
/* */
/* The following two macros are present to allow forcing */
/* various calling conventions on the Shapelib API. */
/* */
/* To force __stdcall conventions (needed to call Shapelib */
/* from Visual Basic and/or Dephi I believe) the makefile could */
/* be modified to define: */
/* */
/* /DSHPAPI_CALL=__stdcall */
/* */
/* If it is desired to force export of the Shapelib API without */
/* using the shapelib.def file, use the following definition. */
/* */
/* /DSHAPELIB_DLLEXPORT */
/* */
/* To get both at once it will be necessary to hack this */
/* include file to define: */
/* */
/* #define SHPAPI_CALL __declspec(dllexport) __stdcall */
/* #define SHPAPI_CALL1 __declspec(dllexport) * __stdcall */
/* */
/* The complexity of the situtation is partly caused by the */
/* peculiar requirement of Visual C++ that __stdcall appear */
/* after any "*"'s in the return value of a function while the */
/* __declspec(dllexport) must appear before them. */
/* -------------------------------------------------------------------- */
#ifdef SHAPELIB_DLLEXPORT
# define SHPAPI_CALL __declspec(dllexport)
# define SHPAPI_CALL1(x) __declspec(dllexport) x
#endif
#ifndef SHPAPI_CALL
# define SHPAPI_CALL
#endif
#ifndef SHPAPI_CALL1
# define SHPAPI_CALL1(x) x SHPAPI_CALL
#endif
/************************************************************************/
/* SHP Support. */
/************************************************************************/
typedef struct
{
FILE *fpSHP;
FILE *fpSHX;
int nShapeType; /* SHPT_* */
int nFileSize; /* SHP file */
int nRecords;
int nMaxRecords;
int *panRecOffset;
int *panRecSize;
double adBoundsMin[4];
double adBoundsMax[4];
int bUpdated;
unsigned char *pabyRec;
int nBufSize;
} SHPInfo;
typedef SHPInfo * SHPHandle;
/* -------------------------------------------------------------------- */
/* Shape types (nSHPType) */
/* -------------------------------------------------------------------- */
#define SHPT_NULL 0
#define SHPT_POINT 1
#define SHPT_ARC 3
#define SHPT_POLYGON 5
#define SHPT_MULTIPOINT 8
#define SHPT_POINTZ 11
#define SHPT_ARCZ 13
#define SHPT_POLYGONZ 15
#define SHPT_MULTIPOINTZ 18
#define SHPT_POINTM 21
#define SHPT_ARCM 23
#define SHPT_POLYGONM 25
#define SHPT_MULTIPOINTM 28
#define SHPT_MULTIPATCH 31
/* -------------------------------------------------------------------- */
/* Part types - everything but SHPT_MULTIPATCH just uses */
/* SHPP_RING. */
/* -------------------------------------------------------------------- */
#define SHPP_TRISTRIP 0
#define SHPP_TRIFAN 1
#define SHPP_OUTERRING 2
#define SHPP_INNERRING 3
#define SHPP_FIRSTRING 4
#define SHPP_RING 5
/* -------------------------------------------------------------------- */
/* SHPObject - represents on shape (without attributes) read */
/* from the .shp file. */
/* -------------------------------------------------------------------- */
typedef struct
{
int nSHPType;
int nShapeId; /* -1 is unknown/unassigned */
int nParts;
int *panPartStart;
int *panPartType;
int nVertices;
double *padfX;
double *padfY;
double *padfZ;
double *padfM;
double dfXMin;
double dfYMin;
double dfZMin;
double dfMMin;
double dfXMax;
double dfYMax;
double dfZMax;
double dfMMax;
} SHPObject;
/* -------------------------------------------------------------------- */
/* SHP API Prototypes */
/* -------------------------------------------------------------------- */
SHPHandle SHPAPI_CALL
SHPOpen( const char * pszShapeFile, const char * pszAccess );
SHPHandle SHPAPI_CALL
SHPCreate( const char * pszShapeFile, int nShapeType );
void SHPAPI_CALL
SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType,
double * padfMinBound, double * padfMaxBound );
SHPObject SHPAPI_CALL1(*)
SHPReadObject( SHPHandle hSHP, int iShape );
int SHPAPI_CALL
SHPWriteObject( SHPHandle hSHP, int iShape, SHPObject * psObject );
void SHPAPI_CALL
SHPDestroyObject( SHPObject * psObject );
void SHPAPI_CALL
SHPComputeExtents( SHPObject * psObject );
SHPObject SHPAPI_CALL1(*)
SHPCreateObject( int nSHPType, int nShapeId,
int nParts, int * panPartStart, int * panPartType,
int nVertices, double * padfX, double * padfY,
double * padfZ, double * padfM );
SHPObject SHPAPI_CALL1(*)
SHPCreateSimpleObject( int nSHPType, int nVertices,
double * padfX, double * padfY, double * padfZ );
int SHPAPI_CALL
SHPRewindObject( SHPHandle hSHP, SHPObject * psObject );
void SHPAPI_CALL
SHPClose( SHPHandle hSHP );
const char SHPAPI_CALL1(*)
SHPTypeName( int nSHPType );
const char SHPAPI_CALL1(*)
SHPPartTypeName( int nPartType );
/* -------------------------------------------------------------------- */
/* Shape quadtree indexing API. */
/* -------------------------------------------------------------------- */
/* this can be two or four for binary or quad tree */
#define MAX_SUBNODE 4
typedef struct shape_tree_node
{
/* region covered by this node */
double adfBoundsMin[4];
double adfBoundsMax[4];
/* list of shapes stored at this node. The papsShapeObj pointers
or the whole list can be NULL */
int nShapeCount;
int *panShapeIds;
SHPObject **papsShapeObj;
int nSubNodes;
struct shape_tree_node *apsSubNode[MAX_SUBNODE];
} SHPTreeNode;
typedef struct
{
SHPHandle hSHP;
int nMaxDepth;
int nDimension;
SHPTreeNode *psRoot;
} SHPTree;
SHPTree SHPAPI_CALL1(*)
SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
double *padfBoundsMin, double *padfBoundsMax );
void SHPAPI_CALL
SHPDestroyTree( SHPTree * hTree );
int SHPAPI_CALL
SHPWriteTree( SHPTree *hTree, const char * pszFilename );
SHPTree SHPAPI_CALL
SHPReadTree( const char * pszFilename );
int SHPAPI_CALL
SHPTreeAddObject( SHPTree * hTree, SHPObject * psObject );
int SHPAPI_CALL
SHPTreeAddShapeId( SHPTree * hTree, SHPObject * psObject );
int SHPAPI_CALL
SHPTreeRemoveShapeId( SHPTree * hTree, int nShapeId );
void SHPAPI_CALL
SHPTreeTrimExtraNodes( SHPTree * hTree );
int SHPAPI_CALL1(*)
SHPTreeFindLikelyShapes( SHPTree * hTree,
double * padfBoundsMin,
double * padfBoundsMax,
int * );
int SHPAPI_CALL
SHPCheckBoundsOverlap( double *, double *, double *, double *, int );
/************************************************************************/
/* DBF Support. */
/************************************************************************/
typedef struct
{
FILE *fp;
int nRecords;
int nRecordLength;
int nHeaderLength;
int nFields;
int *panFieldOffset;
int *panFieldSize;
int *panFieldDecimals;
char *pachFieldType;
char *pszHeader;
int nCurrentRecord;
int bCurrentRecordModified;
char *pszCurrentRecord;
int bNoHeader;
int bUpdated;
} DBFInfo;
typedef DBFInfo * DBFHandle;
typedef enum {
FTString,
FTInteger,
FTDouble,
FTLogical,
FTInvalid
} DBFFieldType;
#define XBASE_FLDHDR_SZ 32
DBFHandle SHPAPI_CALL
DBFOpen( const char * pszDBFFile, const char * pszAccess );
DBFHandle SHPAPI_CALL
DBFCreate( const char * pszDBFFile );
int SHPAPI_CALL
DBFGetFieldCount( DBFHandle psDBF );
int SHPAPI_CALL
DBFGetRecordCount( DBFHandle psDBF );
int SHPAPI_CALL
DBFAddField( DBFHandle hDBF, const char * pszFieldName,
DBFFieldType eType, int nWidth, int nDecimals );
DBFFieldType SHPAPI_CALL
DBFGetFieldInfo( DBFHandle psDBF, int iField,
char * pszFieldName, int * pnWidth, int * pnDecimals );
int SHPAPI_CALL
DBFGetFieldIndex(DBFHandle psDBF, const char *pszFieldName);
int SHPAPI_CALL
DBFReadIntegerAttribute( DBFHandle hDBF, int iShape, int iField );
double SHPAPI_CALL
DBFReadDoubleAttribute( DBFHandle hDBF, int iShape, int iField );
const char SHPAPI_CALL1(*)
DBFReadStringAttribute( DBFHandle hDBF, int iShape, int iField );
const char SHPAPI_CALL1(*)
DBFReadLogicalAttribute( DBFHandle hDBF, int iShape, int iField );
int SHPAPI_CALL
DBFIsAttributeNULL( DBFHandle hDBF, int iShape, int iField );
int SHPAPI_CALL
DBFWriteIntegerAttribute( DBFHandle hDBF, int iShape, int iField,
int nFieldValue );
int SHPAPI_CALL
DBFWriteDoubleAttribute( DBFHandle hDBF, int iShape, int iField,
double dFieldValue );
int SHPAPI_CALL
DBFWriteStringAttribute( DBFHandle hDBF, int iShape, int iField,
const char * pszFieldValue );
int SHPAPI_CALL
DBFWriteNULLAttribute( DBFHandle hDBF, int iShape, int iField );
int SHPAPI_CALL
DBFWriteLogicalAttribute( DBFHandle hDBF, int iShape, int iField,
const char lFieldValue);
int SHPAPI_CALL
DBFWriteAttributeDirectly(DBFHandle psDBF, int hEntity, int iField,
void * pValue );
const char SHPAPI_CALL1(*)
DBFReadTuple(DBFHandle psDBF, int hEntity );
int SHPAPI_CALL
DBFWriteTuple(DBFHandle psDBF, int hEntity, void * pRawTuple );
DBFHandle SHPAPI_CALL
DBFCloneEmpty(DBFHandle psDBF, const char * pszFilename );
void SHPAPI_CALL
DBFClose( DBFHandle hDBF );
char SHPAPI_CALL
DBFGetNativeFieldType( DBFHandle hDBF, int iField );
#ifdef __cplusplus
}
#endif
#endif /* ndef _SHAPEFILE_H_INCLUDED */

View file

@ -1,334 +0,0 @@
<html>
<head>
<title>Shapefile C Library V1.2</title>
</head>
<body>
<h1>Shapefile C Library V1.2</h1>
<h2>Purpose</h2>
The Shapefile C Library provides the ability to write simple C programs
for reading, writing and updating (to a limited extent) ESRI Shapefiles,
and the associated attribute file (.dbf).<p>
<h2>Manifest</h2>
<ul>
<li> <b>shapelib.html</b>: This file - general documentation on the
Shapefile C Library.<p>
<li> <b><a href="shp_api.html">shp_api.html</a></b>: Documentation
for the API for accessing the .shp/.shx files. <p>
<li> <b><a href="dbf_api.html">dbf_api.html</a></b>: Documentation
for the API for accessing the .dbf attribute files. <p>
<li> <b>shpopen.c</b>: C code for access to .shp/.shx vertex files.<p>
<li> <b>dbfopen.c</b>: C code for access to .dbf attribute file.<p>
<li> <b>shapefil.h</b>: Include file defining all the services of dbfopen.c
and shpopen.c.<p>
<li> <b>contrib/</b>: A directory of "in progress" contributed programs
from Carl Anderson.<p>
<li> <b>dbfcreate.c</b>: Simple example program for creating a new .dbf file.
<p>
<li> <b>dbfadd.c</b>:
Simple example program for adding a record to a .dbf file.<p>
<li> <b>dbfdump.c</b>: Simple example program for displaying the contents of
a .dbf file.<p>
<li> <b>shpcreate.c</b>: Simple example program for creating a new .shp and
.shx file.<p>
<li> <b>shpadd.c</b>: Simple example program for adding a shape to an existing
shape file.<p>
<li> <b>shpdump.c</b>: Simple program for dumping all the vertices in a
shapefile with an indicating of the parts.<p>
<li> <b>shputils.c</b>: Complex contributed program capable of clipping and
appending
shapefiles as well as a few other things. Type shputils
after building to get a full usage message.<p>
<li> <b>Makefile</b>: A simple makefile to compile the library and example
programs.<p>
<li> <b>makeshape.sh</b>: A simple script for running some of the example
programs.<p>
<li> <b>shptest.c</b>: A simple test harnass to generate each of the supported
types of shapefiles. <p>
<li> <b>shptree.c</b>: Implements a simple quadtree algorithm for fast
spatial searches of shapefiles.<p>
<li> <b>shptreedump.c</b>: A simple mainly showing information on quad
trees build using the quad tree api.<p>
<li> <b>stream1.sh</b> - A test script, which should produce stream1.out.
Note this will only work if you have the example data downloaded.<p>
<li> <b>stream1.out</b>: Expected output of stream1.sh test script.<p>
<li> <b>stream2.sh</b>: A test script, which should produce stream2.out.<p>
<li> <b>stream2.out</b>: Expected output of stream2.sh test script.<p>
<li> <b>pyshapelib-0.1</b>: Prototype contributed Python bindings.<p>
</ul>
<h2>What is a Shapefile?</h2>
If you don't know, you probably don't need this library. The Shapefile
format is a new working and interchange format promulagated by ESRI
(http://www.esri.com/) for simple vector data with attributes. It is
apparently the only file format that can be edited in ARCView 2/3, and can
also be exported and imported in Arc/Info. <p>
An excellent white paper on the shapefile format is available from ESRI,
but it is .pdf format, so you will need Adobe Acrobat to browse it.<p>
The file format actually consists of three files.<p>
<pre>
XXX.shp - holds the actual vertices.
XXX.shx - hold index data pointing to the structures in the .shp file.
XXX.dbf - holds the attributes in xBase (dBase) format.
</pre>
<h2>Release Notes</h2>
To get notification of new releases of Shapelib <i>subscribe</i> to
the project at www.freshmeat.net. This is currently the only reliable
way of finding out about new releases since there is no shapelib specific
mailing list.<p>
<b>Release 1.2.10</b>: Added SHPRewindObject() function, and shprewind utility
program. Added FTLogical, DBFReadLogicalAttribute() and
DBFWriteLogicalAttribute() (thanks to Olek Neyman). <p>
<b>Release 1.2.9</b>: Good support for reading and writing NULL fields
in .dbf files, good support for NULL shapes and addition of the
DBFGetFieldIndex() functions (all contributed by Jim Matthews).<p>
An upgraded shputils.c has been contributed by Bill Miller. Daniel
Morissette contributed DBFGetNativeFieldType(). Better error checking
for disk errors in dbfopen.c. Various other bug fixes and safety improvements.
<p>
<b>Release 1.2.8</b>: Added hacked libtool support (supplied by Jan)
and "rpm ready" install logic.<p>
<b>Release 1.2.7</b>: Fix record size (was 4 bytes too long). Modify
SHPReadObject() to handle null shapes properly. Use atof() instead of
sscanf(). Support .DBF as well as .dbf.<p>
<b>Release 1.2.6</b>: Now available under old MIT style license, or at the
users option, LGPL. Added the contrib directory of stuff from Carl Anderson
and the shptree.c API for quadtree based spatial searches.<p>
<b>Release 1.2.5</b>: SHPOpen() now forcably uses "rb" or "r+b" access string
to avoid common mistakes on Windows. Also fixed a serious bug with .dbf
files with a 'F' field type.<p>
<b>Release 1.2.4</b>: DBFOpen() will now automatically translate a .shp
extension to .dbf for convenience. SHPOpen() will try datasets with lower
and uppercase extension. DBFAddField() now returns the field number,
not TRUE/FALSE.<p>
<b>Release 1.2.3</b>: Disable writing measures to multi-patches as ArcView
seems to puke on them (as reported by Monika Sester). Add white space
trimming, and string/numeric attribute interchangability in DBF API
as suggested by Steve Lime. Dbfdump was updated to include several
reporting options.<p>
<b>Release 1.2.2</b>: Added proper support for multipatch (reading and
writing) - this release just for testing purposes.<p>
<b>Release 1.2</b> is mostly a rewrite of the .shp/.shx access API to account
for ArcView 3.x 3D shapes, and to encapsulate the shapes in a structure.
Existing code using the shapefile library will require substantial changes
to use release 1.2.<p>
<b>Release V1.1</b> has been built on a number of platforms, and used by a
number of people successfully. V1.1 is the first release with the xBase API
documentation.<p>
<h2>Maintainer</h2>
This library is maintained by me (Frank Warmerdam) on my own time. Please
send me bug patches and suggestions for the library. Email can be sent to
warmerdam@pobox.com.<p>
The current status of the Shapelib code can be found at
<a href="http://pobox.com/~warmerdam/root/projects/shapelib/">
http://pobox.com/~warmerdam/root/projects/shapelib/</a>. To find out about
new releases of Shapelib, select the "Subscribe to new releases" option
from the link at
<a href="http://freshmeat.net/projects/shapelib/">Freshmeat</a>.<p>
The shputils.c module was contributed by Bill Miller (NC-DOT) who can be
reached at bmiller@doh.dot.state.nc.us. I had to modify it substantially
to work with the 1.2 API, and I am not sure that it works as well as it
did when it was originally provided by Bill.<p>
<h2>Credits</h2>
I didn't start this section anywhere near soon enough, so alot of earlier
contributors to Shapelib are lost in pre-history.
<ul>
<li> Bill Miller (NY-DOT) for shputils.c
<li> Carl Anderson for the contents of the contrib directory, and
the "tuple" additions to dbfopen.c.
<li> Andrea Giacomelli for patches for dbfopen.c.
<li> Doug Matthews for portability improvements.
<li> Jan-Oliver Wagner for convincing me to make it available under LGPL,
shared library support, and various other patches.
<li> Dennis Christopher (of Avenza) for testing and bug fixes.
<li> Miko Syrjä (of 3D-system Oy) for a record size bug fix.
<li> Steven Lime and Curtis Hill for help with NULL shapes.
<li> Jim Matthews for support of NULL attributes in dbf files.
<li> <a href="http://www.pcigeomatics.com/">PCI Geomatics</a> who let me
release a modified version of their shapefile code in the beginning and
who hosted shapelib for years.
</ul>
<h2>In Memorium</h2>
I would like to dedicate Shapelib to the memory of Sol Katz. While I never
met him in person, his generous contributions to the GIS community took
many forms, including free distribution of a variety of GIS translators
with source. The fact that he used this Shapelib in some of his utilities,
and thanked me was a great encouragement to me. I hope I can do his memory
honour by trying to contribute in a similar fashion.<p>
<h2>Portability</h2>
The Shapefile C Library should port easily to 32bit systems with ANSI C
compilers. It should work on 64 bit architectures (such as the DEC AXP).<p>
Care should also be taken to pass the binary access flag into SHPOpen()
and DBFOpen() when operating on systems with special text file translation
such as MSDOS.<p>
The shputils.c module is contributed, and may not take the same approach
to portability as the rest of the package.<p>
On Linux, and most unix systems it should be possible to build and
install shapefile support as a shared library using the "lib" and "lib_install"
targets of the Makefile. Note that this Makefile doesn't use autoconf
mechanisms and will generally require some hand tailoring for your environment.
<h2>Limitations</h2>
<ul>
<li> You can't modify the vertices of existing structures (though you
can update the attributes of existing structures, and create new
structures).<p>
<li> Not written in such a way as to be particularly fast. This is
particularly true of the 1.2 API. For applications more concerned with
speed it may be worth using the V1.1 API.<p>
<li> Doesn't set the last access time properly in the .dbf files.<p>
<li> There is no way to synchronize information to the file except to close it.
<p>
<li> Poor error checking and reporting.<p>
<li> Not professionally supported (well it can be, if you want to pay).<p>
<li> Some aspects of xBase files not supported, though I believe they are
not used by ESRI.<p>
<li> The application must keep the .dbf file in sync with the .shp/.shx
files through appropriate use of the DBF and SHP APIs.<p>
<li> No support for the undocumented .sbn/.sbx spatial index files.<p>
</ul>
<h2>Copyright</h2>
The source for the Shapefile C Library is (c) 1998 Frank Warmerdam,
and released under the following conditions. The intent is that anyone
can do anything with the code, but that I do not assume any liability, nor
express any warranty for this code. <p>
As of Shapelib 1.2.6 the core portions of the library are made available
under two possible licenses. The licensee can choose to use the code
under either the Library GNU Public License (LGPL) described in
LICENSE.LGPL or under the following MIT style license. Any files in
the Shapelib distribution without explicit copyright license terms
(such as this documentation, the Makefile and so forth) should be
considered to have the following licensing terms. Some auxilary portions
of Shapelib, notably some of the components in the contrib directory
come under slightly different license restrictions. Check the source
files that you are actually using for conditions.<p>
<h3>Default License Terms</h3>
<quote>
Copyright (c) 1999, Frank Warmerdam<p>
This software is available under the following "MIT Style" license,
or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
option is discussed in more detail in shapelib.html.<p>
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:<p>
The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.<p>
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.<p>
</quote>
<h3>Shapelib Modifications</h3>
I am pleased to receive bug fixes, and improvements for Shapelib. Unless
the submissions indicate otherwise I will assume that changes submitted to
me remain under the the above "dual license" terms. If changes are made
to the library with the intention that those changes should be protected by
the LGPL then I should be informed upon submission. Note that I will not
generally incorporate changes into the core of Shapelib that are protected
under the LGPL as this would effectively limit the whole file and
distribution to LGPL terms.<p>
<h3>Opting for LGPL</h3>
For licensee's opting to use Shapelib under LGPL as opposed to the MIT
Style license above, and wishing to redistribute the software based on
Shapelib, I would ask that all "dual license" modules be updated to
indicate that only the LGPL (and not the MIT Style license) applies. This
action represents opting for the LGPL, and thereafter LGPL terms apply to
any redistribution and modification of the affected modules.<p>
</body>
</html>

View file

@ -1,376 +0,0 @@
<html>
<head>
<title>.SHP File API</title>
</head>
<body>
<h1>.SHP File API</h1>
The .SHP API uses a SHPHandle to represent an open .shp/.shx file pair.
The contents of the SHPHandle are visible (see shapefile.h) but should
be ignored by the application. It is intended that all information be
accessed by the API functions. <p>
<!-------------------------------------------------------------------------->
<h2>Shape Types</h2>
Shapes have types associated with them. The following is a list of the
different shapetypes supported by Shapefiles. At this time all shapes in
a Shapefile must be of the same type (with the exception of NULL shapes). <p>
<pre>
#define SHPT_NULL 0
2D Shape Types (pre ArcView 3.x):
#define SHPT_POINT 1 Points
#define SHPT_ARC 3 Arcs (Polylines, possible in parts)
#define SHPT_POLYGON 5 Polygons (possible in parts)
#define SHPT_MULTIPOINT 8 MultiPoint (related points)
3D Shape Types (may include "measure" values for vertices):
#define SHPT_POINTZ 11
#define SHPT_ARCZ 13
#define SHPT_POLYGONZ 15
#define SHPT_MULTIPOINTZ 18
2D + Measure Types:
#define SHPT_POINTM 21
#define SHPT_ARCM 23
#define SHPT_POLYGONM 25
#define SHPT_MULTIPOINTM 28
Complex (TIN-like) with Z, and Measure:
#define SHPT_MULTIPATCH 31
</pre>
<!-------------------------------------------------------------------------->
<h2>SHPObject</h2>
An individual shape is represented by the SHPObject structure. SHPObject's
created with SHPCreateObject(), SHPCreateSimpleObject(), or SHPReadObject()
should be disposed of with SHPDestroyObject().<p>
<pre>
typedef struct
{
int nSHPType; Shape Type (SHPT_* - see list above)
int nShapeId; Shape Number (-1 is unknown/unassigned)
int nParts; # of Parts (0 implies single part with no info)
int *panPartStart; Start Vertex of part
int *panPartType; Part Type (SHPP_RING if not SHPT_MULTIPATCH)
int nVertices; Vertex list
double *padfX;
double *padfY;
double *padfZ; (all zero if not provided)
double *padfM; (all zero if not provided)
double dfXMin; Bounds in X, Y, Z and M dimensions
double dfYMin;
double dfZMin;
double dfMMin;
double dfXMax;
double dfYMax;
double dfZMax;
double dfMMax;
} SHPObject;
</pre>
<!-------------------------------------------------------------------------->
<h2>SHPOpen()</h2>
<pre>
SHPHandle SHPOpen( const char * pszShapeFile, const char * pszAccess );
pszShapeFile: The name of the layer to access. This can be the
name of either the .shp or the .shx file or can
just be the path plus the basename of the pair.
pszAccess: The fopen() style access string. At this time only
"rb" (read-only binary) and "rb+" (read/write binary)
should be used.
</pre>
The SHPOpen() function should be used to establish access to the two files
for accessing vertices (.shp and .shx). Note that both files have to
be in the indicated directory, and must have the expected extensions in
lower case. The returned SHPHandle is passed to other access functions,
and SHPClose() should be invoked to recover resources, and flush changes
to disk when complete.<p>
<!-------------------------------------------------------------------------->
<h2>SHPGetInfo()</h2>
<pre>
void SHPGetInfo( SHPHandle hSHP, int * pnEntities, int * pnShapeType,
double * padfMinBound, double * padfMaxBound );
hSHP: The handle previously returned by SHPOpen()
or SHPCreate().
pnEntities: A pointer to an integer into which the number of
entities/structures should be placed. May be NULL.
pnShapetype: A pointer to an integer into which the shapetype
of this file should be placed. Shapefiles may contain
either SHPT_POINT, SHPT_ARC, SHPT_POLYGON or
SHPT_MULTIPOINT entities. This may be NULL.
padfMinBound: The X, Y, Z and M minimum values will be placed into
this four entry array. This may be NULL.
padfMaxBound: The X, Y, Z and M maximum values will be placed into
this four entry array. This may be NULL.
</pre>
The SHPGetInfo() function retrieves various information about shapefile
as a whole. The bounds are read from the file header, and may be
inaccurate if the file was improperly generated. <p>
<!-------------------------------------------------------------------------->
<h2>SHPReadObject()</h2>
<pre>
SHPObject *SHPReadObject( SHPHandle hSHP, int iShape );
hSHP: The handle previously returned by SHPOpen()
or SHPCreate().
iShape: The entity number of the shape to read. Entity
numbers are between 0 and nEntities-1 (as returned
by SHPGetInfo()).
</pre>
The SHPReadObject() call is used to read a single structure, or entity
from the shapefile. See the definition of the SHPObject structure for
detailed information on fields of a SHPObject. SHPObject's returned from
SHPReadObject() should be deallocated with SHPDestroyShape().
SHPReadObject() will return NULL if an illegal iShape value is requested.<p>
Note that the bounds placed into the SHPObject are those read from the
file, and may not be correct. For points the bounds are generated from
the single point since bounds aren't normally provided for point types.<p>
Generally the shapes returned will be of the type of the file as a whole.
However, any file may also contain type SHPT_NULL shapes which will have
no geometry. Generally speaking applications should skip rather than
preserve them, as they usually represented interactively deleted shapes.<p>
<!-------------------------------------------------------------------------->
<h2>SHPClose()</h2>
<pre>
void SHPClose( SHPHandle hSHP );
hSHP: The handle previously returned by SHPOpen()
or SHPCreate().
</pre>
The SHPClose() function will close the .shp and .shx files, and flush
all outstanding header information to the files. It will also recover
resources associated with the handle. After this call the hSHP handle
cannot be used again.<p>
<!-------------------------------------------------------------------------->
<h2>SHPCreate()</h2>
<pre>
SHPHandle SHPCreate( const char * pszShapeFile, int nShapeType );
pszShapeFile: The name of the layer to access. This can be the
name of either the .shp or the .shx file or can
just be the path plus the basename of the pair.
nShapeType: The type of shapes to be stored in the newly created
file. It may be either SHPT_POINT, SHPT_ARC,
SHPT_POLYGON or SHPT_MULTIPOINT.
</pre>
The SHPCreate() function will create a new .shp and .shx file of the
desired type.<p>
<!-------------------------------------------------------------------------->
<h2>SHPCreateSimpleObject()</h2>
<pre>
SHPObject *
SHPCreateSimpleObject( int nSHPType, int nVertices,
double *padfX, double * padfY, double *padfZ, );
nSHPType: The SHPT_ type of the object to be created, such
as SHPT_POINT, or SHPT_POLYGON.
nVertices: The number of vertices being passed in padfX,
padfY, and padfZ.
padfX: An array of nVertices X coordinates of the vertices
for this object.
padfY: An array of nVertices Y coordinates of the vertices
for this object.
padfZ: An array of nVertices Z coordinates of the vertices
for this object. This may be NULL in which case
they are all assumed to be zero.
</pre>
The SHPCreateSimpleObject() allows for the convenient creation of
simple objects. This is normally used so that the SHPObject can be
passed to SHPWriteObject() to write it to the file. The simple object
creation API assumes an M (measure) value of zero for each vertex. For
complex objects (such as polygons) it is assumed that there is only one
part, and that it is of the default type (SHPP_RING). <p>
Use the SHPCreateObject() function for more sophisticated objects. The
SHPDestroyObject() function should be used to free resources associated with
an object allocated with SHPCreateSimpleObject(). <p>
This function computes a bounding box for the SHPObject from the given
vertices.<p>
<!-------------------------------------------------------------------------->
<h2>SHPCreateObject()</h2>
<pre>
SHPObject *
SHPCreateObject( int nSHPType, int iShape,
int nParts, int * panPartStart, int * panPartType,
int nVertices, double *padfX, double * padfY,
double *padfZ, double *padfM );
nSHPType: The SHPT_ type of the object to be created, such
as SHPT_POINT, or SHPT_POLYGON.
iShape: The shapeid to be recorded with this shape.
nParts: The number of parts for this object. If this is
zero for ARC, or POLYGON type objects, a single
zero valued part will be created internally.
panPartStart: The list of zero based start vertices for the rings
(parts) in this object. The first should always be
zero. This may be NULL if nParts is 0.
panPartType: The type of each of the parts. This is only meaningful
for MULTIPATCH files. For all other cases this may
be NULL, and will be assumed to be SHPP_RING.
nVertices: The number of vertices being passed in padfX,
padfY, and padfZ.
padfX: An array of nVertices X coordinates of the vertices
for this object.
padfY: An array of nVertices Y coordinates of the vertices
for this object.
padfZ: An array of nVertices Z coordinates of the vertices
for this object. This may be NULL in which case
they are all assumed to be zero.
padfM: An array of nVertices M (measure values) of the
vertices for this object. This may be NULL in which
case they are all assumed to be zero.
</pre>
The SHPCreateSimpleObject() allows for the creation of objects (shapes).
This is normally used so that the SHPObject can be passed to
SHPWriteObject() to write it to the file. <p>
The SHPDestroyObject() function should be used to free resources associated
with an object allocated with SHPCreateObject(). <p>
This function computes a bounding box for the SHPObject from the given
vertices.<p>
<!-------------------------------------------------------------------------->
<h2>SHPComputeExtents()</h2>
<pre>
void SHPComputeExtents( SHPObject * psObject );
psObject: An existing shape object to be updated in place.
</pre>
This function will recompute the extents of this shape, replacing the
existing values of the dfXMin, dfYMin, dfZMin, dfMMin, dfXMax, dfYMax,
dfZMax, and dfMMax values based on the current set of vertices for the
shape. This function is automatically called by SHPCreateObject() but
if the vertices of an existing object are altered it should be called again
to fix up the extents.<p>
<!-------------------------------------------------------------------------->
<h2>SHPWriteObject()</h2>
<pre>
int SHPWriteObject( SHPHandle hSHP, int iShape, SHPObject *psObject );
hSHP: The handle previously returned by SHPOpen("r+")
or SHPCreate().
iShape: The entity number of the shape to write. A value of
-1 should be used for new shapes.
psObject: The shape to write to the file. This should have
been created with SHPCreateObject(), or
SHPCreateSimpleObject().
</pre>
The SHPWriteObject() call is used to write a single structure, or entity
to the shapefile. See the definition of the SHPObject structure for
detailed information on fields of a SHPObject. The return value is the
entity number of the written shape. <p>
<!-------------------------------------------------------------------------->
<h2>SHPDestroyObject()</h2>
<pre>
void SHPDestroyObject( SHPObject *psObject );
psObject: The object to deallocate.
</pre>
This function should be used to deallocate the resources associated with
a SHPObject when it is no longer needed, including those created with
SHPCreateSimpleObject(), SHPCreateObject() and returned from SHPReadObject().
<p>
<!-------------------------------------------------------------------------->
<h2>SHPRewindObject()</h2>
<pre>
int SHPRewindObject( SHPHandle hSHP, SHPObject *psObject );
hSHP: The shapefile (not used at this time).
psObject: The object to deallocate.
</pre>
This function will reverse any rings necessary in order to enforce the
shapefile restrictions on the required order of inner and outer rings in
the Shapefile specification. It returns TRUE if a change is made and FALSE
if no change is made. Only polygon objects will be affected though any
object may be passed.
<p>
</body>
</html>

View file

@ -1,171 +0,0 @@
/******************************************************************************
* $Id: shpadd.c,v 1.13 2002/01/15 14:36:07 warmerda Exp $
*
* Project: Shapelib
* Purpose: Sample application for adding a shape to a shapefile.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: shpadd.c,v $
* Revision 1.13 2002/01/15 14:36:07 warmerda
* updated email address
*
* Revision 1.12 2001/05/31 19:35:29 warmerda
* added support for writing null shapes
*
* Revision 1.11 2000/07/07 13:39:45 warmerda
* removed unused variables, and added system include files
*
* Revision 1.10 2000/05/24 15:09:22 warmerda
* Added logic to graw vertex lists of needed.
*
* Revision 1.9 1999/11/05 14:12:04 warmerda
* updated license terms
*
* Revision 1.8 1998/12/03 16:36:26 warmerda
* Use r+b rather than rb+ for binary access.
*
* Revision 1.7 1998/11/09 20:57:04 warmerda
* Fixed SHPGetInfo() call.
*
* Revision 1.6 1998/11/09 20:19:16 warmerda
* Changed to use SHPObject based API.
*
* Revision 1.5 1997/03/06 14:05:02 warmerda
* fixed typo.
*
* Revision 1.4 1997/03/06 14:01:16 warmerda
* added memory allocation checking, and free()s.
*
* Revision 1.3 1995/10/21 03:14:37 warmerda
* Changed to use binary file access
*
* Revision 1.2 1995/08/04 03:18:01 warmerda
* Added header.
*
*/
static char rcsid[] =
"$Id: shpadd.c,v 1.13 2002/01/15 14:36:07 warmerda Exp $";
#include <stdlib.h>
#include <string.h>
#include "shapefil.h"
int main( int argc, char ** argv )
{
SHPHandle hSHP;
int nShapeType, nVertices, nParts, *panParts, i, nVMax;
double *padfX, *padfY;
SHPObject *psObject;
/* -------------------------------------------------------------------- */
/* Display a usage message. */
/* -------------------------------------------------------------------- */
if( argc < 2 )
{
printf( "shpadd shp_file [[x y] [+]]*\n" );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Open the passed shapefile. */
/* -------------------------------------------------------------------- */
hSHP = SHPOpen( argv[1], "r+b" );
if( hSHP == NULL )
{
printf( "Unable to open:%s\n", argv[1] );
exit( 1 );
}
SHPGetInfo( hSHP, NULL, &nShapeType, NULL, NULL );
if( argc == 2 )
nShapeType = SHPT_NULL;
/* -------------------------------------------------------------------- */
/* Build a vertex/part list from the command line arguments. */
/* -------------------------------------------------------------------- */
nVMax = 1000;
padfX = (double *) malloc(sizeof(double) * nVMax);
padfY = (double *) malloc(sizeof(double) * nVMax);
nVertices = 0;
if( (panParts = (int *) malloc(sizeof(int) * 1000 )) == NULL )
{
printf( "Out of memory\n" );
exit( 1 );
}
nParts = 1;
panParts[0] = 0;
for( i = 2; i < argc; )
{
if( argv[i][0] == '+' )
{
panParts[nParts++] = nVertices;
i++;
}
else if( i < argc-1 )
{
if( nVertices == nVMax )
{
nVMax = nVMax * 2;
padfX = (double *) realloc(padfX,sizeof(double)*nVMax);
padfY = (double *) realloc(padfY,sizeof(double)*nVMax);
}
sscanf( argv[i], "%lg", padfX+nVertices );
sscanf( argv[i+1], "%lg", padfY+nVertices );
nVertices += 1;
i += 2;
}
}
/* -------------------------------------------------------------------- */
/* Write the new entity to the shape file. */
/* -------------------------------------------------------------------- */
psObject = SHPCreateObject( nShapeType, -1, nParts, panParts, NULL,
nVertices, padfX, padfY, NULL, NULL );
SHPWriteObject( hSHP, -1, psObject );
SHPDestroyObject( psObject );
SHPClose( hSHP );
free( panParts );
free( padfX );
free( padfY );
return 0;
}

View file

@ -1,103 +0,0 @@
/******************************************************************************
* $Id: shpcreate.c,v 1.5 2002/01/15 14:36:07 warmerda Exp $
*
* Project: Shapelib
* Purpose: Sample application for creating a new shapefile.
* Author: Frank Warmerdam, warmerdm@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: shpcreate.c,v $
* Revision 1.5 2002/01/15 14:36:07 warmerda
* updated email address
*
* Revision 1.4 2000/07/07 13:39:45 warmerda
* removed unused variables, and added system include files
*
* Revision 1.3 1999/11/05 14:12:04 warmerda
* updated license terms
*
* Revision 1.2 1995/08/04 03:16:43 warmerda
* Added header.
*
*/
static char rcsid[] =
"$Id: shpcreate.c,v 1.5 2002/01/15 14:36:07 warmerda Exp $";
#include <stdlib.h>
#include "shapefil.h"
int main( int argc, char ** argv )
{
SHPHandle hSHP;
int nShapeType;
/* -------------------------------------------------------------------- */
/* Display a usage message. */
/* -------------------------------------------------------------------- */
if( argc != 3 )
{
printf( "shpcreate shp_file [point/arc/polygon/multipoint]\n" );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Figure out the shape type. */
/* -------------------------------------------------------------------- */
if( strcmp(argv[2],"POINT") == 0 || strcmp(argv[2],"point") == 0 )
nShapeType = SHPT_POINT;
else if( strcmp(argv[2],"ARC") == 0 || strcmp(argv[2],"arc") == 0 )
nShapeType = SHPT_ARC;
else if( strcmp(argv[2],"POLYGON") == 0 || strcmp(argv[2],"polygon") == 0 )
nShapeType = SHPT_POLYGON;
else if( strcmp(argv[2],"MULTIPOINT")==0 ||strcmp(argv[2],"multipoint")==0)
nShapeType = SHPT_MULTIPOINT;
else
{
printf( "Shape Type `%s' not recognised.\n", argv[2] );
exit( 2 );
}
/* -------------------------------------------------------------------- */
/* Create the requested layer. */
/* -------------------------------------------------------------------- */
hSHP = SHPCreate( argv[1], nShapeType );
if( hSHP == NULL )
{
printf( "Unable to create:%s\n", argv[1] );
exit( 3 );
}
SHPClose( hSHP );
return 0;
}

View file

@ -1,200 +0,0 @@
/******************************************************************************
* $Id: shpdump.c,v 1.10 2002/04/10 16:59:29 warmerda Exp $
*
* Project: Shapelib
* Purpose: Sample application for dumping contents of a shapefile to
* the terminal in human readable form.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: shpdump.c,v $
* Revision 1.10 2002/04/10 16:59:29 warmerda
* added -validate switch
*
* Revision 1.9 2002/01/15 14:36:07 warmerda
* updated email address
*
* Revision 1.8 2000/07/07 13:39:45 warmerda
* removed unused variables, and added system include files
*
* Revision 1.7 1999/11/05 14:12:04 warmerda
* updated license terms
*
* Revision 1.6 1998/12/03 15:48:48 warmerda
* Added report of shapefile type, and total number of shapes.
*
* Revision 1.5 1998/11/09 20:57:36 warmerda
* use SHPObject.
*
* Revision 1.4 1995/10/21 03:14:49 warmerda
* Changed to use binary file access.
*
* Revision 1.3 1995/08/23 02:25:25 warmerda
* Added support for bounds.
*
* Revision 1.2 1995/08/04 03:18:11 warmerda
* Added header.
*
*/
static char rcsid[] =
"$Id: shpdump.c,v 1.10 2002/04/10 16:59:29 warmerda Exp $";
#include <stdlib.h>
#include "shapefil.h"
int main( int argc, char ** argv )
{
SHPHandle hSHP;
int nShapeType, nEntities, i, iPart, bValidate = 0,nInvalidCount=0;
const char *pszPlus;
double adfMinBound[4], adfMaxBound[4];
if( argc > 1 && strcmp(argv[1],"-validate") == 0 )
{
bValidate = 1;
argv++;
argc--;
}
/* -------------------------------------------------------------------- */
/* Display a usage message. */
/* -------------------------------------------------------------------- */
if( argc != 2 )
{
printf( "shpdump [-validate] shp_file\n" );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Open the passed shapefile. */
/* -------------------------------------------------------------------- */
hSHP = SHPOpen( argv[1], "rb" );
if( hSHP == NULL )
{
printf( "Unable to open:%s\n", argv[1] );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Print out the file bounds. */
/* -------------------------------------------------------------------- */
SHPGetInfo( hSHP, &nEntities, &nShapeType, adfMinBound, adfMaxBound );
printf( "Shapefile Type: %s # of Shapes: %d\n\n",
SHPTypeName( nShapeType ), nEntities );
printf( "File Bounds: (%12.3f,%12.3f,%g,%g)\n"
" to (%12.3f,%12.3f,%g,%g)\n",
adfMinBound[0],
adfMinBound[1],
adfMinBound[2],
adfMinBound[3],
adfMaxBound[0],
adfMaxBound[1],
adfMaxBound[2],
adfMaxBound[3] );
/* -------------------------------------------------------------------- */
/* Skim over the list of shapes, printing all the vertices. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nEntities; i++ )
{
int j;
SHPObject *psShape;
psShape = SHPReadObject( hSHP, i );
printf( "\nShape:%d (%s) nVertices=%d, nParts=%d\n"
" Bounds:(%12.3f,%12.3f, %g, %g)\n"
" to (%12.3f,%12.3f, %g, %g)\n",
i, SHPTypeName(psShape->nSHPType),
psShape->nVertices, psShape->nParts,
psShape->dfXMin, psShape->dfYMin,
psShape->dfZMin, psShape->dfMMin,
psShape->dfXMax, psShape->dfYMax,
psShape->dfZMax, psShape->dfMMax );
for( j = 0, iPart = 1; j < psShape->nVertices; j++ )
{
const char *pszPartType = "";
if( j == 0 && psShape->nParts > 0 )
pszPartType = SHPPartTypeName( psShape->panPartType[0] );
if( iPart < psShape->nParts
&& psShape->panPartStart[iPart] == j )
{
pszPartType = SHPPartTypeName( psShape->panPartType[iPart] );
iPart++;
pszPlus = "+";
}
else
pszPlus = " ";
printf(" %s (%12.3f,%12.3f, %g, %g) %s \n",
pszPlus,
psShape->padfX[j],
psShape->padfY[j],
psShape->padfZ[j],
psShape->padfM[j],
pszPartType );
}
if( bValidate )
{
int nAltered = SHPRewindObject( hSHP, psShape );
if( nAltered > 0 )
{
printf( " %d rings wound in the wrong direction.\n",
nAltered );
nInvalidCount++;
}
}
SHPDestroyObject( psShape );
}
SHPClose( hSHP );
if( bValidate )
{
printf( "%d object has invalid ring orderings.\n", nInvalidCount );
}
#ifdef USE_DBMALLOC
malloc_dump(2);
#endif
exit( 0 );
}

File diff suppressed because it is too large Load diff

View file

@ -1,109 +0,0 @@
/******************************************************************************
* $Id: shprewind.c,v 1.2 2002/04/10 17:23:11 warmerda Exp $
*
* Project: Shapelib
* Purpose: Utility to validate and reset the winding order of rings in
* polygon geometries to match the ordering required by spec.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 2002, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: shprewind.c,v $
* Revision 1.2 2002/04/10 17:23:11 warmerda
* copy from source to destination now
*
* Revision 1.1 2002/04/10 16:56:36 warmerda
* New
*
*/
#include "shapefil.h"
int main( int argc, char ** argv )
{
SHPHandle hSHP, hSHPOut;
int nShapeType, nEntities, i, nInvalidCount=0;
double adfMinBound[4], adfMaxBound[4];
/* -------------------------------------------------------------------- */
/* Display a usage message. */
/* -------------------------------------------------------------------- */
if( argc != 3 )
{
printf( "shprewind in_shp_file out_shp_file\n" );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Open the passed shapefile. */
/* -------------------------------------------------------------------- */
hSHP = SHPOpen( argv[1], "rb" );
if( hSHP == NULL )
{
printf( "Unable to open:%s\n", argv[1] );
exit( 1 );
}
SHPGetInfo( hSHP, &nEntities, &nShapeType, adfMinBound, adfMaxBound );
/* -------------------------------------------------------------------- */
/* Create output shapefile. */
/* -------------------------------------------------------------------- */
hSHPOut = SHPCreate( argv[2], nShapeType );
if( hSHPOut == NULL )
{
printf( "Unable to create:%s\n", argv[2] );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Skim over the list of shapes, printing all the vertices. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nEntities; i++ )
{
int j;
SHPObject *psShape;
psShape = SHPReadObject( hSHP, i );
if( SHPRewindObject( hSHP, psShape ) )
nInvalidCount++;
SHPWriteObject( hSHPOut, -1, psShape );
SHPDestroyObject( psShape );
}
SHPClose( hSHP );
SHPClose( hSHPOut );
printf( "%d objects rewound.\n", nInvalidCount );
exit( 0 );
}

View file

@ -1,307 +0,0 @@
/******************************************************************************
* $Id: shptest.c,v 1.6 2002/01/15 14:36:07 warmerda Exp $
*
* Project: Shapelib
* Purpose: Application for generating sample Shapefiles of various types.
* Used by the stream2.sh test script.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: shptest.c,v $
* Revision 1.6 2002/01/15 14:36:07 warmerda
* updated email address
*
* Revision 1.5 2001/06/22 02:18:20 warmerda
* Added null shape support
*
* Revision 1.4 2000/07/07 13:39:45 warmerda
* removed unused variables, and added system include files
*
* Revision 1.3 1999/11/05 14:12:05 warmerda
* updated license terms
*
* Revision 1.2 1998/12/16 05:15:20 warmerda
* Added support for writing multipatch.
*
* Revision 1.1 1998/11/09 20:18:42 warmerda
* Initial revision
*
*/
static char rcsid[] =
"$Id: shptest.c,v 1.6 2002/01/15 14:36:07 warmerda Exp $";
#include <stdlib.h>
#include <string.h>
#include "shapefil.h"
/************************************************************************/
/* Test_WritePoints() */
/* */
/* Write a small point file. */
/************************************************************************/
static void Test_WritePoints( int nSHPType, const char *pszFilename )
{
SHPHandle hSHPHandle;
SHPObject *psShape;
double x, y, z, m;
hSHPHandle = SHPCreate( pszFilename, nSHPType );
x = 1.0;
y = 2.0;
z = 3.0;
m = 4.0;
psShape = SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
1, &x, &y, &z, &m );
SHPWriteObject( hSHPHandle, -1, psShape );
SHPDestroyObject( psShape );
x = 10.0;
y = 20.0;
z = 30.0;
m = 40.0;
psShape = SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
1, &x, &y, &z, &m );
SHPWriteObject( hSHPHandle, -1, psShape );
SHPDestroyObject( psShape );
SHPClose( hSHPHandle );
}
/************************************************************************/
/* Test_WriteMultiPoints() */
/* */
/* Write a small multipoint file. */
/************************************************************************/
static void Test_WriteMultiPoints( int nSHPType, const char *pszFilename )
{
SHPHandle hSHPHandle;
SHPObject *psShape;
double x[4], y[4], z[4], m[4];
int i, iShape;
hSHPHandle = SHPCreate( pszFilename, nSHPType );
for( iShape = 0; iShape < 3; iShape++ )
{
for( i = 0; i < 4; i++ )
{
x[i] = iShape * 10 + i + 1.15;
y[i] = iShape * 10 + i + 2.25;
z[i] = iShape * 10 + i + 3.35;
m[i] = iShape * 10 + i + 4.45;
}
psShape = SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
4, x, y, z, m );
SHPWriteObject( hSHPHandle, -1, psShape );
SHPDestroyObject( psShape );
}
SHPClose( hSHPHandle );
}
/************************************************************************/
/* Test_WriteArcPoly() */
/* */
/* Write a small arc or polygon file. */
/************************************************************************/
static void Test_WriteArcPoly( int nSHPType, const char *pszFilename )
{
SHPHandle hSHPHandle;
SHPObject *psShape;
double x[100], y[100], z[100], m[100];
int anPartStart[100];
int anPartType[100], *panPartType;
int i, iShape;
hSHPHandle = SHPCreate( pszFilename, nSHPType );
if( nSHPType == SHPT_MULTIPATCH )
panPartType = anPartType;
else
panPartType = NULL;
for( iShape = 0; iShape < 3; iShape++ )
{
x[0] = 1.0;
y[0] = 1.0+iShape*3;
x[1] = 2.0;
y[1] = 1.0+iShape*3;
x[2] = 2.0;
y[2] = 2.0+iShape*3;
x[3] = 1.0;
y[3] = 2.0+iShape*3;
x[4] = 1.0;
y[4] = 1.0+iShape*3;
for( i = 0; i < 5; i++ )
{
z[i] = iShape * 10 + i + 3.35;
m[i] = iShape * 10 + i + 4.45;
}
psShape = SHPCreateObject( nSHPType, -1, 0, NULL, NULL,
5, x, y, z, m );
SHPWriteObject( hSHPHandle, -1, psShape );
SHPDestroyObject( psShape );
}
/* -------------------------------------------------------------------- */
/* Do a multi part polygon (shape). We close it, and have two */
/* inner rings. */
/* -------------------------------------------------------------------- */
x[0] = 0.0;
y[0] = 0.0;
x[1] = 0;
y[1] = 100;
x[2] = 100;
y[2] = 100;
x[3] = 100;
y[3] = 0;
x[4] = 0;
y[4] = 0;
x[5] = 10;
y[5] = 20;
x[6] = 30;
y[6] = 20;
x[7] = 30;
y[7] = 40;
x[8] = 10;
y[8] = 40;
x[9] = 10;
y[9] = 20;
x[10] = 60;
y[10] = 20;
x[11] = 90;
y[11] = 20;
x[12] = 90;
y[12] = 40;
x[13] = 60;
y[13] = 40;
x[14] = 60;
y[14] = 20;
for( i = 0; i < 15; i++ )
{
z[i] = i;
m[i] = i*2;
}
anPartStart[0] = 0;
anPartStart[1] = 5;
anPartStart[2] = 10;
anPartType[0] = SHPP_RING;
anPartType[1] = SHPP_INNERRING;
anPartType[2] = SHPP_INNERRING;
psShape = SHPCreateObject( nSHPType, -1, 3, anPartStart, panPartType,
15, x, y, z, m );
SHPWriteObject( hSHPHandle, -1, psShape );
SHPDestroyObject( psShape );
SHPClose( hSHPHandle );
}
/************************************************************************/
/* main() */
/************************************************************************/
int main( int argc, char ** argv )
{
/* -------------------------------------------------------------------- */
/* Display a usage message. */
/* -------------------------------------------------------------------- */
if( argc != 2 )
{
printf( "shptest test_number\n" );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Figure out which test to run. */
/* -------------------------------------------------------------------- */
if( atoi(argv[1]) == 0 )
Test_WritePoints( SHPT_NULL, "test0.shp" );
else if( atoi(argv[1]) == 1 )
Test_WritePoints( SHPT_POINT, "test1.shp" );
else if( atoi(argv[1]) == 2 )
Test_WritePoints( SHPT_POINTZ, "test2.shp" );
else if( atoi(argv[1]) == 3 )
Test_WritePoints( SHPT_POINTM, "test3.shp" );
else if( atoi(argv[1]) == 4 )
Test_WriteMultiPoints( SHPT_MULTIPOINT, "test4.shp" );
else if( atoi(argv[1]) == 5 )
Test_WriteMultiPoints( SHPT_MULTIPOINTZ, "test5.shp" );
else if( atoi(argv[1]) == 6 )
Test_WriteMultiPoints( SHPT_MULTIPOINTM, "test6.shp" );
else if( atoi(argv[1]) == 7 )
Test_WriteArcPoly( SHPT_ARC, "test7.shp" );
else if( atoi(argv[1]) == 8 )
Test_WriteArcPoly( SHPT_ARCZ, "test8.shp" );
else if( atoi(argv[1]) == 9 )
Test_WriteArcPoly( SHPT_ARCM, "test9.shp" );
else if( atoi(argv[1]) == 10 )
Test_WriteArcPoly( SHPT_POLYGON, "test10.shp" );
else if( atoi(argv[1]) == 11 )
Test_WriteArcPoly( SHPT_POLYGONZ, "test11.shp" );
else if( atoi(argv[1]) == 12 )
Test_WriteArcPoly( SHPT_POLYGONM, "test12.shp" );
else if( atoi(argv[1]) == 13 )
Test_WriteArcPoly( SHPT_MULTIPATCH, "test13.shp" );
else
{
printf( "Test `%s' not recognised.\n", argv[1] );
exit( 10 );
}
#ifdef USE_DBMALLOC
malloc_dump(2);
#endif
exit( 0 );
}

View file

@ -1,679 +0,0 @@
/******************************************************************************
* $Id: shptree.c,v 1.9 2003/01/28 15:53:41 warmerda Exp $
*
* Project: Shapelib
* Purpose: Implementation of quadtree building and searching functions.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: shptree.c,v $
* Revision 1.9 2003/01/28 15:53:41 warmerda
* Avoid build warnings.
*
* Revision 1.8 2002/05/07 13:07:45 warmerda
* use qsort() - patch from Bernhard Herzog
*
* Revision 1.7 2002/01/15 14:36:07 warmerda
* updated email address
*
* Revision 1.6 2001/05/23 13:36:52 warmerda
* added use of SHPAPI_CALL
*
* Revision 1.5 1999/11/05 14:12:05 warmerda
* updated license terms
*
* Revision 1.4 1999/06/02 18:24:21 warmerda
* added trimming code
*
* Revision 1.3 1999/06/02 17:56:12 warmerda
* added quad'' subnode support for trees
*
* Revision 1.2 1999/05/18 19:11:11 warmerda
* Added example searching capability
*
* Revision 1.1 1999/05/18 17:49:20 warmerda
* New
*
*/
static char rcsid[] =
"$Id: shptree.c,v 1.9 2003/01/28 15:53:41 warmerda Exp $";
#include "shapefil.h"
#include <math.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#ifndef TRUE
# define TRUE 1
# define FALSE 0
#endif
/* -------------------------------------------------------------------- */
/* If the following is 0.5, nodes will be split in half. If it */
/* is 0.6 then each subnode will contain 60% of the parent */
/* node, with 20% representing overlap. This can be help to */
/* prevent small objects on a boundary from shifting too high */
/* up the tree. */
/* -------------------------------------------------------------------- */
#define SHP_SPLIT_RATIO 0.55
/************************************************************************/
/* SfRealloc() */
/* */
/* A realloc cover function that will access a NULL pointer as */
/* a valid input. */
/************************************************************************/
static void * SfRealloc( void * pMem, int nNewSize )
{
if( pMem == NULL )
return( (void *) malloc(nNewSize) );
else
return( (void *) realloc(pMem,nNewSize) );
}
/************************************************************************/
/* SHPTreeNodeInit() */
/* */
/* Initialize a tree node. */
/************************************************************************/
static SHPTreeNode *SHPTreeNodeCreate( double * padfBoundsMin,
double * padfBoundsMax )
{
SHPTreeNode *psTreeNode;
psTreeNode = (SHPTreeNode *) malloc(sizeof(SHPTreeNode));
psTreeNode->nShapeCount = 0;
psTreeNode->panShapeIds = NULL;
psTreeNode->papsShapeObj = NULL;
psTreeNode->nSubNodes = 0;
if( padfBoundsMin != NULL )
memcpy( psTreeNode->adfBoundsMin, padfBoundsMin, sizeof(double) * 4 );
if( padfBoundsMax != NULL )
memcpy( psTreeNode->adfBoundsMax, padfBoundsMax, sizeof(double) * 4 );
return psTreeNode;
}
/************************************************************************/
/* SHPCreateTree() */
/************************************************************************/
SHPTree SHPAPI_CALL1(*)
SHPCreateTree( SHPHandle hSHP, int nDimension, int nMaxDepth,
double *padfBoundsMin, double *padfBoundsMax )
{
SHPTree *psTree;
if( padfBoundsMin == NULL && hSHP == NULL )
return NULL;
/* -------------------------------------------------------------------- */
/* Allocate the tree object */
/* -------------------------------------------------------------------- */
psTree = (SHPTree *) malloc(sizeof(SHPTree));
psTree->hSHP = hSHP;
psTree->nMaxDepth = nMaxDepth;
psTree->nDimension = nDimension;
/* -------------------------------------------------------------------- */
/* If no max depth was defined, try to select a reasonable one */
/* that implies approximately 8 shapes per node. */
/* -------------------------------------------------------------------- */
if( psTree->nMaxDepth == 0 && hSHP != NULL )
{
int nMaxNodeCount = 1;
int nShapeCount;
SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL );
while( nMaxNodeCount*4 < nShapeCount )
{
psTree->nMaxDepth += 1;
nMaxNodeCount = nMaxNodeCount * 2;
}
}
/* -------------------------------------------------------------------- */
/* Allocate the root node. */
/* -------------------------------------------------------------------- */
psTree->psRoot = SHPTreeNodeCreate( padfBoundsMin, padfBoundsMax );
/* -------------------------------------------------------------------- */
/* Assign the bounds to the root node. If none are passed in, */
/* use the bounds of the provided file otherwise the create */
/* function will have already set the bounds. */
/* -------------------------------------------------------------------- */
if( padfBoundsMin == NULL )
{
SHPGetInfo( hSHP, NULL, NULL,
psTree->psRoot->adfBoundsMin,
psTree->psRoot->adfBoundsMax );
}
/* -------------------------------------------------------------------- */
/* If we have a file, insert all it's shapes into the tree. */
/* -------------------------------------------------------------------- */
if( hSHP != NULL )
{
int iShape, nShapeCount;
SHPGetInfo( hSHP, &nShapeCount, NULL, NULL, NULL );
for( iShape = 0; iShape < nShapeCount; iShape++ )
{
SHPObject *psShape;
psShape = SHPReadObject( hSHP, iShape );
SHPTreeAddShapeId( psTree, psShape );
SHPDestroyObject( psShape );
}
}
return psTree;
}
/************************************************************************/
/* SHPDestroyTreeNode() */
/************************************************************************/
static void SHPDestroyTreeNode( SHPTreeNode * psTreeNode )
{
int i;
for( i = 0; i < psTreeNode->nSubNodes; i++ )
{
if( psTreeNode->apsSubNode[i] != NULL )
SHPDestroyTreeNode( psTreeNode->apsSubNode[i] );
}
if( psTreeNode->panShapeIds != NULL )
free( psTreeNode->panShapeIds );
if( psTreeNode->papsShapeObj != NULL )
{
for( i = 0; i < psTreeNode->nShapeCount; i++ )
{
if( psTreeNode->papsShapeObj[i] != NULL )
SHPDestroyObject( psTreeNode->papsShapeObj[i] );
}
free( psTreeNode->papsShapeObj );
}
free( psTreeNode );
}
/************************************************************************/
/* SHPDestroyTree() */
/************************************************************************/
void SHPAPI_CALL
SHPDestroyTree( SHPTree * psTree )
{
SHPDestroyTreeNode( psTree->psRoot );
free( psTree );
}
/************************************************************************/
/* SHPCheckBoundsOverlap() */
/* */
/* Do the given boxes overlap at all? */
/************************************************************************/
int SHPAPI_CALL
SHPCheckBoundsOverlap( double * padfBox1Min, double * padfBox1Max,
double * padfBox2Min, double * padfBox2Max,
int nDimension )
{
int iDim;
for( iDim = 0; iDim < nDimension; iDim++ )
{
if( padfBox2Max[iDim] < padfBox1Min[iDim] )
return FALSE;
if( padfBox1Max[iDim] < padfBox2Min[iDim] )
return FALSE;
}
return TRUE;
}
/************************************************************************/
/* SHPCheckObjectContained() */
/* */
/* Does the given shape fit within the indicated extents? */
/************************************************************************/
static int SHPCheckObjectContained( SHPObject * psObject, int nDimension,
double * padfBoundsMin, double * padfBoundsMax )
{
if( psObject->dfXMin < padfBoundsMin[0]
|| psObject->dfXMax > padfBoundsMax[0] )
return FALSE;
if( psObject->dfYMin < padfBoundsMin[1]
|| psObject->dfYMax > padfBoundsMax[1] )
return FALSE;
if( nDimension == 2 )
return TRUE;
if( psObject->dfZMin < padfBoundsMin[2]
|| psObject->dfZMax < padfBoundsMax[2] )
return FALSE;
if( nDimension == 3 )
return TRUE;
if( psObject->dfMMin < padfBoundsMin[3]
|| psObject->dfMMax < padfBoundsMax[3] )
return FALSE;
return TRUE;
}
/************************************************************************/
/* SHPTreeSplitBounds() */
/* */
/* Split a region into two subregion evenly, cutting along the */
/* longest dimension. */
/************************************************************************/
void SHPAPI_CALL
SHPTreeSplitBounds( double *padfBoundsMinIn, double *padfBoundsMaxIn,
double *padfBoundsMin1, double * padfBoundsMax1,
double *padfBoundsMin2, double * padfBoundsMax2 )
{
/* -------------------------------------------------------------------- */
/* The output bounds will be very similar to the input bounds, */
/* so just copy over to start. */
/* -------------------------------------------------------------------- */
memcpy( padfBoundsMin1, padfBoundsMinIn, sizeof(double) * 4 );
memcpy( padfBoundsMax1, padfBoundsMaxIn, sizeof(double) * 4 );
memcpy( padfBoundsMin2, padfBoundsMinIn, sizeof(double) * 4 );
memcpy( padfBoundsMax2, padfBoundsMaxIn, sizeof(double) * 4 );
/* -------------------------------------------------------------------- */
/* Split in X direction. */
/* -------------------------------------------------------------------- */
if( (padfBoundsMaxIn[0] - padfBoundsMinIn[0])
> (padfBoundsMaxIn[1] - padfBoundsMinIn[1]) )
{
double dfRange = padfBoundsMaxIn[0] - padfBoundsMinIn[0];
padfBoundsMax1[0] = padfBoundsMinIn[0] + dfRange * SHP_SPLIT_RATIO;
padfBoundsMin2[0] = padfBoundsMaxIn[0] - dfRange * SHP_SPLIT_RATIO;
}
/* -------------------------------------------------------------------- */
/* Otherwise split in Y direction. */
/* -------------------------------------------------------------------- */
else
{
double dfRange = padfBoundsMaxIn[1] - padfBoundsMinIn[1];
padfBoundsMax1[1] = padfBoundsMinIn[1] + dfRange * SHP_SPLIT_RATIO;
padfBoundsMin2[1] = padfBoundsMaxIn[1] - dfRange * SHP_SPLIT_RATIO;
}
}
/************************************************************************/
/* SHPTreeNodeAddShapeId() */
/************************************************************************/
static int
SHPTreeNodeAddShapeId( SHPTreeNode * psTreeNode, SHPObject * psObject,
int nMaxDepth, int nDimension )
{
int i;
/* -------------------------------------------------------------------- */
/* If there are subnodes, then consider wiether this object */
/* will fit in them. */
/* -------------------------------------------------------------------- */
if( nMaxDepth > 1 && psTreeNode->nSubNodes > 0 )
{
for( i = 0; i < psTreeNode->nSubNodes; i++ )
{
if( SHPCheckObjectContained(psObject, nDimension,
psTreeNode->apsSubNode[i]->adfBoundsMin,
psTreeNode->apsSubNode[i]->adfBoundsMax))
{
return SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[i],
psObject, nMaxDepth-1,
nDimension );
}
}
}
/* -------------------------------------------------------------------- */
/* Otherwise, consider creating four subnodes if could fit into */
/* them, and adding to the appropriate subnode. */
/* -------------------------------------------------------------------- */
#if MAX_SUBNODE == 4
else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 )
{
double adfBoundsMinH1[4], adfBoundsMaxH1[4];
double adfBoundsMinH2[4], adfBoundsMaxH2[4];
double adfBoundsMin1[4], adfBoundsMax1[4];
double adfBoundsMin2[4], adfBoundsMax2[4];
double adfBoundsMin3[4], adfBoundsMax3[4];
double adfBoundsMin4[4], adfBoundsMax4[4];
SHPTreeSplitBounds( psTreeNode->adfBoundsMin,
psTreeNode->adfBoundsMax,
adfBoundsMinH1, adfBoundsMaxH1,
adfBoundsMinH2, adfBoundsMaxH2 );
SHPTreeSplitBounds( adfBoundsMinH1, adfBoundsMaxH1,
adfBoundsMin1, adfBoundsMax1,
adfBoundsMin2, adfBoundsMax2 );
SHPTreeSplitBounds( adfBoundsMinH2, adfBoundsMaxH2,
adfBoundsMin3, adfBoundsMax3,
adfBoundsMin4, adfBoundsMax4 );
if( SHPCheckObjectContained(psObject, nDimension,
adfBoundsMin1, adfBoundsMax1)
|| SHPCheckObjectContained(psObject, nDimension,
adfBoundsMin2, adfBoundsMax2)
|| SHPCheckObjectContained(psObject, nDimension,
adfBoundsMin3, adfBoundsMax3)
|| SHPCheckObjectContained(psObject, nDimension,
adfBoundsMin4, adfBoundsMax4) )
{
psTreeNode->nSubNodes = 4;
psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
adfBoundsMax1 );
psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
adfBoundsMax2 );
psTreeNode->apsSubNode[2] = SHPTreeNodeCreate( adfBoundsMin3,
adfBoundsMax3 );
psTreeNode->apsSubNode[3] = SHPTreeNodeCreate( adfBoundsMin4,
adfBoundsMax4 );
/* recurse back on this node now that it has subnodes */
return( SHPTreeNodeAddShapeId( psTreeNode, psObject,
nMaxDepth, nDimension ) );
}
}
#endif /* MAX_SUBNODE == 4 */
/* -------------------------------------------------------------------- */
/* Otherwise, consider creating two subnodes if could fit into */
/* them, and adding to the appropriate subnode. */
/* -------------------------------------------------------------------- */
#if MAX_SUBNODE == 2
else if( nMaxDepth > 1 && psTreeNode->nSubNodes == 0 )
{
double adfBoundsMin1[4], adfBoundsMax1[4];
double adfBoundsMin2[4], adfBoundsMax2[4];
SHPTreeSplitBounds( psTreeNode->adfBoundsMin, psTreeNode->adfBoundsMax,
adfBoundsMin1, adfBoundsMax1,
adfBoundsMin2, adfBoundsMax2 );
if( SHPCheckObjectContained(psObject, nDimension,
adfBoundsMin1, adfBoundsMax1))
{
psTreeNode->nSubNodes = 2;
psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
adfBoundsMax1 );
psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
adfBoundsMax2 );
return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[0], psObject,
nMaxDepth - 1, nDimension ) );
}
else if( SHPCheckObjectContained(psObject, nDimension,
adfBoundsMin2, adfBoundsMax2) )
{
psTreeNode->nSubNodes = 2;
psTreeNode->apsSubNode[0] = SHPTreeNodeCreate( adfBoundsMin1,
adfBoundsMax1 );
psTreeNode->apsSubNode[1] = SHPTreeNodeCreate( adfBoundsMin2,
adfBoundsMax2 );
return( SHPTreeNodeAddShapeId( psTreeNode->apsSubNode[1], psObject,
nMaxDepth - 1, nDimension ) );
}
}
#endif /* MAX_SUBNODE == 2 */
/* -------------------------------------------------------------------- */
/* If none of that worked, just add it to this nodes list. */
/* -------------------------------------------------------------------- */
psTreeNode->nShapeCount++;
psTreeNode->panShapeIds =
SfRealloc( psTreeNode->panShapeIds,
sizeof(int) * psTreeNode->nShapeCount );
psTreeNode->panShapeIds[psTreeNode->nShapeCount-1] = psObject->nShapeId;
if( psTreeNode->papsShapeObj != NULL )
{
psTreeNode->papsShapeObj =
SfRealloc( psTreeNode->papsShapeObj,
sizeof(void *) * psTreeNode->nShapeCount );
psTreeNode->papsShapeObj[psTreeNode->nShapeCount-1] = NULL;
}
return TRUE;
}
/************************************************************************/
/* SHPTreeAddShapeId() */
/* */
/* Add a shape to the tree, but don't keep a pointer to the */
/* object data, just keep the shapeid. */
/************************************************************************/
int SHPAPI_CALL
SHPTreeAddShapeId( SHPTree * psTree, SHPObject * psObject )
{
return( SHPTreeNodeAddShapeId( psTree->psRoot, psObject,
psTree->nMaxDepth, psTree->nDimension ) );
}
/************************************************************************/
/* SHPTreeCollectShapesIds() */
/* */
/* Work function implementing SHPTreeFindLikelyShapes() on a */
/* tree node by tree node basis. */
/************************************************************************/
void SHPAPI_CALL
SHPTreeCollectShapeIds( SHPTree *hTree, SHPTreeNode * psTreeNode,
double * padfBoundsMin, double * padfBoundsMax,
int * pnShapeCount, int * pnMaxShapes,
int ** ppanShapeList )
{
int i;
/* -------------------------------------------------------------------- */
/* Does this node overlap the area of interest at all? If not, */
/* return without adding to the list at all. */
/* -------------------------------------------------------------------- */
if( !SHPCheckBoundsOverlap( psTreeNode->adfBoundsMin,
psTreeNode->adfBoundsMax,
padfBoundsMin,
padfBoundsMax,
hTree->nDimension ) )
return;
/* -------------------------------------------------------------------- */
/* Grow the list to hold the shapes on this node. */
/* -------------------------------------------------------------------- */
if( *pnShapeCount + psTreeNode->nShapeCount > *pnMaxShapes )
{
*pnMaxShapes = (*pnShapeCount + psTreeNode->nShapeCount) * 2 + 20;
*ppanShapeList = (int *)
SfRealloc(*ppanShapeList,sizeof(int) * *pnMaxShapes);
}
/* -------------------------------------------------------------------- */
/* Add the local nodes shapeids to the list. */
/* -------------------------------------------------------------------- */
for( i = 0; i < psTreeNode->nShapeCount; i++ )
{
(*ppanShapeList)[(*pnShapeCount)++] = psTreeNode->panShapeIds[i];
}
/* -------------------------------------------------------------------- */
/* Recurse to subnodes if they exist. */
/* -------------------------------------------------------------------- */
for( i = 0; i < psTreeNode->nSubNodes; i++ )
{
if( psTreeNode->apsSubNode[i] != NULL )
SHPTreeCollectShapeIds( hTree, psTreeNode->apsSubNode[i],
padfBoundsMin, padfBoundsMax,
pnShapeCount, pnMaxShapes,
ppanShapeList );
}
}
/************************************************************************/
/* SHPTreeFindLikelyShapes() */
/* */
/* Find all shapes within tree nodes for which the tree node */
/* bounding box overlaps the search box. The return value is */
/* an array of shapeids terminated by a -1. The shapeids will */
/* be in order, as hopefully this will result in faster (more */
/* sequential) reading from the file. */
/************************************************************************/
/* helper for qsort */
static int
compare_ints( const void * a, const void * b)
{
return (*(int*)a) - (*(int*)b);
}
int SHPAPI_CALL1(*)
SHPTreeFindLikelyShapes( SHPTree * hTree,
double * padfBoundsMin, double * padfBoundsMax,
int * pnShapeCount )
{
int *panShapeList=NULL, nMaxShapes = 0;
/* -------------------------------------------------------------------- */
/* Perform the search by recursive descent. */
/* -------------------------------------------------------------------- */
*pnShapeCount = 0;
SHPTreeCollectShapeIds( hTree, hTree->psRoot,
padfBoundsMin, padfBoundsMax,
pnShapeCount, &nMaxShapes,
&panShapeList );
/* -------------------------------------------------------------------- */
/* Sort the id array */
/* -------------------------------------------------------------------- */
qsort(panShapeList, *pnShapeCount, sizeof(int), compare_ints);
return panShapeList;
}
/************************************************************************/
/* SHPTreeNodeTrim() */
/* */
/* This is the recurve version of SHPTreeTrimExtraNodes() that */
/* walks the tree cleaning it up. */
/************************************************************************/
static int SHPTreeNodeTrim( SHPTreeNode * psTreeNode )
{
int i;
/* -------------------------------------------------------------------- */
/* Trim subtrees, and free subnodes that come back empty. */
/* -------------------------------------------------------------------- */
for( i = 0; i < psTreeNode->nSubNodes; i++ )
{
if( SHPTreeNodeTrim( psTreeNode->apsSubNode[i] ) )
{
SHPDestroyTreeNode( psTreeNode->apsSubNode[i] );
psTreeNode->apsSubNode[i] =
psTreeNode->apsSubNode[psTreeNode->nSubNodes-1];
psTreeNode->nSubNodes--;
i--; /* process the new occupant of this subnode entry */
}
}
/* -------------------------------------------------------------------- */
/* We should be trimmed if we have no subnodes, and no shapes. */
/* -------------------------------------------------------------------- */
return( psTreeNode->nSubNodes == 0 && psTreeNode->nShapeCount == 0 );
}
/************************************************************************/
/* SHPTreeTrimExtraNodes() */
/* */
/* Trim empty nodes from the tree. Note that we never trim an */
/* empty root node. */
/************************************************************************/
void SHPAPI_CALL
SHPTreeTrimExtraNodes( SHPTree * hTree )
{
SHPTreeNodeTrim( hTree->psRoot );
}

View file

@ -1,398 +0,0 @@
/******************************************************************************
* $Id: shptreedump.c,v 1.7 2002/04/10 16:59:12 warmerda Exp $
*
* Project: Shapelib
* Purpose: Mainline for creating and dumping an ASCII representation of
* a quadtree.
* Author: Frank Warmerdam, warmerdam@pobox.com
*
******************************************************************************
* Copyright (c) 1999, Frank Warmerdam
*
* This software is available under the following "MIT Style" license,
* or at the option of the licensee under the LGPL (see LICENSE.LGPL). This
* option is discussed in more detail in shapelib.html.
*
* --
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
******************************************************************************
*
* $Log: shptreedump.c,v $
* Revision 1.7 2002/04/10 16:59:12 warmerda
* fixed email
*
* Revision 1.6 1999/11/05 14:12:05 warmerda
* updated license terms
*
* Revision 1.5 1999/06/02 18:24:21 warmerda
* added trimming code
*
* Revision 1.4 1999/06/02 17:56:12 warmerda
* added quad'' subnode support for trees
*
* Revision 1.3 1999/05/18 19:13:13 warmerda
* Use fabs() instead of abs().
*
* Revision 1.2 1999/05/18 19:11:11 warmerda
* Added example searching capability
*
* Revision 1.1 1999/05/18 17:49:20 warmerda
* New
*
*/
static char rcsid[] =
"$Id: shptreedump.c,v 1.7 2002/04/10 16:59:12 warmerda Exp $";
#include "shapefil.h"
#include <assert.h>
#include <stdlib.h>
#include <math.h>
static void SHPTreeNodeDump( SHPTree *, SHPTreeNode *, const char *, int );
static void SHPTreeNodeSearchAndDump( SHPTree *, double *, double * );
/************************************************************************/
/* Usage() */
/************************************************************************/
static void Usage()
{
printf( "shptreedump [-maxdepth n] [-search xmin ymin xmax ymax]\n"
" [-v] shp_file\n" );
exit( 1 );
}
/************************************************************************/
/* main() */
/************************************************************************/
int main( int argc, char ** argv )
{
SHPHandle hSHP;
SHPTree *psTree;
int nExpandShapes = 0;
int nMaxDepth = 0;
int nDoSearch = 0;
double adfSearchMin[4], adfSearchMax[4];
/* -------------------------------------------------------------------- */
/* Consume flags. */
/* -------------------------------------------------------------------- */
while( argc > 1 )
{
if( strcmp(argv[1],"-v") == 0 )
{
nExpandShapes = 1;
argv++;
argc--;
}
else if( strcmp(argv[1],"-maxdepth") == 0 && argc > 2 )
{
nMaxDepth = atoi(argv[2]);
argv += 2;
argc -= 2;
}
else if( strcmp(argv[1],"-search") == 0 && argc > 5 )
{
nDoSearch = 1;
adfSearchMin[0] = atof(argv[2]);
adfSearchMin[1] = atof(argv[3]);
adfSearchMax[0] = atof(argv[4]);
adfSearchMax[1] = atof(argv[5]);
adfSearchMin[2] = adfSearchMax[2] = 0.0;
adfSearchMin[3] = adfSearchMax[3] = 0.0;
if( adfSearchMin[0] > adfSearchMax[0]
|| adfSearchMin[1] > adfSearchMax[1] )
{
printf( "Min greater than max in search criteria.\n" );
Usage();
}
argv += 5;
argc -= 5;
}
else
break;
}
/* -------------------------------------------------------------------- */
/* Display a usage message. */
/* -------------------------------------------------------------------- */
if( argc < 2 )
{
Usage();
}
/* -------------------------------------------------------------------- */
/* Open the passed shapefile. */
/* -------------------------------------------------------------------- */
hSHP = SHPOpen( argv[1], "rb" );
if( hSHP == NULL )
{
printf( "Unable to open:%s\n", argv[1] );
exit( 1 );
}
/* -------------------------------------------------------------------- */
/* Build a quadtree structure for this file. */
/* -------------------------------------------------------------------- */
psTree = SHPCreateTree( hSHP, 2, nMaxDepth, NULL, NULL );
/* -------------------------------------------------------------------- */
/* Trim unused nodes from the tree. */
/* -------------------------------------------------------------------- */
SHPTreeTrimExtraNodes( psTree );
/* -------------------------------------------------------------------- */
/* Dump tree by recursive descent. */
/* -------------------------------------------------------------------- */
if( !nDoSearch )
SHPTreeNodeDump( psTree, psTree->psRoot, "", nExpandShapes );
/* -------------------------------------------------------------------- */
/* or do a search instead. */
/* -------------------------------------------------------------------- */
else
SHPTreeNodeSearchAndDump( psTree, adfSearchMin, adfSearchMax );
/* -------------------------------------------------------------------- */
/* cleanup */
/* -------------------------------------------------------------------- */
SHPDestroyTree( psTree );
SHPClose( hSHP );
#ifdef USE_DBMALLOC
malloc_dump(2);
#endif
exit( 0 );
}
/************************************************************************/
/* EmitCoordinate() */
/************************************************************************/
static void EmitCoordinate( double * padfCoord, int nDimension )
{
const char *pszFormat;
if( fabs(padfCoord[0]) < 180 && fabs(padfCoord[1]) < 180 )
pszFormat = "%.9f";
else
pszFormat = "%.2f";
printf( pszFormat, padfCoord[0] );
printf( "," );
printf( pszFormat, padfCoord[1] );
if( nDimension > 2 )
{
printf( "," );
printf( pszFormat, padfCoord[2] );
}
if( nDimension > 3 )
{
printf( "," );
printf( pszFormat, padfCoord[3] );
}
}
/************************************************************************/
/* EmitShape() */
/************************************************************************/
static void EmitShape( SHPObject * psObject, const char * pszPrefix,
int nDimension )
{
int i;
printf( "%s( Shape\n", pszPrefix );
printf( "%s ShapeId = %d\n", pszPrefix, psObject->nShapeId );
printf( "%s Min = (", pszPrefix );
EmitCoordinate( &(psObject->dfXMin), nDimension );
printf( ")\n" );
printf( "%s Max = (", pszPrefix );
EmitCoordinate( &(psObject->dfXMax), nDimension );
printf( ")\n" );
for( i = 0; i < psObject->nVertices; i++ )
{
double adfVertex[4];
printf( "%s Vertex[%d] = (", pszPrefix, i );
adfVertex[0] = psObject->padfX[i];
adfVertex[1] = psObject->padfY[i];
adfVertex[2] = psObject->padfZ[i];
adfVertex[3] = psObject->padfM[i];
EmitCoordinate( adfVertex, nDimension );
printf( ")\n" );
}
printf( "%s)\n", pszPrefix );
}
/************************************************************************/
/* SHPTreeNodeDump() */
/* */
/* Dump a tree node in a readable form. */
/************************************************************************/
static void SHPTreeNodeDump( SHPTree * psTree,
SHPTreeNode * psTreeNode,
const char * pszPrefix,
int nExpandShapes )
{
char szNextPrefix[150];
int i;
strcpy( szNextPrefix, pszPrefix );
if( strlen(pszPrefix) < sizeof(szNextPrefix) - 3 )
strcat( szNextPrefix, " " );
printf( "%s( SHPTreeNode\n", pszPrefix );
/* -------------------------------------------------------------------- */
/* Emit the bounds. */
/* -------------------------------------------------------------------- */
printf( "%s Min = (", pszPrefix );
EmitCoordinate( psTreeNode->adfBoundsMin, psTree->nDimension );
printf( ")\n" );
printf( "%s Max = (", pszPrefix );
EmitCoordinate( psTreeNode->adfBoundsMax, psTree->nDimension );
printf( ")\n" );
/* -------------------------------------------------------------------- */
/* Emit the list of shapes on this node. */
/* -------------------------------------------------------------------- */
if( nExpandShapes )
{
printf( "%s Shapes(%d):\n", pszPrefix, psTreeNode->nShapeCount );
for( i = 0; i < psTreeNode->nShapeCount; i++ )
{
SHPObject *psObject;
psObject = SHPReadObject( psTree->hSHP,
psTreeNode->panShapeIds[i] );
assert( psObject != NULL );
if( psObject != NULL )
{
EmitShape( psObject, szNextPrefix, psTree->nDimension );
}
SHPDestroyObject( psObject );
}
}
else
{
printf( "%s Shapes(%d): ", pszPrefix, psTreeNode->nShapeCount );
for( i = 0; i < psTreeNode->nShapeCount; i++ )
{
printf( "%d ", psTreeNode->panShapeIds[i] );
}
printf( "\n" );
}
/* -------------------------------------------------------------------- */
/* Emit subnodes. */
/* -------------------------------------------------------------------- */
for( i = 0; i < psTreeNode->nSubNodes; i++ )
{
if( psTreeNode->apsSubNode[i] != NULL )
SHPTreeNodeDump( psTree, psTreeNode->apsSubNode[i],
szNextPrefix, nExpandShapes );
}
printf( "%s)\n", pszPrefix );
return;
}
/************************************************************************/
/* SHPTreeNodeSearchAndDump() */
/************************************************************************/
static void SHPTreeNodeSearchAndDump( SHPTree * hTree,
double *padfBoundsMin,
double *padfBoundsMax )
{
int *panHits, nShapeCount, i;
/* -------------------------------------------------------------------- */
/* Perform the search for likely candidates. These are shapes */
/* that fall into a tree node whose bounding box intersects our */
/* area of interest. */
/* -------------------------------------------------------------------- */
panHits = SHPTreeFindLikelyShapes( hTree, padfBoundsMin, padfBoundsMax,
&nShapeCount );
/* -------------------------------------------------------------------- */
/* Read all of these shapes, and establish whether the shape's */
/* bounding box actually intersects the area of interest. Note */
/* that the bounding box could intersect the area of interest, */
/* and the shape itself still not cross it but we don't try to */
/* address that here. */
/* -------------------------------------------------------------------- */
for( i = 0; i < nShapeCount; i++ )
{
SHPObject *psObject;
psObject = SHPReadObject( hTree->hSHP, panHits[i] );
if( psObject == NULL )
continue;
if( !SHPCheckBoundsOverlap( padfBoundsMin, padfBoundsMax,
&(psObject->dfXMin),
&(psObject->dfXMax),
hTree->nDimension ) )
{
printf( "Shape %d: not in area of interest, but fetched.\n",
panHits[i] );
}
else
{
printf( "Shape %d: appears to be in area of interest.\n",
panHits[i] );
}
SHPDestroyObject( psObject );
}
if( nShapeCount == 0 )
printf( "No shapes found in search.\n" );
}

File diff suppressed because it is too large Load diff

View file

@ -1,28 +0,0 @@
#!/bin/sh
EG_DATA=/u/www/projects/shapelib/eg_data
echo -------------------------------------------------------------------------
echo Test 1: dump anno.shp
echo -------------------------------------------------------------------------
./shpdump $EG_DATA/anno.shp | head -250
echo -------------------------------------------------------------------------
echo Test 2: dump brklinz.shp
echo -------------------------------------------------------------------------
./shpdump $EG_DATA/brklinz.shp | head -500
echo -------------------------------------------------------------------------
echo Test 3: dump polygon.shp
echo -------------------------------------------------------------------------
./shpdump $EG_DATA/polygon.shp | head -500
echo -------------------------------------------------------------------------
echo Test 4: dump pline.dbf - uses new F field type
echo -------------------------------------------------------------------------
./dbfdump -m -h $EG_DATA/pline.dbf | head -50
echo -------------------------------------------------------------------------
echo Test 5: NULL Shapes.
echo -------------------------------------------------------------------------
./shpdump $EG_DATA/csah.dbf | head -150

View file

@ -1,11 +0,0 @@
#!/bin/sh
for i in 0 1 2 3 4 5 6 7 8 9 10 11 12 13; do
echo -----------------------------------------------------------------------
echo Test 2/$i
echo -----------------------------------------------------------------------
./shptest $i
./shpdump test${i}.shp
done

View file

@ -1,3 +0,0 @@
vpf-dump
vpf-summary
vpf-topology

View file

@ -1,44 +0,0 @@
add_library(vpf STATIC
component.cxx
component.hxx
contour.cxx
contour.hxx
coverage.cxx
coverage.hxx
database.cxx
database.hxx
feature.cxx
feature.hxx
label.cxx
label.hxx
library.cxx
library.hxx
line.cxx
line.hxx
polygon.cxx
polygon.hxx
property.cxx
property.hxx
table.cxx
table.hxx
tablemgr.cxx
tablemgr.hxx
tile.cxx
tile.hxx
value.cxx
value.hxx
vpf.hxx
vpfbase.cxx
vpfbase.hxx
)
add_executable(vpf-dump vpf-dump.cxx)
target_link_libraries(vpf-dump vpf)
add_executable(vpf-summary vpf-summary.cxx)
target_link_libraries(vpf-summary vpf)
add_executable(vpf-topology vpf-topology.cxx)
target_link_libraries(vpf-topology vpf)

View file

@ -1,101 +0,0 @@
// component.cxx - implementation of VpfComponent
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "component.hxx"
#include "tablemgr.hxx"
#include <string>
#include <fstream>
using std::string;
using std::ifstream;
VpfComponent::VpfComponent (VpfTableManager &tableManager,
const string &path)
: _path(path),
_table_manager(tableManager)
{
}
VpfComponent::~VpfComponent ()
{
}
const string &
VpfComponent::getPath () const
{
return _path;
}
bool
VpfComponent::hasChildFile (const string &child) const
{
return hasFile(getPath(), child);
}
string
VpfComponent::getChildFileName (const string &child) const
{
return getFileName (getPath(), child);
}
bool
VpfComponent::hasFile (const string &path, const string &file) const
{
// FIXME: portable, but not that efficient
bool result;
string fullpath = getFileName(path, file);
ifstream input(fullpath.c_str());
if (!input) {
input.clear();
fullpath += '.';
input.open(fullpath.c_str());
}
result = input;
input.close();
return result;
}
string
VpfComponent::getFileName (const string &path, const string &file) const
{
string result = path;
if (result[result.length()-1] != PATHSEP)
result += PATHSEP;
result += file;
return result;
}
const VpfTable *
VpfComponent::getChildTable (const string &child) const
{
return getTable(getChildFileName(child));
}
const VpfTable *
VpfComponent::getTable (const string &path) const
{
return _table_manager.getTable(path);
}
const VpfTable *
VpfComponent::copyTable (const VpfTable * table) const
{
return _table_manager.copyTable(table);
}
void
VpfComponent::freeTable (const VpfTable * table) const
{
_table_manager.freeTable(table);
}
VpfTableManager &
VpfComponent::getTableManager () const
{
return _table_manager;
}
// end of component.cxx

View file

@ -1,198 +0,0 @@
// component.hxx - declaration of VpfComponent base class
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_COMPONENT_HXX
#define __VPF_COMPONENT_HXX 1
#include "vpfbase.hxx"
#include <string>
class VpfTable;
class VpfTableManager;
/**
* Base class for hierarchical VPF components.
*
* <p>This class provides simple, base functionality for all components,
* especially path-related operations such as opening and testing
* for tables.</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision: 1.1 $
*/
class VpfComponent
{
public:
/**
* Get the base directory for this component.
*
* @return The base directory as a string.
*/
virtual const std::string &getPath () const;
protected:
/**
* Protected constructor.
*
* <p>Only subclasses should invoke this constructor.</p>
*
* @param table_manager The underlying table manager.
* @param path The base path for the component.
*/
VpfComponent (VpfTableManager &table_manager,
const std::string &path);
/**
* Destructor.
*/
virtual ~VpfComponent ();
#ifdef __MSDOS__
static const char PATHSEP = '\\';
#else
static const char PATHSEP = '/'; // FIXME: make more robust
#endif
/**
* Test if this component has a child file.
*
* <p>This method tests for the file relative to the component's
* path. The current implementation is very crude, but
* portable; note, however, that it will fail if the child is
* a directory rather than a file.</p>
*
* @param child The relative file name, which must not contain
* any path separators.
* @return true if the file exists and can be read, false otherwise.
* @see #hasFile
*/
virtual bool hasChildFile (const std::string &child) const;
/**
* Get the absolute name of a child file.
*
* <p>This method can be used with a file or directory. The name
* returned is relative to the component's path.</p>
*
* @param child The relative file or directory name, which must not
* contain any path separators.
* @return The absolute file or directory name.
* @see #getFileName
*/
virtual std::string getChildFileName (const std::string &child) const;
/**
* Test for the existence of a file.
*
* <p>This method tests for the existence of a file inside a
* directory and creates a new absolute file name using the
* appropriate path separator. Note that this method will fail if
* the relative path points to a directory rather than a file.</p>
*
* @param path The partial path leading up to the file or directory.
* @param file The relative name of the file or directory, which
* must not contain any path separators.
* @return true if the file exists, false otherwise.
*/
virtual bool hasFile (const std::string &path,
const std::string &file) const;
/**
* Get the absolute name for a file.
*
* <p>This method builds the absolute name of a file or directory
* inside any arbitrary directory, using the appropriate path
* separator. Invocations can be nested to get a complex path.</p>
*
* @param path The partial path leading up to the component.
* @param file The relative name of the file or directory, which
* must not contain any path separators.
* @return The absolute file name.
*/
virtual std::string getFileName (const std::string &path,
const std::string &file) const;
/**
* Get a VPF table based on an absolute pathname.
*
* <p>The application must call {@link #freeTable} to release the
* table once it is finished with it. It must <em>not</em>
* delete the table.</p>
*
* @param path The absolute pathname to the VPF table.
* @return A pointer to a table from the table manager.
* @exception VpfException If the table cannot be read.
*/
virtual const VpfTable * getTable (const std::string &path) const;
/**
* Get a VPF table based on a relative filename.
*
* <p>The table will be loaded from the component's base directory.</p>
*
* <p>The application must call {@link #freeTable} to release the
* table once it is finished with it. It must <em>not</em>
* delete the table.</p>
*
* @param file The table's relative file name, which must not
* contain any path separators.
* @return A pointer to a table from the table manager.
* @exception VpfException If the table cannot be read.
*/
virtual const VpfTable * getChildTable (const std::string &file) const;
/**
* Create a new copy of an existing table.
*
* <p>This method currently increases the reference counter in the
* table manager.</p>
*
* <p>The application must call {@link #freeTable} to release the
* table once it is finished with it. It must <em>not</em>
* delete the table.</p>
*
* @param table The table to copy.
* @return A new copy of the table.
*/
virtual const VpfTable * copyTable (const VpfTable * table) const;
/**
* Release a table.
*
* <p>This method currently decreases the reference counter in the
* table manager, which may cause the table to be freed. The
* application must not attempt to use this copy of the table
* after freeing it.</p>
*
* @param table The table to copy.
*/
virtual void freeTable (const VpfTable * table) const;
virtual VpfTableManager &getTableManager () const;
private:
std::string _path;
VpfTableManager &_table_manager;
};
#endif
// end of component.hxx

View file

@ -1,126 +0,0 @@
// contour.cxx - implementation of VpfContour
#include "contour.hxx"
#include "table.hxx"
#include "line.hxx"
#include <string>
#include <vector>
using std::string;
using std::vector;
VpfContour::VpfContour (int faceId, int startEdge, const string &path,
VpfTableManager &tableManager)
: VpfComponent(tableManager, path),
_polygon_id(faceId),
_start_edge(startEdge),
_nPoints(0),
_edg(0),
_lines(0)
{
}
VpfContour::VpfContour (const VpfContour &contour)
: VpfComponent(contour.getTableManager(), contour.getPath()),
_polygon_id(contour._polygon_id),
_start_edge(contour._start_edge),
_nPoints(0),
_edg(copyTable(contour._edg)),
_lines(0)
{
}
VpfContour::~VpfContour ()
{
freeTable(_edg);
delete _lines;
}
int
VpfContour::getPointCount () const
{
getLines();
return _nPoints;
}
const VpfPoint
VpfContour::getPoint (int index) const
{
const vector<line_info> &lines = getLines();
int nLines = lines.size();
for (int i = 0; i < nLines; i++) {
if (index < (lines[i].offset + lines[i].size)) {
VpfLine line(lines[i].id, getPath(), getTableManager());
if (lines[i].isLR)
return line.getPoint(index - lines[i].offset);
else
return line.getPoint(lines[i].offset + lines[i].size - index - 1);
}
}
throw VpfException("contour point out of range");
}
const VpfTable &
VpfContour::getEDG () const
{
if (_edg == 0)
_edg = getChildTable("edg");
return *_edg;
}
const vector<VpfContour::line_info> &
VpfContour::getLines () const
{
if (_lines == 0) {
_lines = new vector<line_info>;
const VpfTable &edg = getEDG();
int current_offset = 0;
int current_edge = _start_edge;
// std::cout << "start edge: " << _start_edge << std::endl;
int previous_edge = -1;
do {
int row = edg.findMatch("id", current_edge);
line_info info;
info.id = current_edge;
info.offset = current_offset;
info.size = edg.getValue(row, "coordinates").getElementCount();
current_offset += info.size;
_nPoints += info.size;
previous_edge = current_edge;
if (edg.getValue(row, "right_face")
.getCrossRef().current_tile_key == _polygon_id) {
info.isLR = true;
current_edge = edg.getValue(row, "right_edge")
.getCrossRef().current_tile_key;
if (edg.getValue(row, "left_face")
.getCrossRef().current_tile_key == _polygon_id)
std::cout << "right face also left face" << std::endl;
} else if (edg.getValue(row, "left_face")
.getCrossRef().current_tile_key == _polygon_id) {
info.isLR = false;
current_edge = edg.getValue(row, "left_edge")
.getCrossRef().current_tile_key;
} else {
throw VpfException("edge does not belong to face");
}
for ( vector<line_info>::reverse_iterator it = _lines->rbegin();
it != _lines->rend(); it++ )
{
if ( it->id == info.id )
{
std::cout << "eeek!!! infinite loop..." << std::endl;
_nPoints -= info.size;
return *_lines;
}
}
_lines->push_back(info);
} while (current_edge != _start_edge);
}
return *_lines;
}
// end of contour.cxx

View file

@ -1,52 +0,0 @@
// contour.hxx - declaration of VpfContour
#ifndef __CONTOUR_HXX
#define __CONTOUR_HXX 1
#include "vpfbase.hxx"
#include "component.hxx"
#include <string>
#include <vector>
class VpfTable;
struct VpfPoint;
class VpfContour : public VpfComponent
{
public:
VpfContour (const VpfContour &contour);
virtual ~VpfContour ();
virtual int getPointCount () const;
virtual const VpfPoint getPoint (int index) const;
protected:
struct line_info
{
bool isLR;
int id;
int offset;
int size;
};
friend class VpfPolygon;
VpfContour (int faceId, int startEdge, const std::string &path,
VpfTableManager &tableManager);
virtual const VpfTable &getEDG () const;
virtual const std::vector<line_info> &getLines() const;
private:
int _polygon_id;
int _start_edge;
mutable int _nPoints;
mutable const VpfTable * _edg;
mutable std::vector<line_info> * _lines;
};
#endif
// end of contour.hxx

View file

@ -1,137 +0,0 @@
// coverage.cxx - implementation of VpfCoverage
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "coverage.hxx"
#include "library.hxx"
#include "table.hxx"
#include "feature.hxx"
#include <string>
#include <vector>
#include <algorithm>
using std::string;
using std::vector;
////////////////////////////////////////////////////////////////////////
// Implementation of VpfCoverage
////////////////////////////////////////////////////////////////////////
VpfCoverage::VpfCoverage (const string &path, const VpfLibrary &lib,
int cat_row)
: VpfComponent(lib.getTableManager(), path),
_library_path(lib.getPath()),
_name(lib.getCAT().getValue(cat_row, "coverage_name").getText()),
_description(lib.getCAT().getValue(cat_row, "description").getText()),
_level(lib.getCAT().getValue(cat_row, "level").getInt()),
_feature_names(0),
_fcs(0)
{
}
VpfCoverage::VpfCoverage (const VpfCoverage &coverage)
: VpfComponent(coverage.getTableManager(), coverage.getPath()),
_library_path(coverage._library_path),
_name(coverage._name),
_description(coverage._description),
_level(coverage._level),
_feature_names(0),
_fcs(copyTable(coverage._fcs))
{
}
VpfCoverage::~VpfCoverage ()
{
delete _feature_names;
freeTable(_fcs);
}
const char *
VpfCoverage::getName () const
{
return _name.c_str();
}
const char *
VpfCoverage::getDescription () const
{
return _description.c_str();
}
int
VpfCoverage::getLevel () const
{
return _level;
}
int
VpfCoverage::getFeatureCount () const
{
return getFeatureNames().size();
}
const VpfFeature
VpfCoverage::getFeature (int index) const
{
return VpfFeature(getPath(), getFeatureNames()[index], *this);
}
bool
VpfCoverage::hasFeature (const string &name) const
{
if (_feature_names == 0)
getFeatureNames();
vector<string>::iterator it;
for (it = _feature_names->begin(); it != _feature_names->end(); it++)
if (*it == name)
return(it != _feature_names->end());
return false;
// return (std::find(_feature_names->begin(), _feature_names->end(), name)
// != _feature_names->end());
}
const VpfFeature
VpfCoverage::getFeature (const string &name) const
{
if (!hasFeature(name))
throw VpfException(string("No feature named ") + name);
return VpfFeature(getPath(), name, *this);
}
const vector<string> &
VpfCoverage::getFeatureNames () const
{
if (_feature_names == 0) {
_feature_names = new vector<string>;
const VpfTable &fcs = getFCS();
int nRows = fcs.getRowCount();
for (int i = 0; i < nRows; i++) {
const string &name = fcs.getValue(i, "feature_class").getText();
if (!hasFeature(name))
_feature_names->push_back(name);
}
}
return *_feature_names;
}
const string &
VpfCoverage::getLibraryPath () const
{
return _library_path;
}
const VpfTable &
VpfCoverage::getFCS () const
{
if (_fcs == 0)
_fcs = getChildTable("fcs");
return *_fcs;
}
// end of coverage.cxx

View file

@ -1,214 +0,0 @@
// coverage.hxx - declaration of VpfCoverage.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_COVERAGE_HXX
#define __VPF_COVERAGE_HXX 1
#include "vpfbase.hxx"
#include "component.hxx"
#include <string>
#include <vector>
class VpfTable;
class VpfLibrary;
class VpfFeature;
class VpfLine;
class VpfPolygon;
class VpfTileRef;
/**
* A coverage in a library in a VPF database.
*
* <p>This is the third level of the VPF hierarchy: every database
* contains one or move libraries, and every library contains one or
* more coverages, collections of GIS data belonging to the same
* general class (i.e. transportation) and sharing the same attribute
* dictionary. This class has a copy constructor, so it can
* safely be assigned and passed around by value.</p>
*
* <p>All of the points, lines, and polygons for the coverage are
* available through this class; however, if the coverage contains
* multiple features, it will often be simpler to access the points,
* lines, and polygons through each feature individually.</p>
*
* <p>Users should obtain a copy of the coverage object through the
* library's getCoverage methods; new coverage objects cannot be
* created directly (except by copying an existing one).</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision: 1.2 $
* @see VpfDataBase
* @see VpfLibrary
*/
class VpfCoverage : public VpfComponent
{
public:
/**
* Copy constructor.
*
* @param coverage The coverage to copy.
*/
VpfCoverage (const VpfCoverage &coverage);
/**
* Destructor.
*/
virtual ~VpfCoverage ();
/**
* Get the name of the coverage.
*
* @return The coverage's name as a character string.
*/
virtual const char * getName () const;
/**
* Get a description of the coverage.
*
* @return The coverage's description as a character string.
*/
virtual const char * getDescription () const;
/**
* Get the topographical level of the coverage.
*
* <p>According to MIL-STD-2407, the meaning of this integer is as
* follows:</p>
*
* <dl>
* <dt>Level 0</dt>
* <dd>Purely geometric aspects of spatial data, with no
* topology.</dd>
* <dt>Level 1</dt>
* <dd>Non-planar graph.</dd>
* <dt>Level 2</dt>
* <dd>Planar graph.</dd>
* <dt>Level 3</dt>
* <dd>Faces defined by the planar graph.</dd>
* </dl>
*
* <p>Make of that what you will.</p>
*
* @return The coverage's topographical level.
*/
virtual int getLevel () const;
/**
* Count the features.
*
* <p>A feature is a category of data within the coverage, such as
* roads, or forest.</p>
*
* @return The number of features present in the coverage.
* @see #getFeature
*/
virtual int getFeatureCount () const;
/**
* Get a feature by index.
*
* @param index The zero-based index of the feature.
* @return A copy of an object representing the feature.
* @exception VpfException If the index is out of bounds.
* @see #getFeatureCount
*/
virtual const VpfFeature getFeature (int index) const;
/**
* Test whether a feature is present.
*
* @param name The feature name.
* @return true if the feature is present, false if it is not.
*/
virtual bool hasFeature (const std::string &name) const;
/**
* Get a feature by name.
*
* @param name The name of the feature.
* @return A copy of the object representing the feature.
* @exception VpfException If no feature exists with the name
* provided.
* @see #hasFeature
*/
virtual const VpfFeature getFeature (const std::string &name) const;
protected:
friend class VpfLibrary;
friend class VpfFeature;
/**
* Protected constructor.
*
* <p>This is the only mechanism for creating a new coverage from
* scratch. Library users will obtain a coverage object from
* the VpfLibrary class, rather than constructing one directly.</p>
*
* @param path The path to the directory containing the FCS table.
* @param library The parent library object.
* @param cat_row The row in the parent library's CAT table.
*/
VpfCoverage (const std::string &path, const VpfLibrary &library,
int cat_row);
/**
* Get a feature schema table.
*
* <p>The feature schema table declares all of the features used
* in the coverage. This is a lazy implementation: the FCS will not
* be loaded unless it is actually needed.</p>
*
* @return The feature schema table for this coverage.
*/
const VpfTable &getFCS () const;
/**
* Get a vector of feature names for this coverage.
*
* <p>The names are collected from the FCS. This is a lazy
* implementation: the vector will not be built unless it is
* actually needed.</p>
*
* @return A vector containing one copy of each feature name.
*/
const std::vector<std::string> &getFeatureNames () const;
/**
* Get the path of the parent library.
*
* @return The parent library's path.
*/
const std::string &getLibraryPath () const;
private:
std::string _library_path;
std::string _name;
std::string _description;
int _level;
mutable std::vector<std::string> * _feature_names;
mutable const VpfTable * _fcs;
};
#endif
// end of coverage.hxx

View file

@ -1,91 +0,0 @@
// database.cxx - implementation of VpfDatabase
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "vpfbase.hxx"
#include "database.hxx"
#include "library.hxx"
#include "table.hxx"
#include <string>
using std::string;
VpfDataBase::VpfDataBase (const string &path)
: VpfComponent(_table_manager, path),
_dht(0),
_lat(0)
{
}
VpfDataBase::VpfDataBase (const VpfDataBase &database)
: VpfComponent(database._table_manager, database.getPath()),
_dht(copyTable(database._dht)),
_lat(copyTable(database._lat))
{
}
VpfDataBase::~VpfDataBase ()
{
freeTable(_dht);
freeTable(_lat);
}
const char *
VpfDataBase::getName () const
{
return getDHT().getValue(0, "database_name").getText();
}
const char *
VpfDataBase::getDescription () const
{
return getDHT().getValue(0, "database_desc").getText();
}
int
VpfDataBase::getLibraryCount () const
{
return getLAT().getRowCount();
}
const VpfLibrary
VpfDataBase::getLibrary (int index) const
{
const char * name = getLAT().getValue(index, "library_name").getText();
return getLibrary(name);
}
bool
VpfDataBase::hasLibrary (const std::string &name) const
{
return (getLAT().findMatch("library_name", name.c_str()) != -1);
}
const VpfLibrary
VpfDataBase::getLibrary (const string &name) const
{
if (!hasLibrary(name))
throw VpfException(string("No library named ") + name);
return VpfLibrary(getChildFileName(name), *this);
}
const VpfTable &
VpfDataBase::getDHT () const
{
if (_dht == 0)
_dht = getChildTable("dht");
return *_dht;
}
const VpfTable &
VpfDataBase::getLAT () const
{
if (_lat == 0)
_lat = getChildTable("lat");
return *_lat;
}
// end of database.cxx

View file

@ -1,162 +0,0 @@
// database.hxx - declaration for VpfDataBase
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_DATABASE_HXX
#define __VPF_DATABASE_HXX 1
#include <string>
#include <map>
#include <list>
#include "vpfbase.hxx"
#include "component.hxx"
#include "tablemgr.hxx"
class VpfTableManager;
class VpfLibrary;
/**
* A Vector Product Format (VPF) database.
*
* <p>This is the top level of the VPF hierarchy: the database contains
* one or more libraries, which in turn contain coverages of various
* sorts. This class has a copy constructor, so it can safely be
* assigned and passed around by value.</p>
*
* <p>This is the only class that users should create directly using a
* public constructor, providing the path to the root of the database
* in the file system. This class can be used to create library
* objects, which, in turn, create coverage objects, and so on.</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision: 1.2 $
* @see VpfDataBase
* @see VpfCoverage
*/
class VpfDataBase : public VpfComponent
{
public:
/**
* Public constructor.
*
* <p>This constructor is the main mechanism for creating a VPF
* database. The user provides it with a path to the root of the
* VPF database, the name of a directory containing "dht" and "lat"
* files, such as "/cdrom/vmaplv0/" or "d:\\vmaplv0\\".</p>
*
* @param path The directory at the root of the VPF database.
*/
VpfDataBase (const std::string &path);
/**
* Destructor.
*/
virtual ~VpfDataBase ();
/**
* Copy constructor.
*/
VpfDataBase (const VpfDataBase &database);
/**
* Get the name of the database.
*
* @return The database's name as a character string.
*/
virtual const char * getName () const;
/**
* Get a description of the database.
*
* @return The database's description as a character string.
*/
virtual const char * getDescription () const;
/**
* Count the libraries in the database.
*
* @return The number of libraries in the database.
*/
virtual int getLibraryCount () const;
/**
* Get a library by index.
*
* @param index The zero-based index of the library.
* @return The library.
* @exception VpfException If the library is out of range.
* @see #getLibraryCount
*/
virtual const VpfLibrary getLibrary (int index) const;
/**
* Test whether a library is present.
*
* @param name The library name to test.
* @return true if a library exists with the name specified, false
* otherwise.
*/
virtual bool hasLibrary (const std::string &name) const;
/**
* Get a library by name.
*
* @param name The library's name.
* @return The library.
* @exception VpfException If there is no library with the
* name provided.
* @see #hasLibrary
*/
virtual const VpfLibrary getLibrary (const std::string &name) const;
protected:
friend class VpfLibrary;
/**
* Get a copy of the database header table.
*
* <p>The DHT contains information about the database, including
* its name and description. This is a lazy implementation: it will
* not load the DHT table unless it is actually needed.</p>
*
* @return The DHT table.
*/
virtual const VpfTable &getDHT () const;
/**
* Get a copy of the library attribute table.
*
* <p>The LAT contains the name and bounding rectangle for every
* library in the database. This is a lazy implementation: it will
* not load the LAT table unless it is actually needed.</p>
*
* @return the LAT table.
*/
virtual const VpfTable &getLAT () const;
private:
mutable VpfTableManager _table_manager;
mutable const VpfTable * _dht;
mutable const VpfTable * _lat;
};
#endif // __VPF_DATABASE_HXX
// end of database.hxx

View file

@ -1,276 +0,0 @@
// feature.cxx - implementation of VpfFeature class.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include <string>
#include "vpfbase.hxx"
#include "value.hxx"
#include "feature.hxx"
#include "coverage.hxx"
#include "table.hxx"
#include "line.hxx"
#include "polygon.hxx"
#include "label.hxx"
#include "property.hxx"
#include "tile.hxx"
using std::string;
VpfFeature::VpfFeature (const string &path, const string &name,
const VpfCoverage &coverage)
: VpfComponent(coverage.getTableManager(), path),
_name(name),
_topology_type(UNKNOWN),
_tileref_path(getFileName(coverage.getLibraryPath(), "tileref")),
_xft(0),
_fca(0)
{
if (hasChildFile(_name + ".pft"))
_topology_type = POINT;
else if (hasChildFile(_name + ".lft"))
_topology_type = LINE;
else if (hasChildFile(_name + ".aft"))
_topology_type = POLYGON;
else if (hasChildFile(_name + ".tft"))
_topology_type = LABEL;
}
VpfFeature::VpfFeature (const VpfFeature &feature)
: VpfComponent(feature.getTableManager(), feature.getPath()),
_name(feature._name),
_topology_type(feature._topology_type),
_tileref_path(feature._tileref_path),
_xft(copyTable(feature._xft)),
_fca(copyTable(feature._fca))
{
}
VpfFeature::~VpfFeature ()
{
freeTable(_xft);
freeTable(_fca);
}
const char *
VpfFeature::getName () const
{
return _name.c_str();
}
const char *
VpfFeature::getDescription () const
{
if (hasChildFile("fca")) {
const VpfTable &fca = getFCA();
int row = fca.findMatch("fclass", getName());
return fca.getValue(row, "descr").getText();
} else {
return "";
}
}
bool
VpfFeature::isTiled () const
{
return getXFT().hasColumn("tile_id");
}
int
VpfFeature::getPropertyDeclCount () const
{
const VpfTable &xft = getXFT();
int nCols = xft.getColumnCount();
int result = 0;
for (int i = 0; i < nCols; i++) {
const VpfColumnDecl &decl = xft.getColumnDecl(i);
if (isProperty(decl.getName()))
result++;
}
return result;
}
const VpfPropertyDecl
VpfFeature::getPropertyDecl (int index) const
{
const VpfTable &xft = getXFT();
int nCols = xft.getColumnCount();
for (int i = 0; i < nCols; i++) {
const VpfColumnDecl &decl = xft.getColumnDecl(i);
if (isProperty(decl.getName())) {
if (index == 0)
return VpfPropertyDecl(getPath(), i, *this);
else
index--;
}
}
throw VpfException("property declaration index out of range");
}
bool
VpfFeature::hasProperty (const string &name) const
{
return (isProperty(name) && getXFT().hasColumn(name));
}
const VpfPropertyDecl
VpfFeature::getPropertyDecl (const string &name) const
{
if (!hasProperty(name))
throw VpfException(string("No feature property named ") + name);
int col = getXFT().findColumn(name);
return VpfPropertyDecl(getPath(), col, *this);
}
const VpfValue &
VpfFeature::getPropertyValue (const string &name, int index) const
{
if (!hasProperty(name))
throw VpfException(string("No feature property named ") + name);
return getXFT().getValue(index, name);
}
VpfFeature::TopologyType
VpfFeature::getTopologyType () const
{
return _topology_type;
}
int
VpfFeature::getTopologyCount () const
{
return getXFT().getRowCount();
}
const VpfPoint
VpfFeature::getPoint (int index) const
{
if (_topology_type != POINT)
throw VpfException("Not point topology");
const VpfTable &pft = getXFT();
int pointId = pft.getValue(index, "end_id").getInt();
if (isTiled()) {
string end_path =
getFileName(getChildFileName(getTile(index).getTileSubdir()), "end");
const VpfTable * end = getTable(end_path);
int row = end->findMatch("id", pointId);
const VpfPoint p = end->getValue(row, "coordinate").getPoint(0);
freeTable(end);
return p;
} else {
const VpfTable * end = getChildTable("end");
int row = end->findMatch("id", pointId);
const VpfPoint p = end->getValue(row, "coordinate").getPoint(0);
freeTable(end);
return p;
}
}
const VpfLine
VpfFeature::getLine (int index) const
{
if (_topology_type != LINE)
throw VpfException("Not line topology");
const VpfTable &lft = getXFT();
int lineId = lft.getValue(index, "edg_id").getInt();
if (isTiled()) {
string path = getChildFileName(getTile(index).getTileSubdir());
return VpfLine(lineId, path, getTableManager());
} else {
return VpfLine(lineId, getPath(), getTableManager());
}
}
const VpfPolygon
VpfFeature::getPolygon (int index) const
{
if (_topology_type != POLYGON)
throw VpfException("Not polygon topology");
const VpfTable &aft = getXFT();
int polygonId = aft.getValue(index, "fac_id").getInt();
// Polygon #1 is the global polygon;
// no one should ever be trying to
// fetch it from a feature.
if (polygonId == 1)
throw VpfException("Getting polygon #1!!!!!");
if (isTiled()) {
string path = getChildFileName(getTile(index).getTileSubdir());
return VpfPolygon(polygonId, path, getTableManager());
} else {
return VpfPolygon(polygonId, getPath(), getTableManager());
}
}
const VpfLabel
VpfFeature::getLabel (int index) const
{
if (_topology_type != LABEL)
throw VpfException("Not label topology");
const VpfTable &tft = getXFT();
int labelId = tft.getValue(index, "txt_id").getInt();
if (isTiled()) {
string path = getChildFileName(getTile(index).getTileSubdir());
return VpfLabel(labelId, path, getTableManager());
} else {
return VpfLabel(labelId, getPath(), getTableManager());
}
}
const VpfTile
VpfFeature::getTile (int index) const
{
if (!isTiled())
throw VpfException("Not a tiled feature");
int tile_id = getXFT().getValue(index, "tile_id").getInt();
return VpfTile(getTableManager(), _tileref_path, tile_id);
}
const VpfTable &
VpfFeature::getXFT () const
{
if (_xft == 0)
_xft = getChildTable(getFeatureTableName());
return *_xft;
}
const VpfTable &
VpfFeature::getFCA () const
{
if (_fca == 0)
_fca = getChildTable("fca");
return *_fca;
}
bool
VpfFeature::isProperty (const string &name) const
{
return (name != string("id") &&
name != string("tile_id") &&
name != string("end_id") &&
name != string("edg_id") &&
name != string("fac_id") &&
name != string("txt_id"));
}
const string
VpfFeature::getFeatureTableName () const
{
switch (_topology_type) {
case POINT:
return _name + ".pft";
case LINE:
return _name + ".lft";
case POLYGON:
return _name + ".aft";
case LABEL:
return _name + ".tft";
default:
throw VpfException("Unsupported feature topology type");
}
}
// end of feature.cxx

View file

@ -1,271 +0,0 @@
// feature.hxx - declaration of VpfFeature class.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_FEATURE_HXX
#define __VPF_FEATURE_HXX 1
#include "vpfbase.hxx"
#include "component.hxx"
class VpfTable;
class VpfValue;
class VpfCoverage;
class VpfLine;
class VpfPolygon;
class VpfLabel;
class VpfPropertyDecl;
class VpfTile;
/**
* A feature in a coverage in a library in a VPF database.
*
* <p>This is the optional fourth level of the VPF hierarchy: a
* library (such as transportation) may or may not be divided into
* separate features (such as roads, railroads, etc.). This class
* provides information about a feature, and also provides a
* convenient way to access all of the shape information for a
* specific feature in a single place.</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision: 1.1 $
*/
class VpfFeature : public VpfComponent
{
public:
/**
* The possible topology types.
*/
enum TopologyType {
UNKNOWN,
POINT,
LINE,
POLYGON,
LABEL
};
/**
* Copy constructor.
*/
VpfFeature (const VpfFeature &feature);
/**
* Destructor.
*/
virtual ~VpfFeature ();
/**
* Get the name of this feature.
*
* @return The feature's short name as a character string.
*/
virtual const char * getName () const;
/**
* Get the full description of this feature.
*
* @return The feature's description as a character string.
*/
virtual const char * getDescription () const;
/**
* Test whether this feature's topology is tiled.
*
* @return true if the feature's topology is tiled, false otherwise.
*/
virtual bool isTiled () const;
/**
* Count the feature properties.
*
* @return The number of properties for the feature.
*/
virtual int getPropertyDeclCount () const;
/**
* Get a property declaration.
*
* @param index The index of the property declaration.
* @return The property declaration.
*/
virtual const VpfPropertyDecl getPropertyDecl (int index) const;
/**
* Test whether a property is present.
*
* @param name The property name to test.
* @return true if the property is present, false otherwise.
*/
virtual bool hasProperty (const std::string &name) const;
/**
* Get a property declaration by name.
*
* @param name The name of the feature property.
* @return The declaration for the property.
* @exception VpfException If the specified feature property does not
* exist.
*/
virtual const VpfPropertyDecl
getPropertyDecl (const std::string &name) const;
/**
* Get a property value for a specific piece of topology.
*
* @param name The property name to look up.
* @param index The index of the topology.
* @return The property value for the specified topology.
* @exception VpfException If the specified feature property does
* not exist or if the index is out of range.
* @see #getTopologyCount
*/
virtual const VpfValue &getPropertyValue (const std::string &name,
int index) const;
/**
* Get the type of topology covered by the feature.
*
* @return
*/
virtual TopologyType getTopologyType () const;
/**
* Count the topology items in the feature.
*/
virtual int getTopologyCount () const;
/**
* Get a point from this feature.
*
* @param index The index of the point to retrieve.
* @return The point requested.
* @exception VpfException If the index is out of range.
*/
virtual const VpfPoint getPoint (int index) const;
/**
* Get a line from this feature.
*
* @param index The index of the line to retrieve.
* @return The line requested.
* @exception VpfException If the index is out of range.
*/
virtual const VpfLine getLine (int index) const;
/**
* Get a polygon from this feature.
*
* @param index The index of the polygon to retrieve.
* @return The polygon requested.
* @exception VpfException If the index is out of range.
*/
virtual const VpfPolygon getPolygon (int index) const;
/**
* Text a label from this feature.
*
* @param index The index of the label to retrieve.
* @return The label requested.
* @exception VpfException If the index is out of range.
*/
virtual const VpfLabel getLabel (int index) const;
/**
* Get the tile where a specific topology occurs.
*
* @param index The index of the topology.
* @return The tile where the topology occurs.
* @exception VpfException If the index is out of range.
* @see #getTopologyCount
*/
virtual const VpfTile getTile (int index) const;
protected:
friend class VpfCoverage;
friend class VpfPropertyDecl;
/**
* Protected constructor.
*
* <p>This is the only way to build a new feature from scratch.
* Library users should obtain a feature object from the VpfCoverage
* class.</p>
*
* @param path The path to the coverage directory.
* @param name The name of the feature.
* @param coverage The parent coverage.
*/
VpfFeature (const std::string &path, const std::string &name,
const VpfCoverage &coverage);
/**
* Get the feature table for the feature.
*
* <p>The feature table (*.pft, *.lft, *.aft, or *.tft, depending
* on the coverage type) contains information about the feature,
* including a list of topologies. This is a lazy implementation:
* the feature table will not be loaded unless it is actually
* needed.</p>
*
* @return The feature table for this feature.
*/
virtual const VpfTable &getXFT () const;
/**
* Get the feature class attribute table.
*
* <p>The FCA contains the description of each feature. This is
* a lazy implementation: the FCA will not be loaded unless it is
* actually needed.</p>
*
* @return The FCA table.
*/
virtual const VpfTable &getFCA () const;
/**
* Get the name of the feature table.
*
* @return The name of the feature table, with the appropriate
* extension based on the feature type.
*/
virtual const std::string getFeatureTableName () const;
private:
bool isProperty (const std::string &name) const;
std::string _name;
TopologyType _topology_type;
std::string _tileref_path;
mutable const VpfTable * _xft;
mutable const VpfTable * _fca;
};
#endif
// end of feature.hxx

View file

@ -1,57 +0,0 @@
// label.cxx - implementation of VpfLabel
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "label.hxx"
#include "vpfbase.hxx"
#include "table.hxx"
#include "value.hxx"
#include <string>
using std::string;
VpfLabel::VpfLabel (int labelId, const string &path,
VpfTableManager &tableManager)
: VpfComponent(tableManager, path),
_label_id(labelId),
_txt(0)
{
}
VpfLabel::VpfLabel (const VpfLabel &table)
: VpfComponent(table.getTableManager(), table.getPath()),
_label_id(table._label_id),
_txt(copyTable(table._txt))
{
}
VpfLabel::~VpfLabel ()
{
freeTable(_txt);
}
const char *
VpfLabel::getText () const
{
const VpfTable &txt = getTXT();
int row = txt.findMatch("id", _label_id);
return txt.getValue(row, "string").getText();
}
const VpfPoint
VpfLabel::getPoint () const
{
const VpfTable &txt = getTXT();
int row = txt.findMatch("id", _label_id);
return txt.getValue(row, "shape_line").getPoint(0);
}
const VpfTable &
VpfLabel::getTXT () const
{
if (_txt == 0)
_txt = getChildTable("txt");
return *_txt;
}
// end of label.cxx

View file

@ -1,96 +0,0 @@
// label.hxx - declaration of VpfLabel
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_LABEL_HXX
#define __VPF_LABEL_HXX 1
#include "vpfbase.hxx"
#include "component.hxx"
class VpfTable;
/**
* Label topology.
*
* <p>This class represents a textual label attached to a point.
* In vmap0, most labels (i.e. for geographical locations) are
* actually contained in point topology with a txt feature property,
* so this class is not needed that often. This implementation is
* lazy: getting a label from a feature doesn't actually cause
* the TXT table to be read until you actually need it.</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision: 1.1 $
*/
class VpfLabel : public VpfComponent
{
public:
/**
* Copy constructor.
*
* @param label The label to copy.
*/
VpfLabel (const VpfLabel &label);
/**
* Destructor.
*/
virtual ~VpfLabel ();
/**
* Get the text associated with the label.
*
* @return The label's text.
*/
virtual const char * getText () const;
/**
* Get the point associated with the label.
*
* @return The label's point.
*/
virtual const VpfPoint getPoint () const;
protected:
friend class VpfFeature;
/**
* Protected constructor.
*
* <p>This is the only way to build a new label from scratch.
* Library users should obtain label objects from the VpfFeature
* class.</p>
*
* @param labelId The label identifier.
* @param path The path to the directory containing the txt file.
*/
VpfLabel (int labelId, const std::string &path,
VpfTableManager &tableManager);
/**
* Get the raw TXT table.
*
* <p>This table contains the text and point for each label.
* This is a lazy implementation: the table won't be loaded unless
* it's actually needed.</p>
*/
const VpfTable &getTXT () const;
private:
int _label_id;
mutable const VpfTable * _txt;
};
#endif
// end of label.hxx

View file

@ -1,121 +0,0 @@
// library.cxx - implementation of VpfLibrary
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "vpfbase.hxx"
#include "table.hxx"
#include "database.hxx"
#include "library.hxx"
#include "coverage.hxx"
using std::string;
VpfLibrary::VpfLibrary (const std::string &path, const VpfDataBase &database)
: VpfComponent(database.getTableManager(), path),
_lat(copyTable(&(database.getLAT()))),
_cat(0),
_lht(0),
_tileref_aft(0),
_tileref_fbr(0)
{
string fullpath = getChildFileName("tileref");
if (hasFile(fullpath, "tileref.aft"))
_tileref_aft = getTable(getFileName(fullpath, "tileref.aft"));
if (hasFile(fullpath, "fbr"))
_tileref_fbr = getTable(getFileName(fullpath, "fbr"));
}
VpfLibrary::VpfLibrary (const VpfLibrary &library)
: VpfComponent(library.getTableManager(), library.getPath()),
_lat(copyTable(library._lat)),
_cat(copyTable(library._cat)),
_lht(copyTable(library._lht)),
_tileref_aft(copyTable(library._tileref_aft)),
_tileref_fbr(copyTable(library._tileref_fbr))
{
}
VpfLibrary::~VpfLibrary ()
{
freeTable(_lat);
freeTable(_cat);
freeTable(_lht);
freeTable(_tileref_aft);
freeTable(_tileref_fbr);
}
const char *
VpfLibrary::getName () const
{
return getLHT().getValue(0, "library_name").getText();
}
const char *
VpfLibrary::getDescription () const
{
return getLHT().getValue(0, "description").getText();
}
const VpfRectangle
VpfLibrary::getBoundingRectangle () const
{
const VpfTable &lat = getLAT();
VpfRectangle bounds;
int row = lat.findMatch("library_name", getName());
bounds.minX = lat.getValue(row, "xmin").getReal();
bounds.minY = lat.getValue(row, "ymin").getReal();
bounds.maxX = lat.getValue(row, "xmax").getReal();
bounds.maxY = lat.getValue(row, "ymax").getReal();
return bounds;
}
int
VpfLibrary::getCoverageCount () const
{
return getCAT().getRowCount();
}
const VpfCoverage
VpfLibrary::getCoverage (int index) const
{
const char * name = getCAT().getValue(index, "coverage_name").getText();
return VpfCoverage(getChildFileName(name), *this, index);
}
bool
VpfLibrary::hasCoverage (const std::string &name) const
{
return (getCAT().findMatch("coverage_name", name.c_str()) != -1);
}
const VpfCoverage
VpfLibrary::getCoverage (const string &name) const
{
if (!hasCoverage(name))
throw VpfException(string("No coverage named " + name));
int cat_row = getCAT().findMatch("coverage_name", name.c_str());
return VpfCoverage(getChildFileName(name), *this, cat_row);
}
const VpfTable &
VpfLibrary::getLAT () const
{
return *_lat;
}
const VpfTable &
VpfLibrary::getCAT () const
{
if (_cat == 0)
_cat = getChildTable("cat");
return *_cat;
}
const VpfTable &
VpfLibrary::getLHT () const
{
if (_lht == 0)
_lht = getChildTable("lht");
return *_lht;
}
// end of library.cxx

View file

@ -1,183 +0,0 @@
// library.hxx - declaration for VpfLibrary class.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_LIBRARY_HXX
#define __VPF_LIBRARY_HXX 1
#include <string>
#include "vpfbase.hxx"
class VpfDataBase;
class VpfTable;
class VpfCoverage;
/**
* A library in a VPF database.
*
* <p>This is the second level of the VPF hierarchy: every
* database consists of one or more libraries, collections of related
* coverages in the same area (i.e. North America, or southern
* Ontario). This class has a copy constructor, so it can safely be
* assigned and passed around by value.</p>
*
* <p>Users should obtain a copy of the library object through the
* database's getLibrary methods; new library objects cannot be
* created directly (except by copying an existing one).</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision: 1.1 $
* @see VpfDataBase
* @see VpfCoverage
*/
class VpfLibrary : public VpfComponent
{
public:
/**
* Copy constructor.
*/
VpfLibrary (const VpfLibrary &library);
/**
* Destructor.
*/
virtual ~VpfLibrary ();
/**
* Get the name of the library.
*
* @return The library's name as a character string.
*/
virtual const char * getName () const;
/**
* Get a description of the library.
*
* @return The library's description as a character string.
*/
virtual const char * getDescription () const;
/**
* Get the minimum bounding rectangle of the library's coverages.
*
* <p>This is the smallest rectangle that can fit around all of
* the topology in the library's coverages.</p>
*
* @return The minimum bounding rectangle.
*/
virtual const VpfRectangle getBoundingRectangle () const;
/**
* Count the coverages available in the library.
*
* @return The number of coverages.
*/
virtual int getCoverageCount () const;
/**
* Get a coverage by index.
*
* @param index The zero-based index of the coverage.
* @return The coverage requested.
* @exception VpfException If the index is out of range.
* @see #getCoverageCount
*/
virtual const VpfCoverage getCoverage (int index) const;
/**
* Test whether a named coverage is present.
*
* @param name The name of the coverage to test.
* @return true if the coverage is present, false otherwise.
*/
virtual bool hasCoverage (const std::string &name) const;
/**
* Get a coverage by name.
*
* @param name The name of the coverage.
* @return The coverage requested.
* @exception VpfException If no coverage exists with the name
* provided.
* @see #hasCoverage
*/
virtual const VpfCoverage getCoverage (const std::string &name) const;
protected:
friend class VpfDataBase;
friend class VpfCoverage;
/**
* Protected constructor.
*
* <p>This is the only mechanism for constructing a new library
* from scratch. Library users should obtain a library from the
* database class.</p>
*
* @param path The path to the directory containing the CAT, LHT, and
* CRT files.
* @param database The parent database.
*/
VpfLibrary (const std::string &path, const VpfDataBase &database);
/**
* Get the library attribute table for the parent database.
*
* <p>The LAT contains the bounding rectangle for the library.
*
* @return The LAT.
*/
const VpfTable &getLAT () const;
/**
* Get the coverage attribute table for this library.
*
* <p>The CAT lists all of the coverages available and provides
* information about them. This is a lazy implementation: the
* CAT will not be loaded unless it is actually needed.</p>
*
* @return The CAT.
*/
virtual const VpfTable &getCAT () const;
/**
* Get the library header table for this library.
*
* <p>The LHT contains information about the library itself, including
* its name and description. This is a lazy implementation: the
* LHT will not be loaded unless it is actually needed.</p>
*
* @return The LHT.
*/
virtual const VpfTable &getLHT () const;
private:
const VpfTable * _lat;
mutable const VpfTable * _cat;
mutable const VpfTable * _lht;
mutable const VpfTable * _tileref_aft;
mutable const VpfTable * _tileref_fbr;
};
#endif
// end of library.hxx

View file

@ -1,93 +0,0 @@
// line.cxx - implementation of VpfLine
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "vpfbase.hxx"
#include "line.hxx"
#include "table.hxx"
#include "value.hxx"
#include <string>
using std::string;
VpfLine::VpfLine (int lineId, const std::string &path,
VpfTableManager &tableManager)
: VpfComponent(tableManager, path),
_line_id(lineId),
_ebr(0),
_edg(0),
_value(0)
{
}
VpfLine::VpfLine (const VpfLine &line)
: VpfComponent(line.getTableManager(), line.getPath()),
_line_id(line._line_id),
_ebr(copyTable(line._ebr)),
_edg(copyTable(line._edg)),
_value(0)
{
}
VpfLine::~VpfLine ()
{
freeTable(_ebr);
freeTable(_edg);
}
int
VpfLine::getPointCount () const
{
return getValue().getElementCount();
}
const VpfRectangle
VpfLine::getBoundingRectangle () const
{
const VpfTable &ebr = getEBR();
VpfRectangle rect;
int row = ebr.findMatch("id", _line_id);
rect.minX = ebr.getValue(row, "xmin").getReal();
rect.minY = ebr.getValue(row, "ymin").getReal();
rect.maxX = ebr.getValue(row, "xmax").getReal();
rect.maxY = ebr.getValue(row, "ymax").getReal();
return rect;
}
const VpfPoint
VpfLine::getPoint (int index) const
{
return getValue().getPoint(index);
}
const VpfValue &
VpfLine::getValue () const
{
if (_value == 0) {
const VpfTable &edg = getEDG();
int row = edg.findMatch("id", _line_id);
if (row == -1)
throw VpfException("Line does not exist");
_value = &(edg.getValue(row, "coordinates"));
}
return *_value;
}
const VpfTable &
VpfLine::getEBR () const
{
if (_ebr == 0)
_ebr = getChildTable("ebr");
return *_ebr;
}
const VpfTable &
VpfLine::getEDG () const
{
if (_edg == 0)
_edg = getChildTable("edg");
return *_edg;
}
// end of line.cxx

View file

@ -1,144 +0,0 @@
// line.hxx - declaration of VpfLine
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_LINE_HXX
#define __VPF_LINE_HXX 1
#include "vpfbase.hxx"
#include "component.hxx"
#include <string>
class VpfValue;
/**
* Line topology.
*
* <p>This class represents an actual line, a series of connected
* points. The implementation is lazy: getting a line from a
* polygon or feature doesn't actually cause the (very large) EBR
* or EDG tables to be read until you actually need them.</p>
*
* <p>In VPF terminology, a line is called an "edge", abbreviated
* "edg".</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision: 1.1 $
*/
class VpfLine : public VpfComponent
{
public:
/**
* Copy constructor.
*
* @param line The line to copy.
*/
VpfLine (const VpfLine &line);
/**
* Destructor.
*/
virtual ~VpfLine ();
/**
* Get the minimum bounding rectangle for the line.
*
* <p>The bounding rectangle is useful for determining whether any
* of the line falls inside a region of interest.</p>
*
* @return A rectangle containing the points for the top-left and
* bottom-right corners of the smallest rectangle that can fit
* around the line.
*/
virtual const VpfRectangle getBoundingRectangle () const;
/**
* Count the points in this line.
*
* @return The number of points in the line (at least two).
* @see #getPoint
*/
virtual int getPointCount () const;
/**
* Get a point from the line.
*
* @param index The zero-based index of the point to retrieve.
* @return The point.
* @exception VpfException If the index is out of range.
* @see #getPointCount
*/
virtual const VpfPoint getPoint (int index) const;
protected:
friend class VpfFeature;
friend class VpfContour;
/**
* Protected constructor.
*
* <p>This is the only mechanism for creating a new line from
* scratch. Library users will obtain a line from the VpfFeature
* or VpfPolygon classes, rather than constructing one directly.
*
* @param lineId The identifier of the line (foreign key into
* the ebr and edg tables).
* @param path The path to the directory containing the EBR and
* EDG files for the line. The directory may be a tile directory
* or the main coverage directory.
*/
VpfLine (int lineId, const std::string &path, VpfTableManager &tableManager);
/**
* Get the raw EBR table.
*
* <p>This table contains minimum bounding rectangles for each line,
* referenced by the line id. This is a lazy implementation: the
* table won't be loaded unless it's actually needed.</p>
*
* @return The EBR table.
*/
const VpfTable &getEBR () const;
/**
* Get the raw EDG table.
*
* <p>This table contains the actual points for each line. This
* is a lazy implementation: the table won't be loaded unless
* it's actually needed.</p>
*
* @return The EDG table.
*/
const VpfTable &getEDG () const;
/**
* Get the value from the EDG table containing the line's points.
*
* @return The value from the EDG table.
*/
const VpfValue &getValue () const;
private:
int _line_id;
mutable const VpfTable * _ebr;
mutable const VpfTable * _edg;
mutable const VpfValue * _value; // no need to delete
};
#endif
// end of line.hxx

View file

@ -1,82 +0,0 @@
// polygon.cxx - implementation of VpfPolygon
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "vpfbase.hxx"
#include "table.hxx"
#include "contour.hxx"
#include "polygon.hxx"
#include <string>
using std::string;
VpfPolygon::VpfPolygon (int polygonId, const std::string &path,
VpfTableManager &tableManager)
: VpfComponent(tableManager, path),
_polygon_id(polygonId),
_fbr(0),
_rng(0)
{
}
VpfPolygon::VpfPolygon (const VpfPolygon &polygon)
: VpfComponent(polygon.getTableManager(), polygon.getPath()),
_polygon_id(polygon._polygon_id),
_fbr(copyTable(polygon._fbr)),
_rng(copyTable(polygon._rng))
{
}
VpfPolygon::~VpfPolygon ()
{
freeTable(_fbr);
freeTable(_rng);
}
const VpfRectangle
VpfPolygon::getBoundingRectangle () const
{
const VpfTable &fbr = getFBR();
VpfRectangle rect;
int row = fbr.findMatch("id", _polygon_id);
rect.minX = fbr.getValue(row, "xmin").getReal();
rect.minY = fbr.getValue(row, "ymin").getReal();
rect.maxX = fbr.getValue(row, "xmax").getReal();
rect.maxY = fbr.getValue(row, "ymax").getReal();
return rect;
}
int
VpfPolygon::getContourCount () const
{
return getRNG().countMatches("face_id", _polygon_id);
}
const VpfContour
VpfPolygon::getContour (int contour) const
{
const VpfTable &rng = getRNG();
int row = rng.findMatch("face_id", _polygon_id, contour);
return VpfContour(_polygon_id,
rng.getValue(row, "start_edge").getInt(),
getPath(),
getTableManager());
}
const VpfTable &
VpfPolygon::getFBR () const
{
if (_fbr == 0)
_fbr = getChildTable("fbr");
return *_fbr;
}
const VpfTable &
VpfPolygon::getRNG () const
{
if (_rng == 0)
_rng = getChildTable("rng");
return *_rng;
}
// end of polygon.cxx

View file

@ -1,146 +0,0 @@
// polygon.hxx - declaration of VpfPolygon
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_POLYGON_HXX
#define __VPF_POLYGON_HXX 1
#include "vpfbase.hxx"
#include <string>
class VpfTable;
class VpfContour;
/**
* Polygon topology.
*
* <p>This class represents an actual polygon, a collection of lines
* each of which completely encloses an area. Each of the lines is
* called a contour: the first contour is always the outside ring of
* the polygon, and the remaining contours always represent holes inside
* it (such as a park in a city or an island in a lake).</p>
*
* <p>The implementation is lazy: getting a polygon from a feature doesn't
* actually cause the (very large) FBR, RNG, or FAC tables to be read
* until you actually need them.</p>
*
* <p>In VPF terminology, a polygon is called a "face", abbreviated
* "fac".</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision: 1.1 $
*/
class VpfPolygon : public VpfComponent
{
public:
/**
* Copy constructor.
*
* @param polygon The polygon to copy.
*/
VpfPolygon (const VpfPolygon &polygon);
/**
* Destructor.
*/
virtual ~VpfPolygon ();
/**
* Get the minimum bounding rectangle for the polygon.
*
* <p>The bounding rectangle is useful for determining whether any
* of the polygon falls inside a region of interest.</p>
*
* @return A rectangle containing the points for the top-left and
* bottom-right corners of the smallest rectangle that can fit around
* the polygon.
*/
virtual const VpfRectangle getBoundingRectangle () const;
/**
* Count the contours in the polygon.
*
* <p>Every polygon contains at least one contour for its outer
* boundary (the contour is a line where the last point joins with
* the first to enclose an area). Any additional contours are holes
* inside the outer boundary.</p>
*
* @return The number of contours in the polygon (at least one).
* @see #getContour
*/
virtual int getContourCount () const;
/**
* Get a contour from the polygon.
*
* @param index The zero-based index of the contour to retrieve.
* @return The contour as a line.
* @exception VpfException If the index is out of range.
* @see #getContourCount
*/
virtual const VpfContour getContour (int index) const;
protected:
friend class VpfTileRef;
friend class VpfFeature;
/**
* Protected constructor.
*
* <p>This is the only mechanism for creating a new polygon from
* scratch. Library users will obtain a polygon from the VpfFeature
* class rather than constructing one directly.
*
* @param polygonId The identifier of the polygon (foreign key into
* the FBR and RNG tables).
* @param path The path to the directory containing the fbr and rng
* files for the polygon.
*/
VpfPolygon (int polygonId, const std::string &path,
VpfTableManager &tableManager);
/**
* Get the raw FBR table.
*
* <p>This table contains minimum bounding rectangles for each polygon,
* referenced by the polygon id. This is a lazy implementation: the
* table won't be loaded unless it's actually needed.</p>
*
* @return The FBR table.
*/
const VpfTable &getFBR () const;
/**
* Get the raw RNG tables.
*
* <p>This table contains pointers, referenced by polygon id, to the
* lines in the EDG table representing each of the polygon's
* contours. This is a lazy implementation: the table won't be
* loaded unless it's actually needed.</p>
*
* @return The RNG tables.
*/
const VpfTable &getRNG () const;
private:
int _polygon_id;
mutable const VpfTable * _fbr;
mutable const VpfTable * _rng;
};
#endif
// end of polygon.hxx

View file

@ -1,138 +0,0 @@
// property.cxx - implementation of VpfProperty
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "property.hxx"
#include "table.hxx"
#include "feature.hxx"
#include <string>
using std::string;
VpfPropertyDecl::VpfPropertyDecl (const string &path, int xft_col,
const VpfFeature &feature)
: VpfComponent(feature.getTableManager(), path),
_xft_name(feature.getFeatureTableName()),
_xft_col(xft_col),
_xft(copyTable(&(feature.getXFT()))),
_vdt(0)
{
}
VpfPropertyDecl::VpfPropertyDecl (const VpfPropertyDecl &decl)
: VpfComponent(decl.getTableManager(), decl.getPath()),
_xft_name(decl._xft_name),
_xft_col(decl._xft_col),
_xft(copyTable(decl._xft)),
_vdt(copyTable(decl._vdt))
{
}
VpfPropertyDecl::~VpfPropertyDecl ()
{
freeTable(_xft);
freeTable(_vdt);
}
const char *
VpfPropertyDecl::getName () const
{
return getXFT().getColumnDecl(_xft_col).getName().c_str();
}
const char *
VpfPropertyDecl::getDescription () const
{
return getXFT().getColumnDecl(_xft_col).getDescription().c_str();
}
VpfValue::Type
VpfPropertyDecl::getValueType () const
{
return getXFT().getColumnDecl(_xft_col).getValueType();
}
int
VpfPropertyDecl::getValueCount () const
{
if (hasVDT()) {
string name = getName();
const VpfTable &vdt = getVDT();
int nRows = vdt.getRowCount();
int result = 0;
for (int i = 0; i < nRows; i++) {
if (name == vdt.getValue(i, "attribute").getText() &&
_xft_name == vdt.getValue(i, "table").getText())
result++;
}
return result;
} else {
return 0;
}
}
const char *
VpfPropertyDecl::getValueDescription (int index) const
{
if (hasVDT()) {
string name = getName();
const VpfTable &vdt = getVDT();
int nRows = vdt.getRowCount();
for (int i = 0; i < nRows; i++) {
if (name == vdt.getValue(i, "attribute").getText() &&
_xft_name == vdt.getValue(i, "table").getText()) {
if (index == 0)
return vdt.getValue(i, "description").getText();
else
index--;
}
}
throw VpfException("value not found");
} else {
throw VpfException("index out of range");
}
}
const VpfValue &
VpfPropertyDecl::getValue (int index) const
{
if (hasVDT()) {
int row = getVDT().findMatch("attribute", getName(), index);
return getVDT().getValue(row, "value");
} else {
throw VpfException("index out of range");
}
}
const string
VpfPropertyDecl::getVDTName () const
{
return getXFT().getColumnDecl(_xft_col).getValueDescriptionTable();
}
bool
VpfPropertyDecl::hasVDT () const
{
return (getVDTName() != string("-"));
}
const VpfTable &
VpfPropertyDecl::getXFT () const
{
return *_xft; // initialized in constructor
}
const VpfTable &
VpfPropertyDecl::getVDT () const
{
if (_vdt == 0) {
string name = getVDTName();
if (name == "-")
throw VpfException("No VDT");
else
_vdt = getChildTable(name);
}
return *_vdt;
}
// end of property.cxx

View file

@ -1,181 +0,0 @@
// property.hxx - declaration of VpfPropertyDecl
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_PROPERTY_HXX
#define __VPF_PROPERTY_HXX 1
#include "vpfbase.hxx"
#include "component.hxx"
#include "value.hxx"
#include <string>
class VpfFeature;
class VpfTable;
/**
* Declaration information for a feature property.
*
* <p>This declaration contains extra information about a feature
* property, useful mainly for generating schemas or summaries (such
* as a prose description of the property and a list of allowed values
* and their meanings).</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision: 1.1 $
*/
class VpfPropertyDecl : public VpfComponent
{
public:
/**
* Copy constructor.
*
* @param decl The feature property declaration to copy.
*/
VpfPropertyDecl (const VpfPropertyDecl &decl);
/**
* Destructor.
*/
virtual ~VpfPropertyDecl ();
/**
* Get the name of the feature property.
*
* @return The feature property's name.
*/
virtual const char * getName () const;
/**
* Get a prose description of the feature property.
*
* @return The feature property's description.
*/
virtual const char * getDescription () const;
/**
* Get the value type of the feature property.
*
* @return The feature property's value type.
*/
virtual VpfValue::Type getValueType () const;
/**
* Count the allowed values for the feature property.
*
* <p>A count of 0 means that the property does not have a fixed
* list of enumerated values (i.e. an elevation, date, or
* distance).</p>
*
* @return The number of allowed values, or 0 for unrestricted
* values.
*/
virtual int getValueCount () const;
/**
* Get a prose description of one of the allowed values.
*
* @param index The zero-based index of the value.
* @return The prose description, or the empty string ""
* if none was provided in the VPF feature table.
* @exception VpfException If the index is out of range.
*/
virtual const char * getValueDescription (int index) const;
/**
* Get an allowed value.
*
* @param index The zero-based index of the value.
* @return The allowed value.
* @exception VpfException If the index is out of range.
*/
virtual const VpfValue &getValue (int index) const;
protected:
friend class VpfFeature;
/**
* Protected constructor.
*
* <p>This is the only mechanism for creating a new feature property
* from scratch. Library users will obtain a feature property from
* the VpfFeature class, rather than constructing one directly.</p>
*
* @param path The path containing the feature table and value
* description table for the feature.
* @param xft_col The number of the column in the feature table
* containing this property.
* @param feature The parent feature of this property.
*/
VpfPropertyDecl (const std::string &path, int xft_col,
const VpfFeature &feature);
/**
* Test whether this property is linked to a value description table.
*
* @return true if the property is associated with a VDT, false
* otherwise.
*/
virtual bool hasVDT () const;
/**
* Get the name of the value description table.
*
* @return The value description table's name as a string.
* @exception VpfException If there is no VDT present.
* @see #hasVDT
*/
virtual const std::string getVDTName () const;
/**
* Get the feature table for this property.
*
* <p>The feature table may be for points, lines, polygons, or text
* labels. It is already loaded by the parent feature. The table
* contains the actual values for each property.</p>
*
* @return The feature table for this property.
*/
virtual const VpfTable &getXFT () const;
/**
* Get the value description table for this property.
*
* <p>The value description table contains information about
* each property, such as a prose description and the allowed
* values. This is a lazy implementation: the VDT will not be
* loaded unless it is actually needed.</p>
*
* @return The VDT.
* @exception VpfException If there is no VDT present.
* @see #hasVDT
*/
virtual const VpfTable &getVDT () const;
private:
std::string _xft_name;
int _xft_col;
const VpfTable * _xft;
mutable const VpfTable * _vdt;
};
#endif
// end of property.hxx

View file

@ -1,863 +0,0 @@
// table.cxx - implementation of VpfTable
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include <simgear/compiler.h>
#include <string>
#include <fstream>
#include <simgear/misc/zfstream.hxx> // ios_binary
#include <stdlib.h>
#include "vpfbase.hxx"
#include "table.hxx"
using std::string;
using std::ifstream;
using std::istream;
////////////////////////////////////////////////////////////////////////
// Static I/O methods.
////////////////////////////////////////////////////////////////////////
/**
* Test whether the local system uses MSB or LSB encoding.
*/
VpfTable::ByteOrder
VpfTable::get_system_byte_order () const
{
int test = 0x01020304;
char * b = (char *)(&test);
if (b[0] == 0x01 && b[1] == 0x02 && b[2] == 0x03 && b[3] == 0x04)
return VpfTable::MSB;
else if (b[0] == 0x04 && b[1] == 0x03 && b[2] == 0x02 && b[3] == 0x01)
return VpfTable::LSB;
else
throw VpfException("Unsupported byte encoding in local system");
}
static void
swap2 (char in[2], char out[2])
{
out[0] = in[1] ;
out[1] = in[0] ;
}
static void
swap4 (char in[4], char out[4])
{
out[0] = in[3] ;
out[1] = in[2] ;
out[2] = in[1] ;
out[3] = in[0] ;
}
static void
swap8 (char in[8], char out[8])
{
out[0] = in[7] ;
out[1] = in[6] ;
out[2] = in[5] ;
out[3] = in[4] ;
out[4] = in[3] ;
out[5] = in[2] ;
out[6] = in[1] ;
out[7] = in[0] ;
}
/**
* Read a fixed number of characters into a buffer.
*
* @param input The input stream.
* @param buffer The buffer to receive the characters.
* @param length The number of characters to read.
* @exception VpfException if the specified number of characters
* cannot be read from the stream.
*/
static void
read_chars (istream &input, char * buffer, int length)
{
if (!input.read(buffer, length))
throw VpfException("Failure reading from file");
}
/**
* Read a single character.
*
* @param input The input stream.
* @return A single character.
* @exception VpfException if one character cannot be read from the
* stream.
*/
static char
read_char (istream &input)
{
char c;
read_chars(input, &c, 1);
return c;
}
/**
* Read up to a delimiter.
*
* @param input The input stream.
* @param delim The delimiter character.
* @exception VpfException if the delimiter character cannot be found
* or if there is an error reading from the stream.
*/
static string
read_to_delim (istream &input, char delim)
{
string result;
char c = read_char(input);
while (c != delim) {
result += c;
c = read_char(input);
}
return result;
}
/**
* Read text from a column description.
*
* @param input The input stream.
* @exception VpfException if there is an error reading the text.
*/
static string
read_column_text (istream &input)
{
string result;
char c = read_char(input);
while (c != ',') {
if (c == ':') // FIXME: what if there was some text first?
throw true;
if (c == '\\')
c = read_char(input);
result += c;
c = read_char(input);
}
return result;
}
/**
* Test that an expected character appears.
*
* @param actual The character that appeared.
* @param expected The character that was expected.
* @exception VpfException If the actual character is not the same as
* the expected one.
*/
static void
assert_char (char actual, char expected)
{
if (actual != expected) {
string message = "Expected '";
message += expected;
message += "' but found '";
message += actual;
message += '\'';
throw VpfException(message);
}
}
/**
* Read a number of varying length.
*
* @param input The input stream.
* @param type The number type (0=none, 1=byte, 2=short, 3=int).
* @return The number, or -1 for an empty field.
*/
int
VpfTable::read_variable_int (istream &input, int type) const
{
switch (type) {
case 0:
return -1;
case 1:
return (unsigned char)read_char(input);
case 2:
return (unsigned short)read_short(input);
case 3:
return read_int(input);
default:
throw VpfException("Internal error reading variable integer");
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of VpfTable
////////////////////////////////////////////////////////////////////////
VpfTable::VpfTable (const string &fileName)
: _path(fileName),
_system_byte_order(LSB),
_file_byte_order(LSB),
_header_byte_size(-1),
_description(""),
_doc_file_name("")
{
init();
read(_path);
}
VpfTable::VpfTable (const VpfTable &table)
: _path(table._path),
_system_byte_order(table._system_byte_order),
_file_byte_order(table._file_byte_order),
_header_byte_size(table._header_byte_size),
_description(table._description),
_doc_file_name(table._doc_file_name)
{
init();
read(_path);
}
void
VpfTable::init ()
{
_system_byte_order = get_system_byte_order();
}
VpfTable::~VpfTable ()
{
int len = _columns.size();
int i;
for (i = 0; i < len; i++) {
VpfColumnDecl * tmp = _columns[i];
_columns[i] = 0;
delete tmp;
}
len = _rows.size();
for (i = 0; i < len; i++) {
VpfValue * tmp = _rows[i];
_rows[i] = 0;
delete[] tmp;
}
}
const string &
VpfTable::getPath () const
{
return _path;
}
const string &
VpfTable::getDescription () const
{
return _description;
}
const string &
VpfTable::getDocFileName () const
{
return _doc_file_name;
}
bool
VpfTable::hasColumn (const string &name) const
{
return (findColumn(name) != -1);
}
int
VpfTable::getColumnCount () const
{
return _columns.size();
}
int
VpfTable::getRowCount () const
{
return _rows.size();
}
const VpfColumnDecl &
VpfTable::getColumnDecl (int index) const
{
return *(_columns[index]);
}
void
VpfTable::read (const string &fileName)
{
_path = fileName;
ifstream input;
input.open(fileName.c_str(), ios_binary);
if (!input) {
input.clear();
string fileName2 = fileName + '.';
input.open(fileName2.c_str(), ios_binary);
}
if (!input)
throw VpfException(string("Failed to open VPF table file ") + fileName);
// Read the length as raw bytes
// (we don't know byte-order yet).
char rawLen[4];
read_chars(input, rawLen, 4);
// Now, check the byte order
char c = read_char(input);
switch (c) {
case 'L':
case 'l':
c = read_char(input);
// fall through...
case ';':
_file_byte_order = LSB;
break;
case 'M':
case 'm':
c = read_char(input);
_file_byte_order = MSB;
break;
default:
throw VpfException("Unknown byte-order marker");
}
assert_char(c, ';');
_header_byte_size = make_int(rawLen) + 4; // for initial integer
_description = read_to_delim(input, ';');
_doc_file_name = read_to_delim(input, ';');
// Read all of the column defs
while (true) {
VpfColumnDecl * col = new VpfColumnDecl(this);
if (!col->read_header(input))
break;
_columns.push_back(col);
}
if (!input.seekg(_header_byte_size))
throw VpfException("Failed to seek past header");
// Ignore variable-length indices for
// now, since we don't need random
// access.
VpfValue * row = new VpfValue[getColumnCount()];
while (read_row(input, row)) {
_rows.push_back(row);
row = new VpfValue[getColumnCount()];
}
delete[] row;
input.close();
}
bool
VpfTable::read_row (istream &input, VpfValue * row)
{
// FIXME: excessively crude test for EOF
char c;
if (!input.get(c))
return false;
else
#if !defined(SG_HAVE_NATIVE_SGI_COMPILERS)
input.unget();
#else
input.putback(c);
#endif
// OK, continue
int nCols = _columns.size();
for (int i = 0; i < nCols; i++) {
_columns[i]->read_value(input, &(row[i]));
}
return true;
}
const VpfValue &
VpfTable::getValue (int row, int column) const
{
if (row < 0 || row >= getRowCount())
throw VpfException("Row index out of range");
else if (column < 0 || column >= getColumnCount())
throw VpfException("Column index out of range");
else
return _rows[row][column];
}
const VpfValue &
VpfTable::getValue (int row, const string &columnName) const
{
int column = findColumn(columnName);
if (column == -1)
throw VpfException(string("Column name not found: ") + columnName);
else
return getValue(row, column);
}
int
VpfTable::findColumn (const string &columnName) const
{
int nColumns = getColumnCount();
for (int i = 0; i < nColumns; i++) {
if (columnName == getColumnDecl(i).getName())
return i;
}
return -1;
}
int
VpfTable::countMatches (const string &columnName, const char * value) const
{
int column = findColumn(columnName);
if (column == -1)
throw VpfException("Column does not exist");
int result = 0;
int nRows = getRowCount();
for (int i = 0; i < nRows; i++) {
if (string(value) == getValue(i, column).getText())
result++;
}
return result;
}
int
VpfTable::findMatch (const string &columnName, const char * value,
int index) const
{
int column = findColumn(columnName);
if (column == -1)
throw VpfException("Column does not exist");
int result = -1;
int nRows = getRowCount();
for (int i = 0; i < nRows; i++) {
if (string(value) == getValue(i, column).getText()) {
if (index == 0)
return i;
else
index--;
}
}
return result;
}
int
VpfTable::countMatches (const string &columnName, int value) const
{
int column = findColumn(columnName);
if (column == -1)
throw VpfException("Column does not exist");
int result = 0;
int nRows = getRowCount();
for (int i = 0; i < nRows; i++) {
if (value == getValue(i, column).getInt())
result++;
}
return result;
}
int
VpfTable::findMatch (const string &columnName, int value, int index) const
{
// START KLUDGE
if (columnName == "id" &&
hasColumn("id") &&
index == 0 &&
value >= 0 &&
value < getRowCount() &&
value == getValue(value-1, "id").getInt())
return value - 1;
// END KLUDGE
int column = findColumn(columnName);
if (column == -1)
throw VpfException("Column does not exist");
int result = -1;
int nRows = getRowCount();
for (int i = 0; i < nRows; i++) {
if (value == getValue(i, column).getRawInt()) {
if (index == 0)
return i;
else
index--;
}
}
return result;
}
short
VpfTable::read_short (istream &input) const
{
char buf[2];
read_chars(input, buf, 2);
return make_short(buf);
}
int
VpfTable::read_int (istream &input) const
{
char buf[4];
read_chars(input, buf, 4);
return make_int(buf);
}
float
VpfTable::read_float (istream &input) const
{
char buf[4];
read_chars(input, buf, 4);
return make_float(buf);
}
double
VpfTable::read_double (istream &input) const
{
char buf[8];
read_chars(input, buf, 8);
return make_double(buf);
}
short
VpfTable::make_short (char buf[2]) const
{
if (_system_byte_order == _file_byte_order) {
return *((short *)buf);
} else {
char out[2];
short *out_short = (short *)out;
swap2(buf, out);
return *out_short;
}
}
int
VpfTable::make_int (char buf[4]) const
{
if (_system_byte_order == _file_byte_order) {
return *((int *)buf);
} else {
char out[4];
int *int_out = (int *)out;
swap4(buf, out);
return *int_out;
}
}
float
VpfTable::make_float (char buf[4]) const
{
if (_system_byte_order == _file_byte_order) {
return *((float *)buf);
} else {
char out[4];
float *float_out = (float *)out;
swap4(buf, out);
return *float_out;
}
}
double
VpfTable::make_double (char buf[8]) const
{
if (_system_byte_order == _file_byte_order) {
return *((double *)buf);
} else {
char out[8];
double *double_out = (double *)out;
swap8(buf, out);
return *double_out;
}
}
////////////////////////////////////////////////////////////////////////
// Implementation of VpfColumnDecl
////////////////////////////////////////////////////////////////////////
VpfColumnDecl::VpfColumnDecl (const VpfTable * table)
: _table(table),
_description(""),
_value_description_table("-"),
_thematic_index_name("-"),
_narrative_table("-")
{
}
VpfColumnDecl::~VpfColumnDecl ()
{
}
const string &
VpfColumnDecl::getName () const
{
return _name;
}
VpfColumnDecl::KeyType
VpfColumnDecl::getKeyType () const
{
return _key_type;
}
VpfValue::Type
VpfColumnDecl::getValueType () const
{
return VpfValue::convertType(_raw_type);
}
const string &
VpfColumnDecl::getDescription () const
{
return _description;
}
const string &
VpfColumnDecl::getValueDescriptionTable () const
{
return _value_description_table;
}
const string &
VpfColumnDecl::getThematicIndexName () const
{
return _thematic_index_name;
}
const string &
VpfColumnDecl::getNarrativeTable () const
{
return _narrative_table;
}
bool
VpfColumnDecl::read_header (istream &input)
{
char c = read_char(input);
if (c == ';')
return false;
_name = "";
_name += c;
_name += read_to_delim(input, '=');
_raw_type = read_char(input);
c = read_char(input);
assert_char(c, ',');
string length_string = read_to_delim(input, ',');
if (length_string == "*")
_element_count = -1;
else
_element_count = atoi(length_string.c_str());
// Not allowed in an array...
if (_element_count != 1) {
switch (_raw_type) {
case 'F':
case 'R':
case 'S':
case 'I':
case 'D':
case 'X':
case 'K':
throw VpfException("Illegal array type");
}
}
string keyType;
try {
keyType = read_column_text(input);
} catch (bool end) { // FIXME: what is this is only field???
throw VpfException("required key type field missing");
}
if (keyType.size() != 1)
throw VpfException("Key type should be length 1");
switch (keyType[0]) {
case 'P':
_key_type = PRIMARY_KEY;
break;
case 'U':
_key_type = UNIQUE;
break;
case 'N':
_key_type = NON_UNIQUE;
break;
default:
throw VpfException("Unrecognized key type");
}
// FIXME: test for end of record
try {
_description = read_column_text(input);
} catch (bool end) {
return true;
}
try {
_value_description_table = read_column_text(input);
} catch (bool end) {
return true;
}
// fixme: convert to lower case
try {
_thematic_index_name = read_column_text(input);
} catch (bool end) {
return true;
}
// fixme: convert to lower case
try {
_narrative_table = read_column_text(input);
} catch (bool end) {
return true;
}
// fixme: convert to lower case
c = read_char(input);
assert_char(c, ':');
return true;
}
bool
VpfColumnDecl::read_value (istream &input, VpfValue * value)
{
switch (_raw_type) {
case 'T':
case 'L':
case 'N':
case 'M': {
int length = getElementCount();
if (length == -1)
length = _table->read_int(input);
char *buf = new char[length]; // FIXME: inefficient
read_chars(input, buf, length);
value->setRawCharArray(buf, length, _raw_type);
delete[] buf;
break;
};
case 'F':
value->setRawFloat(_table->read_float(input));
break;
case 'R':
value->setRawDouble(_table->read_double(input));
break;
case 'S':
value->setRawShort(_table->read_short(input));
break;
case 'I':
value->setRawInt(_table->read_int(input));
break;
case 'C': {
int length = getElementCount();
if (length == -1)
length = _table->read_int(input);
VpfValue::float_xy * buf = new VpfValue::float_xy[length];
for (int i = 0; i < length; i++) {
buf[i].x = _table->read_float(input);
buf[i].y = _table->read_float(input);
}
value->setRawFloatXYArray(buf, length);
delete[] buf;
break;
};
case 'B': {
int length = getElementCount();
if (length == -1)
length = _table->read_int(input);
VpfValue::double_xy * buf = new VpfValue::double_xy[length];
for (int i = 0; i < length; i++) {
buf[i].x = _table->read_double(input);
buf[i].y = _table->read_double(input);
}
value->setRawDoubleXYArray(buf, length);
delete[] buf;
break;
};
case 'Z': {
int length = getElementCount();
if (length == -1)
length = _table->read_int(input);
VpfValue::float_xyz * buf = new VpfValue::float_xyz[length];
for (int i = 0; i < length; i++) {
buf[i].x = _table->read_float(input);
buf[i].y = _table->read_float(input);
buf[i].z = _table->read_float(input);
}
value->setRawFloatXYZArray(buf, length);
delete[] buf;
break;
};
case 'Y': {
int length = getElementCount();
if (length == -1)
length = _table->read_int(input);
VpfValue::double_xyz * buf = new VpfValue::double_xyz[length];
for (int i = 0; i < length; i++) {
buf[i].x = _table->read_double(input);
buf[i].y = _table->read_double(input);
buf[i].z = _table->read_double(input);
}
value->setRawDoubleXYZArray(buf, length);
delete[] buf;
break;
};
case 'D': {
char *buf = new char[20]; // FIXME: inefficient
read_chars(input, buf, 20);
value->setRawDateTime(buf);
delete[] buf;
break;
};
case 'X':
value->setNull();
break;
case 'K': {
VpfCrossRef id;
unsigned char length_info = (unsigned char)read_char(input);
id.current_tile_key =
_table->read_variable_int(input, (length_info&0xC0)>>6);
id.next_tile_id =
_table->read_variable_int(input, (length_info&0x30)>>4);
id.next_tile_key =
_table->read_variable_int(input, (length_info&0x0C)>>2);
id.unused_key = _table->read_variable_int(input, length_info&0x03);
value->setRawCrossTileId(id);
break;
};
default:
throw VpfException("Internal error: bad type");
}
return true;
}
char
VpfColumnDecl::getRawType () const
{
return _raw_type;
}
int
VpfColumnDecl::getElementCount () const
{
return _element_count;
}
// end of table.cxx

Some files were not shown because too many files have changed in this diff Show more