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

Joints by topology #157

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased

### Added
* added `ApplyJointsByTopology` GH Component
* added `fabrication` package
* added `BTLx` as a wrapper for `TimberAssembly` to generate .btlx files for machining timber beams
* added `BTLxPart` as wrapper for `Beam`
Expand Down
8 changes: 4 additions & 4 deletions src/compas_timber/connections/french_ridge_lap.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,10 @@ def check_geometry(self):
This method checks whether the parts are aligned as necessary to create French Ridge Lap and determines which face is used as reference face for machining.
"""
if not (self.beam_a and self.beam_b):
raise(BeamJoinningError("French Ridge Lap requires 2 beams"))
raise (BeamJoinningError("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(BeamJoinningError("widths and heights for both beams must match for the French Ridge Lap"))
raise (BeamJoinningError("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)

Expand All @@ -113,7 +113,7 @@ def check_geometry(self):
elif angle_vectors(normal, -self.beam_a.frame.zaxis) < 0.001:
indices.append(2)
else:
raise(BeamJoinningError("part not aligned with corner normal, no French Ridge Lap possible"))
raise (BeamJoinningError("part not aligned with corner normal, no French Ridge Lap possible"))

if abs(angle_vectors(normal, self.beam_b.frame.yaxis) - math.pi) < 0.001:
indices.append(3)
Expand All @@ -124,5 +124,5 @@ def check_geometry(self):
elif abs(angle_vectors(normal, -self.beam_b.frame.zaxis) - math.pi) < 0.001:
indices.append(2)
else:
raise(BeamJoinningError("part not aligned with corner normal, no French Ridge Lap possible"))
raise (BeamJoinningError("part not aligned with corner normal, no French Ridge Lap possible"))
self.reference_face_indices = {str(self.beam_a.key): indices[0], str(self.beam_b.key): indices[1]}
1 change: 0 additions & 1 deletion src/compas_timber/connections/joint.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,6 @@ def create(cls, assembly, *beams):

@property
def ends(self):

"""Returns a map of ehich end of each beam is joined by this joint."""

self._ends = {}
Expand Down
6 changes: 6 additions & 0 deletions src/compas_timber/fabrication/btlx.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,12 @@ def __init__(self, beam):
self.processings = []
self._et_element = None

def reference_surface_from_beam_face(self, beam_face):
"""Finds the reference surface with normal that matches the normal of the beam face argument"""
for key, face in self.reference_surfaces.items():
if face.normal == beam_face.normal:
return key

def reference_surface_planes(self, index):
"""Returns the reference surface planes for a given index per BTLx docs."""
if len(self._reference_surfaces) != 6:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
from compas_timber.fabrication import BTLx
from compas_timber.fabrication import BTLxProcess

# from compas_timber.fabrication import BT
...

class BTLxFrenchRidgeLap(object):
"""
BTLxFrenchRidgeLap represents a fabrication process for creating a French Ridge Lap joint.
Expand Down Expand Up @@ -78,7 +77,7 @@ def __init__(self, part, joint, is_top):
"Priority": "0",
"ProcessID": "0",
"ReferencePlaneID": str(self.ref_face_index),
} # XML attributes of the process element in the BTLx file
} # XML attributes of the process element in the BTLx file

self.process_joints()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def apply_processings(self, joint, parts):
bottom_key = joint.beams[1].key
bottom_part = parts[str(bottom_key)]
bottom_part._test.append(
bottom_part.reference_surface_planes(joint.reference_face_indices[str(bottom_part.beam.key)]))
bottom_part.reference_surface_planes(joint.reference_face_indices[str(bottom_part.beam.key)])
)
bottom_part.processings.append(BTLxFrenchRidgeLap.create_process(bottom_part, joint, False))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def __init__(self):

@classmethod
def apply_processings(cls, joint, parts):
""" Apply processings to the joint and its associated parts.
"""Apply processings to the joint and its associated parts.

Parameters:
----------
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
from ghpythonlib.componentbase import executingcomponent as component
from Grasshopper.Kernel.GH_RuntimeMessageLevel import Warning

from compas_timber.connections import ConnectionSolver
from compas_timber.connections import JointTopology
from compas_timber.ghpython import JointDefinition

from compas_timber.connections import LButtJoint
from compas_timber.connections import LMiterJoint
from compas_timber.connections import TButtJoint
from compas_timber.connections import XHalfLapJoint
from compas_timber.connections import FrenchRidgeLapJoint


class MyComponent(component):
def RunScript(self, Beams, L, T, X, MaxDistance):
MAP = {
"T-Butt": TButtJoint,
"L-Miter": LMiterJoint,
"L-Butt": LButtJoint,
"French Ridge Lap": FrenchRidgeLapJoint,
"X-HalfLap": XHalfLapJoint,
}

max_dist = MaxDistance or 1
solver = ConnectionSolver()
found_pairs = solver.find_intersecting_pairs(Beams, rtree=True, max_distance=max_dist)
Joints = []
Info = []

for pair in found_pairs:
beam_a, beam_b = pair
detected_topo, beam_a, beam_b = solver.find_topology(beam_a, beam_b, max_distance=max_dist)
flip_beams = False
if detected_topo == JointTopology.TOPO_UNKNOWN:
continue
elif detected_topo == JointTopology.TOPO_L:
joint_type = MAP.get(str(L)) or LMiterJoint
if joint_type == LButtJoint:
if beam_a.width * beam_a.height > beam_b.width * beam_b.height:
flip_beams = True
elif detected_topo == JointTopology.TOPO_T:
joint_type = MAP.get(str(T)) or TButtJoint
elif detected_topo == JointTopology.TOPO_X:
joint_type = MAP.get(str(X)) or XHalfLapJoint

if flip_beams:
Joints.append(JointDefinition(joint_type, [beam_b, beam_a]))
else:
Joints.append(JointDefinition(joint_type, [beam_a, beam_b]))
msg = "Beams: {}, {} meet with topology: {} and use joint: {}"
Info.append(msg.format(beam_a, beam_b, JointTopology.get_name(detected_topo), joint_type.__name__))
return Joints, Info
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{
"name": "Apply Joints by Topology",
"nickname": "JointsByTopo",
"category": "COMPAS Timber",
"subcategory": "Joints",
"description": "Analyzes beams and applies given joint types for each topology type.",
"exposure": 2,
"ghpython": {
"isAdvancedMode": true,
"iconDisplay": 0,
"inputParameters": [
{
"name": "Beams",
"description": "Collection of Beams.",
"typeHintID": "none",
"scriptParamAccess": 1
},
{
"name": "L",
"description": "Joint type to be applied to L topology. Default type is L-Miter. If L-Butt, the beam with a larger cross section area will be used as crossing beam.",
"typeHintID": "none",
"scriptParamAccess": 0
},
{
"name": "T",
"description": "Joint type to be applied to T topology. Default type is T-Butt.",
"typeHintID": "float",
"scriptParamAccess": 0
},
{
"name": "X",
"description": "Joint type to be applied to X topology. Default type is X-HalfLap.",
"typeHintID": "float",
"scriptParamAccess": 0
},
{
"name": "MaxDistance",
"description": "(optional) Maximum distance between centerlines of two Beams (limited to segments) to consider the Beams as connecting. Optional (if omitted, a default value equal to the average beam height will be taken).",
"typeHintID": "float",
"scriptParamAccess": 0
}
],
"outputParameters": [
{
"name": "Joints",
"description": "List of JointDefinitions."
},
{
"name": "Info",
"description": "Report and analysis of the found connections and any issues."
}
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from Grasshopper.Kernel.GH_RuntimeMessageLevel import Error
from Grasshopper.Kernel.GH_RuntimeMessageLevel import Warning

from compas.scene import Scene
from pip install compas==1.13.3.scene import Scene
Copy link
Member

Choose a reason for hiding this comment

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

does that work? that's a scary import :P

from compas_timber.parts.beam import Beam as ctBeam


Expand Down
2 changes: 1 addition & 1 deletion tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"ghuser": {
"source_dir": "src/compas_timber/ghpython/components",
"target_dir": "src/compas_timber/ghpython/components/ghuser",
"prefix": "(COMPAS_TIMBER)",
"prefix": "CT_",
Copy link
Member

Choose a reason for hiding this comment

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

I started using Projectname: in core and fab components, maybe change to CT: ?

},
}
)
Loading