mirror of
https://github.com/gumyr/build123d.git
synced 2025-12-06 02:30:55 -08:00
AATA: Add test matrix to spot check min/max limits, tangency for each condition
This commit is contained in:
parent
ab6eaff52b
commit
6dd89cf004
2 changed files with 88 additions and 12 deletions
|
|
@ -1377,7 +1377,7 @@ class ArcArcTangentArc(BaseEdgeObject):
|
|||
|
||||
keep specifies tangent arc position with a Keep pair: (placement, type)
|
||||
|
||||
- placement: start_arc is tangent INSIDE or OUTSIDE the tangent arc. BOTH is a
|
||||
- placement: start_arc is tangent INSIDE or OUTSIDE the tangent arc. BOTH is a
|
||||
special case for overlapping arcs with type INSIDE
|
||||
- type: tangent arc is INSIDE or OUTSIDE start_arc and end_arc
|
||||
|
||||
|
|
@ -1432,13 +1432,14 @@ class ArcArcTangentArc(BaseEdgeObject):
|
|||
else:
|
||||
workplane = copy_module.copy(WorkplaneList._get_context().workplanes[0])
|
||||
|
||||
side_sign = 1 if side == Side.LEFT else -1
|
||||
keep_sign = 1 if keep_placement == Keep.OUTSIDE else -1
|
||||
arcs = [start_arc, end_arc]
|
||||
points = [arc.arc_center for arc in arcs]
|
||||
radii = [arc.radius for arc in arcs]
|
||||
side_sign = 1 if side == Side.LEFT else -1
|
||||
keep_sign = 1 if keep_placement == Keep.OUTSIDE else -1
|
||||
r_sign = 1 if radii[0] < radii[1] else -1
|
||||
|
||||
# make a normal vector for sorting intersections
|
||||
# Make a normal vector for sorting intersections
|
||||
midline = points[1] - points[0]
|
||||
normal = side_sign * midline.cross(workplane.z_dir)
|
||||
|
||||
|
|
@ -1447,19 +1448,19 @@ class ArcArcTangentArc(BaseEdgeObject):
|
|||
|
||||
if midline.length == sum(radii) and keep_type == Keep.INSIDE:
|
||||
raise ValueError(
|
||||
"Cannot find tangent type Keep.INSIDE for non-overlapping arcs " \
|
||||
"Cannot find tangent type Keep.INSIDE for non-overlapping arcs "
|
||||
"already tangent."
|
||||
)
|
||||
|
||||
if midline.length == abs(radii[0] - radii[1]) and keep_placement == Keep.INSIDE:
|
||||
raise ValueError(
|
||||
"Cannot find tangent placement Keep.INSIDE for completely " \
|
||||
"Cannot find tangent placement Keep.INSIDE for completely "
|
||||
"overlapping arcs already tangent."
|
||||
)
|
||||
|
||||
min_radius = 0.
|
||||
# Set following parameters based on overlap condition and keep configuration
|
||||
min_radius = 0.0
|
||||
max_radius = None
|
||||
r_sign = 1 if radii[0] < radii[1] else -1
|
||||
x_sign = [1, 1]
|
||||
pick_index = 0
|
||||
if midline.length > abs(radii[0] - radii[1]) and keep_type == Keep.OUTSIDE:
|
||||
|
|
@ -1558,6 +1559,7 @@ class ArcArcTangentArc(BaseEdgeObject):
|
|||
)
|
||||
arc_center = ref_intersections.sort_by(Axis(points[0], normal))[pick_index]
|
||||
|
||||
# x_sign determines if tangent is near side or far side of circle
|
||||
intersect = [
|
||||
points[i]
|
||||
+ x_sign[i] * radii[i] * (Vector(arc_center) - points[i]).normalized()
|
||||
|
|
|
|||
|
|
@ -652,6 +652,7 @@ class BuildLineTests(unittest.TestCase):
|
|||
- Arcs must be coplanar
|
||||
- Cannot make tangent for concentric arcs
|
||||
"""
|
||||
|
||||
# Test line properties in algebra mode
|
||||
start_r = 2
|
||||
end_r = 5
|
||||
|
|
@ -765,10 +766,83 @@ class BuildLineTests(unittest.TestCase):
|
|||
start_arc, CenterArc((0, end_r - start_r), end_r, 0, 360), 3
|
||||
)
|
||||
|
||||
# Radius size
|
||||
with self.assertRaises(ValueError):
|
||||
r = (separation - (start_r + end_r)) / 2 - 1
|
||||
ArcArcTangentArc(CenterArc((0, 0, 1), 5, 0, 360), end_arc, r)
|
||||
## Spot check all conditions
|
||||
r1, r2 = 3, 8
|
||||
start_center = (0, 0)
|
||||
start_arc = CenterArc(start_center, r1, 0, 360)
|
||||
|
||||
end_y = {
|
||||
"no_overlap": (r1 + r2) * 1.1,
|
||||
"partial_overlap": (r1 + r2) / 2,
|
||||
"full_overlap": (r2 - r1) * 0.9,
|
||||
}
|
||||
|
||||
# Test matrix:
|
||||
# (separation, keep pair, [min_limit, max_limit])
|
||||
# actual limit will be (separation + min_limit) / 2
|
||||
cases = [
|
||||
(end_y["no_overlap"], (Keep.INSIDE, Keep.INSIDE), [r1 - r2, None]),
|
||||
(end_y["no_overlap"], (Keep.OUTSIDE, Keep.INSIDE), [-r1 + r2, None]),
|
||||
(end_y["no_overlap"], (Keep.INSIDE, Keep.OUTSIDE), [r1 + r2, None]),
|
||||
(end_y["no_overlap"], (Keep.OUTSIDE, Keep.OUTSIDE), [-r1 - r2, None]),
|
||||
(end_y["partial_overlap"], (Keep.INSIDE, Keep.INSIDE), [None, r1 - r2]),
|
||||
(end_y["partial_overlap"], (Keep.OUTSIDE, Keep.INSIDE), [None, -r1 + r2]),
|
||||
(end_y["partial_overlap"], (Keep.BOTH, Keep.INSIDE), [None, r1 + r2]),
|
||||
(end_y["partial_overlap"], (Keep.INSIDE, Keep.OUTSIDE), [r1 + r2, None]),
|
||||
(end_y["partial_overlap"], (Keep.OUTSIDE, Keep.OUTSIDE), [None, None]),
|
||||
(end_y["full_overlap"], (Keep.INSIDE, Keep.INSIDE), [r1 + r2, r1 + r2]),
|
||||
(end_y["full_overlap"], (Keep.OUTSIDE, Keep.INSIDE), [-r1 + r2, -r1 + r2]),
|
||||
]
|
||||
|
||||
# Check min and max radii, tangency
|
||||
for case in cases:
|
||||
end_center = (0, case[0])
|
||||
end_arc = CenterArc(end_center, r2, 0, 360)
|
||||
|
||||
flip_max = -1 if case[1] == (Keep.BOTH, Keep.INSIDE) else 1
|
||||
flip_min = -1 if case[0] == end_y["full_overlap"] else 1
|
||||
|
||||
min_r = 0 if case[2][0] is None else (flip_min * case[0] + case[2][0]) / 2
|
||||
max_r = 1e6 if case[2][1] is None else (flip_max * case[0] + case[2][1]) / 2
|
||||
|
||||
print(case[1], min_r, max_r, case[0])
|
||||
print(min_r + 0.01, min_r * 0.99, max_r - 0.01, max_r + 0.01)
|
||||
print((case[0] - 1 * (r1 + r2)) / 2)
|
||||
|
||||
# Greater than min
|
||||
l1 = ArcArcTangentArc(start_arc, end_arc, min_r + 0.01, keep=case[1])
|
||||
_, p1, p2 = start_arc.distance_to_with_closest_points(l1)
|
||||
self.assertTupleAlmostEquals(tuple(p1), tuple(p2), 5)
|
||||
self.assertAlmostEqual(
|
||||
start_arc.tangent_at(p1).cross(l1.tangent_at(p2)).length, 0, 5
|
||||
)
|
||||
_, p1, p2 = end_arc.distance_to_with_closest_points(l1)
|
||||
self.assertTupleAlmostEquals(tuple(p1), tuple(p2), 5)
|
||||
self.assertAlmostEqual(
|
||||
end_arc.tangent_at(p1).cross(l1.tangent_at(p2)).length, 0, 5
|
||||
)
|
||||
|
||||
# Less than max
|
||||
l1 = ArcArcTangentArc(start_arc, end_arc, max_r - 0.01, keep=case[1])
|
||||
_, p1, p2 = start_arc.distance_to_with_closest_points(l1)
|
||||
self.assertTupleAlmostEquals(tuple(p1), tuple(p2), 5)
|
||||
self.assertAlmostEqual(
|
||||
start_arc.tangent_at(p1).cross(l1.tangent_at(p2)).length, 0, 5
|
||||
)
|
||||
_, p1, p2 = end_arc.distance_to_with_closest_points(l1)
|
||||
self.assertTupleAlmostEquals(tuple(p1), tuple(p2), 5)
|
||||
self.assertAlmostEqual(
|
||||
end_arc.tangent_at(p1).cross(l1.tangent_at(p2)).length, 0, 5
|
||||
)
|
||||
|
||||
# Less than min
|
||||
with self.assertRaises(ValueError):
|
||||
ArcArcTangentArc(start_arc, end_arc, min_r * 0.99, keep=case[1])
|
||||
|
||||
# Greater than max
|
||||
if max_r != 1e6:
|
||||
with self.assertRaises(ValueError):
|
||||
ArcArcTangentArc(start_arc, end_arc, max_r + 0.01, keep=case[1])
|
||||
|
||||
def test_line_with_list(self):
|
||||
"""Test line with a list of points"""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue