Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions source/MRMesh/MRICP.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,9 @@ class MeshICP
{
public:
// xf parameters should represent current transformations of meshes
// initMeshXf transform from the local mesh basis to the global.
// refMeshXf transform from the local refMesh basis to the global
// calculateTransform returns new mesh transformation to the global frame, which matches refMesh in the global frame
// bitset allows to take exact set of vertices from the mesh
// fltMeshXf transform from the local floatingMesh basis to the global
// refMeshXf transform from the local referenceMesh basis to the global
// floatingMeshBitSet allows to take exact set of vertices from the mesh
MRMESH_API MeshICP(const MeshPart& floatingMesh, const MeshPart& referenceMesh, const AffineXf3f& fltMeshXf, const AffineXf3f& refMeshXf,
const VertBitSet& floatingMeshBitSet);
MRMESH_API MeshICP(const MeshPart& floatingMesh, const MeshPart& referenceMesh, const AffineXf3f& fltMeshXf, const AffineXf3f& refMeshXf,
Expand All @@ -106,7 +105,7 @@ class MeshICP
const std::vector<VertPair>& getVertPairs() const { return vertPairs_; } // used to visualize generated points pairs
MRMESH_API std::pair<float, float> getDistLimitsSq() const; // finds squared minimum and maximum pairs distances

//returns new xf transformation for the floating mesh, which allows to match reference mesh
// returns new xf transformation for the floating mesh, which allows to match reference mesh
MRMESH_API AffineXf3f calculateTransformation();

private:
Expand Down
42 changes: 42 additions & 0 deletions source/mrmeshpy/MRPythonMeshExposing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, MeshTopology, [] ( pybind11::module_& m )
def( "findBoundaryFaces", &MR::MeshTopology::findBoundaryFaces, "returns all boundary faces, having at least one boundary edge" ).
def( "findBoundaryEdges", &MR::MeshTopology::findBoundaryEdges, "returns all boundary edges, where each edge does not have valid left face" ).
def( "findBoundaryVerts", &MR::MeshTopology::findBoundaryVerts, "returns all boundary vertices, incident to at least one boundary edge" ).
def( "deleteFaces", &MR::MeshTopology::deleteFaces, pybind11::arg( "fs" ), "deletes multiple given faces" ).
def( "findBoundary", &MR::MeshTopology::findBoundary, pybind11::arg( "region" ) = nullptr,
"returns all boundary loops, where each edge has region face to the right and does not have valid or in-region left face;\n"
"unlike findRegionBoundary this method returns loops in opposite orientation" ).
Expand Down Expand Up @@ -237,6 +238,10 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, FillHole, [] ( pybind11::module_& m )
m.def( "getEdgeLengthFillMetric", &MR::getEdgeLengthFillMetric, pybind11::arg( "mesh" ),
"Simple metric minimizing the sum of all edge lengths" );

m.def( "getEdgeLengthStitchMetric", &MR::getEdgeLengthStitchMetric, pybind11::arg( "mesh" ),
"Forbids connecting vertices from the same hole\n"
"Simple metric minimizing edge length" );

m.def( "getCircumscribedMetric", &MR::getCircumscribedMetric, pybind11::arg( "mesh" ),
"This metric minimizes the sum of circumcircle radii for all triangles in the triangulation.\n"
"It is rather fast to calculate, and it results in typically good triangulations." );
Expand All @@ -251,6 +256,13 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, FillHole, [] ( pybind11::module_& m )
def_readwrite( "maxPolygonSubdivisions", &MR::FillHoleParams::maxPolygonSubdivisions, "The maximum number of polygon subdivisions on a triangle and two smaller polygons,\n""must be 2 or larger" ).
def_readwrite( "outNewFaces", &MR::FillHoleParams::outNewFaces, "If not nullptr accumulate new faces" );

pybind11::class_<MR::StitchHolesParams>( m, "StitchHolesParams", "Structure has some options to control buildCylinderBetweenTwoHoles" ).
def( pybind11::init<>() ).
def_readwrite( "metric", &StitchHolesParams::metric,
"Specifies triangulation metric\n"
"default for buildCylinderBetweenTwoHoles: getComplexStitchMetric").
def_readwrite( "outNewFaces", &StitchHolesParams::outNewFaces, "If not nullptr accumulate new faces" );

m.def( "fillHole", &MR::fillHole,
pybind11::arg( "mesh" ), pybind11::arg( "a" ), pybind11::arg( "params" ) = MR::FillHoleParams{},
"Fills given hole represented by one of its edges (having no valid left face),\n"
Expand All @@ -259,6 +271,19 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, FillHole, [] ( pybind11::module_& m )
"\tmesh - mesh with hole\n"
"\ta - EdgeId which represents hole\n"
"\tparams - parameters of hole filling" );

m.def( "buildCylinderBetweenTwoHoles", ( void ( * )( Mesh&, EdgeId, EdgeId, const StitchHolesParams& ) )& MR::buildCylinderBetweenTwoHoles,
pybind11::arg( "mesh" ), pybind11::arg( "a" ), pybind11::arg( "b" ), pybind11::arg( "params" ) = MR::StitchHolesParams{},
"Build cylindrical patch to fill space between two holes represented by one of their edges each,\n"
"default metric: ComplexStitchMetric\n"
"\tmesh - mesh with hole\n"
"\ta - EdgeId which represents 1st hole\n"
"\tb - EdgeId which represents 2nd hole\n"
"\tparams - parameters of holes stitching" );

m.def( "buildCylinderBetweenTwoHoles", ( bool ( * )( Mesh&, const StitchHolesParams& ) )& MR::buildCylinderBetweenTwoHoles,
pybind11::arg( "mesh" ), pybind11::arg( "params" ) = MR::StitchHolesParams{},
"this version finds holes in the mesh by itself and returns false if they are not found" );
} )

