Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fabrication initial PR #138

Merged
merged 53 commits into from
Dec 4, 2023
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
ca91d86
FabBranch initial commit
obucklin Sep 5, 2023
bd5bb23
6_9 nice
obucklin Sep 6, 2023
3aeb1b3
fixed circular import
obucklin Sep 6, 2023
1b1c884
Merge branch 'main' into fabBranch
obucklin Sep 6, 2023
6d158cb
added BTLX part string methods
obucklin Sep 14, 2023
7c555fc
merge main
obucklin Sep 14, 2023
e2fb8f7
Merge branch 'main' into fabBranch
obucklin Sep 14, 2023
4ea29ad
BTLx_Shape and beam.geometry call in BTLx class
obucklin Sep 15, 2023
8d9b9a2
shape data as string argument
obucklin Sep 18, 2023
e29296e
chen saved me 3 weeks of work and 50000 grey hairs
obucklin Oct 5, 2023
3d24cc1
remove beam inheritnce
obucklin Oct 5, 2023
bfb6c76
Merge branch 'main' into fabBranch
obucklin Oct 5, 2023
f89e73b
before I commit to fixed key merge
obucklin Oct 5, 2023
5770f73
pre main #135 merge
obucklin Oct 5, 2023
3ff09d3
pre-beam.key update
obucklin Oct 6, 2023
c6c0bbe
Merge branch 'main' into fabBranch
obucklin Oct 6, 2023
2ee0598
works with joint input
obucklin Oct 6, 2023
fbf95fe
BTLx isolated and ready for expansion
obucklin Oct 9, 2023
c19caa1
remplaced blank_geometry def with beam.shape
obucklin Oct 9, 2023
f4e1374
added apply_process flag
obucklin Oct 10, 2023
95eb5aa
added BTLxJoint class. it broke
obucklin Oct 11, 2023
e957b03
started French Ridge Lap
obucklin Oct 11, 2023
145bbd6
Added FrenchRidgeLapJoint incl BTLx and GH modules
obucklin Oct 11, 2023
6c47c10
Cleaned up before bldg french ridge lap GH comps
obucklin Oct 11, 2023
a4d765a
Merge branch 'main' into fabBranch
obucklin Oct 11, 2023
0c50f7e
hopefully Py2.7 compliant. no jack cut import
obucklin Oct 18, 2023
4c6aa97
doesn't call registered process
obucklin Oct 18, 2023
c43f629
Merge branch 'main' into Fabrication
obucklin Oct 18, 2023
956fd2e
everything but REGISTERED_PROCESSES
obucklin Oct 18, 2023
d82c18c
added metadata
obucklin Oct 19, 2023
1644a2c
works but not FrenchLap
obucklin Oct 19, 2023
5db395e
Jack cut factories functioning
obucklin Oct 20, 2023
dd234b7
before code review
obucklin Oct 24, 2023
75180f6
merge to main
obucklin Oct 24, 2023
31654be
Ready for initial PR
obucklin Oct 24, 2023
cd685ff
initial PR
obucklin Oct 24, 2023
f410ffc
sorted into folders and commented
obucklin Oct 25, 2023
82a6adb
started_removing_BTLxJoint
obucklin Nov 7, 2023
4711320
cleaned up, removed BTLxJoint
obucklin Nov 8, 2023
84ed0a5
started_wrapperizing
obucklin Nov 22, 2023
aa6796f
Merge branch 'main' into Fabrication
obucklin Nov 27, 2023
0965d0b
it worked and then not
obucklin Nov 27, 2023
2ea56c7
added blank_frame and blank_length to Beam
obucklin Nov 27, 2023
ddca3d4
Blank_frame and blank_length initially beam values
obucklin Nov 28, 2023
20bef76
ran clean, format, test etc.
obucklin Nov 29, 2023
a7643fa
try test
obucklin Nov 29, 2023
1cd11bd
changelog and documentation
obucklin Nov 29, 2023
f5bef56
Merge branch 'main' into Fabrication
chenkasirer Dec 1, 2023
88ab1e8
made blank stuff properties
chenkasirer Dec 1, 2023
50b7bd1
implemented BeamJoinningError
obucklin Dec 1, 2023
26ecfdd
Merge branch 'Fabrication' of https://github.com/gramaziokohler/compa…
obucklin Dec 1, 2023
c0a84cc
Added docstrings and resolved comments
obucklin Dec 4, 2023
8a18292
Merge branch 'main' into Fabrication
obucklin Dec 4, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/compas_timber/connections/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from .l_butt import LButtJoint
from .l_miter import LMiterJoint
from .x_halflap import XHalfLapJoint
from .french_ridge_lap import FrenchRidgeLapJoint
from .solver import JointTopology
from .solver import ConnectionSolver
from .solver import find_neighboring_beams
Expand All @@ -62,6 +63,7 @@
"LButtJoint",
"LMiterJoint",
"XHalfLapJoint",
"FrenchRidgeLapJoint",
"JointTopology",
"ConnectionSolver",
"find_neighboring_beams",
Expand Down
152 changes: 152 additions & 0 deletions src/compas_timber/connections/french_ridge_lap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
from compas.geometry import Frame
from compas.geometry import cross_vectors
from compas.geometry import angle_vectors
import math


