1/* -*-c++-*- */
2/* osgEarth - Geospatial SDK for OpenSceneGraph
3 * Copyright 2019 Pelican Mapping
4 * http://osgearth.org
5 *
6 * osgEarth is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>
18 */
19#ifndef OSGEARTHSYMBOLOGY_GEOMETRY_H
20#define OSGEARTHSYMBOLOGY_GEOMETRY_H 1
21
22#include <osgEarthSymbology/Common>
23#include <osgEarth/GeoData>
24#include <osgEarth/Containers>
25#include <vector>
26#include <stack>
27
28namespace osgEarth { namespace Symbology
29{
30    using namespace osgEarth;
31
32    /** Options for the Geometry::buffer() operation. */
33    class BufferParameters
34    {
35    public:
36        enum CapStyle  { CAP_DEFAULT, CAP_SQUARE, CAP_ROUND, CAP_FLAT };
37        enum JoinStyle { JOIN_ROUND, JOIN_MITRE, JOIN_BEVEL};
38        BufferParameters( CapStyle capStyle =CAP_DEFAULT, JoinStyle joinStyle = JOIN_ROUND, int cornerSegs =0, bool singleSided=false, bool leftSide=false )
39            : _capStyle(capStyle), _joinStyle(joinStyle),_cornerSegs(cornerSegs), _singleSided(singleSided), _leftSide(leftSide) { }
40        CapStyle  _capStyle;
41        JoinStyle _joinStyle;
42        int       _cornerSegs; // # of line segment making up a rounded corner
43        bool      _singleSided; //Whether or not to do a single sided buffer
44        bool      _leftSide;    //If doing a single sided buffer are we buffering to the left?  If false, buffer to the right
45    };
46
47    typedef std::vector<osg::Vec3d> Vec3dVector;
48
49    /**
50     * Baseline geometry class. All Geometry objects derive from this
51     * class, even MultiGeometry.
52     */
53    class OSGEARTHSYMBOLOGY_EXPORT Geometry : public osgEarth::MixinVector<osg::Vec3d,osg::Referenced>
54    {
55    public:
56        Geometry( int capacity =0 );
57        Geometry( const Geometry& rhs );
58        Geometry( const Vec3dVector* toCopy );
59
60        /** dtor - intentionally public */
61        virtual ~Geometry();
62
63    public:
64        enum Type {
65            TYPE_UNKNOWN,
66            TYPE_POINTSET,
67            TYPE_LINESTRING,
68            TYPE_RING,
69            TYPE_POLYGON,
70            TYPE_MULTI
71        };
72
73        enum Orientation {
74            ORIENTATION_CCW,
75            ORIENTATION_CW,
76            ORIENTATION_DEGENERATE
77        };
78
79        static std::string toString( Type t ) {
80            return
81                t == TYPE_POINTSET ?   "pointset" :
82                t == TYPE_LINESTRING ? "linestring" :
83                t == TYPE_RING ?       "ring" :
84                t == TYPE_POLYGON ?    "polygon" :
85                t == TYPE_MULTI ?      "multi" :
86                "unknown";
87        }
88
89        /** Creates a geometry from a vector array */
90        static Geometry* create( Type type, const Vec3dVector* toCopy );
91
92        // true if osgEarth is compiled for buffering
93        static bool hasBufferOperation();
94
95    public:
96        /**
97         * Gets the total number of points in this geometry.
98         */
99        virtual int getTotalPointCount() const;
100
101        /**
102         * Gets the total number of geometry components
103         */
104        virtual unsigned getNumComponents() const { return 1; }
105
106        /**
107         * Gets the total number of geometries; it is the total of all parts of all
108         * components. Also can be seen as the number of Geometry objects that would
109         * be returned by a full GeometryIterator.
110         */
111        virtual unsigned getNumGeometries() const { return 1; }
112
113        /**
114         * Converts this geometry to another type. This function will return "this" if
115         * the type is the same, and will return NULL if the conversion is impossible.
116         */
117        virtual Geometry* cloneAs( const Geometry::Type& newType ) const;
118
119        /**
120         * Creates a new Vec3Array (single-precision), copies the part into it, and
121         * returns the new object.
122         */
123        osg::Vec3Array* createVec3Array() const;
124
125        /**
126         * Creates a new Vec3dArray (double-precision), copies the part into it, and
127         * returns the new object.
128         */
129        osg::Vec3dArray* createVec3dArray() const;
130
131        /**
132         * Gets the bounds of this geometry
133         */
134        virtual Bounds getBounds() const;
135
136        /**
137         * Length of the [outermost] geometry.
138         */
139        virtual double getLength() const;
140
141        /**
142         * Whether the geometry is lines
143         */
144        bool isLinear() const { return getComponentType() == TYPE_LINESTRING || getComponentType() == TYPE_RING; }
145
146        /**
147         * Runs a buffer (dialate/erode) operation on this geometry and returns the
148         * result in the output parameter. Returns true if the op succeeded.
149         */
150        bool buffer(
151            double distance,
152            osg::ref_ptr<Geometry>& output,
153            const BufferParameters& bp =BufferParameters() ) const;
154
155        /**
156         * Crops this geometry to the region represented by the crop polygon, returning
157         * the result in the output parameter. Returns true if the op succeeded.
158         */
159        bool crop(
160            const class Polygon* cropPolygon,
161            osg::ref_ptr<Geometry>& output ) const;
162
163        /**
164         * Crops this geometry to the bounds, returning the result in the output parameter.
165         * Returns true if the op succeeded.
166         */
167        bool crop(
168            const Bounds& bounds,
169            osg::ref_ptr<Geometry>& output) const;
170
171        /**
172         * Creates the union of this geometry with the other geometry, returning
173         * the result in the output parameter. Returns true if the op succeeded.
174         */
175        bool geounion(
176            const Geometry* other,
177            osg::ref_ptr<Geometry>& output ) const;
178
179        /**
180         * Boolean difference - subtracts diffPolygon from this geometry, and put the
181         * result in output.
182         */
183        bool difference(
184            const class Polygon* diffPolygon,
185            osg::ref_ptr<Geometry>& output ) const;
186
187        /**
188         * Whether this geometry intersects with another geometry
189         */
190        bool intersects(
191            const class Geometry* other
192            ) const;
193
194        /**
195         * Localizes this geometry relative to its centroid, and returns the localization
196         * offset.
197         */
198        osg::Vec3d localize();
199
200        /**
201         * Reverses a call the localize(), given the same offset returned by that method.
202         */
203        void delocalize( const osg::Vec3d& offset );
204
205        /**
206         * Reorders the points in the geometry so that, if the last point was connected
207         * to the first in a ring, they would be would in the specified direction.
208         */
209        virtual void rewind( Orientation ori );
210
211        /**
212         * Makes the last point the same as the first point. Suitable for rings and polygons.
213         */
214        virtual void close();
215
216        /**
217         * Removes consecutive duplicates in the geometry to prepare for tessellation.
218         */
219        virtual void removeDuplicates();
220
221        /**
222         * Removes any colinear points, i.e. points that can be safely removed without
223         * affecting the shape/area of the geometry.
224         */
225        virtual void removeColinearPoints();
226
227        /**
228         * Get the winding orientation of the geometry (if you consider the last point
229         * to connect back to the first in a ring.)
230         */
231        Orientation getOrientation() const;
232
233    public:
234        virtual Type getType() const { return TYPE_UNKNOWN; }
235        virtual Type getComponentType() const { return getType(); }
236        virtual bool isValid() const { return size() >= 1; }
237
238        virtual Geometry* clone() const { return cloneAs(getType()); }
239
240        void push_back(const osg::Vec3d& v ) {
241            osgEarth::MixinVector<osg::Vec3d,osg::Referenced>::push_back(v); }
242        void push_back(double x, double y) {
243            osgEarth::MixinVector<osg::Vec3d,osg::Referenced>::push_back(osg::Vec3d(x,y,0.)); }
244        void push_back(double x, double y, double z) {
245            osgEarth::MixinVector<osg::Vec3d,osg::Referenced>::push_back(osg::Vec3d(x,y,z)); }
246
247    protected:
248    };
249
250    typedef std::vector< osg::ref_ptr<Geometry> > GeometryCollection;
251
252    /**
253     * An unordered collections of points.
254     */
255    class OSGEARTHSYMBOLOGY_EXPORT PointSet : public Geometry
256    {
257    public:
258        PointSet( int capacity =0 ) : Geometry( capacity ) { }
259        PointSet( const Vec3dVector* toCopy ) : Geometry( toCopy ) { }
260        PointSet( const PointSet& rhs );
261
262        /** dtor */
263        virtual ~PointSet();
264
265        virtual void close();
266
267    public:
268        virtual Type getType() const { return Geometry::TYPE_POINTSET; }
269    };
270
271    /**
272     * An ordered set of points forming a single contiguous line string.
273     */
274    class OSGEARTHSYMBOLOGY_EXPORT LineString : public Geometry
275    {
276    public:
277        LineString( int capacity =0 ) : Geometry( capacity ) { }
278        LineString( const LineString& rhs );
279        LineString( const Vec3dVector* toCopy );
280
281        /** dtor */
282        virtual ~LineString();
283
284        bool getSegment(double length, osg::Vec3d& start, osg::Vec3d& end);
285
286        virtual void close();
287
288    public:
289        virtual Type getType() const { return Geometry::TYPE_LINESTRING; }
290        virtual bool isValid() const { return size() >= 2; }
291    };
292
293    /**
294     * A Ring is a closed region. It is open (the first and last
295     * points are not the same). It has an orientation, i.e. it is either
296     * wound clockwise or counter-clockwise.
297     */
298    class OSGEARTHSYMBOLOGY_EXPORT Ring : public Geometry
299    {
300    public:
301        Ring( int capacity =0 ) : Geometry( capacity ) { }
302        Ring( const Ring& ring );
303        Ring( const Vec3dVector* toCopy );
304
305        /** dtor */
306        virtual ~Ring();
307
308        // override
309        virtual Geometry* cloneAs( const Geometry::Type& newType ) const;
310
311        // tests whether the point falls within the ring
312        virtual bool contains2D( double x, double y ) const;
313
314        // gets the signed area of a part that is known to be open.
315        virtual double getSignedArea2D() const;
316
317        // gets the length of the ring (override)
318        virtual double getLength() const;
319
320        // ensures that the first and last points are not idential.
321        virtual void open();
322
323        // ensures that the first and last points are identical.
324        virtual void close();
325
326        // whether the ring is open (i.e. first and last points are different)
327        virtual bool isOpen() const;
328
329        // opens and winds the ring in the specified direction
330        virtual void rewind( Orientation ori );
331
332    public:
333        virtual Type getType() const { return Geometry::TYPE_RING; }
334        virtual bool isValid() const { return size() >= 3; }
335    };
336
337    typedef std::vector<osg::ref_ptr<Ring> > RingCollection;
338
339    /**
340     * A Polygon is a geometry that consists of one outer boundary Ring, and
341     * zero or more inner "hole" rings. The boundary ring is would CCW, and the
342     * inner "holes" are wound CW.
343     */
344    class OSGEARTHSYMBOLOGY_EXPORT Polygon : public Ring
345    {
346    public:
347        Polygon( int capacity =0 ) : Ring( capacity ) { }
348        Polygon( const Polygon& rhs );
349        Polygon( const Vec3dVector* toCopy );
350
351        /** dtor */
352        virtual ~Polygon();
353
354    public:
355        virtual Type getType() const { return Geometry::TYPE_POLYGON; }
356        virtual int getTotalPointCount() const;
357
358        virtual unsigned getNumGeometries() const { return 1 + _holes.size(); }
359
360        // tests whether the point falls within the polygon (but not its holes)
361        virtual bool contains2D( double x, double y ) const;
362
363        virtual void open();
364
365        virtual void close();
366
367        virtual void removeDuplicates();
368
369        virtual void removeColinearPoints();
370
371    public:
372        RingCollection& getHoles() { return _holes; }
373        const RingCollection& getHoles() const { return _holes; }
374
375    protected:
376        RingCollection _holes;
377    };
378
379    /**
380     * A collection of multiple geometries (aka, a "multi-part" geometry).
381     */
382    class OSGEARTHSYMBOLOGY_EXPORT MultiGeometry : public Geometry
383    {
384    public:
385        MultiGeometry() { }
386        MultiGeometry( const GeometryCollection& parts );
387        MultiGeometry( const MultiGeometry& rhs );
388
389        /** dtor */
390        virtual ~MultiGeometry();
391
392    public:
393        virtual Type getType() const { return Geometry::TYPE_MULTI; }
394        virtual Type getComponentType() const;
395        virtual int getTotalPointCount() const;
396        virtual unsigned getNumComponents() const { return _parts.size(); }
397
398        virtual unsigned getNumGeometries() const;
399
400        // gets the combined length of all parts
401        virtual double getLength() const;
402
403        // override
404        virtual Geometry* cloneAs( const Geometry::Type& newType ) const;
405        virtual bool isValid() const;
406        virtual Bounds getBounds() const;
407        virtual void rewind( Orientation ori );
408        virtual void removeColinearPoints();
409        virtual void close();
410
411    public:
412        GeometryCollection& getComponents() { return _parts; }
413        const GeometryCollection& getComponents() const { return _parts; }
414
415        Geometry* add( Geometry* geom ) { _parts.push_back(geom); return geom; }
416
417    protected:
418        GeometryCollection _parts;
419    };
420
421    /**
422     * Iterates over a Geometry object, returning each component Geometry
423     * in turn. The iterator automatically traverses MultiGeometry objects,
424     * returning their components. The iterator NEVER returns an actual
425     * MultiGeometry object.
426     */
427    class OSGEARTHSYMBOLOGY_EXPORT GeometryIterator
428    {
429    public:
430        /**
431         * New iterator.
432         *
433         * traversePolyHoles: set to TRUE to return Polygons AND Polygon hole geometries;
434         *                    set to FALSE to only return Polygon (outer ring).
435         *
436         * traverseMultiGeometry: set to TRUE to return MG children, but never an MG itself;
437         *                        set to FALSE to return MGs and NOT their children.
438         */
439        GeometryIterator(
440            Geometry* geom,
441            bool      traversePolygonHoles  =true );
442
443        bool hasMore() const;
444        Geometry* next();
445
446    private:
447        Geometry* _next;
448        std::stack<Geometry*> _stack;
449        bool _traverseMulti;
450        bool _traversePolyHoles;
451
452        void fetchNext();
453    };
454
455    class OSGEARTHSYMBOLOGY_EXPORT ConstGeometryIterator
456    {
457    public:
458        /**
459         * New iterator.
460         *
461         * traversePolyHoles: set to TRUE to return Polygons AND Polygon hole geometries;
462         *                    set to FALSE to only return Polygon (outer ring).
463         *
464         * traverseMultiGeometry: set to TRUE to return MG children, but never an MG itself;
465         *                        set to FALSE to return MGs and NOT their children.
466         */
467        ConstGeometryIterator(
468            const Geometry* geom,
469            bool            traversePolygonHoles  =true );
470
471        bool hasMore() const;
472        const Geometry* next();
473
474    private:
475        const Geometry* _next;
476        std::stack<const Geometry*> _stack;
477        bool _traverseMulti;
478        bool _traversePolyHoles;
479
480        void fetchNext();
481    };
482
483    typedef std::pair<osg::Vec3d, osg::Vec3d> Segment;
484
485    class OSGEARTHSYMBOLOGY_EXPORT ConstSegmentIterator
486    {
487    public:
488        ConstSegmentIterator( const Geometry* verts, bool forceClosedLoop =false );
489        bool hasMore() const { return !_done; }
490        Segment next();
491
492    private:
493        const Vec3dVector* _verts;
494        Vec3dVector::const_iterator _iter;
495        bool _done;
496        bool _closeLoop;
497    };
498
499    typedef std::vector<osg::ref_ptr<Geometry> > GeometryList;
500
501} } // namespace osgEarth::Symbology
502
503
504#endif // OSGEARTHSYMBOLOGY_GEOMETRY_H
505
506