/* -*-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. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see */ #ifndef OSGEARTH_CALLOUTS_H #define OSGEARTH_CALLOUTS_H 1 #include #include namespace osgUtil { class CullVisitor; } namespace osgEarth { class LineDrawable; } #define USE_RTREE #ifdef USE_RTREE #include "rtree.h" #endif namespace osgEarth { namespace Contrib { class CalloutManager; class OSGEARTH_EXPORT Callout : public osgEarth::Text { public: Callout(CalloutManager* cm); // unique ID and sorting string. void setUID(const std::string& value) { _uid = value; } const std::string& getUID() const { return _uid; } // override from osg::Node void accept(osg::NodeVisitor& nv); private: CalloutManager* _cm; std::string _uid; }; class OSGEARTH_EXPORT CalloutManager : public osg::Drawable { public: CalloutManager(); //! Reset the label positions based on the current view void reset(); //! Whether to draw labels that are overlapping. void setDrawObscuredItems(bool value); bool getDrawObscuredItems() const; //! Whether to reset the label positioning when the view changes void setResetWhenViewChanges(bool value); //! Whether decluttering should be aggressive, thereby sorting //! faster but using more resources void setAggressiveSorting(bool value); // from osg::Drawable void drawImplementation(osg::RenderInfo& ri) const; protected: virtual ~CalloutManager() { } private: //! Callout calls this to push itself onto the rendering queue void push(Callout*, osgUtil::CullVisitor&); friend class Callout; struct BBox { BBox() { } BBox(const osg::BoundingBox& bbox); bool overlaps(const BBox& rhs) const; double overlap(const BBox& rhs) const; osg::Vec2d LL, UR; }; struct CalloutRecord { CalloutRecord(); osgEarth::Text* _node; // node to render osg::ref_ptr _matrix; unsigned _frame; // frame number of last update BBox _textBB; BBox _vpBB; BBox _leaderBB; osg::Vec3d _offsetVector; // offset in pixels at which to place the label osg::Vec3d _bestVector; unsigned _leaderLineIndex; // index of leader line vertex in line drawable bool _conflicted; bool _moveRequested; int _moveAttempts; float _overlap; bool operator < (const CalloutRecord& rhs) const; void move(float dir); void realign(); void setAlpha(float a); }; void sort(osg::NodeVisitor& nv); void handleOverlap(CalloutRecord* lhs, const BBox& bb); bool isStuck(const CalloutRecord*) const; #ifdef USE_RTREE typedef RTree SpatialIndex; #else typedef std::vector SpatialIndex; #endif typedef std::map Callouts; typedef std::pair CalloutTuple; Callouts _callouts; LineDrawable* _leaders; mutable bool _leadersDirty; osg::Vec4f _leaderColor; mutable SpatialIndex _labelIndex; mutable SpatialIndex _leaderIndex; double _leaderLen; Callouts::iterator _walker; double _maxOverlap; int _maxMoveAttempts; bool _drawConflictedRecords; bool _resetWhenViewChanges; bool _declutterIncrementally; osg::Matrix _vpm; bool _vpmChanged; unsigned _movesThisFrame; struct SortCallback : public osg::NodeCallback { SortCallback(CalloutManager* cm); void operator()(osg::Node* node, osg::NodeVisitor* nv); CalloutManager* _cm; }; friend struct SortCallback; }; } } #endif // OSGEARTH_CALLOUTS_H