[AutoTool] rework two-L routing to avoid some bugs with incorrect transitions

This commit is contained in:
Jan Petykiewicz 2026-04-17 20:41:37 -07:00
commit 950d144ead
2 changed files with 119 additions and 48 deletions

View file

@ -791,55 +791,46 @@ class AutoTool(Tool, metaclass=ABCMeta):
Solve for a path consisting of two L-bends connected by a straight segment.
Used for both U-turns (ccw1 == ccw2) and S-bends (ccw1 != ccw2).
"""
is_u = bool(ccw1) == bool(ccw2)
out_rot = 0 if is_u else pi
for plan1 in self._iter_l_plans(ccw1, in_ptype, None):
for plan2 in self._iter_l_plans(ccw2, plan1.out_ptype, out_ptype):
# Solving for:
# X = L1_total +/- R2_actual = length
# Y = R1_actual + L2_straight + overhead_mid + overhead_b2 + L3_total = jog
rot_mid = rotation_matrix_2d(pi + plan1.bend_angle)
mid_axis = rot_mid @ numpy.array((1.0, 0.0))
if not numpy.isclose(mid_axis[0], 0) or numpy.isclose(mid_axis[1], 0):
continue
# Sign for overhead_y2 depends on whether it's a U-turn or S-bend
is_u = bool(ccw1) == bool(ccw2)
# U-turn: X = L1_total - R2 = length => L1_total = length + R2
# S-bend: X = L1_total + R2 = length => L1_total = length - R2
l1_total = length + (abs(plan2.overhead_y) if is_u else -abs(plan2.overhead_y))
l1_straight = l1_total - plan1.overhead_x
for straight_mid in self.straights:
mid_ptype_pair = (plan1.out_ptype, straight_mid.ptype)
mid_trans = self.transitions.get(mid_ptype_pair, None)
mid_trans_dxy = self._itransition2dxy(mid_trans)
for plan2 in self._iter_l_plans(ccw2, straight_mid.ptype, out_ptype):
fixed_dxy = numpy.array((plan1.overhead_x, plan1.overhead_y))
fixed_dxy += rot_mid @ (
mid_trans_dxy
+ numpy.array((plan2.overhead_x, plan2.overhead_y))
)
if plan1.straight.length_range[0] <= l1_straight < plan1.straight.length_range[1]:
for straight_mid in self.straights:
# overhead_mid accounts for the transition from bend1 to straight_mid
mid_ptype_pair = (plan1.out_ptype, straight_mid.ptype)
mid_trans = self.transitions.get(mid_ptype_pair, None)
mid_trans_dxy = self._itransition2dxy(mid_trans)
l1_straight = length - fixed_dxy[0]
l2_straight = (jog - fixed_dxy[1]) / mid_axis[1]
# b_trans2 accounts for the transition from straight_mid to bend2
b2_trans = None
if plan2.bend is not None and plan2.bend.in_port.ptype != straight_mid.ptype:
b2_trans = self.transitions.get((plan2.bend.in_port.ptype, straight_mid.ptype), None)
b2_trans_dxy = self._itransition2dxy(b2_trans)
if plan1.straight.length_range[0] <= l1_straight < plan1.straight.length_range[1] \
and straight_mid.length_range[0] <= l2_straight < straight_mid.length_range[1]:
l3_straight = 0
if plan2.straight.length_range[0] <= l3_straight < plan2.straight.length_range[1]:
ldata0 = self.LData(
l1_straight, plan1.straight, kwargs, ccw1, plan1.bend,
plan1.in_trans, plan1.b_trans, plan1.out_trans,
)
ldata1 = self.LData(
l3_straight, plan2.straight, kwargs, ccw2, plan2.bend,
plan2.in_trans, plan2.b_trans, plan2.out_trans,
)
l2_straight = abs(jog) - abs(plan1.overhead_y) - plan2.overhead_x - mid_trans_dxy[0] - b2_trans_dxy[0]
if straight_mid.length_range[0] <= l2_straight < straight_mid.length_range[1]:
# Found a solution!
# For plan2, we assume l3_straight = 0.
# We need to verify if l3=0 is valid for plan2.straight.
l3_straight = 0
if plan2.straight.length_range[0] <= l3_straight < plan2.straight.length_range[1]:
ldata0 = self.LData(
l1_straight, plan1.straight, kwargs, ccw1, plan1.bend,
plan1.in_trans, plan1.b_trans, plan1.out_trans,
)
ldata1 = self.LData(
l3_straight, plan2.straight, kwargs, ccw2, plan2.bend,
b2_trans, None, plan2.out_trans,
)
data = self.UData(ldata0, ldata1, straight_mid, l2_straight, mid_trans)
# out_port is at (length, jog) rot pi (for S-bend) or 0 (for U-turn) relative to input
out_rot = 0 if is_u else pi
out_port = Port((length, jog), rotation=out_rot, ptype=plan2.out_ptype)
return out_port, data
data = self.UData(ldata0, ldata1, straight_mid, l2_straight, mid_trans)
out_port = Port((length, jog), rotation=out_rot, ptype=plan2.out_ptype)
return out_port, data
raise BuildError(f"Failed to find a valid double-L configuration for {length=}, {jog=}")
straights: list[Straight]