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

FreeContour BTLxProcessing #382

Open
wants to merge 17 commits into
base: main
Choose a base branch
from
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added
* Added `YButtJoint` which joins the ends of three joints where the `cross_beams` get a miter cut and the `main_beam` gets a double cut.
obucklin marked this conversation as resolved.
Show resolved Hide resolved
* Added `FreeContour` BTLx processing and applied it to the `Plate` type so that plates can be machined.

### Changed

Expand Down
27 changes: 11 additions & 16 deletions src/compas_timber/design/wall_from_surface.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import math

from compas.geometry import Brep
from compas.geometry import Frame
from compas.geometry import Line
from compas.geometry import NurbsCurve
from compas.geometry import Plane
from compas.geometry import Point
from compas.geometry import Polyline
from compas.geometry import Vector
from compas.geometry import angle_vectors
from compas.geometry import angle_vectors_signed
from compas.geometry import bounding_box_xy
from compas.geometry import closest_point_on_plane
from compas.geometry import closest_point_on_segment
from compas.geometry import cross_vectors
from compas.geometry import distance_point_point_sqrd
Expand All @@ -26,10 +26,9 @@
from compas_timber.connections import LButtJoint
from compas_timber.connections import TButtJoint
from compas_timber.design import CategoryRule
from compas_timber.design import FeatureDefinition
from compas_timber.elements import Beam
from compas_timber.elements import Plate
from compas_timber.elements.features import BrepSubtraction
from compas_timber.fabrication import FreeContour
from compas_timber.model import TimberModel


Expand Down Expand Up @@ -489,7 +488,8 @@ def generate_plates(self):
pline.translate(self.frame.zaxis * (self.frame_depth + self.sheeting_outside))
self._elements.append(Plate(pline, self.sheeting_outside))
for window in self.windows:
self._features.append(FeatureDefinition(window.boolean_feature, [plate for plate in self.plate_elements]))
for plate in self.plate_elements:
window.apply_contour_to_plate(plate)

class Window(object):
"""
Expand Down Expand Up @@ -584,17 +584,12 @@ def frame(self):
self._frame, self._panel_length, self._panel_height = get_frame(self.points, self.parent.normal, self.zaxis)
return self._frame

@property
def boolean_feature(self):
offset = self.parent.sheeting_inside if self.parent.sheeting_inside else 0
so = self.parent.sheeting_outside if self.parent.sheeting_outside else 0
thickness = offset + so + self.parent.frame_depth

crv = self.outline.copy()
crv.translate(self.normal * -offset)

vol = Brep.from_extrusion(NurbsCurve.from_points(crv.points, degree=1), self.normal * thickness)
return BrepSubtraction(vol)
def apply_contour_to_plate(self, plate):
projected_points = []
for point in self.outline.points:
projected_points.append(closest_point_on_plane(point, Plane.from_frame(plate.frame)))
feature = FreeContour.from_polyline_and_element(Polyline(projected_points), plate)
plate.add_feature(feature)

def process_outlines(self):
for i, segment in enumerate(self.outline.lines):
Expand Down
2 changes: 1 addition & 1 deletion src/compas_timber/elements/beam.py
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ def compute_geometry(self, include_features=True):
if include_features:
for feature in self.features:
try:
blank_geo = feature.apply(blank_geo, beam=self)
blank_geo = feature.apply(blank_geo, self)
except FeatureApplicationError as error:
self.debug_info.append(error)
return blank_geo # type: ignore
Expand Down
27 changes: 1 addition & 26 deletions src/compas_timber/elements/fasteners/ball_node_fastener.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@
from compas.geometry import Sphere
from compas.geometry import Transformation
from compas.geometry import Vector
from compas.geometry import angle_vectors_signed

from compas_timber.elements import CutFeature
from compas_timber.elements import Fastener
from compas_timber.elements import FastenerTimberInterface
from compas_timber.utils import correct_polyline_direction


class BallNodeFastener(Fastener):
Expand Down Expand Up @@ -155,28 +155,3 @@ def interface_shape(self):
for geometry in geometries[1:]:
self._interface_shape += geometry
return self._interface_shape


def correct_polyline_direction(polyline, normal_vector):
"""Corrects the direction of a polyline to be counter-clockwise around a given vector.

Parameters
----------
polyline : :class:`compas.geometry.Polyline`
The polyline to correct.

Returns
-------
:class:`compas.geometry.Polyline`
The corrected polyline.

