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