feat: 完善 Face 参数化编辑和隔离执行
This commit is contained in:
@@ -58,6 +58,17 @@ def _first_boss_face(model: StepModel) -> int:
|
||||
return candidates[0]
|
||||
|
||||
|
||||
def _first_circle_edge_adjacent_to_face(model: StepModel, face_id: int) -> int:
|
||||
for edge_id in range(len(model.edges)):
|
||||
info = model.edge_info(edge_id)
|
||||
if info.get("curve") != "circle":
|
||||
continue
|
||||
adjacent_face_ids = tuple(int(item) for item in info.get("adjacent_face_ids", ()) or ())
|
||||
if face_id in adjacent_face_ids:
|
||||
return edge_id
|
||||
raise SystemExit(f"no circular edge adjacent to Face {face_id} was recognized")
|
||||
|
||||
|
||||
def _axis_center(model: StepModel, face_id: int) -> tuple[float, float, float]:
|
||||
info = model.face_info(face_id)
|
||||
axis_point = info.get("axis_point")
|
||||
@@ -185,6 +196,55 @@ def _run_axis_center_case(offset: float, tolerance: float) -> None:
|
||||
print(result.encode("ascii", "backslashreplace").decode("ascii"))
|
||||
|
||||
|
||||
def _run_circle_edge_axis_center_case(offset: float, tolerance: float) -> None:
|
||||
with tempfile.TemporaryDirectory(prefix="geom_param_boss_circle_edge_axis_") as temp_dir:
|
||||
model_path = Path(temp_dir) / "boss.step"
|
||||
_write_boss_model(model_path)
|
||||
model = StepModel.load(model_path)
|
||||
face_id = _first_boss_face(model)
|
||||
edge_id = _first_circle_edge_adjacent_to_face(model, face_id)
|
||||
before = model.stats()
|
||||
current_center = _axis_center(model, face_id)
|
||||
current_diameter = _diameter(model, face_id)
|
||||
current_height = _height(model, face_id)
|
||||
edge_info = model.edge_info(edge_id)
|
||||
edge_center = edge_info.get("center")
|
||||
if not isinstance(edge_center, tuple):
|
||||
raise SystemExit(f"circle edge center is missing on Edge {edge_id}")
|
||||
target_edge_center = (float(edge_center[0]) + offset, float(edge_center[1]), float(edge_center[2]))
|
||||
target_axis_center = (current_center[0] + offset, current_center[1], current_center[2])
|
||||
plan = model.circular_edge_axis_move_plan(edge_id, target_edge_center)
|
||||
if plan["status"] == "blocked":
|
||||
raise SystemExit(f"circle_edge_axis_center plan was blocked: {plan['message']}")
|
||||
result = model.move_circular_edge_axis_center(edge_id, target_edge_center)
|
||||
after = model.stats()
|
||||
verified_face, diameter, height, center, _ = _nearest_boss(model, current_diameter, target_axis_center)
|
||||
center_error = _distance(center, target_axis_center)
|
||||
height_error = abs(height - current_height)
|
||||
if after.solids != before.solids:
|
||||
raise SystemExit(f"circle_edge_axis_center changed solid count: before={before.solids}, after={after.solids}")
|
||||
if center_error > tolerance or abs(diameter - current_diameter) > tolerance:
|
||||
raise SystemExit(
|
||||
f"circle_edge_axis_center verification failed: target={target_axis_center}, center={center}, "
|
||||
f"center_error={center_error:g}, diameter={diameter:g}"
|
||||
)
|
||||
if height_error > tolerance:
|
||||
raise SystemExit(
|
||||
f"circle_edge_axis_center changed boss height: before={current_height:g}, after={height:g}, error={height_error:g}"
|
||||
)
|
||||
print("mode=circle_edge_axis_center")
|
||||
print(f"source_edge={edge_id}")
|
||||
print(f"source_face={face_id}")
|
||||
print(f"strategy={plan.get('resize_strategy')}")
|
||||
print(f"delegated_mode={plan.get('circular_edge_cylinder_mode')}")
|
||||
print(f"before={before}")
|
||||
print(f"after={after}")
|
||||
print(f"verified_face={verified_face}")
|
||||
print(f"target_edge_center={target_edge_center}")
|
||||
print(f"target_axis_center={target_axis_center} value={center} diameter={diameter:.6f} height={height:.6f} error={center_error:.6g}")
|
||||
print(result.encode("ascii", "backslashreplace").decode("ascii"))
|
||||
|
||||
|
||||
def _run_height_case(target: float, tolerance: float) -> None:
|
||||
with tempfile.TemporaryDirectory(prefix="geom_param_boss_height_") as temp_dir:
|
||||
model_path = Path(temp_dir) / "boss.step"
|
||||
@@ -219,13 +279,14 @@ def main() -> int:
|
||||
parser.add_argument(
|
||||
"--mode",
|
||||
default="all",
|
||||
choices=["all", "diameter", "diameter_shrink", "height", "axis_center"],
|
||||
choices=["all", "diameter", "diameter_shrink", "height", "axis_center", "circle_edge_axis_center"],
|
||||
help="Boss edit mode to verify.",
|
||||
)
|
||||
parser.add_argument("--diameter", type=float, default=8.0)
|
||||
parser.add_argument("--diameter-shrink", type=float, default=4.0)
|
||||
parser.add_argument("--height", type=float, default=7.0)
|
||||
parser.add_argument("--axis-center", type=float, default=2.0, help="Axis-center X offset to verify.")
|
||||
parser.add_argument("--circle-edge-axis-center", type=float, default=2.0, help="Circle Edge center X offset to verify.")
|
||||
parser.add_argument("--tolerance", type=float, default=2e-4)
|
||||
args = parser.parse_args()
|
||||
|
||||
@@ -235,6 +296,7 @@ def main() -> int:
|
||||
("diameter_shrink", args.diameter_shrink),
|
||||
("height", args.height),
|
||||
("axis_center", args.axis_center),
|
||||
("circle_edge_axis_center", args.circle_edge_axis_center),
|
||||
]
|
||||
if args.mode == "all"
|
||||
else [(args.mode, getattr(args, args.mode.replace("-", "_")))]
|
||||
@@ -246,6 +308,8 @@ def main() -> int:
|
||||
_run_height_case(float(target), args.tolerance)
|
||||
elif mode == "axis_center":
|
||||
_run_axis_center_case(float(target), args.tolerance)
|
||||
elif mode == "circle_edge_axis_center":
|
||||
_run_circle_edge_axis_center_case(float(target), args.tolerance)
|
||||
else:
|
||||
raise SystemExit(f"unsupported mode: {mode}")
|
||||
return 0
|
||||
|
||||
Reference in New Issue
Block a user