fix(extract): use EvaluateUnitVectors for parametric edge sampling
Available NXOpen.UF.Eval methods discovered: - EvaluateUnitVectors(evaluator, t) - parametric point+tangent - AskArc(evaluator) - arc center/radius for circular edges - Initialize2, AskLimits, Free - evaluator lifecycle Also logs arc data attributes for debugging.
This commit is contained in:
@@ -176,97 +176,63 @@ def _sample_edge_polyline(edge: Any, chord_tol_mm: float, lister: Any = None) ->
|
||||
|
||||
uf = NXOpen.UF.UFSession.GetUFSession()
|
||||
|
||||
# Discover the correct method name (varies by NX version)
|
||||
# UF_MODL_ask_curve_props → uf.Modl.AskCurveProps or similar
|
||||
modl = uf.Modl
|
||||
modl_methods = [m for m in dir(modl) if 'curve' in m.lower() or 'Curve' in m]
|
||||
_log(f"[edge] UF.Modl curve methods: {modl_methods}")
|
||||
|
||||
eval_obj = uf.Eval
|
||||
eval_methods = [m for m in dir(eval_obj) if not m.startswith('_')]
|
||||
_log(f"[edge] UF.Eval methods: {eval_methods}")
|
||||
|
||||
# Also check uf.Curve
|
||||
try:
|
||||
curve_obj = uf.Curve
|
||||
curve_methods = [m for m in dir(curve_obj) if 'eval' in m.lower() or 'Eval' in m or 'prop' in m.lower()]
|
||||
_log(f"[edge] UF.Curve eval methods: {curve_methods}")
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
pts: List[Point3D] = []
|
||||
parse_failures = 0
|
||||
|
||||
# Try each possible API in order
|
||||
eval_func = None
|
||||
eval_style = None
|
||||
try:
|
||||
evaluator = eval_obj.Initialize2(edge.Tag)
|
||||
limits = eval_obj.AskLimits(evaluator)
|
||||
t0, t1 = float(limits[0]), float(limits[1])
|
||||
|
||||
# Pattern A: uf.Modl.AskCurveProps(tag, param) — normalized 0..1
|
||||
for method_name in ('AskCurveProps', 'ask_curve_props'):
|
||||
fn = getattr(modl, method_name, None)
|
||||
if callable(fn):
|
||||
eval_func = fn
|
||||
eval_style = 'modl_props'
|
||||
_log(f"[edge] Using uf.Modl.{method_name}")
|
||||
break
|
||||
|
||||
# Pattern B: uf.Eval.EvaluateUnitVectors or similar
|
||||
if eval_func is None:
|
||||
for method_name in eval_methods:
|
||||
if 'valuat' in method_name.lower():
|
||||
eval_func = getattr(eval_obj, method_name)
|
||||
eval_style = 'eval_' + method_name
|
||||
_log(f"[edge] Using uf.Eval.{method_name}")
|
||||
break
|
||||
|
||||
# Pattern C: uf.Curve.EvaluateCurve(tag, param, deriv_flag)
|
||||
if eval_func is None:
|
||||
# Try arc-specific analytical approach first
|
||||
is_arc_edge = False
|
||||
try:
|
||||
curve_obj = uf.Curve
|
||||
for method_name in ('EvaluateCurve', 'evaluate_curve'):
|
||||
fn = getattr(curve_obj, method_name, None)
|
||||
if callable(fn):
|
||||
eval_func = fn
|
||||
eval_style = 'curve_eval'
|
||||
_log(f"[edge] Using uf.Curve.{method_name}")
|
||||
break
|
||||
is_arc_edge = eval_obj.IsArc(evaluator)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if eval_func is None:
|
||||
raise RuntimeError(f"No UF curve evaluation method found. Modl methods: {modl_methods}, Eval methods: {eval_methods}")
|
||||
|
||||
try:
|
||||
evaluator = None
|
||||
if 'eval_' in (eval_style or ''):
|
||||
evaluator = eval_obj.Initialize2(edge.Tag)
|
||||
limits = eval_obj.AskLimits(evaluator)
|
||||
t0, t1 = float(limits[0]), float(limits[1])
|
||||
if is_arc_edge:
|
||||
# Get arc data and generate points analytically
|
||||
try:
|
||||
arc_data = eval_obj.AskArc(evaluator)
|
||||
# arc_data is UFEval.Arc struct with: center, radius, etc.
|
||||
# Extract what we can
|
||||
_log(f"[edge] Arc data type: {type(arc_data).__name__}, attrs: {[a for a in dir(arc_data) if not a.startswith('_')]}")
|
||||
# Try to access fields
|
||||
center = None
|
||||
radius = None
|
||||
for attr in ('center', 'Center', 'arc_center'):
|
||||
if hasattr(arc_data, attr):
|
||||
center = getattr(arc_data, attr)
|
||||
break
|
||||
for attr in ('radius', 'Radius'):
|
||||
if hasattr(arc_data, attr):
|
||||
radius = float(getattr(arc_data, attr))
|
||||
break
|
||||
if center is not None and radius is not None:
|
||||
_log(f"[edge] Arc: center={center}, radius={radius}, t0={t0}, t1={t1}")
|
||||
except Exception as exc:
|
||||
_log(f"[edge] AskArc failed: {exc}")
|
||||
|
||||
# Use EvaluateUnitVectors for parametric sampling
|
||||
# Signature: EvaluateUnitVectors(evaluator, param) → returns point + tangent + ...
|
||||
for i in range(n_pts + 1):
|
||||
param = float(i) / float(n_pts)
|
||||
|
||||
if eval_style == 'modl_props':
|
||||
result = eval_func(edge.Tag, param)
|
||||
elif eval_style == 'curve_eval':
|
||||
# UF_CURVE_evaluate_curve(tag, natural_param, deriv_flag) → output array
|
||||
# For arcs, natural param is in radians; for lines, arc length
|
||||
# Use 0 = just point
|
||||
t = t0 + (t1 - t0) * param if evaluator else param
|
||||
result = eval_func(edge.Tag, t, 0)
|
||||
else:
|
||||
# eval_* method on evaluator
|
||||
t = t0 + (t1 - t0) * param
|
||||
result = eval_func(evaluator, 0, t)
|
||||
|
||||
# Parse result — try multiple formats
|
||||
pt = _parse_eval_point(result)
|
||||
if pt is not None:
|
||||
pts.append(pt)
|
||||
else:
|
||||
t = t0 + (t1 - t0) * (float(i) / float(n_pts))
|
||||
try:
|
||||
result = eval_obj.EvaluateUnitVectors(evaluator, t)
|
||||
# Parse result — could be tuple of (point, tangent, normal, binormal)
|
||||
pt = _parse_eval_point(result)
|
||||
if pt is not None:
|
||||
pts.append(pt)
|
||||
else:
|
||||
parse_failures += 1
|
||||
if parse_failures <= 2:
|
||||
_log(f"[edge] Parse failed at t={t:.4f}, type={type(result).__name__}, repr={repr(result)[:300]}")
|
||||
except Exception as exc:
|
||||
parse_failures += 1
|
||||
if parse_failures <= 2:
|
||||
_log(f"[edge] Parse failed at param={param:.3f}, raw type={type(result).__name__}, repr={repr(result)[:200]}")
|
||||
_log(f"[edge] EvaluateUnitVectors failed at t={t:.4f}: {exc}")
|
||||
finally:
|
||||
if evaluator is not None:
|
||||
try:
|
||||
@@ -275,12 +241,12 @@ def _sample_edge_polyline(edge: Any, chord_tol_mm: float, lister: Any = None) ->
|
||||
pass
|
||||
|
||||
if len(pts) >= 2:
|
||||
_log(f"[edge] sampled via {eval_style} ({len(pts)} pts, {parse_failures} failures)")
|
||||
_log(f"[edge] sampled via EvaluateUnitVectors ({len(pts)} pts, {parse_failures} failures)")
|
||||
return pts
|
||||
|
||||
_log(f"[edge] {eval_style} insufficient points ({len(pts)}), falling back")
|
||||
_log(f"[edge] EvaluateUnitVectors insufficient points ({len(pts)}), falling back")
|
||||
except Exception as exc:
|
||||
_log(f"[edge] UF curve eval failed: {exc}")
|
||||
_log(f"[edge] UF Eval failed: {exc}")
|
||||
|
||||
# 2) Fallback: IBaseCurve.Evaluate (signature differs by NX versions)
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user