Mesh pythonMergeMehses( const pybind11::list& meshes )
Expand Down Expand Up @@ -345,5 +370,22 @@ MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, SimpleFunctions, [] ( pybind11::module_& m )
"creates torus with empty sectors\n"
"main application - testing Components" );


pybind11::class_<MR::FaceFace>( m, "FaceFace" ).
def( pybind11::init<>() ).
def( pybind11::init<FaceId, FaceId>(), pybind11::arg( "a" ), pybind11::arg( "b" ) ).
def_readwrite( "aFace", &MR::FaceFace::aFace ).
def_readwrite( "bFace", &MR::FaceFace::bFace );

m.def( "findSelfCollidingTriangles", &MR::findSelfCollidingTriangles, pybind11::arg( "mp" ), "finds all pairs of colliding triangles from one mesh or a region" );

m.def( "findSelfCollidingTrianglesBS", &MR::findSelfCollidingTrianglesBS, pybind11::arg( "mp" ), "finds union of all self-intersecting faces" );

m.def( "findCollidingTriangles", &MR::findCollidingTriangles,
pybind11::arg( "a" ), pybind11::arg( "b" ), pybind11::arg( "rigidB2A" ) = nullptr, pybind11::arg( "firstIntersectionOnly" ) = false,
"finds all pairs of colliding triangles from two meshes or two mesh regions\n"
"\trigidB2A - rigid transformation from B-mesh space to A mesh space, nullptr considered as identity transformation\n"
"\tfirstIntersectionOnly - if true then the function returns at most one pair of intersecting triangles and returns faster" );
} )

