Skip to content

Commit

Permalink
Merge pull request #275 from gramaziokohler/features_extensions
Browse files Browse the repository at this point in the history
Features extensions
  • Loading branch information
chenkasirer authored Sep 9, 2024
2 parents 90a1b27 + 1602d1a commit cde3ab7
Show file tree
Hide file tree
Showing 10 changed files with 167 additions and 36 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

* Fixed error in BakeWithBoxMap component.
* Added `add_extensions` to `Joint` interface.
* Added `process_joinery` to `TimberModel`.
* Features are not automatically added when creating a joint using `Joint.create()`.
* Features are not automatically added when de-serializing.

### Removed

Expand Down
Binary file modified examples/Grasshopper/dynamic_gh_demo.gh
Binary file not shown.
17 changes: 16 additions & 1 deletion src/compas_timber/connections/joint.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,22 @@ def add_features(self):
"""
raise NotImplementedError

def add_extensions(self):
"""Adds the extensions defined by this joint to affected beam(s).
This is optional and should only be implemented by joints that require it.
Note
----
Extensions are added to all beams before the features are added.
Raises
------
:class:`~compas_timber.connections.BeamJoinningError`
Should be raised whenever the joint was not able to calculate the extensions to be applied to the beams.
"""
pass

def restore_beams_from_keys(self, model):
"""Restores the reference to the beams associate with this joint.
Expand Down Expand Up @@ -124,7 +140,6 @@ def create(cls, model, *beams, **kwargs):
raise ValueError("Expected at least 2 beams. Got instead: {}".format(len(beams)))
joint = cls(*beams, **kwargs)
model.add_joint(joint, beams)
joint.add_features()
return joint

@property
Expand Down
49 changes: 33 additions & 16 deletions src/compas_timber/connections/l_butt.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,37 @@ def get_main_cutting_plane(self):
)
return super(LButtJoint, self).get_main_cutting_plane()

def add_extensions(self):
"""Calculates and adds the necessary extensions to the beams.
This method is automatically called when joint is created by the call to `Joint.create()`.
Raises
------
BeamJoinningError
If the extension could not be calculated.
"""
assert self.main_beam and self.cross_beam # should never happen

try:
main_cutting_plane = self.get_main_cutting_plane()[0]
start_main, end_main = self.main_beam.extension_to_plane(main_cutting_plane)
extension_tolerance = 0.01 # TODO: this should be proportional to the unit used
self.main_beam.add_blank_extension(
start_main + extension_tolerance, end_main + extension_tolerance, self.guid
)

if self.modify_cross:
cross_cutting_plane = self.get_cross_cutting_plane()
start_cross, end_cross = self.cross_beam.extension_to_plane(cross_cutting_plane)
self.cross_beam.add_blank_extension(
start_cross + extension_tolerance, end_cross + extension_tolerance, self.guid
)
except Exception as ex:
debug_info = getattr(ex, "debug_info", str(ex))
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=debug_info)

