/* -*-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 */ #pragma once #include #include #include #include #include #include #include #include #include namespace osgEarth { /** * Horizon operations (for a geocentric map). */ class OSGEARTH_EXPORT Horizon : public osg::Object { public: META_Object(osgEarth, Horizon); public: //! Construct a horizon using a default WGS84 ellipsoid model Horizon(); //! Construct a horizon providing the ellipsoid model Horizon(const Ellipsoid& ellipsoid); //! Construct a horizon from a spatial reference Horizon(const SpatialReference* srs); //! Copy Horizon(const Horizon& rhs, const osg::CopyOp& op = osg::CopyOp::DEEP_COPY_ALL); //! Ellipsoid model to use for occlusion testing void setEllipsoid(const Ellipsoid& ellipsoid); const Ellipsoid& getEllipsoid() const { return _em; } //! Minimum allowable height-above-ellipsoid to consider when doing visibility testing void setMinHAE(double meters); double getMinHAE() const { return _minHAE; } //! Eye position to use when testing for occlusion //! @return true if the value changed; false if it was the same bool setEye(const osg::Vec3d& eyeECEF, const osg::RefMatrix* proj =nullptr); const osg::Vec3d& getEye() const { return _eye; } //! Whether a point is potentially visible over the horizon. //! Specify an optional radius to test a sphere bool isVisible(const osg::Vec3d& point, double radius =0.0) const; //! Whether a bounding sphere is potentially visible over the horizon. inline bool isVisible(const osg::BoundingSphere& bs) const { return isVisible(bs.center(), bs.radius()); } //! Whether the horizon occludes a point/sphere. bool occludes(const osg::Vec3d& point, double radius =0.0) const { return !isVisible(point, radius); } //! Sets the output variable to the horizon plane plane with its //! normal pointing at the eye. bool getPlane(osg::Plane& out_plane) const; //! Caclulate distance from eye to visible horizon double getDistanceToVisibleHorizon() const; //! Radius of the ellipsoid under the eye double getRadius() const; protected: Ellipsoid _em; bool _valid = false; bool _orthographic = false; osg::Vec3d _eye; osg::Vec3d _eyeUnit; osg::Vec3d _VC; double _VCmag = 0; // distance from eye to center (scaled) double _VCmag2 = 0; // distance from eye to center squared (scaled) double _VHmag2 = 0; // distance from eye to horizon squared (scaled) double _coneCos = 0; // cosine of half-cone double _coneTan = 0; // tangent of half-cone osg::Vec3d _scale; osg::Vec3d _scaleInv; double _minVCmag = 0; double _minHAE = 0; }; /** * Cull callback that culls a node if it is occluded by the horizon. */ class OSGEARTH_EXPORT HorizonCullCallback : public osg::NodeCallback { public: /** Construct the callback with a default Horizon model. */ HorizonCullCallback(); //! Whether to cull by the center point only, or by the bounding sphere void setCullByCenterPointOnly(bool value) { _centerOnly = value; } bool getCullByCenterPointOnly() const { return _centerOnly; } //! Enable or disable the culler void setEnabled(bool value) { _enabled = value; } bool getEnabled() const { return _enabled; } //! Sets an alternate node whose bounds will be used to perform //! the culling test. By default, the culling test is performed //! against the node to which this callback is attached. void setProxyNode(osg::Node* node) { _proxy = node; } osg::observer_ptr& getProxyNode() { return _proxy; } const osg::observer_ptr& getProxyNode() const { return _proxy; } //! Custom ellipsoid to cull against. //! Normally this object will automatically detect the active ellipsoid //! from the NodeVisitor, but if you want to use a custom one you //! can do so here. void setEllipsoid(const Ellipsoid& em); const Ellipsoid& getEllipsoid() const { return _customEllipsoid; } public: // osg::NodeCallback void operator()(osg::Node* node, osg::NodeVisitor* nv) override; protected: bool isVisible(osg::Node* node, osg::NodeVisitor* nv); private: bool _centerOnly; bool _enabled; Ellipsoid _customEllipsoid; bool _customEllipsoidSet; osg::observer_ptr _proxy; }; }