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()
|
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_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] = []
|
pts: List[Point3D] = []
|
||||||
parse_failures = 0
|
parse_failures = 0
|
||||||
|
|
||||||
# Try each possible API in order
|
try:
|
||||||
eval_func = None
|
evaluator = eval_obj.Initialize2(edge.Tag)
|
||||||
eval_style = None
|
limits = eval_obj.AskLimits(evaluator)
|
||||||
|
t0, t1 = float(limits[0]), float(limits[1])
|
||||||
|
|
||||||
# Pattern A: uf.Modl.AskCurveProps(tag, param) — normalized 0..1
|
# Try arc-specific analytical approach first
|
||||||
for method_name in ('AskCurveProps', 'ask_curve_props'):
|
is_arc_edge = False
|
||||||
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:
|
try:
|
||||||
curve_obj = uf.Curve
|
is_arc_edge = eval_obj.IsArc(evaluator)
|
||||||
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
|
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
if eval_func is None:
|
if is_arc_edge:
|
||||||
raise RuntimeError(f"No UF curve evaluation method found. Modl methods: {modl_methods}, Eval methods: {eval_methods}")
|
# Get arc data and generate points analytically
|
||||||
|
try:
|
||||||
try:
|
arc_data = eval_obj.AskArc(evaluator)
|
||||||
evaluator = None
|
# arc_data is UFEval.Arc struct with: center, radius, etc.
|
||||||
if 'eval_' in (eval_style or ''):
|
# Extract what we can
|
||||||
evaluator = eval_obj.Initialize2(edge.Tag)
|
_log(f"[edge] Arc data type: {type(arc_data).__name__}, attrs: {[a for a in dir(arc_data) if not a.startswith('_')]}")
|
||||||
limits = eval_obj.AskLimits(evaluator)
|
# Try to access fields
|
||||||
t0, t1 = float(limits[0]), float(limits[1])
|
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):
|
for i in range(n_pts + 1):
|
||||||
param = float(i) / float(n_pts)
|
t = t0 + (t1 - t0) * (float(i) / float(n_pts))
|
||||||
|
try:
|
||||||
if eval_style == 'modl_props':
|
result = eval_obj.EvaluateUnitVectors(evaluator, t)
|
||||||
result = eval_func(edge.Tag, param)
|
# Parse result — could be tuple of (point, tangent, normal, binormal)
|
||||||
elif eval_style == 'curve_eval':
|
pt = _parse_eval_point(result)
|
||||||
# UF_CURVE_evaluate_curve(tag, natural_param, deriv_flag) → output array
|
if pt is not None:
|
||||||
# For arcs, natural param is in radians; for lines, arc length
|
pts.append(pt)
|
||||||
# Use 0 = just point
|
else:
|
||||||
t = t0 + (t1 - t0) * param if evaluator else param
|
parse_failures += 1
|
||||||
result = eval_func(edge.Tag, t, 0)
|
if parse_failures <= 2:
|
||||||
else:
|
_log(f"[edge] Parse failed at t={t:.4f}, type={type(result).__name__}, repr={repr(result)[:300]}")
|
||||||
# eval_* method on evaluator
|
except Exception as exc:
|
||||||
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:
|
|
||||||
parse_failures += 1
|
parse_failures += 1
|
||||||
if parse_failures <= 2:
|
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:
|
finally:
|
||||||
if evaluator is not None:
|
if evaluator is not None:
|
||||||
try:
|
try:
|
||||||
@@ -275,12 +241,12 @@ def _sample_edge_polyline(edge: Any, chord_tol_mm: float, lister: Any = None) ->
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if len(pts) >= 2:
|
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
|
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:
|
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)
|
# 2) Fallback: IBaseCurve.Evaluate (signature differs by NX versions)
|
||||||
try:
|
try:
|
||||||
|
|||||||
Reference in New Issue
Block a user