def add_features(self):
"""Adds the required extension and trimming features to both beams.
Expand All @@ -93,33 +124,19 @@ def add_features(self):
assert self.main_beam and self.cross_beam # should never happen
if self.features:
self.main_beam.remove_features(self.features)
start_main, start_cross = None, None

try:
main_cutting_plane = self.get_main_cutting_plane()[0]
cross_cutting_plane = self.get_cross_cutting_plane()
start_main, end_main = self.main_beam.extension_to_plane(main_cutting_plane)
start_cross, end_cross = self.cross_beam.extension_to_plane(cross_cutting_plane)
except BeamJoinningError as be:
raise be
except AttributeError as ae:
# I want here just the plane that caused the error
geometries = [cross_cutting_plane] if start_main is not None else [main_cutting_plane]
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=str(ae), debug_geometries=geometries)
except Exception as ex:
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=str(ex))

extension_tolerance = 0.01 # TODO: this should be proportional to the unit used
debug_info = getattr(ex, "debug_info", str(ex))
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=debug_info)

if self.modify_cross:
self.cross_beam.add_blank_extension(
start_cross + extension_tolerance, end_cross + extension_tolerance, self.guid
)
f_cross = CutFeature(cross_cutting_plane)
self.cross_beam.add_features(f_cross)
self.features.append(f_cross)

self.main_beam.add_blank_extension(start_main + extension_tolerance, end_main + extension_tolerance, self.guid)
f_main = CutFeature(main_cutting_plane)
if self.mill_depth:
self.cross_beam.add_features(MillVolume(self.subtraction_volume()))
Expand Down
24 changes: 21 additions & 3 deletions src/compas_timber/connections/l_halflap.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,21 @@ class LHalfLapJoint(LapJoint):
def __init__(self, main_beam=None, cross_beam=None, flip_lap_side=False, cut_plane_bias=0.5, **kwargs):
super(LHalfLapJoint, self).__init__(main_beam, cross_beam, flip_lap_side, cut_plane_bias, **kwargs)

def add_features(self):
assert self.main_beam and self.cross_beam
def add_extensions(self):
"""Calculates and adds the necessary extensions to the beams.
This method is automatically called when joint is created by the call to `Joint.create()`.
Raises
------
BeamJoinningError
If the extension could not be calculated.
"""
assert self.main_beam and self.cross_beam
try:
main_cutting_frame = self.get_main_cutting_frame()
cross_cutting_frame = self.get_cross_cutting_frame()
negative_brep_main_beam, negative_brep_cross_beam = self._create_negative_volumes()
except Exception as ex:
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=str(ex))

Expand All @@ -70,6 +78,16 @@ def add_features(self):
start_cross + extension_tolerance, end_cross + extension_tolerance, self.guid
)

def add_features(self):
assert self.main_beam and self.cross_beam

try:
main_cutting_frame = self.get_main_cutting_frame()
cross_cutting_frame = self.get_cross_cutting_frame()
negative_brep_main_beam, negative_brep_cross_beam = self._create_negative_volumes()
except Exception as ex:
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=str(ex))

main_volume = MillVolume(negative_brep_main_beam)
cross_volume = MillVolume(negative_brep_cross_beam)

Expand Down
35 changes: 26 additions & 9 deletions src/compas_timber/connections/l_miter.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,18 +98,18 @@ def get_cutting_planes(self):
plnB = Frame.from_plane(plnB)
return plnA, plnB

def add_features(self):
"""Adds the required extension and trimming features to both beams.
def add_extensions(self):
"""Calculates and adds the necessary extensions to the beams.
This method is automatically called when joint is created by the call to `Joint.create()`.
"""
assert self.beam_a and self.beam_b # should never happen

if self.features:
self.beam_a.remove_features(self.features)
self.beam_b.remove_features(self.features)
Raises
------
BeamJoinningError
If the extension could not be calculated.
"""
assert self.beam_a and self.beam_b
start_a, start_b = None, None
try:
plane_a, plane_b = self.get_cutting_planes()
Expand All @@ -121,9 +121,26 @@ def add_features(self):
raise BeamJoinningError(self.beams, self, debug_info=str(ae), debug_geometries=geometries)
except Exception as ex:
raise BeamJoinningError(self.beams, self, debug_info=str(ex))

self.beam_a.add_blank_extension(start_a, end_a, self.guid)
self.beam_b.add_blank_extension(start_b, end_b, self.guid)

def add_features(self):
"""Adds the required extension and trimming features to both beams.
This method is automatically called when joint is created by the call to `Joint.create()`.
"""
assert self.beam_a and self.beam_b # should never happen

if self.features:
self.beam_a.remove_features(self.features)
self.beam_b.remove_features(self.features)

try:
plane_a, plane_b = self.get_cutting_planes()
except Exception as ex:
raise BeamJoinningError(self.beams, self, debug_info=str(ex))

f1, f2 = CutFeature(plane_a), CutFeature(plane_b)
self.beam_a.add_features(f1)
self.beam_b.add_features(f2)
Expand Down
27 changes: 23 additions & 4 deletions src/compas_timber/connections/t_butt.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,28 @@ def restore_beams_from_keys(self, model):
self.main_beam = model.beam_by_guid(self.main_beam_guid)
self.cross_beam = model.beam_by_guid(self.cross_beam_guid)

def add_extensions(self):
"""Calculates and adds the necessary extensions to the beams.
This method is automatically called when joint is created by the call to `Joint.create()`.
Raises
------
BeamJoinningError
If the extension could not be calculated.
"""
assert self.main_beam and self.cross_beam
try:
cutting_plane = self.get_main_cutting_plane()[0]
start_main, end_main = self.main_beam.extension_to_plane(cutting_plane)
except AttributeError as ae:
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=str(ae), debug_geometries=[cutting_plane])
except Exception as ex:
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=str(ex))
extension_tolerance = 0.01 # TODO: this should be proportional to the unit used
self.main_beam.add_blank_extension(start_main + extension_tolerance, end_main + extension_tolerance, self.guid)

def add_features(self):
"""Adds the trimming plane to the main beam (no features for the cross beam).
Expand All @@ -50,18 +72,15 @@ def add_features(self):

