Boolean mapping
Hi, we are working with the python exposed boolean functions and I believe their might still be some issue with the mapping function for mapping the results:
def get_inside(mesh_a, mesh_b):
bOperation = mm.BooleanOperation.InsideA
bResMapper = mm.BooleanResultMapper()
bResult = mm.boolean(mesh_a, mesh_b, bOperation, None, bResMapper)
inner_faces = bResMapper.map(mesh_a.topology.getValidFaces(), mm.BooleanResMapObj.A)
inner_verts = bResMapper.map(mesh_a.topology.getValidVerts(), mm.BooleanResMapObj.A)
return mn.getNumpyBitSet(inner_faces), mn.getNumpyBitSet(inner_verts)
I believe the intended way of working is shown in the implementation above. However it seems the Bitsets returned allways contain all True values. And the number of values is equal or smaller then the total number of verts/faces. It seems like only the True values of the Bitset are returned instead of the full Bitset. As such we can't yet map the results on the original mesh.
Hello!
Could you please provide meshes so we can reproduce the issue on our end?
Sure thing. Please see the example below:
from meshlib import mrmeshpy as mm
from meshlib import mrmeshnumpy as mn
def get_inside(mesh_a, mesh_b):
bOperation = mm.BooleanOperation.InsideA
bResMapper = mm.BooleanResultMapper()
bResult = mm.boolean(mesh_a, mesh_b, bOperation, None, bResMapper)
inner_faces = bResMapper.map(mesh_a.topology.getValidFaces(), mm.BooleanResMapObj.A)
inner_verts = bResMapper.map(mesh_a.topology.getValidVerts(), mm.BooleanResMapObj.A)
return mn.getNumpyBitSet(inner_faces), mn.getNumpyBitSet(inner_verts)
torusIntersected = mm.makeTorusWithSelfIntersections(2, 1, 10, 10, None)
mm.fixSelfIntersections(torusIntersected, 0.1)
torus = mm.makeTorus(2, 1, 10, 10, None)
transVector = mm.Vector3f()
transVector.x = 0.5
transVector.y = 1
transVector.z = 1
diffXf = mm.AffineXf3f.translation(transVector)
torus2 = mm.makeTorus(2, 1, 10, 10, None)
torus2.transform(diffXf)
print(f"Valid faces: {torus.topology.getValidFaces().size()}")
print(f"Valid verts: {torus.topology.getValidVerts().size()}")
inside_faces, inside_verts = get_inside(mesh_a=torus, mesh_b=torus2)
print(f"Inside faces: {inside_faces.size}")
print(f"Inside verts: {inside_verts.size}")
print(inside_faces)
print(inside_verts)
Which outputs the following:
Valid faces: 200
Valid verts: 100
Inside faces: 154
Inside verts: 25
[ True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True True True
True True True True True True True True True True]
[ True True True True True True True True True True True True
True True True True True True True True True True True True
True]
What I'd expected was the that the outputted bitsets would be the same length as that of getValidFaces and getValidVerts but with boolean values indicating if face or vertices comply with the boolean operation.
Thanks!
Now I understand the problem, really BooleanResultMapper.map functions return BitSets of result mesh that correspond to given BitSet. As I understand you need to filter torus.topology.getValidFaces()
There are maps that allow to do it in c++
auto validFaces = torus.topology.getValidFaces();
const auto& cut2originMap = mapper.maps[int(BooleanResultMapper::MapObject::A)].cut2origin;
const auto& cut2newMap = mapper.maps[int(BooleanResultMapper::MapObject::A)].cut2newFaces;
for ( int i = 0; i < cut2originMap.size(); ++i )
{
auto orgFace = cut2originMap[FaceId(i)];
if ( !orgFace.valid() )
continue;
if ( !cut2newMap[FaceId(i)].valid() )
validFaces.reset( orgFace );
}
Unfortunately these maps are not exposed to python yet, we will expose them, an maybe add special functions in Mapper class.
For now there is workaround
def get_inside(mesh_a, mesh_b):
bOperation = mm.BooleanOperation.InsideA
bResMapper = mm.BooleanResultMapper()
bResult = mm.boolean(mesh_a, mesh_b, bOperation, None, bResMapper)
inner_faces = mesh_a.topology.getValidFaces()
for f in inner_faces:
bs = mm.FaceBitSet()
bs.resize( f.get()+1)
bs.set(f)
if (bResMapper.map(bs, mm.BooleanResMapObj.A).count() == 0):
inner_faces.set(f,False)
inner_verts = mesh_a.topology.getValidVerts()
for v in inner_verts:
bs = mm.VertBitSet()
bs.resize( v.get()+1)
bs.set(v)
if (bResMapper.map(bs, mm.BooleanResMapObj.A).count() == 0):
inner_verts.set(v,False)
return mn.getNumpyBitSet(inner_faces), mn.getNumpyBitSet(inner_verts)
surely it will do a lot of excessive computations, but it is easiest way to implement it right now
Got it! Indeed see where this is coming from now!