fix: arc midpoint parsing + edge type detection for NX integer enums

- EvaluateUnitVectors returns nested lists — added recursive parser
- SolidEdgeType returns int 1 (not 'Linear') — handle both formats
This commit is contained in:
2026-02-17 02:32:52 +00:00
parent b6dc15e19e
commit dc34b7f6d5

View File

@@ -116,6 +116,42 @@ class EdgeSegment:
# NX edge analysis — extract type + arc parameters
# ---------------------------------------------------------------------------
def _parse_eval_result(result: Any) -> Point3D | None:
"""Parse NX UF EvaluateUnitVectors return into a 3D point.
Handles multiple NX Python return formats:
- NXOpen.Point3d with .X/.Y/.Z attrs
- Tuple/list of (point_obj, tangent_obj, ...)
- Nested numeric tuples ((x,y,z), (tx,ty,tz), ...)
- Flat numeric list [x,y,z,tx,ty,tz,...]
"""
# Direct Point3d-like object
if hasattr(result, 'X') and hasattr(result, 'Y') and hasattr(result, 'Z'):
return (float(result.X), float(result.Y), float(result.Z))
if isinstance(result, (list, tuple)):
# Check if first 3 elements are all numeric (flat array)
if len(result) >= 3 and all(isinstance(v, (int, float)) for v in result[:3]):
return (float(result[0]), float(result[1]), float(result[2]))
# Check first element — could be a point object or sub-list
if len(result) >= 1:
first = result[0]
# Point3d-like object
if hasattr(first, 'X') and hasattr(first, 'Y') and hasattr(first, 'Z'):
return (float(first.X), float(first.Y), float(first.Z))
# Sub-list/tuple of 3 numbers
if isinstance(first, (list, tuple)) and len(first) >= 3:
if all(isinstance(v, (int, float)) for v in first[:3]):
return (float(first[0]), float(first[1]), float(first[2]))
# Recurse into first element
parsed = _parse_eval_result(first)
if parsed is not None:
return parsed
return None
def _analyze_edge(edge: Any, lister: Any = None) -> EdgeSegment:
"""
Analyze an NX edge and return a typed EdgeSegment.
@@ -137,13 +173,18 @@ def _analyze_edge(edge: Any, lister: Any = None) -> EdgeSegment:
# Classify edge type
edge_type_str = "?"
edge_type_val = None
try:
edge_type_str = str(edge.SolidEdgeType)
edge_type_val = edge.SolidEdgeType
edge_type_str = str(edge_type_val)
except Exception:
pass
is_linear = "Linear" in edge_type_str
is_circular = "Circular" in edge_type_str
# NX returns either enum name ("Linear") or integer (1=linear, 2=circular, etc.)
is_linear = ("Linear" in edge_type_str or edge_type_val == 1
or edge_type_str == "1")
is_circular = ("Circular" in edge_type_str or edge_type_val == 2
or edge_type_str == "2")
# Linear edges — simple
if is_linear:
@@ -198,15 +239,12 @@ def _analyze_edge(edge: Any, lister: Any = None) -> EdgeSegment:
limits = eval_obj.AskLimits(evaluator)
t_mid = (float(limits[0]) + float(limits[1])) / 2.0
result = eval_obj.EvaluateUnitVectors(evaluator, t_mid)
# Parse point from result
if hasattr(result, '__len__') and len(result) >= 1:
item = result[0] if hasattr(result[0], 'X') else result
if hasattr(item, 'X'):
mid_pt = (float(item.X), float(item.Y), float(item.Z))
elif isinstance(item, (list, tuple)) and len(item) >= 3:
mid_pt = (float(item[0]), float(item[1]), float(item[2]))
if mid_pt is None and hasattr(result, 'X'):
mid_pt = (float(result.X), float(result.Y), float(result.Z))
# Parse point from result — multiple possible formats:
# 1) NXOpen.Point3d with .X/.Y/.Z
# 2) Tuple of (point, tangent, ...) where point has .X/.Y/.Z
# 3) Nested lists/tuples like ((x,y,z), (tx,ty,tz), ...)
# 4) Flat list [x,y,z,tx,ty,tz,...]
mid_pt = _parse_eval_result(result)
except Exception as exc2:
_log(f"[edge] Arc midpoint sampling failed: {exc2}")