DYT/Tool/OpenSceneGraph-3.6.5/include/osgEarth/NodeUtils
2024-12-25 07:49:36 +08:00

476 lines
15 KiB
C++

/* -*-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 <http://www.gnu.org/licenses/>
*/
#pragma once
#include <osgEarth/Common>
#include <osg/View>
#include <osg/PagedLOD>
#include <osgEarth/LoadableNode>
#include <osgEarth/PagedNode>
#include <osgGA/GUIActionAdapter>
#include <osgUtil/LineSegmentIntersector>
#include <osgEarth/Threading>
#include <set>
#include <vector>
namespace osgEarth { namespace Util
{
using namespace osgEarth;
/**
* Visitor that finds all the parental Camera Views, and calls an operator
* on each one.
*/
template<typename T>
class ViewVisitor : public osg::NodeVisitor, public T
{
public:
ViewVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_PARENTS) { }
virtual ~ViewVisitor() { }
void apply(osg::Camera& cam) {
osg::View* view = cam.getView();
if ( view ) this->operator()( view );
traverse(cam);
}
};
/**
* Visitor that locates a node by its type
*/
template<typename T>
class FindTopMostNodeOfTypeVisitor : public osg::NodeVisitor
{
public:
FindTopMostNodeOfTypeVisitor():
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_foundNode(0)
{}
void apply(osg::Node& node)
{
T* result = dynamic_cast<T*>(&node);
if (result)
{
_foundNode = result;
}
else
{
traverse(node);
}
}
T* _foundNode;
};
/**
* Collects all the nodes of type "T"
*/
template<typename T>
struct FindNodesVisitor : public osg::NodeVisitor
{
FindNodesVisitor() : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN) { }
void apply(osg::Node& node)
{
T* result = dynamic_cast<T*>( &node );
if ( result )
_results.push_back( result );
traverse(node);
}
std::vector<T*> _results;
};
template<typename T, typename FUNC>
struct NodeFunctorVisitor : public osg::NodeVisitor
{
NodeFunctorVisitor(const FUNC& func) : osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN), _func(func) { }
void apply(osg::Node& node) override
{
T* result = dynamic_cast<T*>( &node );
if ( result )
_func( result );
traverse(node);
}
FUNC _func;
};
template<typename T, typename FUNC>
inline void forEachNodeOfType(osg::Node* root, const FUNC& functor)
{
NodeFunctorVisitor<T, FUNC> visitor(functor);
if (root)
root->accept( visitor );
}
/**
* Searchs the scene graph downward starting at [node] and returns the first node found
* that matches the template parameter type.
*/
template<typename T>
T* findTopMostNodeOfType(osg::Node* node, unsigned traversalMask =~0)
{
if (!node) return 0;
FindTopMostNodeOfTypeVisitor<T> fnotv;
fnotv.setTraversalMode(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN);
fnotv.setTraversalMask(traversalMask);
node->accept(fnotv);
return fnotv._foundNode;
}
//! Synonym for findTopMostNodeOfType.
template<typename T>
T* findNode(osg::Node* node, unsigned traversalMask = ~0) {
return findTopMostNodeOfType<T>(node, traversalMask);
}
/**
* Searchs the scene graph upward starting at [node] and returns the first node found
* that matches the template parameter type.
*/
template<typename T>
T* findFirstParentOfType(osg::Node* node, unsigned traversalMask =~0)
{
if (!node) return 0;
FindTopMostNodeOfTypeVisitor<T> fnotv;
fnotv.setTraversalMode(osg::NodeVisitor::TRAVERSE_PARENTS);
fnotv.setTraversalMask(traversalMask);
node->accept(fnotv);
return fnotv._foundNode;
}
/**
* Searchs the scene graph starting at [node] and returns the first node found
* that matches the template parameter type. First searched upward, then downward.
*/
template<typename T>
T* findRelativeNodeOfType(osg::Node* node, unsigned traversalMask =~0)
{
if ( !node ) return 0;
T* result = findFirstParentOfType<T>( node, traversalMask );
if ( !result )
result = findTopMostNodeOfType<T>( node, traversalMask );
return result;
}
/** Find the top of the scene graph through parent 0 */
inline osg::Node* findTopOfGraph(osg::Node* node)
{
return node && node->getNumParents() > 0 ? findTopOfGraph(node->getParent(0)) : node;
}
/** Finds a typed node in a node visitor's node path */
template<typename T>
T* findInNodePath(osg::NodeVisitor& nv) {
for (osg::NodePath::iterator i = nv.getNodePath().begin(); i != nv.getNodePath().end(); ++i) {
T* node = dynamic_cast<T*>(*i);
if (node) return node;
}
return 0L;
}
/** Finds all the siblings of a node */
inline osg::NodeList findSiblings(osg::Node* node)
{
osg::NodeList output;
if (node && node->getNumParents() > 0)
{
auto parent = node->getParent(0);
for(unsigned i=0; i<parent->getNumChildren(); ++i)
if (parent->getChild(i) != node)
output.push_back(parent->getChild(i));
}
return output;
}
class FindNamedNodeVisitor : public osg::NodeVisitor
{
public:
FindNamedNodeVisitor(const std::string& name) :
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
_name(name)
{
setTraversalMask(~0);
}
virtual void apply(osg::Node& node)
{
if (node.getName() == _name)
{
_foundNodes.push_back(&node);
}
traverse(node);
}
typedef std::vector< osg::ref_ptr<osg::Node> > NodeList;
std::string _name;
NodeList _foundNodes;
};
inline osg::Node* findNamedNode(osg::Node* node, const std::string& name)
{
FindNamedNodeVisitor v(name);
node->accept(v);
if (!v._foundNodes.empty())
{
return v._foundNodes[0].get();
}
return 0;
}
/**
* Replace one group with another
*/
inline void replaceGroup( osg::Group* oldGroup, osg::Group* newGroup )
{
if ( oldGroup && newGroup && oldGroup->getNumParents() > 0 )
{
for(unsigned i=0; i<oldGroup->getNumChildren(); ++i)
{
newGroup->addChild( oldGroup->getChild(i) );
}
osg::Node::ParentList parents = oldGroup->getParents();
for(osg::Node::ParentList::iterator i = parents.begin(); i != parents.end(); ++i )
{
(*i)->replaceChild( oldGroup, newGroup );
}
}
}
/** Insert a group between a parent and its children. */
inline void insertGroup(osg::Group* newGroup, osg::Group* parent)
{
if (parent && newGroup)
{
for(unsigned i=0; i<parent->getNumChildren(); ++i)
{
newGroup->addChild( parent->getChild(i) );
}
parent->removeChildren(0, parent->getNumChildren());
parent->addChild( newGroup );
}
}
/** Insert a group above a node. */
inline void insertParent(osg::Group* newParent, osg::Node* existingChild)
{
if ( newParent && existingChild )
{
newParent->addChild(existingChild);
for (unsigned i = 0; i < existingChild->getNumParents(); ++i)
{
osg::Group* parent = existingChild->getParent(i);
if ( parent != newParent )
{
parent->removeChild( existingChild );
parent->addChild( newParent );
}
}
}
}
/** Remove a group from the middle of a scene graph */
inline void removeGroup(osg::Group* group)
{
if (group)
{
osg::ref_ptr<osg::Group> g = group;
while (g->getNumParents() > 0)
{
osg::Group* parent = group->getParent(group->getNumParents()-1);
for (unsigned c = 0; c < group->getNumChildren(); ++c)
{
parent->addChild(group->getChild(c));
}
parent->removeChild(group);
}
}
}
/**
* Remove all a group's children.
*/
inline void clearChildren( osg::Group* group )
{
if ( group )
group->removeChildren( 0, group->getNumChildren() );
}
/**
* OSG Group that keeps its children as observer_ptrs instead of ref_ptrs, and
* removes them when they deref.
*/
class OSGEARTH_EXPORT ObserverGroup : public osg::Group
{
public:
ObserverGroup();
virtual void traverse( osg::NodeVisitor& nv );
std::set<osg::Node*> _orphans;
};
/**
* Group that acts like a normal group but also notifies another
* object when a change occurs.
*/
template<typename T>
class NotifierGroup : public osg::Group
{
public:
NotifierGroup(T* listener) : _listener(listener) { }
virtual bool addChild( osg::Node* child ) {
bool ok = osg::Group::addChild(child);
if ( ok && _listener.valid() ) _listener->onGroupChanged(this);
return ok;
}
virtual bool insertChild( unsigned index, osg::Node* child ) {
bool ok = osg::Group::insertChild(index, child);
if ( ok && _listener.valid() ) _listener->onGroupChanged(this);
return ok;
}
virtual bool removeChild( osg::Node* child ) {
bool ok = osg::Group::removeChild( child );
if ( ok && _listener.valid() ) _listener->onGroupChanged(this);
return ok;
}
virtual bool replaceChild( osg::Node* origChild, osg::Node* newChild ) {
bool ok = osg::Group::replaceChild(origChild, newChild);
if ( ok && _listener.valid() ) _listener->onGroupChanged(this);
return ok;
}
protected:
virtual ~NotifierGroup() { }
osg::observer_ptr<T> _listener;
};
/**
* Adjusts a node's update traversal count by a delta.
* Only safe to call from the UPDATE thread
*/
#define ADJUST_UPDATE_TRAV_COUNT( NODE, DELTA ) \
{ \
unsigned oldCount = NODE ->getNumChildrenRequiringUpdateTraversal(); \
unsigned newCount = (unsigned)(((int)oldCount)+(DELTA)); \
if ( ((DELTA) < 0 && newCount < oldCount) || ((DELTA) >= 0 && newCount >= oldCount) ) { \
NODE ->setNumChildrenRequiringUpdateTraversal( newCount ); \
} else { \
OE_WARN << "**INTERNAL: ADJUST_UPDATE_TRAV_COUNT wrapped around" << std::endl; \
} \
}
/**
* Adjusts a node's event traversal count by a delta.
* Only safe to call from the main/event/update threads
*/
#define ADJUST_EVENT_TRAV_COUNT( NODE, DELTA ) \
{ \
unsigned oldCount = NODE ->getNumChildrenRequiringEventTraversal(); \
unsigned newCount = (unsigned)(((int)oldCount)+(DELTA)); \
if ( ((DELTA) < 0 && newCount < oldCount) || ((DELTA) >= 0 && newCount >= oldCount) ) { \
NODE ->setNumChildrenRequiringEventTraversal( newCount ); \
} else { \
OE_WARN << "**INTERNAL: ADJUST_EVENT_TRAV_COUNT wrapped around" << std::endl; \
} \
}
/**
* Enables auto unloading on any PagedNode2 in the scene graph
* This is useful if you've used the LoadDataVisitor to
* preload an area and you no longer care about it.
*/
struct OSGEARTH_EXPORT EnableAutoUnloadVisitor : public osg::NodeVisitor
{
EnableAutoUnloadVisitor();
void apply(osg::Node& node);
};
/**
* Preloads data within a list of bounding spheres so that the data is available without
* actually viewing it first.
* Once the visitor has been sent down a scene graph, you can check the isFullyLoaded
* property to determine if all of the data in that area has been loaded. If isFullyLoaded is false
* then send the visitor down again until isFullyLoaded returns true.
*/
struct OSGEARTH_EXPORT LoadDataVisitor : public osg::NodeVisitor
{
LoadDataVisitor();
bool getLoadHighestResolutionOnly() const;
void setLoadHighestResolutionOnly(bool value);
//! Whether all potential data in the areas are loaded
bool isFullyLoaded() const;
//! Resets isFullyLoaded so you can reuse the same visitor multiple times.
void reset();
bool intersects(osg::Node& node);
//! A list of bounding spheres in world coordinates to intersect the scene graph against.
std::vector<osg::BoundingSphered>& getAreasToLoad();
void apply(osg::Node& node);
void apply(LoadableNode& loadableNode);
void apply(osg::Transform& transform);
/**
* Most async nodes will require an update traversal to be called. If you calling this visitor outside
* of a normal frame loop you will need to call manualUpdate after you run the visitor in order to update the scene graph properly
*/
void manualUpdate();
inline void pushMatrix(osg::Matrix& matrix) { _matrixStack.push_back(matrix); }
inline void popMatrix() { _matrixStack.pop_back(); }
typedef std::vector<osg::Matrix> MatrixStack;
MatrixStack _matrixStack;
bool _fullyLoaded = true;
std::set < osg::ref_ptr < PagingManager> > _pagingManagers;
std::vector< osg::BoundingSphered > _areasToLoad;
bool _loadHighestResolutionOnly = false;
};
/**
* Loads async data within the given areas and sets the nodes to not expire.
*/
extern OSGEARTH_EXPORT void loadData(osg::Node* node, std::vector<osg::BoundingSphered>& areasToLoad);
} }