-
Notifications
You must be signed in to change notification settings - Fork 26
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
Changes from 37 commits
ca91d86
bd5bb23
3aeb1b3
1b1c884
6d158cb
7c555fc
e2fb8f7
4ea29ad
8d9b9a2
e29296e
3d24cc1
bfb6c76
f89e73b
5770f73
3ff09d3
c6c0bbe
2ee0598
fbf95fe
c19caa1
f4e1374
95eb5aa
e957b03
145bbd6
6c47c10
a4d765a
0c50f7e
4c6aa97
c43f629
956fd2e
d82c18c
1644a2c
5db395e
dd234b7
75180f6
31654be
cd685ff
f410ffc
82a6adb
4711320
84ed0a5
aa6796f
0965d0b
2ea56c7
ddca3d4
20bef76
a7643fa
1cd11bd
f5bef56
88ab1e8
50b7bd1
26ecfdd
c0a84cc
8a18292
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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") | ||
print(indices) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. please remove debug prints. There was a problem hiding this comment. Choose a reason for hiding this commentThe 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") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there's a There was a problem hiding this comment. Choose a reason for hiding this commentThe 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]) |
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", | ||
] |
There was a problem hiding this comment.
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.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done