- new library to support NIMA's Vector Product Format
This commit is contained in:
parent
4e43a03fcb
commit
3050aca5c7
36 changed files with 6372 additions and 1 deletions
|
@ -9,4 +9,5 @@ SUBDIRS = \
|
|||
Polygon \
|
||||
poly2tri \
|
||||
shapelib \
|
||||
TriangleJRS
|
||||
TriangleJRS \
|
||||
vpf
|
||||
|
|
49
src/Lib/vpf/Makefile.am
Normal file
49
src/Lib/vpf/Makefile.am
Normal 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
101
src/Lib/vpf/component.cxx
Normal 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
198
src/Lib/vpf/component.hxx
Normal 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
111
src/Lib/vpf/contour.cxx
Normal 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
52
src/Lib/vpf/contour.hxx
Normal 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
129
src/Lib/vpf/coverage.cxx
Normal 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
214
src/Lib/vpf/coverage.hxx
Normal 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
91
src/Lib/vpf/database.cxx
Normal 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
161
src/Lib/vpf/database.hxx
Normal 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
276
src/Lib/vpf/feature.cxx
Normal 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
271
src/Lib/vpf/feature.hxx
Normal 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
57
src/Lib/vpf/label.cxx
Normal 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
96
src/Lib/vpf/label.hxx
Normal 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
121
src/Lib/vpf/library.cxx
Normal 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
183
src/Lib/vpf/library.hxx
Normal 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
93
src/Lib/vpf/line.cxx
Normal 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
144
src/Lib/vpf/line.hxx
Normal 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
82
src/Lib/vpf/polygon.cxx
Normal 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
146
src/Lib/vpf/polygon.hxx
Normal 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
138
src/Lib/vpf/property.cxx
Normal 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
181
src/Lib/vpf/property.hxx
Normal 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
845
src/Lib/vpf/table.cxx
Normal 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
454
src/Lib/vpf/table.hxx
Normal 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
98
src/Lib/vpf/tablemgr.cxx
Normal 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
51
src/Lib/vpf/tablemgr.hxx
Normal 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
88
src/Lib/vpf/tile.cxx
Normal 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
120
src/Lib/vpf/tile.hxx
Normal 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
521
src/Lib/vpf/value.cxx
Normal 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
528
src/Lib/vpf/value.hxx
Normal 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
131
src/Lib/vpf/vpf-dump.cxx
Normal 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
258
src/Lib/vpf/vpf-summary.cxx
Normal 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
|
189
src/Lib/vpf/vpf-topology.cxx
Normal file
189
src/Lib/vpf/vpf-topology.cxx
Normal 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
28
src/Lib/vpf/vpf.hxx
Normal 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
74
src/Lib/vpf/vpfbase.cxx
Normal 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
91
src/Lib/vpf/vpfbase.hxx
Normal 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
|
Loading…
Add table
Reference in a new issue