mirror of
https://github.com/OrcaSlicer/OrcaSlicer.git
synced 2026-09-27 19:01:02 +00:00
CAD: Transform feature — move/rotate a body as a real B-rep operation
Until now move and rotate lived only in the GUI as m_body_xform, a display transform. That made them a correctness hole, not a missing tool: a moved body recomputed and booleaned at its ORIGINAL position, and the move was not in the recipe at all, so it vanished on save/reload. Only export_step consulted the transform, which is why the discrepancy stayed hidden. CadFeatureType::Transform makes it a real feature: rotate angle_deg about xf_axis through xf_pivot, then translate by xf_translate, applied to the target body with BRepBuilderAPI_Transform. xf_copy=true keeps the source and appends the transformed body instead of mutating in place, which covers Onshape's Transform/copy in the same feature. Rotation is composed before translation (trsf = tr * rot) so the pivot means what a user expects — the point the body turns about, not a point that then drifts with the translation. A rotation with a degenerate axis is refused rather than silently skipped; a zero angle skips the rotation entirely so a pure move needs no axis at all. The decisive test is not the bbox arithmetic but "moved body participates in a later boolean at its new position": two coincident boxes, one moved to partial overlap, fused. The fused volume must be strictly greater than one box (the move took effect in the kernel) and strictly less than both (they still intersect). With a display-only transform the first assertion fails. Serialization stays append-only; recipe version unchanged at 2. Golden fixture regenerated with a GoldenTransform feature carrying distinctive literals so a field reorder shows up as obviously wrong values. Also fills in the Helix arm of feature_type_name(), missing since the helix commit. Kernel suite 51 -> 57 cases, 985 -> 1054 assertions, green. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BVzKmX6Y1aEteit1HTXG4Q
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
017bb08a1d
commit
0100c95ed1
@@ -73,6 +73,8 @@ const char* feature_type_name(CadFeatureType t)
|
||||
case CadFeatureType::Cut: return "Cut";
|
||||
case CadFeatureType::Axis: return "Axis";
|
||||
case CadFeatureType::CoordSys: return "CoordSys";
|
||||
case CadFeatureType::Helix: return "Helix";
|
||||
case CadFeatureType::Transform: return "Transform";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -186,6 +188,21 @@ json describe_tools()
|
||||
json{{"name", "keep_original"},{"type", "boolean"}, {"default", true}, {"description", "when mode=new, keep the source body"}},
|
||||
json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
|
||||
})}},
|
||||
json{{"name", "transform"}, {"summary", "Move and/or rotate a body (B-rep transform). copy=true keeps the source and appends the transformed copy as a new body."},
|
||||
{"params", json::array({
|
||||
json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
|
||||
json{{"name", "dx"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
|
||||
json{{"name", "dy"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
|
||||
json{{"name", "dz"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
|
||||
json{{"name", "axis_x"}, {"type", "number"}, {"default", 0}},
|
||||
json{{"name", "axis_y"}, {"type", "number"}, {"default", 0}},
|
||||
json{{"name", "axis_z"}, {"type", "number"}, {"default", 1}},
|
||||
json{{"name", "pivot_x"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
|
||||
json{{"name", "pivot_y"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
|
||||
json{{"name", "pivot_z"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
|
||||
json{{"name", "angle"}, {"type", "number"}, {"unit", "deg"}, {"default", 0}},
|
||||
json{{"name", "copy"}, {"type", "boolean"}, {"default", false}},
|
||||
})}},
|
||||
json{{"name", "axis"}, {"summary", "Create a datum axis (reference line): two points, face normal, cylinder centreline, plane intersection, or along edge."},
|
||||
{"params", json::array({
|
||||
json{{"name", "type"}, {"type", "string"}, {"enum", json::array({"two_points", "face_normal", "cylinder", "plane_intersection", "along_edge"})}, {"default", "two_points"}},
|
||||
@@ -846,6 +863,24 @@ json action_mirror(DesignPanel* panel, const json& params)
|
||||
return json{{"ok", ok}, {"mirror_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
|
||||
}
|
||||
|
||||
json action_transform(DesignPanel* panel, const json& params)
|
||||
{
|
||||
CadDocument& doc = panel->mcp_doc();
|
||||
if (doc.bodies.empty()) throw std::runtime_error("no body to transform");
|
||||
int bi = target_body_arg(params, doc);
|
||||
Vec3d translate(params.value("dx", 0.0), params.value("dy", 0.0), params.value("dz", 0.0));
|
||||
Vec3d axis(params.value("axis_x", 0.0), params.value("axis_y", 0.0), params.value("axis_z", 1.0));
|
||||
Vec3d pivot(params.value("pivot_x", 0.0), params.value("pivot_y", 0.0), params.value("pivot_z", 0.0));
|
||||
double angle = params.value("angle", 0.0);
|
||||
bool copy = params.value("copy", false);
|
||||
doc.checkpoint();
|
||||
int idx = doc.add_transform(bi, translate, axis, pivot, angle, copy, "Transform");
|
||||
bool ok = doc.recompute();
|
||||
if (!ok) doc.undo();
|
||||
panel->mcp_after_change();
|
||||
return json{{"ok", ok}, {"transform_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
|
||||
}
|
||||
|
||||
json action_axis(DesignPanel* panel, const json& params)
|
||||
{
|
||||
CadDocument& doc = panel->mcp_doc();
|
||||
@@ -944,6 +979,7 @@ std::string handle_on_main(const std::string& method, const json& params, const
|
||||
if (method == "shell") return rpc_result(id, action_shell(panel, params));
|
||||
if (method == "draft") return rpc_result(id, action_draft(panel, params));
|
||||
if (method == "mirror") return rpc_result(id, action_mirror(panel, params));
|
||||
if (method == "transform") return rpc_result(id, action_transform(panel, params));
|
||||
if (method == "axis") return rpc_result(id, action_axis(panel, params));
|
||||
if (method == "coordsys") return rpc_result(id, action_coordsys(panel, params));
|
||||
if (method == "helix") return rpc_result(id, action_helix(panel, params));
|
||||
|
||||
Reference in New Issue
Block a user