]> git.mxchange.org Git - flightgear.git/commitdiff
Core data class for PolyLine handling.
authorJames Turner <zakalawe@mac.com>
Wed, 6 Mar 2013 17:22:34 +0000 (17:22 +0000)
committerJames Turner <zakalawe@mac.com>
Wed, 6 Mar 2013 17:22:34 +0000 (17:22 +0000)
This is all unused yet, but defines the simple model for polyLines.

src/Navaids/CMakeLists.txt
src/Navaids/PolyLine.cxx [new file with mode: 0644]
src/Navaids/PolyLine.hxx [new file with mode: 0644]
src/Navaids/PositionedOctree.cxx
src/Navaids/PositionedOctree.hxx

index d611e1c16c4f5a734bdb1f0fac683ee64e166473..485a7ac62e320d366d177bef399c987d478e1be6 100644 (file)
@@ -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)
diff --git a/src/Navaids/PolyLine.cxx b/src/Navaids/PolyLine.cxx
new file mode 100644 (file)
index 0000000..f7164ea
--- /dev/null
@@ -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;
+}
+
+
diff --git a/src/Navaids/PolyLine.hxx b/src/Navaids/PolyLine.hxx
new file mode 100644 (file)
index 0000000..f6db381
--- /dev/null
@@ -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
\ No newline at end of file
index 781fee8f220c17999b96aa4e6ce90da00f4bd75f..2dbae40893d1c1c4d818fb9288d1fb6477c1f865 100644 (file)
@@ -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
 {
index 3a830349c6cf5e34b3ff63a025bd7fe7a360abba..b2100718bc0f90ba9a08f85851334e3690ec8f4f 100644 (file)
@@ -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;