from compas_timber.parts import BeamExtensionFeature
from compas_timber.parts import BeamTrimmingFeature

from .joint import Joint
from .joint import beam_side_incidence
from .solver import JointTopology


class FrenchRidgeLapJoint(Joint):
"""Represents a French Ridge Lap type joint which joins two beam at their ends.

This joint type is compatible with beams in L topology.

Please use `LButtJoint.create()` to properly create an instance of this class and associate it with an assembly.

Parameters
----------
assembly : :class:`~compas_timber.assembly.TimberAssembly`
The assembly associated with the beams to be joined.
beam_a : :class:`~compas_timber.parts.Beam`
The top beam to be joined.
beam_b : :class:`~compas_timber.parts.Beam`
The bottom beam to be joined.

Attributes
----------
beams : list(:class:`~compas_timber.parts.Beam`)
The beams joined by this joint.
joint_type : str
A string representation of this joint's type.


"""

SUPPORTED_TOPOLOGY = JointTopology.TOPO_L

def __init__(self, beam_a=None, beam_b=None, gap=0.0, frame=None, key=None):
super(FrenchRidgeLapJoint, self).__init__(frame=frame, key=key)
self.beam_a = beam_a
self.beam_b = beam_b
self.beam_a_key = beam_a.key if beam_a else None
self.beam_b_key = beam_b.key if beam_b else None
self.features = []
self.reference_face_indices = {}
self.check_geometry()

@property
def data(self):
data_dict = {
"beam_a_key": self.beam_a_key,
"beam_b_key": self.beam_b_key,
"gap": self.gap,
}
data_dict.update(super(FrenchRidgeLapJoint, self).data)
return data_dict

@classmethod
def from_data(cls, value):
instance = cls(frame=Frame.from_data(value["frame"]), key=value["key"], gap=value["gap"])
instance.beam_a_key = value["beam_a_key"]
instance.beam_b_key = value["beam_b_key"]
return instance

@property
def beams(self):
return [self.beam_a, self.beam_b]

@property
def joint_type(self):
return "French Ridge Lap"

@property
def cutting_plane_top(self):
angles_faces = beam_side_incidence(self.beam_a, self.beam_b)
cfr = max(angles_faces, key=lambda x: x[0])[1]
cfr = Frame(cfr.point, cfr.xaxis, cfr.yaxis * -1.0) # flip normal
return cfr

@property
def cutting_plane_bottom(self):
angles_faces = beam_side_incidence(self.beam_b, self.beam_a)
cfr = max(angles_faces, key=lambda x: x[0])[1]
return cfr

def restore_beams_from_keys(self, assemly):
"""After de-serialization, resotres references to the top and bottom beams saved in the assembly."""
self.beam_a = assemly.find_by_key(self.beam_a_key)
self.beam_b = assemly.find_by_key(self.beam_b_key)

def check_geometry(self):
"""
This method checks whether the parts are aligned as necessary to create French Ridge Lap.
"""
if not (self.beam_a and self.beam_b):
raise ("French Ridge Lap requires 2 beams")

if not (self.beam_a.width == self.beam_b.width and self.beam_a.height == self.beam_b.height):
raise ("widths and heights for both beams must match for the French Ridge Lap")

normal = cross_vectors(self.beam_a.frame.xaxis, self.beam_b.frame.xaxis)

indices = []

if angle_vectors(normal, self.beam_a.frame.yaxis) < 0.001:
indices.append(3)
elif angle_vectors(normal, self.beam_a.frame.zaxis) < 0.001:
indices.append(4)
elif angle_vectors(normal, -self.beam_a.frame.yaxis) < 0.001:
indices.append(1)
elif angle_vectors(normal, -self.beam_a.frame.zaxis) < 0.001:
indices.append(2)
else:
raise ("part not aligned with corner normal, no French Ridge Lap possible")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a BeamJoiningError you could raise here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