MR_ADD_PYTHON_VEC( mrmeshpy, vectorFaceFace, MR::FaceFace )
106 changes: 61 additions & 45 deletions source/mrmeshpy/MRPythonMeshICPExposing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,59 +21,75 @@ bool operator == ( const VertPair& a, const VertPair& b )
MR_ADD_PYTHON_CUSTOM_DEF( mrmeshpy, ICPExposing, [] ( pybind11::module_& m )
{
pybind11::enum_<MR::ICPMethod>( m, "ICPMethod" ).
value( "Combined", MR::ICPMethod::Combined ).
value( "PointToPoint", MR::ICPMethod::PointToPoint ).
value( "PointToPlane", MR::ICPMethod::PointToPlane );
value( "Combined", MR::ICPMethod::Combined, "PointToPoint for the first 2 iterations, PointToPlane then" ).
value( "PointToPoint", MR::ICPMethod::PointToPoint, "use it in the cases with big differences, takes more iterations" ).
value( "PointToPlane", MR::ICPMethod::PointToPlane, "finds solution faster in fewer iterations" );

pybind11::enum_<MR::ICPMode>( m, "ICPMode" ).
value( "AnyRigidXf", MR::ICPMode::AnyRigidXf ).
value( "OrthogonalAxis", MR::ICPMode::OrthogonalAxis ).
value( "FixedAxis", MR::ICPMode::FixedAxis ).
value( "TranslationOnly", MR::ICPMode::TranslationOnly );
pybind11::enum_<MR::ICPMode>( m, "ICPMode", "You could fix any axis(axes) of rotation by using this modes" ).
value( "AnyRigidXf", MR::ICPMode::AnyRigidXf, "all 6 degrees of freedom (dof)" ).
value( "OrthogonalAxis", MR::ICPMode::OrthogonalAxis, "5 dof, except argument axis" ).
value( "FixedAxis", MR::ICPMode::FixedAxis, "4 dof, translation and one argument axis" ).
value( "TranslationOnly", MR::ICPMode::TranslationOnly, "3 dof, no rotation" );

pybind11::class_<MR::VertPair>( m, "ICPVertPair" ).
pybind11::class_<MR::VertPair>( m, "VertPair" ).
def( pybind11::init<>() ).
def_readwrite( "refPoint", &MR::VertPair::refPoint ).
def_readwrite( "norm", &MR::VertPair::norm ).
def_readwrite( "normRef", &MR::VertPair::normRef ).
def_readwrite( "vertId", &MR::VertPair::vertId ).
def_readwrite( "normalsAngleCos", &MR::VertPair::normalsAngleCos ).
def_readwrite( "vertDist2", &MR::VertPair::vertDist2 ).
def_readwrite( "weight", &MR::VertPair::weight );
def_readwrite( "refPoint", &MR::VertPair::refPoint, "coordinates of the closest point on reference mesh (after applying refXf)" ).
def_readwrite( "norm", &MR::VertPair::norm, "surface normal in a vertex on the floating mesh (after applying Xf)" ).
def_readwrite( "normRef", &MR::VertPair::normRef, "surface normal in a vertex on the reference mesh (after applying Xf)" ).
def_readwrite( "vertId", &MR::VertPair::vertId, "ID of the floating mesh vertex (usually applying Xf required)" ).
def_readwrite( "normalsAngleCos", &MR::VertPair::normalsAngleCos,
"This is cosine between normals in first(floating mesh) and second(reference mesh) points\n"
"It evaluates how good is this pair" ).
def_readwrite( "vertDist2", &MR::VertPair::vertDist2, "Storing squared distance between vertices" ).
def_readwrite( "weight", &MR::VertPair::weight, "weight of the pair with respect to the sum of adjoining triangles square" );

pybind11::class_<MR::ICPProperties>( m, "ICPProperties" ).
def( pybind11::init<>() ).
def_readwrite( "method", &MR::ICPProperties::method ).
def_readwrite( "p2plAngleLimit", &MR::ICPProperties::p2plAngleLimit ).
def_readwrite( "cosTreshold", &MR::ICPProperties::cosTreshold ).
def_readwrite( "distTresholdSq", &MR::ICPProperties::distTresholdSq ).
def_readwrite( "distStatisticSigmaFactor ", &MR::ICPProperties::distStatisticSigmaFactor ).
def_readwrite( "icpMode", &MR::ICPProperties::icpMode ).
def_readwrite( "fixedRotationAxis", &MR::ICPProperties::fixedRotationAxis ).
def_readwrite( "freezePairs", &MR::ICPProperties::freezePairs ).
def_readwrite( "iterLimit", &MR::ICPProperties::iterLimit ).
def_readwrite( "badIterStopCount", &MR::ICPProperties::badIterStopCount ).
def_readwrite( "exitVal", &MR::ICPProperties::exitVal );
def_readwrite( "p2plAngleLimit", &MR::ICPProperties::p2plAngleLimit,
"rotation part will be limited by this value. If the whole rotation exceed this value, it will be normalized to that.\n"
"Note: PointToPlane only!").
def_readwrite( "cosTreshold", &MR::ICPProperties::cosTreshold, "Points pair will be counted only if cosine between surface normals in points is higher" ).
def_readwrite( "distTresholdSq", &MR::ICPProperties::distTresholdSq, "Points pair will be counted only if squared distance between points is lower than" ).
def_readwrite( "distStatisticSigmaFactor ", &MR::ICPProperties::distStatisticSigmaFactor,
"Sigma multiplier for statistic throw of paints pair based on the distance\n"
"Default: all pairs in the interval the (distance = mean +- 3*sigma) are passed" ).
def_readwrite( "icpMode", &MR::ICPProperties::icpMode, "Finds only translation. Rotation part is identity matrix" ).
def_readwrite( "fixedRotationAxis", &MR::ICPProperties::fixedRotationAxis, "If this vector is not zero then rotation is allowed relative to this axis only" ).
def_readwrite( "freezePairs", &MR::ICPProperties::freezePairs, "keep point pairs from first iteration" ).
def_readwrite( "iterLimit", &MR::ICPProperties::iterLimit, "maximum iterations" ).
def_readwrite( "badIterStopCount", &MR::ICPProperties::badIterStopCount, "maximum iterations without improvements" ).
def_readwrite( "exitVal", &MR::ICPProperties::exitVal, "Algorithm target root-mean-square distance. As soon as it is reached, the algorithm stops." );

pybind11::class_<MR::MeshICP>( m, "MeshICP" ).
def( pybind11::init<const MR::Mesh&, const MR::Mesh&, const MR::AffineXf3f&, const MR::AffineXf3f&, const MR::VertBitSet&>() ).
def( pybind11::init<const MR::Mesh&, const MR::Mesh&, const MR::AffineXf3f&, const MR::AffineXf3f&, float>() ).
def( "setParams", &MR::MeshICP::setParams ).
def( "setCosineLimit", &MR::MeshICP::setCosineLimit ).
def( "setDistanceLimit", &MR::MeshICP::setDistanceLimit ).
def( "setBadIterCount", &MR::MeshICP::setBadIterCount ).
def( "setPairsWeight", &MR::MeshICP::setPairsWeight ).
def( "setDistanceFilterSigmaFactor", &MR::MeshICP::setDistanceFilterSigmaFactor ).
def( "recomputeBitSet", &MR::MeshICP::recomputeBitSet ).
def( "getParams", &MR::MeshICP::getParams,pybind11::return_value_policy::copy ).
def( "getShiftVector", &MR::MeshICP::getShiftVector ).
def( "getLastICPInfo", &MR::MeshICP::getLastICPInfo ).
def( "getMeanSqDistToPoint", &MR::MeshICP::getMeanSqDistToPoint ).
def( "getMeanSqDistToPlane", &MR::MeshICP::getMeanSqDistToPlane ).
def( "getVertPairs", &MR::MeshICP::getVertPairs, pybind11::return_value_policy::copy ).
def( "getDistLimitsSq", &MR::MeshICP::getDistLimitsSq ).
def( "calculateTransformation", &MR::MeshICP::calculateTransformation ).
def( "updateVertPairs", &MR::MeshICP::updateVertPairs );
pybind11::class_<MR::MeshICP>( m, "MeshICP", "This class allows to match two meshes with almost same geometry throw ICP point-to-point or point-to-plane algorithms" ).
def( pybind11::init<const MR::Mesh&, const MR::Mesh&, const MR::AffineXf3f&, const MR::AffineXf3f&, const MR::VertBitSet&>(),
pybind11::arg("floatingMesh"), pybind11::arg( "referenceMesh" ), pybind11::arg( "fltMeshXf" ), pybind11::arg( "refMeshXf" ), pybind11::arg( "floatingMeshBitSet" ),
"xf parameters should represent current transformations of meshes\n"
"fltMeshXf - transform from the local floatingMesh basis to the global\n"
"refMeshXf - transform from the local referenceMesh basis to the global\n"
"floatingMeshBitSet - allows to take exact set of vertices from the mesh" ).
def( pybind11::init<const MR::Mesh&, const MR::Mesh&, const MR::AffineXf3f&, const MR::AffineXf3f&, float>(),
pybind11::arg( "floatingMesh" ), pybind11::arg( "referenceMesh" ), pybind11::arg( "fltMeshXf" ), pybind11::arg( "refMeshXf" ), pybind11::arg( "floatSamplingVoxelSize" ),
"xf parameters should represent current transformations of meshes\n"
"fltMeshXf - transform from the local floatingMesh basis to the global\n"
"refMeshXf - transform from the local referenceMesh basis to the global\n"
"floatSamplingVoxelSize = positive value here defines voxel size, and only one vertex per voxel will be selected" ).
def( "setParams", &MR::MeshICP::setParams, pybind11::arg( "prop" ), "tune algirithm params before run calculateTransformation()" ).
def( "setCosineLimit", &MR::MeshICP::setCosineLimit, pybind11::arg( "cos" ) ).
def( "setDistanceLimit", &MR::MeshICP::setDistanceLimit, pybind11::arg( "dist" ) ).
def( "setBadIterCount", &MR::MeshICP::setBadIterCount, pybind11::arg( "iter" ) ).
def( "setPairsWeight", &MR::MeshICP::setPairsWeight, pybind11::arg( "v" ) ).
def( "setDistanceFilterSigmaFactor", &MR::MeshICP::setDistanceFilterSigmaFactor, pybind11::arg( "factor" ) ).
def( "recomputeBitSet", &MR::MeshICP::recomputeBitSet, pybind11::arg( "floatSamplingVoxelSize" ) ).
def( "getParams", &MR::MeshICP::getParams, pybind11::return_value_policy::copy ).
def( "getShiftVector", &MR::MeshICP::getShiftVector, "shows mean pair vector" ).
def( "getLastICPInfo", &MR::MeshICP::getLastICPInfo, "returns status info string" ).
def( "getMeanSqDistToPoint", &MR::MeshICP::getMeanSqDistToPoint, "computes root-mean-square deviation between points" ).
def( "getMeanSqDistToPlane", &MR::MeshICP::getMeanSqDistToPlane, "computes root-mean-square deviation from points to target planes" ).
def( "getVertPairs", &MR::MeshICP::getVertPairs, pybind11::return_value_policy::copy, "used to visualize generated points pairs" ).
def( "getDistLimitsSq", &MR::MeshICP::getDistLimitsSq, "finds squared minimum and maximum pairs distances" ).
def( "calculateTransformation", &MR::MeshICP::calculateTransformation, "returns new xf transformation for the floating mesh, which allows to match reference mesh" ).
def( "updateVertPairs", &MR::MeshICP::updateVertPairs, "recompute point pairs after manual change of transformations or parameters" );
} )

MR_ADD_PYTHON_VEC( mrmeshpy, vectorICPVertPair, MR::VertPair )
Loading