/* -*-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/> */ #pragma once #include <osgEarth/Common> #include <osgEarth/Profile> #include <osgEarth/Geometry> #include <osgEarth/Style> #include <osgEarth/GeoCommon> #include <osgEarth/SpatialReference> #include <osg/Array> #include <osg/Shape> #include <map> #include <list> #include <vector> namespace osgEarth { namespace Util { class FilterContext; class Session; } /** * Metadata and schema information for feature data. */ class OSGEARTH_EXPORT FeatureProfile : public osg::Referenced { public: //! Construct a non-tiled feature profile with an extent FeatureProfile(const GeoExtent& featuresExtent); //! Construct a TILED feature profile with a tiling schema FeatureProfile(const Profile* tilingProfile); //! Copy ctor FeatureProfile(const FeatureProfile& rhs); //! Spatial extents of the features data void setExtent(const GeoExtent& value) { _extent = value; } const GeoExtent& getExtent() const { return _extent; } //! Spatial reference system of feature data const SpatialReference* getSRS() const { return _extent.getSRS(); } //! Whether the feature data is pre-tiled bool isTiled() const; //! For tiled data, the tiling profile const osgEarth::Profile* getTilingProfile() const; void setTilingProfile( const osgEarth::Profile* profile ); //! For tiled data, the first tiling level of detail int getFirstLevel() const; void setFirstLevel(int firstLevel ); //! For tiled data, the last tiling level fo detail int getMaxLevel() const; void setMaxLevel(int maxLevel); //! Interpolation method for geodetic data optional<GeoInterpolation>& geoInterp() { return _geoInterp; } const optional<GeoInterpolation>& geoInterp() const { return _geoInterp; } protected: virtual ~FeatureProfile() { } osg::ref_ptr< const osgEarth::Profile > _tilingProfile; GeoExtent _extent; int _firstLevel; int _maxLevel; optional<GeoInterpolation> _geoInterp; }; struct AttributeValueUnion { std::string stringValue; double doubleValue; long long intValue; bool boolValue; std::vector<double> doubleArrayValue; bool set = false; }; enum AttributeType { ATTRTYPE_UNSPECIFIED, ATTRTYPE_STRING, ATTRTYPE_INT, ATTRTYPE_DOUBLE, ATTRTYPE_BOOL, ATTRTYPE_DOUBLEARRAY }; struct OSGEARTH_EXPORT AttributeValue { AttributeType type; AttributeValueUnion value; std::string getString() const; double getDouble(double defaultValue = 0.0) const; long long getInt(long long defaultValue = 0) const; bool getBool(bool defaultValue = false) const; const std::vector<double>& getDoubleArrayValue() const; }; using AttributeTable = vector_map<std::string, AttributeValue, ci_string_less>; using FeatureID = std::int64_t; // long long; using FeatureSchema = std::map<std::string, AttributeType>; class Feature; using FeatureList = std::vector<osg::ref_ptr<Feature>>; /** * Basic building block of vector feature data. */ class OSGEARTH_EXPORT Feature : public osg::Referenced // : public osg::Object { public: //! Construct a feature Feature(Geometry* geom, const SpatialReference* srs, const Style& style =Style(), FeatureID fid =0LL ); //! Construct a feature (copy) Feature(const Feature& rhs); //! Contruct a feature (move) Feature(Feature&& rhs); public: /** * The unique ID of this feature (unique relative to its provider) */ FeatureID getFID() const; /** * Set the FID of this feature. */ void setFID(FeatureID fid); /** * Gets the GeoExtent of this Feature */ GeoExtent getExtent() const; /** * The geometry in this feature. */ void setGeometry( Geometry* geom ); Geometry* getGeometry() { dirty(); return _geom.get(); } const Geometry* getGeometry() const { return _geom.get(); } /** * The spatial reference of the geometry in this feature. */ const SpatialReference* getSRS() const { return _srs.get(); } void setSRS( const SpatialReference* srs ); /** * Computes the bound of this feature in the specified SRS. */ bool getWorldBound( const SpatialReference* srs, osg::BoundingSphered& out_bound ) const; /** * Gets a polytope, in world coordinates (proj or ECEF) that bounds the * geographic extents covered by this feature. This is useful for roughly * intersecting the feature with the terrain graph. */ bool getWorldBoundingPolytope( const SpatialReference* srs, osg::Polytope& out_polytope ) const; /** * Gets a polytope, in world coordinates (proj or ECEF) that bounds the * world coordinates covered by the given bounding sphere. This is useful for roughly * intersecting features with the terrain graph. */ static bool getWorldBoundingPolytope( const osg::BoundingSphered& bs, const SpatialReference* srs, osg::Polytope& out_polytope ); /** * Calculates the extent of this feature. */ GeoExtent calculateExtent() const; const AttributeTable& getAttrs() const { return _attrs; } void set( const std::string& name, const std::string& value ); void set( const std::string& name, double value ); void set(const std::string& name, int value); void set( const std::string& name, long long value ); void set( const std::string& name, bool value ); void set( const std::string& name, const std::vector<double>& value ); void setSwap( const std::string& name, std::vector<double>& value ); void set( const std::string& name, const AttributeValue& value); /** Sets the attribute to NULL */ void setNull( const std::string& name ); void setNull( const std::string& name, AttributeType type ); void removeAttribute(const std::string& name); bool hasAttr( const std::string& name ) const; std::string getString( const std::string& name ) const; double getDouble( const std::string& name, double defaultValue =0.0 ) const; long long getInt( const std::string& name, long long defaultValue =0 ) const; bool getBool( const std::string& name, bool defaultValue =false ) const; const std::vector<double>* getDoubleArray( const std::string& name ) const; /** * Gets whether the attribute is set, meaning it is non-NULL */ bool isSet( const std::string& name ) const; /** Embedded style. */ optional<Style>& style() { return _style; } const optional<Style>& style() const { return _style; } /** Geodetic interpolation method. */ optional<GeoInterpolation>& geoInterp() { dirty(); return _geoInterp; } const optional<GeoInterpolation>& geoInterp() const { return _geoInterp; } /** populates the variables of an expression with attribute values and evals the expression. */ double eval(NumericExpression& expr, const FilterContext* context) const; double eval(NumericExpression& expr, Session* session) const; /** populates the variables of an expression with attribute values and evals the expression. */ const std::string& eval(StringExpression& expr, const FilterContext* context) const; const std::string& eval(StringExpression& expr, Session* session) const; public: /** Gets a GeoJSON representation of this Feature */ std::string getGeoJSON() const; /** Gets a FeatureList as a GeoJSON FeatureCollection */ static std::string featuresToGeoJSON(const FeatureList& features); public: /** * Transforms this Feature to the given SpatialReference */ void transform( const SpatialReference* srs ); /** * Splits this feature into multiple features if it is a geodetic feature and cross the date line. */ void splitAcrossDateLine(FeatureList& splitFeatures); protected: Feature(); Feature( FeatureID fid ); virtual ~Feature(); FeatureID _fid; osg::ref_ptr<Geometry> _geom; osg::ref_ptr<const SpatialReference> _srs; AttributeTable _attrs; optional<Style> _style; optional<GeoInterpolation> _geoInterp; GeoExtent _cachedExtent; void dirty(); }; } // namespace osgEarth