if self.features:
self.main_beam.remove_features(self.features)

cutting_plane = None
try:
cutting_plane = self.get_main_cutting_plane()[0]
start_main, end_main = self.main_beam.extension_to_plane(cutting_plane)
except AttributeError as ae:
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=str(ae), debug_geometries=[cutting_plane])
except Exception as ex:
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=str(ex))

extension_tolerance = 0.01 # TODO: this should be proportional to the unit used
self.main_beam.add_blank_extension(start_main + extension_tolerance, end_main + extension_tolerance, self.guid)

trim_feature = CutFeature(cutting_plane)
if self.mill_depth:
self.cross_beam.add_features(MillVolume(self.subtraction_volume()))
Expand Down
30 changes: 28 additions & 2 deletions src/compas_timber/connections/t_halflap.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,22 @@ class THalfLapJoint(LapJoint):
def __init__(self, main_beam=None, cross_beam=None, flip_lap_side=False, cut_plane_bias=0.5):
super(THalfLapJoint, self).__init__(main_beam, cross_beam, flip_lap_side, cut_plane_bias)

def add_features(self):
def add_extensions(self):
"""Calculates and adds the necessary extensions to the beams.
This method is automatically called when joint is created by the call to `Joint.create()`.
Raises
------
BeamJoinningError
If the extension could not be calculated.
"""
assert self.main_beam and self.cross_beam # should never happen

main_cutting_frame = None
try:
main_cutting_frame = self.get_main_cutting_frame()
negative_brep_main_beam, negative_brep_cross_beam = self._create_negative_volumes()
start_main, end_main = self.main_beam.extension_to_plane(main_cutting_frame)
except AttributeError as ae:
raise BeamJoinningError(
Expand All @@ -52,6 +61,23 @@ def add_features(self):
extension_tolerance = 0.01 # TODO: this should be proportional to the unit used
self.main_beam.add_blank_extension(start_main + extension_tolerance, end_main + extension_tolerance, self.guid)

def add_features(self):
assert self.main_beam and self.cross_beam # should never happen

if self.features:
self.main_beam.remove_features(self.features)

main_cutting_frame = None
try:
main_cutting_frame = self.get_main_cutting_frame()
negative_brep_main_beam, negative_brep_cross_beam = self._create_negative_volumes()
except AttributeError as ae:
raise BeamJoinningError(
beams=self.beams, joint=self, debug_info=str(ae), debug_geometries=[main_cutting_frame]
)
except Exception as ex:
raise BeamJoinningError(beams=self.beams, joint=self, debug_info=str(ex))

main_volume = MillVolume(negative_brep_main_beam)
cross_volume = MillVolume(negative_brep_cross_beam)
self.main_beam.add_features(main_volume)
Expand Down
3 changes: 3 additions & 0 deletions src/compas_timber/ghpython/components/CT_Model/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,9 @@ def RunScript(self, Beams, JointRules, Features, MaxDistance, CreateGeometry):
else:
handled_beams.append(beam_pair_ids)

# applies extensions and features resulting from joints
Model.process_joinery()

if Features:
features = [f for f in Features if f is not None]
for f_def in features:
Expand Down
14 changes: 13 additions & 1 deletion src/compas_timber/model/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ def __from_data__(cls, data):
for interaction in model.interactions():
model._joints.append(interaction)
interaction.restore_beams_from_keys(model)
interaction.add_features()
return model

def __init__(self, *args, **kwargs):
Expand Down Expand Up @@ -170,3 +169,16 @@ def remove_joint(self, joint):
def set_topologies(self, topologies):
"""TODO: calculate the topologies inside the model using the ConnectionSolver."""
self._topologies = topologies

def process_joinery(self):
"""Process the joinery of the model. This methods instructs all joints to add their extensions and features.
The sequence is important here since the feature parameters must be calculated based on the extended blanks.
For this reason, the first iteration will only extend the beams, and the second iteration will add the features.
"""
for joint in self.joints:
joint.add_extensions()

for joint in self.joints:
joint.add_features()

0 comments on commit cde3ab7

Please sign in to comment.