226 lines
11 KiB
Python
226 lines
11 KiB
Python
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import traceback
|
|
from pathlib import Path
|
|
|
|
from .model import StepModel
|
|
|
|
|
|
def _optional_int(value: object) -> int | None:
|
|
if value is None or value == "":
|
|
return None
|
|
return int(value)
|
|
|
|
|
|
def _point3(value: object, operation: str) -> tuple[float, float, float]:
|
|
point = list(value) if isinstance(value, (list, tuple)) else []
|
|
if len(point) != 3:
|
|
raise ValueError(f"{operation} requires a 3D target center.")
|
|
return (float(point[0]), float(point[1]), float(point[2]))
|
|
|
|
|
|
def _execute(model: StepModel, operation: str, args: list[object]) -> str:
|
|
if operation == "push_pull_face":
|
|
return model.push_pull_face(int(args[0]), float(args[1]))
|
|
if operation == "push_pull_face_keep_relations":
|
|
return model.push_pull_face_keep_relations(int(args[0]), float(args[1]))
|
|
if operation == "move_face_plane_offset_local":
|
|
return model.move_face_plane_offset_local(int(args[0]), float(args[1]))
|
|
if operation == "translate_face_plane_offset_owning":
|
|
return model.translate_face_plane_offset_owning(int(args[0]), float(args[1]))
|
|
if operation == "resize_face_area_local":
|
|
return model.resize_face_area_local(int(args[0]), float(args[1]))
|
|
if operation == "resize_face_area":
|
|
return model.resize_face_area(int(args[0]), float(args[1]))
|
|
if operation == "resize_face_size_local":
|
|
return model.resize_face_size_local(int(args[0]), float(args[1]), str(args[2]))
|
|
if operation == "resize_face_size_local_keep_relations":
|
|
return model.resize_face_size_local_keep_relations(int(args[0]), float(args[1]), str(args[2]))
|
|
if operation == "resize_face_size_owning_scale":
|
|
return model.resize_face_size_owning_scale(int(args[0]), float(args[1]), str(args[2]))
|
|
if operation == "move_face_center_local":
|
|
center = list(args[1])
|
|
if len(center) != 3:
|
|
raise ValueError("move_face_center_local requires a 3D target center.")
|
|
return model.move_face_center_local(
|
|
int(args[0]),
|
|
(float(center[0]), float(center[1]), float(center[2])),
|
|
)
|
|
if operation == "move_face_center_local_keep_relations":
|
|
center = list(args[1])
|
|
if len(center) != 3:
|
|
raise ValueError("move_face_center_local_keep_relations requires a 3D target center.")
|
|
return model.move_face_center_local_keep_relations(
|
|
int(args[0]),
|
|
(float(center[0]), float(center[1]), float(center[2])),
|
|
)
|
|
if operation == "resize_shell_thickness":
|
|
return model.resize_shell_thickness(int(args[0]), float(args[1]))
|
|
if operation == "resize_shell_thickness_owning_scale":
|
|
return model.resize_shell_thickness_owning_scale(int(args[0]), float(args[1]))
|
|
if operation == "resize_cylindrical_height":
|
|
return model.resize_cylindrical_height(int(args[0]), float(args[1]))
|
|
if operation == "resize_cylindrical_boss_height":
|
|
return model.resize_cylindrical_boss_height(int(args[0]), float(args[1]))
|
|
if operation == "resize_cylindrical_boss":
|
|
return model.resize_cylindrical_boss(int(args[0]), float(args[1]))
|
|
if operation == "resize_cylindrical_height_owning_scale":
|
|
return model.resize_cylindrical_height_owning_scale(int(args[0]), float(args[1]))
|
|
if operation == "resize_cone_reference_radius":
|
|
return model.resize_conical_reference_radius(int(args[0]), float(args[1]))
|
|
if operation == "resize_cone_semi_angle":
|
|
return model.resize_conical_semi_angle(int(args[0]), float(args[1]))
|
|
if operation == "resize_sphere_radius":
|
|
return model.resize_spherical_radius(int(args[0]), float(args[1]))
|
|
if operation == "resize_torus_radius":
|
|
return model.resize_toroidal_radius(int(args[0]), float(args[1]), str(args[2]))
|
|
if operation == "resize_cylindrical_hole":
|
|
return model.resize_cylindrical_hole(int(args[0]), float(args[1]))
|
|
if operation == "resize_cylindrical_owning_scale":
|
|
return model.resize_cylindrical_owning_scale(int(args[0]), float(args[1]))
|
|
if operation == "move_cylindrical_hole_axis":
|
|
return model.move_cylindrical_hole_axis(int(args[0]), _point3(args[1], operation))
|
|
if operation == "move_cylindrical_boss_axis":
|
|
return model.move_cylindrical_boss_axis(int(args[0]), _point3(args[1], operation))
|
|
if operation == "suppress_cylindrical_hole":
|
|
return model.suppress_cylindrical_hole(int(args[0]))
|
|
if operation == "resize_cylindrical_depth":
|
|
bottom_face_id = _optional_int(args[2]) if len(args) > 2 else None
|
|
return model.resize_cylindrical_depth(int(args[0]), float(args[1]), bottom_face_id=bottom_face_id)
|
|
if operation == "resize_cylindrical_depth_owning_scale":
|
|
bottom_face_id = _optional_int(args[2]) if len(args) > 2 else None
|
|
return model.resize_cylindrical_depth_owning_scale(int(args[0]), float(args[1]), bottom_face_id=bottom_face_id)
|
|
if operation == "move_cylindrical_slot_axis":
|
|
return model.move_cylindrical_slot_axis(int(args[0]), _point3(args[1], operation))
|
|
if operation == "resize_cylindrical_slot_width":
|
|
pair_face_id = _optional_int(args[2]) if len(args) > 2 else None
|
|
return model.resize_cylindrical_slot_width(int(args[0]), float(args[1]), pair_face_id=pair_face_id)
|
|
if operation == "resize_cylindrical_slot_depth":
|
|
pair_face_id = _optional_int(args[2]) if len(args) > 2 else None
|
|
return model.resize_cylindrical_slot_depth(int(args[0]), float(args[1]), pair_face_id=pair_face_id)
|
|
if operation == "resize_cylindrical_slot_arc_length":
|
|
pair_face_id = _optional_int(args[2]) if len(args) > 2 else None
|
|
return model.resize_cylindrical_slot_arc_length(int(args[0]), float(args[1]), pair_face_id=pair_face_id)
|
|
if operation == "resize_cylindrical_slot_angular_span":
|
|
return model.resize_cylindrical_slot_angular_span(int(args[0]), float(args[1]))
|
|
if operation == "resize_cylindrical_slot_total_length":
|
|
pair_face_id = _optional_int(args[2]) if len(args) > 2 else None
|
|
return model.resize_cylindrical_slot_total_length(int(args[0]), float(args[1]), pair_face_id=pair_face_id)
|
|
if operation == "resize_cylindrical_slot_center_distance":
|
|
pair_face_id = _optional_int(args[2]) if len(args) > 2 else None
|
|
return model.resize_cylindrical_slot_center_distance(
|
|
int(args[0]),
|
|
float(args[1]),
|
|
pair_face_id=pair_face_id,
|
|
)
|
|
if operation == "resize_general_edge_length":
|
|
anchor_mode = str(args[2]) if len(args) > 2 else "auto"
|
|
strategy_mode = str(args[3]) if len(args) > 3 else "auto"
|
|
return model.resize_general_edge_length(
|
|
int(args[0]),
|
|
float(args[1]),
|
|
anchor_mode=anchor_mode,
|
|
strategy_mode=strategy_mode,
|
|
)
|
|
if operation == "move_edge_endpoint":
|
|
return model.move_edge_endpoint(int(args[0]), str(args[1]), _point3(args[2], operation))
|
|
if operation == "move_edge_center":
|
|
return model.move_edge_center(int(args[0]), _point3(args[1], operation))
|
|
if operation == "move_circular_edge_axis_center":
|
|
return model.move_circular_edge_axis_center(int(args[0]), _point3(args[1], operation))
|
|
if operation == "resize_ellipse_edge_axis_radius":
|
|
axis_kind = str(args[2]) if len(args) > 2 else "major"
|
|
return model.resize_ellipse_edge_axis_radius(int(args[0]), float(args[1]), axis_kind=axis_kind)
|
|
if operation == "resize_existing_fillet":
|
|
return model.resize_existing_fillet(int(args[0]), float(args[1]))
|
|
if operation == "resize_existing_chamfer":
|
|
return model.resize_existing_chamfer(int(args[0]), float(args[1]))
|
|
if operation == "fillet_edge":
|
|
return model.fillet_edge(int(args[0]), float(args[1]))
|
|
if operation == "chamfer_edge":
|
|
return model.chamfer_edge(int(args[0]), float(args[1]))
|
|
if operation == "chamfer_edge_asymmetric":
|
|
reference_face_id = _optional_int(args[3]) if len(args) > 3 else None
|
|
return model.chamfer_edge_asymmetric(int(args[0]), float(args[1]), float(args[2]), reference_face_id)
|
|
if operation == "chamfer_edge_distance_angle":
|
|
reference_face_id = _optional_int(args[3]) if len(args) > 3 else None
|
|
return model.chamfer_edge_distance_angle(int(args[0]), float(args[1]), float(args[2]), reference_face_id)
|
|
raise ValueError(f"Unsupported isolated edit operation: {operation}")
|
|
|
|
|
|
def _load_request_model(path: Path, file_format: str) -> StepModel:
|
|
if file_format == "brep":
|
|
return StepModel.load_internal_brep(path)
|
|
if file_format == "step":
|
|
return StepModel.load(path)
|
|
raise ValueError(f"Unsupported isolated edit input format: {file_format}")
|
|
|
|
|
|
def _export_response_model(model: StepModel, path: Path, file_format: str) -> None:
|
|
if file_format == "brep":
|
|
model.export_internal_brep(path)
|
|
return
|
|
if file_format == "step":
|
|
model.export_all(path)
|
|
return
|
|
raise ValueError(f"Unsupported isolated edit output format: {file_format}")
|
|
|
|
|
|
def run_request(request: str | Path) -> int:
|
|
request_path = Path(request)
|
|
response_path = request_path.with_suffix(".response.json")
|
|
try:
|
|
request = json.loads(request_path.read_text(encoding="utf-8-sig"))
|
|
input_path = Path(str(request["input_path"]))
|
|
output_path = Path(str(request["output_path"]))
|
|
operation = str(request["operation"])
|
|
args = list(request.get("args") or [])
|
|
input_format = str(request.get("input_format") or "step").strip().lower()
|
|
output_format = str(request.get("output_format") or input_format).strip().lower()
|
|
|
|
model = _load_request_model(input_path, input_format)
|
|
message = _execute(model, operation, args)
|
|
_export_response_model(model, output_path, output_format)
|
|
response_path.write_text(
|
|
json.dumps(
|
|
{
|
|
"ok": True,
|
|
"message": message,
|
|
"stats": model.stats().__dict__,
|
|
"output_path": str(output_path),
|
|
"output_format": output_format,
|
|
},
|
|
ensure_ascii=False,
|
|
indent=2,
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
return 0
|
|
except Exception as exc:
|
|
response_path.write_text(
|
|
json.dumps(
|
|
{
|
|
"ok": False,
|
|
"error": str(exc),
|
|
"traceback": traceback.format_exc(),
|
|
},
|
|
ensure_ascii=False,
|
|
indent=2,
|
|
),
|
|
encoding="utf-8",
|
|
)
|
|
return 2
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="Run one high-risk geometry edit in an isolated process.")
|
|
parser.add_argument("request", help="JSON request file.")
|
|
parsed = parser.parse_args()
|
|
return run_request(parsed.request)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|