|
| 1 | +#include "MRMesh/MRBitSetParallelFor.h" |
| 2 | +#include "MRMesh/MRBoolean.h" |
| 3 | +#include "MRMesh/MREdgeIterator.h" |
| 4 | +#include "MRMesh/MRMesh.h" |
| 5 | +#include "MRMesh/MRPointsToMeshProjector.h" |
| 6 | + |
| 7 | +// Only the functions that should be exported should be in `MR::Extra`. Place everything else somewhere outside. |
| 8 | +// Note that the comments are pasted to Python too. |
| 9 | + |
| 10 | +namespace MR::Extra |
| 11 | +{ |
| 12 | + // Fix self-intersections by converting to voxels and back. |
| 13 | + void fixSelfIntersections( Mesh& mesh, float voxelSize ) |
| 14 | + { |
| 15 | + MeshVoxelsConverter convert; |
| 16 | + convert.voxelSize = voxelSize; |
| 17 | + auto gridA = convert(mesh); |
| 18 | + mesh = convert(gridA); |
| 19 | + } |
| 20 | + |
| 21 | + // Subtract mesh B from mesh A. |
| 22 | + Mesh voxelBooleanSubtract( const Mesh& mesh1, const Mesh& mesh2, float voxelSize ) |
| 23 | + { |
| 24 | + MeshVoxelsConverter convert; |
| 25 | + convert.voxelSize = voxelSize; |
| 26 | + auto gridA = convert(mesh1); |
| 27 | + auto gridB = convert(mesh2); |
| 28 | + gridA -= gridB; |
| 29 | + return convert(gridA); |
| 30 | + } |
| 31 | + |
| 32 | + // Unite mesh A and mesh B. |
| 33 | + Mesh voxelBooleanUnite( const Mesh& mesh1, const Mesh& mesh2, float voxelSize ) |
| 34 | + { |
| 35 | + MeshVoxelsConverter convert; |
| 36 | + convert.voxelSize = voxelSize; |
| 37 | + auto gridA = convert(mesh1); |
| 38 | + auto gridB = convert(mesh2); |
| 39 | + gridA += gridB; |
| 40 | + return convert( gridA ); |
| 41 | + } |
| 42 | + |
| 43 | + // Intersect mesh A and mesh B. |
| 44 | + Mesh voxelBooleanIntersect( const Mesh& mesh1, const Mesh& mesh2, float voxelSize ) |
| 45 | + { |
| 46 | + MeshVoxelsConverter convert; |
| 47 | + convert.voxelSize = voxelSize; |
| 48 | + auto gridA = convert(mesh1); |
| 49 | + auto gridB = convert(mesh2); |
| 50 | + gridA *= gridB; |
| 51 | + return convert( gridA ); |
| 52 | + } |
| 53 | + |
| 54 | + // Computes signed distances from all mesh points to refMesh. |
| 55 | + // `refMesh` - all points will me projected to this mesh |
| 56 | + // `mesh` - this mesh points will be projected |
| 57 | + // `refXf` - world transform for refMesh |
| 58 | + // `upDistLimitSq` - upper limit on the distance in question, if the real distance is larger than the returning upDistLimit |
| 59 | + // `loDistLimitSq` - low limit on the distance in question, if a point is found within this distance then it is immediately returned without searching for a closer one |
| 60 | + VertScalars projectAllMeshVertices( const Mesh& refMesh, const Mesh& mesh, const AffineXf3f* refXf = nullptr, const AffineXf3f* xf = nullptr, float upDistLimitSq = FLT_MAX, float loDistLimitSq = 0.0f ) |
| 61 | + { |
| 62 | + PointsToMeshProjector projector; |
| 63 | + projector.updateMeshData( &refMesh ); |
| 64 | + std::vector<MeshProjectionResult> mpRes( mesh.points.vec_.size() ); |
| 65 | + projector.findProjections( mpRes, mesh.points.vec_, xf, refXf, upDistLimitSq, loDistLimitSq ); |
| 66 | + VertScalars res( mesh.topology.lastValidVert() + 1, std::sqrt( upDistLimitSq ) ); |
| 67 | + |
| 68 | + AffineXf3f fullXf; |
| 69 | + if ( refXf ) |
| 70 | + fullXf = refXf->inverse(); |
| 71 | + if ( xf ) |
| 72 | + fullXf = fullXf * ( *xf ); |
| 73 | + |
| 74 | + BitSetParallelFor( mesh.topology.getValidVerts(), [&] ( VertId v ) |
| 75 | + { |
| 76 | + const auto& mpResV = mpRes[v.get()]; |
| 77 | + auto& resV = res[v]; |
| 78 | + |
| 79 | + resV = mpResV.distSq; |
| 80 | + if ( mpResV.mtp.e ) |
| 81 | + resV = refMesh.signedDistance( fullXf( mesh.points[v] ), mpResV ); |
| 82 | + else |
| 83 | + resV = std::sqrt( resV ); |
| 84 | + } ); |
| 85 | + return res; |
| 86 | + } |
| 87 | + |
| 88 | + // Merge a list of meshes to one mesh. |
| 89 | + Mesh mergeMeshes( const std::vector<std::shared_ptr<MR::Mesh>>& meshes ) |
| 90 | + { |
| 91 | + Mesh res; |
| 92 | + for ( const auto& m : meshes ) |
| 93 | + res.addPart( *m ); |
| 94 | + return res; |
| 95 | + } |
| 96 | + |
| 97 | + // Return faces with at least one edge longer than the specified length. |
| 98 | + FaceBitSet getFacesByMinEdgeLength( const Mesh& mesh, float minLength ) |
| 99 | + { |
| 100 | + using namespace MR; |
| 101 | + FaceBitSet resultFaces( mesh.topology.getValidFaces().size() ); |
| 102 | + float minLengthSq = minLength * minLength; |
| 103 | + for ( auto ue : undirectedEdges( mesh.topology ) ) |
| 104 | + { |
| 105 | + if ( mesh.edgeLengthSq( ue ) > minLengthSq ) |
| 106 | + { |
| 107 | + auto l = mesh.topology.left( ue ); |
| 108 | + auto r = mesh.topology.right( ue ); |
| 109 | + if ( l ) |
| 110 | + resultFaces.set( l ); |
| 111 | + if ( r ) |
| 112 | + resultFaces.set( r ); |
| 113 | + } |
| 114 | + } |
| 115 | + return resultFaces; |
| 116 | + } |
| 117 | +} |
0 commit comments