Skip to content

Commit

Permalink
Merge branch 'main' into fastener_element
Browse files Browse the repository at this point in the history
  • Loading branch information
obucklin committed Oct 28, 2024
2 parents ab7bca3 + 718c69b commit 025d8ce
Show file tree
Hide file tree
Showing 10 changed files with 195 additions and 149 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Changed

* Changed incorrect import of `compas.geometry.intersection_line_plane()` to `compas_timber.utils.intersection_line_plane()`
* Renamed `intersection_line_plane` to `intersection_line_plane_param`.
* Renamed `intersection_line_line_3D` to `intersection_line_line_param`.

### Removed

* Removed module `compas_timber.utils.compas_extra`.

## [0.11.0] 2024-09-17

Expand Down
4 changes: 2 additions & 2 deletions src/compas_timber/connections/l_miter.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from compas.geometry import cross_vectors

from compas_timber._fabrication import JackRafterCut
from compas_timber.utils import intersection_line_line_3D
from compas_timber.utils import intersection_line_line_param

from .joint import BeamJoinningError
from .joint import Joint
Expand Down Expand Up @@ -64,7 +64,7 @@ def get_cutting_planes(self):
vA = Vector(*self.beam_a.frame.xaxis) # frame.axis gives a reference, not a copy
vB = Vector(*self.beam_b.frame.xaxis)
# intersection point (average) of both centrelines
[pxA, tA], [pxB, tB] = intersection_line_line_3D(
[pxA, tA], [pxB, tB] = intersection_line_line_param(
self.beam_a.centerline,
self.beam_b.centerline,
max_distance=float("inf"),
Expand Down
4 changes: 2 additions & 2 deletions src/compas_timber/design/workflow.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from compas_timber.connections import LMiterJoint
from compas_timber.connections import TButtJoint
from compas_timber.utils.compas_extra import intersection_line_line_3D
from compas_timber.utils import intersection_line_line_param


class CollectionDef(object):
Expand Down Expand Up @@ -204,7 +204,7 @@ def __str__(self):
def guess_joint_topology_2beams(beamA, beamB, tol=1e-6, max_distance=1e-6):
# TODO: replace default max_distance ~ zero with global project precision

[pa, ta], [pb, tb] = intersection_line_line_3D(beamA.centerline, beamB.centerline, max_distance, True, tol)
[pa, ta], [pb, tb] = intersection_line_line_param(beamA.centerline, beamB.centerline, max_distance, True, tol)

if ta is None or tb is None:
# lines do not intersect within max distance or they are parallel
Expand Down
6 changes: 3 additions & 3 deletions src/compas_timber/elements/beam.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from compas.tolerance import TOL
from compas_model.elements import reset_computed

from compas_timber.utils import intersection_line_plane
from compas_timber.utils import intersection_line_plane_param

from .features import FeatureApplicationError
from .timber import TimberElement
Expand Down Expand Up @@ -577,10 +577,10 @@ def extension_to_plane(self, pln):
x = {}
pln = Plane.from_frame(pln) # type: ignore
for e in self.long_edges:
p, t = intersection_line_plane(e, pln)
p, t = intersection_line_plane_param(e, pln)
x[t] = p

px = intersection_line_plane(self.centerline, pln)[0]
px = intersection_line_plane_param(self.centerline, pln)[0]
if px is None:
raise ValueError("The plane does not intersect with the centerline of the beam.")
side, _ = self.endpoint_closest_to_point(px)
Expand Down
6 changes: 4 additions & 2 deletions src/compas_timber/fabrication/btlx_processes/btlx_jack_cut.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from compas_timber.fabrication import BTLx
from compas_timber.fabrication import BTLxProcess
from compas_timber.utils.compas_extra import intersection_line_plane
from compas_timber.utils import intersection_line_plane_param


class BTLxJackCut(object):
Expand Down Expand Up @@ -77,7 +77,9 @@ def generate_process(self):

self.x_edge = Line.from_point_and_vector(self.reference_side.point, self.reference_side.xaxis)

self.startX = intersection_line_plane(self.x_edge, Plane.from_frame(self.cut_plane))[1] * self.x_edge.length
self.startX = (
intersection_line_plane_param(self.x_edge, Plane.from_frame(self.cut_plane))[1] * self.x_edge.length
)
if self.startX < self.part.blank_length / 2:
self.orientation = "start"
else:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from compas_rhino.conversions import point_to_rhino
from ghpythonlib.componentbase import executingcomponent as component

from compas_timber.utils.compas_extra import intersection_line_line_3D
from compas_timber.utils import intersection_line_line_param


class ShowJointTypes(component):
Expand All @@ -16,7 +16,7 @@ def RunScript(self, model):

for joint in model.joints:
line_a, line_b = joint.beams[0].centerline, joint.beams[1].centerline
[p1, t1], [p2, t2] = intersection_line_line_3D(line_a, line_b, float("inf"), False, 1e-3)
[p1, t1], [p2, t2] = intersection_line_line_param(line_a, line_b, float("inf"), False, 1e-3)
p1 = point_to_rhino(p1)
p2 = point_to_rhino(p2)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from ghpythonlib.componentbase import executingcomponent as component

from compas_timber.connections import JointTopology
from compas_timber.utils.compas_extra import intersection_line_line_3D
from compas_timber.utils import intersection_line_line_param


class ShowTopologyTypes(component):
Expand All @@ -19,7 +19,7 @@ def RunScript(self, model):
beam_b = topo["beam_b"]
topology = topo.get("detected_topo")

[p1, _], [p2, _] = intersection_line_line_3D(
[p1, _], [p2, _] = intersection_line_line_param(
beam_a.centerline, beam_b.centerline, float("inf"), False, 1e-3
)
p1 = point_to_rhino(p1)
Expand Down
138 changes: 135 additions & 3 deletions src/compas_timber/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,136 @@
from .compas_extra import intersection_line_line_3D
from .compas_extra import intersection_line_plane
from math import fabs

__all__ = ["intersection_line_line_3D", "intersection_line_plane", "close", "are_objects_identical"]
from compas.geometry import Plane
from compas.geometry import Point
from compas.geometry import add_vectors
from compas.geometry import cross_vectors
from compas.geometry import distance_point_point
from compas.geometry import dot_vectors
from compas.geometry import length_vector
from compas.geometry import normalize_vector
from compas.geometry import scale_vector
from compas.geometry import subtract_vectors


def intersection_line_line_param(line1, line2, max_distance=1e-6, limit_to_segments=True, tol=1e-6):
"""Find, if exists, the intersection point of `line1` and `line2` and returns parametric information about it.
For each of the lines, the point of intersection and a `t` parameter are returned.
The `t` parameter is the normalized parametric value (0.0 -> 1.0) of the location of the intersection point
in relation to the line's starting point.
0.0 indicates intersaction near the starting point, 1.0 indicates intersection near the end.
If no intersection is detected within the max_distance, or the intersection falls outside either of the line segments,
[None, None], [None, None] is returned.
Parameters
----------
line1 : :class:`~compas.geometry.Line`
First line.
line2 : :class:`~compas.geometry.Line`
Second line.
max_distance : float
Maximum distance between the lines to still consider as intersection.
limit_to_segments : bool, defualt is True
If True, the lines are considered intersection only if the intersection point falls whithin the given line segments for both lines.
tol : float, default is 1e-6
The tolerance used for floating point operations.
Returns
-------
tuple(:class:`~compas.geometry.Point`, float), tuple(:class:`~compas.geometry.Point`, float)
"""
a, b = line1
c, d = line2

ab = subtract_vectors(b, a)
cd = subtract_vectors(d, c)

n = cross_vectors(ab, cd)

# check if lines are parallel
if length_vector(n) < tol: # if any([abs(x)<tol for x in n]):
return [None, None], [None, None]

n1 = normalize_vector(cross_vectors(ab, n))
n2 = normalize_vector(cross_vectors(cd, n))

pln1 = Plane(a, n1)
pln2 = Plane(c, n2)

# get intersection points (should never be None, only if parallel, which was errorcatched before)
x1, t1 = intersection_line_plane_param(line1, pln2, tol)
x2, t2 = intersection_line_plane_param(line2, pln1, tol)

# double-check for parallels, should not happen:
if t1 is None or t2 is None:
print("intersection_line_plane detected parallel lines")
return [None, None], [None, None]

# is intersection exact / within some max_distance?
d = distance_point_point(x1, x2)
if d > max_distance:
return [None, None], [None, None]

# is intersection within the line segment? if not, override results with None
if limit_to_segments:
if t1 < 0.0 - tol or t1 > 1.0 + tol:
x1 = None
t1 = None
if t2 < 0.0 - tol or t2 > 1.0 + tol:
x2 = None
t2 = None
return [x1, t1], [x2, t2]


def intersection_line_plane_param(line, plane, tol=1e-6):
"""Computes the intersection point of a line and a plane.
A tuple containing the intersection point and a `t` value are returned.
The `t` parameter is the normalized parametric value (0.0 -> 1.0) of the location of the intersection point
in relation to the line's starting point.
0.0 indicates intersaction near the starting point, 1.0 indicates intersection near the end.
If no intersection is found, [None, None] is returned.
Parameters
----------
line : :class:`~compas.geometry.Line`
Two points defining the line.
plane : :class:`~compas.geometry.Plane`
The base point and normal defining the plane.
tol : float, optional. Default is 1e-6.
A tolerance for membership verification.
Returns
-------
tuple(:class:`~compas.geometry.Point`, float)
"""
a, b = line
o, n = plane

ab = subtract_vectors(b, a)
dotv = dot_vectors(n, ab)

if fabs(dotv) <= tol:
# if the dot product (cosine of the angle between segment and plane)
# is close to zero the line and the normal are almost perpendicular
# hence there is no intersection
return None, None

# based on the ratio = -dot_vectors(n, ab) / dot_vectors(n, oa)
# there are three scenarios
# 1) 0.0 < ratio < 1.0: the intersection is between a and b
# 2) ratio < 0.0: the intersection is on the other side of a
# 3) ratio > 1.0: the intersection is on the other side of b
oa = subtract_vectors(a, o)
t = -dot_vectors(n, oa) / dotv
ab = scale_vector(ab, t)
return Point(*add_vectors(a, ab)), t


__all__ = ["intersection_line_line_param", "intersection_line_plane_param"]
133 changes: 0 additions & 133 deletions src/compas_timber/utils/compas_extra.py

This file was deleted.

Loading

0 comments on commit 025d8ce

Please sign in to comment.