def filter_declarations(self): code_generator_t.filter_declarations(self) # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # exclude solve() methods that take a "const PlannerTerminationCondition &" # as first argument; only keep the solve() that just takes a double argument self.ompl_ns.member_functions('solve', arg_types=['::ompl::base::PlannerTerminationCondition const &']).exclude() # Py++ seems to get confused by virtual methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, are not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. # do this for all planners for planner in ['BallTreeRRTstar', 'RRTstar']: self.ompl_ns.class_(planner).add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner) self.ompl_ns.class_(planner).add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &%s_wrapper::default_checkValidity )""" % planner)
def filter_declarations(self): code_generator_t.filter_declarations(self) # rename STL vectors of certain types self.std_ns.class_('vector< unsigned long >').include() self.std_ns.class_('vector< unsigned long >').rename('vectorSizeT') # not needed; causes problems when compiling in C++11 mode #self.std_ns.class_('vector< bool >').include() #self.std_ns.class_('vector< bool >').rename('vectorBool') self.std_ns.class_('vector< int >').include() self.std_ns.class_('vector< int >').rename('vectorInt') self.std_ns.class_('vector< double >').include() self.std_ns.class_('vector< double >').rename('vectorDouble') self.std_ns.class_('vector< unsigned int >').include() self.std_ns.class_('vector< unsigned int >').rename('vectorUint') self.std_ns.class_('vector< std::string >').include() self.std_ns.class_('vector< std::string >').rename('vectorString') self.std_ns.class_('vector< std::vector<int> >').include() self.std_ns.class_('vector< std::vector<int> >').rename('vectorVectorInt') self.std_ns.class_('vector< std::vector<unsigned int> >').include() self.std_ns.class_('vector< std::vector<unsigned int> >').rename('vectorVectorUint') self.std_ns.class_('vector< std::vector<double> >').include() self.std_ns.class_('vector< std::vector<double> >').rename('vectorVectorDouble') self.std_ns.class_('vector< std::map<std::string, std::string > >').include() self.std_ns.class_('vector< std::map<std::string, std::string > >').rename('vectorMapStringToString') self.std_ns.class_('map<std::string, std::string >').include() self.std_ns.class_('map<std::string, std::string >').rename('mapStringToString') self.std_ns.class_('vector< ompl::PPM::Color >').rename('vectorPPMColor') try: # Exclude the ProlateHyperspheroid Class which needs Eigen, and the associated member functions in the RNG self.ompl_ns.class_('ProlateHyperspheroid').exclude() self.ompl_ns.class_('RNG').member_functions('uniformProlateHyperspheroidSurface').exclude() self.ompl_ns.class_('RNG').member_functions('uniformProlateHyperspheroid').exclude() except: pass
def filter_declarations(self): code_generator_t.filter_declarations(self) # rename STL vectors of certain types self.std_ns.class_('vector< unsigned long >').include() self.std_ns.class_('vector< unsigned long >').rename('vectorSizeT') # not needed; causes problems when compiling in C++11 mode #self.std_ns.class_('vector< bool >').include() #self.std_ns.class_('vector< bool >').rename('vectorBool') self.std_ns.class_('vector< int >').include() self.std_ns.class_('vector< int >').rename('vectorInt') self.std_ns.class_('vector< double >').include() self.std_ns.class_('vector< double >').rename('vectorDouble') self.std_ns.class_('vector< unsigned int >').include() self.std_ns.class_('vector< unsigned int >').rename('vectorUint') self.std_ns.class_('vector< std::string >').include() self.std_ns.class_('vector< std::string >').rename('vectorString') self.std_ns.class_('vector< std::vector<int> >').include() self.std_ns.class_('vector< std::vector<int> >').rename('vectorVectorInt') self.std_ns.class_('vector< std::vector<unsigned int> >').include() self.std_ns.class_('vector< std::vector<unsigned int> >').rename('vectorVectorUint') self.std_ns.class_('vector< std::vector<double> >').include() self.std_ns.class_('vector< std::vector<double> >').rename('vectorVectorDouble') self.std_ns.class_('vector< std::map<std::string, std::string > >').include() self.std_ns.class_('vector< std::map<std::string, std::string > >').rename('vectorMapStringToString') self.std_ns.class_('map<std::string, std::string >').include() self.std_ns.class_('map<std::string, std::string >').rename('mapStringToString') self.std_ns.class_('vector< ompl::PPM::Color >').rename('vectorPPMColor') try: # Exclude the ProlateHyperspheroid Class which needs Eigen, and the associated member functions in the RNG self.ompl_ns.class_('ProlateHyperspheroid').exclude() self.ompl_ns.class_('RNG').member_functions('uniformProlateHyperspheroidSurface').exclude() self.ompl_ns.class_('RNG').member_functions('uniformProlateHyperspheroid').exclude() except: pass
def filter_declarations(self): code_generator_t.filter_declarations(self) # rename STL vectors of certain types self.std_ns.class_('vector< unsigned long >').include() self.std_ns.class_('vector< unsigned long >').rename('vectorSizeT') # not needed; causes problems when compiling in C++11 mode #self.std_ns.class_('vector< bool >').include() #self.std_ns.class_('vector< bool >').rename('vectorBool') self.std_ns.class_('vector< int >').include() self.std_ns.class_('vector< int >').rename('vectorInt') self.std_ns.class_('vector< double >').include() self.std_ns.class_('vector< double >').rename('vectorDouble') self.std_ns.class_('vector< unsigned int >').include() self.std_ns.class_('vector< unsigned int >').rename('vectorUint') self.std_ns.class_('vector< std::string >').include() self.std_ns.class_('vector< std::string >').rename('vectorString') self.std_ns.class_('vector< std::vector<int> >').include() self.std_ns.class_('vector< std::vector<int> >').rename('vectorVectorInt') self.std_ns.class_('vector< std::vector<unsigned int> >').include() self.std_ns.class_('vector< std::vector<unsigned int> >').rename('vectorVectorUint') self.std_ns.class_('vector< std::vector<double> >').include() self.std_ns.class_('vector< std::vector<double> >').rename('vectorVectorDouble') self.std_ns.class_('vector< std::map<std::string, std::string > >').include() self.std_ns.class_('vector< std::map<std::string, std::string > >').rename('vectorMapStringToString') self.std_ns.class_('map<std::string, std::string >').include() self.std_ns.class_('map<std::string, std::string >').rename('mapStringToString')
def filter_declarations(self): code_generator_t.filter_declarations(self) # rename STL vectors/maps of certain types self.std_ns.class_('vector< ompl::tools::Benchmark::PlannerExperiment >').rename( 'vectorPlannerExperiment') self.std_ns.class_('vector< std::vector< std::map<std::string, std::string> > >').rename( 'vectorRunProgressData') # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) benchmark_cls = self.ompl_ns.class_('Benchmark') self.replace_member_function(benchmark_cls.member_function('benchmark')) for constructor in benchmark_cls.constructors(arg_types=[None, "::std::string const &"]): constructor.add_transformation(FT.input(1)) # don't want to export iostream benchmark_cls.member_function('saveResultsToStream').exclude() self.ompl_ns.member_functions('addPlannerAllocator').exclude() self.replace_member_functions(benchmark_cls.member_functions( lambda method: method.name.startswith('set') and method.name.endswith('Event'))) benchmark_cls.add_registration_code( 'def("addPlannerAllocator", &ompl::tools::Benchmark::addPlannerAllocator)') self.ompl_ns.class_('OptimizePlan').add_registration_code( 'def("addPlannerAllocator", &ompl::tools::OptimizePlan::addPlannerAllocator)') self.add_function_wrapper('void(const ompl::base::PlannerPtr)', \ 'PreSetupEvent', 'Pre-setup event') self.add_function_wrapper( 'void(ompl::base::PlannerPtr, ompl::tools::Benchmark::RunProperties&)', 'PostSetupEvent', 'Post-setup event') benchmark_cls.class_('Request').no_init = False
def filter_declarations(self): code_generator_t.filter_declarations(self) # Py++/pygccxml generates the wrong code for scoped enums (enum class AppType), # so manually generate the right code self.mb.enum('::ompl::app::AppType').exclude() self.mb.add_registration_code("""bp::enum_< ompl::app::AppType>("AppType") .value("GEOMETRIC", ompl::app::AppType::GEOMETRIC) .value("CONTROL", ompl::app::AppType::CONTROL) .export_values() ;""") self.mb.class_('::ompl::app::AppBase< ompl::app::AppType::GEOMETRIC >').rename('AppBaseGeometric') self.mb.class_('::ompl::app::AppBase< ompl::app::AppType::CONTROL>').rename('AppBaseControl') self.mb.class_('::ompl::app::AppTypeSelector< ompl::app::AppType::GEOMETRIC >').rename('AppTypeGeometric') self.mb.class_('::ompl::app::AppTypeSelector< ompl::app::AppType::CONTROL >').rename('AppTypeControl') # The virtual functions "solve" and "clear" from SimpleSetup are not redefined # in these derived classes, and for some reason Py++ doesn't export them # (even though it does generate some wrapper code for them) for cls in ['SE2RigidBodyPlanning', 'SE3RigidBodyPlanning', 'SE2MultiRigidBodyPlanning', 'SE3MultiRigidBodyPlanning', 'GSE2RigidBodyPlanning', 'GSE3RigidBodyPlanning']: self.ompl_ns.class_(cls).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::app::%s::*)( double ))(&::ompl::app::%s::solve), (bp::arg("solveTime")) )""" % (cls, cls)) self.ompl_ns.class_(cls).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::app::%s::*)( const ompl::base::PlannerTerminationCondition& ))(&::ompl::app::%s::solve), (bp::arg("ptc")) )""" % (cls,cls)) self.ompl_ns.class_(cls).add_registration_code( 'def("clear", &%s_wrapper::clear)' % cls) self.ompl_ns.class_(cls).add_registration_code( 'def("getStateSpace", &::ompl::geometric::SimpleSetup::getStateSpace, bp::return_value_policy< bp::copy_const_reference >())') # work around bug in py++/pygccxml parsing of a templated constructor try: self.ompl_ns.class_(cls).constructor(arg_types=["::ompl::app::SE2RigidBodyPlanning"]).exclude() except declaration_not_found_t: pass for cls in ['KinematicCarPlanning', 'GKinematicCarPlanning', 'DynamicCarPlanning', 'GDynamicCarPlanning', 'BlimpPlanning', 'GBlimpPlanning', 'QuadrotorPlanning', 'GQuadrotorPlanning']: self.ompl_ns.class_(cls).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::app::%s::*)( double ))(&::ompl::app::%s::solve), (bp::arg("solveTime")) )""" % (cls, cls)) self.ompl_ns.class_(cls).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::app::%s::*)( const ompl::base::PlannerTerminationCondition& ))(&::ompl::app::%s::solve), (bp::arg("ptc")) )""" % (cls,cls)) self.ompl_ns.class_(cls).add_registration_code( 'def("clear", &%s_wrapper::clear)' % cls) self.ompl_ns.class_(cls).add_registration_code( 'def("getStateSpace", &::ompl::control::SimpleSetup::getStateSpace, bp::return_value_policy< bp::copy_const_reference >())') # workaround for internal compiler error in Xcode 4.3 (already fixed in MacPorts clang-3.1) rb = self.ompl_ns.class_('RigidBodyGeometry') rb.member_function('setEnvironmentMesh').exclude() rb.add_registration_code('def("setEnvironmentMesh",&::ompl::app::RigidBodyGeometry::setEnvironmentMesh)') rb.member_function('addEnvironmentMesh').exclude() rb.add_registration_code('def("addEnvironmentMesh",&::ompl::app::RigidBodyGeometry::addEnvironmentMesh)') rb.member_function('setRobotMesh').exclude() rb.add_registration_code('def("setRobotMesh",&::ompl::app::RigidBodyGeometry::setRobotMesh)') rb.member_function('addRobotMesh').exclude() rb.add_registration_code('def("addRobotMesh",&::ompl::app::RigidBodyGeometry::addRobotMesh)') rb.member_function('setStateValidityCheckerType').exclude() rb.add_registration_code('def("setStateValidityCheckerType",&::ompl::app::RigidBodyGeometry::setStateValidityCheckerType)')
def filter_declarations(self): code_generator_t.filter_declarations(self) # rename STL vectors/maps of certain types self.std_ns.class_( 'vector< ompl::tools::Benchmark::PlannerExperiment >').rename( 'vectorPlannerExperiment') self.std_ns.class_( 'vector< std::vector< std::map<std::string, std::string> > >' ).rename('vectorRunProgressData') # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) benchmark_cls = self.ompl_ns.class_('Benchmark') self.replace_member_function( benchmark_cls.member_function('benchmark')) # next five statements take care of weird error in default value for name argument in constructor benchmark_cls.constructors().exclude() benchmark_cls.add_registration_code( 'def(bp::init< ompl::geometric::SimpleSetup &, bp::optional< std::string const & > >(( bp::arg("setup"), bp::arg("name")=std::basic_string<char, std::char_traits<char>, std::allocator<char> >() )) )' ) benchmark_cls.add_wrapper_code( """Benchmark_wrapper(::ompl::geometric::SimpleSetup & setup, const ::std::string & name=std::string() ) : ompl::tools::Benchmark( boost::ref(setup), name ) , bp::wrapper< ompl::tools::Benchmark >(){}""") benchmark_cls.add_registration_code( 'def(bp::init< ompl::control::SimpleSetup &, bp::optional< std::string const & > >(( bp::arg("setup"), bp::arg("name")=std::basic_string<char, std::char_traits<char>, std::allocator<char> >() )) )' ) benchmark_cls.add_wrapper_code( """Benchmark_wrapper(::ompl::control::SimpleSetup & setup, const ::std::string & name=std::string() ) : ompl::tools::Benchmark( boost::ref(setup), name ) , bp::wrapper< ompl::tools::Benchmark >(){}""") # don't want to export iostream benchmark_cls.member_function('saveResultsToStream').exclude() # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('addPlannerAllocator').exclude() benchmark_cls.member_functions(lambda method: method.name.startswith( 'set') and method.name.endswith('Event')).exclude() benchmark_cls.add_registration_code( 'def("addPlannerAllocator", &ompl::tools::Benchmark::addPlannerAllocator)' ) self.ompl_ns.class_('OptimizePlan').add_registration_code( 'def("addPlannerAllocator", &ompl::tools::OptimizePlan::addPlannerAllocator)' ) benchmark_cls.add_registration_code( 'def("setPlannerSwitchEvent", &ompl::tools::Benchmark::setPlannerSwitchEvent)' ) benchmark_cls.add_registration_code( 'def("setPreRunEvent", &ompl::tools::Benchmark::setPreRunEvent)') benchmark_cls.add_registration_code( 'def("setPostRunEvent", &ompl::tools::Benchmark::setPostRunEvent)') self.add_boost_function('void(const ompl::base::PlannerPtr&)', 'PreSetupEvent', 'Pre-setup event') self.add_boost_function( 'void(const ompl::base::PlannerPtr&, ompl::tools::Benchmark::RunProperties&)', 'PostSetupEvent', 'Post-setup event') benchmark_cls.class_('Request').no_init = False
def filter_declarations(self): code_generator_t.filter_declarations(self) # Py++/pygccxml generates the wrong code for scoped enums (enum class AppType), # so manually generate the right code self.mb.enum('::ompl::app::AppType').exclude() self.mb.add_registration_code("""bp::enum_< ompl::app::AppType>("AppType") .value("GEOMETRIC", ompl::app::AppType::GEOMETRIC) .value("CONTROL", ompl::app::AppType::CONTROL) .export_values() ;""") self.mb.class_('::ompl::app::AppBase< ompl::app::AppType::GEOMETRIC >').rename('AppBaseGeometric') self.mb.class_('::ompl::app::AppBase< ompl::app::AppType::CONTROL>').rename('AppBaseControl') self.mb.class_('::ompl::app::AppTypeSelector< ompl::app::AppType::GEOMETRIC >').rename('AppTypeGeometric') self.mb.class_('::ompl::app::AppTypeSelector< ompl::app::AppType::CONTROL >').rename('AppTypeControl') # The virtual functions "solve" and "clear" from SimpleSetup are not redefined # in these derived classes, and for some reason Py++ doesn't export them # (even though it does generate some wrapper code for them) for cls in ['SE2RigidBodyPlanning', 'SE3RigidBodyPlanning', 'SE2MultiRigidBodyPlanning', 'SE3MultiRigidBodyPlanning', 'GSE2RigidBodyPlanning', 'GSE3RigidBodyPlanning']: self.ompl_ns.class_(cls).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::app::%s::*)( double ))(&::ompl::app::%s::solve), (bp::arg("solveTime")) )""" % (cls, cls)) self.ompl_ns.class_(cls).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::app::%s::*)( const ompl::base::PlannerTerminationCondition& ))(&::ompl::app::%s::solve), (bp::arg("ptc")) )""" % (cls,cls)) self.ompl_ns.class_(cls).add_registration_code( 'def("clear", &%s_wrapper::clear)' % cls) self.ompl_ns.class_(cls).add_registration_code( 'def("getStateSpace", &::ompl::geometric::SimpleSetup::getStateSpace, bp::return_value_policy< bp::copy_const_reference >())') for cls in ['KinematicCarPlanning', 'GKinematicCarPlanning', 'DynamicCarPlanning', 'GDynamicCarPlanning', 'BlimpPlanning', 'GBlimpPlanning', 'QuadrotorPlanning', 'GQuadrotorPlanning']: self.ompl_ns.class_(cls).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::app::%s::*)( double ))(&::ompl::app::%s::solve), (bp::arg("solveTime")) )""" % (cls, cls)) self.ompl_ns.class_(cls).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::app::%s::*)( const ompl::base::PlannerTerminationCondition& ))(&::ompl::app::%s::solve), (bp::arg("ptc")) )""" % (cls,cls)) self.ompl_ns.class_(cls).add_registration_code( 'def("clear", &%s_wrapper::clear)' % cls) self.ompl_ns.class_(cls).add_registration_code( 'def("getStateSpace", &::ompl::control::SimpleSetup::getStateSpace, bp::return_value_policy< bp::copy_const_reference >())') # workaround for internal compiler error in Xcode 4.3 (already fixed in MacPorts clang-3.1) rb = self.ompl_ns.class_('RigidBodyGeometry') rb.member_function('setEnvironmentMesh').exclude() rb.add_registration_code('def("setEnvironmentMesh",&::ompl::app::RigidBodyGeometry::setEnvironmentMesh)') rb.member_function('addEnvironmentMesh').exclude() rb.add_registration_code('def("addEnvironmentMesh",&::ompl::app::RigidBodyGeometry::addEnvironmentMesh)') rb.member_function('setRobotMesh').exclude() rb.add_registration_code('def("setRobotMesh",&::ompl::app::RigidBodyGeometry::setRobotMesh)') rb.member_function('addRobotMesh').exclude() rb.add_registration_code('def("addRobotMesh",&::ompl::app::RigidBodyGeometry::addRobotMesh)') rb.member_function('setStateValidityCheckerType').exclude() rb.add_registration_code('def("setStateValidityCheckerType",&::ompl::app::RigidBodyGeometry::setStateValidityCheckerType)')
def filter_declarations(self): code_generator_t.filter_declarations(self) # rename STL vectors/maps of certain types self.std_ns.class_('vector< ompl::tools::Benchmark::PlannerExperiment >').rename('vectorPlannerExperiment') self.std_ns.class_('vector< std::vector< std::map<std::string, std::string> > >').rename('vectorRunProgressData') # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) benchmark_cls = self.ompl_ns.class_('Benchmark') self.replace_member_function(benchmark_cls.member_function('benchmark')) # next five statements take care of weird error in default value for name argument in constructor benchmark_cls.constructors().exclude() benchmark_cls.add_registration_code( 'def(bp::init< ompl::geometric::SimpleSetup &, bp::optional< std::string const & > >(( bp::arg("setup"), bp::arg("name")=std::basic_string<char, std::char_traits<char>, std::allocator<char> >() )) )') benchmark_cls.add_wrapper_code( """Benchmark_wrapper(::ompl::geometric::SimpleSetup & setup, const ::std::string & name=std::string() ) : ompl::tools::Benchmark( boost::ref(setup), name ) , bp::wrapper< ompl::tools::Benchmark >(){}""") benchmark_cls.add_registration_code( 'def(bp::init< ompl::control::SimpleSetup &, bp::optional< std::string const & > >(( bp::arg("setup"), bp::arg("name")=std::basic_string<char, std::char_traits<char>, std::allocator<char> >() )) )') benchmark_cls.add_wrapper_code( """Benchmark_wrapper(::ompl::control::SimpleSetup & setup, const ::std::string & name=std::string() ) : ompl::tools::Benchmark( boost::ref(setup), name ) , bp::wrapper< ompl::tools::Benchmark >(){}""") # don't want to export iostream benchmark_cls.member_function('saveResultsToStream').exclude() # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('addPlannerAllocator').exclude() benchmark_cls.member_functions(lambda method: method.name.startswith('set') and method.name.endswith('Event')).exclude() benchmark_cls.add_registration_code( 'def("addPlannerAllocator", &ompl::tools::Benchmark::addPlannerAllocator)') self.ompl_ns.class_('OptimizePlan').add_registration_code( 'def("addPlannerAllocator", &ompl::tools::OptimizePlan::addPlannerAllocator)') benchmark_cls.add_registration_code( 'def("setPlannerSwitchEvent", &ompl::tools::Benchmark::setPlannerSwitchEvent)') benchmark_cls.add_registration_code( 'def("setPreRunEvent", &ompl::tools::Benchmark::setPreRunEvent)') benchmark_cls.add_registration_code( 'def("setPostRunEvent", &ompl::tools::Benchmark::setPostRunEvent)') self.add_boost_function('void(const ompl::base::PlannerPtr&)', 'PreSetupEvent', 'Pre-setup event') self.add_boost_function('void(const ompl::base::PlannerPtr&, ompl::tools::Benchmark::RunProperties&)', 'PostSetupEvent', 'Post-setup event') benchmark_cls.class_('Request').no_init = False
def filter_declarations(self): code_generator_t.filter_declarations(self) # rename STL vectors of certain types self.std_ns.class_('vector< ompl::control::Control* >').rename('vectorControlPtr') # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # force ControlSpace::allocControl to be exported. # (not sure why this is necessary) allocControlFn = self.ompl_ns.class_('ControlSpace').member_function('allocControl') allocControlFn.include() allocControlFn.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) # don't export components which is of type Control** self.ompl_ns.class_('CompoundControl').variable('components').exclude() # don't export some internal data structure self.ompl_ns.class_('OrderCellsByImportance').exclude() # don't expose this utility function self.ompl_ns.member_functions('getValueAddressAtIndex').exclude() self.ompl_ns.class_('KPIECE1').member_functions('freeGridMotions').exclude() # add array indexing to the RealVectorState self.add_array_access(self.ompl_ns.class_('RealVectorControlSpace').class_('ControlType')) # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # make settings printable self.replace_member_functions(self.ompl_ns.member_functions('printSettings')) # make controls printable self.replace_member_functions(self.ompl_ns.member_functions('printControl')) # print paths as matrices self.replace_member_functions(self.ompl_ns.member_functions('printAsMatrix')) try: # export ODESolver-derived classes that use Boost.OdeInt for odesolver in ['ODEBasicSolver', 'ODEErrorSolver', 'ODEAdaptiveSolver']: self.ompl_ns.class_(lambda cls: cls.name.startswith(odesolver)).rename(odesolver) # Somehow, Py++ changes the type of the ODE's first argument. Weird... self.add_boost_function('void(ompl::control::ODESolver::StateType, const ompl::control::Control*, ompl::control::ODESolver::StateType &)', 'ODE','Ordinary differential equation') # workaround for default argument for PostPropagationEvent self.replace_member_function(self.ompl_ns.class_('ODESolver').member_function( 'getStatePropagator')) except declarations.matcher.declaration_not_found_t: # not available for boost < 1.44, so ignore this pass # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # export pure virtual member functions, otherwise code doesn't compile syclop = self.ompl_ns.class_('Syclop') syclop.add_wrapper_code(""" virtual ompl::control::Syclop::Motion* addRoot(const ompl::base::State* s) { bp::override func_addRoot = this->get_override("addRoot"); return func_addRoot(s); } virtual void selectAndExtend(ompl::control::Syclop::Region& region, std::vector<ompl::control::Syclop::Motion*>& newMotions) { bp::override func_selectAndExtend = this->get_override("selectAndExtend"); func_selectAndExtend(region, newMotions); }""") # omit ompl::control::Syclop::Defaults nested subclass, otherwise # code doesn't compile (don't know why) syclop.class_('Defaults').exclude() # add wrappers for boost::function types self.add_boost_function('ompl::control::ControlSamplerPtr(const ompl::control::ControlSpace*)', 'ControlSamplerAllocator', 'Control sampler allocator') self.add_boost_function('ompl::control::DirectedControlSamplerPtr(const ompl::control::SpaceInformation*)', 'DirectedControlSamplerAllocator','Directed control sampler allocator') # same type as StatePropagatorFn, so no need to export this. Instead, we just define a type alias in the python module. #self.add_boost_function('void(const ompl::base::State*, const ompl::control::Control*, const double, ompl::base::State*)', # 'PostPropagationEvent','Post-propagation event') self.add_boost_function('void(const ompl::base::State*, const ompl::control::Control*, const double, ompl::base::State*)', 'StatePropagatorFn','State propagator function') self.add_boost_function('double(int, int)','EdgeCostFactorFn', 'Syclop edge cost factor function') self.add_boost_function('void(int, int, std::vector<int>&)','LeadComputeFn', 'Syclop lead compute function') # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('control').class_('SimpleSetup').add_registration_code( 'def("setPlannerAllocator", &ompl::control::SimpleSetup::setPlannerAllocator)') self.ompl_ns.namespace('control').class_('SimpleSetup').add_registration_code( 'def("getPlannerAllocator", &ompl::control::SimpleSetup::getPlannerAllocator, bp::return_value_policy< bp::copy_const_reference >())') # Do this for all classes that exist with the same name in another namespace # (We also do it for all planners; see below) for cls in ['SimpleSetup', 'SpaceInformation']: self.ompl_ns.namespace('control').class_(cls).wrapper_alias = 'Control%s_wrapper' % cls # Py++ seems to get confused by some methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. # do this for all planners for planner in ['KPIECE1', 'PDST', 'RRT', 'EST', 'Syclop', 'SyclopEST', 'SyclopRRT']: # many planners exist with the same name in another namespace self.ompl_ns.namespace('control').class_(planner).wrapper_alias = 'Control%s_wrapper' % planner self.ompl_ns.class_(planner).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::base::Planner::*)( double ))(&::ompl::base::Planner::solve), (bp::arg("solveTime")) )""") self.ompl_ns.class_(planner).add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &Control%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner) self.ompl_ns.class_(planner).add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &Control%s_wrapper::default_checkValidity )""" % planner)
def filter_declarations(self): code_generator_t.filter_declarations(self) # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # print paths as matrices self.replace_member_functions(self.ompl_ns.member_functions('printAsMatrix')) # print debug info self.replace_member_functions(self.ompl_ns.member_functions('printDebug')) self.ompl_ns.member_functions('freeGridMotions').exclude() self.ompl_ns.class_('PRM').member_functions('maybeConstructSolution').exclude() self.ompl_ns.class_('PRM').member_functions('growRoadmap', function=declarations.access_type_matcher_t('protected')).exclude() self.ompl_ns.class_('PRM').member_functions('expandRoadmap', function=declarations.access_type_matcher_t('protected')).exclude() # don't export some internal data structure self.ompl_ns.classes('OrderCellsByImportance').exclude() # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # add wrappers for boost::function types self.add_boost_function('unsigned int()', 'NumNeighborsFn', 'Number of neighbors function') # self.add_boost_function('std::vector<ompl::geometric::PRM::Vertex>&(const ompl::geometric::PRM::Vertex)', # 'ConnectionStrategy', 'Connection strategy') self.add_boost_function('bool(const ompl::geometric::PRM::Vertex&, const ompl::geometric::PRM::Vertex&)', 'ConnectionFilter', 'Connection filter') # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("setPlannerAllocator", &ompl::geometric::SimpleSetup::setPlannerAllocator)') self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("getPlannerAllocator", &ompl::geometric::SimpleSetup::getPlannerAllocator, bp::return_value_policy< bp::copy_const_reference >())') # Py++ seems to get confused by some methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. # do this for all planners for planner in ['EST', 'KPIECE1', 'BKPIECE1', 'LBKPIECE1', 'PRM', 'LazyPRM', 'LazyPRMstar', 'PDST', 'LazyRRT', 'RRT', 'RRTConnect', 'TRRT', 'RRTstar', 'LBTRRT', 'SBL', 'SPARS', 'SPARStwo', 'STRIDE', 'FMT', 'BITstar']: try: cls = self.ompl_ns.class_(planner) except: continue self.ompl_ns.class_(planner).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::base::Planner::*)( double ))(&::ompl::base::Planner::solve), (bp::arg("solveTime")) )""") if planner!='PRM': # PRM overrides setProblemDefinition, so we don't need to add this code self.ompl_ns.class_(planner).add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner) self.ompl_ns.class_(planner).add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &%s_wrapper::default_checkValidity )""" % planner) # The OMPL implementation of PRM uses two threads: one for constructing # the roadmap and another for checking for a solution. This causes # problems when both threads try to access the python interpreter # simultaneously. This is a known limitation of Boost.Python. We # therefore use a single-threaded version of PRM in python. PRM_cls = self.ompl_ns.class_('PRM') PRM_cls.member_function('solve').exclude() PRM_cls.add_wrapper_code(""" virtual ::ompl::base::PlannerStatus solve( ::ompl::base::PlannerTerminationCondition const & ptc ) { if( bp::override func_solve = this->get_override( "solve" ) ) return func_solve( boost::ref(ptc) ); else{ return default_solve( boost::ref(ptc) ); } } ::ompl::base::PlannerStatus default_solve( ::ompl::base::PlannerTerminationCondition const & ptc ); """) PRM_cls.add_declaration_code(open('PRM.SingleThreadSolve.cpp','r').read()) # This needs to be the last registration code added to the PRM_cls to the ugly hack below. PRM_cls.add_registration_code("""def("solve", (::ompl::base::PlannerStatus(::ompl::geometric::PRM::*)( ::ompl::base::PlannerTerminationCondition const &))(&PRM_wrapper::solve), (::ompl::base::PlannerStatus(PRM_wrapper::*)( ::ompl::base::PlannerTerminationCondition const & ))(&PRM_wrapper::default_solve), bp::arg("ptc") ); // HACK ALERT: closing brace destroys bp::scope, so that PRMstar is not a nested class of PRM } { // wrapper for PRMstar, derived from single-threaded PRM_wrapper bp::class_<PRMstar_wrapper, bp::bases< PRM_wrapper >, boost::noncopyable >("PRMstar", bp::init< ompl::base::SpaceInformationPtr const & >( bp::arg("si") ) ) """) # Add wrapper code for PRM* PRM_cls.add_declaration_code(""" class PRMstar_wrapper : public PRM_wrapper { public: PRMstar_wrapper(const ompl::base::SpaceInformationPtr &si) : PRM_wrapper(si, true) { setName("PRMstar"); params_.remove("max_nearest_neighbors"); } }; """) # LazyPRM's Vertex type is void* so exclude addMilestone which has return type void* self.ompl_ns.class_('LazyPRM').member_function('addMilestone').exclude() # avoid difficulties in exporting the return type std::vector<base::PlannerDataPtr> # do this for all multithreaded planners for planner in ['SPARS', 'SPARStwo']: cls = self.ompl_ns.class_(planner) cls.constructor(arg_types=["::ompl::base::SpaceInformationPtr const &"]).exclude() cls.add_registration_code('def(bp::init<ompl::base::SpaceInformationPtr const &>(bp::arg("si")))') cls.add_wrapper_code(""" {0}_wrapper(::ompl::base::SpaceInformationPtr const &si) : ompl::geometric::{0}(si), bp::wrapper<ompl::geometric::{0}>() {{ OMPL_WARN("%s: this planner uses multiple threads and might crash if your StateValidityChecker, OptimizationObjective, etc., are allocated within Python.", getName().c_str()); }} """.format(planner)) # used in SPARS self.std_ns.class_('deque<ompl::base::State*>').rename('dequeState') # needed to able to set connection strategy for PRM # the PRM::Vertex type is typedef-ed to boost::graph_traits<Graph>::vertex_descriptor. This can # be equal to an unsigned long or unsigned int, depending on architecture (or version of boost?) try: self.ompl_ns.class_('NearestNeighbors<unsigned long>').include() self.ompl_ns.class_('NearestNeighbors<unsigned long>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned long>').rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned long>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned long>').rename('KStarStrategy') # used in SPARStwo self.std_ns.class_('map<unsigned long, ompl::base::State*>').rename('mapVertexToState') except: self.ompl_ns.class_('NearestNeighbors<unsigned int>').include() self.ompl_ns.class_('NearestNeighbors<unsigned int>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned int>').rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned int>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned int>').rename('KStarStrategy') # used in SPARStwo self.std_ns.class_('map<unsigned int, ompl::base::State*>').rename('mapVertexToState') try: # Exclude some functions from BIT* that cause some Py++ compilation problems: self.ompl_ns.class_('BITstar').member_functions('getEdgeQueue').exclude() #I don't know why this doesn't work. self.ompl_ns.class_('BITstar').member_functions('getVertexQueue').exclude() #I don't know why this doesn't work. except: pass
def filter_declarations(self): code_generator_t.filter_declarations(self) # rename STL vectors of certain types self.std_ns.class_('vector< ompl::control::Control* >').rename('vectorControlPtr') # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # force ControlSpace::allocControl to be exported. # (not sure why this is necessary) allocControlFn = self.ompl_ns.class_('ControlSpace').member_function('allocControl') allocControlFn.include() allocControlFn.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) # don't export components which is of type Control** self.ompl_ns.class_('CompoundControl').variable('components').exclude() # don't export some internal data structure self.ompl_ns.class_('OrderCellsByImportance').exclude() # don't expose this utility function self.ompl_ns.member_functions('getValueAddressAtIndex').exclude() self.ompl_ns.class_('KPIECE1').member_functions('freeGridMotions').exclude() # add array indexing to the RealVectorState self.add_array_access(self.ompl_ns.class_('RealVectorControlSpace').class_('ControlType')) # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # make settings printable self.replace_member_functions(self.ompl_ns.member_functions('printSettings')) # make controls printable self.replace_member_functions(self.ompl_ns.member_functions('printControl')) # print paths as matrices self.replace_member_functions(self.ompl_ns.member_functions('printAsMatrix')) try: # export ODESolver-derived classes that use Boost.OdeInt for odesolver in ['ODEBasicSolver', 'ODEErrorSolver', 'ODEAdaptiveSolver']: self.ompl_ns.class_(lambda cls: cls.name.startswith(odesolver)).rename(odesolver) # Somehow, Py++ changes the type of the ODE's first argument. Weird... self.add_boost_function('void(ompl::control::ODESolver::StateType, const ompl::control::Control*, ompl::control::ODESolver::StateType &)', 'ODE','Ordinary differential equation') # workaround for default argument for PostPropagationEvent self.replace_member_function(self.ompl_ns.class_('ODESolver').member_function( 'getStatePropagator')) except declarations.matcher.declaration_not_found_t: # not available for boost < 1.44, so ignore this pass # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # export pure virtual member functions, otherwise code doesn't compile syclop = self.ompl_ns.class_('Syclop') syclop.add_wrapper_code(""" virtual ompl::control::Syclop::Motion* addRoot(const ompl::base::State* s) { bp::override func_addRoot = this->get_override("addRoot"); return func_addRoot(s); } virtual void selectAndExtend(ompl::control::Syclop::Region& region, std::vector<ompl::control::Syclop::Motion*>& newMotions) { bp::override func_selectAndExtend = this->get_override("selectAndExtend"); func_selectAndExtend(region, newMotions); }""") # omit ompl::control::Syclop::Defaults nested subclass, otherwise # code doesn't compile (don't know why) syclop.class_('Defaults').exclude() # add wrappers for boost::function types self.add_boost_function('ompl::control::ControlSamplerPtr(const ompl::control::ControlSpace*)', 'ControlSamplerAllocator', 'Control sampler allocator') self.add_boost_function('ompl::control::DirectedControlSamplerPtr(const ompl::control::SpaceInformation*)', 'DirectedControlSamplerAllocator','Directed control sampler allocator') # same type as StatePropagatorFn, so no need to export this. Instead, we just define a type alias in the python module. #self.add_boost_function('void(const ompl::base::State*, const ompl::control::Control*, const double, ompl::base::State*)', # 'PostPropagationEvent','Post-propagation event') self.add_boost_function('void(const ompl::base::State*, const ompl::control::Control*, const double, ompl::base::State*)', 'StatePropagatorFn','State propagator function') self.add_boost_function('double(int, int)','EdgeCostFactorFn', 'Syclop edge cost factor function') self.add_boost_function('void(int, int, std::vector<int>&)','LeadComputeFn', 'Syclop lead compute function') # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('control').class_('SimpleSetup').add_registration_code( 'def("setPlannerAllocator", &ompl::control::SimpleSetup::setPlannerAllocator)') self.ompl_ns.namespace('control').class_('SimpleSetup').add_registration_code( 'def("getPlannerAllocator", &ompl::control::SimpleSetup::getPlannerAllocator, bp::return_value_policy< bp::copy_const_reference >())') # Do this for all classes that exist with the same name in another namespace # (We also do it for all planners; see below) for cls in ['SimpleSetup', 'SpaceInformation']: self.ompl_ns.namespace('control').class_(cls).wrapper_alias = 'Control%s_wrapper' % cls # Py++ seems to get confused by some methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. # do this for all planners for planner in ['KPIECE1', 'PDST', 'RRT', 'EST', 'Syclop', 'SyclopEST', 'SyclopRRT']: # many planners exist with the same name in another namespace self.ompl_ns.namespace('control').class_(planner).wrapper_alias = 'Control%s_wrapper' % planner self.ompl_ns.class_(planner).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::base::Planner::*)( double ))(&::ompl::base::Planner::solve), (bp::arg("solveTime")) )""") self.ompl_ns.class_(planner).add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &Control%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner) self.ompl_ns.class_(planner).add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &Control%s_wrapper::default_checkValidity )""" % planner)
def filter_declarations(self): # force ProblemDefinition to be included, because it is used by other modules self.ompl_ns.class_('ProblemDefinition').include() # force the abstract base class Path to be included, because it is used by other modules self.ompl_ns.class_('Path').include() code_generator_t.filter_declarations(self) # rename STL vectors of certain types self.std_ns.class_('map< std::string, boost::shared_ptr< ompl::base::ProjectionEvaluator > >').rename('mapStringToProjectionEvaluator') self.std_ns.class_('vector< ompl::base::State* >').rename('vectorState') try: self.std_ns.class_('vector< ompl::base::State const* >').rename('vectorConstState') except: pass self.std_ns.class_('vector< boost::shared_ptr<ompl::base::StateSpace> >').rename('vectorStateSpacePtr') #self.std_ns.class_('vector< <ompl::base::PlannerSolution> >').rename('vectorPlannerSolution') self.std_ns.class_('map< std::string, boost::shared_ptr<ompl::base::GenericParam> >').rename('mapStringToGenericParam') self.std_ns.class_('map< std::string, ompl::base::StateSpace::SubstateLocation >').rename('mapStringToSubstateLocation') self.std_ns.class_('vector<ompl::base::PlannerSolution>').rename('vectorPlannerSolution') # rename some templated types self.ompl_ns.class_('SpecificParam< bool >').rename('SpecificParamBool') self.ompl_ns.class_('SpecificParam< char >').rename('SpecificParamChar') self.ompl_ns.class_('SpecificParam< int >').rename('SpecificParamInt') self.ompl_ns.class_('SpecificParam< unsigned int >').rename('SpecificParamUint') self.ompl_ns.class_('SpecificParam< float >').rename('SpecificParamFloat') self.ompl_ns.class_('SpecificParam< double >').rename('SpecificParamDouble') self.ompl_ns.class_('SpecificParam< std::string >').rename('SpecificParamString') for cls in self.ompl_ns.classes(lambda decl: decl.name.startswith('SpecificParam')): cls.constructors().exclude() # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # force StateSpace::allocState to be exported. # (not sure why this is necessary) allocStateFn = self.ompl_ns.class_('StateSpace').member_function('allocState') allocStateFn.include() allocStateFn.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) # rename the abstract base class State to AbstractState state = self.ompl_ns.class_('State') state.rename('AbstractState') # don't export components which is of type State** state = self.ompl_ns.class_('CompoundState') state.variable('components').exclude() state.rename('CompoundStateInternal') # rename a ScopedState<> to State bstate = self.ompl_ns.class_('ScopedState< ompl::base::StateSpace >') bstate.rename('State') bstate.operator('=', arg_types=['::ompl::base::State const &']).exclude() # add array access to double components of state self.add_array_access(bstate,'double') # loop over all predefined state spaces for stype in ['Compound', 'RealVector', 'SO2', 'SO3', 'SE2', 'SE3', 'Discrete', 'Time', 'Dubins', 'ReedsShepp']: # create a python type for each of their corresponding state types state = self.ompl_ns.class_('ScopedState< ompl::base::%sStateSpace >' % stype) state.rename(stype+'State') state.operator('=', arg_types=['::ompl::base::State const &']).exclude() # add a constructor that allows, e.g., an SE3State to be constructed from a State state.add_registration_code( 'def(bp::init<ompl::base::ScopedState<ompl::base::StateSpace> const &>(( bp::arg("other") )))') # mark the space statetype as 'internal' to emphasize that it # shouldn't typically be used by a regular python user if stype!='Dubins' and stype!='ReedsShepp': self.ompl_ns.class_(stype + 'StateSpace').decls('StateType').rename( stype + 'StateInternal') # add a constructor that allows, e.g., a State to be constructed from a SE3State bstate.add_registration_code( 'def(bp::init<ompl::base::ScopedState<ompl::base::%sStateSpace> const &>(( bp::arg("other") )))' % stype) # add array access to double components of state self.add_array_access(state,'double') # I don't know how to export a C-style array of an enum type for stype in ['Dubins', 'ReedsShepp']: self.ompl_ns.enumeration(stype + 'PathSegmentType').exclude() self.ompl_ns.class_(stype + 'Path').exclude() self.ompl_ns.class_(stype + 'StateSpace').member_function( stype[0].lower()+stype[1:]).exclude() # don't expose these utility functions that return double* self.ompl_ns.member_functions('getValueAddressAtIndex').exclude() self.ompl_ns.member_functions('getValueAddressAtName').exclude() self.ompl_ns.member_functions('getValueAddressAtLocation').exclude() # don't export vector<ValueLocation> self.ompl_ns.member_functions('getValueLocations').exclude() # don't export map<std::string, ValueLocation> self.ompl_ns.member_functions('getValueLocationsByName').exclude() # don't expose double* self.ompl_ns.class_('RealVectorStateSpace').class_( 'StateType').variable('values').exclude() try: stateStorage = self.ompl_ns.class_('StateStorage') stateStorage.member_function('getStateSamplerAllocatorRange').exclude() stateStorage.add_registration_code('def("getStateSamplerAllocatorRange", &ompl::base::StateStorage::getStateSamplerAllocatorRange)') except: pass cls = self.ompl_ns.class_('PlannerStatus') # rename to something more memorable than the default Py++ name for # the casting operator: # as__scope_ompl_scope_base_scope_PlannerStatus_scope_StatusType cls.operator(lambda decl: decl.name=='operator ::ompl::base::PlannerStatus::StatusType').rename('getStatus') # for python 2.x cls.add_registration_code( 'def("__nonzero__", &ompl::base::PlannerStatus::operator bool)') # for python 3.x cls.add_registration_code( 'def("__bool__", &ompl::base::PlannerStatus::operator bool)') # Exclude PlannerData::getEdges function that returns a map of PlannerDataEdge* for now #self.ompl_ns.class_('PlannerData').member_functions('getEdges').exclude() #self.std_ns.class_('map< unsigned int, ompl::base::PlannerDataEdge const*>').include() mapUintToPlannerDataEdge_cls = self.std_ns.class_('map< unsigned int, ompl::base::PlannerDataEdge const*>') mapUintToPlannerDataEdge_cls.rename('mapUintToPlannerDataEdge') mapUintToPlannerDataEdge_cls.indexing_suite.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) # Remove Boost.Graph representation from PlannerData self.ompl_ns.class_('PlannerData').member_functions('toBoostGraph').exclude() # Make PlannerData printable self.replace_member_function(self.ompl_ns.class_('PlannerData').member_function('printGraphviz')) self.replace_member_function(self.ompl_ns.class_('PlannerData').member_function('printGraphML')) # add array indexing to the RealVectorState self.add_array_access(self.ompl_ns.class_('RealVectorStateSpace').class_('StateType')) # typedef's are not handled by Py++, so we need to explicitly rename uBLAS vector to EuclideanProjection cls = self.mb.namespace('ublas').class_( 'vector<double, boost::numeric::ublas::unbounded_array<double, std::allocator<double> > >') cls.include() cls.rename('EuclideanProjection') cls.member_functions().exclude() cls.operators().exclude() self.add_array_access(cls,'double') # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # handle special case (abstract base class with pure virtual method) self.ompl_ns.class_('Path').add_wrapper_code( 'virtual void print(std::ostream&) const {}') # make settings printable self.replace_member_functions(self.ompl_ns.member_functions('printSettings')) # make properties printable self.replace_member_functions(self.ompl_ns.member_functions('printProperties')) # make states printable self.replace_member_functions(self.ompl_ns.member_functions('printState')) # make list of available projections printable self.replace_member_functions(self.ompl_ns.member_functions('printProjections')) # make projections printable self.replace_member_functions(self.ompl_ns.member_functions('printProjection')) # make state space diagram printable self.replace_member_function(self.ompl_ns.class_('StateSpace').member_function('Diagram')) # make state space list printable self.replace_member_function(self.ompl_ns.class_('StateSpace').member_function('List')) # add wrappers for boost::function types self.add_boost_function('bool(const ompl::base::GoalLazySamples*, ompl::base::State*)', 'GoalSamplingFn', 'Goal sampling function') self.add_boost_function('void(const ompl::base::State*)', 'NewStateCallbackFn', 'New state callback function') self.add_boost_function('ompl::base::PlannerPtr(const ompl::base::SpaceInformationPtr&)', 'PlannerAllocator', 'Planner allocator') self.add_boost_function('bool()', 'PlannerTerminationConditionFn','Planner termination condition function') self.add_boost_function('bool(const ompl::base::State*)', 'StateValidityCheckerFn', 'State validity checker function') self.add_boost_function('ompl::base::StateSamplerPtr(const ompl::base::StateSpace*)', 'StateSamplerAllocator', 'State sampler allocator') self.add_boost_function('ompl::base::ValidStateSamplerPtr(ompl::base::SpaceInformation const*)', 'ValidStateSamplerAllocator', 'Valid state allocator function') self.add_boost_function('double(const ompl::base::PlannerDataVertex&, const ompl::base::PlannerDataVertex&, const ompl::base::PlannerDataEdge&)', 'EdgeWeightFn', 'Edge weight function') self.add_boost_function('ompl::base::Cost(const ompl::base::State*, const ompl::base::Goal*)', 'CostToGoHeuristic', 'Cost-to-go heuristic for optimizing planners') self.add_boost_function('std::string()', 'PlannerProgressProperty', 'Function that returns stringified value of a property while a planner is running') # rename SamplerSelectors self.ompl_ns.class_('SamplerSelector< ompl::base::StateSampler >').rename('StateSamplerSelector') self.ompl_ns.class_('SamplerSelector< ompl::base::ValidStateSampler >').rename('ValidStateSamplerSelector') try: cls = self.ompl_ns.class_('StateStorage').member_functions('load') self.ompl_ns.class_('StateStorage').member_function('load', arg_types=['::std::istream &']).exclude() self.ompl_ns.class_('StateStorage').member_function('store', arg_types=['::std::ostream &']).exclude() except: pass
def filter_declarations(self): code_generator_t.filter_declarations(self) #self.ompl_ns.namespace('util').exclude() # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # print paths as matrices self.replace_member_functions(self.ompl_ns.member_functions('printAsMatrix')) # print debug info self.replace_member_functions(self.ompl_ns.member_functions('printDebug')) self.ompl_ns.member_functions('freeGridMotions').exclude() self.ompl_ns.class_('PRM').member_functions('maybeConstructSolution').exclude() self.ompl_ns.class_('PRM').member_functions('growRoadmap', \ function=declarations.access_type_matcher_t('protected')).exclude() self.ompl_ns.class_('PRM').member_functions('expandRoadmap', \ function=declarations.access_type_matcher_t('protected')).exclude() # don't export some internal data structure self.ompl_ns.classes('OrderCellsByImportance').exclude() # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # add wrappers for std::function types self.add_function_wrapper('unsigned int()', \ 'NumNeighborsFn', 'Number of neighbors function') # self.add_function_wrapper( # 'std::vector<ompl::geometric::PRM::Vertex>&(const ompl::geometric::PRM::Vertex)', # 'ConnectionStrategy', 'Connection strategy') self.add_function_wrapper( 'bool(const ompl::geometric::PRM::Vertex&, const ompl::geometric::PRM::Vertex&)', 'ConnectionFilter', 'Connection filter') # code generation fails to compile, most likely because of a bug in # Py++'s generation of exposed_decl.pypp.txt. self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("setPlannerAllocator", &ompl::geometric::SimpleSetup::setPlannerAllocator)') self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( \ 'def("getPlannerAllocator", &ompl::geometric::SimpleSetup::getPlannerAllocator, ' \ 'bp::return_value_policy< bp::copy_const_reference >())') self.std_ns.class_('vector< std::shared_ptr<ompl::geometric::BITstar::Vertex> >').exclude() self.std_ns.class_('vector<const ompl::base::State *>').exclude() # exclude deprecated API function self.ompl_ns.free_function('getDefaultPlanner').exclude() # Using nullptr as a default value in method arguments causes # problems with Boost.Python. # See https://github.com/boostorg/python/issues/60 self.ompl_ns.class_('PathSimplifier').add_declaration_code('#define nullptr NULL\n') # Py++ seems to get confused by some methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. planners = [p.related_class for p in self.ompl_ns.class_('Planner').recursive_derived] for planner in planners: planner.add_registration_code( 'def("solve", (::ompl::base::PlannerStatus(::ompl::base::Planner::*)( double ))' \ '(&::ompl::base::Planner::solve), (bp::arg("solveTime")) )') if planner.name != 'PRM': # PRM overrides setProblemDefinition, so we don't need to add this code planner.add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner.name) planner.add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &%s_wrapper::default_checkValidity )""" % planner.name) # The OMPL implementation of PRM uses two threads: one for constructing # the roadmap and another for checking for a solution. This causes # problems when both threads try to access the python interpreter # simultaneously. This is a known limitation of Boost.Python. We # therefore use a single-threaded version of PRM in python. PRM_cls = self.ompl_ns.class_('PRM') PRM_cls.member_function('solve').exclude() PRM_cls.add_wrapper_code(""" virtual ::ompl::base::PlannerStatus solve( ::ompl::base::PlannerTerminationCondition const & ptc ) { if( bp::override func_solve = this->get_override( "solve" ) ) return func_solve( boost::ref(ptc) ); else{ return default_solve( boost::ref(ptc) ); } } ::ompl::base::PlannerStatus default_solve( ::ompl::base::PlannerTerminationCondition const & ptc ); """) PRM_cls.add_declaration_code(open(join(dirname(__file__), \ 'PRM.SingleThreadSolve.cpp'), 'r').read()) # This needs to be the last registration code added to the PRM_cls to the ugly hack below. PRM_cls.add_registration_code("""def("solve", (::ompl::base::PlannerStatus(::ompl::geometric::PRM::*)( ::ompl::base::PlannerTerminationCondition const &))(&PRM_wrapper::solve), (::ompl::base::PlannerStatus(PRM_wrapper::*)( ::ompl::base::PlannerTerminationCondition const & ))(&PRM_wrapper::default_solve), bp::arg("ptc") ); // HACK ALERT: closing brace destroys bp::scope, // so that PRMstar is not a nested class of PRM } { // wrapper for PRMstar, derived from single-threaded PRM_wrapper bp::class_<PRMstar_wrapper, bp::bases< PRM_wrapper >, boost::noncopyable >("PRMstar", bp::init< ompl::base::SpaceInformationPtr const & >( bp::arg("si") ) ) """) # Add wrapper code for PRM* PRM_cls.add_declaration_code(""" class PRMstar_wrapper : public PRM_wrapper { public: PRMstar_wrapper(const ompl::base::SpaceInformationPtr &si) : PRM_wrapper(si, true) { setName("PRMstar"); params_.remove("max_nearest_neighbors"); } }; """) # LazyPRM's Vertex type is void* so exclude addMilestone which has return type void* self.ompl_ns.class_('LazyPRM').member_function('addMilestone').exclude() # avoid difficulties in exporting the return type std::vector<base::PlannerDataPtr> # do this for all multithreaded planners for planner in ['SPARS', 'SPARStwo']: cls = self.ompl_ns.class_(planner) cls.constructor(arg_types=["::ompl::base::SpaceInformationPtr const &"]).exclude() cls.add_registration_code( 'def(bp::init<ompl::base::SpaceInformationPtr const &>(bp::arg("si")))') cls.add_wrapper_code(""" {0}_wrapper(::ompl::base::SpaceInformationPtr const &si) : ompl::geometric::{0}(si), bp::wrapper<ompl::geometric::{0}>() {{ OMPL_WARN("%s: this planner uses multiple threads and might crash if your StateValidityChecker, OptimizationObjective, etc., are allocated within Python.", getName().c_str()); }} """.format(planner)) # exclude methods that use problematic types cls = self.ompl_ns.class_('SPARS') cls.member_function('addPathToSpanner').exclude() cls.member_function('computeDensePath').exclude() self.ompl_ns.class_('SPARStwo').member_function('findCloseRepresentatives').exclude() # needed to able to set connection strategy for PRM # the PRM::Vertex type is typedef-ed to boost::graph_traits<Graph>::vertex_descriptor. This # can be equal to an unsigned long or unsigned int, depending on architecture (or version # of boost?) try: self.ompl_ns.class_('NearestNeighbors<unsigned long>').include() self.ompl_ns.class_('NearestNeighbors<unsigned long>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned long>').rename( 'NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned long>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned long>').rename('KStarStrategy') except declaration_not_found_t: self.ompl_ns.class_('NearestNeighbors<unsigned int>').include() self.ompl_ns.class_('NearestNeighbors<unsigned int>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned int>').rename( 'NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned int>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned int>').rename('KStarStrategy') try: # Exclude some functions from BIT* that cause some Py++ compilation problems # (#I don't know why this doesn't work): self.ompl_ns.class_('BITstar').member_functions('getEdgeQueue').exclude() self.ompl_ns.class_('BITstar').member_functions('getVertexQueue').exclude() except declaration_not_found_t: pass
def filter_declarations(self): code_generator_t.filter_declarations(self) # rename STL vectors of certain types self.std_ns.class_('vector< ompl::control::Control * >').rename('vectorControlPtr') # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # force ControlSpace::allocControl to be exported. # (not sure why this is necessary) allocControlFn = self.ompl_ns.class_('ControlSpace').member_function('allocControl') allocControlFn.include() allocControlFn.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) # don't export components which is of type Control** self.ompl_ns.class_('CompoundControl').variable('components').exclude() # don't export some internal data structure self.ompl_ns.class_('OrderCellsByImportance').exclude() # don't expose this utility function self.ompl_ns.member_functions('getValueAddressAtIndex').exclude() self.ompl_ns.class_('KPIECE1').member_functions('freeGridMotions').exclude() # add array indexing to the RealVectorState self.add_array_access(self.ompl_ns.class_('RealVectorControlSpace').class_('ControlType')) # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # make settings printable self.replace_member_functions(self.ompl_ns.member_functions('printSettings')) # make controls printable self.replace_member_functions(self.ompl_ns.member_functions('printControl')) # print paths as matrices self.replace_member_functions(self.ompl_ns.member_functions('printAsMatrix')) # export ODESolver-derived classes that use Boost.OdeInt for odesolver in ['ODEBasicSolver', 'ODEErrorSolver', 'ODEAdaptiveSolver']: cls = self.ompl_ns.class_(lambda cls, slv=odesolver: cls.name.startswith(slv)) cls.rename(odesolver) if odesolver == 'ODEAdaptiveSolver': cls.include_files.append('boost/numeric/odeint.hpp') self.add_function_wrapper( 'void(const ompl::control::ODESolver::StateType &, const ompl::control::Control*, ' \ 'ompl::control::ODESolver::StateType &)', 'ODE', 'Ordinary differential equation') # workaround for default argument for PostPropagationEvent self.replace_member_function(self.ompl_ns.class_('ODESolver').member_function( 'getStatePropagator')) # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # this method requires ompl::Grid::Coord (aka Eigen::VectorXi) to be exported self.ompl_ns.class_('KPIECE1').member_function('findNextMotion').exclude() # export pure virtual member functions, otherwise code doesn't compile syclop = self.ompl_ns.class_('Syclop') syclop.add_wrapper_code(""" virtual ompl::control::Syclop::Motion* addRoot(const ompl::base::State* s) { bp::override func_addRoot = this->get_override("addRoot"); return func_addRoot(s); } virtual void selectAndExtend(ompl::control::Syclop::Region& region, std::vector<ompl::control::Syclop::Motion*>& newMotions) { bp::override func_selectAndExtend = this->get_override("selectAndExtend"); func_selectAndExtend(region, newMotions); }""") # omit ompl::control::Syclop::Defaults nested subclass, otherwise # code doesn't compile (don't know why) syclop.class_('Defaults').exclude() # add wrappers for std::function types self.add_function_wrapper( 'ompl::control::ControlSamplerPtr(const ompl::control::ControlSpace*)', 'ControlSamplerAllocator', 'Control sampler allocator') self.add_function_wrapper( 'ompl::control::DirectedControlSamplerPtr(const ompl::control::SpaceInformation*)', 'DirectedControlSamplerAllocator', 'Directed control sampler allocator') self.add_function_wrapper( 'void(const ompl::base::State*, const ompl::control::Control*, const double, ' 'ompl::base::State*)', 'StatePropagatorFn', 'State propagator function') self.add_function_wrapper('double(int, int)', 'EdgeCostFactorFn', \ 'Syclop edge cost factor function') self.add_function_wrapper('void(int, int, std::vector<int>&)', 'LeadComputeFn', \ 'Syclop lead compute function') # code generation fails to compile, most likely because of a bug in # Py++'s generation of exposed_decl.pypp.txt. self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('control').class_('SimpleSetup').add_registration_code( 'def("setPlannerAllocator", &ompl::control::SimpleSetup::setPlannerAllocator)') self.ompl_ns.namespace('control').class_('SimpleSetup').add_registration_code( 'def("getPlannerAllocator", &ompl::control::SimpleSetup::getPlannerAllocator, ' \ 'bp::return_value_policy< bp::copy_const_reference >())') # exclude deprecated API function self.ompl_ns.free_function('getDefaultPlanner').exclude() # Do this for all classes that exist with the same name in another namespace # (We also do it for all planners; see below) for cls in ['SimpleSetup', 'SpaceInformation']: self.ompl_ns.namespace('control').class_(cls).wrapper_alias = 'Control%s_wrapper' % cls # Py++ seems to get confused by some methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. planners = [p.related_class for p in self.ompl_ns.class_('Planner').recursive_derived] for planner in planners: # many planners exist with the same name in another namespace planner.wrapper_alias = 'Control%s_wrapper' % planner.name planner.add_registration_code( 'def("solve", (::ompl::base::PlannerStatus(::ompl::base::Planner::*)( double ))' \ '(&::ompl::base::Planner::solve), (bp::arg("solveTime")) )') planner.add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &Control%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % \ planner.name) planner.add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &Control%s_wrapper::default_checkValidity )""" % planner.name)
def filter_declarations(self): # force ProblemDefinition to be included, because it is used by other modules self.ompl_ns.class_('ProblemDefinition').include() # force the abstract base class Path to be included, because it is used by other modules self.ompl_ns.class_('Path').include() code_generator_t.filter_declarations(self) # rename STL vectors of certain types self.std_ns.class_( 'map< std::string, std::shared_ptr< ompl::base::ProjectionEvaluator > >').rename( 'mapStringToProjectionEvaluator') self.std_ns.class_('vector< ompl::base::State * >').rename('vectorState') try: self.std_ns.class_('vector< ompl::base::State const* >').rename('vectorConstState') except declaration_not_found_t: pass self.std_ns.class_('vector< std::shared_ptr<ompl::base::StateSpace> >').rename( 'vectorStateSpacePtr') #self.std_ns.class_('vector< <ompl::base::PlannerSolution> >').rename( # 'vectorPlannerSolution') self.std_ns.class_('map< std::string, std::shared_ptr<ompl::base::GenericParam> >').rename( 'mapStringToGenericParam') self.std_ns.class_('map< std::string, ompl::base::StateSpace::SubstateLocation >').rename( 'mapStringToSubstateLocation') self.std_ns.class_('vector<ompl::base::PlannerSolution>').rename('vectorPlannerSolution') pairStateDouble = self.std_ns.class_('pair<ompl::base::State *, double>') pairStateDouble.rename('pairStateDouble') pairStateDouble.include() # this operator seems to cause problems with g++-6 pairStateDouble.operators('=').exclude() # rename some templated types self.ompl_ns.class_('SpecificParam< bool >').rename('SpecificParamBool') self.ompl_ns.class_('SpecificParam< char >').rename('SpecificParamChar') self.ompl_ns.class_('SpecificParam< int >').rename('SpecificParamInt') self.ompl_ns.class_('SpecificParam< unsigned int >').rename('SpecificParamUint') self.ompl_ns.class_('SpecificParam< float >').rename('SpecificParamFloat') self.ompl_ns.class_('SpecificParam< double >').rename('SpecificParamDouble') self.ompl_ns.class_('SpecificParam< long double >').rename('SpecificParamLongDouble') self.ompl_ns.class_('SpecificParam< std::basic_string<char> >').rename( 'SpecificParamString') for cls in self.ompl_ns.classes(lambda decl: decl.name.startswith('SpecificParam')): cls.constructors().exclude() # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # force StateSpace::allocState to be exported. # (not sure why this is necessary) allocStateFn = self.ompl_ns.class_('StateSpace').member_function('allocState') allocStateFn.include() allocStateFn.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) # rename the abstract base class State to AbstractState state = self.ompl_ns.class_('State') state.rename('AbstractState') # don't export components which is of type State** state = self.ompl_ns.class_('CompoundState') state.variable('components').exclude() state.rename('CompoundStateInternal') # rename a ScopedState<> to State bstate = self.ompl_ns.class_('ScopedState< ompl::base::StateSpace >') bstate.rename('State') bstate.operator('=', arg_types=['::ompl::base::State const &']).exclude() # add array access to double components of state self.add_array_access(bstate, 'double') # loop over all predefined state spaces spaces = [s.related_class.name.replace('StateSpace', '') \ for s in self.ompl_ns.class_('StateSpace').recursive_derived] for stype in spaces: # create a python type for each of their corresponding state types state = self.ompl_ns.class_('ScopedState< ompl::base::%sStateSpace >' % stype) state.rename(stype+'State') state.operator('=', arg_types=['::ompl::base::State const &']).exclude() # add a constructor that allows, e.g., an SE3State to be constructed from a State state.add_registration_code( 'def(bp::init<ompl::base::ScopedState<ompl::base::StateSpace> const &>' \ '(( bp::arg("other") )))') # mark the space statetype as 'internal' to emphasize that it # shouldn't typically be used by a regular python user try: self.ompl_ns.class_(stype + 'StateSpace').decls('StateType').rename( stype + 'StateInternal') except: # ignore derived statespaces that do not define their own StateType pass # add a constructor that allows, e.g., a State to be constructed from a SE3State bstate.add_registration_code( 'def(bp::init<ompl::base::ScopedState<ompl::base::%sStateSpace> const &>' \ '(( bp::arg("other") )))' % stype) # add array access to double components of state self.add_array_access(state, 'double') # I don't know how to export a C-style array of an enum type for stype in ['Dubins', 'ReedsShepp']: self.ompl_ns.enumeration(stype + 'PathSegmentType').exclude() self.ompl_ns.class_(stype + 'Path').exclude() self.ompl_ns.class_(stype + 'StateSpace').member_function( stype[0].lower()+stype[1:]).exclude() # don't expose these utility functions that return double* self.ompl_ns.member_functions('getValueAddressAtIndex').exclude() self.ompl_ns.member_functions('getValueAddressAtName').exclude() self.ompl_ns.member_functions('getValueAddressAtLocation').exclude() # don't export vector<ValueLocation> self.ompl_ns.member_functions('getValueLocations').exclude() # don't export map<std::string, ValueLocation> self.ompl_ns.member_functions('getValueLocationsByName').exclude() # exclude member function for which there are multiple signatures self.ompl_ns.class_('Goal').member_function( 'isSatisfied', arg_types=['::ompl::base::State const *', 'double *']).exclude() # don't expose double* self.ompl_ns.class_('RealVectorStateSpace').class_( 'StateType').variable('values').exclude() try: stateStorage = self.ompl_ns.class_('StateStorage') stateStorage.member_function('getStateSamplerAllocatorRange').exclude() stateStorage.add_registration_code('def("getStateSamplerAllocatorRange", ' \ '&ompl::base::StateStorage::getStateSamplerAllocatorRange)') except declaration_not_found_t: pass cls = self.ompl_ns.class_('PlannerStatus') # rename to something more memorable than the default Py++ name for # the casting operator: # as__scope_ompl_scope_base_scope_PlannerStatus_scope_StatusType cls.operator( lambda decl: decl.name == 'operator ::ompl::base::PlannerStatus::StatusType').rename( 'getStatus') # for python 2.x cls.add_registration_code( 'def("__nonzero__", &ompl::base::PlannerStatus::operator bool)') # for python 3.x cls.add_registration_code( 'def("__bool__", &ompl::base::PlannerStatus::operator bool)') # Using nullptr as a default value in method arguments causes # problems with Boost.Python. # See https://github.com/boostorg/python/issues/60 self.ompl_ns.class_('ProblemDefinition').add_declaration_code('#define nullptr NULL\n') try: for cls in ['AtlasChart', 'AtlasStateSpace', 'ConstrainedStateSpace', \ 'ProjectedStateSpace', 'TangentBundleStateSpace']: self.ompl_ns.class_(cls).add_declaration_code('#define nullptr NULL\n') self.ompl_ns.class_('AtlasChart').member_function('toPolygon').exclude() self.replace_member_function(self.ompl_ns.class_( 'AtlasStateSpace').member_function('printPLY')) self.add_function_wrapper( 'double(ompl::base::AtlasChart *)', 'AtlasChartBiasFunction', 'Bias function for sampling a chart from an atlas.') # add code for numpy.array <-> Eigen conversions self.mb.add_declaration_code(open(join(dirname(__file__), \ 'numpy_eigen.cpp'), 'r').read()) self.mb.add_registration_code(""" EIGEN_ARRAY_CONVERTER(Eigen::MatrixXd, 2) EIGEN_ARRAY_CONVERTER(Eigen::VectorXd, 1) """) self.mb.add_registration_code('np::initialize();', tail=False) self.add_array_access(self.ompl_ns.class_( 'ConstrainedStateSpace').class_('StateType'), 'double') for cls in [self.ompl_ns.class_('Constraint'), self.ompl_ns.class_('ConstraintIntersection')]: for method in ['function', 'jacobian']: cls.member_function(method, arg_types=[ '::Eigen::Ref<const Eigen::Matrix<double, -1, 1, 0, -1, 1>, ' '0, Eigen::InnerStride<1> > const &', None]).add_transformation(FT.input(0)) cls = self.ompl_ns.class_('Constraint') for method in ['distance', 'isSatisfied']: cls.member_function(method, arg_types=[ '::Eigen::Ref<const Eigen::Matrix<double, -1, 1, 0, -1, 1>, ' '0, Eigen::InnerStride<1> > const &']).add_transformation(FT.input(0)) except: # python bindings for constrained planning code is only generated # if boost.numpy was found pass # Exclude PlannerData::getEdges function that returns a map of PlannerDataEdge* for now #self.ompl_ns.class_('PlannerData').member_functions('getEdges').exclude() #self.std_ns.class_('map< unsigned int, ompl::base::PlannerDataEdge const*>').include() mapUintToPlannerDataEdge_cls = self.std_ns.class_( 'map< unsigned int, const ompl::base::PlannerDataEdge *>') mapUintToPlannerDataEdge_cls.rename('mapUintToPlannerDataEdge') mapUintToPlannerDataEdge_cls.indexing_suite.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) # Remove Boost.Graph representation from PlannerData plannerData = self.ompl_ns.class_('PlannerData') plannerData.member_functions('toBoostGraph').exclude() # Make PlannerData printable self.replace_member_function(plannerData.member_function('printGraphviz')) self.replace_member_function(plannerData.member_function('printGraphML')) # serialize passes archive by reference which causes problems self.ompl_ns.class_('PlannerDataVertex').member_functions('serialize').exclude() self.ompl_ns.class_('PlannerDataEdge').member_functions('serialize').exclude() # add array indexing to the RealVectorState self.add_array_access(self.ompl_ns.class_('RealVectorStateSpace').class_('StateType')) # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # handle special case (abstract base class with pure virtual method) self.ompl_ns.class_('Path').add_wrapper_code( 'virtual void print(std::ostream&) const {}') # make settings printable self.replace_member_functions(self.ompl_ns.member_functions('printSettings')) # make properties printable self.replace_member_functions(self.ompl_ns.member_functions('printProperties')) # make states printable self.replace_member_functions(self.ompl_ns.member_functions('printState')) # make list of available projections printable self.replace_member_functions(self.ompl_ns.member_functions('printProjections')) # make projections printable self.replace_member_functions(self.ompl_ns.member_functions('printProjection')) # make state space diagram printable self.replace_member_function(self.ompl_ns.class_('StateSpace').member_function('Diagram')) # make state space list printable self.replace_member_function(self.ompl_ns.class_('StateSpace').member_function('List')) # add wrappers for std::function types self.add_function_wrapper('bool(const ompl::base::GoalLazySamples*, ompl::base::State*)', \ 'GoalSamplingFn', 'Goal sampling function') self.add_function_wrapper('void(const ompl::base::State*)', \ 'NewStateCallbackFn', 'New state callback function') self.add_function_wrapper( 'ompl::base::PlannerPtr(const ompl::base::SpaceInformationPtr&)', 'PlannerAllocator', 'Planner allocator') self.add_function_wrapper('bool()', \ 'PlannerTerminationConditionFn', 'Planner termination condition function') self.add_function_wrapper('bool(const ompl::base::State*)', \ 'StateValidityCheckerFn', 'State validity checker function') self.add_function_wrapper('ompl::base::StateSamplerPtr(const ompl::base::StateSpace*)', \ 'StateSamplerAllocator', 'State sampler allocator') self.add_function_wrapper( 'ompl::base::ValidStateSamplerPtr(ompl::base::SpaceInformation const*)', 'ValidStateSamplerAllocator', 'Valid state allocator function') self.add_function_wrapper('double(const ompl::base::PlannerDataVertex&, ' \ 'const ompl::base::PlannerDataVertex&, const ompl::base::PlannerDataEdge&)', \ 'EdgeWeightFn', 'Edge weight function') self.add_function_wrapper( 'ompl::base::Cost(const ompl::base::State*, const ompl::base::Goal*)', 'CostToGoHeuristic', 'Cost-to-go heuristic for optimizing planners') self.add_function_wrapper('std::string()', 'PlannerProgressProperty', \ 'Function that returns stringified value of a property while a planner is running') # rename SamplerSelectors self.ompl_ns.class_('SamplerSelector< ompl::base::StateSampler >').rename( 'StateSamplerSelector') self.ompl_ns.class_('SamplerSelector< ompl::base::ValidStateSampler >').rename( 'ValidStateSamplerSelector') try: cls = self.ompl_ns.class_('StateStorage').member_functions('load') self.ompl_ns.class_('StateStorage').member_function('load', \ arg_types=['::std::istream &']).exclude() self.ompl_ns.class_('StateStorage').member_function('store', \ arg_types=['::std::ostream &']).exclude() except declaration_not_found_t: pass
def filter_declarations(self): # force ProblemDefinition to be included, because it is used by other modules self.ompl_ns.class_('ProblemDefinition').include() # force the abstract base class Path to be included, because it is used by other modules self.ompl_ns.class_('Path').include() code_generator_t.filter_declarations(self) # rename STL vectors of certain types self.std_ns.class_('map< std::string, boost::shared_ptr< ompl::base::ProjectionEvaluator > >').rename('mapStringToProjectionEvaluator') self.std_ns.class_('vector< ompl::base::State* >').rename('vectorState') try: self.std_ns.class_('vector< ompl::base::State const* >').rename('vectorConstState') except: pass self.std_ns.class_('vector< boost::shared_ptr<ompl::base::StateSpace> >').rename('vectorStateSpacePtr') #self.std_ns.class_('vector< <ompl::base::PlannerSolution> >').rename('vectorPlannerSolution') self.std_ns.class_('map< std::string, boost::shared_ptr<ompl::base::GenericParam> >').rename('mapStringToGenericParam') self.std_ns.class_('map< std::string, ompl::base::StateSpace::SubstateLocation >').rename('mapStringToSubstateLocation') self.std_ns.class_('vector<ompl::base::PlannerSolution>').rename('vectorPlannerSolution') # rename some templated types self.ompl_ns.class_('SpecificParam< bool >').rename('SpecificParamBool') self.ompl_ns.class_('SpecificParam< char >').rename('SpecificParamChar') self.ompl_ns.class_('SpecificParam< int >').rename('SpecificParamInt') self.ompl_ns.class_('SpecificParam< unsigned int >').rename('SpecificParamUint') self.ompl_ns.class_('SpecificParam< float >').rename('SpecificParamFloat') self.ompl_ns.class_('SpecificParam< double >').rename('SpecificParamDouble') self.ompl_ns.class_('SpecificParam< std::string >').rename('SpecificParamString') for cls in self.ompl_ns.classes(lambda decl: decl.name.startswith('SpecificParam')): cls.constructors().exclude() # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # force StateSpace::allocState to be exported. # (not sure why this is necessary) allocStateFn = self.ompl_ns.class_('StateSpace').member_function('allocState') allocStateFn.include() allocStateFn.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) # rename the abstract base class State to AbstractState state = self.ompl_ns.class_('State') state.rename('AbstractState') # don't export components which is of type State** state = self.ompl_ns.class_('CompoundState') state.variable('components').exclude() state.rename('CompoundStateInternal') # rename a ScopedState<> to State bstate = self.ompl_ns.class_('ScopedState< ompl::base::StateSpace >') bstate.rename('State') bstate.operator('=', arg_types=['::ompl::base::State const &']).exclude() # add array access to double components of state self.add_array_access(bstate,'double') # loop over all predefined state spaces for stype in ['Compound', 'RealVector', 'SO2', 'SO3', 'SE2', 'SE3', 'Discrete', 'Time', 'Dubins', 'ReedsShepp']: # create a python type for each of their corresponding state types state = self.ompl_ns.class_('ScopedState< ompl::base::%sStateSpace >' % stype) state.rename(stype+'State') state.operator('=', arg_types=['::ompl::base::State const &']).exclude() # add a constructor that allows, e.g., an SE3State to be constructed from a State state.add_registration_code( 'def(bp::init<ompl::base::ScopedState<ompl::base::StateSpace> const &>(( bp::arg("other") )))') # mark the space statetype as 'internal' to emphasize that it # shouldn't typically be used by a regular python user if stype!='Dubins' and stype!='ReedsShepp': self.ompl_ns.class_(stype + 'StateSpace').decls('StateType').rename( stype + 'StateInternal') # add a constructor that allows, e.g., a State to be constructed from a SE3State bstate.add_registration_code( 'def(bp::init<ompl::base::ScopedState<ompl::base::%sStateSpace> const &>(( bp::arg("other") )))' % stype) # add array access to double components of state self.add_array_access(state,'double') # I don't know how to export a C-style array of an enum type for stype in ['Dubins', 'ReedsShepp']: self.ompl_ns.enumeration(stype + 'PathSegmentType').exclude() self.ompl_ns.class_(stype + 'Path').exclude() self.ompl_ns.class_(stype + 'StateSpace').member_function( stype[0].lower()+stype[1:]).exclude() # don't expose these utility functions that return double* self.ompl_ns.member_functions('getValueAddressAtIndex').exclude() self.ompl_ns.member_functions('getValueAddressAtName').exclude() self.ompl_ns.member_functions('getValueAddressAtLocation').exclude() # don't export vector<ValueLocation> self.ompl_ns.member_functions('getValueLocations').exclude() # don't export map<std::string, ValueLocation> self.ompl_ns.member_functions('getValueLocationsByName').exclude() # don't expose double* self.ompl_ns.class_('RealVectorStateSpace').class_( 'StateType').variable('values').exclude() try: stateStorage = self.ompl_ns.class_('StateStorage') stateStorage.member_function('getStateSamplerAllocatorRange').exclude() stateStorage.add_registration_code('def("getStateSamplerAllocatorRange", &ompl::base::StateStorage::getStateSamplerAllocatorRange)') except: pass cls = self.ompl_ns.class_('PlannerStatus') # rename to something more memorable than the default Py++ name for # the casting operator: # as__scope_ompl_scope_base_scope_PlannerStatus_scope_StatusType cls.operator(lambda decl: decl.name=='operator ::ompl::base::PlannerStatus::StatusType').rename('getStatus') # for python 2.x cls.add_registration_code( 'def("__nonzero__", &ompl::base::PlannerStatus::operator bool)') # for python 3.x cls.add_registration_code( 'def("__bool__", &ompl::base::PlannerStatus::operator bool)') # Exclude PlannerData::getEdges function that returns a map of PlannerDataEdge* for now #self.ompl_ns.class_('PlannerData').member_functions('getEdges').exclude() #self.std_ns.class_('map< unsigned int, ompl::base::PlannerDataEdge const*>').include() mapUintToPlannerDataEdge_cls = self.std_ns.class_('map< unsigned int, ompl::base::PlannerDataEdge const*>') mapUintToPlannerDataEdge_cls.rename('mapUintToPlannerDataEdge') mapUintToPlannerDataEdge_cls.indexing_suite.call_policies = \ call_policies.return_value_policy(call_policies.reference_existing_object) # Remove Boost.Graph representation from PlannerData self.ompl_ns.class_('PlannerData').member_functions('toBoostGraph').exclude() # Make PlannerData printable self.replace_member_function(self.ompl_ns.class_('PlannerData').member_function('printGraphviz')) self.replace_member_function(self.ompl_ns.class_('PlannerData').member_function('printGraphML')) # add array indexing to the RealVectorState self.add_array_access(self.ompl_ns.class_('RealVectorStateSpace').class_('StateType')) # typedef's are not handled by Py++, so we need to explicitly rename uBLAS vector to EuclideanProjection cls = self.mb.namespace('ublas').class_( 'vector<double, boost::numeric::ublas::unbounded_array<double, std::allocator<double> > >') cls.include() cls.rename('EuclideanProjection') cls.member_functions().exclude() cls.operators().exclude() self.add_array_access(cls,'double') # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # handle special case (abstract base class with pure virtual method) self.ompl_ns.class_('Path').add_wrapper_code( 'virtual void print(std::ostream&) const {}') # make settings printable self.replace_member_functions(self.ompl_ns.member_functions('printSettings')) # make properties printable self.replace_member_functions(self.ompl_ns.member_functions('printProperties')) # make states printable self.replace_member_functions(self.ompl_ns.member_functions('printState')) # make list of available projections printable self.replace_member_functions(self.ompl_ns.member_functions('printProjections')) # make projections printable self.replace_member_functions(self.ompl_ns.member_functions('printProjection')) # make state space diagram printable self.replace_member_function(self.ompl_ns.class_('StateSpace').member_function('Diagram')) # make state space list printable self.replace_member_function(self.ompl_ns.class_('StateSpace').member_function('List')) # add wrappers for boost::function types self.add_boost_function('bool(const ompl::base::GoalLazySamples*, ompl::base::State*)', 'GoalSamplingFn', 'Goal sampling function') self.add_boost_function('void(const ompl::base::State*)', 'NewStateCallbackFn', 'New state callback function') self.add_boost_function('ompl::base::PlannerPtr(const ompl::base::SpaceInformationPtr&)', 'PlannerAllocator', 'Planner allocator') self.add_boost_function('bool()', 'PlannerTerminationConditionFn','Planner termination condition function') self.add_boost_function('bool(const ompl::base::State*)', 'StateValidityCheckerFn', 'State validity checker function') self.add_boost_function('ompl::base::StateSamplerPtr(const ompl::base::StateSpace*)', 'StateSamplerAllocator', 'State sampler allocator') self.add_boost_function('ompl::base::ValidStateSamplerPtr(ompl::base::SpaceInformation const*)', 'ValidStateSamplerAllocator', 'Valid state allocator function') self.add_boost_function('double(const ompl::base::PlannerDataVertex&, const ompl::base::PlannerDataVertex&, const ompl::base::PlannerDataEdge&)', 'EdgeWeightFn', 'Edge weight function') self.add_boost_function('ompl::base::Cost(const ompl::base::State*, const ompl::base::Goal*)', 'CostToGoHeuristic', 'Cost-to-go heuristic for optimizing planners') self.add_boost_function('std::string()', 'PlannerProgressProperty', 'Function that returns stringified value of a property while a planner is running') # rename SamplerSelectors self.ompl_ns.class_('SamplerSelector< ompl::base::StateSampler >').rename('StateSamplerSelector') self.ompl_ns.class_('SamplerSelector< ompl::base::ValidStateSampler >').rename('ValidStateSamplerSelector') try: cls = self.ompl_ns.class_('StateStorage').member_functions('load') self.ompl_ns.class_('StateStorage').member_function('load', arg_types=['::std::istream &']).exclude() self.ompl_ns.class_('StateStorage').member_function('store', arg_types=['::std::ostream &']).exclude() except: pass
def filter_declarations(self): code_generator_t.filter_declarations(self) # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) self.ompl_ns.member_functions('freeGridMotions').exclude() self.ompl_ns.class_('PRM').member_functions('haveSolution').exclude() self.ompl_ns.class_('PRM').member_functions('growRoadmap', function=declarations.access_type_matcher_t('protected')).exclude() self.ompl_ns.class_('PRM').member_functions('expandRoadmap', function=declarations.access_type_matcher_t('protected')).exclude() # don't export some internal data structure self.ompl_ns.classes('OrderCellsByImportance').exclude() # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # exclude solve() methods that take a "const PlannerTerminationCondition &" # as first argument; only keep the solve() that just takes a double argument self.ompl_ns.member_functions('solve', arg_types=['::ompl::base::PlannerTerminationCondition const &']).exclude() # add wrappers for boost::function types self.add_boost_function('unsigned int()', 'NumNeighborsFn', 'Number of neighbors function') # self.add_boost_function('std::vector<ompl::geometric::PRM::Vertex>&(const ompl::geometric::PRM::Vertex)', # 'ConnectionStrategy', 'Connection strategy') self.add_boost_function('bool(const ompl::geometric::PRM::Vertex&, const ompl::geometric::PRM::Vertex&)', 'ConnectionFilter', 'Connection filter') # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("setPlannerAllocator", &ompl::geometric::SimpleSetup::setPlannerAllocator)') self.ompl_ns.namespace('geometric').class_('SimpleSetup').add_registration_code( 'def("getPlannerAllocator", &ompl::geometric::SimpleSetup::getPlannerAllocator, bp::return_value_policy< bp::copy_const_reference >())') # The OMPL implementation of PRM uses two threads: one for constructing # the roadmap and another for checking for a solution. This causes # problems when both threads try to access the python interpreter # simultaneously. This is a know limitation of Boost.Python. We # therefore use a single-threaded version of PRM in python. PRM_cls = self.ompl_ns.class_('PRM') PRM_cls.add_wrapper_code('ompl::base::PlannerStatus solve(const ompl::base::PlannerTerminationCondition& ptc);') PRM_cls.add_declaration_code(open('PRM.SingleThreadSolve.cpp','r').read()) PRM_cls.add_registration_code('def("solve", &PRM_wrapper::solve)') PRM_cls.add_registration_code('def("solve", timed_solve_function_type(&ompl::base::Planner::solve))') # Py++ seems to get confused by virtual methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. # do this for all planners for planner in ['EST', 'KPIECE1', 'BKPIECE1', 'LBKPIECE1', 'PRM', 'LazyRRT', 'RRT', 'RRTConnect', 'TRRT', 'SBL']: if planner!='PRM': # PRM overrides setProblemDefinition, so we don't need to add this code self.ompl_ns.class_(planner).add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner) self.ompl_ns.class_(planner).add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &%s_wrapper::default_checkValidity )""" % planner) # needed to able to set connection strategy for PRM # the PRM::Vertex type is typedef-ed to boost::graph_traits<Graph>::vertex_descriptor. This can # be equal to an unsigned long or unsigned int, depending on architecture (or version of boost?) try: self.ompl_ns.class_('NearestNeighbors<unsigned long>').include() self.ompl_ns.class_('NearestNeighbors<unsigned long>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned long>').rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned long>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned long>').rename('KStarStrategy') except: self.ompl_ns.class_('NearestNeighbors<unsigned int>').include() self.ompl_ns.class_('NearestNeighbors<unsigned int>').rename('NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned int>').rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned int>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned int>').rename('KStarStrategy')
def filter_declarations(self): code_generator_t.filter_declarations(self) # don't export variables that need a wrapper self.ompl_ns.variables(lambda decl: decl.is_wrapper_needed()).exclude() # make objects printable that have a print function self.replace_member_functions(self.ompl_ns.member_functions('print')) # print paths as matrices self.replace_member_functions( self.ompl_ns.member_functions('printAsMatrix')) # print debug info self.replace_member_functions( self.ompl_ns.member_functions('printDebug')) self.ompl_ns.member_functions('freeGridMotions').exclude() self.ompl_ns.class_('PRM').member_functions( 'maybeConstructSolution').exclude() self.ompl_ns.class_('PRM').member_functions( 'growRoadmap', function=declarations.access_type_matcher_t( 'protected')).exclude() self.ompl_ns.class_('PRM').member_functions( 'expandRoadmap', function=declarations.access_type_matcher_t( 'protected')).exclude() # don't export some internal data structure self.ompl_ns.classes('OrderCellsByImportance').exclude() # LLVM's clang++ compiler doesn't like exporting this method because # the argument type (Grid::Cell) is protected self.ompl_ns.member_functions('computeImportance').exclude() # add wrappers for boost::function types self.add_boost_function('unsigned int()', 'NumNeighborsFn', 'Number of neighbors function') # self.add_boost_function('std::vector<ompl::geometric::PRM::Vertex>&(const ompl::geometric::PRM::Vertex)', # 'ConnectionStrategy', 'Connection strategy') self.add_boost_function( 'bool(const ompl::geometric::PRM::Vertex&, const ompl::geometric::PRM::Vertex&)', 'ConnectionFilter', 'Connection filter') # code generation fails because of same bug in gxxcml that requires us # to patch the generated code with workaround_for_gccxml_bug.cmake self.ompl_ns.member_functions('getPlannerAllocator').exclude() self.ompl_ns.member_functions('setPlannerAllocator').exclude() self.ompl_ns.namespace('geometric').class_( 'SimpleSetup' ).add_registration_code( 'def("setPlannerAllocator", &ompl::geometric::SimpleSetup::setPlannerAllocator)' ) self.ompl_ns.namespace('geometric').class_( 'SimpleSetup' ).add_registration_code( 'def("getPlannerAllocator", &ompl::geometric::SimpleSetup::getPlannerAllocator, bp::return_value_policy< bp::copy_const_reference >())' ) # The OMPL implementation of PRM uses two threads: one for constructing # the roadmap and another for checking for a solution. This causes # problems when both threads try to access the python interpreter # simultaneously. This is a known limitation of Boost.Python. We # therefore use a single-threaded version of PRM in python. PRM_cls = self.ompl_ns.class_('PRM') PRM_cls.member_function('solve').exclude() PRM_cls.add_wrapper_code(""" virtual ::ompl::base::PlannerStatus solve( ::ompl::base::PlannerTerminationCondition const & ptc ) { if( bp::override func_solve = this->get_override( "solve" ) ) return func_solve( boost::ref(ptc) ); else{ return default_solve( boost::ref(ptc) ); } } ::ompl::base::PlannerStatus default_solve( ::ompl::base::PlannerTerminationCondition const & ptc ); """) PRM_cls.add_declaration_code( open('PRM.SingleThreadSolve.cpp', 'r').read()) PRM_cls.add_registration_code("""def("solve", (::ompl::base::PlannerStatus(::ompl::geometric::PRM::*)( ::ompl::base::PlannerTerminationCondition const &))(&PRM_wrapper::solve), (::ompl::base::PlannerStatus(PRM_wrapper::*)( ::ompl::base::PlannerTerminationCondition const & ))(&PRM_wrapper::default_solve), bp::arg("ptc") )""" ) # exclude PRM*, define it in python to use the single-threaded version # of PRM with the k* connection strategy self.ompl_ns.class_('PRMstar').exclude() # LazyPRM's Vertex type is void* so exclude addMilestone which has return type void* self.ompl_ns.class_('LazyPRM').member_function( 'addMilestone').exclude() # Py++ seems to get confused by some methods declared in one module # that are *not* overridden in a derived class in another module. The # Planner class is defined in ompl::base and two of its virtual methods, # setProblemDefinition and checkValidity, and not overridden by most # planners. The code below forces Py++ to do the right thing (or at # least make it work). It seems rather hacky and there may be a better # solution. # do this for all planners for planner in [ 'EST', 'KPIECE1', 'BKPIECE1', 'LBKPIECE1', 'PRM', 'LazyPRM', 'PDST', 'LazyRRT', 'RRT', 'RRTConnect', 'TRRT', 'RRTstar', 'LBTRRT', 'SBL', 'SPARS', 'SPARStwo', 'STRIDE', 'FMT', 'BITstar' ]: self.ompl_ns.class_(planner).add_registration_code(""" def("solve", (::ompl::base::PlannerStatus(::ompl::base::Planner::*)( double ))(&::ompl::base::Planner::solve), (bp::arg("solveTime")) )""" ) if planner != 'PRM': # PRM overrides setProblemDefinition, so we don't need to add this code self.ompl_ns.class_(planner).add_registration_code(""" def("setProblemDefinition",&::ompl::base::Planner::setProblemDefinition, &%s_wrapper::default_setProblemDefinition, (bp::arg("pdef")) )""" % planner) self.ompl_ns.class_(planner).add_registration_code(""" def("checkValidity",&::ompl::base::Planner::checkValidity, &%s_wrapper::default_checkValidity )""" % planner) # do this for all multithreaded planners for planner in ['SPARS', 'SPARStwo']: cls = self.ompl_ns.class_(planner) cls.constructor( arg_types=["::ompl::base::SpaceInformationPtr const &" ]).exclude() cls.add_registration_code( 'def(bp::init<ompl::base::SpaceInformationPtr const &>(bp::arg("si")))' ) cls.add_wrapper_code(""" {0}_wrapper(::ompl::base::SpaceInformationPtr const &si) : ompl::geometric::{0}(si), bp::wrapper<ompl::geometric::{0}>() {{ OMPL_WARN("%s: this planner uses multiple threads and might crash if your StateValidityChecker, OptimizationObjective, etc., are allocated within Python.", getName().c_str()); }} """.format(planner)) # used in SPARS self.std_ns.class_('deque<ompl::base::State*>').rename('dequeState') # needed to able to set connection strategy for PRM # the PRM::Vertex type is typedef-ed to boost::graph_traits<Graph>::vertex_descriptor. This can # be equal to an unsigned long or unsigned int, depending on architecture (or version of boost?) try: self.ompl_ns.class_('NearestNeighbors<unsigned long>').include() self.ompl_ns.class_('NearestNeighbors<unsigned long>').rename( 'NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned long>' ).rename('NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned long>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned long>').rename( 'KStarStrategy') # used in SPARStwo self.std_ns.class_('map<unsigned long, ompl::base::State*>' ).rename('mapVertexToState') except: self.ompl_ns.class_('NearestNeighbors<unsigned int>').include() self.ompl_ns.class_('NearestNeighbors<unsigned int>').rename( 'NearestNeighbors') self.ompl_ns.class_('NearestNeighborsLinear<unsigned int>').rename( 'NearestNeighborsLinear') self.ompl_ns.class_('KStrategy<unsigned int>').rename('KStrategy') self.ompl_ns.class_('KStarStrategy<unsigned int>').rename( 'KStarStrategy') # used in SPARStwo self.std_ns.class_('map<unsigned int, ompl::base::State*>').rename( 'mapVertexToState')