Skip to content

Commit 26265a9

Browse files
authored
Merge pull request #1180 from nmaslarinos/polyline_new_methods
Polyline new methods
2 parents 8041075 + cebc537 commit 26265a9

File tree

3 files changed

+91
-2
lines changed

3 files changed

+91
-2
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
118118
* Added `compas.geometry.Surface.point_at`.
119119
* Added `compas.geometry.Surface.normal_at`.
120120
* Added `compas.geometry.Surface.frame_at`.
121+
* Added `compas.geometry.Polyline.parameter_at`.
122+
* Added `compas.geometry.Polyline.divide_at_corners`.
121123
* Added `mesh_to_rhino` to `compas_rhino.conversions`.
122124
* Added `vertices_and_faces_to_rhino` to `compas_rhino.conversions`.
123125
* Added `polyhedron_to_rhino` to `compas_rhino.conversions`.
@@ -225,6 +227,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
225227
* Changed `compas.datastructures.Graph.delete_edge` to delete invalid (u, u) edges and not delete edges in opposite directions (v, u)
226228
* Fixed bug in `compas.datastructures.Mesh.insert_vertex`.
227229
* Fixed bug in `compas.geometry.angle_vectors_signed`.
230+
* Fixed bug in `compas.geometry.Polyline.split_at_corners` where angles were sometimes wrongly calculated.
228231
* Changed `compas.artists.MeshArtist` default colors.
229232
* Changed internal _plane storage of the `compas.datastructures.Halfface` from `_plane[u][v][w]` to `_plane[u][v][fkey]`
230233
* Fixed `SyntaxError` when importing COMPAS in GHPython.

src/compas/geometry/curves/polyline.py

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from compas.geometry import allclose
88
from compas.geometry import transform_points
9-
from compas.geometry import is_point_on_line
9+
from compas.geometry import is_point_on_line, is_point_on_polyline
1010
from compas.geometry import Point
1111
from compas.geometry import Line
1212
from compas.geometry import Frame
@@ -277,6 +277,40 @@ def point_at(self, t, snap=False):
277277
x += dx
278278
i += 1
279279

280+
def parameter_at(self, point, tol=1e-6):
281+
"""Parameter of the polyline at a specific point.
282+
283+
Parameters
284+
----------
285+
point : [float, float, float] | :class:`~compas.geometry.Point`
286+
The point on the polyline.
287+
tol : float, optional
288+
A tolerance for membership verification.
289+
290+
Returns
291+
-------
292+
float
293+
The parameter of the polyline.
294+
295+
Examples
296+
--------
297+
>>> from compas.geometry import Point
298+
>>> polyline = Polyline([[0.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 1.0, 0.0]])
299+
>>> polyline.parameter_at(Point(0.1, 0.0, 0.0))
300+
0.5
301+
302+
"""
303+
if not is_point_on_polyline(point, self, tol):
304+
raise Exception("{} not found!".format(point))
305+
dx = 0
306+
for line in self.lines:
307+
if not is_point_on_line(point, line, tol):
308+
dx += line.length
309+
continue
310+
dx += line.start.distance_to_point(point)
311+
break
312+
return dx / self.length
313+
280314
def tangent_at(self, t):
281315
"""Tangent vector at a specific normalized parameter.
282316
@@ -358,7 +392,7 @@ def split_at_corners(self, angle_threshold):
358392
seg_ids.append(0)
359393

360394
for seg1, seg2 in pairwise(seg_ids):
361-
angle = self.lines[seg1].vector.angle(self.lines[seg2].vector)
395+
angle = self.lines[seg2].vector.angle(-self.lines[seg1].vector)
362396
if angle >= angle_threshold:
363397
corner_ids.append(seg1 + 1)
364398

@@ -380,6 +414,30 @@ def split_at_corners(self, angle_threshold):
380414

381415
return split_polylines
382416

417+
def divide_at_corners(self, angle_threshold):
418+
"""Divides a polyline at corners larger than the given angle_threshold
419+
420+
Parameters
421+
----------
422+
angle_threshold : float
423+
In radians.
424+
425+
Returns
426+
-------
427+
list[:class:`~compas.geometry.Point`]
428+
429+
"""
430+
corner_ids = []
431+
seg_ids = list(range(len(self.lines)))
432+
if self.is_closed:
433+
seg_ids.insert(0, seg_ids[-1])
434+
435+
for seg1, seg2 in pairwise(seg_ids):
436+
angle = self.lines[seg2].vector.angle(-self.lines[seg1].vector)
437+
if angle >= angle_threshold:
438+
corner_ids.append(seg1 + 1)
439+
return [self.points[i] for i in corner_ids]
440+
383441
def divide(self, num_segments):
384442
"""Divide a polyline in equal segments.
385443

tests/compas/geometry/test_curves_polyline.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,24 @@ def test_polyline_split_at_corners(coords, input, expected):
257257
assert expected == Polyline(coords).split_at_corners(input)
258258

259259

260+
@pytest.mark.parametrize(
261+
"input,expected",
262+
[
263+
(
264+
math.radians(160),
265+
[],
266+
),
267+
(math.radians(100), [(1, 0, 0)]),
268+
(math.radians(90), [(0, 0, 0), (1, 0, 0)]),
269+
(math.radians(75), [(0, 0, 0), (1, 0, 0), (0, 1, 0)]),
270+
(math.radians(44), [(0, 0, 0), (1, 0, 0), (1.86602540378444, 0.5, 0), (0, 1, 0)]),
271+
],
272+
)
273+
def test_polyline_divide_at_corners(input, expected):
274+
polyline = Polyline(([0, 0, 0], [1, 0, 0], [1.86602540378444, 0.5, 0], [0, 1, 0], [0, 0, 0]))
275+
assert expected == polyline.divide_at_corners(input)
276+
277+
260278
@pytest.mark.parametrize(
261279
"coords,segments_number,expected",
262280
[
@@ -431,6 +449,16 @@ def test_polyline_tangent_at_point(coords, input, expected):
431449
assert expected == Polyline(coords).tangent_at_point(input)
432450

433451

452+
@pytest.mark.parametrize("input,expected", [((0, 0, 0), 0.0), ((1, 0, 0), 0.5), ((1, 1, 0), 1.0), ((2, 0, 0), None)])
453+
def test_polyline_parameter_at(input, expected):
454+
polyline = Polyline(((0, 0, 0), (1, 0, 0), (1, 1, 0)))
455+
if expected is not None:
456+
assert expected == polyline.parameter_at(input)
457+
else:
458+
with pytest.raises(Exception):
459+
polyline.parameter_at(input)
460+
461+
434462
@pytest.mark.parametrize(
435463
"coords,input,expected",
436464
[

0 commit comments

Comments
 (0)