Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cut off part feature of the mesh model #1512

Closed
xiaodongdong101 opened this issue Aug 9, 2023 · 16 comments
Closed

Cut off part feature of the mesh model #1512

xiaodongdong101 opened this issue Aug 9, 2023 · 16 comments

Comments

@xiaodongdong101
Copy link

Hello,If I use a plane to cut off a model, can I cut off some mesh features?For example, I want to cut off the A feature of the mesh model, but I don't want to cut off the B feature of the mesh model.
8026feec4a602a13d8f0fd999024439
Is there any better way to solve this problem?

@Grantim
Copy link
Contributor

Grantim commented Aug 9, 2023

Hello!

First you need to use

/// extracts all plane sections of given mesh
[[nodiscard]] MRMESH_API PlaneSections extractPlaneSections( const MeshPart & mp, const Plane3f & plane );

It will return vector with plane sections, then you remove all sections that are not intersting for you (leaving only sections of A).

Then call

/** \ingroup BooleanGroup
* \brief Converts SurfacePaths to OneMeshContours
*
* Creates MR::OneMeshContours object from given surface paths for MR::cutMesh input
*/
[[nodiscard]]
MRMESH_API OneMeshContours convertSurfacePathsToMeshContours( const Mesh& mesh, const std::vector<SurfacePath>& surfacePaths );

with remained contours
and
/** \ingroup BooleanGroup
* \brief Cuts mesh by given contours
*
* This function cuts mesh making new edges paths on place of input contours
* \param mesh Input mesh that will be cut
* \param contours Input contours to cut mesh with, find more \ref MR::OneMeshContours
* \param params Parameters describing some cut options, find more \ref MR::CutMeshParameters
* \return New edges that correspond to given contours, find more \ref MR::CutMeshResult
* \parblock
* \warning Input contours should have no intersections, faces where contours intersects (`bad faces`) will not be allowed for fill
* \endparblock
* \parblock
* \warning Input mesh will be changed in any case, if `bad faces` are in mesh, mesh will be spoiled, \n
* so if you cannot guarantee contours without intersections better make copy of mesh, before using this function
* \endparblock
*/
MRMESH_API CutMeshResult cutMesh( Mesh& mesh, const OneMeshContours& contours, const CutMeshParameters& params = {} );

with the result

It will give you

/// Paths of new edges on mesh, they represent same contours as input, but already cut
std::vector<EdgePath> resultCut;

then you need to remove part that you dont need need:

// fill region located to the left from given edges
MRMESH_API FaceBitSet fillContourLeft( const MeshTopology & topology, const EdgePath & contour );
MRMESH_API FaceBitSet fillContourLeft( const MeshTopology & topology, const std::vector<EdgePath> & contours );

/// deletes multiple given faces
MRMESH_API void deleteFaces( const FaceBitSet& fs );

note that it is not always possible, for example in torus mesh there will not be determined left or right part

@xiaodongdong101
Copy link
Author

Hello,Can I set specified coordinates and normal vectors to determine the plane?
code******
auto plane = MR::makePlane();


if If I want to set the coordinate point as (1,1,0), the normal vector is (1,0,1),Can I directly set it?

@Grantim
Copy link
Contributor

Grantim commented Aug 16, 2023

Hello!

You should rotate and move the plane in this case:

auto plane = MR::makePlane();
auto rotation = MR::Matrix3f::rotation( MR::Vector3f::plusZ(), MR::Vector3f( 1, 0, 1) );
plane.transform( MR::AffineXf3f::translation( MR::Vector3f( 1, 1, 0) ) * MR::AffineXf3f::linear( rotation ) );

@xiaodongdong101
Copy link
Author

Thanks a lot

@xiaodongdong101
Copy link
Author

Hello,I found that there is only one cut function in the software, will more cutting functions be added in the future?I need to remove the facets in the positive direction of multiple facets
d587e8dc4b1c1c79d70a09bd0795f18

@Grantim
Copy link
Contributor

Grantim commented Aug 17, 2023

Hello!
You can cut it three times one by one. We are not planning to add several cuts at the same time.

@xiaodongdong101
Copy link
Author

Thanks a lot.Now it is possible to find a section through three cuts,But I want to get the other half, how should I get better?
00dfacd1bcc5e8db0c425eb3e9b3070
image

code*********
auto plane11 = MR::Plane3f::fromDirAndPt(MR::Vector3f(0.5, 0.2, 0.6), MR::Vector3f(9, 0, 18));
auto plane22 = MR::Plane3f::fromDirAndPt(MR::Vector3f(0.142, -0.984, 0.104), MR::Vector3f(1, 0, 20));
auto plane33 = MR::Plane3f::fromDirAndPt(MR::Vector3f(0.5, -0.837, 0.071), MR::Vector3f(8, 4, 20));
auto planesection1 = MR::extractPlaneSections(*cylinder, plane11);
auto MeshContours1 = MR::convertSurfacePathsToMeshContours(*cylinder, planesection1);
MR::CutMeshResult result_plane_1 = MR::cutMesh(*cylinder, MeshContours1);