"""
angle_sum = 0
for i in range(len(polyline) - 1):
u = Vector.from_start_end(polyline[i - 1], polyline[i])
v = Vector.from_start_end(polyline[i], polyline[i + 1])
angle = angle_vectors_signed(u, v, normal_vector)
angle_sum += angle
if angle_sum > 0:
polyline = polyline[::-1]
return polyline
68 changes: 43 additions & 25 deletions src/compas_timber/elements/plate.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
from compas.geometry import Box
from compas.geometry import Brep
from compas.geometry import Frame
from compas.geometry import NurbsCurve
from compas.geometry import Polyline
from compas.geometry import Transformation
from compas.geometry import Vector
from compas.geometry import angle_vectors_signed
from compas.geometry import dot_vectors
from compas_model.elements import reset_computed

from compas_timber.errors import FeatureApplicationError
from compas_timber.fabrication import FreeContour

from .timber import TimberElement

Expand Down Expand Up @@ -62,6 +63,10 @@ def __init__(self, outline, thickness, vector=None, frame=None, **kwargs):
self.attributes = {}
self.attributes.update(kwargs)
self.debug_info = []
self._ref_frame = None
self._blank = None
contour_feature = FreeContour.from_polyline_and_element(self.outline.points, self, interior=False)
self.add_feature(contour_feature)

def __repr__(self):
# type: () -> str
Expand All @@ -85,16 +90,29 @@ def is_plate(self):

@property
def blank(self):
return self.obb
return self._blank

@property
def blank_length(self):
return self._blank.xsize

@property
def width(self):
return self._blank.zsize

@property
def height(self):
return self._blank.ysize

@property
def vector(self):
return self.frame.zaxis * self.thickness

@property
def shape(self):
brep = Brep.from_extrusion(NurbsCurve.from_points(self.outline.points, degree=1), self.vector)
return brep
def ref_frame(self):
if not self._ref_frame:
self.compute_obb()
return self._ref_frame

@property
def has_features(self):
Expand Down Expand Up @@ -124,9 +142,8 @@ def set_frame_and_outline(self, outline, vector=None):
if vector is not None and dot_vectors(frame.zaxis, vector) < 0:
# if the vector is pointing in the opposite direction from self.frame.normal
frame = Frame(frame.point, frame.yaxis, frame.xaxis)
self.outline.reverse()
self.outline = Polyline(self.outline[::-1])
# flips the frame if the frame.point is at an exterior corner

self.frame = frame

def compute_geometry(self, include_features=True):
Expand All @@ -144,13 +161,12 @@ def compute_geometry(self, include_features=True):
:class:`compas.datastructures.Mesh` | :class:`compas.geometry.Brep`

"""
plate_geo = self.shape
if include_features:
for feature in self.features:
try:
plate_geo = feature.apply(plate_geo)
except FeatureApplicationError as error:
self.debug_info.append(error)
plate_geo = Brep.from_box(self.blank)
for feature in self.features:
try:
plate_geo = feature.apply(plate_geo, self)
except FeatureApplicationError as error:
self.debug_info.append(error)
return plate_geo

def compute_aabb(self, inflate=0.0):
Expand All @@ -177,7 +193,7 @@ def compute_aabb(self, inflate=0.0):
box.zsize += inflate
return box

def compute_obb(self, inflate=0.0):
def compute_obb(self):
Copy link
Contributor

Choose a reason for hiding this comment

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

update docstring

# type: (float | None) -> compas.geometry.Box
"""Computes the Oriented Bounding Box (OBB) of the element.

Expand All @@ -192,18 +208,20 @@ def compute_obb(self, inflate=0.0):
The OBB of the element.

"""
vertices = [point for point in self.outline.points]
vertices = []
for point in self.outline.points:
vertices.append(point + self.vector)
for point in vertices:
point.transform(Transformation.from_change_of_basis(Frame.worldXY(), self.frame))
vertices.append(point.transformed(Transformation.from_frame_to_frame(self.frame, Frame.worldXY())))
obb = Box.from_points(vertices)
obb.xsize += inflate
obb.ysize += inflate
obb.zsize += inflate

obb.transform(Transformation.from_change_of_basis(self.frame, Frame.worldXY()))

obb.zsize = self.thickness
obb.translate([0, 0, self.thickness / 2])
self._blank = obb.copy()
self._blank.xsize += self.thickness
self._blank.ysize += self.thickness
self._ref_frame = Frame([self._blank.xmin, self._blank.ymin, self._blank.zmin], Vector.Xaxis(), Vector.Yaxis())
xform_back = Transformation.from_frame_to_frame(Frame.worldXY(), self.frame)
obb.transform(xform_back)
self._blank.transform(xform_back)
self._ref_frame.transform(xform_back)
return obb

def compute_collision_mesh(self):
Expand Down
2 changes: 2 additions & 0 deletions src/compas_timber/fabrication/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from .tenon import Tenon
from .mortise import Mortise
from .slot import Slot
from .free_contour import FreeContour
from .btlx import TenonShapeType
from .btlx import EdgePositionType
from .btlx import LimitationTopType
Expand All @@ -37,6 +38,7 @@
"Tenon",
"Mortise",
"Slot",
"FreeContour",
"TenonShapeType",
"EdgePositionType",
"LimitationTopType",
Expand Down
Loading