diff --git a/CMakeLists.txt b/CMakeLists.txt index a99f36027..2719a77ab 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -347,8 +347,16 @@ endif() # Python wrap if (GTSAM_BUILD_PYTHON) - include(GtsamPythonWrap) + # NOTE: The automatic generation of python wrapper from the gtsampy.h interface is + # not working yet, so we're using a handwritten wrapper files on python/handwritten. + # Once the python wrapping from the interface file is working, you can _swap_ the + # comments on the next lines + + # include(GtsamPythonWrap) # wrap_and_install_python(gtsampy.h "${GTSAM_ADDITIONAL_LIBRARIES}" "") + + add_subdirectory(python) + endif() # Build gtsam_unstable diff --git a/python/CMakeLists.txt b/python/CMakeLists.txt new file mode 100644 index 000000000..0fcb1fc28 --- /dev/null +++ b/python/CMakeLists.txt @@ -0,0 +1,13 @@ +# Obtain Dependencies +# Boost Python +find_package(Boost COMPONENTS python REQUIRED) +include_directories(${Boost_INCLUDE_DIRS}) + +# Find Python +find_package(PythonLibs 2.7 REQUIRED) +include_directories(${PYTHON_INCLUDE_DIRS}) + +# Numpy_Eigen +include_directories(${CMAKE_SOURCE_DIR}/gtsam/3rdparty/numpy_eigen/include/) + +add_subdirectory(handwritten) \ No newline at end of file diff --git a/python/gtsam/.gitignore b/python/gtsam/.gitignore new file mode 100644 index 000000000..8f89b0f14 --- /dev/null +++ b/python/gtsam/.gitignore @@ -0,0 +1 @@ +/libgtsam_python.so diff --git a/python/gtsam/__init__.py b/python/gtsam/__init__.py index 39d0d08ef..4b18783d3 100644 --- a/python/gtsam/__init__.py +++ b/python/gtsam/__init__.py @@ -1,5 +1 @@ -import registernumpyeigen -import noiseModel -from geometry import * -from nonlinear import * -from slam import * +from libgtsam_python import * \ No newline at end of file diff --git a/python/handwritten/examples/OdometeryExample.py b/python/gtsam/examples/OdometeryExample.py similarity index 100% rename from python/handwritten/examples/OdometeryExample.py rename to python/gtsam/examples/OdometeryExample.py diff --git a/python/handwritten/CMakeLists.txt b/python/handwritten/CMakeLists.txt index 6693beba5..753e33831 100644 --- a/python/handwritten/CMakeLists.txt +++ b/python/handwritten/CMakeLists.txt @@ -1,27 +1,48 @@ -include_directories("${PROJECT_SOURCE_DIR}/gtsam") +# Macro to get list of subdirectories +MACRO(SUBDIRLIST result curdir) + FILE(GLOB children RELATIVE ${curdir} ${curdir}/*) + SET(dirlist "") + FOREACH(child ${children}) + IF(IS_DIRECTORY ${curdir}/${child}) + LIST(APPEND dirlist ${child}) + ENDIF() + ENDFOREACH() + SET(${result} ${dirlist}) +ENDMACRO() -#set the default path for built executables to the "bin" directory -set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin) -#set the default path for built libraries to the "lib" directory -set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib) +# get subdirectories list +SUBDIRLIST(SUBDIRS ${CMAKE_CURRENT_SOURCE_DIR}) -list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../cmake) +# get the sources needed to compile gtsam python module +SET(gtsam_python_srcs "") +FOREACH(subdir ${SUBDIRS}) + file(GLOB ${subdir}_src "${subdir}/*.cpp") + LIST(APPEND gtsam_python_srcs ${${subdir}_src}) +ENDFOREACH() -#include_directories(${EIGEN_INCLUDE_DIRS}) +# Create the library +set(moduleName gtsam) +set(gtsamLib gtsam) +add_library(${moduleName}_python SHARED exportgtsam.cpp ${gtsam_python_srcs}) -file(GLOB base_src "base/*.cpp") -file(GLOB geometry_src "geometry/*.cpp") -file(GLOB inference_src "inference/*.cpp") -file(GLOB linear_src "linear/*.cpp") -file(GLOB nonlinear_src "nonlinear/*.cpp") -file(GLOB slam_src "slam/*.cpp") -file(GLOB symbolic_src "symbolic/*.cpp") +set_target_properties(${moduleName}_python PROPERTIES + OUTPUT_NAME ${moduleName}_python + CLEAN_DIRECT_OUTPUT 1) -#wrap_python("base" ${PROJECT_SOURCE_DIR}/python/${PROJECT_NAME} ${base_src}) -wrap_python("pygtsam" ${PROJECT_SOURCE_DIR}/python/gtsam exportgtsam.cpp - ${geometry_src} ${linear_src} ${nonlinear_src} ${slam_src}) -#wrap_python("nonlinear" ${PROJECT_SOURCE_DIR}/python/gtsam ${nonlinear_src}) -#wrap_python("slam" ${PROJECT_SOURCE_DIR}/python/gtsam ${slam_src}) -#add_python_export_library(${PROJECT_NAME}_test ${PROJECT_SOURCE_DIR}/python/${PROJECT_NAME} -# ${AUTOGEN_TEST_FILES} -#) \ No newline at end of file +target_link_libraries(${moduleName}_python ${Boost_PYTHON_LIBRARY} ${PYTHON_LIBRARY} ${gtsamLib}) #temp + +# On OSX and Linux, the python library must end in the extension .so. Build this +# filename here. +get_property(PYLIB_OUTPUT_FILE TARGET ${moduleName}_python PROPERTY LOCATION) +set(PYLIB_OUTPUT_FILE $) +get_filename_component(PYLIB_OUTPUT_NAME ${PYLIB_OUTPUT_FILE} NAME_WE) +set(PYLIB_SO_NAME lib${moduleName}_python.so) + +# Installs the library in the gtsam folder, which is used by setup.py to create the gtsam package +set(PYTHON_MODULE_DIRECTORY ${CMAKE_SOURCE_DIR}/python/gtsam) +# Cause the library to be output in the correct directory. +add_custom_command(TARGET ${moduleName}_python + POST_BUILD + COMMAND cp -v ${PYLIB_OUTPUT_FILE} ${PYTHON_MODULE_DIRECTORY}/${PYLIB_SO_NAME} + WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} + COMMENT "Copying library files to python directory" ) diff --git a/python/handwritten/exportgtsam.cpp b/python/handwritten/exportgtsam.cpp index 51e0ae1f3..3799ef584 100644 --- a/python/handwritten/exportgtsam.cpp +++ b/python/handwritten/exportgtsam.cpp @@ -45,7 +45,7 @@ typedef gtsam::BetweenFactor Pose2BetweenFactor; //-----------------------------------// -BOOST_PYTHON_MODULE(libgtsam){ +BOOST_PYTHON_MODULE(libgtsam_python){ using namespace boost::python; exportPoint2(); exportRot2(); diff --git a/python/handwritten/geometry/Point2.cpp b/python/handwritten/geometry/Point2.cpp index 0d1e7092b..9e1a4d6b8 100644 --- a/python/handwritten/geometry/Point2.cpp +++ b/python/handwritten/geometry/Point2.cpp @@ -15,9 +15,9 @@ void exportPoint2(){ .def("print", &Point2::print, print_overloads(args("s"))) .def("equals", &Point2::equals, equals_overloads(args("q","tol"))) .def("inverse", &Point2::inverse) - .def("compose", &Point2::compose, compose_overloads(args("q", "H1", "H2"))) + // .def("compose", &Point2::compose, compose_overloads(args("q", "H1", "H2"))) .def("between", &Point2::between) - .def("dim", &Point2::dim) + // .def("dim", &Point2::dim) .def("retract", &Point2::retract) .def("x", &Point2::x) .def("y", &Point2::y) diff --git a/python/handwritten/geometry/Pose2.cpp b/python/handwritten/geometry/Pose2.cpp index 577a8da2c..133a6f05f 100644 --- a/python/handwritten/geometry/Pose2.cpp +++ b/python/handwritten/geometry/Pose2.cpp @@ -17,15 +17,15 @@ BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(range_overloads, Pose2::range, 1, 3) void exportPose2(){ - double (Pose2::*range1)(const Pose2&, boost::optional, boost::optional) const - = &Pose2::range; - double (Pose2::*range2)(const Point2&, boost::optional, boost::optional) const - = &Pose2::range; + // double (Pose2::*range1)(const Pose2&, boost::optional, boost::optional) const + // = &Pose2::range; + // double (Pose2::*range2)(const Point2&, boost::optional, boost::optional) const + // = &Pose2::range; - Rot2 (Pose2::*bearing1)(const Pose2&, boost::optional, boost::optional) const - = &Pose2::bearing; - Rot2 (Pose2::*bearing2)(const Point2&, boost::optional, boost::optional) const - = &Pose2::bearing; + // Rot2 (Pose2::*bearing1)(const Pose2&, boost::optional, boost::optional) const + // = &Pose2::bearing; + // Rot2 (Pose2::*bearing2)(const Point2&, boost::optional, boost::optional) const + // = &Pose2::bearing; class_("Pose2", init<>()) .def(init()) @@ -34,11 +34,11 @@ void exportPose2(){ .def("print", &Pose2::print, print_overloads(args("s"))) .def("equals", &Pose2::equals, equals_overloads(args("pose","tol"))) - .def("inverse", &Pose2::inverse) - .def("compose", &Pose2::compose, compose_overloads(args("p2", "H1", "H2"))) - .def("between", &Pose2::between, between_overloads(args("p2", "H1", "H2"))) - .def("dim", &Pose2::dim) - .def("retract", &Pose2::retract) + // .def("inverse", &Pose2::inverse) + // .def("compose", &Pose2::compose, compose_overloads(args("p2", "H1", "H2"))) + // .def("between", &Pose2::between, between_overloads(args("p2", "H1", "H2"))) + // .def("dim", &Pose2::dim) + // .def("retract", &Pose2::retract) .def("transform_to", &Pose2::transform_to, transform_to_overloads(args("point", "H1", "H2"))) @@ -55,12 +55,12 @@ void exportPose2(){ .def("translation", &Pose2::translation, return_value_policy()) .def("rotation", &Pose2::rotation, return_value_policy()) - .def("bearing", bearing1, bearing_overloads()) - .def("bearing", bearing2, bearing_overloads()) + // .def("bearing", bearing1, bearing_overloads()) + // .def("bearing", bearing2, bearing_overloads()) // Function overload example - .def("range", range1, range_overloads()) - .def("range", range2, range_overloads()) + // .def("range", range1, range_overloads()) + // .def("range", range2, range_overloads()) .def("Expmap", &Pose2::Expmap) diff --git a/python/handwritten/geometry/Rot2.cpp b/python/handwritten/geometry/Rot2.cpp index 06a6a7072..e79fabd9d 100644 --- a/python/handwritten/geometry/Rot2.cpp +++ b/python/handwritten/geometry/Rot2.cpp @@ -28,11 +28,11 @@ void exportRot2(){ .def("print", &Rot2::print, print_overloads(args("s"))) .def("equals", &Rot2::equals, equals_overloads(args("q","tol"))) - .def("inverse", &Rot2::inverse) - .def("compose", &Rot2::compose, compose_overloads(args("q", "H1", "H2"))) - .def("between", &Rot2::between) - .def("dim", &Rot2::dim) - .def("retract", &Rot2::retract) + // .def("inverse", &Rot2::inverse) + // .def("compose", &Rot2::compose, compose_overloads(args("q", "H1", "H2"))) + // .def("between", &Rot2::between) + // .def("dim", &Rot2::dim) + // .def("retract", &Rot2::retract) .def("Expmap", &Rot2::Expmap) .staticmethod("Expmap")