print(indices)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please remove debug prints.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


if abs(angle_vectors(normal, self.beam_b.frame.yaxis) - math.pi) < 0.001:
indices.append(3)
elif abs(angle_vectors(normal, self.beam_b.frame.zaxis) - math.pi) < 0.001:
indices.append(4)
elif abs(angle_vectors(normal, -self.beam_b.frame.yaxis) - math.pi) < 0.001:
indices.append(1)
elif abs(angle_vectors(normal, -self.beam_b.frame.zaxis) - math.pi) < 0.001:
indices.append(2)
else:
raise ("part not aligned with corner normal, no French Ridge Lap possible")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's a BeamJoiningError you could raise here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


self.reference_face_indices = {str(self.beam_a.key): indices[0], str(self.beam_b.key): indices[1]}
obucklin marked this conversation as resolved.
Show resolved Hide resolved

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()`.

"""

if self.features:
self.beam_a.clear_features(self.features)
self.beam_b.clear_features(self.features)
self.features = []

top_extend = BeamExtensionFeature(*self.beam_a.extension_to_plane(self.cutting_plane_top))
bottom_extend = BeamExtensionFeature(*self.beam_b.extension_to_plane(self.cutting_plane_bottom))

self.beam_a.add_feature(top_extend)
self.beam_b.add_feature(bottom_extend)
self.features.extend([top_extend, bottom_extend])
3 changes: 3 additions & 0 deletions src/compas_timber/connections/t_butt.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
from compas.geometry import Frame

from compas_timber.parts import BeamTrimmingFeature
from compas_timber.parts import BeamExtensionFeature

from .joint import BeamJoinningError
from .joint import Joint
Expand Down Expand Up @@ -98,8 +99,10 @@ def add_features(self):
self.features = []

trim_feature = BeamTrimmingFeature(self.cutting_plane)
extend_feature = BeamExtensionFeature(*self.main_beam.extension_to_plane(self.cutting_plane))
try:
self.main_beam.add_feature(trim_feature)
self.main_beam.add_feature(extend_feature)
self.features.append(trim_feature)
except BrepTrimmingError:
msg = "Failed trimming beam: {} with cutting plane: {}. Does it intersect with beam: {}".format(
Expand Down
52 changes: 52 additions & 0 deletions src/compas_timber/fabrication/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
"""
obucklin marked this conversation as resolved.
Show resolved Hide resolved
Processes are BTLx machining steps. Each Joint type generates one or more different processes.

To add a new joint including BTLx process or processes:

1. create the joint module
-inherits from Joint class.
-This does not requre generating a geometrical representation.

2. create necessary processes
-if the process or processes do not exist, generate new modules in the btlx_processes package.
-new processes should follow the BTLx documentation found here: https://design2machine.com/btlx/btlx_2_1_0.pdf
-processes are instantiated with the apply_process(BTLxPart, BTLxJoint, *args) method that appends the process to the input BTLxPart.processes list.
-BTLxProcess is instantiated in apply_process method with BTLxProcess(PROCESS_TYPE, header_attributes, process_params) where:
-PROCESS_TYPE a class attribute which matches the btlx process name
-self.header_attributes which matches as a dict,
-self.process_parameters which describe the geometric parameters of the process

3. create a joint factory
-takes a BTLxJoint as input and calls a specific btlx_joint.apply_process() method for each process for each BTLxPart/Beam used in that joint.
-The joint factory is called with a factory.apply_processes(BTLxJoint) method which takes a BTLxJoint object as input.
-the factory module should call the BTLxJoint.register_joint(joint type, joint factory) function so that the BTLxJoint class can call specific factory types.
-the factory can apply multiple processes to a single part

4. create import and dependencies
-add import to this __init__.py file

Mind the reference surfaces used in the BTLx definition

"""

from .btlx import BTLx
from .btlx import BTLxProcess
from .btlx import BTLxJoint
from .btlx_processes.btlx_jack_cut import BTLxJackCut
from .btlx_processes.btlx_french_ridge_lap import BTLxFrenchRidgeLap
from .joint_factories.l_butt_factory import LButtFactory
from .joint_factories.t_butt_factory import TButtFactory
from .joint_factories.l_miter_factory import LMiterFactory
from .joint_factories.french_ridge_factory import FrenchRidgeFactory

__all__ = [
"BTLx",
"BTLxProcess",
"BTLxJoint",
"BTLxJackCut",
"BTLxFrenchRidgeLap",
"LButtFactory",
"TButtFactory",
"LMiterFactory",
"FrenchRidgeFactory",
]
Loading
Loading