Skip to content

Commit cdca144

Browse files
ADD boolean_modifier and slicer_modifier.
1 parent 9828f15 commit cdca144

File tree

2 files changed

+99
-8
lines changed

2 files changed

+99
-8
lines changed

src/compas_model/interactions/modifiers/boolean_modifier.py

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,58 @@
77

88

99
class BooleanModifier(Modifier):
10-
"""Class representing a modifier that performs a boolean operation on a target geometry.
10+
"""Perform boolean difference on the target element.
1111
1212
Parameters
1313
----------
14+
source : :class:`compas.geometry.Brep` | :class:`compas.datastructures.Mesh`
15+
The geometry to be used as the modifier
1416
name : str, optional
1517
The name of the interaction.
1618
1719
"""
1820

19-
def apply(self, source: Union[Brep, Mesh], target: Union[Brep, Mesh]):
21+
@property
22+
def __data__(self):
23+
# type: () -> dict
24+
return {"name": self.name, "source": self.source}
25+
26+
def __init__(self, source: Union[Brep, Mesh], name=None):
27+
# type: (Union[Brep, Mesh], str | None) -> None
28+
super(BooleanModifier, self).__init__(name=name)
29+
self.source = source
30+
31+
def __repr__(self):
32+
return '{}(name="{}")'.format(self.__class__.__name__, self.name)
33+
34+
def apply(self, target: Union[Brep, Mesh]):
2035
"""Apply the interaction to the affected geometry.
36+
NOTE: If the result is not a valid geometry, the original geometry is returned.
2137
2238
Parameters
2339
----------
24-
source : :class:`compas.geometry.Brep` | :class:`compas.datastructures.Mesh`
25-
The source of the modification.
26-
target : :class:`compas.geometry.Brep` | :class:`compas.datastructures.Mesh`
27-
The target of the modification.
28-
40+
targetgeometry : :class:`compas.geometry.Brep` | :class:`compas.datastructures.Mesh`
41+
The geometry to be affected iteratively. The same geometry can be modified multiple times.
42+
sourcegeometry : :class:`compas.geometry.Brep` | :class:`compas.datastructures.Mesh`
43+
The geometry to be used as the modifier.
2944
"""
30-
raise NotImplementedError
45+
# Local import is needed otherwise, remove contact interactions in algorithms module.
46+
if isinstance(target, Brep) and isinstance(self.source, Brep):
47+
try:
48+
return Brep.from_boolean_difference(target, self.source)
49+
except Exception:
50+
print("Boolean difference is not successful.")
51+
return target
52+
else:
53+
from compas_cgal.booleans import boolean_difference_mesh_mesh
54+
55+
mesh0: Mesh = target.copy() if not isinstance(target, Brep) else Mesh.from_polygons(target.to_polygons())
56+
mesh1: Mesh = self.source.copy() if not isinstance(self.source, Brep) else Mesh.from_polygons(self.source.to_polygons())
57+
print(mesh0)
58+
print(mesh1)
59+
A = mesh0.to_vertices_and_faces(triangulated=True)
60+
B = mesh1.to_vertices_and_faces(triangulated=True)
61+
62+
V, F = boolean_difference_mesh_mesh(A, B)
63+
mesh: Mesh = Mesh.from_vertices_and_faces(V, F) if len(V) > 0 and len(F) > 0 else mesh0
64+
return mesh
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from typing import Union
2+
3+
from compas.datastructures import Mesh
4+
from compas.geometry import Brep
5+
from compas.geometry import Plane
6+
7+
from .modifier import Modifier
8+
9+
10+
class SlicerModifier(Modifier):
11+
"""Perform boolean difference on the target element.
12+
13+
Parameters
14+
----------
15+
source : :class:`compas.geometry.Brep` | :class:`compas.datastructures.Mesh`
16+
The geometry to be used as the modifier
17+
name : str, optional
18+
The name of the interaction.
19+
20+
"""
21+
22+
@property
23+
def __data__(self):
24+
# type: () -> dict
25+
return {"name": self.name, "source": self.source}
26+
27+
def __init__(self, slice_plane: Plane, name=None):
28+
# type: (Union[Brep, Mesh], str | None) -> None
29+
super(SlicerModifier, self).__init__(name=name)
30+
self.slice_plane = slice_plane
31+
32+
def __repr__(self):
33+
return '{}(name="{}")'.format(self.__class__.__name__, self.name)
34+
35+
def apply(self, target: Union[Brep, Mesh]):
36+
"""Cut target geometry by the frame.
37+
NOTE: If the result is not a valid geometry, the original geometry is returned.
38+
39+
Parameters
40+
----------
41+
target : :class:`compas.geometry.Brep` | :class:`compas.datastructures.Mesh`
42+
The geometry to be affected iteratively. The same geometry can be modified multiple times.
43+
"""
44+
# Local import is needed otherwise, remove contact interactions in algorithms module.
45+
46+
try:
47+
if isinstance(target, Brep):
48+
target.make_solid()
49+
slice_plane_flipped = Plane(self.slice_plane.point, -self.slice_plane.normal)
50+
target.trim(slice_plane_flipped)
51+
return target
52+
else:
53+
split_meshes: list[Mesh] = target.slice(self.slice_plane)
54+
return split_meshes[0] if split_meshes else target
55+
except Exception:
56+
print("SlicerModifier is not successful.")
57+
return target

0 commit comments

Comments
 (0)