MR::Mesh Mesh_result1;
MR::reverse(result_plane_1.resultCut);
auto outerBitSet_plane_1 = MR::fillContourLeft(cylinder->topology, result_plane_1.resultCut);
Mesh_result1.addPartByMask(*cylinder, outerBitSet_plane_1);

auto planesection2 = MR::extractPlaneSections(Mesh_result1, plane22);
auto MeshContours2 = MR::convertSurfacePathsToMeshContours(Mesh_result1, planesection2);
MR::CutMeshResult result_plane_2 = MR::cutMesh(Mesh_result1, MeshContours2);

MR::Mesh Mesh_result2;
auto outerBitSet_plane_2 = MR::fillContourLeft(Mesh_result1.topology, result_plane_2.resultCut);
Mesh_result2.addPartByMask(Mesh_result1, outerBitSet_plane_2);

auto planesection3 = MR::extractPlaneSections(Mesh_result2, plane33);
auto MeshContours3 = MR::convertSurfacePathsToMeshContours(Mesh_result2, planesection3);
MR::CutMeshResult result_plane_3 = MR::cutMesh(Mesh_result2, MeshContours3);

MR::Mesh Mesh_result3;
auto outerBitSet_plane_3 = MR::fillContourLeft(Mesh_result2.topology, result_plane_3.resultCut);
Mesh_result3.addPartByMask(Mesh_result2, outerBitSet_plane_3);
std::string filename_outerMesh_test_1 = "Mesh_result.stl";
MR::MeshSave::toBinaryStl(Mesh_result3, filename_outerMesh_test_1);

@xiaodongdong101
Copy link
Author

If the above small piece is what I want to delete, how should I do it?

@Grantim
Copy link
Contributor

Grantim commented Aug 18, 2023

You don't need to make new Mesh each time:

auto plane11 = MR::Plane3f::fromDirAndPt(MR::Vector3f(0.5, 0.2, 0.6), MR::Vector3f(9, 0, 18));
auto plane22 = MR::Plane3f::fromDirAndPt(MR::Vector3f(0.142, -0.984, 0.104), MR::Vector3f(1, 0, 20));
auto plane33 = MR::Plane3f::fromDirAndPt(MR::Vector3f(0.5, -0.837, 0.071), MR::Vector3f(8, 4, 20));

auto planesection1 = MR::extractPlaneSections(*cylinder, plane11);
auto MeshContours1 = MR::convertSurfacePathsToMeshContours(*cylinder, planesection1);
MR::CutMeshResult result_plane_1 = MR::cutMesh(*cylinder, MeshContours1);

cylinder->topology.deleteFaces( MR::fillContourLeft(cylinder->topology, result_plane_1.resultCut) );
cylinder->invalidateCaches();

auto planesection2 = MR::extractPlaneSections(cylinder, plane22);
auto MeshContours2 = MR::convertSurfacePathsToMeshContours(cylinder, planesection2);
MR::CutMeshResult result_plane_2 = MR::cutMesh(cylinder, MeshContours2);

cylinder->topology.deleteFaces( cylinder->topology.flip( MR::fillContourLeft(cylinder->topology, result_plane_2.resultCut) ) );
cylinder->invalidateCaches();

auto planesection3 = MR::extractPlaneSections(cylinder, plane33);
auto MeshContours3 = MR::convertSurfacePathsToMeshContours(cylinder, planesection3);
MR::CutMeshResult result_plane_3 = MR::cutMesh(cylinder, MeshContours3);

cylinder->topology.deleteFaces( cylinder->topology.flip( MR::fillContourLeft(cylinder->topology, result_plane_3.resultCut) ) );
cylinder->invalidateCaches();

std::string filename_outerMesh_test_1 = "Mesh_result.stl";
MR::MeshSave::toBinaryStl(Mesh_result3, filename_outerMesh_test_1);

@xiaodongdong101
Copy link
Author

Thanks a lot,There is a problem with the clip in the code that the author replied
code************************
cylinder->topology.deleteFaces(MR::fillContourLeft(cylinder->topology, result_plane_1.resultCut));
cylinder->invalidateCaches();

auto planesection2 = MR::extractPlaneSections(*cylinder, plane22);
auto MeshContours2 = MR::convertSurfacePathsToMeshContours(*cylinder, planesection2);
MR::CutMeshResult result_plane_2 = MR::cutMesh(*cylinder, MeshContours2);

auto facebitset1 = MR::fillContourLeft(cylinder->topology, result_plane_2.resultCut);
cylinder->topology.flip(facebitset1);
cylinder->topology.deleteFaces(facebitset1);
cylinder->invalidateCaches();

