Compare commits
2 Commits
c4d98ee97c
...
ecba40f189
| Author | SHA1 | Date | |
|---|---|---|---|
| ecba40f189 | |||
| 515eef145f |
@@ -31,6 +31,8 @@ from typing import Any, Dict, List, Tuple
|
|||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
SKETCH_NAME_PREFIX = "ISOGRID_RIB_" # e.g., ISOGRID_RIB_sandbox_1
|
SKETCH_NAME_PREFIX = "ISOGRID_RIB_" # e.g., ISOGRID_RIB_sandbox_1
|
||||||
|
EXTRUDE_NAME_PREFIX = "ISOGRID_EXTRUDE_" # e.g., ISOGRID_EXTRUDE_sandbox_1
|
||||||
|
DEFAULT_RIB_THICKNESS = 10.0 # mm, fallback if not in profile JSON
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -95,37 +97,78 @@ def _find_old_sketch_feature(part: Any, sketch_name: str, lister: Any):
|
|||||||
|
|
||||||
def _replace_and_delete_old_sketch(part: Any, old_feature: Any, new_feature: Any, lister: Any):
|
def _replace_and_delete_old_sketch(part: Any, old_feature: Any, new_feature: Any, lister: Any):
|
||||||
"""
|
"""
|
||||||
Replace all references from old sketch feature to new one, then delete old.
|
Replace old sketch with new one using NX's ReplaceFeatureBuilder.
|
||||||
Uses NX Edit > Feature > Replace Feature approach.
|
|
||||||
|
This mirrors the interactive: right-click sketch → Replace Feature.
|
||||||
|
All downstream features (extrude, trim, etc.) automatically re-reference
|
||||||
|
the new sketch. The old sketch is deleted after replacement.
|
||||||
|
|
||||||
|
API: NXOpen.Features.ReplaceFeatureBuilder
|
||||||
|
- SelectFeature → original feature to replace
|
||||||
|
- ReplacementFeature → new feature that takes over
|
||||||
|
- DeleteOriginalFeature → True (remove old after remap)
|
||||||
|
- DoAutomaticGeomMatch → True (auto-match edges/curves)
|
||||||
|
- AutomatchMap() → run the auto-matching
|
||||||
|
- Commit() → execute the replacement
|
||||||
"""
|
"""
|
||||||
import NXOpen
|
import NXOpen
|
||||||
|
|
||||||
session = NXOpen.Session.GetSession()
|
session = NXOpen.Session.GetSession()
|
||||||
|
mark = session.SetUndoMark(NXOpen.Session.MarkVisibility.Visible,
|
||||||
|
"Replace isogrid sketch")
|
||||||
|
|
||||||
# Try to replace references from old → new
|
|
||||||
try:
|
try:
|
||||||
# Get all parent features that reference the old sketch (e.g. Extrude)
|
# Create the ReplaceFeatureBuilder
|
||||||
parents = old_feature.GetParents()
|
builder = part.Features.CreateReplaceFeatureBuilder(
|
||||||
if parents:
|
NXOpen.Features.Feature.Null
|
||||||
lister.WriteLine(f"[import] Old sketch has {len(parents)} parent feature(s) — replacing references")
|
)
|
||||||
for parent in parents:
|
|
||||||
try:
|
# Set the original feature (old sketch) to be replaced
|
||||||
parent.ReplaceEntity(old_feature, new_feature)
|
added_old = builder.SelectFeature.Add(old_feature)
|
||||||
lister.WriteLine(f"[import] Replaced reference in {parent.JournalIdentifier}")
|
lister.WriteLine(f"[import] Set original feature: {old_feature.JournalIdentifier}")
|
||||||
except Exception as exc:
|
|
||||||
lister.WriteLine(f"[import] Could not replace in {parent.JournalIdentifier}: {exc}")
|
# Set the replacement feature (new sketch)
|
||||||
except Exception as exc:
|
added_new = builder.ReplacementFeature.Add(new_feature)
|
||||||
lister.WriteLine(f"[import] Warning getting parents: {exc}")
|
lister.WriteLine(f"[import] Set replacement feature: {new_feature.JournalIdentifier}")
|
||||||
|
|
||||||
|
# Configuration
|
||||||
|
builder.DeleteOriginalFeature = True
|
||||||
|
builder.DoAutomaticGeomMatch = True
|
||||||
|
|
||||||
|
# Run automatic geometry matching (maps old curves → new curves)
|
||||||
|
try:
|
||||||
|
builder.AutomatchMap()
|
||||||
|
lister.WriteLine("[import] Auto-match mapping completed")
|
||||||
|
except Exception as exc:
|
||||||
|
lister.WriteLine(f"[import] Auto-match warning (may still work): {exc}")
|
||||||
|
|
||||||
|
# Update the mapping
|
||||||
|
try:
|
||||||
|
builder.UpdateMap()
|
||||||
|
except Exception as exc:
|
||||||
|
lister.WriteLine(f"[import] UpdateMap note: {exc}")
|
||||||
|
|
||||||
|
# Commit the replacement
|
||||||
|
builder.Commit()
|
||||||
|
lister.WriteLine("[import] ReplaceFeature committed — all references updated")
|
||||||
|
|
||||||
|
builder.Destroy()
|
||||||
|
|
||||||
# Delete the old sketch feature
|
|
||||||
try:
|
|
||||||
mark = session.SetUndoMark(NXOpen.Session.MarkVisibility.Visible, "Delete old isogrid sketch")
|
|
||||||
nErrs = session.UpdateManager.AddToDeleteList(old_feature)
|
|
||||||
nErrs2 = session.UpdateManager.DoUpdate(mark)
|
|
||||||
lister.WriteLine(f"[import] Deleted old sketch feature ({nErrs + nErrs2} warnings)")
|
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
lister.WriteLine(f"[import] Warning deleting old sketch: {exc}")
|
lister.WriteLine(f"[import] ReplaceFeatureBuilder failed: {exc}")
|
||||||
lister.WriteLine(f"[import] You may need to manually delete the old sketch")
|
lister.WriteLine("[import] Falling back to manual delete + re-reference...")
|
||||||
|
|
||||||
|
# Fallback: just delete the old sketch
|
||||||
|
# Downstream features (extrude) will go into "out of date" state
|
||||||
|
# and need manual re-selection of the new sketch section
|
||||||
|
try:
|
||||||
|
nErrs = session.UpdateManager.AddToDeleteList(old_feature)
|
||||||
|
nErrs2 = session.UpdateManager.DoUpdate(mark)
|
||||||
|
lister.WriteLine(f"[import] Deleted old sketch ({nErrs + nErrs2} warnings)")
|
||||||
|
lister.WriteLine("[import] ⚠ Extrude may need manual sketch re-selection")
|
||||||
|
except Exception as exc2:
|
||||||
|
lister.WriteLine(f"[import] Delete also failed: {exc2}")
|
||||||
|
lister.WriteLine("[import] ⚠ Manually delete old sketch and fix extrude")
|
||||||
|
|
||||||
|
|
||||||
def _find_or_create_sketch(
|
def _find_or_create_sketch(
|
||||||
@@ -238,10 +281,25 @@ def _find_or_create_sketch(
|
|||||||
|
|
||||||
lister.WriteLine(f"[import] Created sketch: {sketch_name}")
|
lister.WriteLine(f"[import] Created sketch: {sketch_name}")
|
||||||
|
|
||||||
# If old sketch existed, replace references and delete it
|
# If old sketch existed, delete it (extrude will be recreated by _extrude_sketch)
|
||||||
if old_feature is not None and new_feature is not None:
|
if old_feature is not None:
|
||||||
lister.WriteLine(f"[import] Replacing old sketch with new one...")
|
import NXOpen as _NXOpen
|
||||||
_replace_and_delete_old_sketch(part, old_feature, new_feature, lister)
|
_session = _NXOpen.Session.GetSession()
|
||||||
|
|
||||||
|
# First try ReplaceFeatureBuilder to preserve downstream references
|
||||||
|
replaced = False
|
||||||
|
if new_feature is not None:
|
||||||
|
lister.WriteLine(f"[import] Attempting ReplaceFeatureBuilder (old → new)...")
|
||||||
|
try:
|
||||||
|
_replace_and_delete_old_sketch(part, old_feature, new_feature, lister)
|
||||||
|
replaced = True
|
||||||
|
except Exception as exc:
|
||||||
|
lister.WriteLine(f"[import] ReplaceFeatureBuilder failed: {exc}")
|
||||||
|
|
||||||
|
# Fallback: just delete old sketch (extrude will be re-created)
|
||||||
|
if not replaced:
|
||||||
|
lister.WriteLine(f"[import] Deleting old sketch (extrude will be re-created)...")
|
||||||
|
_delete_feature(_session, old_feature, lister, f"old sketch {sketch_name}")
|
||||||
|
|
||||||
return sketch
|
return sketch
|
||||||
|
|
||||||
@@ -375,6 +433,205 @@ def _draw_structured_pocket(part, pocket, transform, lister):
|
|||||||
return lines_drawn, arcs_drawn
|
return lines_drawn, arcs_drawn
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Extrude sketch
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _find_extrude_feature(part: Any, extrude_name: str, lister: Any):
|
||||||
|
"""Find an existing extrude feature by name. Returns Feature or None."""
|
||||||
|
try:
|
||||||
|
for feat in part.Features:
|
||||||
|
try:
|
||||||
|
if feat.Name == extrude_name:
|
||||||
|
lister.WriteLine(f"[import] Found existing extrude: {extrude_name}")
|
||||||
|
return feat
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _delete_feature(session: Any, feature: Any, lister: Any, label: str = "feature"):
|
||||||
|
"""Delete a feature using the update manager."""
|
||||||
|
import NXOpen
|
||||||
|
try:
|
||||||
|
mark = session.SetUndoMark(NXOpen.Session.MarkVisibility.Visible,
|
||||||
|
f"Delete {label}")
|
||||||
|
session.UpdateManager.AddToDeleteList(feature)
|
||||||
|
session.UpdateManager.DoUpdate(mark)
|
||||||
|
lister.WriteLine(f"[import] Deleted {label}: {feature.JournalIdentifier}")
|
||||||
|
return True
|
||||||
|
except Exception as exc:
|
||||||
|
lister.WriteLine(f"[import] WARNING: Could not delete {label}: {exc}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _extrude_sketch(part: Any, sketch: Any, thickness: float,
|
||||||
|
normal: List[float], extrude_name: str, lister: Any):
|
||||||
|
"""
|
||||||
|
Extrude all curves in the sketch by `thickness` along the face normal.
|
||||||
|
Creates a new Extrude feature named `extrude_name`.
|
||||||
|
|
||||||
|
If an old extrude with the same name exists, delete it first.
|
||||||
|
"""
|
||||||
|
import NXOpen
|
||||||
|
|
||||||
|
session = NXOpen.Session.GetSession()
|
||||||
|
|
||||||
|
# Delete old extrude if it exists
|
||||||
|
old_extrude = _find_extrude_feature(part, extrude_name, lister)
|
||||||
|
if old_extrude is not None:
|
||||||
|
_delete_feature(session, old_extrude, lister, f"old extrude {extrude_name}")
|
||||||
|
|
||||||
|
lister.WriteLine(f"[import] Extruding sketch by {thickness} mm along normal")
|
||||||
|
|
||||||
|
mark = session.SetUndoMark(NXOpen.Session.MarkVisibility.Visible,
|
||||||
|
f"Extrude {extrude_name}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Create ExtrudeBuilder (null feature = new extrude)
|
||||||
|
builder = part.Features.CreateExtrudeBuilder(
|
||||||
|
NXOpen.Features.Feature.Null
|
||||||
|
)
|
||||||
|
|
||||||
|
# Set the section: use sketch curves
|
||||||
|
# Get all curves from the sketch
|
||||||
|
sketch_feature = sketch.Feature
|
||||||
|
curves = []
|
||||||
|
try:
|
||||||
|
# Try getting sketch geometry objects
|
||||||
|
geom = sketch.GetAllGeometry()
|
||||||
|
for obj in geom:
|
||||||
|
curves.append(obj)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if not curves:
|
||||||
|
# Fallback: get curves from feature's entities
|
||||||
|
try:
|
||||||
|
entities = sketch_feature.GetEntities()
|
||||||
|
for ent in entities:
|
||||||
|
if hasattr(ent, 'StartPoint') or hasattr(ent, 'GetLength'):
|
||||||
|
curves.append(ent)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
lister.WriteLine(f"[import] Found {len(curves)} curves in sketch for extrude")
|
||||||
|
|
||||||
|
# Create section and add curves
|
||||||
|
section = part.Sections.CreateSection(
|
||||||
|
0.0095, # chaining tolerance
|
||||||
|
0.01, # distance tolerance
|
||||||
|
0.5, # angle tolerance
|
||||||
|
)
|
||||||
|
section.SetAllowedEntityTypes(
|
||||||
|
NXOpen.Section.AllowTypes.OnlyCurves
|
||||||
|
)
|
||||||
|
|
||||||
|
# Add sketch curves to the section
|
||||||
|
sketch_feature_tag = sketch.Feature
|
||||||
|
curves_added = False
|
||||||
|
|
||||||
|
# Method 1: Add the sketch feature directly as section input
|
||||||
|
try:
|
||||||
|
feature_rule = part.ScRuleFactory.CreateRuleFeatureCurves(
|
||||||
|
[sketch_feature_tag]
|
||||||
|
)
|
||||||
|
section.AllowSelfIntersection(True)
|
||||||
|
help_pt = NXOpen.Point3d(0, 0, 0)
|
||||||
|
section.AddToSection(
|
||||||
|
[feature_rule],
|
||||||
|
NXOpen.NXObject.Null, # seed
|
||||||
|
NXOpen.NXObject.Null, # start connector
|
||||||
|
NXOpen.NXObject.Null, # end connector
|
||||||
|
help_pt,
|
||||||
|
NXOpen.Section.Mode.Create,
|
||||||
|
False, # go to end
|
||||||
|
)
|
||||||
|
curves_added = True
|
||||||
|
lister.WriteLine("[import] Added sketch curves to section via FeatureCurves rule")
|
||||||
|
except Exception as exc:
|
||||||
|
lister.WriteLine(f"[import] FeatureCurves rule failed: {exc}")
|
||||||
|
|
||||||
|
if not curves_added and curves:
|
||||||
|
# Method 2: Add individual curves
|
||||||
|
try:
|
||||||
|
curve_rule = part.ScRuleFactory.CreateRuleCurveDumb(curves)
|
||||||
|
help_pt = NXOpen.Point3d(0, 0, 0)
|
||||||
|
section.AddToSection(
|
||||||
|
[curve_rule],
|
||||||
|
curves[0],
|
||||||
|
NXOpen.NXObject.Null,
|
||||||
|
NXOpen.NXObject.Null,
|
||||||
|
help_pt,
|
||||||
|
NXOpen.Section.Mode.Create,
|
||||||
|
False,
|
||||||
|
)
|
||||||
|
curves_added = True
|
||||||
|
lister.WriteLine("[import] Added curves via CurveDumb rule")
|
||||||
|
except Exception as exc:
|
||||||
|
lister.WriteLine(f"[import] CurveDumb rule failed: {exc}")
|
||||||
|
|
||||||
|
if not curves_added:
|
||||||
|
lister.WriteLine("[import] ERROR: Could not add curves to extrude section")
|
||||||
|
builder.Destroy()
|
||||||
|
return None
|
||||||
|
|
||||||
|
builder.Section = section
|
||||||
|
|
||||||
|
# Set direction (along face normal)
|
||||||
|
direction = part.Directions.CreateDirection(
|
||||||
|
NXOpen.Point3d(0, 0, 0),
|
||||||
|
NXOpen.Vector3d(normal[0], normal[1], normal[2]),
|
||||||
|
NXOpen.SmartObject.UpdateOption.WithinModeling,
|
||||||
|
)
|
||||||
|
builder.Direction = direction
|
||||||
|
|
||||||
|
# Set limits: start=0, end=thickness
|
||||||
|
builder.Limits.StartExtend.Value.RightHandSide = "0"
|
||||||
|
builder.Limits.EndExtend.Value.RightHandSide = str(thickness)
|
||||||
|
|
||||||
|
# Boolean: create (no unite/subtract for now — idealized model)
|
||||||
|
builder.BooleanOperation.Type = NXOpen.GeometricUtilities.BooleanOperation.BooleanType.Create
|
||||||
|
|
||||||
|
# Commit
|
||||||
|
extrude_obj = builder.Commit()
|
||||||
|
builder.Destroy()
|
||||||
|
|
||||||
|
# Rename the extrude feature
|
||||||
|
committed = builder.GetCommittedObjects() if hasattr(builder, 'GetCommittedObjects') else []
|
||||||
|
extrude_feature = None
|
||||||
|
|
||||||
|
if isinstance(extrude_obj, NXOpen.Features.Feature):
|
||||||
|
extrude_feature = extrude_obj
|
||||||
|
else:
|
||||||
|
# Find the most recently created extrude feature
|
||||||
|
for feat in part.Features:
|
||||||
|
try:
|
||||||
|
if "Extrude" in feat.FeatureType and feat.Name == "":
|
||||||
|
extrude_feature = feat
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if extrude_feature is not None:
|
||||||
|
try:
|
||||||
|
extrude_feature.SetName(extrude_name)
|
||||||
|
lister.WriteLine(f"[import] Extrude created and named: {extrude_name}")
|
||||||
|
except Exception:
|
||||||
|
lister.WriteLine(f"[import] Extrude created (could not rename)")
|
||||||
|
else:
|
||||||
|
lister.WriteLine(f"[import] Extrude committed (feature reference unclear)")
|
||||||
|
|
||||||
|
return extrude_feature
|
||||||
|
|
||||||
|
except Exception as exc:
|
||||||
|
lister.WriteLine(f"[import] ERROR creating extrude: {exc}")
|
||||||
|
import traceback
|
||||||
|
lister.WriteLine(traceback.format_exc())
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Main
|
# Main
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
@@ -547,8 +804,25 @@ def main():
|
|||||||
|
|
||||||
lister.WriteLine(f"[import] Pockets: {len(pockets)}")
|
lister.WriteLine(f"[import] Pockets: {len(pockets)}")
|
||||||
|
|
||||||
|
# --- Auto-extrude ---
|
||||||
|
rib_thickness = profile.get("parameters_used", {}).get("thickness",
|
||||||
|
geometry.get("thickness", DEFAULT_RIB_THICKNESS))
|
||||||
|
if rib_thickness is None:
|
||||||
|
rib_thickness = DEFAULT_RIB_THICKNESS
|
||||||
|
normal = transform["normal"]
|
||||||
|
extrude_name = EXTRUDE_NAME_PREFIX + sandbox_id
|
||||||
|
|
||||||
|
extrude_feat = _extrude_sketch(
|
||||||
|
work_part, sketch, rib_thickness, normal, extrude_name, lister
|
||||||
|
)
|
||||||
|
if extrude_feat is not None:
|
||||||
|
lister.WriteLine(f"[import] ✓ Sketch + Extrude complete for {sandbox_id}")
|
||||||
|
else:
|
||||||
|
lister.WriteLine(f"[import] ⚠ Sketch created but extrude failed — extrude manually")
|
||||||
|
lister.WriteLine(f"[import] Thickness: {rib_thickness} mm along normal {normal}")
|
||||||
|
|
||||||
lister.WriteLine("\n" + "=" * 60)
|
lister.WriteLine("\n" + "=" * 60)
|
||||||
lister.WriteLine(" Import complete — extrude the sketch to rib thickness")
|
lister.WriteLine(" Import complete")
|
||||||
lister.WriteLine("=" * 60)
|
lister.WriteLine("=" * 60)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user