This is all unused yet, but defines the simple model for polyLines.
FlightPlan.cxx
NavDataCache.cxx
PositionedOctree.cxx
+ PolyLine.cxx
)
set(HEADERS
FlightPlan.hxx
NavDataCache.hxx
PositionedOctree.hxx
+ PolyLine.hxx
)
if (NOT SYSTEM_SQLITE)
--- /dev/null
+/**
+ * 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;
+}
+
+
--- /dev/null
+/**
+ * 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
\ No newline at end of file
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)
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
{
#include <Navaids/positioned.hxx>
#include <Navaids/NavDataCache.hxx>
+#include <Navaids/PolyLine.hxx>
namespace flightgear
{
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;
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),
}
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();
};
}
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;