Skip to content

Commit 41f874d

Browse files
authored
Merge pull request #1066 from nmaslarinos/circle_functions_bugfix
Circle functions bugfix
2 parents dad276e + 6eff1b3 commit 41f874d

File tree

6 files changed

+63
-31
lines changed

6 files changed

+63
-31
lines changed

AUTHORS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@
3434
- Nizar Taha <<[email protected]>> [@nizartaha](https://github.com/nizartaha)
3535
- Gene Ting-Chun Kao <<[email protected]>> [@GeneKao](https://github.com/GeneKao)
3636
- Chen Kasirer <<[email protected]>> [@chenkasirer](https://github.com/chenkasirer)
37+
- Nickolas Maslarinos <<[email protected]>> [@nmaslarinos](https://github.com/nmaslarinos)

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1919
* Added boolean operation operator overloads in `compas.geometry.Brep`
2020
* Added `format` task using `black` formatter.
2121

22+
* Added a `test_intersection_circle_circle_xy` in the `test_intersections`
23+
2224
### Changed
2325
* Based all gltf data classes on `BaseGLTFDataClass`
2426

@@ -27,6 +29,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2729
* Changed linter to `black`.
2830
* Automatically trigger `invoke format` during `invoke release`.
2931

32+
* Fixed bug in `intersections.intersection_circle_circle_xy` where the Circle's Plane was accessed instead of the centre.
33+
* Fixed bug in `_core.tangent` where the Circle's Plane was accessed instead of the centre.
34+
* Fixed the `test_tangent` to work with a properly defined circle
3035
### Removed
3136

3237

src/compas/geometry/_core/tangent.py

Lines changed: 22 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from __future__ import absolute_import
33
from __future__ import division
44

5-
import math
5+
from math import sqrt
66

77

88
__all__ = ["tangent_points_to_circle_xy"]
@@ -14,7 +14,7 @@ def tangent_points_to_circle_xy(circle, point):
1414
Parameters
1515
----------
1616
circle : [plane, float] | :class:`~compas.geometry.Circle`
17-
center, radius of the circle in the xy plane.
17+
Plane and radius of the circle.
1818
point : [float, float] or [float, float, float] | :class:`~compas.geometry.Point`
1919
XY(Z) coordinates of a point in the xy plane.
2020
@@ -26,25 +26,33 @@ def tangent_points_to_circle_xy(circle, point):
2626
Examples
2727
--------
2828
>>> from compas.geometry import allclose
29-
>>> circle = (0, 0, 0), 1.0
29+
>>> circle = ((0, 0, 0), (0, 0, 1)), 1.0
3030
>>> point = (2, 4, 0)
3131
>>> t1, t2 = tangent_points_to_circle_xy(circle, point)
3232
>>> allclose(t1, [-0.772, 0.636, 0.000], 1e-3)
3333
True
3434
>>> allclose(t2, [0.972, -0.236, 0.000], 1e-3)
3535
True
3636
"""
37-
m, r = circle[0], circle[1]
38-
cx, cy = m[0], m[1]
39-
px = point[0] - cx
40-
py = point[1] - cy
37+
plane, R = circle
38+
center, _ = plane
4139

42-
a1 = r * (px * r - py * math.sqrt(px**2 + py**2 - r**2)) / (px**2 + py**2)
43-
a2 = r * (px * r + py * math.sqrt(px**2 + py**2 - r**2)) / (px**2 + py**2)
40+
cx, cy = center[:2]
41+
px, py = point[:2]
4442

45-
b1 = (r**2 - px * a1) / py
46-
b2 = (r**2 - px * a2) / py
43+
dx = px - cx
44+
dy = py - cy
4745

48-
p1 = [a1 + cx, b1 + cy, 0]
49-
p2 = [a2 + cx, b2 + cy, 0]
50-
return p1, p2
46+
D = sqrt(dx**2 + dy**2)
47+
L2 = D**2 - R**2
48+
49+
a = dx / D, dy / D
50+
b = -a[1], a[0]
51+
52+
A = D - L2 / D
53+
B = sqrt(R**2 - A**2)
54+
55+
t1 = cx + A * a[0] + B * b[0], cy + A * a[1] + B * b[1], 0
56+
t2 = cx + A * a[0] - B * b[0], cy + A * a[1] - B * b[1], 0
57+
58+
return t1, t2

src/compas/geometry/intersections/intersections.py

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -893,9 +893,9 @@ def intersection_circle_circle_xy(circle1, circle2):
893893
Parameters
894894
----------
895895
circle1 : [plane, float] | :class:`~compas.geometry.Circle`
896-
Circle defined by a point, with at least XY coordinates, and a radius.
896+
Circle defined by a plane, with at least XY coordinates, and a radius.
897897
circle2 : [plane, float] | :class:`~compas.geometry.Circle`
898-
Circle defined by a point, with at least XY coordinates, and a radius.
898+
Circle defined by a plane, with at least XY coordinates, and a radius.
899899
900900
Returns
901901
-------
@@ -905,26 +905,35 @@ def intersection_circle_circle_xy(circle1, circle2):
905905
None otherwise.
906906
907907
"""
908-
p1, r1 = circle1[0], circle1[1]
909-
p2, r2 = circle2[0], circle2[1]
908+
plane1, r1 = circle1
909+
plane2, r2 = circle2
910+
p1, n1 = plane1
911+
p2, n2 = plane2
912+
R = length_vector_xy(subtract_vectors_xy(p2, p1))
910913

911-
d = length_vector_xy(subtract_vectors_xy(p2, p1))
912-
913-
if d > r1 + r2:
914+
if R > r1 + r2:
914915
return None
915916

916-
if d < fabs(r1 - r2):
917+
if R < fabs(r1 - r2):
917918
return None
918919

919-
if (d == 0) and (r1 == r2):
920+
if (R == 0) and (r1 == r2):
920921
return None
921922

922-
a = (r1 * r1 - r2 * r2 + d * d) / (2 * d)
923-
h = (r1 * r1 - a * a) ** 0.5
924-
cx2 = p1[0] + a * (p2[0] - p1[0]) / d
925-
cy2 = p1[1] + a * (p2[1] - p1[1]) / d
926-
i1 = ((cx2 + h * (p2[1] - p1[1]) / d), (cy2 - h * (p2[0] - p1[0]) / d), 0)
927-
i2 = ((cx2 - h * (p2[1] - p1[1]) / d), (cy2 + h * (p2[0] - p1[0]) / d), 0)
923+
x1, y1 = p1[:2]
924+
x2, y2 = p2[:2]
925+
926+
cx = 0.5 * (x1 + x2)
927+
cy = 0.5 * (y2 + y1)
928+
929+
R2 = R * R
930+
R4 = R2 * R2
931+
932+
a = (r1 * r1 - r2 * r2) / (2 * R2)
933+
b = 0.5 * sqrt(2 * (r1 * r1 + r2 * r2) / R2 - (r1 * r1 - r2 * r2) ** 2 / R4 - 1)
934+
935+
i1 = cx + a * (x2 - x1) + b * (y2 - y1), cy + a * (y2 - y1) + b * (x1 - x2), 0
936+
i2 = cx + a * (x2 - x1) - b * (y2 - y1), cy + a * (y2 - y1) - b * (x1 - x2), 0
928937

929938
return i1, i2
930939

tests/compas/geometry/test_intersections.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from compas.geometry import allclose
22
from compas.geometry import intersection_sphere_line
33
from compas.geometry import intersection_plane_circle
4+
from compas.geometry import intersection_circle_circle_xy
45

56

67
def test_intersection_sphere_line():
@@ -17,3 +18,11 @@ def test_intersection_plane_circle():
1718
ipt1, ipt2 = intersection_plane_circle(plane, circle)
1819
assert allclose(ipt1, (-6.165, 7.000, 0.000), tol=1e-3)
1920
assert allclose(ipt2, (12.165, 7.000, 0.000), tol=1e-3)
21+
22+
23+
def test_intersection_circle_circle_xy():
24+
circle1 = ((0.0, 0.0, 0.0), (0, 0, 1)), 10.0
25+
circle2 = ((3.0, 7.0, 0.0), (0, 0, 1)), 10.0
26+
ipt1, ipt2 = intersection_circle_circle_xy(circle1, circle2)
27+
assert allclose(ipt1, (9.999, -0.142, 0.000), tol=1e-3)
28+
assert allclose(ipt2, (-6.999, 7.142, 0.000), tol=1e-3)

tests/compas/geometry/test_tangent.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44

55
def test_tangent_points_to_circle_xy():
6-
circle = (0, 0, 0), 1.0
7-
point = (2, 4, 0)
6+
circle = ((0.0, 0.0, 0.0), (0.0, 0.0, 1.0)), 1.0
7+
point = (2.0, 4.0, 0.0)
88
t1, t2 = tangent_points_to_circle_xy(circle, point)
99
assert allclose(t1, (-0.772, 0.636, 0.000), tol=1e-3)
1010
assert allclose(t2, (0.972, -0.236, 0.000), tol=1e-3)

0 commit comments

Comments
 (0)