651 lines
22 KiB
Plaintext
651 lines
22 KiB
Plaintext
|
/* -*-c++-*- */
|
||
|
/* osgEarth - Geospatial SDK for OpenSceneGraph
|
||
|
* Copyright 2020 Pelican Mapping
|
||
|
* http://osgearth.org
|
||
|
*
|
||
|
* osgEarth is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU Lesser 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 Lesser General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU Lesser General Public License
|
||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||
|
*/
|
||
|
#ifndef OSGEARTHSYMBOLOGY_GEOMETRY_H
|
||
|
#define OSGEARTHSYMBOLOGY_GEOMETRY_H 1
|
||
|
|
||
|
#include <osgEarth/Common>
|
||
|
#include <osgEarth/GeoData>
|
||
|
#include <osgEarth/Containers>
|
||
|
#include <vector>
|
||
|
#include <stack>
|
||
|
#include <queue>
|
||
|
|
||
|
namespace osgEarth
|
||
|
{
|
||
|
using namespace osgEarth;
|
||
|
|
||
|
/** Options for the Geometry::buffer() operation. */
|
||
|
class BufferParameters
|
||
|
{
|
||
|
public:
|
||
|
enum CapStyle { CAP_DEFAULT, CAP_SQUARE, CAP_ROUND, CAP_FLAT };
|
||
|
enum JoinStyle { JOIN_ROUND, JOIN_MITRE, JOIN_BEVEL};
|
||
|
BufferParameters( CapStyle capStyle =CAP_DEFAULT, JoinStyle joinStyle = JOIN_ROUND, int cornerSegs =0, bool singleSided=false, bool leftSide=false )
|
||
|
: _capStyle(capStyle), _joinStyle(joinStyle),_cornerSegs(cornerSegs), _singleSided(singleSided), _leftSide(leftSide) { }
|
||
|
CapStyle _capStyle;
|
||
|
JoinStyle _joinStyle;
|
||
|
int _cornerSegs; // # of line segment making up a rounded corner
|
||
|
bool _singleSided; //Whether or not to do a single sided buffer
|
||
|
bool _leftSide; //If doing a single sided buffer are we buffering to the left? If false, buffer to the right
|
||
|
};
|
||
|
|
||
|
typedef std::vector<osg::Vec3d> Vec3dVector;
|
||
|
|
||
|
/**
|
||
|
* Baseline geometry class. All Geometry objects derive from this
|
||
|
* class, even MultiGeometry.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT Geometry : public osgEarth::InlineVector<osg::Vec3d,osg::Referenced>
|
||
|
{
|
||
|
public:
|
||
|
enum Type {
|
||
|
TYPE_UNKNOWN,
|
||
|
TYPE_POINT,
|
||
|
TYPE_POINTSET,
|
||
|
TYPE_LINESTRING,
|
||
|
TYPE_RING,
|
||
|
TYPE_POLYGON,
|
||
|
TYPE_TRIMESH,
|
||
|
TYPE_MULTI
|
||
|
};
|
||
|
|
||
|
enum Orientation {
|
||
|
ORIENTATION_CCW,
|
||
|
ORIENTATION_CW,
|
||
|
ORIENTATION_DEGENERATE
|
||
|
};
|
||
|
|
||
|
public:
|
||
|
Geometry() : Geometry(TYPE_UNKNOWN) { }
|
||
|
Geometry(const Geometry& rhs) = default;
|
||
|
|
||
|
/** dtor - intentionally public */
|
||
|
virtual ~Geometry();
|
||
|
|
||
|
public:
|
||
|
static std::string toString( Type t ) {
|
||
|
return
|
||
|
t == TYPE_POINT ? "Point" :
|
||
|
t == TYPE_POINTSET ? "PointSet" :
|
||
|
t == TYPE_LINESTRING ? "LineString" :
|
||
|
t == TYPE_RING ? "Ring" :
|
||
|
t == TYPE_POLYGON ? "Polygon" :
|
||
|
t == TYPE_TRIMESH ? "TriangleMesh" :
|
||
|
t == TYPE_MULTI ? "MultiGeometry" :
|
||
|
"Unknown";
|
||
|
}
|
||
|
|
||
|
/** Creates a geometry from a vector array */
|
||
|
static Geometry* create( Type type, const Vec3dVector* toCopy );
|
||
|
|
||
|
// true if osgEarth is compiled for buffering
|
||
|
static bool hasBufferOperation();
|
||
|
|
||
|
public:
|
||
|
/**
|
||
|
* Gets the total number of points in this geometry.
|
||
|
*/
|
||
|
virtual int getTotalPointCount() const;
|
||
|
|
||
|
/**
|
||
|
* Gets the total number of geometry components
|
||
|
*/
|
||
|
virtual unsigned getNumComponents() const { return 1; }
|
||
|
|
||
|
/**
|
||
|
* Gets the total number of geometries; it is the total of all parts of all
|
||
|
* components. Also can be seen as the number of Geometry objects that would
|
||
|
* be returned by a full GeometryIterator.
|
||
|
*/
|
||
|
virtual unsigned getNumGeometries() const { return 1; }
|
||
|
|
||
|
/**
|
||
|
* Converts this geometry to another type. This function will return "this" if
|
||
|
* the type is the same, and will return NULL if the conversion is impossible.
|
||
|
*/
|
||
|
virtual Geometry* cloneAs( const Geometry::Type& newType ) const;
|
||
|
|
||
|
/**
|
||
|
* Creates a new Vec3Array (single-precision), copies the part into it, and
|
||
|
* returns the new object.
|
||
|
*/
|
||
|
osg::Vec3Array* createVec3Array() const;
|
||
|
|
||
|
/**
|
||
|
* Creates a new Vec3dArray (double-precision), copies the part into it, and
|
||
|
* returns the new object.
|
||
|
*/
|
||
|
osg::Vec3dArray* createVec3dArray() const;
|
||
|
|
||
|
/**
|
||
|
* Gets the bounds of this geometry
|
||
|
*/
|
||
|
virtual Bounds getBounds() const;
|
||
|
|
||
|
/**
|
||
|
* Length of the [outermost] geometry.
|
||
|
*/
|
||
|
virtual double getLength() const;
|
||
|
|
||
|
/**
|
||
|
* Whether the geometry is lines
|
||
|
*/
|
||
|
bool isLinear() const { return getComponentType() == TYPE_LINESTRING || getComponentType() == TYPE_RING; }
|
||
|
|
||
|
/**
|
||
|
* Runs a buffer (dialate/erode) operation on this geometry and returns the
|
||
|
* result in the output parameter. Returns true if the op succeeded.
|
||
|
*/
|
||
|
bool buffer(
|
||
|
double distance,
|
||
|
osg::ref_ptr<Geometry>& output,
|
||
|
const BufferParameters& bp =BufferParameters() ) const;
|
||
|
|
||
|
/**
|
||
|
* Crops this geometry to the region represented by the crop polygon, returning
|
||
|
* the result in the output parameter. Returns true if the op succeeded.
|
||
|
*/
|
||
|
bool crop(
|
||
|
const class Polygon* cropPolygon,
|
||
|
osg::ref_ptr<Geometry>& output ) const;
|
||
|
|
||
|
/**
|
||
|
* Crops this geometry to the bounds, returning the result in the output parameter.
|
||
|
* Returns true if the op succeeded.
|
||
|
*/
|
||
|
bool crop(
|
||
|
const Bounds& bounds,
|
||
|
osg::ref_ptr<Geometry>& output) const;
|
||
|
|
||
|
/**
|
||
|
* Creates the union of this geometry with the other geometry, returning
|
||
|
* the result in the output parameter. Returns true if the op succeeded.
|
||
|
*/
|
||
|
bool geounion(
|
||
|
const Geometry* other,
|
||
|
osg::ref_ptr<Geometry>& output ) const;
|
||
|
|
||
|
/**
|
||
|
* Boolean difference - subtracts diffPolygon from this geometry, and put the
|
||
|
* result in output.
|
||
|
*/
|
||
|
bool difference(
|
||
|
const class Polygon* diffPolygon,
|
||
|
osg::ref_ptr<Geometry>& output ) const;
|
||
|
|
||
|
/**
|
||
|
* Whether this geometry intersects with another geometry
|
||
|
*/
|
||
|
bool intersects(
|
||
|
const class Geometry* other
|
||
|
) const;
|
||
|
|
||
|
/**
|
||
|
* Simplifies this geometry, returning the result in the output parameter.
|
||
|
*/
|
||
|
bool simplify(
|
||
|
double tolerance,
|
||
|
bool preserveTopology,
|
||
|
osg::ref_ptr<Geometry>& output
|
||
|
) const;
|
||
|
|
||
|
//! Calculate the signed distance (in the XY plane) from a point
|
||
|
//! to this geometry.
|
||
|
//! A negative distance indicates that the point is interior
|
||
|
//! to a ring or polygon.
|
||
|
virtual double getSignedDistance2D(
|
||
|
const osg::Vec3d& point) const;
|
||
|
|
||
|
/**
|
||
|
* Localizes this geometry relative to its centroid, and returns the localization
|
||
|
* offset.
|
||
|
*/
|
||
|
osg::Vec3d localize();
|
||
|
|
||
|
/**
|
||
|
* Reverses a call the localize(), given the same offset returned by that method.
|
||
|
*/
|
||
|
void delocalize( const osg::Vec3d& offset );
|
||
|
|
||
|
/**
|
||
|
* Reorders the points in the geometry so that, if the last point was connected
|
||
|
* to the first in a ring, they would be would in the specified direction.
|
||
|
*/
|
||
|
virtual void rewind( Orientation ori );
|
||
|
|
||
|
/**
|
||
|
* Makes the last point the same as the first point. Suitable for rings and polygons.
|
||
|
*/
|
||
|
virtual void close();
|
||
|
|
||
|
virtual void open() { }
|
||
|
|
||
|
/**
|
||
|
* Removes consecutive duplicates in the geometry to prepare for tessellation.
|
||
|
*/
|
||
|
virtual void removeDuplicates();
|
||
|
|
||
|
/**
|
||
|
* Removes any colinear points, i.e. points that can be safely removed without
|
||
|
* affecting the shape/area of the geometry.
|
||
|
*/
|
||
|
virtual void removeColinearPoints();
|
||
|
|
||
|
/**
|
||
|
* Get the winding orientation of the geometry (if you consider the last point
|
||
|
* to connect back to the first in a ring.)
|
||
|
*/
|
||
|
Orientation getOrientation() const;
|
||
|
|
||
|
//! Whether a closed geometry contains the 2D point
|
||
|
virtual bool contains2D(double x, double y) const { return false; }
|
||
|
|
||
|
|
||
|
//! Iterate over all the parts of a geometry (signature = void(Geometry* part))
|
||
|
template<typename CALLABLE>
|
||
|
inline void forEachPart(bool includePolygonHoles, CALLABLE&& func);
|
||
|
template<typename CALLABLE>
|
||
|
inline void forEachPart(CALLABLE&& func) { forEachPart(true, func); };
|
||
|
|
||
|
//! Iterate over all the parts of a CONST geometry (signature = void(const Geometry* part))
|
||
|
template<typename CALLABLE>
|
||
|
inline void forEachPart(bool includePolygonHoles, CALLABLE&& func) const;
|
||
|
template<typename CALLABLE>
|
||
|
inline void forEachPart(CALLABLE&& func) const { forEachPart(true, func); };
|
||
|
|
||
|
public:
|
||
|
inline Type getType() const { return _type; }
|
||
|
virtual Type getComponentType() const { return getType(); }
|
||
|
virtual bool isValid() const { return size() >= 1; }
|
||
|
|
||
|
virtual Geometry* clone() const { return cloneAs(getType()); }
|
||
|
|
||
|
void push_back(const osg::Vec3d& v ) {
|
||
|
osgEarth::InlineVector<osg::Vec3d,osg::Referenced>::push_back(v); }
|
||
|
void push_back(double x, double y) {
|
||
|
osgEarth::InlineVector<osg::Vec3d,osg::Referenced>::push_back(osg::Vec3d(x,y,0.)); }
|
||
|
void push_back(double x, double y, double z) {
|
||
|
osgEarth::InlineVector<osg::Vec3d,osg::Referenced>::push_back(osg::Vec3d(x,y,z)); }
|
||
|
|
||
|
virtual bool isRing() const { return getComponentType() == TYPE_RING || getComponentType() == TYPE_POLYGON; }
|
||
|
virtual bool isPolygon() const { return getComponentType() == TYPE_POLYGON; }
|
||
|
virtual bool isPointSet() const { return getComponentType()==TYPE_POINT || getComponentType()==TYPE_POINTSET; }
|
||
|
virtual bool isLineString() const { return getComponentType() == TYPE_LINESTRING; }
|
||
|
virtual bool isOpen() const { return true; }
|
||
|
|
||
|
protected:
|
||
|
Geometry(Type type, int capacity = 0);
|
||
|
Geometry(Type type, const Vec3dVector* toCopy);
|
||
|
|
||
|
Type _type = TYPE_UNKNOWN;
|
||
|
};
|
||
|
|
||
|
typedef std::vector< osg::ref_ptr<Geometry> > GeometryCollection;
|
||
|
|
||
|
/**
|
||
|
* An unordered collections of points.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT PointSet : public Geometry
|
||
|
{
|
||
|
public:
|
||
|
PointSet(int capacity = 0) : Geometry(TYPE_POINTSET, capacity) { }
|
||
|
PointSet(const Vec3dVector* toCopy) : Geometry(TYPE_POINTSET, toCopy) { }
|
||
|
PointSet(const PointSet& rhs) = default;
|
||
|
|
||
|
// Don't close point sets
|
||
|
void close() override { }
|
||
|
|
||
|
protected:
|
||
|
PointSet(Type type, int capacity = 0) : Geometry(type, capacity) { }
|
||
|
PointSet(Type type, const Vec3dVector* toCopy) : Geometry(type, toCopy) { }
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* A single point.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT Point : public PointSet
|
||
|
{
|
||
|
public:
|
||
|
Point(int capacity = 0) : PointSet(TYPE_POINT, capacity) { }
|
||
|
Point(const Vec3dVector* toCopy) : PointSet(TYPE_POINT, toCopy) { }
|
||
|
Point(const Point& rhs) = default;
|
||
|
|
||
|
void set(const osg::Vec3d& value);
|
||
|
|
||
|
// don't close
|
||
|
void close() override { }
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* An ordered set of points forming a single contiguous line string.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT LineString : public Geometry
|
||
|
{
|
||
|
public:
|
||
|
LineString(int capacity = 0) : Geometry(TYPE_LINESTRING, capacity) { }
|
||
|
LineString(const Vec3dVector* toCopy) : Geometry(TYPE_LINESTRING, toCopy) { }
|
||
|
LineString(const LineString& rhs) = default;
|
||
|
|
||
|
bool getSegment(double length, osg::Vec3d& start, osg::Vec3d& end);
|
||
|
|
||
|
void close() override;
|
||
|
|
||
|
double getSignedDistance2D(const osg::Vec3d& point) const override;
|
||
|
|
||
|
public:
|
||
|
bool isValid() const override { return size() >= 2; }
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* A Ring is a closed region. It is open (the first and last
|
||
|
* points are not the same). It has an orientation, i.e. it is either
|
||
|
* wound clockwise or counter-clockwise.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT Ring : public Geometry
|
||
|
{
|
||
|
public:
|
||
|
Ring(int capacity = 0) : Geometry(TYPE_RING, capacity) { }
|
||
|
Ring(const Vec3dVector* toCopy) : Ring(TYPE_RING, toCopy) { }
|
||
|
Ring(const Ring& ring) = default;
|
||
|
|
||
|
// override
|
||
|
virtual Geometry* cloneAs( const Geometry::Type& newType ) const;
|
||
|
|
||
|
// tests whether the point falls within the ring
|
||
|
bool contains2D( double x, double y ) const override;
|
||
|
|
||
|
// gets the signed area of a part that is known to be open.
|
||
|
double getSignedArea2D() const;
|
||
|
|
||
|
// gets the length of the ring (override)
|
||
|
double getLength() const;
|
||
|
|
||
|
// ensures that the first and last points are not idential.
|
||
|
void open() override;
|
||
|
|
||
|
// ensures that the first and last points are identical.
|
||
|
void close() override;
|
||
|
|
||
|
// whether the ring is open (i.e. first and last points are different)
|
||
|
bool isOpen() const override;
|
||
|
|
||
|
// opens and winds the ring in the specified direction
|
||
|
virtual void rewind(Orientation ori);
|
||
|
|
||
|
double getSignedDistance2D(const osg::Vec3d& a) const override;
|
||
|
|
||
|
public:
|
||
|
virtual Type getType() const { return Geometry::TYPE_RING; }
|
||
|
virtual bool isValid() const { return size() >= 3; }
|
||
|
|
||
|
protected:
|
||
|
Ring(Type type, int capacity = 0) : Geometry(type, capacity) { }
|
||
|
Ring(Type type, const Vec3dVector* toCopy);
|
||
|
};
|
||
|
|
||
|
typedef std::vector<osg::ref_ptr<Ring> > RingCollection;
|
||
|
|
||
|
/**
|
||
|
* A Polygon is a geometry that consists of one outer boundary Ring, and
|
||
|
* zero or more inner "hole" rings. The boundary ring is would CCW, and the
|
||
|
* inner "holes" are wound CW.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT Polygon : public Ring
|
||
|
{
|
||
|
public:
|
||
|
Polygon(int capacity = 0) : Ring(TYPE_POLYGON, capacity) { }
|
||
|
Polygon(const Vec3dVector* toCopy) : Ring(TYPE_POLYGON, toCopy) { }
|
||
|
Polygon(const Polygon& rhs);
|
||
|
|
||
|
public:
|
||
|
virtual Type getType() const { return Geometry::TYPE_POLYGON; }
|
||
|
virtual int getTotalPointCount() const;
|
||
|
|
||
|
virtual unsigned getNumGeometries() const { return 1 + _holes.size(); }
|
||
|
|
||
|
// tests whether the point falls within the polygon (but not its holes)
|
||
|
virtual bool contains2D( double x, double y ) const override;
|
||
|
|
||
|
virtual void open();
|
||
|
|
||
|
virtual void close();
|
||
|
|
||
|
virtual void removeDuplicates();
|
||
|
|
||
|
virtual void removeColinearPoints();
|
||
|
|
||
|
virtual double getSignedDistance2D(
|
||
|
const osg::Vec3d& a) const override;
|
||
|
|
||
|
public:
|
||
|
RingCollection& getHoles() { return _holes; }
|
||
|
const RingCollection& getHoles() const { return _holes; }
|
||
|
|
||
|
protected:
|
||
|
RingCollection _holes;
|
||
|
};
|
||
|
|
||
|
class OSGEARTH_EXPORT TriMesh : public Geometry
|
||
|
{
|
||
|
public:
|
||
|
TriMesh() : Geometry(TYPE_TRIMESH) { }
|
||
|
|
||
|
unsigned getNumGeometries() const override { return 1u; }
|
||
|
|
||
|
bool contains2D(double x, double y) const override;
|
||
|
|
||
|
public:
|
||
|
std::vector<unsigned> _indices;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* A collection of multiple geometries (aka, a "multi-part" geometry).
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT MultiGeometry : public Geometry
|
||
|
{
|
||
|
public:
|
||
|
MultiGeometry() : Geometry(TYPE_MULTI) { }
|
||
|
MultiGeometry(const MultiGeometry& rhs);
|
||
|
MultiGeometry(const GeometryCollection& parts);
|
||
|
|
||
|
public:
|
||
|
Type getComponentType() const override;
|
||
|
int getTotalPointCount() const override;
|
||
|
unsigned getNumComponents() const override { return _parts.size(); }
|
||
|
|
||
|
unsigned getNumGeometries() const override;
|
||
|
|
||
|
// gets the combined length of all parts
|
||
|
double getLength() const override;
|
||
|
|
||
|
// override
|
||
|
Geometry* cloneAs( const Geometry::Type& newType ) const override;
|
||
|
bool isValid() const override;
|
||
|
Bounds getBounds() const override;
|
||
|
void rewind( Orientation ori ) override;
|
||
|
void removeDuplicates() override;
|
||
|
void removeColinearPoints() override;
|
||
|
void open() override;
|
||
|
void close() override;
|
||
|
double getSignedDistance2D(const osg::Vec3d& a) const override;
|
||
|
bool contains2D(double x, double y) const override;
|
||
|
|
||
|
public:
|
||
|
GeometryCollection& getComponents() { return _parts; }
|
||
|
const GeometryCollection& getComponents() const { return _parts; }
|
||
|
|
||
|
Geometry* add( Geometry* geom ) { _parts.push_back(geom); return geom; }
|
||
|
|
||
|
protected:
|
||
|
GeometryCollection _parts;
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Iterates over a Geometry object, returning each component Geometry
|
||
|
* in turn. The iterator automatically traverses MultiGeometry objects,
|
||
|
* returning their components. The iterator NEVER returns an actual
|
||
|
* MultiGeometry object.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT GeometryIterator
|
||
|
{
|
||
|
public:
|
||
|
//! Constructs a new iterator.
|
||
|
//! @param geom Geometry over which to iterator
|
||
|
//! @param traversePolyHoles Whether to include polygon holes in the traversal
|
||
|
GeometryIterator(
|
||
|
Geometry* geom,
|
||
|
bool traversePolygonHoles = true);
|
||
|
|
||
|
//! Whether next() will return another geometry
|
||
|
bool hasMore() const;
|
||
|
|
||
|
//! Returns the next geometry part when hasMore() == true
|
||
|
Geometry* next();
|
||
|
|
||
|
//! Visits each part and calls a user-defined functor
|
||
|
inline void forEach(const std::function<void(Geometry* part)>& func) {
|
||
|
while (hasMore()) func(next());
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
Geometry* _next;
|
||
|
std::queue<Geometry*> _stack;
|
||
|
bool _traverseMulti;
|
||
|
bool _traversePolyHoles;
|
||
|
|
||
|
void fetchNext();
|
||
|
};
|
||
|
|
||
|
/**
|
||
|
* Iterates over a Geometry object, returning each component Geometry
|
||
|
* in turn. The iterator automatically traverses MultiGeometry objects,
|
||
|
* returning their components. The iterator NEVER returns an actual
|
||
|
* MultiGeometry object.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT ConstGeometryIterator
|
||
|
{
|
||
|
public:
|
||
|
//! Null constructor (must call reset before using)
|
||
|
ConstGeometryIterator();
|
||
|
|
||
|
//! Constructs a new iterator.
|
||
|
//! @param geom Geometry over which to iterator
|
||
|
//! @param traversePolyHoles Whether to include polygon holes in the traversal
|
||
|
ConstGeometryIterator(
|
||
|
const Geometry* geom,
|
||
|
bool traversePolygonHoles =true );
|
||
|
|
||
|
//! Sets the iterator to iterate a new geometry
|
||
|
void reset(const Geometry* geom, bool traversePolygonHoles = true);
|
||
|
|
||
|
//! Whether next() will return another geometry
|
||
|
bool hasMore() const;
|
||
|
|
||
|
//! Returns the next geometry part when hasMore() == true
|
||
|
const Geometry* next();
|
||
|
|
||
|
//! Visits each part and calls a user-defined functor
|
||
|
//! Signature = void(const Geometry* part)
|
||
|
template<typename CALLABLE>
|
||
|
inline void forEach(CALLABLE&& func) { //const std::function<void(const Geometry* part)>& func) {
|
||
|
while (hasMore()) func(next());
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
const Geometry* _next = nullptr;
|
||
|
std::vector<const Geometry*> _stack;
|
||
|
//std::stack<const Geometry*> _stack;
|
||
|
bool _traverseMulti = true;
|
||
|
bool _traversePolyHoles = true;
|
||
|
|
||
|
void fetchNext();
|
||
|
};
|
||
|
|
||
|
typedef std::pair<osg::Vec3d, osg::Vec3d> Segment;
|
||
|
|
||
|
/**
|
||
|
* Iterates over geometry, returning each consecutive pair of points
|
||
|
* as a line segment.
|
||
|
*/
|
||
|
class OSGEARTH_EXPORT ConstSegmentIterator
|
||
|
{
|
||
|
public:
|
||
|
//! Construct an iterator.
|
||
|
//! @param verts Geometry over which to iterate segments
|
||
|
//! @param forceClosedLoop connect the last and first point even if the
|
||
|
//! geometry is not a ring.
|
||
|
ConstSegmentIterator(const Geometry* verts, bool forceClosedLoop = false) {
|
||
|
_verts = &verts->asVector();
|
||
|
_iter = verts->begin();
|
||
|
_done = verts->size() < 2;
|
||
|
_closeLoop = forceClosedLoop ? true : verts->getType() == verts->TYPE_RING || verts->getType() == verts->TYPE_POLYGON;
|
||
|
}
|
||
|
|
||
|
//! Whether next() will return a valid segment
|
||
|
inline bool hasMore() const {
|
||
|
return !_done;
|
||
|
}
|
||
|
|
||
|
//! Next segment when hasMore() == true
|
||
|
const Segment& next() {
|
||
|
_current.first = *_iter++;
|
||
|
if (_iter == _verts->end()) {
|
||
|
_iter = _verts->begin();
|
||
|
_done = true;
|
||
|
}
|
||
|
else if (_iter + 1 == _verts->end() && !_closeLoop) {
|
||
|
_done = true;
|
||
|
}
|
||
|
_current.second = *_iter;
|
||
|
return _current;
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
const Vec3dVector* _verts;
|
||
|
Vec3dVector::const_iterator _iter;
|
||
|
bool _done;
|
||
|
bool _closeLoop;
|
||
|
Segment _current;
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
//! Iterate over all the parts of a geometry
|
||
|
template<typename CALLABLE>
|
||
|
inline void Geometry::forEachPart(bool includePolygonHoles, CALLABLE&& func)
|
||
|
{
|
||
|
GeometryIterator i(this, includePolygonHoles);
|
||
|
i.forEach(func);
|
||
|
}
|
||
|
|
||
|
//! Iterate over all the parts of a geometry
|
||
|
template<typename CALLABLE>
|
||
|
inline void Geometry::forEachPart(bool includePolygonHoles, CALLABLE&& func) const
|
||
|
{
|
||
|
ConstGeometryIterator i(this, includePolygonHoles);
|
||
|
i.forEach(func);
|
||
|
}
|
||
|
|
||
|
|
||
|
} // namespace osgEarth
|
||
|
|
||
|
|
||
|
#endif // OSGEARTHSYMBOLOGY_GEOMETRY_H
|
||
|
|