auto planesection3 = MR::extractPlaneSections(*cylinder, plane33);
auto MeshContours3 = MR::convertSurfacePathsToMeshContours(*cylinder, planesection3);
MR::CutMeshResult result_plane_3 = MR::cutMesh(*cylinder, MeshContours3);

auto facebitset2 = MR::fillContourLeft(cylinder->topology, result_plane_3.resultCut);
cylinder->topology.flip(facebitset2);
cylinder->topology.deleteFaces(facebitset2);
cylinder->invalidateCaches();

code********************************
Now I want to delete the model, that is, output the model without this part, how should I do it better?

@Grantim
Copy link
Contributor

Grantim commented Aug 21, 2023

If I understand correctly you need to cut other part of mesh, to do it you need to flip bitsets before delete operation:
in current code version I suggest flip facebitset1 and facebitset2 and not flipping MR::fillContourLeft(cylinder->topology, result_plane_1.resultCut). So you can try not to flip them.

@xiaodongdong101
Copy link
Author

Thanks a lot.In fact, there is some doubt:
If I import a cylinder model,The blue part is what I want and the white part is what I want to remove
eb98e6324ccc1cc816230f73e324346
If I cut three times it is easy to get the white part.But if I cut three times it's easy to cut the rest of the blue.
How should I get the blue part of the mesh without changing the mesh model too much?

@Grantim
Copy link
Contributor

Grantim commented Aug 22, 2023

Now I see, this can be done by like this:

auto plane11 = MR::Plane3f::fromDirAndPt(MR::Vector3f(0.5, 0.2, 0.6), MR::Vector3f(9, 0, 18));
auto plane22 = MR::Plane3f::fromDirAndPt(MR::Vector3f(0.142, -0.984, 0.104), MR::Vector3f(1, 0, 20));
auto plane33 = MR::Plane3f::fromDirAndPt(MR::Vector3f(0.5, -0.837, 0.071), MR::Vector3f(8, 4, 20));

auto planesection1 = MR::extractPlaneSections(*cylinder, plane11);
auto MeshContours1 = MR::convertSurfacePathsToMeshContours(*cylinder, planesection1);
MR::CutMeshResult result_plane_1 = MR::cutMesh(*cylinder, MeshContours1);
auto leftFaces = cylinder->topology.flip( MR::fillContourLeft(cylinder->topology, result_plane_1.resultCut) );

MR::FaceMap new2OldMap2;
auto planesection2 = MR::extractPlaneSections(cylinder, plane22);
auto MeshContours2 = MR::convertSurfacePathsToMeshContours(cylinder, planesection2);
MR::FaceId oldFaceSize = cylinder->topology.lastValidFace() + 1;
MR::CutMeshResult result_plane_2 = MR::cutMesh(cylinder, MeshContours2, { .new2OldMap =  new2OldMap2} );
for ( MR::FaceId f = oldFaceSize; f < MR::FaceId( int( cylinder->topology.faceSize() ) ); f++ )
{
    if ( leftFaces.test( new2OldMap2[f] ) )
        leftFaces.autoResizeSet( f );
}
leftFaces |= MR::fillContourLeft(cylinder->topology, result_plane_2.resultCut);

MR::FaceMap new2OldMap3;
auto planesection3 = MR::extractPlaneSections(cylinder, plane33);
auto MeshContours3 = MR::convertSurfacePathsToMeshContours(cylinder, planesection3);
oldFaceSize = cylinder->topology.lastValidFace() + 1;
MR::CutMeshResult result_plane_3 = MR::cutMesh(cylinder, MeshContours3, { .new2OldMap =  new2OldMap3} );
for ( MR::FaceId f = oldFaceSize; f < MR::FaceId( int( cylinder->topology.faceSize() ) ); f++ )
{
    if ( leftFaces.test( new2OldMap3[f] ) )
        leftFaces.autoResizeSet( f );
}
leftFaces |= MR::fillContourLeft(cylinder->topology, result_plane_3.resultCut);

leftFaces &= cylinder->topology.getValidFaces();
cylinder->topology.deleteFaces( leftFaces );
cylinder->invalidateCaches();

@xiaodongdong101
Copy link
Author

Thanks a lot for reply.
The code needs to be modified slightly
leftFaces &= MR::fillContourLeft(cylinder->topology, result_plane_2.resultCut);
leftFaces &= MR::fillContourLeft(cylinder->topology, result_plane_3.resultCut);
Then the relevant mesh can be obtained
44da1a4c865505f4af87f76f6ef9696

@Grantim
Copy link
Contributor

Grantim commented Aug 22, 2023

Oh, sure you are right, does it fit your needs?

@xiaodongdong101
Copy link
Author

Thanks a lot.It would be even better if it can be improved.
In fact, there is another detail
If I cut three times, then the other local area meshes will also be cut
for example:
3be0e7841604af41359430675269474
It would be better if these can be avoided

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants