1
0
Fork 0

- new library to support NIMA's Vector Product Format

This commit is contained in:
curt 2001-09-18 21:17:48 +00:00
parent 4e43a03fcb
commit 3050aca5c7
36 changed files with 6372 additions and 1 deletions

View file

@ -9,4 +9,5 @@ SUBDIRS = \
Polygon \
poly2tri \
shapelib \
TriangleJRS
TriangleJRS \
vpf

49
src/Lib/vpf/Makefile.am Normal file
View file

@ -0,0 +1,49 @@
noinst_LIBRARIES = libvpf.a
libvpf_a_SOURCES = \
component.hxx \
coverage.hxx \
database.hxx \
feature.hxx \
label.hxx \
library.hxx \
contour.hxx \
line.hxx \
polygon.hxx \
property.hxx \
table.hxx \
tablemgr.hxx \
tile.hxx \
value.hxx \
vpf.hxx \
vpfbase.hxx \
vpfbase.cxx \
value.cxx \
table.cxx \
tablemgr.cxx \
component.cxx \
database.cxx \
library.cxx \
coverage.cxx \
feature.cxx \
line.cxx \
contour.cxx \
polygon.cxx \
label.cxx \
property.cxx \
tile.cxx \
vpf-summary.cxx \
vpf-dump.cxx \
vpf-topology.cxx
noinst_PROGRAMS = vpf-dump vpf-topology vpf-summary
vpf_dump_SOURCES = vpf-dump.cxx
vpf_dump_LDADD = libvpf.a
vpf_topology_SOURCES = vpf-topology.cxx
vpf_topology_LDADD = libvpf.a
vpf_summary_SOURCES = vpf-summary.cxx
vpf_summary_LDADD = libvpf.a

101
src/Lib/vpf/component.cxx Normal file
View file

@ -0,0 +1,101 @@
// 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

198
src/Lib/vpf/component.hxx Normal file
View file

@ -0,0 +1,198 @@
// 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$
*/
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;
mutable VpfTableManager &_table_manager;
};
#endif
// end of component.hxx

111
src/Lib/vpf/contour.cxx Normal file
View file

@ -0,0 +1,111 @@
// 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;
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;
} 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");
}
_lines->push_back(info);
} while (current_edge != _start_edge);
}
return *_lines;
}
// end of contour.cxx

52
src/Lib/vpf/contour.hxx Normal file
View file

@ -0,0 +1,52 @@
// contour.hxx - declaration of VpfContour
#ifndef __CONTOUR_HXX
#define __CONTOUR_HXX 1
#include "vpfbase.hxx"
#include "component.hxx"
#include <string>
#include <vector>
class VpfTable;
class 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

129
src/Lib/vpf/coverage.cxx Normal file
View file

@ -0,0 +1,129 @@
// 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();
return (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

214
src/Lib/vpf/coverage.hxx Normal file
View file

@ -0,0 +1,214 @@
// 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$
* @see VpfDataBase
* @see VpfLibrary
*/
class VpfCoverage : public VpfComponent
{
public:
/**
* Copy constructor.
*
* @param coverage The coverage to copy.
*/
VpfCoverage::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

91
src/Lib/vpf/database.cxx Normal file
View file

@ -0,0 +1,91 @@
// 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

161
src/Lib/vpf/database.hxx Normal file
View file

@ -0,0 +1,161 @@
// 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$
* @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 ();
/**
* 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:
/**
* Copy constructor.
*/
VpfDataBase (const VpfDataBase &database);
mutable VpfTableManager _table_manager;
mutable const VpfTable * _dht;
mutable const VpfTable * _lat;
};
#endif // __VPF_DATABASE_HXX
// end of database.hxx

276
src/Lib/vpf/feature.cxx Normal file
View file

@ -0,0 +1,276 @@
// 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 != "id" &&
name != "tile_id" &&
name != "end_id" &&
name != "edg_id" &&
name != "fac_id" &&
name != "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

271
src/Lib/vpf/feature.hxx Normal file
View file

@ -0,0 +1,271 @@
// 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$
*/
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

57
src/Lib/vpf/label.cxx Normal file
View file

@ -0,0 +1,57 @@
// 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

96
src/Lib/vpf/label.hxx Normal file
View file

@ -0,0 +1,96 @@
// 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$
*/
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

121
src/Lib/vpf/library.cxx Normal file
View file

@ -0,0 +1,121 @@
// 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 path = getChildFileName("tileref");
if (hasFile(path, "tileref.aft"))
_tileref_aft = getTable(getFileName(path, "tileref.aft"));
if (hasFile(path, "fbr"))
_tileref_fbr = getTable(getFileName(path, "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

183
src/Lib/vpf/library.hxx Normal file
View file

@ -0,0 +1,183 @@
// 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$
* @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

93
src/Lib/vpf/line.cxx Normal file
View file

@ -0,0 +1,93 @@
// 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

144
src/Lib/vpf/line.hxx Normal file
View file

@ -0,0 +1,144 @@
// 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$
*/
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

82
src/Lib/vpf/polygon.cxx Normal file
View file

@ -0,0 +1,82 @@
// 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

146
src/Lib/vpf/polygon.hxx Normal file
View file

@ -0,0 +1,146 @@
// 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$
*/
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

138
src/Lib/vpf/property.cxx Normal file
View file

@ -0,0 +1,138 @@
// 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() != "-");
}
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

181
src/Lib/vpf/property.hxx Normal file
View file

@ -0,0 +1,181 @@
// 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$
*/
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

845
src/Lib/vpf/table.cxx Normal file
View file

@ -0,0 +1,845 @@
// table.cxx - implementation of VpfTable
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include <string>
#include <fstream>
using std::string;
using std::ifstream;
using std::istream;
#include "vpfbase.hxx"
#include "table.hxx"
////////////////////////////////////////////////////////////////////////
// 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(), std::ios::binary);
if (!input) {
input.clear();
string fileName2 = fileName + '.';
input.open(fileName2.c_str(), std::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
input.unget();
// 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];
swap2(buf, out);
return *((short *)out);
}
}
int
VpfTable::make_int (char buf[4]) const
{
if (_system_byte_order == _file_byte_order) {
return *((int *)buf);
} else {
char out[4];
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];
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];
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

454
src/Lib/vpf/table.hxx Normal file
View file

@ -0,0 +1,454 @@
// table.hxx - declarations for VPF low-level table structures.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_TABLE_HXX
#define __VPF_TABLE_HXX 1
#include <iostream>
#include <string>
#include <vector>
#include "vpfbase.hxx"
#include "value.hxx"
////////////////////////////////////////////////////////////////////////
// VpfTable class declaration.
////////////////////////////////////////////////////////////////////////
class VpfColumnDecl;
/**
* A low-level view of a VPF data table.
*
* <p>This class provides basic row/column access to the data in a
* VPF table. Higher-level classes implement the logic behind the
* different table types. Each column in the table contains
* declaration information available though a {@link VpfColumnDecl}
* object, and every field contains a leaf value available through
* a {@link VpfValue} object.</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision$
*/
class VpfTable {
public:
/**
* Construct a new table from a file name.
*
* @param fileName The path to the table file.
* @exception VpfException If there is an error reading the table.
*/
VpfTable (const std::string &fileName);
/**
* Copy a table.
*
* @param table The table to copy.
*/
VpfTable (const VpfTable &table);
/**
* Destructor.
*/
virtual ~VpfTable ();
/**
* Get the path/filename of this table.
*
* @return The table's filename.
*/
virtual const std::string &getPath () const;
/**
* Get the table description.
*
* <p>This is the human-readable title provided by the table
* creator.</p>
*
* @return The description provided in the table.
*/
virtual const std::string &getDescription () const;
/**
* Get the name of the documentation file for this table.
*
* @return The documentation file name, or "-" if there is no
* documentation file.
*/
virtual const std::string &getDocFileName () const;
/**
* Test whether a column exists in a table.
*
* @param name The column name to test.
* @return true if the column is present, false otherwise.
*/
virtual bool hasColumn (const std::string &name) const;
/**
* Count the columns in the table.
*
* @return The number of columns in each row of the table.
*/
virtual int getColumnCount () const;
/**
* Count the rows in the table.
*
* @return The number of rows in the table.
*/
virtual int getRowCount () const;
/**
* Get the declaration information for a column.
*
* <p>This information includes the column name and type and
* optional associated files.</p>
*
* @param index The zero-based index of the row.
* @return The column's declaration information.
* @exception VpfException If the index is out of range.
*/
virtual const VpfColumnDecl &getColumnDecl (int index) const;
/**
* Get a value by row and column.
*
* @param row The zero-based index of the row.
* @param column The zero-based index of the column.
* @return The value at the specified position.
* @exception VpfException If the row or column is out of range.
*/
virtual const VpfValue &getValue (int row, int column) const;
/**
* Get a value by row and column name.
*
* @param row The zero-based index of the row.
* @param columnName The name of the column.
* @return The value at the specified position.
* @exception VpfException If the row is out of range or there
* is no column with the name provided.
*/
virtual const VpfValue &getValue (int row,
const std::string &columName) const;
/**
* Given a column name, look up the column number.
*
* @param columnName The name of the column to look up.
* @return The column number, or -1 if not found.
*/
virtual int findColumn (const std::string &columnName) const;
/**
* Count the matches for a character array value in a column.
*
* @param columnName The name of the column to search.
* @param value The value to count.
* @return The number of times the value appears.
* @exception VpfException If the column does not exist or does
* not contain a character-array data type.
*/
virtual int countMatches (const std::string &columnName,
const char * value) const;
/**
* Find a row with a column value matching a character array.
*
* @param columnName The name of the column to search.
* @param value The value to search for.
* @param index The index of the match to return (defaults to
* 0 for the first match).
* @return The row number containing the match, or -1 if none was
* found.
* @exception VpfException If the column does not exist or does
* not contain a character-array data type.
*/
virtual int findMatch (const std::string &columnName,
const char * value,
int index = 0) const;
/**
* Count the matches for an integer value in a column.
*
* @param columnName The name of the column to search.
* @param value The value to count.
* @return The number of times the value appears.
* @exception VpfException If the column does not exist or does
* not contain an integer data type.
*/
virtual int countMatches (const std::string &columnName, int value) const;
/**
* Find a row with a column value matching an integer.
*
* @param columnName The name of the column to search.
* @param value The value to search for.
* @param index The index of the match to return (defaults to
* 0 for the first match).
* @return The row number containing the match, or -1 if none was
* found.
* @exception VpfException If the column does not exist or does
* not contain an integer type.
*/
virtual int findMatch (const std::string &columnName,
int value,
int index = 0) const;
protected:
friend class VpfColumnDecl;
friend class VpfTableManager;
friend class VpfComponent;
enum ByteOrder {
MSB,
LSB
};
virtual void init ();
virtual ByteOrder get_system_byte_order () const;
virtual void read (const std::string &fileName);
virtual bool read_row (std::istream &input, VpfValue row[]);
// virtual void seek_to_row (std::istream &input, int row);
virtual short read_short (std::istream &input) const;
virtual int read_int (std::istream &input) const;
virtual float read_float (std::istream &input) const;
virtual double read_double (std::istream &input) const;
virtual int read_variable_int (std::istream &input, int type) const;
virtual short make_short (char buf[2]) const;
virtual int make_int (char buf[4]) const;
virtual float make_float (char buf[4]) const;
virtual double make_double (char buf[8]) const;
private:
std::string _path;
ByteOrder _system_byte_order;
ByteOrder _file_byte_order;
int _header_byte_size;
std::string _description;
std::string _doc_file_name;
std::vector<VpfColumnDecl *> _columns;
std::vector<VpfValue *> _rows;
};
////////////////////////////////////////////////////////////////////////
// VpfColumnDecl class declaration.
////////////////////////////////////////////////////////////////////////
/**
* Declaration for a column in a VPF table.
*
* <p>This declaration applies to the same column position in all rows
* of the table. It specified the column name and data type and
* whether the column contains primary or unique keys, among other
* information.</p>
*
* <p>Instances of this class are managed only by the {@link VpfTable}
* class, so there are no public constructors or destructors.</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision$
*/
class VpfColumnDecl {
public:
// FIXME: there may also be an 'F'
// type for foreign key (at least,
// openmap thinks so).
/**
* The key type of the column.
*
* <p>A column may contain a primary key, a unique key, or a
* non-unique key (i.e. just general data). The primary key
* can be used to look up a specific row.</p>
*/
enum KeyType {
PRIMARY_KEY,
UNIQUE,
NON_UNIQUE
};
/**
* Get the column name.
*
* <p>This is the equivalent of a variable name for all
* entries in this column.</p>
*
* @return The column name as a string.
*/
virtual const std::string &getName () const;
/**
* Get the key type of this column (PRIMARY_KEY, UNIQUE, or NON_UNIQUE).
*
* @return The key type for this column.
*/
virtual KeyType getKeyType () const;
/**
* Get the user-visible value type.
*
* @return The value type for the column.
*/
virtual VpfValue::Type getValueType () const;
/**
* Get a textual description of this column.
*
* @return Text describing this column.
*/
virtual const std::string &getDescription () const;
/**
* Get the name of the table describing this column.
*
* <p>Columns may optionally have an external table providing
* a more detailed description.</p>
*
* @return The name of the value description table, or "-" if there
* is none.
*/
virtual const std::string &getValueDescriptionTable () const;
/**
* Get the name of the thematic index for this column.
*
* <p>Columns may optionally have an external table providing
* a thematic index.</p>
*
* @return The name of the table containing the thematic index, or
* "-" if there is none.
*/
virtual const std::string &getThematicIndexName () const;
/**
* Get the name of the narrative table for this column.
*
* <p>Columns may optionally have an external table providing
* narrative.</p>
*
* @return The name of the narrative table, or "-" if there is none.
*/
virtual const std::string &getNarrativeTable () const;
/**
* Get the declared size of the column
*
* @return The declared size of the column, or -1 for variable size.
*/
virtual int getElementCount () const;
protected:
friend class VpfTable;
/**
* Protected constructor.
*
* <p>This is the only way to make a column from scratch. Users
* will obtain references to column objects through VpfTable.</p>
*
* @param table The table to which the column declaration applies.
*/
VpfColumnDecl (const VpfTable * table);
/**
* Protected destructor.
*
* <p>Only VpfTable may delete a column declaration.
*/
virtual ~VpfColumnDecl ();
/**
* Read the actual header from input.
*
* @param input The input stream.
* @return true if the header was read successfully.
*/
bool read_header (std::istream &input);
/**
* Read a value from input.
*
* @param input The input stream.
* @param value The object to hold the value.
* @return true if a value was read successfully.
*/
bool read_value (std::istream &input, VpfValue * value);
/**
* Get the column data type.
*
* <p>This is the only type of data that will appear in this column.
* The types are declared in the {@link VpfValue} class.</p>
*
* @return The column data type.
*/
virtual char getRawType () const;
private:
const VpfTable * _table;
std::string _name;
char _raw_type;
int _element_count;
KeyType _key_type;
std::string _description;
std::string _value_description_table;
std::string _thematic_index_name;
std::string _narrative_table;
};
#endif
// end of table.hxx

98
src/Lib/vpf/tablemgr.cxx Normal file
View file

@ -0,0 +1,98 @@
// tablemgr.cxx - implementation of VpfTableManager
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "tablemgr.hxx"
#include "table.hxx"
// #include <iostream>
// using std::cerr;
// using std::endl;
#include <string>
#include <map>
#include <list>
using std::string;
using std::map;
using std::list;
VpfTableManager::VpfTableManager ()
: _table_count(0)
{
}
VpfTableManager::~VpfTableManager ()
{
cull_queue(0);
// cerr << "Queue size at end: " << _empty_queue.size() << endl;
// cerr << "Total tables remaining: " << _table_count << endl;
if (_table_count != 0)
throw VpfTable("Table manager deleted while some tables still in use");
}
const VpfTable *
VpfTableManager::getTable (const string &path)
{
const VpfTable * result = _table_map[path];
if (result == 0) {
result = new VpfTable(path);
_table_map[path] = result;
_table_references[path] = 1;
_table_count++;
} else {
if (_table_references[path] < 1)
remove_from_queue(result);
_table_references[path]++;
}
return result;
}
const VpfTable *
VpfTableManager::copyTable (const VpfTable * table)
{
if (table != 0) {
_table_references[table->getPath()]++;
}
return table;
}
void
VpfTableManager::freeTable (const VpfTable *table)
{
if (table != 0) {
const string &path = table->getPath();
_table_references[path]--;
if (_table_references[path] == 0)
add_to_queue(table);
cull_queue(MAX_QUEUE_SIZE);
}
}
void
VpfTableManager::add_to_queue (const VpfTable * table)
{
_empty_queue.push_front(table);
}
void
VpfTableManager::remove_from_queue (const VpfTable * table)
{
_empty_queue.remove(table);
}
void
VpfTableManager::cull_queue (int max_size)
{
while (int(_empty_queue.size()) > max_size) {
const VpfTable * table = _empty_queue.back();
// cerr << "Culling " << table->getPath() << endl;
_empty_queue.pop_back();
_table_map[table->getPath()] = 0; // FIXME: remove key completely
_table_references[table->getPath()] = 0; // FIXME: ditto
delete table;
_table_count--;
}
}
// end of tablemgr.cxx

51
src/Lib/vpf/tablemgr.hxx Normal file
View file

@ -0,0 +1,51 @@
// tablemgr.hxx - declaration of VpfTableManager
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_TABLEMGR_HXX
#define __VPF_TABLEMGR_HXX 1
#include <string>
#include <map>
#include <list>
class VpfTable;
/**
* Manage VPF tables in memory with reference counting.
*
* <p>This is an extremely simplistic management class, but it's
* useful for ensuring that tables are kept around for a little
* while in case they're needed, and that the same table is
* never loaded twice.</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision$
*/
class VpfTableManager
{
public:
VpfTableManager ();
virtual ~VpfTableManager ();
virtual const VpfTable * getTable (const std::string &path);
virtual const VpfTable * copyTable (const VpfTable * table);
virtual void freeTable (const VpfTable * table);
private:
static const int MAX_QUEUE_SIZE = 3; // keep up to 3 unused tables around
void add_to_queue (const VpfTable * table);
void remove_from_queue (const VpfTable * table);
void cull_queue (int max_size);
int _table_count;
std::map<std::string,const VpfTable *> _table_map;
std::map<std::string,int> _table_references;
std::list<const VpfTable *> _empty_queue;
};
#endif
// end of tablemgr.hxx

88
src/Lib/vpf/tile.cxx Normal file
View file

@ -0,0 +1,88 @@
// tile.cxx - implementation of VpfTile
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include "tile.hxx"
#include "table.hxx"
#include "value.hxx"
#include <string>
using std::string;
VpfTile::VpfTile (VpfTableManager &tableManager,
const string &path, int tile_id)
: VpfComponent(tableManager, path),
_tile_id(tile_id), // FIXME: kludge
_face_id(-1),
_aft(0),
_fbr(0)
{
}
VpfTile::VpfTile (const VpfTile &tile)
: VpfComponent(tile.getTableManager(), tile.getPath()),
_tile_id(tile._tile_id),
_face_id(tile._face_id),
_aft(copyTable(tile._aft)),
_fbr(copyTable(tile._fbr))
{
}
VpfTile::~VpfTile ()
{
freeTable(_aft);
freeTable(_fbr);
}
const char *
VpfTile::getTileSubdir () const
{
const VpfTable &aft = getAFT();
int row = aft.findMatch("id", _tile_id);
string subdir = aft.getValue(row, "tile_name").getText();
for (unsigned int i = 0; i < subdir.size(); i++) {
if (subdir[i] == '\\')
subdir[i] = PATHSEP;
else
subdir[i] = tolower(subdir[i]);
}
return subdir.c_str();
}
const VpfRectangle
VpfTile::getBoundingRectangle () const
{
VpfRectangle rect;
const VpfTable &fbr = getFBR();
if (_face_id == -1) {
const VpfTable &aft = getAFT();
int row = aft.findMatch("id", _tile_id);
_face_id = aft.getValue(row, "fac_id").getInt();
}
int row = fbr.findMatch("id", _face_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;
}
const VpfTable &
VpfTile::getAFT () const
{
if (_aft == 0)
_aft = getChildTable("tileref.aft");
return *_aft;
}
const VpfTable &
VpfTile::getFBR () const
{
if (_fbr == 0)
_fbr = getChildTable("fbr");
return *_fbr;
}
// end of tile.cxx

120
src/Lib/vpf/tile.hxx Normal file
View file

@ -0,0 +1,120 @@
// tile.hxx - declaration of VpfTile
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_TILE_HXX
#define __VPF_TILE_HXX 1
#include "vpfbase.hxx"
#include "component.hxx"
#include <string>
class VpfTable;
/**
* Information about a tile.
*
* <p>This class applies only to tiled coverages. The library uses
* it to find the path to a tile, and the end-user can get a copy
* from the VpfFeature class to do a quick check on a topology's
* tile bounds before getting the topology's own bounding rectangle.</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision$
*/
class VpfTile : public VpfComponent
{
public:
/**
* Copy constructor.
*
* @param tile The tile to copy.
*/
VpfTile (const VpfTile &tile);
/**
* Destructor.
*/
virtual ~VpfTile ();
/**
* Get the subdirectory for a tile.
*
* <p>The subdirectory returned is relative to a coverage.</p>
*
* @return The subdirectory for a tile.
*/
virtual const char * getTileSubdir () const;
/**
* Get the bounding rectangle for a tile.
*
* <p>This is a particularly valuable method for pruning out
* topologies outside an area of interest -- it is much cheaper
* to test the bounding rectangle for a tile than it is to check
* the bounding rectangle for an individual line or polygon, so
* check this first.</p>
*
* @return The bounding rectangle for the tile.
*/
virtual const VpfRectangle getBoundingRectangle () const;
protected:
friend class VpfFeature;
/**
* Protected constructor.
*
* <p>This constructor is the only mechanism for building a new tile
* object from scratch. Library users should obtain a tile object
* from the VpfFeature class.</p>
*
* @param path The path to the tileref directory.
* @param tile_id The identifier of the tile.
*/
VpfTile (VpfTableManager &tableManager,
const std::string &path, int tile_id);
/**
* Get the area feature table for the tileref.
*
* <p>The AFT contains the subdirectory information and face id
* for each tile. This is a lazy implementation: the AFT will not
* be loaded unless it is actually needed.</p>
*
* @return The AFT table.
*/
const VpfTable &getAFT () const;
/**
* Get the face bounding rectangle table for the tileref.
*
* <p>The FBR contains the bounding rectangle for each tile, indexed
* by face id. This is a lazy implementation: the FBR will not
* be loaded unless it is actually needed.</p>
*
* @return The FBR table.
*/
const VpfTable &getFBR () const;
private:
int _tile_id;
mutable int _face_id;
mutable const VpfTable * _aft;
mutable const VpfTable * _fbr;
};
#endif
// end of tile.hxx

521
src/Lib/vpf/value.cxx Normal file
View file

@ -0,0 +1,521 @@
// value.cxx - implementation of VpfValue
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include <iostream>
#include <string>
using std::ostream;
using std::string;
#include "vpfbase.hxx"
#include "value.hxx"
VpfValue::VpfValue ()
: _raw_type('X'),
_element_count(0)
{
}
VpfValue::VpfValue (const VpfValue &value)
: _raw_type('X'),
_element_count(0)
{
switch (value._raw_type) {
case 'T':
case 'L':
case 'N':
case 'M':
setRawCharArray(value.getRawCharArray(),
value._element_count, value._raw_type);
break;
case 'F':
setRawFloat(value.getRawFloat());
break;
case 'R':
setRawDouble(value.getRawDouble());
break;
case 'S':
setRawShort(value.getRawShort());
break;
case 'I':
setRawInt(value.getRawInt());
break;
case 'C':
setRawFloatXYArray(value.getRawFloatXYArray(), value._element_count);
break;
case 'B':
setRawDoubleXYArray(value.getRawDoubleXYArray(), value._element_count);
break;
case 'Z':
setRawFloatXYZArray(value.getRawFloatXYZArray(), value._element_count);
break;
case 'Y':
setRawDoubleXYZArray(value.getRawDoubleXYZArray(), value._element_count);
break;
case 'D':
setRawDateTime(value.getRawDateTime());
break;
case 'X':
break;
case 'K':
setRawCrossTileId(value.getRawCrossTileId());
break;
}
}
VpfValue::~VpfValue ()
{
clear();
}
VpfValue::Type
VpfValue::getType () const
{
return convertType(_raw_type);
}
int
VpfValue::getElementCount () const
{
return _element_count;
}
const char *
VpfValue::getText () const
{
return getRawCharArray();
}
int
VpfValue::getInt () const
{
switch(_raw_type) {
case 'S':
return getRawShort();
case 'I':
return getRawInt();
default:
throw VpfException("Type not 'S' or 'I'");
}
}
double
VpfValue::getReal () const
{
switch(_raw_type) {
case 'F':
return getRawFloat();
case 'R':
return getRawDouble();
default:
throw VpfException("Type not 'F' or 'R'");
}
}
const VpfPoint
VpfValue::getPoint (int index) const
{
VpfPoint result;
if (index < 0 || index >= _element_count)
throw VpfException("Index out of range");
switch (_raw_type) {
case 'C':
result.x = _raw_value.float_xy_array[index].x;
result.y = _raw_value.float_xy_array[index].y;
result.z = 0.0;
break;
case 'B':
result.x = _raw_value.double_xy_array[index].x;
result.y = _raw_value.double_xy_array[index].y;
result.z = 0.0;
break;
case 'Z':
result.x = _raw_value.float_xyz_array[index].x;
result.y = _raw_value.float_xyz_array[index].y;
result.z = _raw_value.float_xyz_array[index].z;
break;
case 'Y':
result.x = _raw_value.double_xyz_array[index].x;
result.y = _raw_value.double_xyz_array[index].y;
result.z = _raw_value.double_xyz_array[index].z;
break;
default:
throw VpfException("Not an array of coordinates");
}
return result;
}
const char *
VpfValue::getDate () const
{
return getRawDateTime();
}
const VpfCrossRef
VpfValue::getCrossRef () const
{
return getRawCrossTileId();
}
char
VpfValue::getRawType () const
{
return _raw_type;
}
void
VpfValue::assertRawType (char type) const
{
if (_raw_type != type)
throw VpfException("Type mismatch");
}
const char *
VpfValue::getRawCharArray () const
{
switch (_raw_type) {
case 'T':
case 'L':
case 'N':
case 'M':
return _raw_value.char_array;
default:
throw VpfException("Type mismatch");
}
}
short
VpfValue::getRawShort () const
{
assertRawType('S');
return _raw_value.short_value;
}
int
VpfValue::getRawInt () const
{
assertRawType('I');
return _raw_value.int_value;
}
float
VpfValue::getRawFloat () const
{
assertRawType('F');
return _raw_value.float_value;
}
double
VpfValue::getRawDouble () const
{
assertRawType('R');
return _raw_value.double_value;
}
const VpfValue::float_xy *
VpfValue::getRawFloatXYArray () const
{
assertRawType('C');
return _raw_value.float_xy_array;
}
const VpfValue::double_xy *
VpfValue::getRawDoubleXYArray () const
{
assertRawType('B');
return _raw_value.double_xy_array;
}
const VpfValue::float_xyz *
VpfValue::getRawFloatXYZArray () const
{
assertRawType('Z');
return _raw_value.float_xyz_array;
}
const VpfValue::double_xyz *
VpfValue::getRawDoubleXYZArray () const
{
assertRawType('Y');
return _raw_value.double_xyz_array;
}
const char *
VpfValue::getRawDateTime () const
{
assertRawType('D');
return _raw_value.char_array;
}
const VpfCrossRef &
VpfValue::getRawCrossTileId () const
{
assertRawType('K');
return *(_raw_value.cross_tile_value);
}
void
VpfValue::setNull ()
{
clear();
_raw_type = 'X';
}
void
VpfValue::setRawCharArray (const char * array, int size, char type)
{
clear();
switch (type) {
case 'T':
case 'L':
case 'N':
case 'M':
_raw_type = type;
break;
default:
throw VpfException("Illegal type for character array");
}
_element_count = size;
int i;
// strip trailing spaces
for (i = size - 1; i > 0; i--) {
if (array[i] == ' ')
_element_count--;
else
break;
}
// Add an extra byte for final null
_raw_value.char_array = new char[_element_count+1];
for (i = 0; i < _element_count; i++)
_raw_value.char_array[i] = array[i];
_raw_value.char_array[_element_count] = '\0';
}
void
VpfValue::setRawShort (short value)
{
clear();
_raw_type = 'S';
_element_count = 1;
_raw_value.short_value = value;
}
void
VpfValue::setRawInt (int value)
{
clear();
_raw_type = 'I';
_element_count = 1;
_raw_value.int_value = value;
}
void
VpfValue::setRawFloat (float value)
{
clear();
_raw_type = 'F';
_element_count = 1;
_raw_value.float_value = value;
}
void
VpfValue::setRawDouble (double value)
{
clear();
_raw_type = 'R';
_element_count = 1;
_raw_value.double_value = value;
}
void
VpfValue::setRawFloatXYArray (const float_xy * array, int size)
{
clear();
_raw_type = 'C';
_element_count = size;
_raw_value.float_xy_array = new float_xy[size];
for (int i = 0; i < size; i++) {
_raw_value.float_xy_array[i].x = array[i].x;
_raw_value.float_xy_array[i].y = array[i].y;
}
}
void
VpfValue::setRawDoubleXYArray (const double_xy * array, int size)
{
clear();
_raw_type='B';
_element_count = size;
_raw_value.double_xy_array = new double_xy[size];
for (int i = 0; i < size; i++) {
_raw_value.double_xy_array[i].x = array[i].x;
_raw_value.double_xy_array[i].y = array[i].y;
}
}
void
VpfValue::setRawFloatXYZArray (const float_xyz * array, int size)
{
clear();
_raw_type = 'Z';
_element_count = size;
_raw_value.float_xyz_array = new float_xyz[size];
for (int i = 0; i < size; i++) {
_raw_value.float_xyz_array[i].x = array[i].x;
_raw_value.float_xyz_array[i].y = array[i].y;
_raw_value.float_xyz_array[i].z = array[i].z;
}
}
void
VpfValue::setRawDoubleXYZArray (const double_xyz * array, int size)
{
clear();
_raw_type = 'Y';
_element_count = size;
_raw_value.double_xyz_array = new double_xyz[size];
for (int i = 0; i < size; i++) {
_raw_value.double_xyz_array[i].x = array[i].x;
_raw_value.double_xyz_array[i].y = array[i].y;
_raw_value.double_xyz_array[i].z = array[i].z;
}
}
void
VpfValue::setRawDateTime (const char * array)
{
clear();
_raw_type = 'D';
_element_count = 1;
_raw_value.char_array = new char[20];
for (int i = 0; i < 20; i++)
_raw_value.char_array[i] = array[i];
}
void
VpfValue::setRawCrossTileId (const VpfCrossRef &id)
{
clear();
_raw_type = 'K';
_element_count = 1;
_raw_value.cross_tile_value = new VpfCrossRef;
_raw_value.cross_tile_value->current_tile_key = id.current_tile_key;
_raw_value.cross_tile_value->next_tile_id = id.next_tile_id;
_raw_value.cross_tile_value->next_tile_key = id.next_tile_key;
_raw_value.cross_tile_value->unused_key = id.unused_key;
}
void
VpfValue::clear ()
{
switch (_raw_type) {
case 'T':
case 'L':
case 'N':
case 'M':
delete[] _raw_value.char_array;
_raw_value.char_array = 0;
break;
case 'F':
case 'R':
case 'S':
case 'I':
break;
case 'C':
delete[] _raw_value.float_xy_array;
_raw_value.float_xy_array = 0;
break;
case 'B':
delete[] _raw_value.double_xy_array;
_raw_value.double_xy_array = 0;
break;
case 'Z':
delete[] _raw_value.float_xyz_array;
_raw_value.float_xyz_array = 0;
break;
case 'Y':
delete[] _raw_value.double_xyz_array;
_raw_value.double_xyz_array = 0;
break;
case 'D':
delete [] _raw_value.char_array;
_raw_value.char_array = 0;
break;
case 'X':
break;
case 'K':
delete _raw_value.cross_tile_value;
_raw_value.cross_tile_value = 0;
break;
}
_raw_type = 'X';
}
VpfValue::Type
VpfValue::convertType (char rawType)
{
switch (rawType) {
case 'T':
case 'L':
case 'N':
case 'M':
return TEXT;
case 'F':
case 'R':
return REAL;
case 'S':
case 'I':
return INT;
case 'C':
case 'B':
case 'Z':
case 'Y':
return POINTS;
case 'D':
return DATE;
case 'X':
return EMPTY;
case 'K':
return CROSSREF;
default:
throw VpfException(string("Unknown raw value type: ") + rawType);
}
}
ostream &
operator<< (ostream &output, const VpfValue &value)
{
switch (value.getType()) {
case VpfValue::TEXT:
output << value.getText();
break;
case VpfValue::INT:
output << value.getInt();
break;
case VpfValue::REAL:
output << value.getReal();
break;
case VpfValue::POINTS: {
int nPoints = value.getElementCount();
for (int i = 0; i < nPoints; i++) {
if (i > 0)
output << ',';
output << '{' << value.getPoint(i).x << ','
<< value.getPoint(i).y << ',' << value.getPoint(i).z << '}';
}
break;
}
case VpfValue::DATE:
output << value.getDate(); // FIXME
break;
case VpfValue::CROSSREF:
output << value.getCrossRef().current_tile_key << ','
<< value.getCrossRef().next_tile_id << ','
<< value.getCrossRef().next_tile_key;
break;
}
return output;
}
// end of value.cxx

528
src/Lib/vpf/value.hxx Normal file
View file

@ -0,0 +1,528 @@
// value.hxx - class representing a VPF leaf value.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_VALUE_HXX
#define __VPF_VALUE_HXX 1
#include <iostream>
#include "vpfbase.hxx"
/**
* Leaf data in a VPF table.
*
* <p>This class represents the actual VPF data primitives: strings,
* numbers, dates, and arrays of coordinates. Users need to test
* the value first to find its data type -- any attempt to access
* the wrong data type for the value will raise an exception
* (which can be very helpful in avoiding bugs).</p>
*
* @author David Megginson, david@megginson.com
* @version $Revision$
*/
class VpfValue
{
public:
/**
* High-level, user visible data types.
*
* <p>The VPF table actually stores more types than these, but these
* provide a useful simplification for library users.</p>
*/
enum Type {
EMPTY,
TEXT,
INT,
REAL,
POINTS,
DATE,
CROSSREF
};
/**
* Default constructor.
*/
VpfValue ();
/**
* Copy constructor.
*
* <p>Create a fresh copy of a value.</p>
*
* @param value The value to copy.
*/
VpfValue (const VpfValue &value);
/**
* Destructor.
*/
virtual ~VpfValue ();
/**
* Get the user-visible type of the value.
*
* @return A user-visible type.
*/
virtual Type getType () const;
/**
* Get the number of elements in the value.
*
* <p>Note: for character arrays, this number may be less than the
* element count provided by the {@link VpfColumnDecl}, because
* trailing whitespace is trimmed automatically.</p>
*
* @return The number of elements in the value.
* @see VpfColumnDecl#getElementCount
*/
virtual int getElementCount () const;
/**
* Get the contents of a text value.
*
* <p>The contents are returned as a character array with a '\0'
* appended, so that they can be treated as a C string if desired.</p>
*
* @return The textual contents of the value.
* @exception VpfException If the type of the value is not TEXT.
* @see #getType
* @see #getElementCount
*/
virtual const char * getText () const;
/**
* Get the contents of an integer value.
*
* @return The integer contents of the value.
* @exception VpfException If the type of the value is not INT.
* @see #getType
*/
virtual int getInt () const;
/**
* Get the contents of a real-number value.
*
* @return The real-number contents of the value.
* @exception VpfException If the type of the value is not REAL.
*/
virtual double getReal () const;
/**
* Get a 3D point from a coordinate array.
*
* <p>VPF stores single- and double-precision 2D and 3D points; this
* function normalizes all of them the double-precision 3D points,
* with the z value set to 0 when only 2D information was
* available.</p>
*
* @param index The index of the point in the coordinate array.
* @return A double-precision 3D point.
* @exception VpfException If the index is out of range or the type
* of the value is not POINTS.
* @see #getType
* @see #getElementCount
*/
virtual const VpfPoint getPoint (int index) const;
/**
* Get the contents of a date value.
*
* @return The date as a character string.
* @exception VpfException If the type of the value is not DATE.
* @see #getType
*/
virtual const char * getDate () const;
/**
* Get a cross-tile reference.
*/
virtual const VpfCrossRef getCrossRef () const;
protected:
friend class VpfTable;
friend class VpfColumnDecl;
/**
* A single-precision, two-dimensional coordinate.
*/
struct float_xy {
float x;
float y;
};
/**
* A double-precision, two-dimensional coordinate.
*/
struct double_xy {
double x;
double y;
};
/**
* A single-precision, three-dimensional coordinate.
*/
struct float_xyz {
float x;
float y;
float z;
};
/**
* A double-precision, three-dimensional coordinate.
*/
struct double_xyz {
double x;
double y;
double z;
};
/**
* Get the raw data type of the value.
*
* @return A constant representing the type.
*/
virtual char getRawType () const;
/**
* Assert the raw data type of this value.
*
* <p>This method provides a simple way to force an exception if
* the value is not of the expected type.</p>
*
* @param The type expected.
* @exception VpfException If the expected type does not match the
* actual type.
*/
virtual void assertRawType (char type) const;
/**
* Get the character data for the value.
*
* <p>Note that the return value is <em>unsigned</em>, to allow
* for various eight-bit character encodings.</p>
*
* @return An array of characters (see {@link #getElementCount for
* the length) with a terminating '\0' (not counted in the length).
* @exception VpfException If the data type is not one of the
* *_TEXT types.
*/
virtual const char * getRawCharArray () const;
/**
* Get the short integer data for the value.
*
* @return A short integer in system byte order.
* @exception VpfException If the data type is not 'S'.
*/
virtual short getRawShort () const;
/**
* Get the long integer data for the value.
*
* @return A long integer in system byte order.
* @exception VpfException If the data type is not 'I'.
*/
virtual int getRawInt () const;
/**
* Get the single-precision floating-point data for the value.
*
* @return A single-precision floating-point number in system byte
* order.
* @exception VpfException If the data type is not 'F'.
*/
virtual float getRawFloat () const;
/**
* Get the double-precision floating-point data for the value.
*
* @return A short integer in system byte order.
* @exception VpfException If the data type is not 'R'.
*/
virtual double getRawDouble () const;
/**
* Get an array of single-precision 2D coordinates.
*
* @return An array of single-precision, two-dimensional
* coordinates (see {@link #getElementCount} for the array
* length).
* @exception VpfException If the data type is not 'C'.
*/
virtual const float_xy * getRawFloatXYArray () const;
/**
* Get an array of double-precision 2D coordinates.
*
* @return An array of double-precision, two-dimensional
* coordinates (see {@link #getElementCount} for the array
* length).
* @exception VpfException If the data type is not 'B'.
*/
virtual const double_xy * getRawDoubleXYArray () const;
/**
* Get an array of single-precision 3D coordinates.
*
* @return An array of single-precision, three-dimensional
* coordinates (see {@link #getElementCount} for the array
* length).
* @exception VpfException If the data type is not 'Z'.
*/
virtual const float_xyz * getRawFloatXYZArray () const;
/**
* Get an array of double-precision 3D coordinates.
*
* @return An array of double-precision, three-dimensional
* coordinates (see {@link #getElementCount} for the array
* length).
* @exception VpfException If the data type is not 'Y'.
*/
virtual const double_xyz * getRawDoubleXYZArray () const;
/**
* Get the date and time.
*
* <p>Note that {@link #getElementCount} will return only 1
* (because there is one date), but the date is represented
* by 20 characters.</p>
*
* @return An array of 20 characters representing the date.
* @exception VpfException If the data type is not 'D'.
*/
virtual const char * getRawDateTime () const;
/**
* Get a cross-tile id.
*
* @return The cross-tile identifier.
* @exception VpfException if the data type is not 'K'.
*/
virtual const VpfCrossRef &getRawCrossTileId () const;
/**
* Set a null value.
*
* <p>Free any previous value and set the type to 'X'.</p>
*/
virtual void setNull ();
/**
* Set a text value.
*
* <p>This method applies to all of the *_TEXT types. If no
* explicit type is provided, it defaults to 'T'.</p>
*
* <p>This method will automatically strip trailing whitespace
* during copying, so the array length in the value may be different
* than the length provided. The method will free any previous
* value and set the new type appropriately. This method will
* automatically add a trailing '\0', which will not be counted
* in the length.</p>
*
* @param array The array of characters (will be copied).
* @param size The number of characters in the array.
* @param type The type of text (defaults to 'T').
* @exception VpfException If the type provided is not one
* of the *_TEXT types.
*/
virtual void setRawCharArray (const char * array, int size,
char type='T');
/**
* Set a short integer value.
*
* <p>This method will free any previous value and set the type
* to 'S'.</p>
*
* @param value The new value in system byte order.
*/
virtual void setRawShort (short value);
/**
* Set a long integer value.
*
* <p>This method will free any previous value and set the type
* to LONG.</p>
*
* @param value The new value in system byte order.
*/
virtual void setRawInt (int value);
/**
* Set a single-precision floating-point value.
*
* <p>This method will free any previous value and set the type
* to 'F'.</p>
*
* @param value The new value.
*/
virtual void setRawFloat (float value);
/**
* Set a double-precision floating-point value.
*
* <p>This method will free any previous value and set the type
* to 'R'.</p>
*
* @param value The new value.
*/
virtual void setRawDouble (double value);
/**
* Set a single-precision 2D coordinate array.
*
* <p>This method will free any previous value and set the type
* to 'C'.</p>
*
* @param array The coordinate array.
* @param size The number of elements in the array.
*/
virtual void setRawFloatXYArray (const float_xy * array, int size);
/**
* Set a double-precision 2D coordinate array.
*
* <p>This method will free any previous value and set the type
* to 'B'.</p>
*
* @param array The coordinate array.
* @param size The number of elements in the array.
*/
virtual void setRawDoubleXYArray (const double_xy * array, int size);
/**
* Set a single-precision 3D coordinate array.
*
* <p>This method will free any previous value and set the type
* to 'Z'.</p>
*
* @param array The coordinate array.
* @param size The number of elements in the array.
*/
virtual void setRawFloatXYZArray (const float_xyz * array, int size);
/**
* Set a double-precision 3D coordinate array.
*
* <p>This method will free any previous value and set the type
* to 'Y'.</p>
*
* @param array The coordinate array.
* @param size The number of elements in the array.
*/
virtual void setRawDoubleXYZArray (const double_xyz * array, int size);
/**
* Set a date/time field.
*
* <p>Currently, the date and time is represented as an array of
* 20 characters.</p>
*
* <p>This method will free any previous value and set the type
* to 'D'.</p>
*
* @param date An array of 20 characters.
*/
virtual void setRawDateTime (const char * date);
/**
* Set a cross-tile id.
*
* @param id The cross-tile-id (will be copied).
*/
virtual void setRawCrossTileId (const VpfCrossRef &id);
/**
* Covert a raw type to a high-level one.
*
* @param rawType The raw type to convert.
* @return The high-level type.
*/
static Type convertType (char rawType);
private:
void clear ();
char _raw_type;
int _element_count;
union {
char * char_array;
short short_value;
long int_value;
float float_value;
double double_value;
float_xy * float_xy_array;
double_xy * double_xy_array;
float_xyz * float_xyz_array;
double_xyz * double_xyz_array;
VpfCrossRef * cross_tile_value;
} _raw_value;
};
/**
* Provide a text representation of a value for debugging.
*
* @param output The output stream.
* @param value The value to write.
* @return The output stream provided.
*/
std::ostream &operator<< (std::ostream &output, const VpfValue &value);
#endif
// end of value.hxx

131
src/Lib/vpf/vpf-dump.cxx Normal file
View file

@ -0,0 +1,131 @@
// vpf-dump.cxx - dump the contents of VPF tables for debugging.
// This file is released into the Public Domain, and comes with NO WARRANTY!
////////////////////////////////////////////////////////////////////////
// Dump the contents of one or more VPF tables.
//
// Usage:
//
// vpf-dump <table...>
//
// This utility is useful for studying the structure of VPF tables
// or looking for data not currently available through the library.
// Here's an example:
//
// vpf-table char.vdt | less
////////////////////////////////////////////////////////////////////////
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
#include "vpf.hxx"
/**
* Get a printable name for a value type.
*/
static const char *
get_value_type_name (VpfValue::Type type)
{
switch (type) {
case VpfValue::EMPTY:
return "empty";
case VpfValue::TEXT:
return "text";
case VpfValue::INT:
return "integer";
case VpfValue::REAL:
return "real number";
case VpfValue::POINTS:
return "coordinate array";
case VpfValue::DATE:
return "date and time";
case VpfValue::CROSSREF:
return "cross-tile reference";
default:
throw VpfException("Unknown value type");
}
}
/**
* Dump the table's header.
*/
void
dump_table_header (const VpfTable &table)
{
cout << "Path: " << table.getPath() << endl;
cout << "Description: \"" << table.getDescription() << '"' << endl;
cout << "Documentation file: " << table.getDocFileName() << endl;
cout << "Total columns: " << table.getColumnCount() << endl;
cout << "Total rows: " << table.getRowCount() << endl;
}
/**
* Dump the declarations for each table column.
*/
void
dump_table_column_decls (const VpfTable &table)
{
for (int i = 0; i < table.getColumnCount(); i++) {
const VpfColumnDecl &column = table.getColumnDecl(i);
cout << "Column " << i << " Declaration: " << endl;
cout << " Name: " << column.getName() << endl;
cout << " Type: " << get_value_type_name(column.getValueType()) << endl;
cout << " Element count: " << column.getElementCount() << endl;
cout << " Key type: " << column.getKeyType() << endl;
cout << " Description: " << column.getDescription() << endl;
cout << " Value description table: "
<< column.getValueDescriptionTable() << endl;
cout << " Thematic index name: "
<< column.getThematicIndexName() << endl;
cout << " Narrative table: "
<< column.getNarrativeTable () << endl;
}
}
/**
* Dump the main body of the table itself.
*/
void
dump_table_body (const VpfTable &table)
{
for (int i = 0; i < table.getRowCount(); i++) {
cout << "Row " << i << ':' << endl;
for (int j = 0; j < table.getColumnCount(); j++) {
cout << " "
<< table.getColumnDecl(j).getName()
<< '='
<< table.getValue(i, j)
<< endl;
}
}
}
/**
* Main entry point.
*/
int
main (int ac, char ** av)
{
for (int i = 1; i < ac; i++) {
try {
VpfTable table(av[i]);
dump_table_header(table);
dump_table_column_decls(table);
dump_table_body(table);
} catch (VpfException &e) {
cerr << e.getMessage() << endl;
return 1;
}
}
return 0;
}
// end of vpf-dump.cxx

258
src/Lib/vpf/vpf-summary.cxx Normal file
View file

@ -0,0 +1,258 @@
// vpf-summary.cxx - print a summary of a VPF database's structure.
// This file is released into the Public Domain, and comes with NO WARRANTY!
////////////////////////////////////////////////////////////////////////
// Summarize the structure of a VPF database.
//
// Usage:
//
// vpf-summary <database root> [library [coverage [feature [property]]]]
//
// This utility can drill down fairly far into a VPF database. It can
// display anything from the schema for a whole database to the
// schema for a single feature property, depending on what appears
// on the command line. Here's an example to dump the whole schema
// for all libraries on the vmap0 North America CD:
//
// vpf-summary /cdrom/vmaplv0
//
// Here's a second example to show just the allowed values for the
// f_code feature property on the roadline feature in the transportation
// coverage of the North America library:
//
// vpf-summary /cdrom/vmaplv0 noamer trans roadl f_code
////////////////////////////////////////////////////////////////////////
#include <iostream>
#include <string>
using std::string;
using std::cout;
using std::cerr;
using std::endl;
#include "vpf.hxx"
/**
* Get a printable name for a value type.
*/
static const char *
get_value_type_name (VpfValue::Type type)
{
switch (type) {
case VpfValue::EMPTY:
return "empty";
case VpfValue::TEXT:
return "text";
case VpfValue::INT:
return "integer";
case VpfValue::REAL:
return "real number";
case VpfValue::POINTS:
return "coordinate array";
case VpfValue::DATE:
return "date and time";
case VpfValue::CROSSREF:
return "cross-tile reference";
default:
throw VpfException("Unknown value type");
}
}
/**
* Get a printable name for a topology type.
*/
static const char *
get_topology_name (VpfFeature::TopologyType type)
{
switch (type) {
case VpfFeature::UNKNOWN:
return "unknown";
case VpfFeature::POINT:
return "point";
case VpfFeature::LINE:
return "line";
case VpfFeature::POLYGON:
return "polygon";
case VpfFeature::LABEL:
return "text";
default:
return "unknown";
}
}
/**
* Print an indentation.
*/
static string
indent (int level)
{
string result;
for (int i = 0; i < level; i++)
result += ' ';
return result;
}
/**
* Print a summary of a property declaration.
*/
static void
dump_property_decl (const VpfPropertyDecl &decl, int level)
{
cout << indent(level) << "Name: " << decl.getName() << endl;
cout << indent(level) << "Description: " << decl.getDescription() << endl;
cout << indent(level) << "Type: "
<< get_value_type_name(decl.getValueType()) << endl;
if (decl.getValueCount() > 0) {
cout << indent(level) << "Number of allowed values: "
<< decl.getValueCount() << endl;
for (int i = 0; i < decl.getValueCount(); i++) {
cout << indent(level) << "Allowed Value " << i << ':' << endl;
cout << indent(level+2) << "Value: " << decl.getValue(i) << endl;
cout << indent(level+2) << "Description: "
<< decl.getValueDescription(i) << endl;
}
} else {
cout << indent(level) << "No value restrictions." << endl;
}
}
/**
* Print a summary of a feature.
*/
static void
dump_feature (const VpfFeature &feature, int level)
{
cout << indent(level) << "Name: " << feature.getName() << endl;
cout << indent(level) << "Description: " << feature.getDescription() << endl;
cout << indent(level) << "Topology type: "
<< get_topology_name(feature.getTopologyType()) << endl;
cout << indent(level) << "Number of topologies: "
<< feature.getTopologyCount() << endl;
if (feature.getTopologyType() == VpfFeature::POLYGON &&
feature.getTopologyCount() > 0) {
cout << indent(level) << "Bounding rectangle of first polygon: ";
VpfRectangle bounds = feature.getPolygon(0).getBoundingRectangle();
cout << bounds.minX << ','
<< bounds.minY << ','
<< bounds.maxX << ','
<< bounds.maxY << endl;
}
cout << indent(level) << "Number of feature properties: "
<< feature.getPropertyDeclCount() << endl;
for (int i = 0; i < feature.getPropertyDeclCount(); i++) {
cout << indent(level) << "Feature property " << i << ':' << endl;
dump_property_decl(feature.getPropertyDecl(i), level+2);
}
}
/**
* Print a summary of a coverage.
*/
static void
dump_coverage (const VpfCoverage &cov, int level)
{
cout << indent(level) << "Coverage name: " << cov.getName() << endl;
cout << indent(level) << "Coverage description: "
<< cov.getDescription() << endl;
cout << indent(level) << "Coverage path: " << cov.getPath() << endl;
cout << indent(level) << "Topological level: " << cov.getLevel() << endl;
cout << indent(level) << "Number of features: "
<< cov.getFeatureCount() << endl;
for (int i = 0; i < cov.getFeatureCount(); i++) {
cout << indent(level) << "Feature " << i << ':' << endl;
dump_feature(cov.getFeature(i), level+2);
}
}
/**
* Print a summary of a library.
*/
static void
dump_library (const VpfLibrary &lib, int level)
{
cout << indent(level) << "Library name: " << lib.getName() << endl;
cout << indent(level) << "Library description: "
<< lib.getDescription() << endl;
cout << indent(level) << "Library path: " << lib.getPath() << endl;
cout << indent(level) << "Minimum bounding rectangle: ";
VpfRectangle bounds = lib.getBoundingRectangle();
cout << bounds.minX << ','
<< bounds.minY << ','
<< bounds.maxX << ','
<< bounds.maxY << endl;
cout << indent(level) << "Number of coverages: "
<< lib.getCoverageCount() << endl;
for (int i = 0; i < lib.getCoverageCount(); i++) {
cout << indent(level) << "Coverage " << i << ':' << endl;
dump_coverage(lib.getCoverage(i), level+2);
}
}
/**
* Print a summary of a database.
*/
static void
dump_database (const VpfDataBase &db, int level)
{
cout << indent(level) << "Database name: " << db.getName() << endl;
cout << indent(level) << "Database description: "
<< db.getDescription() << endl;
cout << indent(level) << "Database path: " << db.getPath() << endl;
cout << indent(level) << "Number of libraries: "
<< db.getLibraryCount() << endl;
for (int i = 0; i < db.getLibraryCount(); i++) {
cout << "Library " << (i+1) << ':' << endl;
dump_library(db.getLibrary(i), level+2);
}
}
int
main (int ac, char ** av)
{
try {
switch (ac) {
case 2:
cout << "*** Database: " << av[1] << " ***" << endl << endl;
dump_database(VpfDataBase(av[1]), 0);
return 0;
case 3:
cout << "*** Library: " << av[2] << " ***" << endl << endl;
dump_library(VpfDataBase(av[1]).getLibrary(av[2]), 0);
return 0;
case 4:
cout << "*** Coverage: " << av[3] << " ***" << endl << endl;
dump_coverage(VpfDataBase(av[1])
.getLibrary(av[2]).getCoverage(av[3]), 0);
return 0;
case 5:
cout << "*** Feature: " << av[4] << " ***" << endl << endl;;
dump_feature(VpfDataBase(av[1]).getLibrary(av[2]).getCoverage(av[3])
.getFeature(av[4]), 0);
return 0;
case 6:
cout << "*** Feature Property: " << av[5] << " ***" << endl << endl;
dump_property_decl(VpfDataBase(av[1]).getLibrary(av[2])
.getCoverage(av[3]).getFeature(av[4])
.getPropertyDecl(av[5]), 0);
return 0;
default:
cerr << "Usage: " << av[0] << "<database> [library [coverage [feature]]]"
<< endl;
return 2;
}
} catch (VpfException &e) {
cerr << e.getMessage() << endl;
return 1;
}
}
// end of vpf-summary.cxx

View file

@ -0,0 +1,189 @@
// vpf-topology.cxx - program to dump a topology to output.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include <iostream>
using std::cout;
using std::cerr;
using std::endl;
using std::ostream;
#include <string>
using std::string;
#include "vpf.hxx"
ostream &
operator<< (ostream &output, const VpfRectangle &rect)
{
output << rect.minX << ','
<< rect.minY << ','
<< rect.maxX << ','
<< rect.maxY;
return output;
}
static void
dump_point (const VpfPoint &p)
{
cout << p.x << ' ' << p.y << endl;
}
static void
dump_point (const VpfPoint &p, const VpfRectangle &bounds)
{
if (inside(p, bounds))
dump_point(p);
cout << endl;
}
static void
dump_line (const VpfLine &l)
{
int nPoints = l.getPointCount();
for (int i = 0; i < nPoints; i++)
dump_point(l.getPoint(i));
}
static void
dump_line (const VpfLine &l, const VpfRectangle &bounds)
{
if (overlap(l.getBoundingRectangle(), bounds))
dump_line(l);
cout << endl;
}
static void
dump_contour (const VpfContour &c)
{
int nPoints = c.getPointCount();
cerr << "dumping contour with " << nPoints << " points" << endl;
for (int i = 0; i < nPoints; i++) {
dump_point(c.getPoint(i));
}
}
static void
dump_polygon (const VpfPolygon &poly)
{
int nContours = poly.getContourCount();
for (int i = 0; i < nContours; i++) {
dump_contour(poly.getContour(i));
cout << endl;
}
cout << endl;
}
static void
dump_polygon (const VpfPolygon &poly, const VpfRectangle &bounds)
{
if (overlap(poly.getBoundingRectangle(), bounds))
dump_polygon(poly);
}
static void
dump_label (const VpfLabel &label)
{
const VpfPoint p = label.getPoint();
cout << p.x << ' ' << p.y << ' ' << label.getText() << endl;
}
static void
dump_label (const VpfLabel &label, const VpfRectangle &bounds)
{
if (inside(label.getPoint(), bounds))
dump_label(label);
}
int
main (int ac, char ** av)
{
VpfRectangle bounds;
bounds.minX = -180.0;
bounds.minY = -90.0;
bounds.maxX = 180.0;
bounds.maxY = 90.0;
int args_start = 1;
for (int i = 1; i < ac; i++) {
string opt = av[i];
if (opt.find("--minx=") == 0) {
bounds.minX = atoi(opt.substr(7).c_str());
} else if (opt.find("--miny=") == 0) {
bounds.minY = atoi(opt.substr(7).c_str());
} else if (opt.find("--maxx=") == 0) {
bounds.maxX = atoi(opt.substr(7).c_str());
} else if (opt.find("--maxy=") == 0) {
bounds.maxY = atoi(opt.substr(7).c_str());
} else if (opt.find("--") == 0) {
cerr << "Unrecognized option: " << opt << endl;
return 2;
} else {
break;
}
args_start++;
}
if (ac - args_start != 4) {
cerr << "Usage: " << av[0]
<< " <database dir> <library> <coverage> <feature>" << endl;
return 2;
}
cerr << "Bounds: " << bounds << endl;
try {
VpfDataBase db(av[args_start]);
VpfLibrary library = db.getLibrary(av[args_start+1]);
VpfFeature feature = library.getCoverage(av[args_start+2])
.getFeature(av[args_start+3]);
const VpfRectangle rect = library.getBoundingRectangle();
if (!overlap(rect, bounds)) {
cerr << "Library coverage does not overlap with area" << endl;
cerr << "Library: " << rect << endl;
cerr << "Requested: " << bounds << endl;
return 1;
}
int nTopologies = feature.getTopologyCount();
int type = feature.getTopologyType();
cerr << "Searching through " << nTopologies << " topologies" << endl;
for (int i = 0; i < nTopologies; i++) {
if ((i % 1000) == 0)
cerr << i << "..." << endl;
if (feature.isTiled()) {
VpfRectangle rect = feature.getTile(i).getBoundingRectangle();
if (!overlap(rect, bounds))
continue;
}
switch (type) {
case VpfFeature::POINT:
dump_point(feature.getPoint(i), bounds);
break;
case VpfFeature::LINE:
dump_line(feature.getLine(i), bounds);
break;
case VpfFeature::POLYGON:
dump_polygon(feature.getPolygon(i), bounds);
break;
case VpfFeature::LABEL:
dump_label(feature.getLabel(i), bounds);
break;
default:
throw VpfException("Unsupported topology type");
}
}
} catch (const VpfException &e) {
cerr << "Died with exception: " << e.getMessage() << endl;
return 1;
}
return 0;
}
// end of vpf-topology.cxx

28
src/Lib/vpf/vpf.hxx Normal file
View file

@ -0,0 +1,28 @@
// vpf.hxx - top-level include file for client applications.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_VPF_HXX
#define __VPF_VPF_HXX 1
#include <string>
#include <map>
#include "vpfbase.hxx"
#include "component.hxx"
#include "value.hxx"
#include "table.hxx"
#include "tablemgr.hxx"
#include "tile.hxx"
#include "database.hxx"
#include "library.hxx"
#include "coverage.hxx"
#include "feature.hxx"
#include "property.hxx"
#include "polygon.hxx"
#include "contour.hxx"
#include "line.hxx"
#include "label.hxx"
#endif
// end of vpf.hxx

74
src/Lib/vpf/vpfbase.cxx Normal file
View file

@ -0,0 +1,74 @@
// vpfbase.cxx - basic support classes and structures.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#include <string>
#include "vpfbase.hxx"
using std::string;
////////////////////////////////////////////////////////////////////////
// Point and rectangle functions.
////////////////////////////////////////////////////////////////////////
bool
inside (const VpfPoint &p, const VpfRectangle &r)
{
return (p.x >= r.minX &&
p.x <= r.maxX &&
p.y >= r.minY &&
p.y <= r.maxY);
}
static inline bool
inside (double point, double min, double max)
{
return (point >= min && point <= max);
}
static inline bool
overlap (double min1, double max1, double min2, double max2)
{
return (inside(min1, min2, max2) ||
inside(max1, min2, max2) ||
inside(min2, min1, max1) ||
inside(max2, min1, min2));
}
bool
overlap (const VpfRectangle &r1, const VpfRectangle &r2)
{
return (overlap(r1.minX, r1.maxX, r2.minX, r2.maxX) &&
overlap(r1.minY, r1.maxY, r2.minY, r2.maxY));
}
////////////////////////////////////////////////////////////////////////
// Implementation of VpfException.
////////////////////////////////////////////////////////////////////////
VpfException::VpfException ()
: _message("VPF error")
{
}
VpfException::VpfException (const std::string &message)
: _message(message)
{
}
VpfException::~VpfException ()
{
}
const string &
VpfException::getMessage () const
{
return _message;
}
// end of vpfbase.cxx

91
src/Lib/vpf/vpfbase.hxx Normal file
View file

@ -0,0 +1,91 @@
// vpfbase.hxx - declaration of basic structures and classes for the library.
// This file is released into the Public Domain, and comes with NO WARRANTY!
#ifndef __VPF_VPFBASE_HXX
#define __VPF_VPFBASE_HXX 1
#include <string>
/**
* A double-precision point in 3D space.
*/
struct VpfPoint
{
VpfPoint ()
: x(0), y(0), z(0)
{}
VpfPoint (double xin, double yin, double zin)
: x(xin), y(yin), z(zin)
{}
double x;
double y;
double z;
};
/**
* A rectangle.
*/
struct VpfRectangle
{
double minX;
double minY;
double maxX;
double maxY;
};
/**
* A cross-tile id triplet.
*/
struct VpfCrossRef {
int current_tile_key;
int next_tile_id;
int next_tile_key;
int unused_key;
};
/**
* Test whether a point is inside a rectangle.
*
* <p>On the edge counts as inside.</p>
*
* @param p The point to test.
* @param r The rectangle to test.
* @return true if the point is inside the rectangle or on its edge,
* false otherwise.
*/
extern bool inside (const VpfPoint &p, const VpfRectangle &r);
/**
* Test whether two rectangles overlap.
*
* <p>Coincident edges count as overlap.</p>
*
* @param r1 The first rectangle to test.
* @param r2 The second rectangle to test.
* @return true if the rectangles overlap, false otherwise.
*/
extern bool overlap (const VpfRectangle &r1, const VpfRectangle &r2);
/**
* A VPF-related exception.
*/
class VpfException
{
public:
VpfException ();
VpfException (const std::string &message);
virtual ~VpfException ();
virtual const std::string &getMessage () const;
private:
std::string _message;
};
#endif
// end of vpfbase.hxx