Skip to content

Commit

Permalink
SceneAlgo : Add findAll() method
Browse files Browse the repository at this point in the history
  • Loading branch information
johnhaddon committed Aug 31, 2023
1 parent 5520aa2 commit a73c844
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 0 deletions.
1 change: 1 addition & 0 deletions Changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
API
---

- SceneAlgo : Added `findAll()` method, for finding all scene locations matching a predicate.
- ThreadState : Added `process()` method.
- Process : Added const overload for `handleException()` method. The non-const version will be removed in future.

Expand Down
10 changes: 10 additions & 0 deletions include/GafferScene/SceneAlgo.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ void filteredParallelTraverse( const ScenePlug *scene, const FilterPlug *filterP
template <class ThreadableFunctor>
void filteredParallelTraverse( const ScenePlug *scene, const IECore::PathMatcher &filter, ThreadableFunctor &f, const ScenePlug::ScenePath &root = ScenePlug::ScenePath() );

/// Searching
/// =========

/// Returns all the locations for which `predicate( scene, path )` returns `true`.
///
/// > Caution : The search is performed in parallel, so `predicate` must be safe to call
/// concurrently from multiple threads.
template<typename Predicate>
IECore::PathMatcher findAll( const ScenePlug *scene, Predicate &&predicate, const ScenePlug::ScenePath &root = ScenePlug::ScenePath() );

/// Globals
/// =======

Expand Down
25 changes: 25 additions & 0 deletions include/GafferScene/SceneAlgo.inl
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

#include "Gaffer/Context.h"

#include "tbb/enumerable_thread_specific.h"
#include "tbb/parallel_for.h"

namespace GafferScene
Expand Down Expand Up @@ -179,6 +180,30 @@ void filteredParallelTraverse( const ScenePlug *scene, const IECore::PathMatcher
parallelTraverse( scene, ff, root );
}

template<typename Predicate>
IECore::PathMatcher findAll( const ScenePlug *scene, Predicate &&predicate, const ScenePlug::ScenePath &root )
{
tbb::enumerable_thread_specific<IECore::PathMatcher> threadResults;

auto f = [&] ( const ScenePlug *scene, const ScenePlug::ScenePath &path ) {
if( predicate( scene, path ) )
{
threadResults.local().addPath( path );
}
return true;
};

parallelTraverse( scene, f, root );

return threadResults.combine(
[] ( const IECore::PathMatcher &a, const IECore::PathMatcher &b ) {
IECore::PathMatcher c = a;
c.addPaths( b );
return c;
}
);
}

} // namespace SceneAlgo

} // namespace GafferScene
34 changes: 34 additions & 0 deletions python/GafferSceneTest/SceneAlgoTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1829,6 +1829,40 @@ def testValidateName( self ) :
with self.assertRaises( RuntimeError ) :
GafferScene.SceneAlgo.validateName( badName )

def testFindAll( self ) :

plane = GafferScene.Plane()

planeFilter = GafferScene.PathFilter()
planeFilter["paths"].setValue( IECore.StringVectorData( [ "/plane" ] ) )

sphere = GafferScene.Sphere()

instancer = GafferScene.Instancer()
instancer["in"].setInput( plane["out"] )
instancer["prototypes"].setInput( sphere["out"] )
instancer["filter"].setInput( planeFilter["out"] )

self.assertEqual(
GafferScene.SceneAlgo.findAll(
instancer["out"],
lambda scene, path : scene["transform"].getValue().translation().x > 0
),
IECore.PathMatcher( [
"/plane/instances/sphere/1",
"/plane/instances/sphere/3",
] )
)

self.assertEqual(
GafferScene.SceneAlgo.findAll(
instancer["out"],
lambda scene, path : scene["transform"].getValue().translation().x > 0,
root = "/not/a/location"
),
IECore.PathMatcher()
)

def tearDown( self ) :

GafferSceneTest.SceneTestCase.tearDown( self )
Expand Down
17 changes: 17 additions & 0 deletions src/GafferSceneModule/SceneAlgoBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,20 @@ IECore::MurmurHash matchingPathsHashWrapper2( const IECore::PathMatcher &filter,
return SceneAlgo::matchingPathsHash( filter, &scene );
}

IECore::PathMatcher findAllWrapper( const ScenePlug &scene, object predicate, const ScenePlug::ScenePath &root )
{
IECorePython::ScopedGILRelease gilRelease;
return SceneAlgo::findAll(
&scene,
[&] ( ConstScenePlugPtr scene, const ScenePlug::ScenePath &path ) {
const std::string pathString = ScenePlug::pathToString( path );
IECorePython::ScopedGILLock gilLock;
return predicate( boost::const_pointer_cast<ScenePlug>( scene ), pathString );
},
root
);
}

Imath::V2f shutterWrapper( const IECore::CompoundObject &globals, const ScenePlug &scene )
{
IECorePython::ScopedGILRelease r;
Expand Down Expand Up @@ -319,6 +333,9 @@ void bindSceneAlgo()
def( "matchingPaths", &matchingPathsWrapper4 );
def( "matchingPathsHash", &matchingPathsHashWrapper1, ( arg( "filter" ), arg( "scene" ), arg( "root" ) = "/" ) );
def( "matchingPathsHash", &matchingPathsHashWrapper2, ( arg( "filter" ), arg( "scene" ) ) );

def( "findAll", &findAllWrapper, ( arg( "scene" ), arg( "predicate" ), arg( "root" ) = "/" ) );

def( "shutter", &shutterWrapper );
def( "setExists", &setExistsWrapper );
def(
Expand Down

0 comments on commit a73c844

Please sign in to comment.