Skip to content

Commit 0f2a5b5

Browse files
committed
added boolean operations to RhinoBrep
offset cylinder base plane when converting to rhino
1 parent b0e56b5 commit 0f2a5b5

File tree

4 files changed

+159
-1
lines changed

4 files changed

+159
-1
lines changed

src/compas/geometry/brep/brep.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,63 @@ def from_boolean_union(cls, brep_a, brep_b):
607607
"""
608608
raise NotImplementedError
609609

610+
def __sub__(self, other):
611+
"""Compute the boolean difference using the "-" operator of this shape and another.
612+
613+
Parameters
614+
----------
615+
other : :class:`~compas.geometry.Brep`
616+
The other Brep to create a union with.
617+
618+
Returns
619+
-------
620+
:class:`~compas.geometry.Brep`
621+
The Brep resulting from the difference operation.
622+
623+
"""
624+
results = type(self).from_boolean_difference(self, other)
625+
if isinstance(results, list):
626+
results = results[0]
627+
return results
628+
629+
def __and__(self, other):
630+
"""Compute the boolean intersection using the "&" operator of this shape and another.
631+
632+
Parameters
633+
----------
634+
other : :class:`~compas.geometry.Brep`
635+
The other Brep to create a union with.
636+
637+
Returns
638+
-------
639+
:class:`~compas.geometry.Brep`
640+
The Brep resulting from the intersection operation.
641+
642+
"""
643+
results = type(self).from_boolean_intersection(self, other)
644+
if isinstance(results, list):
645+
results = results[0]
646+
return results
647+
648+
def __add__(self, other):
649+
"""Compute the boolean union using the "+" operator of this Brep and another.
650+
651+
Parameters
652+
----------
653+
other : :class:`~compas.geometry.Brep`
654+
The other Brep to create a union with.
655+
656+
Returns
657+
-------
658+
:class:`~compas.geometry.Brep`
659+
The Brep resulting from the union operation.
660+
661+
"""
662+
results = type(self).from_boolean_union(self, other)
663+
if isinstance(results, list):
664+
results = results[0]
665+
return results
666+
610667
# ==============================================================================
611668
# Converters
612669
# ==============================================================================

src/compas_rhino/conversions/_shapes.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,4 +158,7 @@ def cylinder_to_rhino(cylinder):
158158
:rhino:`Rhino.Geometry.Cylinder`
159159
160160
"""
161-
return RhinoCylinder(circle_to_rhino(cylinder.circle), cylinder.height)
161+
circle = cylinder.circle.copy()
162+
height = cylinder.height
163+
circle.plane.point += circle.plane.normal * (-0.5 * height)
164+
return RhinoCylinder(circle_to_rhino(circle), cylinder.height)

src/compas_rhino/geometry/brep/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,8 @@ def from_brep(*args, **kwargs):
3636
@plugin(category="factories", requires=["Rhino"])
3737
def from_box(*args, **kwargs):
3838
return RhinoBrep.from_box(*args, **kwargs)
39+
40+
41+
@plugin(category="factories", requires=["Rhino"])
42+
def from_cylinder(*args, **kwargs):
43+
return RhinoBrep.from_cylinder(*args, **kwargs)

src/compas_rhino/geometry/brep/brep.py

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from compas_rhino.conversions import point_to_rhino
99
from compas_rhino.conversions import xform_to_rhino
1010
from compas_rhino.conversions import frame_to_rhino
11+
from compas_rhino.conversions import cylinder_to_rhino
1112

1213
import Rhino
1314

@@ -166,6 +167,23 @@ def from_box(cls, box):
166167
rhino_box = box_to_rhino(box)
167168
return cls.from_brep(rhino_box.ToBrep())
168169

170+
@classmethod
171+
def from_cylinder(cls, cylinder):
172+
"""Create a RhinoBrep from a box.
173+
174+
Parameters
175+
----------
176+
box : :class:`~compas.geometry.Box`
177+
The box geometry of the brep.
178+
179+
Returns
180+
-------
181+
:class:`~compas_rhino.geometry.RhinoBrep`
182+
183+
"""
184+
rhino_cylinder = cylinder_to_rhino(cylinder)
185+
return cls.from_brep(rhino_cylinder.ToBrep(True, True))
186+
169187
# ==============================================================================
170188
# Methods
171189
# ==============================================================================
@@ -211,6 +229,81 @@ def trim(self, trimming_plane, tolerance=TOLERANCE):
211229

212230
self._brep = results[0]
213231

232+
@classmethod
233+
def from_boolean_difference(cls, breps_a, breps_b):
234+
"""Construct a Brep from the boolean difference of two groups of Breps.
235+
236+
Parameters
237+
----------
238+
brep_a : :class:`~compas_rhino.geometry.RhinoBrep` or list(:class:`~compas_rhino.geometry.RhinoBrep`)
239+
brep_b : :class:`~compas_rhino.geometry.RhinoBrep` or list(:class:`~compas_rhino.geometry.RhinoBrep`)
240+
241+
Returns
242+
-------
243+
list(:class:`~compas_rhino.geometry.RhinoBrep`)
244+
list of one or more resulting Breps.
245+
246+
"""
247+
if not isinstance(brep_a, list):
248+
brep_a = [brep_a]
249+
if not isinstance(brep_b, list):
250+
brep_b = [brep_b]
251+
resulting_breps = Rhino.Geometry.Brep.CreateBooleanDifference(
252+
[b.native_brep for b in brep_a],
253+
[b.native_brep for b in brep_b],
254+
TOLERANCE
255+
)
256+
return [RhinoBrep.from_brep(brep) for brep in resulting_breps]
257+
258+
@classmethod
259+
def from_boolean_union(cls, breps_a, breps_b):
260+
"""Construct a Brep from the boolean union of two groups of Breps.
261+
262+
Parameters
263+
----------
264+
brep_a : :class:`~compas_rhino.geometry.RhinoBrep` or list(:class:`~compas_rhino.geometry.RhinoBrep`)
265+
brep_b : :class:`~compas_rhino.geometry.RhinoBrep` or list(:class:`~compas_rhino.geometry.RhinoBrep`)
266+
267+
Returns
268+
-------
269+
list(:class:`~compas_rhino.geometry.RhinoBrep`)
270+
list of one or more resulting Breps.
271+
272+
"""
273+
if not isinstance(brep_a, list):
274+
brep_a = [brep_a]
275+
if not isinstance(brep_b, list):
276+
brep_b = [brep_b]
277+
278+
resulting_breps = Rhino.Geometry.Brep.CreateBooleanUnion([b.native_brep for b in brep_a + brep_b], TOLERANCE)
279+
return [RhinoBrep.from_brep(brep) for brep in resulting_breps]
280+
281+
@classmethod
282+
def from_boolean_intersection(cls, brep_a, brep_b):
283+
"""Construct a Brep from the boolean intersection of two groups of Breps.
284+
285+
Parameters
286+
----------
287+
brep_a : :class:`~compas_rhino.geometry.RhinoBrep` or list(:class:`~compas_rhino.geometry.RhinoBrep`)
288+
brep_b : :class:`~compas_rhino.geometry.RhinoBrep` or list(:class:`~compas_rhino.geometry.RhinoBrep`)
289+
290+
Returns
291+
-------
292+
list(:class:`~compas_rhino.geometry.RhinoBrep`)
293+
list of one or more resulting Breps.
294+
295+
"""
296+
if not isinstance(brep_a, list):
297+
brep_a = [brep_a]
298+
if not isinstance(brep_b, list):
299+
brep_b = [brep_b]
300+
resulting_breps = Rhino.Geometry.Brep.CreateBooleanIntersection(
301+
[b.native_brep for b in brep_a],
302+
[b.native_brep for b in brep_b],
303+
TOLERANCE
304+
)
305+
return [RhinoBrep.from_brep(brep) for brep in resulting_breps]
306+
214307
# ==============================================================================
215308
# Other Methods
216309
# ==============================================================================

0 commit comments

Comments
 (0)