diff --git a/doxygen/EmbendedPython.dox b/doxygen/EmbendedPython.dox index 658f9a240c4e..fff6bf136720 100644 --- a/doxygen/EmbendedPython.dox +++ b/doxygen/EmbendedPython.dox @@ -3,7 +3,7 @@ namespace MR { /** \page EmbendedPythonOverview Python overview Python is one of the most popular and widely used programming language in scientific researches, machine learning, data analysis and advanced testing.\n -\b Requires \b python \b 3.10 (3.9 on linux) +\b Requires \b python \b 3.10 (3.8 on Ubuntu 20.04) MeshLib library allows you to call python scripts directly from the command line or use particular functions by `import mrmeshpy`. @@ -20,11 +20,13 @@ MeshLib provides several usage options\n \code import mrmeshpy -mesh = mrmeshpy.load_mesh("mesh.stl") +expMesh = mrmeshpy.loadMesh(mrmeshpy.Path("mesh.stl")) +assert(expMesh.has_value()) +mesh = expMesh.value() # ... # some mesh modifications can be perform here # ... -mrmeshpy.save_mesh("mesh.ply") +mrmeshpy.saveMesh(mesh, mrmeshpy.Path("mesh.ply")) \endcode 2. Run scritp with MeshInspector executable file (MeshInspector.exe on windows or ./MRApp on linux) \code diff --git a/doxygen/HowToExamples.dox b/doxygen/HowToExamples.dox index 109d83fce1e4..db687a68ed0d 100644 --- a/doxygen/HowToExamples.dox +++ b/doxygen/HowToExamples.dox @@ -135,14 +135,17 @@ In this section we provide the same examples but with python code\n Load and save example: \code import mrmeshpy -mesh = mrmeshpy.load_mesh("mesh.stl") -mrmeshpy.save_mesh("mesh.ply") +expectedMesh = mrmeshpy.loadMesh(mrmeshpy.Path("mesh.stl")) +if expectedMesh.has_value(): + mrmeshpy.saveMesh(expectedMesh.value(),mrmeshpy.Path("mesh.ply")) \endcode Mesh modification examples \code import mrmeshpy -mesh = mrmeshpy.load_mesh("mesh.stl") +expectedMesh = mrmeshpy.loadMesh(mrmeshpy.Path("mesh.stl")) +assert(expectedMesh.has_value()) +mesh = expectedMesh.value() relaxParams = mrmeshpy.MeshRelaxParams() relaxParams.iterations = 5 @@ -150,11 +153,11 @@ mrmeshpy.relax(mesh, relaxParams) props = mrmeshpy.SubdivideSettings() props.maxDeviationAfterFlip = 0.5 -mrmeshpy.subdivide_mesh(mesh,props) +mrmeshpy.subdivideMesh(mesh,props) -plusZ = mrmeshpy.Vector3() +plusZ = mrmeshpy.Vector3f() plusZ.z = 1.0 -rotationXf = mrmeshpy.AffineXf3.linear( mrmeshpy.Matrix3.rotation( plusZ, 3.1415*0.5 ) ) +rotationXf = mrmeshpy.AffineXf3f.linear( mrmeshpy.Matrix3f.rotation( plusZ, 3.1415*0.5 ) ) mesh.transform(rotationXf) \endcode diff --git a/python_scripts/test_script.py b/python_scripts/test_script.py index 38ae3a11e73a..f646a3c04b36 100644 --- a/python_scripts/test_script.py +++ b/python_scripts/test_script.py @@ -1,9 +1,9 @@ print('Import mrmesh') -import meshlib.mrmeshpy as mrmesh +import mrmeshpy as mrmesh print('Start test script') -mesh = mrmesh.loadMesh("M:\\sectioning\\sectioning\\468\\Final Output\\P523468_101_OtherFiles\\stitched.mrmesh") +mesh = mrmesh.loadMesh(mrmesh.Path("M:\\sectioning\\sectioning\\468\\Final Output\\P523468_101_OtherFiles\\stitched.mrmesh")).value() holes = mesh.topology.findHoleRepresentiveEdges() vec3 = mrmesh.Vector3f(); vec3.z = 1.0; diff --git a/source/MRMesh/MRPython.h b/source/MRMesh/MRPython.h index 185ebd723397..54ab0defd31e 100644 --- a/source/MRMesh/MRPython.h +++ b/source/MRMesh/MRPython.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include #include @@ -45,6 +46,16 @@ MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name, [] (pybind11::module_& m)\ def( "clear", &vecType::clear ); \ } ) +#define MR_ADD_PYTHON_EXPECTED( moduleName, name, type, errorType )\ +MR_ADD_PYTHON_CUSTOM_DEF( moduleName, name, [] (pybind11::module_& m)\ +{\ + using expectedType = tl::expected;\ + pybind11::class_(m, #name ).\ + def( "has_value", &expectedType::has_value ).\ + def( "value", ( type& ( expectedType::* )( )& )& expectedType::value, pybind11::return_value_policy::reference ).\ + def( "error", ( const errorType& ( expectedType::* )( )const& )& expectedType::error );\ +} ) + enum StreamType { Stdout, diff --git a/source/mrmeshpy/MRPythonBaseExposing.cpp b/source/mrmeshpy/MRPythonBaseExposing.cpp index a388939d8717..8bee7305851f 100644 --- a/source/mrmeshpy/MRPythonBaseExposing.cpp +++ b/source/mrmeshpy/MRPythonBaseExposing.cpp @@ -15,9 +15,25 @@ #include "MRMesh/MREdgePaths.h" #include "MRMesh/MRFillContour.h" #include "MRMesh/MRExpandShrink.h" +#include "MRMesh/MRColor.h" +#include MR_INIT_PYTHON_MODULE( mrmeshpy ) +MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, ExpectedVoid, []( pybind11::module_& m )\ +{ + using expectedType = tl::expected; + pybind11::class_( m, "ExpectedVoid" ). + def( "has_value", &expectedType::has_value ). + def( "error", ( const std::string& ( expectedType::* )( )const& )& expectedType::error ); +} ) + +MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, Path, [] ( pybind11::module_& m ) +{ + pybind11::class_( m, "Path" ). + def( pybind11::init() ); +} ) + MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, Box3f, [] ( pybind11::module_& m ) { pybind11::class_( m, "Box3f", "Box given by its min- and max- corners" ). @@ -71,6 +87,21 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, Vector2f, [] ( pybind11::module_& m ) def( "normalized", &MR::Vector2f::normalized ); } ) +MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, Color, [] ( pybind11::module_& m ) +{ + pybind11::class_( m, "Color" ). + def( pybind11::init<>() ). + def( pybind11::init(), + pybind11::arg( "r" ), pybind11::arg( "g" ), pybind11::arg( "b" ), pybind11::arg( "a" ) = 255 ). + def( pybind11::init(), + pybind11::arg( "r" ), pybind11::arg( "g" ), pybind11::arg( "b" ), pybind11::arg( "a" ) = 1.0f ). + def_readwrite( "r", &MR::Color::r ). + def_readwrite( "r", &MR::Color::g ). + def_readwrite( "r", &MR::Color::b ). + def_readwrite( "r", &MR::Color::a ); +} ) +MR_ADD_PYTHON_VEC( mrmeshpy, vectorColor, MR::Color ) + MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, Vector3f, [] ( pybind11::module_& m ) { pybind11::class_( m, "Vector3f", "three-dimensional vector" ). diff --git a/source/mrmeshpy/MRPythonIO.cpp b/source/mrmeshpy/MRPythonIO.cpp index b7a1ca42e404..64c07ff6c8f7 100644 --- a/source/mrmeshpy/MRPythonIO.cpp +++ b/source/mrmeshpy/MRPythonIO.cpp @@ -1,5 +1,6 @@ #include "MRMesh/MRPython.h" #include +#include #include "MRMesh/MRObjectsAccess.h" #include "MRMesh/MRSceneRoot.h" #include "MRMesh/MRObjectMesh.h" @@ -20,20 +21,6 @@ using namespace MR; -bool pythonSaveMeshToAnyFormat( const Mesh& mesh, const std::string& path ) -{ - auto res = MR::MeshSave::toAnySupportedFormat( mesh, path ); - return res.has_value(); -} - -Mesh pythonLoadMeshFromAnyFormat( const std::string& path ) -{ - auto res = MR::MeshLoad::fromAnySupportedFormat( path ); - if ( res.has_value() ) - return std::move( *res ); - return {}; -} - namespace MR { @@ -120,160 +107,107 @@ class PythonIstreamBuf : public std::streambuf } -Mesh pythonLoadMeshFromAnyFormat( pybind11::object fileHandle, const std::string& extension ) +tl::expected pythonLoadMeshFromAnyFormat( pybind11::object fileHandle, const std::string& extension ) { if ( !( pybind11::hasattr( fileHandle, "read" ) && pybind11::hasattr( fileHandle, "seek" ) && pybind11::hasattr( fileHandle, "tell" ) ) ) - { - spdlog::error( "Argument is not file handle" ); - return {}; - } + return tl::make_unexpected( "Argument is not file handle" ); PythonIstreamBuf streambuf( fileHandle ); std::istream ifs( &streambuf ); - auto res = MR::MeshLoad::fromAnySupportedFormat( ifs, extension ); - if ( res.has_value() ) - return std::move( *res ); - std::cout << res.error() << '\n'; - return {}; + return MR::MeshLoad::fromAnySupportedFormat( ifs, extension ); } -bool pythonSaveMeshToAnyFormat( const Mesh& mesh, const std::string& extension, pybind11::object fileHandle ) +tl::expected pythonSaveMeshToAnyFormat( const Mesh& mesh, const std::string& extension, pybind11::object fileHandle ) { if ( !( pybind11::hasattr( fileHandle, "write" ) && pybind11::hasattr( fileHandle, "flush" ) ) ) - { - spdlog::error( "Argument is not file handle" ); - return false; - } + return tl::make_unexpected( "Argument is not file handle" ); pybind11::detail::pythonbuf pybuf( fileHandle ); std::ostream outfs( &pybuf ); - auto res = MR::MeshSave::toAnySupportedFormat( mesh, outfs, extension ); - return res.has_value(); + return MR::MeshSave::toAnySupportedFormat( mesh, outfs, extension ); } -bool pythonSaveLinesToAnyFormat( const MR::Polyline3& lines, const std::string& path ) -{ - auto res = MR::LinesSave::toAnySupportedFormat( lines, path ); - return res.has_value(); -} - -bool pythonSaveLinesToAnyFormat( const MR::Polyline3& lines, const std::string& extension, pybind11::object fileHandle ) +tl::expected pythonSaveLinesToAnyFormat( const MR::Polyline3& lines, const std::string& extension, pybind11::object fileHandle ) { if ( !( pybind11::hasattr( fileHandle, "write" ) && pybind11::hasattr( fileHandle, "flush" ) ) ) - { - spdlog::error( "Argument is not file handle" ); - return false; - } + return tl::make_unexpected( "Argument is not file handle" ); pybind11::detail::pythonbuf pybuf( fileHandle ); std::ostream outfs( &pybuf ); - auto res = MR::LinesSave::toAnySupportedFormat( lines, outfs, extension ); - return res.has_value(); + return MR::LinesSave::toAnySupportedFormat( lines, outfs, extension ); } -MR::Polyline3 pythonLoadLinesFromAnyFormat( const std::string& path ) -{ - auto res = MR::LinesLoad::fromAnySupportedFormat( path ); - if ( res.has_value() ) - return std::move( *res ); - return {}; -} - -MR::Polyline3 pythonLoadLinesFromAnyFormat( pybind11::object fileHandle, const std::string& extension ) +tl::expected pythonLoadLinesFromAnyFormat( pybind11::object fileHandle, const std::string& extension ) { if ( !( pybind11::hasattr( fileHandle, "read" ) && pybind11::hasattr( fileHandle, "seek" ) && pybind11::hasattr( fileHandle, "tell" ) ) ) - { - spdlog::error( "Argument is not file handle" ); - return {}; - } + return tl::make_unexpected( "Argument is not file handle" ); PythonIstreamBuf streambuf( fileHandle ); std::istream ifs( &streambuf ); - auto res = MR::LinesLoad::fromAnySupportedFormat( ifs, extension ); - if ( res.has_value() ) - return std::move( *res ); - std::cout << res.error() << '\n'; - return {}; -} - -bool pythonSavePointCloudToAnyFormat( const PointCloud& points, const std::string& path ) -{ - auto res = MR::PointsSave::toAnySupportedFormat( points, path ); - return res.has_value(); + return MR::LinesLoad::fromAnySupportedFormat( ifs, extension ); } -bool pythonSavePointCloudToAnyFormat( const PointCloud& points, const std::string& extension, pybind11::object fileHandle ) +tl::expected pythonSavePointCloudToAnyFormat( const PointCloud& points, const std::string& extension, pybind11::object fileHandle ) { if ( !( pybind11::hasattr( fileHandle, "write" ) && pybind11::hasattr( fileHandle, "flush" ) ) ) - { - spdlog::error( "Argument is not file handle" ); - return false; - } + return tl::make_unexpected( "Argument is not file handle" ); pybind11::detail::pythonbuf pybuf( fileHandle ); std::ostream outfs( &pybuf ); - auto res = MR::PointsSave::toAnySupportedFormat( points, outfs, extension ); - return res.has_value(); + return MR::PointsSave::toAnySupportedFormat( points, outfs, extension ); } -PointCloud pythonLoadPointCloudFromAnyFormat( const std::string& path ) -{ - auto res = MR::PointsLoad::fromAnySupportedFormat( path ); - if ( res.has_value() ) - return std::move( *res ); - return {}; -} - -PointCloud pythonLoadPointCloudFromAnyFormat( pybind11::object fileHandle, const std::string& extension ) +tl::expected pythonLoadPointCloudFromAnyFormat( pybind11::object fileHandle, const std::string& extension ) { if ( !( pybind11::hasattr( fileHandle, "read" ) && pybind11::hasattr( fileHandle, "seek" ) && pybind11::hasattr( fileHandle, "tell" ) ) ) - { - spdlog::error( "Argument is not file handle" ); - return {}; - } + return tl::make_unexpected( "Argument is not file handle" ); PythonIstreamBuf streambuf( fileHandle ); std::istream ifs( &streambuf ); - auto res = MR::PointsLoad::fromAnySupportedFormat( ifs, extension ); - if ( res.has_value() ) - return std::move( *res ); - std::cout << res.error() << '\n'; - return {}; + return MR::PointsLoad::fromAnySupportedFormat( ifs, extension ); } MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, SaveMesh, [] ( pybind11::module_& m ) { - m.def( "saveMesh", ( bool( * )( const MR::Mesh&, const std::string& ) )& pythonSaveMeshToAnyFormat, - pybind11::arg( "mesh" ), pybind11::arg( "path" ), "saves mesh in file of known format/extension" ); - m.def( "saveMesh", ( bool( * )( const MR::Mesh&, const std::string&, pybind11::object ) )& pythonSaveMeshToAnyFormat, + m.def( "saveMesh", + ( tl::expected( * )( const MR::Mesh&, const std::filesystem::path&, const Vector*, ProgressCallback ) )& MR::MeshSave::toAnySupportedFormat, + pybind11::arg( "mesh" ), pybind11::arg( "path" ), pybind11::arg( "colors" ) = nullptr, pybind11::arg( "callback" ) = ProgressCallback{}, + "detects the format from file extension and save mesh to it" ); + m.def( "saveMesh", ( tl::expected( * )( const MR::Mesh&, const std::string&, pybind11::object ) )& pythonSaveMeshToAnyFormat, pybind11::arg( "mesh" ), pybind11::arg( "extension" ), pybind11::arg( "fileHandle" ), "saves mesh in python file handler, second arg: extension (`*.ext` format)" ); } ) MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, LoadMesh, [] ( pybind11::module_& m ) { - m.def( "loadMesh", ( MR::Mesh( * )( const std::string& ) )& pythonLoadMeshFromAnyFormat, - pybind11::arg( "path" ), "load mesh of known format" ); - m.def( "loadMesh", ( MR::Mesh( * )( pybind11::object, const std::string& ) )& pythonLoadMeshFromAnyFormat, + m.def( "loadMesh", + ( tl::expected( * )( const std::filesystem::path&, Vector*, ProgressCallback ) )& MR::MeshLoad::fromAnySupportedFormat, + pybind11::arg( "path" ), pybind11::arg( "colors" ) = nullptr, pybind11::arg( "callback" ) = ProgressCallback{}, + "detects the format from file extension and loads mesh from it" ); + m.def( "loadMesh", ( tl::expected( * )( pybind11::object, const std::string& ) )& pythonLoadMeshFromAnyFormat, pybind11::arg( "fileHandle" ), pybind11::arg( "extension" ), "load mesh from python file handler, second arg: extension (`*.ext` format)" ); } ) MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, SaveLines, [] ( pybind11::module_& m ) { - m.def( "saveLines", ( bool( * )( const MR::Polyline3&, const std::string& ) )& pythonSaveLinesToAnyFormat, - pybind11::arg( "polyline" ), pybind11::arg( "path" ), "saves lines in file of known format/extension" ); - m.def( "saveLines", ( bool( * )( const MR::Polyline3&, const std::string&, pybind11::object ) )& pythonSaveLinesToAnyFormat, + m.def( "saveLines", ( tl::expected( * )( const MR::Polyline3&, const std::filesystem::path&, ProgressCallback ) )& MR::LinesSave::toAnySupportedFormat, + pybind11::arg( "polyline" ), pybind11::arg( "path" ), pybind11::arg( "callback" ) = ProgressCallback{}, + "detects the format from file extension and saves polyline in it" ); + m.def( "saveLines", ( tl::expected( * )( const MR::Polyline3&, const std::string&, pybind11::object ) )& pythonSaveLinesToAnyFormat, pybind11::arg( "polyline" ), pybind11::arg( "extension" ), pybind11::arg( "fileHandle" ), "saves lines in python file handler, second arg: extension (`*.ext` format)" ); } ) MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, LoadLines, [] ( pybind11::module_& m ) { - m.def( "loadLines", ( MR::Polyline3( * )( const std::string& ) )& pythonLoadLinesFromAnyFormat, - pybind11::arg( "path" ), "load lines of known format" ); - m.def( "loadLines", ( MR::Polyline3( * )( pybind11::object, const std::string& ) )& pythonLoadLinesFromAnyFormat, + m.def( "loadLines", ( tl::expected( * )( const std::filesystem::path&, ProgressCallback ) )& MR::LinesLoad::fromAnySupportedFormat, + pybind11::arg( "path" ), pybind11::arg( "callback" ) = ProgressCallback{}, + "detects the format from file extension and loads polyline from it" ); + m.def( "loadLines", ( tl::expected( * )( pybind11::object, const std::string& ) )& pythonLoadLinesFromAnyFormat, pybind11::arg( "fileHandle" ), pybind11::arg( "extension" ), "load lines from python file handler, second arg: extension (`*.ext` format)" ); } ) MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, SavePoints, [] ( pybind11::module_& m ) { - m.def( "savePoints", ( bool( * )( const MR::PointCloud&, const std::string& ) )& pythonSavePointCloudToAnyFormat, - pybind11::arg( "pointCloud" ), pybind11::arg( "path" ), "saves point cloud in file of known format/extension" ); - m.def( "savePoints", ( bool( * )( const MR::PointCloud&, const std::string&, pybind11::object ) )& pythonSavePointCloudToAnyFormat, + m.def( "savePoints", ( tl::expected( * )( const MR::PointCloud&, const std::filesystem::path&, const Vector*, ProgressCallback ) )& MR::PointsSave::toAnySupportedFormat, + pybind11::arg( "pointCloud" ), pybind11::arg( "path" ), pybind11::arg( "colors" ) = nullptr, pybind11::arg( "callback" ) = ProgressCallback{}, + "detects the format from file extension and save points to it" ); + m.def( "savePoints", ( tl::expected( * )( const MR::PointCloud&, const std::string&, pybind11::object ) )& pythonSavePointCloudToAnyFormat, pybind11::arg( "pointCloud" ), pybind11::arg( "extension" ), pybind11::arg( "fileHandle" ), "saves point cloud in python file handler, second arg: extension (`*.ext` format)" ); } ) MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, LoadPoints, [] ( pybind11::module_& m ) { - m.def( "loadPoints", ( MR::PointCloud( * )( const std::string& ) )& pythonLoadPointCloudFromAnyFormat, - pybind11::arg( "path" ), "load point cloud of known format" ); - m.def( "loadPoints", ( MR::PointCloud( * )( pybind11::object, const std::string& ) )& pythonLoadPointCloudFromAnyFormat, + m.def( "loadPoints", ( tl::expected( * )( const std::filesystem::path&, Vector*, ProgressCallback ) )& MR::PointsLoad::fromAnySupportedFormat, + pybind11::arg( "path" ), pybind11::arg( "colors" ) = nullptr, pybind11::arg( "callback" ) = ProgressCallback{}, + "detects the format from file extension and loads points from it" ); + m.def( "loadPoints", ( tl::expected( * )( pybind11::object, const std::string& ) )& pythonLoadPointCloudFromAnyFormat, pybind11::arg( "fileHandle" ), pybind11::arg( "extension" ), "load point cloud from python file handler, second arg: extension (`*.ext` format)" ); } ) diff --git a/source/mrmeshpy/MRPythonMeshExposing.cpp b/source/mrmeshpy/MRPythonMeshExposing.cpp index 5999ffc3e800..53a16674428f 100644 --- a/source/mrmeshpy/MRPythonMeshExposing.cpp +++ b/source/mrmeshpy/MRPythonMeshExposing.cpp @@ -97,6 +97,10 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, Vector, [] ( pybind11::module_& m ) pybind11::class_>( m, "VertCoords2" ). def( pybind11::init<>() ). def_readwrite( "vec", &MR::Vector::vec_ ); + + pybind11::class_>( m, "VertColorMap" ). + def( pybind11::init<>() ). + def_readwrite( "vec", &MR::Vector::vec_ ); } ) MR::MeshTopology topologyFromTriangles( const Triangulation& t, const MeshBuilder::BuildSettings& s ) @@ -168,6 +172,8 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, Mesh, [] ( pybind11::module_& m ) m.def( "copyMesh", &pythonCopyMeshFunction, pybind11::arg( "mesh" ), "returns copy of input mesh" ); } ) +MR_ADD_PYTHON_EXPECTED( mrmeshpy, ExpectedMesh, MR::Mesh, std::string ) + MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, MeshPart, [] ( pybind11::module_& m ) { pybind11::class_( m, "MeshPart", "stores reference on whole mesh (if region is nullptr) or on its part (if region pointer is valid)" ). diff --git a/source/mrmeshpy/MRPythonMeshPlugins.cpp b/source/mrmeshpy/MRPythonMeshPlugins.cpp index fcf9195f92a5..5bb76a549ac8 100644 --- a/source/mrmeshpy/MRPythonMeshPlugins.cpp +++ b/source/mrmeshpy/MRPythonMeshPlugins.cpp @@ -24,6 +24,7 @@ #include "MRMesh/MRFaceFace.h" #include "MRMesh/MRLaplacian.h" #include "MRMesh/MRMeshFixer.h" +#include #include using namespace MR; @@ -212,11 +213,8 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, Relax, [] ( pybind11::module_& m ) def( pybind11::init<>() ). def_readwrite( "hardSmoothTetrahedrons", &MeshRelaxParams::hardSmoothTetrahedrons, "smooth tetrahedron verts (with complete three edges ring) to base triangle (based on its edges destinations)" ); - m.def( "relax", [] ( Mesh& mesh, const MeshRelaxParams& params ) - { - return relax( mesh, params ); // lambda to skip progress callback parameter - }, - pybind11::arg( "mesh" ), pybind11::arg( "params" ) = MeshRelaxParams{}, + m.def( "relax", ( bool( * )( Mesh&, const MeshRelaxParams&, ProgressCallback ) )& relax, + pybind11::arg( "mesh" ), pybind11::arg( "params" ) = MeshRelaxParams{}, pybind11::arg( "cb" ) = ProgressCallback{}, "applies given number of relaxation iterations to the whole mesh ( or some region if it is specified )\n" "return true if was finished successfully, false if was interrupted by progress callback"); } ) @@ -250,21 +248,6 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, SubdivideSettings, [] ( pybind11::module_& m } ) - -// Distance Map -void saveDistanceMapToImageSimple( const DistanceMap& dm, const std::string& filename, float threshold ) -{ - saveDistanceMapToImage( dm, filename, threshold ); -} - -DistanceMap loadDistanceMapFromImageSimple( const std::string& path, float threshold ) -{ - auto res = loadDistanceMapFromImage( path, threshold ); - if ( res.has_value() ) - return std::move( *res ); - return DistanceMap(); -} - // Distance Map MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, DistanceMap, [] ( pybind11::module_& m ) { @@ -325,7 +308,7 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, DistanceMap, [] ( pybind11::module_& m ) m.def( "distanceMapToMesh", &MR::distanceMapToMesh, pybind11::arg( "mp" ), pybind11::arg( "params" ), "converts distance map back to the mesh fragment with presented params" ); - m.def( "saveDistanceMapToImage", &saveDistanceMapToImageSimple, + m.def( "saveDistanceMapToImage", &MR::saveDistanceMapToImage, pybind11::arg( "distMap" ), pybind11::arg( "filename" ), pybind11::arg( "threshold" ) = 1.0f / 255.0f, "saves distance map to monochrome image in scales of gray:\n" "\tthreshold - threshold of maximum values [0.; 1.]. invalid pixel set as 0. (black)\n" @@ -333,7 +316,7 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, DistanceMap, [] ( pybind11::module_& m ) "maximum (far): threshold\n" "invalid (infinity): 0.0 (black)" ); - m.def( "loadDistanceMapFromImage", &loadDistanceMapFromImageSimple, + m.def( "loadDistanceMapFromImage", &loadDistanceMapFromImage, pybind11::arg( "filename" ), pybind11::arg( "threshold" ) = 1.0f / 255.0f, "load distance map from monochrome image file\n" "\tthreshold - threshold of valid values [0.; 1.]. pixel with color less then threshold set invalid" ); @@ -351,6 +334,8 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, DistanceMap, [] ( pybind11::module_& m ) } ) +MR_ADD_PYTHON_EXPECTED( mrmeshpy, ExpectedDistanceMap, DistanceMap, std::string ) + // Position Verts Smooth MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, LaplacianEdgeWeightsParam, [] ( pybind11::module_& m ) { diff --git a/source/mrmeshpy/MRPythonPointCloudExposing.cpp b/source/mrmeshpy/MRPythonPointCloudExposing.cpp index 3cb202b414eb..02b1c41af95f 100644 --- a/source/mrmeshpy/MRPythonPointCloudExposing.cpp +++ b/source/mrmeshpy/MRPythonPointCloudExposing.cpp @@ -4,6 +4,7 @@ #include "MRMesh/MRMeshToPointCloud.h" #include "MRMesh/MRBox.h" #include +#include MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, PointCloud, [] ( pybind11::module_& m ) { @@ -28,11 +29,8 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, PointCloud, [] ( pybind11::module_& m ) "Critical length of hole (all holes with length less then this value will be filled)\n" "If value is subzero it is set automaticly to 0.7*bbox.diagonal()" ); - m.def( "triangulatePointCloud", [] ( const MR::PointCloud& pointCloud, const MR::TriangulationParameters& params ) - { - return MR::triangulatePointCloud( pointCloud, params ); // lambda to handle progress callback parameter - }, - pybind11::arg( "pointCloud" ), pybind11::arg( "params" ) = MR::TriangulationParameters{}, + m.def( "triangulatePointCloud", &MR::triangulatePointCloud, + pybind11::arg( "pointCloud" ), pybind11::arg( "params" ) = MR::TriangulationParameters{}, pybind11::arg( "progressCb" ) = MR::ProgressCallback{}, "Creates mesh from given point cloud according params\n" "Returns empty optional if was interrupted by progress bar" ); @@ -41,3 +39,4 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, PointCloud, [] ( pybind11::module_& m ) "Mesh to PointCloud" ); } ) +MR_ADD_PYTHON_EXPECTED( mrmeshpy, ExpectedPointCloud, MR::PointCloud, std::string ) diff --git a/source/mrmeshpy/MRPythonPolyline.cpp b/source/mrmeshpy/MRPythonPolyline.cpp index cc47d6556f07..03c92a35858f 100644 --- a/source/mrmeshpy/MRPythonPolyline.cpp +++ b/source/mrmeshpy/MRPythonPolyline.cpp @@ -87,6 +87,9 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, Polyline##dimension, []( pybind11::module_& MR_ADD_PYTHON_POLYLINE(2) MR_ADD_PYTHON_POLYLINE(3) +MR_ADD_PYTHON_EXPECTED( mrmeshpy, ExpectedPolyline2, MR::Polyline2, std::string ) +MR_ADD_PYTHON_EXPECTED( mrmeshpy, ExpectedPolyline3, MR::Polyline3, std::string ) + MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, PlanarTriangulation, [] ( pybind11::module_& m ) { m.def( "triangulateContours", ( MR::Mesh( * )( const MR::Contours2f&, bool ) )& MR::PlanarTriangulation::triangulateContours, diff --git a/test_python/test_distanceMap.py b/test_python/test_distanceMap.py index 24e1b0fdbcb8..af463d7514f8 100644 --- a/test_python/test_distanceMap.py +++ b/test_python/test_distanceMap.py @@ -6,7 +6,7 @@ def test_distanceMap(): R1 = 2 R2 = 1 torus = mrmesh.makeTorus(R1, R2, 10, 10, None) - mrmesh.saveMesh(torus, "c:/temp/testTorus_dm.stl") + mrmesh.saveMesh(torus, mrmesh.Path("c:/temp/testTorus_dm.stl")) params = mrmesh.MeshToDistanceMapParams() params.resolution.x = 20