DYT/Tool/OpenSceneGraph-3.6.5/include/osgEarth/Geometry

651 lines
22 KiB
Plaintext
Raw Permalink Normal View History

2024-12-24 23:49:36 +00:00
/* -*-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