Remove old libs and tools that have better counterparts in GDAL/GRASS nowdays. genapts810 has to go as well
This commit is contained in:
parent
8a092947da
commit
a1a331db7c
160 changed files with 3 additions and 33855 deletions
|
@ -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)
|
||||
|
|
1
src/Airports/GenAirports/.gitignore
vendored
1
src/Airports/GenAirports/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
genapts
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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
|
||||
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 );
|
|
@ -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
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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";
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
|
@ -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
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
@ -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
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
|
@ -24,7 +24,7 @@ add_executable(genapts850
|
|||
|
||||
target_link_libraries(genapts850
|
||||
Polygon Geometry
|
||||
Array Output poly2tri
|
||||
Array Output
|
||||
${POCO_FOUNDATION}
|
||||
${POCO_NET}
|
||||
${GDAL_LIBRARY}
|
||||
|
|
|
@ -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}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include <simgear/structure/exception.hxx>
|
||||
|
||||
#include <Geometry/trinodes.hxx>
|
||||
#include <poly2tri/interface.h>
|
||||
|
||||
#include "polygon.hxx"
|
||||
|
||||
|
|
1
src/Lib/e00/.gitignore
vendored
1
src/Lib/e00/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
teste00
|
|
@ -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})
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,11 +0,0 @@
|
|||
|
||||
|
||||
add_library(poly2tri STATIC
|
||||
construct.c
|
||||
interface.h
|
||||
misc.c
|
||||
monotone.c
|
||||
tri.c
|
||||
triangulate.h
|
||||
)
|
||||
|
|
@ -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)
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
|
||||
|
|
@ -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 */
|
|
@ -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)
|
||||
|
|
@ -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( <ime );
|
||||
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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
@ -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 */
|
|
@ -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.
8
src/Lib/shapelib/.gitignore
vendored
8
src/Lib/shapelib/.gitignore
vendored
|
@ -1,8 +0,0 @@
|
|||
dbfadd
|
||||
dbfcreate
|
||||
dbfdump
|
||||
shpadd
|
||||
shpcreate
|
||||
shpdump
|
||||
shptest
|
||||
shputils
|
|
@ -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 )
|
||||
|
||||
|
|
@ -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.
|
||||
|
|
@ -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>
|
|
@ -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 );
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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
|
@ -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
|
|
@ -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.
|
||||
|
|
@ -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 */
|
|
@ -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>
|
||||
|
||||
|
||||
|
|
@ -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>
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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
|
@ -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 );
|
||||
}
|
|
@ -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 );
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
|
|
@ -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
|
@ -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
|
|
@ -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
|
||||
|
3
src/Lib/vpf/.gitignore
vendored
3
src/Lib/vpf/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
vpf-dump
|
||||
vpf-summary
|
||||
vpf-topology
|
|
@ -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)
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
Loading…
Add table
Reference in a new issue