Core data class for PolyLine handling.
This is all unused yet, but defines the simple model for polyLines.
This commit is contained in:
parent
12bcea2861
commit
7cad407843
5 changed files with 333 additions and 2 deletions
|
@ -17,6 +17,7 @@ set(SOURCES
|
|||
FlightPlan.cxx
|
||||
NavDataCache.cxx
|
||||
PositionedOctree.cxx
|
||||
PolyLine.cxx
|
||||
)
|
||||
|
||||
set(HEADERS
|
||||
|
@ -36,6 +37,7 @@ set(HEADERS
|
|||
FlightPlan.hxx
|
||||
NavDataCache.hxx
|
||||
PositionedOctree.hxx
|
||||
PolyLine.hxx
|
||||
)
|
||||
|
||||
if (NOT SYSTEM_SQLITE)
|
||||
|
|
161
src/Navaids/PolyLine.cxx
Normal file
161
src/Navaids/PolyLine.cxx
Normal file
|
@ -0,0 +1,161 @@
|
|||
/**
|
||||
* Polyline - store geographic line-segments */
|
||||
|
||||
// Written by James Turner, started 2013.
|
||||
//
|
||||
// Copyright (C) 2013 James Turner <zakalawe@mac.com>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "PolyLine.hxx"
|
||||
|
||||
#include <cassert>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include <simgear/math/sg_geodesy.hxx>
|
||||
|
||||
#include <Navaids/PositionedOctree.hxx>
|
||||
|
||||
using namespace flightgear;
|
||||
|
||||
PolyLine::PolyLine(Type aTy, const SGGeodVec& aPoints) :
|
||||
m_type(aTy),
|
||||
m_data(aPoints)
|
||||
{
|
||||
assert(!aPoints.empty());
|
||||
}
|
||||
|
||||
PolyLine::~PolyLine()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
unsigned int PolyLine::numPoints() const
|
||||
{
|
||||
return m_data.size();
|
||||
}
|
||||
|
||||
SGGeod PolyLine::point(unsigned int aIndex) const
|
||||
{
|
||||
assert(aIndex <= m_data.size());
|
||||
return m_data[aIndex];
|
||||
}
|
||||
|
||||
PolyLineList PolyLine::createChunked(Type aTy, const SGGeodVec& aRawPoints)
|
||||
{
|
||||
PolyLineList result;
|
||||
if (aRawPoints.size() < 2) {
|
||||
return result;
|
||||
}
|
||||
|
||||
const double maxDistanceSquaredM = 40000 * 40000; // 40km to start with
|
||||
|
||||
SGVec3d chunkStartCart = SGVec3d::fromGeod(aRawPoints.front());
|
||||
SGGeodVec chunk;
|
||||
SGGeodVec::const_iterator it = aRawPoints.begin();
|
||||
|
||||
while (it != aRawPoints.end()) {
|
||||
SGVec3d ptCart = SGVec3d::fromGeod(*it);
|
||||
double d2 = distSqr(chunkStartCart, ptCart);
|
||||
|
||||
// distance check, but also ensure we generate actual valid line segments.
|
||||
if ((chunk.size() >= 2) && (d2 > maxDistanceSquaredM)) {
|
||||
chunk.push_back(*it); // close the segment
|
||||
result.push_back(new PolyLine(aTy, chunk));
|
||||
chunkStartCart = ptCart;
|
||||
chunk.clear();
|
||||
}
|
||||
|
||||
chunk.push_back(*it++); // add to open chunk
|
||||
}
|
||||
|
||||
// if we have a single trailing point, we already added it as the last
|
||||
// point of the previous chunk, so we're ok. Otherwise, create the
|
||||
// final chunk's polyline
|
||||
if (chunk.size() > 1) {
|
||||
result.push_back(new PolyLine(aTy, chunk));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void PolyLine::addToSpatialIndex() const
|
||||
{
|
||||
std::set<Octree::Leaf*> seen;
|
||||
|
||||
BOOST_FOREACH(const SGGeod& g, m_data) {
|
||||
SGVec3d cart(SGVec3d::fromGeod(g));
|
||||
Octree::Leaf* lf = Octree::global_spatialOctree->findLeafForPos(cart);
|
||||
if (seen.find(lf) != seen.end()) {
|
||||
continue; // don't insert multiple times
|
||||
}
|
||||
|
||||
lf->addPolyLine(const_cast<PolyLine*>(this));
|
||||
} // of data points iteration
|
||||
}
|
||||
|
||||
class SingleTypeFilter : public PolyLine::TypeFilter
|
||||
{
|
||||
public:
|
||||
SingleTypeFilter(PolyLine::Type aTy) :
|
||||
m_type(aTy)
|
||||
{ }
|
||||
|
||||
virtual bool pass(PolyLine::Type aTy) const
|
||||
{ return (aTy == m_type); }
|
||||
private:
|
||||
PolyLine::Type m_type;
|
||||
};
|
||||
|
||||
PolyLineList PolyLine::linesNearPos(const SGGeod& aPos, double aRangeNm, Type aTy)
|
||||
{
|
||||
return linesNearPos(aPos, aRangeNm, SingleTypeFilter(aTy));
|
||||
}
|
||||
|
||||
|
||||
PolyLineList PolyLine::linesNearPos(const SGGeod& aPos, double aRangeNm, const TypeFilter& aFilter)
|
||||
{
|
||||
std::set<PolyLineRef> resultSet;
|
||||
|
||||
SGVec3d cart = SGVec3d::fromGeod(aPos);
|
||||
double cutoffM = aRangeNm * SG_NM_TO_METER;
|
||||
Octree::FindLinesDeque deque;
|
||||
deque.push_back(Octree::global_spatialOctree);
|
||||
|
||||
while (!deque.empty()) {
|
||||
Octree::Node* nd = deque.front();
|
||||
deque.pop_front();
|
||||
|
||||
PolyLineList lines;
|
||||
nd->visitForLines(cart, cutoffM, lines, deque);
|
||||
|
||||
// merge into result set, filtering as we go.
|
||||
BOOST_FOREACH(PolyLineRef ref, lines) {
|
||||
if (aFilter.pass(ref->type())) {
|
||||
resultSet.insert(ref);
|
||||
}
|
||||
}
|
||||
} // of deque iteration
|
||||
|
||||
PolyLineList result;
|
||||
result.insert(result.end(), resultSet.begin(), resultSet.end());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
115
src/Navaids/PolyLine.hxx
Normal file
115
src/Navaids/PolyLine.hxx
Normal file
|
@ -0,0 +1,115 @@
|
|||
/**
|
||||
* Polyline - store geographic line-segments */
|
||||
|
||||
// Written by James Turner, started 2013.
|
||||
//
|
||||
// Copyright (C) 2013 James Turner <zakalawe@mac.com>
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License as
|
||||
// published by the Free Software Foundation; either version 2 of the
|
||||
// License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful, but
|
||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
// General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#ifndef FG_POLY_LINE_HXX
|
||||
#define FG_POLY_LINE_HXX
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <simgear/sg_inlines.h>
|
||||
#include <simgear/structure/SGSharedPtr.hxx>
|
||||
#include <simgear/math/SGMath.hxx>
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
||||
typedef std::vector<SGGeod> SGGeodVec;
|
||||
|
||||
class PolyLine;
|
||||
|
||||
typedef SGSharedPtr<PolyLine> PolyLineRef;
|
||||
|
||||
typedef std::vector<PolyLineRef> PolyLineList;
|
||||
|
||||
/**
|
||||
* @class Store geographical linear data, with a type code.
|
||||
*
|
||||
* This is a basic in-memory model of GIS line data, without support for
|
||||
* many features; especially there is no support for per-node attributes.
|
||||
*
|
||||
* PolyLines are added to the spatial index and can be queried by passing
|
||||
* a search centre and cutoff distance.
|
||||
*/
|
||||
class PolyLine : public SGReferenced
|
||||
{
|
||||
public:
|
||||
virtual ~PolyLine();
|
||||
|
||||
enum Type
|
||||
{
|
||||
INVALID = 0,
|
||||
COASTLINE,
|
||||
NATIONAL_BOUNDARY, /// aka a border
|
||||
REGIONAL_BOUNDARY, /// state / province / country / department
|
||||
RIVER,
|
||||
// airspace types in the future
|
||||
LAST_TYPE
|
||||
};
|
||||
|
||||
Type type() const
|
||||
{ return m_type; }
|
||||
|
||||
/**
|
||||
* number of points in this line - at least two.
|
||||
*/
|
||||
unsigned int numPoints() const;
|
||||
|
||||
SGGeod point(unsigned int aIndex) const;
|
||||
|
||||
const SGGeodVec& points() const
|
||||
{ return m_data; }
|
||||
|
||||
/**
|
||||
* create poly line objects from raw input points and a type.
|
||||
* input points will be subdivided so the bounding area of each
|
||||
* polyline stays within some threshold.
|
||||
*
|
||||
*/
|
||||
static PolyLineList createChunked(Type aTy, const SGGeodVec& aRawPoints);
|
||||
|
||||
/**
|
||||
* retrieve all the lines within a range of a search point.
|
||||
* lines are returned if any point is near the search location.
|
||||
*/
|
||||
static PolyLineList linesNearPos(const SGGeod& aPos, double aRangeNm, Type aTy);
|
||||
|
||||
class TypeFilter
|
||||
{
|
||||
public:
|
||||
virtual bool pass(Type aTy) const = 0;
|
||||
};
|
||||
|
||||
static PolyLineList linesNearPos(const SGGeod& aPos, double aRangeNm, const TypeFilter& aFilter);
|
||||
private:
|
||||
void addToSpatialIndex() const;
|
||||
|
||||
PolyLine(Type aTy, const SGGeodVec& aPoints);
|
||||
|
||||
Type m_type;
|
||||
SGGeodVec m_data;
|
||||
// cache the bounding box?
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // of namespace flightgear
|
||||
|
||||
#endif
|
|
@ -113,7 +113,21 @@ void Leaf::loadChildren()
|
|||
|
||||
childrenLoaded = true;
|
||||
}
|
||||
|
||||
|
||||
void Leaf::addPolyLine(PolyLineRef aLine)
|
||||
{
|
||||
lines.push_back(aLine);
|
||||
}
|
||||
|
||||
void Leaf::visitForLines(const SGVec3d& aPos, double aCutoff,
|
||||
PolyLineList& aLines,
|
||||
FindLinesDeque& aQ) const
|
||||
{
|
||||
aLines.insert(aLines.end(), lines.begin(), lines.end());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Branch::Branch(const SGBoxd& aBox, int64_t aIdent) :
|
||||
Node(aBox, aIdent),
|
||||
childrenLoaded(false)
|
||||
|
@ -139,6 +153,24 @@ void Branch::visit(const SGVec3d& aPos, double aCutoff,
|
|||
aQ.push(Ordered<Node*>(children[i], d));
|
||||
} // of child iteration
|
||||
}
|
||||
|
||||
void Branch::visitForLines(const SGVec3d& aPos, double aCutoff,
|
||||
PolyLineList& aLines,
|
||||
FindLinesDeque& aQ) const
|
||||
{
|
||||
for (unsigned int i=0; i<8; ++i) {
|
||||
if (!children[i]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
double d = children[i]->distToNearest(aPos);
|
||||
if (d > aCutoff) {
|
||||
continue; // exceeded cutoff
|
||||
}
|
||||
|
||||
aQ.push_back(children[i]);
|
||||
} // of child iteration
|
||||
}
|
||||
|
||||
Node* Branch::childForPos(const SGVec3d& aCart) const
|
||||
{
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include <Navaids/positioned.hxx>
|
||||
#include <Navaids/NavDataCache.hxx>
|
||||
#include <Navaids/PolyLine.hxx>
|
||||
|
||||
namespace flightgear
|
||||
{
|
||||
|
@ -112,6 +113,10 @@ namespace Octree
|
|||
typedef Ordered<FGPositioned*> OrderedPositioned;
|
||||
typedef std::vector<OrderedPositioned> FindNearestResults;
|
||||
|
||||
// for extracting lines, we don't care about distance ordering, since
|
||||
// we're always grabbing all the lines in an area
|
||||
typedef std::deque<Node*> FindLinesDeque;
|
||||
|
||||
extern Node* global_spatialOctree;
|
||||
|
||||
class Leaf;
|
||||
|
@ -144,6 +149,10 @@ namespace Octree
|
|||
FindNearestResults& aResults, FindNearestPQueue&) = 0;
|
||||
|
||||
virtual Leaf* findLeafForPos(const SGVec3d& aPos) const = 0;
|
||||
|
||||
virtual void visitForLines(const SGVec3d& aPos, double aCutoff,
|
||||
PolyLineList& aLines,
|
||||
FindLinesDeque& aQ) const = 0;
|
||||
protected:
|
||||
Node(const SGBoxd &aBox, int64_t aIdent) :
|
||||
_ident(aIdent),
|
||||
|
@ -170,12 +179,20 @@ namespace Octree
|
|||
}
|
||||
|
||||
void insertChild(FGPositioned::Type ty, PositionedID id);
|
||||
|
||||
void addPolyLine(PolyLineRef);
|
||||
|
||||
virtual void visitForLines(const SGVec3d& aPos, double aCutoff,
|
||||
PolyLineList& aLines,
|
||||
FindLinesDeque& aQ) const;
|
||||
private:
|
||||
bool childrenLoaded;
|
||||
|
||||
typedef std::multimap<FGPositioned::Type, PositionedID> ChildMap;
|
||||
ChildMap children;
|
||||
|
||||
|
||||
PolyLineList lines;
|
||||
|
||||
void loadChildren();
|
||||
};
|
||||
|
||||
|
@ -195,6 +212,10 @@ namespace Octree
|
|||
}
|
||||
|
||||
int childMask() const;
|
||||
|
||||
virtual void visitForLines(const SGVec3d& aPos, double aCutoff,
|
||||
PolyLineList& aLines,
|
||||
FindLinesDeque& aQ) const;
|
||||
private:
|
||||
Node* childForPos(const SGVec3d& aCart) const;
|
||||
Node* childAtIndex(int childIndex) const;
|
||||
|
|
Loading…
Reference in a new issue