fix: use mid-point to determine arc direction instead of clockwise flag

The clockwise flag from NX extractor can be inverted depending on face
normal orientation. The sampled mid-point is always reliable. Now
_arc_angles checks which direction (CW vs CCW) passes through the
mid-point and uses that.
This commit is contained in:
2026-02-17 18:34:36 +00:00
parent 9bc3b12745
commit 5cf994ec4b

View File

@@ -16,6 +16,39 @@ def _arc_angles(seg: Dict[str, Any]):
ex, ey = seg["end"]
a0 = math.atan2(sy - cy, sx - cx)
a1 = math.atan2(ey - cy, ex - cx)
# If a midpoint is available, use it to determine the correct arc direction
# (more reliable than the clockwise flag, which can be inverted by face normal orientation)
mid = seg.get("mid")
if mid is not None:
mx, my = float(mid[0]), float(mid[1])
a_mid = math.atan2(my - cy, mx - cx)
# Try CCW direction (a1 > a0)
a1_ccw = a1
if a1_ccw < a0:
a1_ccw += 2.0 * math.pi
# Check if mid angle falls within CCW sweep
a_mid_ccw = a_mid
if a_mid_ccw < a0:
a_mid_ccw += 2.0 * math.pi
ccw_ok = (a0 <= a_mid_ccw <= a1_ccw)
# Try CW direction (a1 < a0)
a1_cw = a1
if a1_cw > a0:
a1_cw -= 2.0 * math.pi
a_mid_cw = a_mid
if a_mid_cw > a0:
a_mid_cw -= 2.0 * math.pi
cw_ok = (a1_cw <= a_mid_cw <= a0)
if ccw_ok and not cw_ok:
return a0, a1_ccw
elif cw_ok and not ccw_ok:
return a0, a1_cw
# If both or neither match, fall through to clockwise flag
cw = bool(seg.get("clockwise", False))
if cw:
if a1 > a0: