OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::GUI::anonymous_namespace{McpControl.cpp} Namespace Reference

Classes

struct  ShapeMetrics

Functions

const char * feature_type_name (CadFeatureType t)
std::string rpc_result (const json &id, const json &result)
std::string rpc_error (const json &id, int code, const std::string &msg)
json describe_tools ()
json describe_scene (DesignPanel *panel)
json vec3 (const Vec3d &v)
SketchPlane plane_from (const json &params, const CadDocument &doc)
BooleanMode bool_from (const std::string &s)
bool profile_from (const json &params, SketchProfile &out)
const TopoDS_Shape & body_shape (DesignPanel *panel, const json &params)
json query_topology (DesignPanel *panel, const json &params)
bool resolve_ref (const TopoDS_Shape &shape, const json &ref, Vec3d &point, Vec3d &dir, bool &has_dir)
json measure (DesignPanel *panel, const json &params)
json mass_properties (DesignPanel *panel, const json &params)
std::vector< std::pair< std::vector< Vec3d >, bool > > chain_segments (std::vector< std::vector< Vec3d > > segs, double tol)
json slice_body (DesignPanel *panel, const json &params)
json import_step (DesignPanel *panel, const json &params)
json import_mesh (DesignPanel *panel, const json &params)
ShapeMetrics shape_metrics (const TopoDS_Shape &s)
json validate_against (DesignPanel *panel, const json &params)
json action_extrude (DesignPanel *panel, const json &params)
json action_revolve (DesignPanel *panel, const json &params)
int target_body_arg (const json &params, const CadDocument &doc)
std::vector< int > edge_ids_arg (const json &params, const char *verb)
json action_fillet (DesignPanel *panel, const json &params)
json action_chamfer (DesignPanel *panel, const json &params)
json action_hole (DesignPanel *panel, const json &params)
json action_hole_styled (DesignPanel *panel, const json &params)
json action_hole_standard (DesignPanel *panel, const json &params)
json action_boolean (DesignPanel *panel, const json &params)
json action_pattern (DesignPanel *panel, const json &params)
json action_pattern_on_curve (DesignPanel *panel, const json &params)
json action_shell (DesignPanel *panel, const json &params)
json action_rib (DesignPanel *panel, const json &params)
json action_surface_extrude (DesignPanel *panel, const json &params)
json action_surface_revolve (DesignPanel *panel, const json &params)
json action_thicken_surface (DesignPanel *panel, const json &params)
json action_surface_offset (DesignPanel *panel, const json &params)
json action_surface_loft (DesignPanel *panel, const json &params)
json action_surface_fill (DesignPanel *panel, const json &params)
json action_draft (DesignPanel *panel, const json &params)
DesignSketchTool & mcp_sketch (DesignPanel *panel)
SketchEntity sketch_entity_from (const json &j)
json sketch_entity_to (const SketchEntity &e, int index)
std::vector< int > sketch_targets (const json &params, DesignSketchTool &t, bool all_if_empty)
json action_sketch_begin (DesignPanel *panel, const json &params)
json action_sketch_commit (DesignPanel *panel, const json &params)
json action_sketch_cancel (DesignPanel *panel, const json &params)
json action_sketch_add (DesignPanel *panel, const json &params)
json action_sketch_select (DesignPanel *panel, const json &params)
json action_sketch_delete (DesignPanel *panel, const json &params)
json action_sketch_construction (DesignPanel *panel, const json &params)
json action_sketch_offset (DesignPanel *panel, const json &params)
json action_sketch_mirror (DesignPanel *panel, const json &params)
json sketch_report (DesignSketchTool &t)
json action_sketch_describe (DesignPanel *panel, const json &params)
json action_sketch_validate (DesignPanel *panel, const json &params)
json action_sketch_heal (DesignPanel *panel, const json &params)
json action_sketch_set_value (DesignPanel *panel, const json &params)
bool verb_is_modal (const char *id)
json action_list_verbs (DesignPanel *panel, const json &params)
json action_run_verb (DesignPanel *panel, const json &params)
json action_mirror (DesignPanel *panel, const json &params)
json action_transform (DesignPanel *panel, const json &params)
json action_thicken (DesignPanel *panel, const json &params)
json action_split (DesignPanel *panel, const json &params)
json action_project (DesignPanel *panel, const json &params)
json action_delete_face (DesignPanel *panel, const json &params)
json action_bridge (DesignPanel *panel, const json &params)
json action_axis (DesignPanel *panel, const json &params)
json action_coordsys (DesignPanel *panel, const json &params)
json action_helix (DesignPanel *panel, const json &params)
json action_mate (DesignPanel *panel, const json &params)
json action_check_interference (DesignPanel *panel, const json &params)
json action_set_variable (DesignPanel *panel, const json &params)
json action_set_feature_expr (DesignPanel *panel, const json &params)
std::string handle_on_main (const std::string &method, const json &params, const json &id)
std::string dispatch_request (const std::string &line)
void serve_client (int cfd)
void remove_socket_at_exit ()
void server_thread (std::string sock_path)

Variables

std::string g_sock_path

Class Documentation

◆ Slic3r::GUI::anonymous_namespace{McpControl.cpp}::ShapeMetrics

struct Slic3r::GUI::anonymous_namespace{McpControl.cpp}::ShapeMetrics
Class Members
Vec3d bmax
Vec3d bmin
Vec3d centroid
double volume

Function Documentation

◆ action_axis()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_axis ( DesignPanel * panel,
const json & params )
1874{
1875 CadDocument& doc = panel->mcp_doc();
1876 std::string t = params.value("type", std::string("two_points"));
1878 if (t == "face_normal") at = AxisType::FaceNormal;
1879 else if (t == "cylinder") at = AxisType::CylinderCenterline;
1880 else if (t == "plane_intersection") at = AxisType::PlaneIntersection;
1881 else if (t == "along_edge") at = AxisType::AlongEdge;
1882 doc.checkpoint();
1883 int idx = doc.add_axis(at, "Axis");
1884 CadFeature& f = doc.features[idx];
1885 if (params.contains("p1") && params["p1"].is_array() && params["p1"].size() >= 3)
1886 f.axis_p1 = Vec3d(params["p1"][0].get<double>(), params["p1"][1].get<double>(), params["p1"][2].get<double>());
1887 if (params.contains("p2") && params["p2"].is_array() && params["p2"].size() >= 3)
1888 f.axis_p2 = Vec3d(params["p2"][0].get<double>(), params["p2"][1].get<double>(), params["p2"][2].get<double>());
1889 f.axis_body = params.value("body", -1);
1890 f.axis_face = params.value("face", -1);
1891 f.axis_edge = params.value("edge", -1);
1892 f.axis_plane_a = params.value("plane_a", -1);
1893 f.axis_plane_b = params.value("plane_b", -1);
1894 // Datum features don't produce a body; check for an error returned by resolve.
1895 bool recompute_ok = doc.recompute();
1896 auto axes = doc.resolve_datum_axes();
1897 std::string err = doc.error;
1898 if (recompute_ok && err.empty() && !axes.empty() && !axes.back().error.empty())
1899 err = axes.back().error;
1900 panel->mcp_after_change();
1901 return json{{"ok", true}, {"axis_index", idx}, {"error", err}};
1902}
Definition CadDocument.hpp:537
std::string error
Definition CadDocument.hpp:558
void checkpoint()
Definition CadDocument.cpp:2048
bool recompute()
Definition CadDocument.cpp:4069
std::vector< DatumAxis > resolve_datum_axes() const
Definition CadDocument.cpp:1818
int add_axis(AxisType axis_type, const std::string &name)
Definition CadDocument.cpp:1462
std::vector< CadFeature > features
Definition CadDocument.hpp:539
void mcp_after_change()
Definition DesignPanel.hpp:87
CadDocument & mcp_doc()
Definition DesignPanel.hpp:86
Eigen::Matrix< double, 3, 1, Eigen::DontAlign > Vec3d
Definition Point.hpp:68
nlohmann::json json
Definition AssembleList.cpp:42
static double f(double x, double z_sin, double z_cos, bool vertical, bool flip)
Definition FillGyroid.cpp:124
AxisType
Definition CadDocument.hpp:29
@ FaceNormal
Definition CadDocument.hpp:29
@ TwoPoints
Definition CadDocument.hpp:29
@ CylinderCenterline
Definition CadDocument.hpp:29
@ PlaneIntersection
Definition CadDocument.hpp:29
@ AlongEdge
Definition CadDocument.hpp:29
Definition CadDocument.hpp:40

References action_axis(), Slic3r::CadDocument::add_axis(), Slic3r::AlongEdge, Slic3r::CadDocument::checkpoint(), Slic3r::CylinderCenterline, Slic3r::CadDocument::error, Slic3r::f(), Slic3r::FaceNormal, Slic3r::CadDocument::features, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::PlaneIntersection, Slic3r::CadDocument::recompute(), Slic3r::CadDocument::resolve_datum_axes(), and Slic3r::TwoPoints.

Referenced by action_axis(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_boolean()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_boolean ( DesignPanel * panel,
const json & params )
997{
998 BooleanMode m = bool_from(params.value("op", std::string("subtract")));
999 if (m == BooleanMode::New) throw std::runtime_error("op must be union | subtract | intersect");
1000 const int target = params.value("target", 0);
1001 const int tool = params.value("tool", 1);
1002 const bool keep = params.value("keep_tool", false);
1003 const double tol = params.value("tolerance", 0.0);
1004 CadDocument& doc = panel->mcp_doc();
1005 int n = int(doc.bodies.size());
1006 if (target < 0 || target >= n || tool < 0 || tool >= n)
1007 throw std::runtime_error("target/tool body index out of range (have " + std::to_string(n) + ")");
1008 if (target == tool) throw std::runtime_error("target and tool must differ");
1009 doc.checkpoint();
1010 int b = doc.add_boolean(m, target, tool, keep, tol, -1, -1, "Boolean");
1011 bool ok = doc.recompute();
1012 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1013 panel->mcp_after_change();
1014 return json{{"ok", ok}, {"boolean_index", b}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1015}
bool undo()
Definition CadDocument.cpp:2062
std::vector< CadBody > bodies
Definition CadDocument.hpp:552
int add_boolean(BooleanMode op, int target_body, int tool_body, bool keep_tool, double tolerance, int target_face, int tool_face, const std::string &name)
Definition CadDocument.cpp:1263
BooleanMode bool_from(const std::string &s)
Definition McpControl.cpp:459
BooleanMode
Definition CadDocument.hpp:31
@ New
Definition CadDocument.hpp:31

References action_boolean(), Slic3r::CadDocument::add_boolean(), Slic3r::CadDocument::bodies, bool_from(), Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::New, Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_boolean(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_bridge()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_bridge ( DesignPanel * panel,
const json & params )
1854{
1855 if (!params.contains("sketch")) throw std::runtime_error("bridge needs 'sketch' (feature index)");
1856 if (!params.contains("ent_a")) throw std::runtime_error("bridge needs 'ent_a' (entity index)");
1857 if (!params.contains("ent_b")) throw std::runtime_error("bridge needs 'ent_b' (entity index)");
1858 int sketch = params["sketch"].get<int>();
1859 int ent_a = params["ent_a"].get<int>();
1860 int ent_b = params["ent_b"].get<int>();
1861 int end_a = params.value("end_a", 1);
1862 int end_b = params.value("end_b", 0);
1863 CadDocument& doc = panel->mcp_doc();
1864 doc.checkpoint();
1865 int ei = doc.add_bridge(sketch, ent_a, end_a, ent_b, end_b, "Bridge");
1866 bool ok = doc.recompute();
1867 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1868 panel->mcp_after_change();
1869 return json{{"ok", ok}, {"sketch_index", sketch}, {"entity_index", ei},
1870 {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1871}
int add_bridge(int sketch_ref, int ent_a, int end_a, int ent_b, int end_b, const std::string &name)
Definition CadDocument.cpp:1433

References action_bridge(), Slic3r::CadDocument::add_bridge(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_bridge(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_chamfer()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_chamfer ( DesignPanel * panel,
const json & params )
910{
911 const std::vector<int> edges = edge_ids_arg(params, "chamfer");
912 const double dist = params.value("distance", 1.0);
913 if (dist <= 0) throw std::runtime_error("distance must be > 0");
914 CadDocument& doc = panel->mcp_doc();
915 if (doc.bodies.empty()) throw std::runtime_error("no body to chamfer");
916 int bi = target_body_arg(params, doc);
917 doc.checkpoint();
918 int c = doc.add_chamfer(dist, edges, "Chamfer");
919 if (bi >= 0) doc.features[c].target_body = bi; // edge id resolved against THIS body's shape
920 bool ok = doc.recompute();
921 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
922 panel->mcp_after_change();
923 return json{{"ok", ok}, {"chamfer_index", c}, {"body", bi < 0 ? int(doc.bodies.size()) - 1 : bi},
924 {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
925}
int add_chamfer(double distance, FaceGroup faces, const std::string &name)
Definition CadDocument.cpp:974
int target_body_arg(const json &params, const CadDocument &doc)
Definition McpControl.cpp:869
std::vector< int > edge_ids_arg(const json &params, const char *verb)
Definition McpControl.cpp:879
T dist(const boost::polygon::point_data< T > &p1, const boost::polygon::point_data< T > &p2)
Definition Geometry.cpp:298

References action_chamfer(), Slic3r::CadDocument::add_chamfer(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::Geometry::dist(), edge_ids_arg(), Slic3r::CadDocument::error, Slic3r::CadDocument::features, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_chamfer(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_check_interference()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_check_interference ( DesignPanel * panel,
const json & params )
1964{
1965 const double min_volume = params.value("min_volume", 1e-6);
1966 CadDocument& doc = panel->mcp_doc();
1967 // Read-only: no checkpoint(), no recompute(), no mcp_after_change().
1968 const auto hits = doc.check_interference(min_volume);
1969 json arr = json::array();
1970 for (const auto& h : hits) {
1971 arr.push_back(json{{"body_a", h.body_a}, {"body_b", h.body_b}, {"volume", h.volume}});
1972 }
1973 return json{{"ok", true}, {"count", int(hits.size())}, {"interferences", arr}};
1974}
std::vector< Interference > check_interference(double min_volume=1e-6) const
Definition CadDocument.cpp:4725

References action_check_interference(), Slic3r::CadDocument::check_interference(), and Slic3r::GUI::DesignPanel::mcp_doc().

Referenced by action_check_interference(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_coordsys()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_coordsys ( DesignPanel * panel,
const json & params )
1905{
1906 CadDocument& doc = panel->mcp_doc();
1907 std::string t = params.value("type", std::string("point_world"));
1909 if (t == "face_and_direction") ct = CoordSysType::FaceAndDirection;
1910 Vec3d pt(0, 0, 0);
1911 if (params.contains("point") && params["point"].is_array() && params["point"].size() >= 3)
1912 pt = Vec3d(params["point"][0].get<double>(), params["point"][1].get<double>(), params["point"][2].get<double>());
1913 doc.checkpoint();
1914 int idx = doc.add_coordsys(ct, pt, "CoordSys");
1915 CadFeature& f = doc.features[idx];
1916 f.coordsys_body = params.value("body", -1);
1917 f.coordsys_face = params.value("face", -1);
1918 f.coordsys_edge = params.value("edge", -1);
1919 if (params.contains("x_hint") && params["x_hint"].is_array() && params["x_hint"].size() >= 3)
1920 f.coordsys_x_hint = Vec3d(params["x_hint"][0].get<double>(), params["x_hint"][1].get<double>(), params["x_hint"][2].get<double>());
1921 bool recompute_ok = doc.recompute();
1922 auto css = doc.resolve_datum_coordsys();
1923 std::string err = doc.error;
1924 if (recompute_ok && err.empty() && !css.empty() && !css.back().error.empty())
1925 err = css.back().error;
1926 panel->mcp_after_change();
1927 return json{{"ok", true}, {"coordsys_index", idx}, {"error", err}};
1928}
int add_coordsys(CoordSysType type, const Vec3d &point, const std::string &name)
Definition CadDocument.cpp:1472
std::vector< DatumCoordSys > resolve_datum_coordsys() const
Definition CadDocument.cpp:2016
CoordSysType
Definition CadDocument.hpp:30
@ PointWorld
Definition CadDocument.hpp:30
@ FaceAndDirection
Definition CadDocument.hpp:30

References action_coordsys(), Slic3r::CadDocument::add_coordsys(), Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::f(), Slic3r::FaceAndDirection, Slic3r::CadDocument::features, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::PointWorld, Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::resolve_datum_coordsys().

Referenced by action_coordsys(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_delete_face()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_delete_face ( DesignPanel * panel,
const json & params )
1837{
1838 if (!params.contains("faces")) throw std::runtime_error("delete_face needs 'faces' (array of face ids)");
1839 CadDocument& doc = panel->mcp_doc();
1840 if (doc.bodies.empty()) throw std::runtime_error("no body to delete faces from");
1841 int bi = target_body_arg(params, doc);
1842 std::vector<int> faces;
1843 if (params["faces"].is_array())
1844 for (const auto& v : params["faces"]) faces.push_back(v.get<int>());
1845 doc.checkpoint();
1846 int idx = doc.add_delete_face(bi, faces, "DeleteFace");
1847 bool ok = doc.recompute();
1848 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1849 panel->mcp_after_change();
1850 return json{{"ok", ok}, {"feature_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1851}
int add_delete_face(int target_body, const std::vector< int > &faces, const std::string &name)
Definition CadDocument.cpp:1239

References action_delete_face(), Slic3r::CadDocument::add_delete_face(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_delete_face(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_draft()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_draft ( DesignPanel * panel,
const json & params )
1179{
1180 if (!params.contains("face")) throw std::runtime_error("draft needs 'face' (id from query_topology)");
1181 const double angle = params.value("angle", 5.0);
1182 CadDocument& doc = panel->mcp_doc();
1183 if (doc.bodies.empty()) throw std::runtime_error("no body to draft");
1184 int bi = target_body_arg(params, doc);
1185 doc.checkpoint();
1186 int d = doc.add_draft(angle, params["face"].get<int>(), bi, "Draft");
1187 bool ok = doc.recompute();
1188 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1189 panel->mcp_after_change();
1190 return json{{"ok", ok}, {"draft_index", d}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1191}
int add_draft(double angle, int face, int target_body, const std::string &name)
Definition CadDocument.cpp:1251
double angle(const Eigen::MatrixBase< Derived > &v1, const Eigen::MatrixBase< Derived2 > &v2)
Definition Point.hpp:138

References action_draft(), Slic3r::CadDocument::add_draft(), Slic3r::angle(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_draft(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_extrude()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_extrude ( DesignPanel * panel,
const json & params )
803{
804 const double d = params.value("distance", 10.0);
805 if (d <= 0) throw std::runtime_error("distance must be > 0");
806 CadDocument& doc = panel->mcp_doc();
807 SketchPlane pl = plane_from(params, doc);
808 BooleanMode mode = bool_from(params.value("boolean", std::string("new")));
809
810 SketchProfile prof;
811 bool has_prof = profile_from(params, prof);
812 double w = 0, h = 0;
813 if (!has_prof) {
814 w = params.value("width", 20.0); h = params.value("height", 20.0);
815 if (w <= 0 || h <= 0) throw std::runtime_error("width and height must be > 0");
816 }
817 doc.checkpoint();
818 int s = has_prof ? doc.add_sketch_profile(prof, pl, "Sketch")
819 : doc.add_sketch(SketchShape::Rectangle, pl, w, h, 0.0, "Sketch");
820 int e = doc.add_extrude(s, d, /*symmetric*/false, mode, "Extrude");
821 // End condition (Onshape parity). apply reads extrude_end directly; the kernel `symmetric`
822 // bool is unused, so set the field here. up_to_face id comes from query_topology on the
823 // target (last) body. taper_deg lofts the side wall; flip negates the direction.
824 const std::string end = params.value("end", std::string("blind"));
825 CadFeature& fe = doc.features[e];
826 fe.flip = params.value("flip", false);
827 fe.taper_deg = params.value("taper", 0.0);
828 if (end == "symmetric") fe.extrude_end = ExtrudeEnd::Symmetric;
829 else if (end == "two_sided") { fe.extrude_end = ExtrudeEnd::TwoSided; fe.distance2 = params.value("distance2", d); }
830 else if (end == "through_all") fe.extrude_end = ExtrudeEnd::ThroughAll;
831 else if (end == "up_to_face") { fe.extrude_end = ExtrudeEnd::UpToFace; fe.up_to_face = params.value("up_to_face", -1); }
833 bool ok = doc.recompute();
834 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
835 panel->mcp_after_change();
836 return json{{"ok", ok}, {"sketch_index", s}, {"extrude_index", e}, {"end", end},
837 {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
838}
int add_sketch_profile(const SketchProfile &profile, const SketchPlane &plane, const std::string &name)
Definition CadDocument.cpp:585
int add_sketch(SketchShape shape, const SketchPlane &plane, double width, double height, double radius, const std::string &name)
Definition CadDocument.cpp:569
int add_extrude(int sketch_ref, double distance, bool symmetric, BooleanMode mode, const std::string &name)
Definition CadDocument.cpp:890
T * end(Slic3r::Mat< N, M, T > &mat)
Definition Point.hpp:841
SketchPlane plane_from(const json &params, const CadDocument &doc)
Definition McpControl.cpp:452
bool profile_from(const json &params, SketchProfile &out)
Definition McpControl.cpp:468
@ Rectangle
Definition CadDocument.hpp:27
@ TwoSided
Definition CadDocument.hpp:33
@ UpToFace
Definition CadDocument.hpp:33
@ ThroughAll
Definition CadDocument.hpp:33
@ Blind
Definition CadDocument.hpp:33
@ Symmetric
Definition CadDocument.hpp:33
bool flip
Definition CadDocument.hpp:105
double taper_deg
Definition CadDocument.hpp:104
int up_to_face
Definition CadDocument.hpp:106
double distance2
Definition CadDocument.hpp:103
ExtrudeEnd extrude_end
Definition CadDocument.hpp:102
Definition SketchEngine.hpp:50
Definition SketchEngine.hpp:71

References action_extrude(), Slic3r::CadDocument::add_extrude(), Slic3r::CadDocument::add_sketch(), Slic3r::CadDocument::add_sketch_profile(), Slic3r::Blind, Slic3r::CadDocument::bodies, bool_from(), Slic3r::CadDocument::checkpoint(), Slic3r::CadFeature::distance2, Slic3r::CadDocument::error, Slic3r::CadFeature::extrude_end, Slic3r::CadDocument::features, Slic3r::CadFeature::flip, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), plane_from(), profile_from(), Slic3r::CadDocument::recompute(), Slic3r::Rectangle, Slic3r::Symmetric, Slic3r::CadFeature::taper_deg, Slic3r::ThroughAll, Slic3r::TwoSided, Slic3r::CadDocument::undo(), Slic3r::CadFeature::up_to_face, and Slic3r::UpToFace.

Referenced by action_extrude(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_fillet()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_fillet ( DesignPanel * panel,
const json & params )
892{
893 const std::vector<int> edges = edge_ids_arg(params, "fillet");
894 const double radius = params.value("radius", 1.0);
895 if (radius <= 0) throw std::runtime_error("radius must be > 0");
896 CadDocument& doc = panel->mcp_doc();
897 if (doc.bodies.empty()) throw std::runtime_error("no body to fillet");
898 int bi = target_body_arg(params, doc);
899 doc.checkpoint();
900 int f = doc.add_fillet(radius, edges, "Fillet");
901 if (bi >= 0) doc.features[f].target_body = bi; // edge id resolved against THIS body's shape
902 bool ok = doc.recompute();
903 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
904 panel->mcp_after_change();
905 return json{{"ok", ok}, {"fillet_index", f}, {"body", bi < 0 ? int(doc.bodies.size()) - 1 : bi},
906 {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
907}
int add_fillet(double radius, FaceGroup faces, const std::string &name)
Definition CadDocument.cpp:939

References action_fillet(), Slic3r::CadDocument::add_fillet(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), edge_ids_arg(), Slic3r::CadDocument::error, Slic3r::f(), Slic3r::CadDocument::features, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_fillet(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_helix()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_helix ( DesignPanel * panel,
const json & params )
1931{
1932 const double radius = params.value("radius", 10.0);
1933 const double pitch = params.value("pitch", 5.0);
1934 const double height = params.value("height", 20.0);
1935 const bool left_handed = params.value("left_handed", false);
1936 const double taper = params.value("taper_deg", 0.0);
1937 CadDocument& doc = panel->mcp_doc();
1938 doc.checkpoint();
1939 int idx = doc.add_helix(plane_from(params, doc), radius, pitch, height, left_handed, taper, "Helix");
1940 panel->mcp_after_change();
1941 return json{{"ok", true}, {"helix_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1942}
int add_helix(const SketchPlane &plane, double radius, double pitch, double height, bool left_handed, double taper_deg, const std::string &name)
Definition CadDocument.cpp:1576

References action_helix(), Slic3r::CadDocument::add_helix(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), and plane_from().

Referenced by action_helix(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_hole()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_hole ( DesignPanel * panel,
const json & params )
928{
929 const double dia = params.value("diameter", 5.0);
930 const double depth = params.value("depth", 10.0);
931 const bool thru = params.value("through", false);
932 const double x = params.value("x", 0.0), y = params.value("y", 0.0);
933 if (dia <= 0) throw std::runtime_error("diameter must be > 0");
934 CadDocument& doc = panel->mcp_doc();
935 if (doc.bodies.empty()) throw std::runtime_error("no body to drill");
936 SketchPlane pl = plane_from(params, doc);
937 doc.checkpoint();
938 int h = doc.add_hole(dia, depth, thru, x, y, pl, "Hole");
939 bool ok = doc.recompute();
940 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
941 panel->mcp_after_change();
942 return json{{"ok", ok}, {"hole_index", h}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
943}
int add_hole(double diameter, double depth, bool through, double x, double y, const SketchPlane &plane, const std::string &name)
Definition CadDocument.cpp:1009

References action_hole(), Slic3r::CadDocument::add_hole(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), plane_from(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_hole(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_hole_standard()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_hole_standard ( DesignPanel * panel,
const json & params )
972{
973 const std::string desig = params.value("designation", std::string(""));
974 if (desig.empty()) throw std::runtime_error("designation is required");
975 const int style = params.value("style", 0);
976 const bool thru = params.value("through", true);
977 const double depth = params.value("depth", 10.0);
978 const double x = params.value("x", 0.0), y = params.value("y", 0.0);
979 CadDocument& doc = panel->mcp_doc();
980 if (doc.bodies.empty()) throw std::runtime_error("no body to drill");
981 SketchPlane pl = plane_from(params, doc);
982 doc.checkpoint();
983 try {
984 int h = doc.add_hole_standard(desig, style, thru, depth, x, y, pl, "Hole");
985 bool ok = doc.recompute();
986 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
987 panel->mcp_after_change();
988 return json{{"ok", ok}, {"hole_index", h}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
989 } catch (const std::exception& ex) {
990 doc.undo();
991 panel->mcp_after_change();
992 return json{{"ok", false}, {"error", ex.what()}};
993 }
994}
#define style
Definition WipeTowerDialog.cpp:101
int add_hole_standard(const std::string &designation, int style, bool through, double depth, double x, double y, const SketchPlane &plane, const std::string &name)
Definition CadDocument.cpp:1085

References action_hole_standard(), Slic3r::CadDocument::add_hole_standard(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), plane_from(), Slic3r::CadDocument::recompute(), style, and Slic3r::CadDocument::undo().

Referenced by action_hole_standard(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_hole_styled()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_hole_styled ( DesignPanel * panel,
const json & params )
946{
947 const double dia = params.value("diameter", 5.0);
948 const double depth = params.value("depth", 10.0);
949 const bool thru = params.value("through", true);
950 const double x = params.value("x", 0.0), y = params.value("y", 0.0);
951 const int style = params.value("style", 0);
952 const double cbore_diameter = params.value("cbore_diameter", 0.0);
953 const double cbore_depth = params.value("cbore_depth", 0.0);
954 const double csink_diameter = params.value("csink_diameter", 0.0);
955 const double csink_angle = params.value("csink_angle", 90.0);
956 const std::string standard = params.value("standard", std::string(""));
957 if (dia <= 0) throw std::runtime_error("diameter must be > 0");
958 CadDocument& doc = panel->mcp_doc();
959 if (doc.bodies.empty()) throw std::runtime_error("no body to drill");
960 SketchPlane pl = plane_from(params, doc);
961 doc.checkpoint();
962 int h = doc.add_hole_styled(dia, depth, thru, x, y, pl, style,
963 cbore_diameter, cbore_depth,
964 csink_diameter, csink_angle, standard, "Hole");
965 bool ok = doc.recompute();
966 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
967 panel->mcp_after_change();
968 return json{{"ok", ok}, {"hole_index", h}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
969}
int add_hole_styled(double diameter, double depth, bool through, double x, double y, const SketchPlane &plane, int style, double cbore_diameter, double cbore_depth, double csink_diameter, double csink_angle, const std::string &standard, const std::string &name)
Definition CadDocument.cpp:1060

References action_hole_styled(), Slic3r::CadDocument::add_hole_styled(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), plane_from(), Slic3r::CadDocument::recompute(), style, and Slic3r::CadDocument::undo().

Referenced by action_hole_styled(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_list_verbs()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_list_verbs ( DesignPanel * panel,
const json & params )
1660{
1661 const int kind = panel->mcp_offer_selection_kind();
1662 const uint32_t bit = offer_bit(OfferSel(kind));
1663 const bool applicable_only = params.value("applicable_only", false);
1664 const bool has_sketch_mode = params.contains("sketch_mode");
1665 const bool want_sketch_mode = has_sketch_mode && params["sketch_mode"].get<bool>();
1666
1667 json verbs = json::array();
1668 for (int i = 0; i < kOfferVerbCount; ++i) {
1669 const OfferVerb& v = kOfferVerbs[i];
1670 const bool applies = (v.accepts & bit) != 0;
1671 if (applicable_only && !applies) continue;
1672 if (has_sketch_mode && v.sketch_mode != want_sketch_mode) continue;
1673 // Verbs whose action is nullptr exist in the vocabulary but have no GUI path yet — report
1674 // them with a null action rather than dropping them.
1675 verbs.push_back(json{
1676 {"id", v.id},
1677 {"name", v.name},
1678 {"row", v.row},
1679 {"row_name", kOfferRowNames[v.row]},
1680 {"key", v.key ? json(v.key) : json(nullptr)},
1681 {"action", v.action ? json(v.action) : json(nullptr)},
1682 {"sketch_mode", v.sketch_mode},
1683 {"applies", applies},
1684 {"modal", verb_is_modal(v.id)}, // opening a dialog: this key will want a mouse
1685 {"hint", v.hint ? json(v.hint) : json(nullptr)},
1686 });
1687 }
1688 return json{{"ok", true}, {"selection_kind", kind}, {"count", verbs.size()},
1689 {"verbs", std::move(verbs)}};
1690}
int mcp_offer_selection_kind() const
Definition DesignPanel.hpp:104
bool verb_is_modal(const char *id)
Definition McpControl.cpp:1647
int row
Definition DesignOffer.hpp:59
bool sketch_mode
Definition DesignOffer.hpp:67
static const char *const kOfferRowNames[]
Definition DesignOffer.hpp:78
uint32_t offer_bit(OfferSel s)
Definition DesignOffer.hpp:48
const char * name
Definition DesignOffer.hpp:58
const char * id
Definition DesignOffer.hpp:57
static const int kOfferVerbCount
Definition DesignOffer.hpp:208
uint32_t accepts
Definition DesignOffer.hpp:63
OfferSel
Definition DesignOffer.hpp:24
static const OfferVerb kOfferVerbs[]
Definition DesignOffer.hpp:104
const char * key
Definition DesignOffer.hpp:60
const char * action
Definition DesignOffer.hpp:61
const char * hint
Definition DesignOffer.hpp:74
Definition DesignOffer.hpp:56

References Slic3r::GUI::OfferVerb::accepts, Slic3r::GUI::OfferVerb::action, action_list_verbs(), Slic3r::GUI::OfferVerb::hint, Slic3r::GUI::OfferVerb::id, Slic3r::GUI::OfferVerb::key, Slic3r::GUI::kOfferRowNames, Slic3r::GUI::kOfferVerbCount, Slic3r::GUI::kOfferVerbs, Slic3r::GUI::DesignPanel::mcp_offer_selection_kind(), Slic3r::GUI::OfferVerb::name, Slic3r::GUI::offer_bit(), Slic3r::GUI::OfferVerb::row, Slic3r::GUI::OfferVerb::sketch_mode, and verb_is_modal().

Referenced by action_list_verbs(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_mate()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_mate ( DesignPanel * panel,
const json & params )
1945{
1946 if (!params.contains("cs_a")) throw std::runtime_error("mate needs 'cs_a' (CoordSys feature index)");
1947 if (!params.contains("cs_b")) throw std::runtime_error("mate needs 'cs_b' (CoordSys feature index)");
1948 const int kind = params.value("kind", 0);
1949 const int cs_a = params["cs_a"].get<int>();
1950 const int cs_b = params["cs_b"].get<int>();
1951 const double offset = params.value("offset", 0.0);
1952 const double angle = params.value("angle", 0.0);
1953 const bool flip = params.value("flip", false);
1954 CadDocument& doc = panel->mcp_doc();
1955 doc.checkpoint();
1956 int idx = doc.add_mate(kind, cs_a, cs_b, offset, angle, flip, "Mate");
1957 bool ok = doc.recompute();
1958 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1959 panel->mcp_after_change();
1960 return json{{"ok", ok}, {"mate_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1961}
int add_mate(int kind, int cs_a, int cs_b, double offset, double angle_deg, bool flip, const std::string &name)
Definition CadDocument.cpp:1483
Slic3r::Polygons offset(const Slic3r::Polygon &polygon, const float delta, JoinType joinType, double miterLimit)
Definition ClipperUtils.cpp:582

References action_mate(), Slic3r::CadDocument::add_mate(), Slic3r::angle(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::offset(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_mate(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_mirror()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_mirror ( DesignPanel * panel,
const json & params )
1749{
1750 std::string m_str = params.value("mode", std::string("new"));
1751 BooleanMode m = (m_str == "add") ? BooleanMode::Add : BooleanMode::New;
1752 CadDocument& doc = panel->mcp_doc();
1753 if (doc.bodies.empty()) throw std::runtime_error("no body to mirror");
1754 int bi = target_body_arg(params, doc);
1755 bool keep = params.value("keep_original", true);
1756 doc.checkpoint();
1757 int idx = doc.add_mirror(plane_from(params, doc), bi, m, "Mirror");
1758 doc.features[idx].mirror_keep_original = keep;
1759 bool ok = doc.recompute();
1760 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1761 panel->mcp_after_change();
1762 return json{{"ok", ok}, {"mirror_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1763}
int add_mirror(const SketchPlane &plane, int target_body, BooleanMode mode, const std::string &name)
Definition CadDocument.cpp:1313
@ Add
Definition CadDocument.hpp:31

References action_mirror(), Slic3r::Add, Slic3r::CadDocument::add_mirror(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::CadDocument::features, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::New, plane_from(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_mirror(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_pattern()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_pattern ( DesignPanel * panel,
const json & params )
1018{
1019 const bool circular = params.value("circular", false);
1020 const int count = params.value("count", 3);
1021 const double spacing = params.value("spacing", 10.0); // linear step (mm)
1022 const int dir = params.value("dir", 0); // 0 = plane X, 1 = plane Y
1023 const double angle = params.value("angle", 360.0); // circular total sweep (deg)
1024 if (count < 1) throw std::runtime_error("count must be >= 1");
1025 CadDocument& doc = panel->mcp_doc();
1026 if (doc.bodies.empty()) throw std::runtime_error("no body to pattern");
1027 int bi = target_body_arg(params, doc);
1028 doc.checkpoint();
1029 int p = doc.add_pattern(circular, count, spacing, dir, angle, bi, "Pattern");
1030 doc.features[p].plane = plane_from(params, doc); // axis (circular) / step dirs (linear)
1031 bool ok = doc.recompute();
1032 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1033 panel->mcp_after_change();
1034 return json{{"ok", ok}, {"pattern_index", p}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1035}
static unsigned int count
Definition AuxiliaryDataViewModel.cpp:246
int add_pattern(bool circular, int count, double spacing, int dir, double angle_deg, int target_body, const std::string &name)
Definition CadDocument.cpp:1175

References action_pattern(), Slic3r::CadDocument::add_pattern(), Slic3r::angle(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), count, Slic3r::CadDocument::error, Slic3r::CadDocument::features, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), plane_from(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_pattern(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_pattern_on_curve()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_pattern_on_curve ( DesignPanel * panel,
const json & params )
1038{
1039 const int count = params.value("count", 3);
1040 if (count < 1) throw std::runtime_error("count must be >= 1");
1041 if (!params.contains("sketch")) throw std::runtime_error("pattern_on_curve needs 'sketch' (feature index)");
1042 if (!params.contains("entity")) throw std::runtime_error("pattern_on_curve needs 'entity' (entity index)");
1043 const int sketch = params["sketch"].get<int>();
1044 const int entity = params["entity"].get<int>();
1045 CadDocument& doc = panel->mcp_doc();
1046 if (doc.bodies.empty()) throw std::runtime_error("no body to pattern");
1047 int bi = target_body_arg(params, doc);
1048 doc.checkpoint();
1049 int p = doc.add_pattern_on_curve(count, sketch, entity, bi, "PatternOnCurve");
1050 bool ok = doc.recompute();
1051 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1052 panel->mcp_after_change();
1053 return json{{"ok", ok}, {"pattern_index", p}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1054}

References action_pattern_on_curve(), count, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), and target_body_arg().

Referenced by action_pattern_on_curve(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_project()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_project ( DesignPanel * panel,
const json & params )
1819{
1820 CadDocument& doc = panel->mcp_doc();
1821 if (doc.bodies.empty()) throw std::runtime_error("no source body to project from");
1822 int source_body = params.value("source_body", -1);
1823 int face = params.value("face", -1);
1824 std::vector<int> edges;
1825 if (params.contains("edges") && params["edges"].is_array())
1826 for (const auto& v : params["edges"]) edges.push_back(v.get<int>());
1827 SketchPlane pl = plane_from(params, doc);
1828 doc.checkpoint();
1829 int idx = doc.add_project_edges(source_body, edges, face, pl, "Project");
1830 bool ok = doc.recompute();
1831 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1832 panel->mcp_after_change();
1833 return json{{"ok", ok}, {"project_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1834}
int add_project_edges(int source_body, const std::vector< int > &edge_ids, int face, const SketchPlane &plane, const std::string &name)
Definition CadDocument.cpp:1388

References action_project(), Slic3r::CadDocument::add_project_edges(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), plane_from(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_project(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_revolve()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_revolve ( DesignPanel * panel,
const json & params )
841{
842 const double angle = params.value("angle", 360.0);
843 const int axis = params.value("axis", 0); // 0 = plane X, 1 = plane Y
844 const bool flip = params.value("flip", false);
845 CadDocument& doc = panel->mcp_doc();
846 SketchPlane pl = plane_from(params, doc);
847 BooleanMode mode = bool_from(params.value("boolean", std::string("new")));
848
849 SketchProfile prof;
850 bool has_prof = profile_from(params, prof);
851 double w = 0, h = 0;
852 if (!has_prof) { // ponytail: rectangle centred on the axis may self-overlap; offset via `profile`
853 w = params.value("width", 20.0); h = params.value("height", 10.0);
854 if (w <= 0 || h <= 0) throw std::runtime_error("width and height must be > 0");
855 }
856 doc.checkpoint();
857 int s = has_prof ? doc.add_sketch_profile(prof, pl, "Sketch")
858 : doc.add_sketch(SketchShape::Rectangle, pl, w, h, 0.0, "Sketch");
859 int r = doc.add_revolve(s, angle, axis, flip, mode, "Revolve");
860 bool ok = doc.recompute();
861 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
862 panel->mcp_after_change();
863 return json{{"ok", ok}, {"sketch_index", s}, {"revolve_index", r},
864 {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
865}
int add_revolve(int sketch_ref, double angle, int axis, bool flip, BooleanMode mode, const std::string &name)
Definition CadDocument.cpp:1116

References action_revolve(), Slic3r::CadDocument::add_revolve(), Slic3r::CadDocument::add_sketch(), Slic3r::CadDocument::add_sketch_profile(), Slic3r::angle(), Slic3r::CadDocument::bodies, bool_from(), Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), plane_from(), profile_from(), Slic3r::CadDocument::recompute(), Slic3r::Rectangle, and Slic3r::CadDocument::undo().

Referenced by action_revolve(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_rib()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_rib ( DesignPanel * panel,
const json & params )
1073{
1074 if (!params.contains("sketch")) throw std::runtime_error("rib needs 'sketch' (feature index)");
1075 if (!params.contains("entity")) throw std::runtime_error("rib needs 'entity' (entity index)");
1076 CadDocument& doc = panel->mcp_doc();
1077 if (doc.bodies.empty()) throw std::runtime_error("no body to rib");
1078 int sketch = params["sketch"].get<int>();
1079 int entity = params["entity"].get<int>();
1080 double thickness = params.value("thickness", 2.0);
1081 double depth = params.value("depth", 10.0);
1082 int bi = target_body_arg(params, doc);
1083 doc.checkpoint();
1084 int idx = doc.add_rib(sketch, entity, thickness, depth, bi, "Rib");
1085 bool ok = doc.recompute();
1086 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1087 panel->mcp_after_change();
1088 return json{{"ok", ok}, {"rib_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1089}
int add_rib(int sketch_ref, int entity, double thickness, double depth, int target_body, const std::string &name)
Definition CadDocument.cpp:1224

References action_rib(), Slic3r::CadDocument::add_rib(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_rib(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_run_verb()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_run_verb ( DesignPanel * panel,
const json & params )
1693{
1694 if (!params.contains("verb")) throw std::runtime_error("run_verb needs 'verb' (an offer verb id)");
1695 const std::string verb = params["verb"].get<std::string>();
1696
1697 // Scan the offer table BEFORE dispatching so the failure message can tell an unknown id from
1698 // one that exists in the vocabulary but has no GUI path (action == nullptr).
1699 bool known = false;
1700 bool has_action = false;
1701 const char* action = nullptr;
1702 for (int i = 0; i < kOfferVerbCount; ++i) {
1703 if (std::strcmp(kOfferVerbs[i].id, verb.c_str()) == 0) {
1704 known = true;
1705 has_action = (kOfferVerbs[i].action != nullptr);
1706 action = kOfferVerbs[i].action;
1707 break;
1708 }
1709 }
1710
1711 if (!known) throw std::runtime_error("run_verb: unknown verb '" + verb + "'");
1712 if (!has_action) throw std::runtime_error("run_verb: '" + verb + "' has no GUI path yet");
1713
1714 // Whether the verb would be OFFERED for the current selection. Not a refusal: the GUI lets
1715 // you press a tool's shortcut whatever is selected, and refusing here would make the socket
1716 // stricter than the keyboard for no reason. Reported so a caller can tell "did nothing
1717 // because it did not apply" from "did nothing because it is broken".
1718 const int kind = panel->mcp_offer_selection_kind();
1719 const uint32_t bit = offer_bit(OfferSel(kind));
1720 bool applies = false;
1721 for (int i = 0; i < kOfferVerbCount; ++i)
1722 if (std::strcmp(kOfferVerbs[i].id, verb.c_str()) == 0) { applies = (kOfferVerbs[i].accepts & bit) != 0; break; }
1723
1724 // The rule is not "validate more", it is "the socket should offer exactly what the GUI
1725 // offers, no more and no less". A "btn:"/"fly:" verb is reachable in the GUI ONLY through
1726 // the offer menu, which GREYS its row when it does not apply to the current selection — so
1727 // a socket caller must not be able to fire it either. But a "key:" verb is reachable from
1728 // the KEYBOARD whatever is selected, and the app permits that, so refusing it would make
1729 // the socket stricter than the keyboard for no reason. Refuse only the menu-only verbs.
1730 if (!applies && action &&
1731 (std::strncmp(action, "btn:", 4) == 0 || std::strncmp(action, "fly:", 4) == 0)) {
1732 throw std::runtime_error("run_verb: '" + verb +
1733 "' does not apply to the current selection (selection_kind " +
1734 std::to_string(kind) + ")");
1735 }
1736
1737 // Dispatch on the NEXT turn of the event loop, never inline. See verb_is_modal above: a verb
1738 // that opens a dialog would otherwise block the thread this call is running on. Deferring
1739 // costs the ability to report the verb's outcome — which run_offer_action never returned
1740 // anyway — and buys a socket that cannot be wedged by any verb in the table.
1741 wxGetApp().CallAfter([panel, verb]() { panel->mcp_run_verb(verb.c_str()); });
1742
1743 return json{{"ok", true}, {"verb", verb}, {"dispatched", true},
1744 {"applies", applies}, {"modal", verb_is_modal(verb.c_str())},
1745 {"selection_kind", kind}};
1746}
bool mcp_run_verb(const char *verb_id)
Definition DesignPanel.cpp:6327

References action_run_verb(), Slic3r::GUI::kOfferVerbCount, Slic3r::GUI::kOfferVerbs, Slic3r::GUI::DesignPanel::mcp_offer_selection_kind(), Slic3r::GUI::DesignPanel::mcp_run_verb(), Slic3r::GUI::offer_bit(), and verb_is_modal().

Referenced by action_run_verb(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_set_feature_expr()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_set_feature_expr ( DesignPanel * panel,
const json & params )
1995{
1996 if (!params.contains("feature")) throw std::runtime_error("set_feature_expr needs 'feature' index");
1997 if (!params.contains("field")) throw std::runtime_error("set_feature_expr needs 'field' name");
1998 if (!params.contains("expr")) throw std::runtime_error("set_feature_expr needs 'expr' string");
1999 CadDocument& doc = panel->mcp_doc();
2000 int fi = params["feature"].get<int>();
2001 if (fi < 0 || fi >= (int)doc.features.size())
2002 return json{{"ok", false}, {"error", "feature index out of range"}};
2003 std::string field = params["field"].get<std::string>();
2004 std::string expr = params["expr"].get<std::string>();
2005 std::string old = doc.features[fi].expr.count(field) ? doc.features[fi].expr[field] : "";
2006 doc.checkpoint();
2007 doc.features[fi].expr[field] = expr;
2008 bool ok = doc.recompute();
2009 // undo() recomputes, which succeeds and clears doc.error; carry the reason across so
2010 // the JSON reply below reports why the edit was rejected instead of an empty string.
2011 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
2012 panel->mcp_after_change();
2013 return json{{"ok", ok}, {"feature", fi}, {"field", field}, {"error", doc.error}};
2014}

References action_set_feature_expr(), Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::CadDocument::features, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_set_feature_expr(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_set_variable()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_set_variable ( DesignPanel * panel,
const json & params )
1977{
1978 if (!params.contains("name")) throw std::runtime_error("set_variable needs 'name'");
1979 if (!params.contains("expr")) throw std::runtime_error("set_variable needs 'expr'");
1980 CadDocument& doc = panel->mcp_doc();
1981 std::string name = params["name"].get<std::string>();
1982 std::string expr = params["expr"].get<std::string>();
1983 std::string old = doc.variables.count(name) ? doc.variables[name] : "";
1984 doc.checkpoint();
1985 doc.variables[name] = expr;
1986 bool ok = doc.recompute();
1987 // undo() recomputes, which succeeds and clears doc.error; carry the reason across so
1988 // the JSON reply below reports why the edit was rejected instead of an empty string.
1989 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1990 panel->mcp_after_change();
1991 return json{{"ok", ok}, {"name", name}, {"error", doc.error}};
1992}
std::map< std::string, std::string > variables
Definition CadDocument.hpp:542

References action_set_variable(), Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), Slic3r::CadDocument::undo(), and Slic3r::CadDocument::variables.

Referenced by action_set_variable(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_shell()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_shell ( DesignPanel * panel,
const json & params )
1057{
1058 const double thickness = params.value("thickness", 1.0);
1059 if (thickness <= 0) throw std::runtime_error("thickness must be > 0");
1060 const int face = params.value("face", -1); // face id to leave open (-1 = closed hollow)
1061 CadDocument& doc = panel->mcp_doc();
1062 if (doc.bodies.empty()) throw std::runtime_error("no body to shell");
1063 int bi = target_body_arg(params, doc);
1064 doc.checkpoint();
1065 int s = doc.add_shell(thickness, face, bi, "Shell");
1066 bool ok = doc.recompute();
1067 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1068 panel->mcp_after_change();
1069 return json{{"ok", ok}, {"shell_index", s}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1070}
int add_shell(double thickness, int face, int target_body, const std::string &name)
Definition CadDocument.cpp:1212

References action_shell(), Slic3r::CadDocument::add_shell(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_shell(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_add()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_add ( DesignPanel * panel,
const json & params )
1395{
1396 DesignSketchTool& t = mcp_sketch(panel);
1397 std::vector<SketchEntity> ents;
1398 if (params.contains("entities")) {
1399 for (const auto& j : params.at("entities")) ents.push_back(sketch_entity_from(j));
1400 } else if (params.contains("type")) {
1401 ents.push_back(sketch_entity_from(params)); // single-entity shorthand
1402 } else if (params.contains("rect")) {
1403 // Corner rectangle as four shared-endpoint lines, so it arrives as ONE closed loop
1404 // rather than four segments that happen to touch.
1405 const json& r = params.at("rect");
1406 if (!r.is_array() || r.size() < 4) throw std::runtime_error("rect must be [x0, y0, x1, y1]");
1407 const double x0 = r[0].get<double>(), y0 = r[1].get<double>();
1408 const double x1 = r[2].get<double>(), y1 = r[3].get<double>();
1409 const bool c = params.value("construction", false);
1410 auto seg = [&](Vec2d a, Vec2d b) { SketchEntity e; e.type = SketchEntity::Type::Line;
1411 e.p0 = a; e.p1 = b; e.construction = c; return e; };
1412 ents.push_back(seg({x0, y0}, {x1, y0}));
1413 ents.push_back(seg({x1, y0}, {x1, y1}));
1414 ents.push_back(seg({x1, y1}, {x0, y1}));
1415 ents.push_back(seg({x0, y1}, {x0, y0}));
1416 } else {
1417 throw std::runtime_error("sketch_add needs 'entities', a single 'type', or 'rect'");
1418 }
1419 const int base = t.add_entities_scripted(ents);
1420 panel->mcp_viewport()->request_repaint();
1421 return json{{"ok", base >= 0}, {"first_index", base}, {"added", int(ents.size())},
1422 {"entities", int(t.entities().size())}, {"dof", t.dof()}};
1423}
void request_repaint()
Definition DesignCanvas.cpp:281
DesignCanvas * mcp_viewport()
Definition DesignPanel.hpp:88
Definition DesignSketchTool.hpp:89
int add_entities_scripted(const std::vector< SketchEntity > &ents)
Definition DesignSketchTool.cpp:10440
int dof() const
Definition DesignSketchTool.hpp:580
const std::vector< SketchEntity > & entities() const
Definition DesignSketchTool.hpp:578
DesignSketchTool & mcp_sketch(DesignPanel *panel)
Definition McpControl.cpp:1215
SketchEntity sketch_entity_from(const json &j)
Definition McpControl.cpp:1224
Eigen::Matrix< double, 2, 1, Eigen::DontAlign > Vec2d
Definition Point.hpp:67
Definition SketchEngine.hpp:30
Vec2d p0
Definition SketchEngine.hpp:33
@ Line
Definition SketchEngine.hpp:31
Type type
Definition SketchEngine.hpp:32
bool construction
Definition SketchEngine.hpp:39
Vec2d p1
Definition SketchEngine.hpp:34

References action_sketch_add(), Slic3r::GUI::DesignSketchTool::add_entities_scripted(), Slic3r::SketchEntity::construction, Slic3r::GUI::DesignSketchTool::dof(), Slic3r::GUI::DesignSketchTool::entities(), Slic3r::SketchEntity::Line, mcp_sketch(), Slic3r::GUI::DesignPanel::mcp_viewport(), Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::GUI::DesignCanvas::request_repaint(), sketch_entity_from(), and Slic3r::SketchEntity::type.

Referenced by action_sketch_add(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_begin()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_begin ( DesignPanel * panel,
const json & params )
1355{
1356 DesignCanvas* vp = panel->mcp_viewport();
1357 if (vp == nullptr) throw std::runtime_error("no viewport");
1358 if (vp->is_sketching()) throw std::runtime_error("a sketch is already open");
1359 const std::string pl = params.value("plane", std::string("XY"));
1360 SketchPlane plane = SketchPlane::XY();
1361 if (pl == "XZ") plane = SketchPlane::XZ();
1362 else if (pl == "YZ") plane = SketchPlane::YZ();
1363 else if (pl != "XY") throw std::runtime_error("plane must be XY, XZ or YZ");
1365 // The panel has to enter sketch mode too, or the app is half in it: the tool sketches, the
1366 // offer menu offers sketch verbs, and every sketch KEY is dead because key dispatch tests
1367 // m_ui_mode while the menu tests the viewport. Driving the socket must leave the GUI in the
1368 // state a user would be in, not a state only the socket can produce.
1369 panel->mcp_set_sketch_mode(true);
1370 return json{{"ok", true}, {"plane", pl}};
1371}
Definition DesignCanvas.hpp:46
void begin_sketch(const SketchPlane &plane, DesignSketchTool::Mode mode)
Definition DesignCanvas.cpp:496
bool is_sketching() const
Definition DesignCanvas.cpp:603
void mcp_set_sketch_mode(bool on)
Definition DesignPanel.hpp:95
@ Select
Definition DesignSketchTool.hpp:91
static SketchPlane XY()
Definition SketchEngine.hpp:57
static SketchPlane YZ()
Definition SketchEngine.hpp:62
static SketchPlane XZ()
Definition SketchEngine.hpp:61

References action_sketch_begin(), Slic3r::GUI::DesignCanvas::begin_sketch(), Slic3r::GUI::DesignCanvas::is_sketching(), Slic3r::GUI::DesignPanel::mcp_set_sketch_mode(), Slic3r::GUI::DesignPanel::mcp_viewport(), Slic3r::GUI::DesignSketchTool::Select, Slic3r::SketchPlane::XY(), Slic3r::SketchPlane::XZ(), and Slic3r::SketchPlane::YZ().

Referenced by action_sketch_begin(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_cancel()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_cancel ( DesignPanel * panel,
const json & params )
1385{
1386 (void)params;
1387 DesignCanvas* vp = panel->mcp_viewport();
1388 if (vp == nullptr || !vp->is_sketching()) throw std::runtime_error("no sketch is open");
1389 vp->cancel_sketch();
1390 panel->mcp_set_sketch_mode(false);
1391 return json{{"ok", true}};
1392}
void cancel_sketch()
Definition DesignCanvas.cpp:605

References action_sketch_cancel(), Slic3r::GUI::DesignCanvas::cancel_sketch(), Slic3r::GUI::DesignCanvas::is_sketching(), Slic3r::GUI::DesignPanel::mcp_set_sketch_mode(), and Slic3r::GUI::DesignPanel::mcp_viewport().

Referenced by action_sketch_cancel(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_commit()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_commit ( DesignPanel * panel,
const json & params )
1374{
1375 (void)params;
1376 DesignCanvas* vp = panel->mcp_viewport();
1377 if (vp == nullptr || !vp->is_sketching()) throw std::runtime_error("no sketch is open");
1378 vp->finish_sketch();
1379 panel->mcp_set_sketch_mode(false);
1380 panel->mcp_after_change();
1381 return json{{"ok", true}, {"features", int(panel->mcp_doc().features.size())}};
1382}
void finish_sketch()
Definition DesignCanvas.cpp:556

References action_sketch_commit(), Slic3r::CadDocument::features, Slic3r::GUI::DesignCanvas::finish_sketch(), Slic3r::GUI::DesignCanvas::is_sketching(), Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::GUI::DesignPanel::mcp_set_sketch_mode(), and Slic3r::GUI::DesignPanel::mcp_viewport().

Referenced by action_sketch_commit(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_construction()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_construction ( DesignPanel * panel,
const json & params )
1450{
1451 DesignSketchTool& t = mcp_sketch(panel);
1452 const std::vector<int> tgt = sketch_targets(params, t, false);
1453 if (tgt.empty()) throw std::runtime_error("nothing selected and no 'entities' given");
1454 t.select_indices(tgt);
1455 const int n = t.toggle_selection_construction();
1456 panel->mcp_viewport()->request_repaint();
1457 return json{{"ok", n > 0}, {"changed", n}};
1458}
bool select_indices(const std::vector< int > &idx)
Definition DesignSketchTool.cpp:10479
int toggle_selection_construction()
Definition DesignSketchTool.cpp:612
std::vector< int > sketch_targets(const json &params, DesignSketchTool &t, bool all_if_empty)
Definition McpControl.cpp:1341

References action_sketch_construction(), mcp_sketch(), Slic3r::GUI::DesignPanel::mcp_viewport(), Slic3r::GUI::DesignCanvas::request_repaint(), Slic3r::GUI::DesignSketchTool::select_indices(), sketch_targets(), and Slic3r::GUI::DesignSketchTool::toggle_selection_construction().

Referenced by action_sketch_construction(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_delete()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_delete ( DesignPanel * panel,
const json & params )
1437{
1438 DesignSketchTool& t = mcp_sketch(panel);
1439 const std::vector<int> tgt = sketch_targets(params, t, false);
1440 if (tgt.empty()) throw std::runtime_error("nothing selected and no 'entities' given");
1441 const int before = int(t.entities().size());
1442 t.select_indices(tgt);
1443 t.delete_selected();
1444 panel->mcp_viewport()->request_repaint();
1445 return json{{"ok", true}, {"removed", before - int(t.entities().size())},
1446 {"entities", int(t.entities().size())}};
1447}
void delete_selected()
Definition DesignSketchTool.cpp:515

References action_sketch_delete(), Slic3r::GUI::DesignSketchTool::delete_selected(), Slic3r::GUI::DesignSketchTool::entities(), mcp_sketch(), Slic3r::GUI::DesignPanel::mcp_viewport(), Slic3r::GUI::DesignCanvas::request_repaint(), Slic3r::GUI::DesignSketchTool::select_indices(), and sketch_targets().

Referenced by action_sketch_delete(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_describe()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_describe ( DesignPanel * panel,
const json & params )
1520{
1521 (void)params;
1522 DesignSketchTool& t = mcp_sketch(panel);
1523 json ents = json::array();
1524 for (int i = 0; i < int(t.entities().size()); ++i)
1525 ents.push_back(sketch_entity_to(t.entities()[i], i));
1526 // The armed TOOL and its pending anchors. Without these the only way to tell which tool a
1527 // menu row actually armed is to draw with it and infer from what came out — which is how a
1528 // menu walk that lands one row off gets diagnosed as "the tool is broken".
1529 static const char* const kModeNames[] = {
1530 "select", "dimension", "polyline", "line", "rect_corner", "rect_center", "rect_oblique",
1531 "rect_rounded", "circle_center", "circle_2pt", "point",
1532 "circle_3pt", "arc_3pt", "arc_tangent", "arc_center", "slot", "slot_arc", "polygon",
1533 "ellipse", "ellipse_arc", "spline",
1534 "fillet", "chamfer", "offset", "mirror",
1535 "trim", "extend",
1536 "move", "rotate", "scale", "array", "array_polar",
1537 "transform_art",
1538 "constrain" };
1539 const int mi = int(t.mode());
1540 json out{{"ok", true},
1541 {"entities", ents},
1542 {"constraints", int(t.constraints().size())},
1543 {"dof", t.dof()},
1544 {"solve_ok", t.solve_ok()},
1545 {"tool", (mi >= 0 && mi < int(sizeof(kModeNames) / sizeof(kModeNames[0])))
1546 ? kModeNames[mi] : "unknown"},
1547 {"pending", t.pending_points()},
1548 {"editing", t.value_field_open()},
1549 {"selection", t.selection()}};
1550 out.update(sketch_report(t));
1551 return out;
1552}
bool solve_ok() const
Definition DesignSketchTool.hpp:581
bool value_field_open() const
Definition DesignSketchTool.hpp:123
int pending_points() const
Definition DesignSketchTool.hpp:108
const std::vector< SketchEntityConstraintDef > & constraints() const
Definition DesignSketchTool.hpp:710
const std::vector< int > & selection() const
Definition DesignSketchTool.hpp:552
Mode mode() const
Definition DesignSketchTool.hpp:107
json sketch_report(DesignSketchTool &t)
Definition McpControl.cpp:1498
json sketch_entity_to(const SketchEntity &e, int index)
Definition McpControl.cpp:1274

References action_sketch_describe(), Slic3r::GUI::DesignSketchTool::constraints(), Slic3r::GUI::DesignSketchTool::dof(), Slic3r::GUI::DesignSketchTool::entities(), mcp_sketch(), Slic3r::GUI::DesignSketchTool::mode(), Slic3r::GUI::DesignSketchTool::pending_points(), Slic3r::GUI::DesignSketchTool::selection(), sketch_entity_to(), sketch_report(), Slic3r::GUI::DesignSketchTool::solve_ok(), and Slic3r::GUI::DesignSketchTool::value_field_open().

Referenced by action_sketch_describe(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_heal()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_heal ( DesignPanel * panel,
const json & params )
1564{
1565 DesignSketchTool& t = mcp_sketch(panel);
1566 const double tol = params.value("tolerance", 1e-3);
1567 const bool ic = params.value("ignore_construction", true);
1568 const int welded = t.heal_coincidences(tol, ic);
1569 panel->mcp_viewport()->request_repaint();
1570 json out{{"ok", true}, {"welded", welded}, {"tolerance", tol},
1571 {"dof", t.dof()}, {"solve_ok", t.solve_ok()}};
1572 out.update(sketch_report(t));
1573 return out;
1574}
int heal_coincidences(double tol, bool ignore_construction)
Definition DesignSketchTool.cpp:10617

References action_sketch_heal(), Slic3r::GUI::DesignSketchTool::dof(), Slic3r::GUI::DesignSketchTool::heal_coincidences(), mcp_sketch(), Slic3r::GUI::DesignPanel::mcp_viewport(), Slic3r::GUI::DesignCanvas::request_repaint(), sketch_report(), and Slic3r::GUI::DesignSketchTool::solve_ok().

Referenced by action_sketch_heal(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_mirror()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_mirror ( DesignPanel * panel,
const json & params )
1478{
1479 DesignSketchTool& t = mcp_sketch(panel);
1480 auto pt = [&](const char* k, double dx, double dy) {
1481 if (!params.contains(k)) return Vec2d(dx, dy);
1482 const json& a = params.at(k);
1483 if (!a.is_array() || a.size() < 2) throw std::runtime_error(std::string(k) + " must be [x, y]");
1484 return Vec2d(a[0].get<double>(), a[1].get<double>());
1485 };
1486 const Vec2d a = pt("axis_a", 0, 0), b = pt("axis_b", 0, 1);
1487 const std::vector<int> tgt = sketch_targets(params, t, true);
1488 std::vector<SketchEntity> src;
1489 for (int i : tgt)
1490 if (i >= 0 && i < int(t.entities().size())) src.push_back(t.entities()[i]);
1491 if (src.empty()) throw std::runtime_error("nothing to mirror");
1492 const auto out = SketchEngine::mirror_entities(src, a, b);
1493 const int base = t.add_entities_scripted(out);
1494 panel->mcp_viewport()->request_repaint();
1495 return json{{"ok", true}, {"first_index", base}, {"added", int(out.size())}, {"dof", t.dof()}};
1496}
static std::vector< SketchEntity > mirror_entities(const std::vector< SketchEntity > &src, const Vec2d &a, const Vec2d &b)
Definition SketchEngine.cpp:1008

References action_sketch_mirror(), Slic3r::GUI::DesignSketchTool::add_entities_scripted(), Slic3r::GUI::DesignSketchTool::dof(), Slic3r::GUI::DesignSketchTool::entities(), mcp_sketch(), Slic3r::GUI::DesignPanel::mcp_viewport(), Slic3r::SketchEngine::mirror_entities(), Slic3r::GUI::DesignCanvas::request_repaint(), and sketch_targets().

Referenced by action_sketch_mirror(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_offset()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_offset ( DesignPanel * panel,
const json & params )
1461{
1462 if (!params.contains("distance")) throw std::runtime_error("sketch_offset needs 'distance'");
1463 DesignSketchTool& t = mcp_sketch(panel);
1464 const double d = params.at("distance").get<double>();
1465 const std::vector<int> tgt = sketch_targets(params, t, true);
1466 std::vector<SketchEntity> src;
1467 for (int i : tgt)
1468 if (i >= 0 && i < int(t.entities().size())) src.push_back(t.entities()[i]);
1469 if (src.empty()) throw std::runtime_error("nothing to offset");
1470 const auto out = SketchEngine::offset_entities(src, d);
1471 if (out.empty()) throw std::runtime_error("offset produced nothing (ellipses and splines are not offset)");
1472 const int base = t.add_entities_scripted(out);
1473 panel->mcp_viewport()->request_repaint();
1474 return json{{"ok", true}, {"first_index", base}, {"added", int(out.size())}, {"dof", t.dof()}};
1475}
static std::vector< SketchEntity > offset_entities(const std::vector< SketchEntity > &src, double d)
Definition SketchEngine.cpp:1329

References action_sketch_offset(), Slic3r::GUI::DesignSketchTool::add_entities_scripted(), Slic3r::GUI::DesignSketchTool::dof(), Slic3r::GUI::DesignSketchTool::entities(), mcp_sketch(), Slic3r::GUI::DesignPanel::mcp_viewport(), Slic3r::SketchEngine::offset_entities(), Slic3r::GUI::DesignCanvas::request_repaint(), and sketch_targets().

Referenced by action_sketch_offset(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_select()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_select ( DesignPanel * panel,
const json & params )
1426{
1427 DesignSketchTool& t = mcp_sketch(panel);
1428 std::vector<int> idx;
1429 if (params.contains("entities"))
1430 for (const auto& v : params.at("entities")) idx.push_back(v.get<int>());
1431 const bool any = t.select_indices(idx);
1432 panel->mcp_viewport()->request_repaint();
1433 return json{{"ok", true}, {"selected", int(t.selection().size())}, {"any", any}};
1434}

References action_sketch_select(), mcp_sketch(), Slic3r::GUI::DesignPanel::mcp_viewport(), Slic3r::GUI::DesignCanvas::request_repaint(), Slic3r::GUI::DesignSketchTool::select_indices(), and Slic3r::GUI::DesignSketchTool::selection().

Referenced by action_sketch_select(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_set_value()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_set_value ( DesignPanel * panel,
const json & params )
1582{
1583 DesignSketchTool& t = mcp_sketch(panel);
1584 if (!params.contains("value")) throw std::runtime_error("sketch_set_value needs 'value'");
1585 const double value = params["value"].get<double>();
1588 throw std::runtime_error("the selection has no value to set — pick a line, an arc, a circle, or two entities");
1589
1590 const char* kind_name = "none";
1591 switch (kind) {
1592 case DesignSketchTool::DimType::Length: kind_name = "length"; break;
1593 case DesignSketchTool::DimType::Radius: kind_name = "radius"; break;
1594 case DesignSketchTool::DimType::Diameter: kind_name = "diameter"; break;
1595 case DesignSketchTool::DimType::Angle: kind_name = "angle"; break;
1596 case DesignSketchTool::DimType::Distance: kind_name = "distance"; break;
1597 case DesignSketchTool::DimType::DistanceToLine: kind_name = "distance_to_line"; break;
1598 default: break;
1599 }
1600
1601 // Validate BEFORE apply_dimension, at the socket boundary. The tool only MOVES geometry when
1602 // the value passes its own per-case thresholds, but it records the driving constraint
1603 // UNCONDITIONALLY afterwards — a negative/zero/NaN value that moved nothing would still be
1604 // pushed to the solver as a constraint it must satisfy and cannot, silently corrupting the
1605 // sketch rather than failing. (apply_dimension has the same flaw for any other caller; this
1606 // guard protects the socket, not the tool.) Fail loudly instead of recording a poison value.
1607 if (!std::isfinite(value))
1608 throw std::runtime_error("dimension must be finite — NaN or infinity is not a dimension");
1609 switch (kind) {
1613 if (value <= 0.0)
1614 throw std::runtime_error(std::string(kind_name) + " must be positive (got " + std::to_string(value) + ")");
1615 break;
1618 if (value < 0.0)
1619 throw std::runtime_error(std::string(kind_name) + " must be >= 0 (zero means coincident / on the line)");
1620 break;
1622 default:
1623 break; // any finite angle is valid
1624 }
1625
1626 const double before = t.dimension_current();
1627 t.apply_dimension(value);
1628 panel->mcp_viewport()->request_repaint();
1629
1630 json out{{"ok", true}, {"kind", kind_name}, {"before", before}, {"value", value},
1631 {"dof", t.dof()}, {"solve_ok", t.solve_ok()}};
1632 out.update(sketch_report(t));
1633 return out;
1634}
DimType dimension_kind() const
Definition DesignSketchTool.cpp:640
void apply_dimension(double v)
Definition DesignSketchTool.cpp:746
double dimension_current() const
Definition DesignSketchTool.cpp:667
DimType
Definition DesignSketchTool.hpp:663
@ Distance
Definition DesignSketchTool.hpp:663
@ DistanceToLine
Definition DesignSketchTool.hpp:663
@ Angle
Definition DesignSketchTool.hpp:663
@ None
Definition DesignSketchTool.hpp:663
@ Diameter
Definition DesignSketchTool.hpp:663
@ Length
Definition DesignSketchTool.hpp:663
@ Radius
Definition DesignSketchTool.hpp:663

References action_sketch_set_value(), Slic3r::GUI::DesignSketchTool::Angle, Slic3r::GUI::DesignSketchTool::apply_dimension(), Slic3r::GUI::DesignSketchTool::Diameter, Slic3r::GUI::DesignSketchTool::dimension_current(), Slic3r::GUI::DesignSketchTool::dimension_kind(), Slic3r::GUI::DesignSketchTool::Distance, Slic3r::GUI::DesignSketchTool::DistanceToLine, Slic3r::GUI::DesignSketchTool::dof(), Slic3r::GUI::DesignSketchTool::Length, mcp_sketch(), Slic3r::GUI::DesignPanel::mcp_viewport(), Slic3r::GUI::DesignSketchTool::None, Slic3r::GUI::DesignSketchTool::Radius, Slic3r::GUI::DesignCanvas::request_repaint(), sketch_report(), and Slic3r::GUI::DesignSketchTool::solve_ok().

Referenced by action_sketch_set_value(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_sketch_validate()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_sketch_validate ( DesignPanel * panel,
const json & params )
1555{
1556 DesignSketchTool& t = mcp_sketch(panel);
1557 const double tol = params.value("tolerance", 1e-3);
1558 json out{{"ok", true}, {"tolerance", tol}, {"dof", t.dof()}, {"solve_ok", t.solve_ok()}};
1559 out.update(sketch_report(t));
1560 return out;
1561}

References action_sketch_validate(), Slic3r::GUI::DesignSketchTool::dof(), mcp_sketch(), sketch_report(), and Slic3r::GUI::DesignSketchTool::solve_ok().

Referenced by action_sketch_validate(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_split()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_split ( DesignPanel * panel,
const json & params )
1801{
1802 if (!params.contains("face")) throw std::runtime_error("split needs 'face' (id from query_topology)");
1803 CadDocument& doc = panel->mcp_doc();
1804 if (doc.bodies.empty()) throw std::runtime_error("no body to split");
1805 int bi = target_body_arg(params, doc);
1806 int face_body = params.value("face_body", -1);
1807 int face = params["face"].get<int>();
1808 bool keep_upper = params.value("keep_upper", true);
1809 bool keep_lower = params.value("keep_lower", true);
1810 doc.checkpoint();
1811 int idx = doc.add_split_by_face(bi, face_body, face, keep_upper, keep_lower, "Split");
1812 bool ok = doc.recompute();
1813 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1814 panel->mcp_after_change();
1815 return json{{"ok", ok}, {"split_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1816}
int add_split_by_face(int target_body, int face_body, int face, bool keep_upper, bool keep_lower, const std::string &name)
Definition CadDocument.cpp:1298

References action_split(), Slic3r::CadDocument::add_split_by_face(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_split(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_surface_extrude()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_surface_extrude ( DesignPanel * panel,
const json & params )
1092{
1093 if (!params.contains("sketch")) throw std::runtime_error("surface_extrude needs 'sketch' (feature index)");
1094 CadDocument& doc = panel->mcp_doc();
1095 int sketch = params["sketch"].get<int>();
1096 double distance = params.value("distance", 10.0);
1097 doc.checkpoint();
1098 int idx = doc.add_surface_extrude(sketch, distance, "SurfaceExtrude");
1099 bool ok = doc.recompute();
1100 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1101 panel->mcp_after_change();
1102 return json{{"ok", ok}, {"feature_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1103}
int add_surface_extrude(int sketch_ref, double distance, const std::string &name)
Definition CadDocument.cpp:4677

References action_surface_extrude(), Slic3r::CadDocument::add_surface_extrude(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_surface_extrude(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_surface_fill()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_surface_fill ( DesignPanel * panel,
const json & params )
1166{
1167 if (!params.contains("sketch")) throw std::runtime_error("surface_fill needs 'sketch' (feature index)");
1168 CadDocument& doc = panel->mcp_doc();
1169 int sketch = params["sketch"].get<int>();
1170 doc.checkpoint();
1171 int idx = doc.add_surface_fill(sketch, "SurfaceFill");
1172 bool ok = doc.recompute();
1173 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1174 panel->mcp_after_change();
1175 return json{{"ok", ok}, {"feature_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1176}
int add_surface_fill(int sketch_ref, const std::string &name)
Definition CadDocument.cpp:4714

References action_surface_fill(), Slic3r::CadDocument::add_surface_fill(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_surface_fill(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_surface_loft()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_surface_loft ( DesignPanel * panel,
const json & params )
1150{
1151 if (!params.contains("profiles") || !params["profiles"].is_array())
1152 throw std::runtime_error("surface_loft needs 'profiles' (array of int feature indices)");
1153 CadDocument& doc = panel->mcp_doc();
1154 std::vector<int> profiles;
1155 for (const json& j : params["profiles"]) profiles.push_back(j.get<int>());
1156 bool ruled = params.value("ruled", false);
1157 doc.checkpoint();
1158 int idx = doc.add_surface_loft(profiles, ruled, "SurfaceLoft");
1159 bool ok = doc.recompute();
1160 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1161 panel->mcp_after_change();
1162 return json{{"ok", ok}, {"feature_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1163}
int add_surface_loft(const std::vector< int > &profile_refs, bool ruled, const std::string &name)
Definition CadDocument.cpp:4702

References action_surface_loft(), Slic3r::CadDocument::add_surface_loft(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_surface_loft(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_surface_offset()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_surface_offset ( DesignPanel * panel,
const json & params )
1136{
1137 CadDocument& doc = panel->mcp_doc();
1138 if (doc.bodies.empty()) throw std::runtime_error("no sheet body to offset");
1139 int bi = target_body_arg(params, doc);
1140 double offset = params.value("offset", 1.0);
1141 doc.checkpoint();
1142 int idx = doc.add_surface_offset(bi, offset, "SurfaceOffset");
1143 bool ok = doc.recompute();
1144 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1145 panel->mcp_after_change();
1146 return json{{"ok", ok}, {"feature_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1147}
int add_surface_offset(int target_body, double offset, const std::string &name)
Definition CadDocument.cpp:1371

References action_surface_offset(), Slic3r::CadDocument::add_surface_offset(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::offset(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_surface_offset(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_surface_revolve()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_surface_revolve ( DesignPanel * panel,
const json & params )
1106{
1107 if (!params.contains("sketch")) throw std::runtime_error("surface_revolve needs 'sketch' (feature index)");
1108 CadDocument& doc = panel->mcp_doc();
1109 int sketch = params["sketch"].get<int>();
1110 double angle = params.value("angle", 360.0);
1111 int axis = params.value("axis", 0);
1112 doc.checkpoint();
1113 int idx = doc.add_surface_revolve(sketch, angle, axis, "SurfaceRevolve");
1114 bool ok = doc.recompute();
1115 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1116 panel->mcp_after_change();
1117 return json{{"ok", ok}, {"feature_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1118}
int add_surface_revolve(int sketch_ref, double angle_deg, int axis, const std::string &name)
Definition CadDocument.cpp:4689

References action_surface_revolve(), Slic3r::CadDocument::add_surface_revolve(), Slic3r::angle(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by action_surface_revolve(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_thicken()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_thicken ( DesignPanel * panel,
const json & params )
1784{
1785 if (!params.contains("face")) throw std::runtime_error("thicken needs 'face' (id from query_topology)");
1786 CadDocument& doc = panel->mcp_doc();
1787 if (doc.bodies.empty()) throw std::runtime_error("no body to thicken");
1788 int bi = target_body_arg(params, doc);
1789 int face = params["face"].get<int>();
1790 double thickness = params.value("thickness", 2.0);
1791 bool flip = params.value("flip", false);
1792 doc.checkpoint();
1793 int idx = doc.add_thicken(bi, face, thickness, flip, "Thicken");
1794 bool ok = doc.recompute();
1795 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1796 panel->mcp_after_change();
1797 return json{{"ok", ok}, {"thicken_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1798}
int add_thicken(int target_body, int face, double thickness, bool flip, const std::string &name)
Definition CadDocument.cpp:1343

References action_thicken(), Slic3r::CadDocument::add_thicken(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_thicken(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_thicken_surface()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_thicken_surface ( DesignPanel * panel,
const json & params )
1121{
1122 CadDocument& doc = panel->mcp_doc();
1123 if (doc.bodies.empty()) throw std::runtime_error("no sheet body to thicken");
1124 int bi = target_body_arg(params, doc);
1125 double thickness = params.value("thickness", 2.0);
1126 bool flip = params.value("flip", false);
1127 doc.checkpoint();
1128 int idx = doc.add_thicken_surface(bi, thickness, flip, "ThickenSurface");
1129 bool ok = doc.recompute();
1130 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1131 panel->mcp_after_change();
1132 return json{{"ok", ok}, {"feature_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1133}
int add_thicken_surface(int target_body, double thickness, bool flip, const std::string &name)
Definition CadDocument.cpp:1357

References action_thicken_surface(), Slic3r::CadDocument::add_thicken_surface(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), and Slic3r::CadDocument::undo().

Referenced by action_thicken_surface(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ action_transform()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::action_transform ( DesignPanel * panel,
const json & params )
1766{
1767 CadDocument& doc = panel->mcp_doc();
1768 if (doc.bodies.empty()) throw std::runtime_error("no body to transform");
1769 int bi = target_body_arg(params, doc);
1770 Vec3d translate(params.value("dx", 0.0), params.value("dy", 0.0), params.value("dz", 0.0));
1771 Vec3d axis(params.value("axis_x", 0.0), params.value("axis_y", 0.0), params.value("axis_z", 1.0));
1772 Vec3d pivot(params.value("pivot_x", 0.0), params.value("pivot_y", 0.0), params.value("pivot_z", 0.0));
1773 double angle = params.value("angle", 0.0);
1774 bool copy = params.value("copy", false);
1775 doc.checkpoint();
1776 int idx = doc.add_transform(bi, translate, axis, pivot, angle, copy, "Transform");
1777 bool ok = doc.recompute();
1778 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
1779 panel->mcp_after_change();
1780 return json{{"ok", ok}, {"transform_index", idx}, {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
1781}
int add_transform(int target_body, const Vec3d &translate, const Vec3d &axis, const Vec3d &pivot, double angle_deg, bool copy, const std::string &name)
Definition CadDocument.cpp:1326
void translate(ExPolygonsWithIds &e, const Point &p)
Definition Emboss.cpp:1368

References action_transform(), Slic3r::CadDocument::add_transform(), Slic3r::angle(), Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::CadDocument::recompute(), target_body_arg(), Slic3r::translate(), and Slic3r::CadDocument::undo().

Referenced by action_transform(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ body_shape()

const TopoDS_Shape & Slic3r::GUI::anonymous_namespace{McpControl.cpp}::body_shape ( DesignPanel * panel,
const json & params )
479{
480 CadDocument& doc = panel->mcp_doc();
481 int idx = params.value("body", 0);
482 if (idx < 0 || idx >= int(doc.bodies.size()))
483 throw std::runtime_error("body index out of range (have " + std::to_string(doc.bodies.size()) + ")");
484 if (doc.bodies[idx].shape.IsNull())
485 throw std::runtime_error("body has no shape");
486 return doc.bodies[idx].shape;
487}

References Slic3r::CadDocument::bodies, body_shape(), and Slic3r::GUI::DesignPanel::mcp_doc().

Referenced by body_shape(), mass_properties(), measure(), query_topology(), slice_body(), and validate_against().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ bool_from()

BooleanMode Slic3r::GUI::anonymous_namespace{McpControl.cpp}::bool_from ( const std::string & s)
460{
461 if (s == "union" || s == "add") return BooleanMode::Add;
462 if (s == "subtract" || s == "cut") return BooleanMode::Cut;
463 if (s == "intersect" || s == "common")return BooleanMode::Intersect;
464 return BooleanMode::New;
465}
@ Intersect
Definition CadDocument.hpp:31
@ Cut
Definition CadDocument.hpp:31

References Slic3r::Add, bool_from(), Slic3r::Cut, Slic3r::Intersect, and Slic3r::New.

Referenced by action_boolean(), action_extrude(), action_revolve(), and bool_from().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ chain_segments()

std::vector< std::pair< std::vector< Vec3d >, bool > > Slic3r::GUI::anonymous_namespace{McpControl.cpp}::chain_segments ( std::vector< std::vector< Vec3d > > segs,
double tol )
603{
604 std::vector<std::pair<std::vector<Vec3d>, bool>> contours;
605 std::vector<char> used(segs.size(), 0);
606 auto meets = [&](const Vec3d& a, const Vec3d& b) { return (a - b).norm() <= tol; };
607 for (size_t i = 0; i < segs.size(); ++i) {
608 if (used[i] || segs[i].size() < 2) continue;
609 used[i] = 1;
610 std::vector<Vec3d> c = segs[i];
611 for (int side = 0; side < 2; ) { // grow tail; reverse once when stuck
612 bool grew = false;
613 for (size_t j = 0; j < segs.size(); ++j) {
614 if (used[j] || segs[j].size() < 2) continue;
615 if (meets(c.back(), segs[j].front())) {
616 c.insert(c.end(), segs[j].begin() + 1, segs[j].end()); used[j] = 1; grew = true;
617 } else if (meets(c.back(), segs[j].back())) {
618 for (auto it = segs[j].rbegin() + 1; it != segs[j].rend(); ++it) c.push_back(*it);
619 used[j] = 1; grew = true;
620 }
621 }
622 if (grew) { side = 0; continue; }
623 std::reverse(c.begin(), c.end()); ++side; // try the other end
624 }
625 bool closed = c.size() > 2 && meets(c.front(), c.back());
626 contours.emplace_back(std::move(c), closed);
627 }
628 return contours;
629}

References chain_segments().

Referenced by chain_segments(), and slice_body().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ describe_scene()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::describe_scene ( DesignPanel * panel)
407{
408 CadDocument& doc = panel->mcp_doc();
409
410 json features = json::array();
411 for (size_t i = 0; i < doc.features.size(); ++i) {
412 const CadFeature& f = doc.features[i];
413 features.push_back(json{
414 {"index", int(i)}, {"type", feature_type_name(f.type)},
415 {"name", f.name}, {"enabled", f.enabled}});
416 }
417
418 json bodies = json::array();
419 for (size_t i = 0; i < doc.bodies.size(); ++i) {
420 // The user's name when the body has one, the derived maker name otherwise — the same
421 // rule the Bodies row shows, so a driver and a person read the same thing.
422 json b{{"index", int(i)},
423 {"name", doc.bodies[i].has_user_name ? doc.bodies[i].user_name : doc.bodies[i].name},
424 {"user_name", doc.bodies[i].has_user_name},
425 {"has_color", doc.bodies[i].has_color}};
426 // Per-body bbox/centre from the already-tessellated display meshes.
427 if (i < doc.display_body_meshes.size() && !doc.display_body_meshes[i].empty()) {
428 BoundingBoxf3 bb = doc.display_body_meshes[i].bounding_box();
429 b["bbox"] = json{{"min", {bb.min.x(), bb.min.y(), bb.min.z()}},
430 {"max", {bb.max.x(), bb.max.y(), bb.max.z()}}};
431 Vec3d c = bb.center();
432 b["center"] = {c.x(), c.y(), c.z()};
433 }
434 bodies.push_back(std::move(b));
435 }
436
437 return json{
438 {"modeling_origin", {doc.modeling_origin.x(), doc.modeling_origin.y(), doc.modeling_origin.z()}},
439 {"features", std::move(features)},
440 {"bodies", std::move(bodies)},
441 {"error", doc.error},
442 // Pass this back as "generation" on any call that takes a face or edge id and the call
443 // is refused if the topology has moved on. See the note on the dispatcher.
444 {"generation", doc.topo_generation},
445 };
446}
uint64_t topo_generation
Definition CadDocument.hpp:765
Vec3d modeling_origin
Definition CadDocument.hpp:572
std::vector< TriangleMesh > display_body_meshes
Definition CadDocument.hpp:555
const char * feature_type_name(CadFeatureType t)
Definition McpControl.cpp:68

References Slic3r::CadDocument::bodies, Slic3r::BoundingBox3Base< PointType >::center(), describe_scene(), Slic3r::CadDocument::display_body_meshes, Slic3r::CadDocument::error, Slic3r::f(), feature_type_name(), Slic3r::CadDocument::features, Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::max, Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::BoundingBoxBase< PointType, std::vector< PointType > >::min, Slic3r::CadDocument::modeling_origin, and Slic3r::CadDocument::topo_generation.

Referenced by describe_scene(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ describe_tools()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::describe_tools ( )
121{
122 // Hand-written descriptor. The bridge turns this into MCP tool schemas; later
123 // slices grow this list (ideally from the kernel directly).
124 return json{
125 {"app", "Orca CAD"},
126 {"protocol", "jsonrpc-2.0"},
127 {"slice", 5},
128 // Read this before using any face or edge id.
129 {"id_lifetime",
130 "Global face and edge ids are indices into the CURRENT topology and expire the moment "
131 "a feature rebuilds the model. Reading the scene once and then issuing several "
132 "operations addresses the wrong edge on every call after the first, and does NOT "
133 "error, because a stale id still names a real edge. Either re-read query_topology "
134 "before each id-taking call, or pass the 'generation' you were given back with the "
135 "call and have it refused if the model has moved on."},
136 {"tools", json::array({
137 json{{"name", "describe_tools"}, {"summary", "List callable tools and their parameters."},
138 {"params", json::array()}},
139 json{{"name", "describe_scene"}, {"summary", "Feature tree + per-body bounding boxes of the Design document."},
140 {"params", json::array()}},
141 json{{"name", "extrude"}, {"summary", "Extrude a profile to a depth. Give an explicit closed `profile` (list of [x,y]) or default to a centred width x height rectangle. End conditions match Onshape."},
142 {"params", json::array({
143 json{{"name", "width"}, {"type", "number"}, {"unit", "mm"}, {"default", 20}, {"min", 0.01}},
144 json{{"name", "height"}, {"type", "number"}, {"unit", "mm"}, {"default", 20}, {"min", 0.01}},
145 json{{"name", "distance"}, {"type", "number"}, {"unit", "mm"}, {"default", 10}, {"min", 0.01}},
146 json{{"name", "plane"}, {"type", "string"}, {"enum", json::array({"XY", "XZ", "YZ"})}, {"default", "XY"}},
147 json{{"name", "profile"}, {"type", "array"}, {"default", json::array()}, {"description", "optional closed contour [[x,y],...] in plane mm; overrides width/height"}},
148 json{{"name", "boolean"}, {"type", "string"}, {"enum", json::array({"new", "union", "subtract", "intersect"})}, {"default", "new"}},
149 json{{"name", "end"}, {"type", "string"}, {"enum", json::array({"blind", "symmetric", "two_sided", "through_all", "up_to_face"})}, {"default", "blind"}},
150 json{{"name", "distance2"},{"type", "number"}, {"unit", "mm"}, {"default", 0}, {"description", "second-side depth when end=two_sided (else falls back to distance)"}},
151 json{{"name", "up_to_face"},{"type", "integer"}, {"default", -1}, {"description", "target face id (query_topology on the last body) when end=up_to_face"}},
152 json{{"name", "taper"}, {"type", "number"}, {"unit", "deg"}, {"default", 0}, {"description", "draft/taper of the side wall"}},
153 json{{"name", "flip"}, {"type", "boolean"}, {"default", false}},
154 })}},
155 json{{"name", "revolve"}, {"summary", "Revolve a profile about a plane axis. Give an explicit `profile` offset from the axis (or a rectangle) — angle degrees about axis 0=plane X / 1=plane Y."},
156 {"params", json::array({
157 json{{"name", "width"}, {"type", "number"}, {"unit", "mm"}, {"default", 20}, {"min", 0.01}},
158 json{{"name", "height"}, {"type", "number"}, {"unit", "mm"}, {"default", 10}, {"min", 0.01}},
159 json{{"name", "angle"}, {"type", "number"}, {"unit", "deg"}, {"default", 360}},
160 json{{"name", "axis"}, {"type", "integer"}, {"enum", json::array({0, 1})}, {"default", 0}},
161 json{{"name", "flip"}, {"type", "boolean"}, {"default", false}},
162 json{{"name", "plane"}, {"type", "string"}, {"enum", json::array({"XY", "XZ", "YZ"})}, {"default", "XY"}},
163 json{{"name", "profile"}, {"type", "array"}, {"default", json::array()}, {"description", "optional closed contour [[x,y],...] in plane mm; overrides width/height"}},
164 json{{"name", "boolean"}, {"type", "string"}, {"enum", json::array({"new", "union", "subtract", "intersect"})}, {"default", "new"}},
165 })}},
166 json{{"name", "fillet"}, {"summary", "Round measured edges of a body (edge ids from query_topology on that body)."},
167 {"params", json::array({
168 json{{"name", "edge"}, {"type", "integer|array"}, {"description", "one edge id, or an array of ids rounded together in one feature"}},
169 json{{"name", "radius"}, {"type", "number"}, {"unit", "mm"}, {"default", 1}, {"min", 0.01}},
170 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body. edge id is resolved against THIS body."}},
171 })}},
172 json{{"name", "chamfer"}, {"summary", "Chamfer measured edges of a body (edge ids from query_topology on that body)."},
173 {"params", json::array({
174 json{{"name", "edge"}, {"type", "integer|array"}, {"description", "one edge id, or an array of ids chamfered together in one feature"}},
175 json{{"name", "distance"}, {"type", "number"}, {"unit", "mm"}, {"default", 1}, {"min", 0.01}},
176 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body. edge id is resolved against THIS body."}},
177 })}},
178 json{{"name", "hole"}, {"summary", "Drill a circular hole into the current body at (x,y) on a plane."},
179 {"params", json::array({
180 json{{"name", "diameter"}, {"type", "number"}, {"unit", "mm"}, {"default", 5}, {"min", 0.01}},
181 json{{"name", "depth"}, {"type", "number"}, {"unit", "mm"}, {"default", 10}, {"min", 0.01}},
182 json{{"name", "through"}, {"type", "boolean"}, {"default", false}},
183 json{{"name", "x"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}, {"description", "in the sketch plane's frame (origin = describe_scene.modeling_origin), NOT world"}},
184 json{{"name", "y"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}, {"description", "in the sketch plane's frame (origin = describe_scene.modeling_origin), NOT world"}},
185 json{{"name", "plane"}, {"type", "string"}, {"enum", json::array({"XY", "XZ", "YZ"})}, {"default", "XY"}},
186 })}},
187 json{{"name", "hole_styled"}, {"summary", "Drill a hole with optional counterbore (style=1) or countersink (style=2) at (x,y) on a plane."},
188 {"params", json::array({
189 json{{"name", "diameter"}, {"type", "number"}, {"unit", "mm"}, {"default", 5}, {"min", 0.01}},
190 json{{"name", "depth"}, {"type", "number"}, {"unit", "mm"}, {"default", 10}, {"min", 0.01}},
191 json{{"name", "through"}, {"type", "boolean"}, {"default", true}},
192 json{{"name", "x"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}, {"description", "in the sketch plane's frame (origin = describe_scene.modeling_origin), NOT world"}},
193 json{{"name", "y"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}, {"description", "in the sketch plane's frame (origin = describe_scene.modeling_origin), NOT world"}},
194 json{{"name", "plane"}, {"type", "string"}, {"enum", json::array({"XY", "XZ", "YZ"})}, {"default", "XY"}},
195 json{{"name", "style"}, {"type", "integer"}, {"default", 0}, {"description", "0=simple, 1=counterbore, 2=countersink"}},
196 json{{"name", "cbore_diameter"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
197 json{{"name", "cbore_depth"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
198 json{{"name", "csink_diameter"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
199 json{{"name", "csink_angle"}, {"type", "number"}, {"unit", "deg"}, {"default", 90}},
200 json{{"name", "standard"}, {"type", "string"}, {"default", ""}, {"description", "provenance designation, e.g. M6"}},
201 })}},
202 json{{"name", "hole_standard"}, {"summary", "Drill a standard clearance hole (ISO 273 / ANSI) at (x,y) on a plane. style: 0=simple, 1=counterbore, 2=countersink."},
203 {"params", json::array({
204 json{{"name", "designation"}, {"type", "string"}, {"description", "e.g. M6, 1/4-20"}},
205 json{{"name", "style"}, {"type", "integer"}, {"default", 0}},
206 json{{"name", "through"}, {"type", "boolean"}, {"default", true}},
207 json{{"name", "depth"}, {"type", "number"}, {"unit", "mm"}, {"default", 10}, {"min", 0.01}},
208 json{{"name", "x"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}, {"description", "in the sketch plane's frame (origin = describe_scene.modeling_origin), NOT world"}},
209 json{{"name", "y"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}, {"description", "in the sketch plane's frame (origin = describe_scene.modeling_origin), NOT world"}},
210 json{{"name", "plane"}, {"type", "string"}, {"enum", json::array({"XY", "XZ", "YZ"})}, {"default", "XY"}},
211 })}},
212 json{{"name", "boolean"}, {"summary", "Combine two bodies: union | subtract (tool from target) | intersect."},
213 {"params", json::array({
214 json{{"name", "op"}, {"type", "string"}, {"enum", json::array({"union", "subtract", "intersect"})}, {"default", "subtract"}},
215 json{{"name", "target"}, {"type", "integer"}, {"default", 0}},
216 json{{"name", "tool"}, {"type", "integer"}, {"default", 1}},
217 json{{"name", "keep_tool"}, {"type", "boolean"}, {"default", false}},
218 json{{"name", "tolerance"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
219 })}},
220 json{{"name", "pattern"}, {"summary", "Replicate a body: linear (count along a plane axis at spacing) or circular (count over an angle about the plane normal)."},
221 {"params", json::array({
222 json{{"name", "circular"}, {"type", "boolean"}, {"default", false}},
223 json{{"name", "count"}, {"type", "integer"}, {"default", 3}, {"min", 1}},
224 json{{"name", "spacing"}, {"type", "number"}, {"unit", "mm"}, {"default", 10}, {"description", "linear step"}},
225 json{{"name", "dir"}, {"type", "integer"}, {"enum", json::array({0, 1})}, {"default", 0}, {"description", "linear axis: 0=plane X, 1=plane Y"}},
226 json{{"name", "angle"}, {"type", "number"}, {"unit", "deg"}, {"default", 360}, {"description", "circular total sweep"}},
227 json{{"name", "plane"}, {"type", "string"}, {"enum", json::array({"XY", "XZ", "YZ"})}, {"default", "XY"}},
228 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
229 })}},
230 json{{"name", "pattern_on_curve"}, {"summary", "Replicate a body along a sketch curve: `count` copies placed at equal-parameter points on the entity, each translated by (P_i - P_0)."},
231 {"params", json::array({
232 json{{"name", "count"}, {"type", "integer"}, {"default", 3}, {"min", 1}},
233 json{{"name", "sketch"}, {"type", "integer"}, {"description", "feature index of the sketch holding the guide curve"}},
234 json{{"name", "entity"}, {"type", "integer"}, {"description", "entity index of the guide curve within that sketch"}},
235 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
236 })}},
237 json{{"name", "shell"}, {"summary", "Hollow a body to a wall thickness (inward); optionally leave one face open."},
238 {"params", json::array({
239 json{{"name", "thickness"}, {"type", "number"}, {"unit", "mm"}, {"default", 1}, {"min", 0.01}},
240 json{{"name", "face"}, {"type", "integer"}, {"default", -1}, {"description", "face id to leave open (query_topology); omit for a closed hollow"}},
241 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
242 })}},
243 json{{"name", "draft"}, {"summary", "Taper a body face by an angle about its base (pull direction +Z)."},
244 {"params", json::array({
245 json{{"name", "face"}, {"type", "integer"}, {"description", "face id to draft (query_topology)"}},
246 json{{"name", "angle"}, {"type", "number"}, {"unit", "deg"}, {"default", 5}},
247 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
248 })}},
249 json{{"name", "mirror"}, {"summary", "Mirror a body about a base plane. mode=new creates a mirrored copy; mode=add fuses the mirror back into the source."},
250 {"params", json::array({
251 json{{"name", "plane"}, {"type", "string"}, {"enum", json::array({"XY", "XZ", "YZ"})}, {"default", "XZ"}},
252 json{{"name", "mode"}, {"type", "string"}, {"enum", json::array({"new", "add"})}, {"default", "new"}},
253 json{{"name", "keep_original"},{"type", "boolean"}, {"default", true}, {"description", "when mode=new, keep the source body"}},
254 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
255 })}},
256 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."},
257 {"params", json::array({
258 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
259 json{{"name", "dx"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
260 json{{"name", "dy"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
261 json{{"name", "dz"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
262 json{{"name", "axis_x"}, {"type", "number"}, {"default", 0}},
263 json{{"name", "axis_y"}, {"type", "number"}, {"default", 0}},
264 json{{"name", "axis_z"}, {"type", "number"}, {"default", 1}},
265 json{{"name", "pivot_x"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
266 json{{"name", "pivot_y"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
267 json{{"name", "pivot_z"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
268 json{{"name", "angle"}, {"type", "number"}, {"unit", "deg"}, {"default", 0}},
269 json{{"name", "copy"}, {"type", "boolean"}, {"default", false}},
270 })}},
271 json{{"name", "axis"}, {"summary", "Create a datum axis (reference line): two points, face normal, cylinder centreline, plane intersection, or along edge."},
272 {"params", json::array({
273 json{{"name", "type"}, {"type", "string"}, {"enum", json::array({"two_points", "face_normal", "cylinder", "plane_intersection", "along_edge"})}, {"default", "two_points"}},
274 json{{"name", "p1"}, {"type", "array"}, {"default", json::array({0,0,0})}, {"description", "first point [x,y,z] for two_points"}},
275 json{{"name", "p2"}, {"type", "array"}, {"default", json::array({0,0,10})}, {"description", "second point [x,y,z] for two_points"}},
276 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "body for face/edge refs"}},
277 json{{"name", "face"}, {"type", "integer"}, {"default", -1}, {"description", "face id (query_topology) for face_normal/cylinder"}},
278 json{{"name", "edge"}, {"type", "integer"}, {"default", -1}, {"description", "edge id (query_topology) for along_edge"}},
279 json{{"name", "plane_a"}, {"type", "integer"}, {"default", -1}, {"description", "first datum plane feature index for plane_intersection"}},
280 json{{"name", "plane_b"}, {"type", "integer"}, {"default", -1}, {"description", "second datum plane feature index for plane_intersection"}},
281 })}},
282 json{{"name", "coordsys"}, {"summary", "Create a datum coordinate system (origin + orthonormal axes). PointWorld aligns to world; FaceAndDirection uses a face for Z and an edge/hint for X."},
283 {"params", json::array({
284 json{{"name", "type"}, {"type", "string"}, {"enum", json::array({"point_world", "face_and_direction"})}, {"default", "point_world"}},
285 json{{"name", "point"}, {"type", "array"}, {"default", json::array({0,0,0})}, {"description", "origin [x,y,z] for point_world"}},
286 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "body for face/edge refs"}},
287 json{{"name", "face"}, {"type", "integer"}, {"default", -1}, {"description", "face id (query_topology) for Z axis"}},
288 json{{"name", "edge"}, {"type", "integer"}, {"default", -1}, {"description", "edge id (query_topology) for X axis hint"}},
289 json{{"name", "x_hint"}, {"type", "array"}, {"default", json::array({1,0,0})}, {"description", "fallback X direction hint if no edge given"}},
290 })}},
291 json{{"name", "helix"}, {"summary", "Create a helical curve (consumed by sweep as a path to build springs/coils/augers). pitch = axial rise per turn. left_handed flips the winding. taper_deg != 0 gives a conical helix."},
292 {"params", json::array({
293 json{{"name", "radius"}, {"type", "number"}, {"unit", "mm"}, {"default", 10}, {"min", 0.01}},
294 json{{"name", "pitch"}, {"type", "number"}, {"unit", "mm"}, {"default", 5}, {"min", 0.01}},
295 json{{"name", "height"}, {"type", "number"}, {"unit", "mm"}, {"default", 20}, {"min", 0.01}},
296 json{{"name", "left_handed"}, {"type", "boolean"}, {"default", false}},
297 json{{"name", "taper_deg"}, {"type", "number"}, {"unit", "deg"}, {"default", 0}},
298 json{{"name", "plane"}, {"type", "string"}, {"enum", json::array({"XY", "XZ", "YZ"})}, {"default", "XY"}},
299 })}},
300 json{{"name", "thicken"}, {"summary", "Offset a face of a body by a wall thickness, producing a new thin solid body."},
301 {"params", json::array({
302 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
303 json{{"name", "face"}, {"type", "integer"}, {"description", "face id to thicken (query_topology)"}},
304 json{{"name", "thickness"}, {"type", "number"}, {"unit", "mm"}, {"default", 2}, {"min", 0.01}},
305 json{{"name", "flip"}, {"type", "boolean"}, {"default", false}},
306 })}},
307 json{{"name", "split"}, {"summary", "Split a body along the plane of a picked face."},
308 {"params", json::array({
309 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
310 json{{"name", "face_body"}, {"type", "integer"}, {"default", -1}, {"description", "body that owns the face; -1 = target"}},
311 json{{"name", "face"}, {"type", "integer"}, {"description", "face id to split along (query_topology)"}},
312 json{{"name", "keep_upper"},{"type", "boolean"}, {"default", true}},
313 json{{"name", "keep_lower"},{"type", "boolean"}, {"default", true}},
314 })}},
315 json{{"name", "project"}, {"summary", "Project edges of a solid onto a sketch plane, producing a new sketch feature."},
316 {"params", json::array({
317 json{{"name", "source_body"}, {"type", "integer"}, {"default", -1}, {"description", "body owning the edges; -1 = last body"}},
318 json{{"name", "face"}, {"type", "integer"}, {"default", -1}, {"description", "global face id on the source body; when set, all its edges are projected"}},
319 json{{"name", "edges"}, {"type", "array"}, {"default", json::array()}, {"description", "global edge ids to project; empty => project the face"}},
320 json{{"name", "plane"}, {"type", "string"}, {"default", "XY"}, {"description", "target sketch plane (XY/XZ/YZ)"}},
321 })}},
322 json{{"name", "delete_face"}, {"summary", "Remove faces from a solid, healing the gap via OCCT defeaturing."},
323 {"params", json::array({
324 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
325 json{{"name", "faces"}, {"type", "array"}, {"description", "global face ids to delete"}},
326 })}},
327 json{{"name", "bridge"}, {"summary", "Build a cubic-Bezier G1 bridge (BSpline) between two sketch-entity endpoints within a sketch feature."},
328 {"params", json::array({
329 json{{"name", "sketch"}, {"type", "integer"}, {"description", "sketch feature index"}},
330 json{{"name", "ent_a"}, {"type", "integer"}, {"description", "first entity index within the sketch"}},
331 json{{"name", "end_a"}, {"type", "integer"}, {"enum", json::array({0, 1})}, {"default", 1}, {"description", "0 = start/p0 side, 1 = end/p1 side"}},
332 json{{"name", "ent_b"}, {"type", "integer"}, {"description", "second entity index within the sketch"}},
333 json{{"name", "end_b"}, {"type", "integer"}, {"enum", json::array({0, 1})}, {"default", 0}, {"description", "0 = start/p0 side, 1 = end/p1 side"}},
334 })}},
335 json{{"name", "rib"}, {"summary", "Grow a thin rib wall (stiffener) from an open Line sketch entity, fused to a body."},
336 {"params", json::array({
337 json{{"name", "sketch"}, {"type", "integer"}, {"description", "sketch feature index holding the open line"}},
338 json{{"name", "entity"}, {"type", "integer"}, {"description", "entity index of the open Line within the sketch"}},
339 json{{"name", "thickness"}, {"type", "number"}, {"unit", "mm"}, {"default", 2}, {"min", 0.01}},
340 json{{"name", "depth"}, {"type", "number"}, {"unit", "mm"}, {"default", 10}, {"min", 0.01}},
341 json{{"name", "body"}, {"type", "integer"}, {"default", -1}, {"description", "target body; omit for the last body"}},
342 })}},
343 json{{"name", "surface_extrude"}, {"summary", "Extrude a sketch wire with no end caps -> an open sheet body."},
344 {"params", json::array({
345 json{{"name", "sketch"}, {"type", "integer"}, {"description", "sketch feature index"}},
346 json{{"name", "distance"},{"type", "number"}, {"unit", "mm"}, {"default", 10}, {"min", 0.01}},
347 })}},
348 json{{"name", "surface_revolve"}, {"summary", "Revolve a sketch wire with no caps -> an open sheet body."},
349 {"params", json::array({
350 json{{"name", "sketch"}, {"type", "integer"}, {"description", "sketch feature index"}},
351 json{{"name", "angle"}, {"type", "number"}, {"unit", "deg"}, {"default", 360}},
352 json{{"name", "axis"}, {"type", "integer"}, {"enum", json::array({0, 1})}, {"default", 0}},
353 })}},
354 json{{"name", "mate"}, {"summary", "Mate two bodies: transform the moving body (cs_b) so its connector lands on the fixed one (cs_a). kind: 0=Fastened, 1=Planar, 2=Revolute, 3=Slider, 4=Cylindrical."},
355 {"params", json::array({
356 json{{"name", "kind"}, {"type", "integer"}, {"default", 0}, {"description", "0=Fastened (rigid), 1=Planar (normal only), 2=Revolute (free rotation about axis), 3=Slider (free translation along axis), 4=Cylindrical (free rotation+translation)"}},
357 json{{"name", "cs_a"}, {"type", "integer"}, {"description", "feature index of the fixed CoordSys (mate connector A)"}},
358 json{{"name", "cs_b"}, {"type", "integer"}, {"description", "feature index of the CoordSys on the body that moves"}},
359 json{{"name", "offset"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
360 json{{"name", "angle"}, {"type", "number"}, {"unit", "deg"}, {"default", 0}},
361 json{{"name", "flip"}, {"type", "boolean"}, {"default", false}},
362 })}},
363 json{{"name", "check_interference"}, {"summary", "Solid bodies that overlap, as {body_a, body_b, volume}. Read-only; bodies that merely touch enclose no volume and are not reported."},
364 {"params", json::array({
365 json{{"name", "min_volume"}, {"type", "number"}, {"unit", "mm^3"}, {"default", 1e-6}, {"description", "overlap volume above which a pair counts as interfering"}},
366 })}},
367 json{{"name", "query_topology"}, {"summary", "Measured faces (centroid/normal/cylinder) and edges (length/circle) of a body."},
368 {"params", json::array({
369 json{{"name", "body"}, {"type", "integer"}, {"default", 0}},
370 })}},
371 json{{"name", "measure"}, {"summary", "Distance (and angle, when both have direction) between two refs {face|edge|point} on a body."},
372 {"params", json::array({
373 json{{"name", "body"}, {"type", "integer"}, {"default", 0}},
374 json{{"name", "a"}, {"type", "object"}},
375 json{{"name", "b"}, {"type", "object"}},
376 })}},
377 json{{"name", "mass_properties"}, {"summary", "Volume / surface area / centre of mass / inertia tensor of a body."},
378 {"params", json::array({
379 json{{"name", "body"}, {"type", "integer"}, {"default", 0}},
380 })}},
381 json{{"name", "slice_body"}, {"summary", "Cross-section of a body by a base plane at an offset (sections-as-evidence); returns ordered world contours, each flagged closed/open."},
382 {"params", json::array({
383 json{{"name", "body"}, {"type", "integer"}, {"default", 0}},
384 json{{"name", "plane"}, {"type", "string"}, {"enum", json::array({"XY", "XZ", "YZ"})}, {"default", "XY"}},
385 json{{"name", "offset"}, {"type", "number"}, {"unit", "mm"}, {"default", 0}},
386 })}},
387 json{{"name", "import_step"}, {"summary", "Import a STEP file as native B-rep bodies (the reference part to measure)."},
388 {"params", json::array({
389 json{{"name", "path"}, {"type", "string"}},
390 })}},
391 json{{"name", "import_mesh"}, {"summary", "Convert a triangle mesh (STL/OBJ) into an editable B-rep body. Reports whether the result is a real solid or an open shell, and why."},
392 {"params", json::array({
393 json{{"name", "path"}, {"type", "string"}},
394 json{{"name", "tolerance"}, {"type", "number"}, {"default", 0.01}},
395 json{{"name", "merge_angle_deg"}, {"type", "number"}, {"default", 5.0}},
396 })}},
397 json{{"name", "validate_against"}, {"summary", "Volume + bbox/centroid + surface deviation (max/mean/rms mm) of a body vs a reference {step:path|body:id} (the RE acceptance metric)."},
398 {"params", json::array({
399 json{{"name", "body"}, {"type", "integer"}, {"default", 0}},
400 json{{"name", "reference"}, {"type", "object"}},
401 })}},
402 })},
403 };
404}

References describe_tools().

Referenced by describe_tools(), and handle_on_main().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ dispatch_request()

std::string Slic3r::GUI::anonymous_namespace{McpControl.cpp}::dispatch_request ( const std::string & line)
2143{
2144 json req;
2145 try { req = json::parse(line); }
2146 catch (const std::exception& ex) { return rpc_error(nullptr, -32700, std::string("parse error: ") + ex.what()); }
2147
2148 json id = req.contains("id") ? req["id"] : json(nullptr);
2149 std::string method = req.value("method", std::string());
2150 json params = req.contains("params") ? req["params"] : json::object();
2151 if (method.empty()) return rpc_error(id, -32600, "missing method");
2152
2153 auto prom = std::make_shared<std::promise<std::string>>();
2154 auto fut = prom->get_future();
2155 // 0 = queued, 1 = running, 2 = abandoned. A request that timed out while still QUEUED must
2156 // never run: the client has been told it failed, and a retry would otherwise apply it twice.
2157 auto state = std::make_shared<std::atomic<int>>(0);
2158 // Nothing may escape this lambda. It is invoked by the wx event loop, which has no
2159 // handler of its own, so an escaping exception is std::terminate — the socket would
2160 // become a way for any client to kill the application. handle_on_main() catches what
2161 // it knows about; this catches what it does not, and still answers the caller.
2162 wxGetApp().CallAfter([prom, state, method, params, id]() {
2163 int queued = 0;
2164 if (!state->compare_exchange_strong(queued, 1)) return; // abandoned by a timeout
2165 try {
2166 prom->set_value(handle_on_main(method, params, id));
2167 } catch (const std::exception& ex) {
2168 prom->set_value(rpc_error(id, -32000, std::string("internal error: ") + ex.what()));
2169 } catch (...) {
2170 prom->set_value(rpc_error(id, -32000, "internal error: unknown exception"));
2171 }
2172 });
2173 if (fut.wait_for(std::chrono::seconds(15)) != std::future_status::ready) {
2174 int queued = 0;
2175 if (state->compare_exchange_strong(queued, 2))
2176 return rpc_error(id, -32000, "main-thread timeout: the command was NOT run");
2177 // Already running: it will finish, so wait for its real answer rather than report a
2178 // failure for a command that is in fact being applied.
2179 fut.wait();
2180 }
2181 return fut.get();
2182}
std::string handle_on_main(const std::string &method, const json &params, const json &id)
Definition McpControl.cpp:2017
std::string rpc_error(const json &id, int code, const std::string &msg)
Definition McpControl.cpp:112

References dispatch_request(), handle_on_main(), and rpc_error().

Referenced by dispatch_request(), and serve_client().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ edge_ids_arg()

std::vector< int > Slic3r::GUI::anonymous_namespace{McpControl.cpp}::edge_ids_arg ( const json & params,
const char * verb )
880{
881 if (!params.contains("edge"))
882 throw std::runtime_error(std::string(verb) + " needs 'edge' (id or array of ids from query_topology)");
883 const json& e = params["edge"];
884 std::vector<int> ids;
885 if (e.is_array()) for (const json& v : e) ids.push_back(v.get<int>());
886 else ids.push_back(e.get<int>());
887 if (ids.empty()) throw std::runtime_error(std::string(verb) + ": 'edge' is an empty array");
888 return ids;
889}

References edge_ids_arg().

Referenced by action_chamfer(), action_fillet(), and edge_ids_arg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ feature_type_name()

const char * Slic3r::GUI::anonymous_namespace{McpControl.cpp}::feature_type_name ( CadFeatureType t)
69{
70 switch (t) {
71 case CadFeatureType::Sketch: return "Sketch";
72 case CadFeatureType::Extrude: return "Extrude";
73 case CadFeatureType::Fillet: return "Fillet";
74 case CadFeatureType::Chamfer: return "Chamfer";
75 case CadFeatureType::Hole: return "Hole";
76 case CadFeatureType::Thread: return "Thread";
77 case CadFeatureType::Shell: return "Shell";
78 case CadFeatureType::Revolve: return "Revolve";
79 case CadFeatureType::Sweep: return "Sweep";
80 case CadFeatureType::Pattern: return "Pattern";
81 case CadFeatureType::Plane: return "Plane";
82 case CadFeatureType::Loft: return "Loft";
83 case CadFeatureType::Draft: return "Draft";
84 case CadFeatureType::Import: return "Import";
85 case CadFeatureType::Boolean: return "Boolean";
86 case CadFeatureType::Cut: return "Cut";
87 case CadFeatureType::Mirror: return "Mirror";
88 case CadFeatureType::Axis: return "Axis";
89 case CadFeatureType::CoordSys: return "CoordSys";
90 case CadFeatureType::Helix: return "Helix";
91 case CadFeatureType::Transform: return "Transform";
92 case CadFeatureType::Thicken: return "Thicken";
93 case CadFeatureType::Project: return "Project";
94 case CadFeatureType::DeleteFace: return "DeleteFace";
95 case CadFeatureType::Rib: return "Rib";
96 case CadFeatureType::SurfaceExtrude: return "SurfaceExtrude";
97 case CadFeatureType::SurfaceRevolve: return "SurfaceRevolve";
98 case CadFeatureType::ThickenSurface: return "ThickenSurface";
99 case CadFeatureType::SurfaceOffset: return "SurfaceOffset";
100 case CadFeatureType::SurfaceLoft: return "SurfaceLoft";
101 case CadFeatureType::SurfaceFill: return "SurfaceFill";
102 case CadFeatureType::Mate: return "Mate";
103 }
104 return "Unknown";
105}
@ Fillet
Definition CadDocument.hpp:26
@ Plane
Definition CadDocument.hpp:26
@ Mirror
Definition CadDocument.hpp:26
@ Boolean
Definition CadDocument.hpp:26
@ Transform
Definition CadDocument.hpp:26
@ Rib
Definition CadDocument.hpp:26
@ SurfaceOffset
Definition CadDocument.hpp:26
@ Axis
Definition CadDocument.hpp:26
@ DeleteFace
Definition CadDocument.hpp:26
@ Sketch
Definition CadDocument.hpp:26
@ Pattern
Definition CadDocument.hpp:26
@ Hole
Definition CadDocument.hpp:26
@ Import
Definition CadDocument.hpp:26
@ SurfaceFill
Definition CadDocument.hpp:26
@ SurfaceLoft
Definition CadDocument.hpp:26
@ Helix
Definition CadDocument.hpp:26
@ Sweep
Definition CadDocument.hpp:26
@ Thicken
Definition CadDocument.hpp:26
@ Revolve
Definition CadDocument.hpp:26
@ Project
Definition CadDocument.hpp:26
@ Mate
Definition CadDocument.hpp:26
@ SurfaceExtrude
Definition CadDocument.hpp:26
@ Loft
Definition CadDocument.hpp:26
@ CoordSys
Definition CadDocument.hpp:26
@ Thread
Definition CadDocument.hpp:26
@ SurfaceRevolve
Definition CadDocument.hpp:26
@ Chamfer
Definition CadDocument.hpp:26
@ Shell
Definition CadDocument.hpp:26
@ Cut
Definition CadDocument.hpp:26
@ Draft
Definition CadDocument.hpp:26
@ Extrude
Definition CadDocument.hpp:26
@ ThickenSurface
Definition CadDocument.hpp:26

References Slic3r::Axis, Slic3r::Boolean, Slic3r::Chamfer, Slic3r::CoordSys, Slic3r::Cut, Slic3r::DeleteFace, Slic3r::Draft, Slic3r::Extrude, feature_type_name(), Slic3r::Fillet, Slic3r::Helix, Slic3r::Hole, Slic3r::Import, Slic3r::Loft, Slic3r::Mate, Slic3r::Mirror, Slic3r::Pattern, Slic3r::Plane, Slic3r::Project, Slic3r::Revolve, Slic3r::Rib, Slic3r::Shell, Slic3r::Sketch, Slic3r::SurfaceExtrude, Slic3r::SurfaceFill, Slic3r::SurfaceLoft, Slic3r::SurfaceOffset, Slic3r::SurfaceRevolve, Slic3r::Sweep, Slic3r::Thicken, Slic3r::ThickenSurface, Slic3r::Thread, and Slic3r::Transform.

Referenced by describe_scene(), and feature_type_name().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ handle_on_main()

std::string Slic3r::GUI::anonymous_namespace{McpControl.cpp}::handle_on_main ( const std::string & method,
const json & params,
const json & id )
2018{
2019 // The panel is built on first use, and in a headless session nobody clicks the tab that
2020 // would build it -- so build it here rather than refusing. Safe: this runs on the main
2021 // thread (see the CallAfter that dispatches us).
2023 if (!panel)
2024 return rpc_error(id, -32001, "Design panel not ready");
2025 // A project opened without ever showing the Design tab has its recipe only in the Model;
2026 // load it, as showing the tab would, before anything reads or writes the document.
2027 panel->hydrate_from_model();
2028
2029 // Methods that only LOOK. Everything else changes the document or the live sketch, and
2030 // must not do it under a GUI editor, a sketch session it does not own, or a rebuild in
2031 // progress (the GUI's worker thread holds the document then).
2032 static const std::set<std::string> kReadOnly = {
2033 "describe_tools", "describe_scene", "query_topology", "measure", "mass_properties",
2034 "slice_body", "validate_against", "list_verbs", "sketch_describe", "sketch_validate",
2035 "check_interference" };
2036 if (kReadOnly.count(method) == 0) {
2037 std::string why;
2038 if (panel->mcp_busy(method.rfind("sketch_", 0) == 0, why))
2039 return rpc_error(id, -32002, "Design tab busy: " + why);
2040 }
2041
2042 // Stale-id guard, checked here rather than in each handler.
2043 //
2044 // Global face and edge ids are indices into TopExp::MapShapes, valid only against the
2045 // topology that produced them. Every dress-up rewrites those maps, so the natural way to
2046 // drive this socket — read the scene once, then issue several operations — silently
2047 // addresses the WRONG edge on every call after the first. Measured on a box: four chamfers
2048 // with ids re-read each time remove 0.400/0.397/0.397/0.395 mm3; the same four with ids
2049 // captured up front remove 0.400/0.008/0.397/0.280. Neither run errors, because a stale id
2050 // still resolves to a real edge — just not the one that was asked for.
2051 //
2052 // So a caller may pass back the "generation" it got from describe_scene or query_topology,
2053 // and a mismatch is refused instead of silently obeyed. Optional by design: omitting it
2054 // keeps every existing script working exactly as before, and supplying it is what buys the
2055 // guarantee. One check at the dispatcher rather than one per handler, so a method added
2056 // later cannot forget it.
2057 //
2058 // The type check is not decoration: this runs OUTSIDE the try below, and a bare
2059 // get<uint64_t>() on `"generation": "x"` throws nlohmann::type_error straight out of
2060 // the CallAfter lambda that invoked us — through a wx event loop, which does not catch,
2061 // so the whole GUI went down on one malformed line. Refuse it as a parameter error.
2062 if (params.is_object() && params.contains("generation")) {
2063 if (!params["generation"].is_number_unsigned())
2064 return rpc_error(id, -32602, "generation must be an unsigned integer");
2065 const uint64_t want = params["generation"].get<uint64_t>();
2066 const uint64_t have = panel->mcp_doc().topo_generation;
2067 if (want != have)
2068 return rpc_error(id, -32010,
2069 "stale face/edge ids: they were read at generation " + std::to_string(want)
2070 + " but the model is now at " + std::to_string(have)
2071 + ". Re-read query_topology and use the new ids — the old ones still name real "
2072 "edges, just not the ones you measured.");
2073 }
2074
2075 try {
2076 if (method == "describe_tools") return rpc_result(id, describe_tools());
2077 if (method == "describe_scene") return rpc_result(id, describe_scene(panel));
2078 if (method == "query_topology") return rpc_result(id, query_topology(panel, params));
2079 if (method == "measure") return rpc_result(id, measure(panel, params));
2080 if (method == "mass_properties") return rpc_result(id, mass_properties(panel, params));
2081 if (method == "slice_body") return rpc_result(id, slice_body(panel, params));
2082 if (method == "import_step") return rpc_result(id, import_step(panel, params));
2083 if (method == "import_mesh") return rpc_result(id, import_mesh(panel, params));
2084 if (method == "validate_against") return rpc_result(id, validate_against(panel, params));
2085 if (method == "extrude") return rpc_result(id, action_extrude(panel, params));
2086 if (method == "revolve") return rpc_result(id, action_revolve(panel, params));
2087 if (method == "fillet") return rpc_result(id, action_fillet(panel, params));
2088 if (method == "chamfer") return rpc_result(id, action_chamfer(panel, params));
2089 if (method == "hole") return rpc_result(id, action_hole(panel, params));
2090 if (method == "hole_styled") return rpc_result(id, action_hole_styled(panel, params));
2091 if (method == "hole_standard") return rpc_result(id, action_hole_standard(panel, params));
2092 if (method == "boolean") return rpc_result(id, action_boolean(panel, params));
2093 if (method == "pattern") return rpc_result(id, action_pattern(panel, params));
2094 if (method == "pattern_on_curve") return rpc_result(id, action_pattern_on_curve(panel, params));
2095 if (method == "shell") return rpc_result(id, action_shell(panel, params));
2096 if (method == "rib") return rpc_result(id, action_rib(panel, params));
2097 if (method == "draft") return rpc_result(id, action_draft(panel, params));
2098 if (method == "mirror") return rpc_result(id, action_mirror(panel, params));
2099 if (method == "sketch_begin") return rpc_result(id, action_sketch_begin(panel, params));
2100 if (method == "sketch_commit") return rpc_result(id, action_sketch_commit(panel, params));
2101 if (method == "sketch_cancel") return rpc_result(id, action_sketch_cancel(panel, params));
2102 if (method == "sketch_add") return rpc_result(id, action_sketch_add(panel, params));
2103 if (method == "sketch_select") return rpc_result(id, action_sketch_select(panel, params));
2104 if (method == "sketch_delete") return rpc_result(id, action_sketch_delete(panel, params));
2105 if (method == "sketch_construction") return rpc_result(id, action_sketch_construction(panel, params));
2106 if (method == "sketch_offset") return rpc_result(id, action_sketch_offset(panel, params));
2107 if (method == "sketch_mirror") return rpc_result(id, action_sketch_mirror(panel, params));
2108 if (method == "sketch_describe") return rpc_result(id, action_sketch_describe(panel, params));
2109 if (method == "sketch_validate") return rpc_result(id, action_sketch_validate(panel, params));
2110 if (method == "sketch_heal") return rpc_result(id, action_sketch_heal(panel, params));
2111 if (method == "sketch_set_value") return rpc_result(id, action_sketch_set_value(panel, params));
2112 if (method == "list_verbs") return rpc_result(id, action_list_verbs(panel, params));
2113 if (method == "run_verb") return rpc_result(id, action_run_verb(panel, params));
2114 if (method == "transform") return rpc_result(id, action_transform(panel, params));
2115 if (method == "thicken") return rpc_result(id, action_thicken(panel, params));
2116 if (method == "split") return rpc_result(id, action_split(panel, params));
2117 if (method == "project") return rpc_result(id, action_project(panel, params));
2118 if (method == "delete_face") return rpc_result(id, action_delete_face(panel, params));
2119 if (method == "bridge") return rpc_result(id, action_bridge(panel, params));
2120 if (method == "axis") return rpc_result(id, action_axis(panel, params));
2121 if (method == "coordsys") return rpc_result(id, action_coordsys(panel, params));
2122 if (method == "helix") return rpc_result(id, action_helix(panel, params));
2123 if (method == "set_variable") return rpc_result(id, action_set_variable(panel, params));
2124 if (method == "set_feature_expr") return rpc_result(id, action_set_feature_expr(panel, params));
2125 if (method == "surface_extrude") return rpc_result(id, action_surface_extrude(panel, params));
2126 if (method == "surface_revolve") return rpc_result(id, action_surface_revolve(panel, params));
2127 if (method == "thicken_surface") return rpc_result(id, action_thicken_surface(panel, params));
2128 if (method == "surface_offset") return rpc_result(id, action_surface_offset(panel, params));
2129 if (method == "surface_loft") return rpc_result(id, action_surface_loft(panel, params));
2130 if (method == "surface_fill") return rpc_result(id, action_surface_fill(panel, params));
2131 if (method == "mate") return rpc_result(id, action_mate(panel, params));
2132 if (method == "check_interference") return rpc_result(id, action_check_interference(panel, params));
2133 return rpc_error(id, -32601, "Unknown method: " + method);
2134 } catch (const Standard_Failure& ex) { // derives from std::exception, so it comes first
2135 return rpc_error(id, -32000, std::string("OCCT: ") + (*ex.what() ? ex.what() : "failure"));
2136 } catch (const std::exception& ex) {
2137 return rpc_error(id, -32000, ex.what());
2138 }
2139}
Definition DesignPanel.hpp:64
bool mcp_busy(bool sketch_method, std::string &why) const
Definition DesignPanel.cpp:4884
void hydrate_from_model()
Definition DesignPanel.cpp:7412
static DesignPanel * ensure()
Definition Lazy.hpp:186
json mass_properties(DesignPanel *panel, const json &params)
Definition McpControl.cpp:571
json action_sketch_offset(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1460
std::string rpc_result(const json &id, const json &result)
Definition McpControl.cpp:108
json action_helix(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1930
json action_hole_standard(DesignPanel *panel, const json &params)
Definition McpControl.cpp:971
json action_sketch_cancel(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1384
json action_coordsys(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1904
json import_mesh(DesignPanel *panel, const json &params)
Definition McpControl.cpp:698
json action_bridge(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1853
json action_chamfer(DesignPanel *panel, const json &params)
Definition McpControl.cpp:909
json action_draft(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1178
json action_thicken(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1783
json action_rib(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1072
json action_sketch_set_value(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1581
json import_step(DesignPanel *panel, const json &params)
Definition McpControl.cpp:668
json action_surface_loft(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1149
json describe_tools()
Definition McpControl.cpp:120
json action_mirror(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1748
json action_surface_extrude(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1091
json action_project(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1818
json describe_scene(DesignPanel *panel)
Definition McpControl.cpp:406
json measure(DesignPanel *panel, const json &params)
Definition McpControl.cpp:555
json action_sketch_begin(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1354
json action_hole(DesignPanel *panel, const json &params)
Definition McpControl.cpp:927
json action_check_interference(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1963
json action_sketch_add(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1394
json action_delete_face(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1836
json action_boolean(DesignPanel *panel, const json &params)
Definition McpControl.cpp:996
json action_pattern_on_curve(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1037
json action_surface_fill(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1165
json query_topology(DesignPanel *panel, const json &params)
Definition McpControl.cpp:489
json action_sketch_mirror(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1477
json action_surface_offset(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1135
json action_run_verb(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1692
json action_extrude(DesignPanel *panel, const json &params)
Definition McpControl.cpp:802
json action_surface_revolve(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1105
json action_sketch_describe(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1519
json action_pattern(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1017
json action_shell(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1056
json action_sketch_select(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1425
json action_hole_styled(DesignPanel *panel, const json &params)
Definition McpControl.cpp:945
json slice_body(DesignPanel *panel, const json &params)
Definition McpControl.cpp:632
json action_revolve(DesignPanel *panel, const json &params)
Definition McpControl.cpp:840
json action_thicken_surface(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1120
json action_sketch_delete(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1436
json action_sketch_heal(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1563
json action_split(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1800
json action_set_feature_expr(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1994
json action_mate(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1944
json action_list_verbs(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1659
json action_sketch_validate(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1554
json action_axis(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1873
json validate_against(DesignPanel *panel, const json &params)
Definition McpControl.cpp:760
json action_fillet(DesignPanel *panel, const json &params)
Definition McpControl.cpp:891
json action_sketch_construction(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1449
json action_sketch_commit(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1373
json action_set_variable(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1976
json action_transform(DesignPanel *panel, const json &params)
Definition McpControl.cpp:1765

References action_axis(), action_boolean(), action_bridge(), action_chamfer(), action_check_interference(), action_coordsys(), action_delete_face(), action_draft(), action_extrude(), action_fillet(), action_helix(), action_hole(), action_hole_standard(), action_hole_styled(), action_list_verbs(), action_mate(), action_mirror(), action_pattern(), action_pattern_on_curve(), action_project(), action_revolve(), action_rib(), action_run_verb(), action_set_feature_expr(), action_set_variable(), action_shell(), action_sketch_add(), action_sketch_begin(), action_sketch_cancel(), action_sketch_commit(), action_sketch_construction(), action_sketch_delete(), action_sketch_describe(), action_sketch_heal(), action_sketch_mirror(), action_sketch_offset(), action_sketch_select(), action_sketch_set_value(), action_sketch_validate(), action_split(), action_surface_extrude(), action_surface_fill(), action_surface_loft(), action_surface_offset(), action_surface_revolve(), action_thicken(), action_thicken_surface(), action_transform(), describe_scene(), describe_tools(), Slic3r::GUI::LazyInstance< DesignPanel >::ensure(), handle_on_main(), Slic3r::GUI::DesignPanel::hydrate_from_model(), import_mesh(), import_step(), mass_properties(), Slic3r::GUI::DesignPanel::mcp_busy(), Slic3r::GUI::DesignPanel::mcp_doc(), measure(), query_topology(), rpc_error(), rpc_result(), slice_body(), Slic3r::CadDocument::topo_generation, and validate_against().

Referenced by dispatch_request(), and handle_on_main().

Here is the caller graph for this function:

◆ import_mesh()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::import_mesh ( DesignPanel * panel,
const json & params )
699{
700 if (!params.contains("path")) throw std::runtime_error("import_mesh needs 'path'");
701 const std::string path = params["path"].get<std::string>();
702 const double tolerance = params.value("tolerance", 0.01);
703 const double merge_angle_deg = params.value("merge_angle_deg", 5.0);
704
705 TriangleMesh mesh;
706 const std::string ext = boost::algorithm::to_lower_copy(
707 boost::filesystem::path(path).extension().string());
708 if (ext == ".stl") {
709 if (!mesh.ReadSTLFile(path.c_str())) throw std::runtime_error("could not read STL: " + path);
710 } else if (ext == ".obj") {
711 ObjInfo obj_info; std::string obj_err;
712 if (!load_obj(path.c_str(), &mesh, obj_info, obj_err))
713 throw std::runtime_error("could not read OBJ: " + obj_err);
714 } else {
715 throw std::runtime_error("unsupported mesh format (want .stl or .obj): " + ext);
716 }
717
718 GeometryEngine::MeshBrepStats st;
719 const TopoDS_Shape shape = GeometryEngine::mesh_to_brep(mesh.its, tolerance, merge_angle_deg, st);
720 if (shape.IsNull()) throw std::runtime_error("mesh conversion produced no geometry");
721
722 CadDocument& doc = panel->mcp_doc();
723 doc.checkpoint();
724 const int first = int(doc.features.size());
725 CadFeature f;
727 f.name = "Mesh" + std::to_string(first + 1);
728 f.imported_solid = shape;
729 f.mode = BooleanMode::New;
730 doc.features.push_back(f);
731
732 const bool ok = doc.recompute();
733 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
734 panel->mcp_after_change();
735 return json{{"ok", ok}, {"first_feature", first}, {"bodies", int(doc.bodies.size())},
736 {"input_triangles", st.input_tris}, {"kept_triangles", st.kept_tris},
737 {"degenerate_collapsed", st.degenerate_collapsed},
738 {"degenerate_sliver", st.degenerate_sliver},
739 {"faces_built", st.faces_built}, {"faces_failed", st.faces_failed},
740 {"faces_final", st.faces_final}, {"unique_edges", st.unique_edges},
741 {"boundary_edges", st.boundary_edges},
742 {"nonmanifold_edges", st.nonmanifold_edges},
743 {"watertight", st.watertight}, {"is_solid", st.is_solid},
744 {"volume", st.volume}, {"error", doc.error}};
745}
static TopoDS_Shape mesh_to_brep(const indexed_triangle_set &its, double tolerance, double merge_angle_deg, MeshBrepStats &stats)
Definition GeometryEngine.cpp:109
Definition TriangleMesh.hpp:94
indexed_triangle_set its
Definition TriangleMesh.hpp:164
bool ReadSTLFile(const char *input_file, bool repair=true, ImportstlProgressFn stlFn=nullptr, int custom_header_length=80)
Definition TriangleMesh.cpp:228
bool load_obj(const char *path, TriangleMesh *meshptr, ObjInfo &obj_info, std::string &message, ObjParser::MtlData *out_mtl)
Definition OBJ.cpp:38
Definition OBJ.hpp:19

References Slic3r::CadDocument::bodies, Slic3r::GeometryEngine::MeshBrepStats::boundary_edges, Slic3r::CadDocument::checkpoint(), Slic3r::GeometryEngine::MeshBrepStats::degenerate_collapsed, Slic3r::GeometryEngine::MeshBrepStats::degenerate_sliver, Slic3r::CadDocument::error, Slic3r::f(), Slic3r::GeometryEngine::MeshBrepStats::faces_built, Slic3r::GeometryEngine::MeshBrepStats::faces_failed, Slic3r::GeometryEngine::MeshBrepStats::faces_final, Slic3r::CadDocument::features, Slic3r::Import, import_mesh(), Slic3r::GeometryEngine::MeshBrepStats::input_tris, Slic3r::GeometryEngine::MeshBrepStats::is_solid, Slic3r::TriangleMesh::its, Slic3r::GeometryEngine::MeshBrepStats::kept_tris, Slic3r::load_obj(), Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::GeometryEngine::mesh_to_brep(), Slic3r::New, Slic3r::GeometryEngine::MeshBrepStats::nonmanifold_edges, Slic3r::TriangleMesh::ReadSTLFile(), Slic3r::CadDocument::recompute(), Slic3r::CadDocument::undo(), Slic3r::GeometryEngine::MeshBrepStats::unique_edges, Slic3r::GeometryEngine::MeshBrepStats::volume, and Slic3r::GeometryEngine::MeshBrepStats::watertight.

Referenced by handle_on_main(), and import_mesh().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ import_step()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::import_step ( DesignPanel * panel,
const json & params )
669{
670 if (!params.contains("path")) throw std::runtime_error("import_step needs 'path'");
671 const std::string path = params["path"].get<std::string>();
672 std::string err;
673 std::vector<TopoDS_Shape> solids = GeometryEngine::read_step_solids(path, err);
674 if (solids.empty()) throw std::runtime_error(err.empty() ? "no solids in STEP" : err);
675
676 CadDocument& doc = panel->mcp_doc();
677 doc.checkpoint();
678 int first = int(doc.features.size());
679 for (const TopoDS_Shape& s : solids) {
682 f.name = "STEP" + std::to_string(int(doc.features.size()) + 1);
683 f.imported_solid = s;
684 f.mode = BooleanMode::New; // each solid = its own coexisting body
685 doc.features.push_back(f);
686 }
687 bool ok = doc.recompute();
688 if (!ok) { const std::string why = doc.error; doc.undo(); doc.error = why; }
689 panel->mcp_after_change();
690 return json{{"ok", ok}, {"imported", int(solids.size())}, {"first_feature", first},
691 {"bodies", int(doc.bodies.size())}, {"error", doc.error}};
692}
static std::vector< TopoDS_Shape > read_step_solids(const std::string &path, std::string &err)
Definition GeometryEngine.cpp:70

References Slic3r::CadDocument::bodies, Slic3r::CadDocument::checkpoint(), Slic3r::CadDocument::error, Slic3r::f(), Slic3r::CadDocument::features, Slic3r::Import, import_step(), Slic3r::GUI::DesignPanel::mcp_after_change(), Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::New, Slic3r::GeometryEngine::read_step_solids(), Slic3r::CadDocument::recompute(), and Slic3r::CadDocument::undo().

Referenced by handle_on_main(), and import_step().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mass_properties()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::mass_properties ( DesignPanel * panel,
const json & params )
572{
573 const TopoDS_Shape& shape = body_shape(panel, params);
574 auto mp = GeometryEngine::mass_properties(shape);
575 if (!mp.valid) throw std::runtime_error("mass properties could not be computed (null/empty shape)");
576 // A sheet body has no volume and no inertia. Report the area and say so, rather than
577 // returning numbers a caller would reasonably treat as a material check.
578 if (!mp.is_solid)
579 return json{
580 {"surface_area", mp.surface_area},
581 {"volume", 0.0},
582 {"is_solid", false},
583 {"valid", mp.valid},
584 {"note", "sheet body (open shell): it encloses no material, so volume and inertia "
585 "are not defined; surface_area is exact"},
586 };
587 return json{
588 {"volume", mp.volume},
589 {"surface_area", mp.surface_area},
590 {"center_of_mass", json::array({mp.center_of_mass.x(), mp.center_of_mass.y(), mp.center_of_mass.z()})},
591 {"inertia", mp.inertia},
592 {"is_solid", true},
593 {"valid", mp.valid},
594 };
595}
static MassProps mass_properties(const TopoDS_Shape &shape)
Definition GeometryEngine.cpp:482
const TopoDS_Shape & body_shape(DesignPanel *panel, const json &params)
Definition McpControl.cpp:478

References body_shape(), Slic3r::GeometryEngine::mass_properties(), and mass_properties().

Referenced by handle_on_main(), and mass_properties().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ mcp_sketch()

DesignSketchTool & Slic3r::GUI::anonymous_namespace{McpControl.cpp}::mcp_sketch ( DesignPanel * panel)
1216{
1217 DesignCanvas* vp = panel->mcp_viewport();
1218 if (vp == nullptr) throw std::runtime_error("no viewport");
1219 if (!vp->is_sketching())
1220 throw std::runtime_error("no sketch is open — call sketch_begin first");
1221 return vp->mcp_sketch_tool();
1222}
DesignSketchTool & mcp_sketch_tool()
Definition DesignCanvas.hpp:381

References Slic3r::GUI::DesignCanvas::is_sketching(), mcp_sketch(), Slic3r::GUI::DesignCanvas::mcp_sketch_tool(), and Slic3r::GUI::DesignPanel::mcp_viewport().

Referenced by action_sketch_add(), action_sketch_construction(), action_sketch_delete(), action_sketch_describe(), action_sketch_heal(), action_sketch_mirror(), action_sketch_offset(), action_sketch_select(), action_sketch_set_value(), action_sketch_validate(), and mcp_sketch().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ measure()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::measure ( DesignPanel * panel,
const json & params )
556{
557 const TopoDS_Shape& shape = body_shape(panel, params);
558 Vec3d pa, pb, da, db; bool hda = false, hdb = false;
559 if (!params.contains("a") || !params.contains("b"))
560 throw std::runtime_error("measure needs refs 'a' and 'b' ({face|edge|point})");
561 if (!resolve_ref(shape, params["a"], pa, da, hda) || !resolve_ref(shape, params["b"], pb, db, hdb))
562 throw std::runtime_error("could not resolve a measurement reference");
563 json r{{"distance", (pa - pb).norm()}, {"point_a", vec3(pa)}, {"point_b", vec3(pb)}};
564 if (hda && hdb) {
565 double c = std::max(-1.0, std::min(1.0, da.normalized().dot(db.normalized())));
566 r["angle_deg"] = std::acos(c) * 180.0 / M_PI;
567 }
568 return r;
569}
#define M_PI
Definition ExtrusionSimulator.cpp:31
json vec3(const Vec3d &v)
Definition McpControl.cpp:449
bool resolve_ref(const TopoDS_Shape &shape, const json &ref, Vec3d &point, Vec3d &dir, bool &has_dir)
Definition McpControl.cpp:533

References body_shape(), M_PI, measure(), resolve_ref(), and vec3().

Referenced by handle_on_main(), and measure().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ plane_from()

SketchPlane Slic3r::GUI::anonymous_namespace{McpControl.cpp}::plane_from ( const json & params,
const CadDocument & doc )
453{
454 std::string n = params.value("plane", std::string("XY"));
455 SketchPlane pl = n == "XZ" ? SketchPlane::XZ() : n == "YZ" ? SketchPlane::YZ() : SketchPlane::XY();
456 pl.origin = doc.modeling_origin; // land on the bed centre, like the GUI
457 return pl;
458}
Vec3d origin
Definition SketchEngine.hpp:51

References Slic3r::CadDocument::modeling_origin, Slic3r::SketchPlane::origin, plane_from(), Slic3r::SketchPlane::XY(), Slic3r::SketchPlane::XZ(), and Slic3r::SketchPlane::YZ().

Referenced by action_extrude(), action_helix(), action_hole(), action_hole_standard(), action_hole_styled(), action_mirror(), action_pattern(), action_project(), action_revolve(), and plane_from().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ profile_from()

bool Slic3r::GUI::anonymous_namespace{McpControl.cpp}::profile_from ( const json & params,
SketchProfile & out )
469{
470 if (!params.contains("profile")) return false;
471 out.points.clear();
472 for (const auto& p : params["profile"]) out.points.emplace_back(p[0].get<double>(), p[1].get<double>());
473 out.closed = true;
474 return out.points.size() >= 3;
475}
bool closed
Definition SketchEngine.hpp:73
std::vector< Vec2d > points
Definition SketchEngine.hpp:72

References Slic3r::SketchProfile::closed, Slic3r::SketchProfile::points, and profile_from().

Referenced by action_extrude(), action_revolve(), and profile_from().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ query_topology()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::query_topology ( DesignPanel * panel,
const json & params )
490{
491 const TopoDS_Shape& shape = body_shape(panel, params);
492 // Enumerate once. The _by_index accessors rescan the shape on every call (edge_by_index
493 // rebuilds the whole indexed map), so indexing a body face-by-face is quadratic: ~15 s on a
494 // 4.7k-face imported solid, on the UI thread. faces_of/edges_of keep the very same ids.
495 const std::vector<TopoDS_Face> all_faces = GeometryEngine::faces_of(shape);
496 const std::vector<TopoDS_Edge> all_edges = GeometryEngine::edges_of(shape);
497
498 json faces = json::array();
499 const int nf = int(all_faces.size());
500 for (int i = 0; i < nf; ++i) {
501 const TopoDS_Face& f = all_faces[i];
502 if (f.IsNull()) continue;
503 json jf{{"id", i}, {"centroid", vec3(GeometryEngine::face_centroid_world(f))},
504 {"normal", vec3(GeometryEngine::face_normal_world(f))}, {"kind", "planar"}};
505 GeometryEngine::CylinderFace cyl = GeometryEngine::cylinder_of_face(f);
506 if (cyl.ok) { jf["kind"] = "cylindrical"; jf["radius"] = cyl.radius;
507 jf["axis"] = vec3(cyl.axis); jf["internal"] = cyl.internal; }
508 faces.push_back(std::move(jf));
509 }
510 json edges = json::array();
511 const int ne = int(all_edges.size());
512 for (int i = 0; i < ne; ++i) {
513 const TopoDS_Edge& e = all_edges[i];
514 if (e.IsNull()) continue;
515 std::vector<Vec3d> pts = GeometryEngine::sample_edge_world(e);
516 if (pts.size() < 2) continue;
517 double len = 0; for (size_t k = 1; k < pts.size(); ++k) len += (pts[k] - pts[k-1]).norm();
518 json je{{"id", i}, {"length", len}, {"p0", vec3(pts.front())}, {"p1", vec3(pts.back())},
519 {"kind", "line"}};
520 GeometryEngine::CylinderFace circ = GeometryEngine::circle_of_edge(e);
521 if (circ.ok) { je["kind"] = "circle"; je["radius"] = circ.radius; je["center"] = vec3(circ.base); }
522 edges.push_back(std::move(je));
523 }
524 return json{{"body", params.value("body", 0)}, {"face_count", nf}, {"edge_count", ne},
525 {"faces", std::move(faces)}, {"edges", std::move(edges)},
526 // The ids above are indices into this exact topology and expire with it. Echo
527 // this back as "generation" on the calls that consume them.
528 {"generation", panel->mcp_doc().topo_generation}};
529}
static CylinderFace circle_of_edge(const TopoDS_Edge &edge)
Definition GeometryEngine.cpp:675
static Vec3d face_normal_world(const TopoDS_Face &face)
Definition GeometryEngine.cpp:627
static std::vector< TopoDS_Face > faces_of(const TopoDS_Shape &shape)
Definition GeometryEngine.cpp:546
static std::vector< TopoDS_Edge > edges_of(const TopoDS_Shape &shape)
Definition GeometryEngine.cpp:554
static std::vector< Vec3d > sample_edge_world(const TopoDS_Edge &edge, double chord_tol=0.05)
Definition GeometryEngine.cpp:575
static CylinderFace cylinder_of_face(const TopoDS_Face &face)
Definition GeometryEngine.cpp:639
static Vec3d face_centroid_world(const TopoDS_Face &face)
Definition GeometryEngine.cpp:619

References Slic3r::GeometryEngine::CylinderFace::axis, Slic3r::GeometryEngine::CylinderFace::base, body_shape(), Slic3r::GeometryEngine::circle_of_edge(), Slic3r::GeometryEngine::cylinder_of_face(), Slic3r::GeometryEngine::edges_of(), Slic3r::f(), Slic3r::GeometryEngine::face_centroid_world(), Slic3r::GeometryEngine::face_normal_world(), Slic3r::GeometryEngine::faces_of(), Slic3r::GeometryEngine::CylinderFace::internal, Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::GeometryEngine::CylinderFace::ok, query_topology(), Slic3r::GeometryEngine::CylinderFace::radius, Slic3r::GeometryEngine::sample_edge_world(), Slic3r::CadDocument::topo_generation, and vec3().

Referenced by handle_on_main(), and query_topology().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ remove_socket_at_exit()

void Slic3r::GUI::anonymous_namespace{McpControl.cpp}::remove_socket_at_exit ( )
2223{
2224 struct stat st{};
2225 if (!g_sock_path.empty() && ::lstat(g_sock_path.c_str(), &st) == 0 && S_ISSOCK(st.st_mode))
2226 ::unlink(g_sock_path.c_str());
2227}
std::string g_sock_path
Definition McpControl.cpp:2220

References g_sock_path, and remove_socket_at_exit().

Referenced by remove_socket_at_exit(), and server_thread().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ resolve_ref()

bool Slic3r::GUI::anonymous_namespace{McpControl.cpp}::resolve_ref ( const TopoDS_Shape & shape,
const json & ref,
Vec3d & point,
Vec3d & dir,
bool & has_dir )
534{
535 has_dir = false;
536 if (ref.contains("point")) { auto p = ref["point"]; point = Vec3d(p[0], p[1], p[2]); return true; }
537 if (ref.contains("face")) {
538 TopoDS_Face f = GeometryEngine::face_by_index(shape, ref["face"].get<int>());
539 if (f.IsNull()) return false;
541 dir = GeometryEngine::face_normal_world(f); has_dir = true; return true;
542 }
543 if (ref.contains("edge")) {
544 TopoDS_Edge e = GeometryEngine::edge_by_index(shape, ref["edge"].get<int>());
545 if (e.IsNull()) return false;
546 std::vector<Vec3d> pts = GeometryEngine::sample_edge_world(e);
547 if (pts.empty()) return false;
548 point = pts[pts.size() / 2]; // midpoint sample
549 if (pts.size() >= 2) { dir = (pts.back() - pts.front()).normalized(); has_dir = true; }
550 return true;
551 }
552 return false;
553}
static TopoDS_Face face_by_index(const TopoDS_Shape &shape, int index)
Definition GeometryEngine.cpp:534
static TopoDS_Edge edge_by_index(const TopoDS_Shape &shape, int index)
Definition GeometryEngine.cpp:717

References Slic3r::GeometryEngine::edge_by_index(), Slic3r::f(), Slic3r::GeometryEngine::face_by_index(), Slic3r::GeometryEngine::face_centroid_world(), Slic3r::GeometryEngine::face_normal_world(), resolve_ref(), and Slic3r::GeometryEngine::sample_edge_world().

Referenced by measure(), and resolve_ref().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ rpc_error()

std::string Slic3r::GUI::anonymous_namespace{McpControl.cpp}::rpc_error ( const json & id,
int code,
const std::string & msg )
113{
114 return json{{"jsonrpc", "2.0"}, {"id", id},
115 {"error", {{"code", code}, {"message", msg}}}}.dump();
116}

References rpc_error().

Referenced by dispatch_request(), handle_on_main(), and rpc_error().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ rpc_result()

std::string Slic3r::GUI::anonymous_namespace{McpControl.cpp}::rpc_result ( const json & id,
const json & result )
109{
110 return json{{"jsonrpc", "2.0"}, {"id", id}, {"result", result}}.dump();
111}

References rpc_result().

Referenced by handle_on_main(), and rpc_result().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ serve_client()

void Slic3r::GUI::anonymous_namespace{McpControl.cpp}::serve_client ( int cfd)
2188{
2189 constexpr size_t kMaxLine = 16u << 20; // 16 MB — far above any real request
2190 std::string buf;
2191 char chunk[4096];
2192 for (;;) {
2193 ssize_t n = ::read(cfd, chunk, sizeof(chunk));
2194 if (n <= 0) break;
2195 buf.append(chunk, size_t(n));
2196 if (buf.size() > kMaxLine && buf.find('\n') == std::string::npos) {
2197 BOOST_LOG_TRIVIAL(error) << "MCP: request line over " << kMaxLine << " bytes; closing the connection";
2198 return;
2199 }
2200 size_t nl;
2201 while ((nl = buf.find('\n')) != std::string::npos) {
2202 std::string line = buf.substr(0, nl);
2203 buf.erase(0, nl + 1);
2204 if (line.empty()) continue;
2205 std::string reply = dispatch_request(line);
2206 reply.push_back('\n');
2207 // Never a bare write(): a client that hangs up between its request and our
2208 // reply raises SIGPIPE, whose default action kills the process — so closing
2209 // a socket mid-call would take the GUI with it.
2210#ifdef MSG_NOSIGNAL
2211 if (::send(cfd, reply.data(), reply.size(), MSG_NOSIGNAL) < 0) return;
2212#else
2213 if (::write(cfd, reply.data(), reply.size()) < 0) return; // SO_NOSIGPIPE set at accept
2214#endif
2215 }
2216 }
2217}
std::string dispatch_request(const std::string &line)
Definition McpControl.cpp:2142

References dispatch_request(), and serve_client().

Referenced by serve_client(), and server_thread().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ server_thread()

void Slic3r::GUI::anonymous_namespace{McpControl.cpp}::server_thread ( std::string sock_path)
2230{
2231 // Clear a stale socket from an earlier run — and ONLY a socket. ORCA_CAD_MCP names a path,
2232 // and unlinking it unconditionally deleted whatever file that path happened to be.
2233 {
2234 struct stat st{};
2235 if (::lstat(sock_path.c_str(), &st) == 0) {
2236 if (!S_ISSOCK(st.st_mode)) {
2237 BOOST_LOG_TRIVIAL(error) << "MCP: " << sock_path << " exists and is not a socket; refusing to replace it";
2238 return;
2239 }
2240 ::unlink(sock_path.c_str());
2241 }
2242 }
2243 int sfd = ::socket(AF_UNIX, SOCK_STREAM, 0);
2244 if (sfd < 0) { BOOST_LOG_TRIVIAL(error) << "MCP: socket() failed"; return; }
2245
2246 sockaddr_un addr{};
2247 addr.sun_family = AF_UNIX;
2248 std::strncpy(addr.sun_path, sock_path.c_str(), sizeof(addr.sun_path) - 1);
2249 // The socket is the full CAD command surface, including import_step on absolute paths.
2250 // It lands in a world-writable directory by default (/tmp), so its access control is
2251 // its file mode and nothing else — leaving that to the ambient umask means any local
2252 // process may drive the modeller. umask around bind() makes it 0600 with no window in
2253 // which a wider mode exists; the chmod afterwards covers platforms that do not apply
2254 // umask to sockets.
2255 const mode_t old_umask = ::umask(0177);
2256 const int bind_rc = ::bind(sfd, reinterpret_cast<sockaddr*>(&addr), sizeof(addr));
2257 ::umask(old_umask);
2258 if (bind_rc < 0) {
2259 BOOST_LOG_TRIVIAL(error) << "MCP: bind() failed on " << sock_path;
2260 ::close(sfd); return;
2261 }
2262 if (::chmod(sock_path.c_str(), S_IRUSR | S_IWUSR) < 0) {
2263 BOOST_LOG_TRIVIAL(error) << "MCP: cannot restrict " << sock_path << " to the owner; refusing to listen";
2264 ::close(sfd); ::unlink(sock_path.c_str()); return;
2265 }
2266 if (::listen(sfd, 1) < 0) { BOOST_LOG_TRIVIAL(error) << "MCP: listen() failed"; ::close(sfd); return; }
2267 g_sock_path = sock_path;
2268 std::atexit(remove_socket_at_exit); // do not leave the socket file behind
2269 BOOST_LOG_TRIVIAL(info) << "MCP control listening on " << sock_path;
2270
2271 for (;;) {
2272 int cfd = ::accept(sfd, nullptr, nullptr);
2273 if (cfd < 0) continue;
2274#if !defined(MSG_NOSIGNAL) && defined(SO_NOSIGPIPE)
2275 const int on = 1; // macOS/BSD equivalent of MSG_NOSIGNAL
2276 ::setsockopt(cfd, SOL_SOCKET, SO_NOSIGPIPE, &on, sizeof(on));
2277#endif
2278 serve_client(cfd);
2279 ::close(cfd);
2280 }
2281}
void serve_client(int cfd)
Definition McpControl.cpp:2187
void remove_socket_at_exit()
Definition McpControl.cpp:2222

References g_sock_path, remove_socket_at_exit(), serve_client(), and server_thread().

Referenced by server_thread().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ shape_metrics()

ShapeMetrics Slic3r::GUI::anonymous_namespace{McpControl.cpp}::shape_metrics ( const TopoDS_Shape & s)
752{
753 GProp_GProps vp; BRepGProp::VolumeProperties(s, vp);
754 gp_Pnt c = vp.CentreOfMass();
755 Bnd_Box bb; BRepBndLib::Add(s, bb);
756 double x0, y0, z0, x1, y1, z1; bb.Get(x0, y0, z0, x1, y1, z1);
757 return {vp.Mass(), Vec3d(c.X(), c.Y(), c.Z()), Vec3d(x0, y0, z0), Vec3d(x1, y1, z1)};
758}

References shape_metrics().

Referenced by shape_metrics(), and validate_against().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sketch_entity_from()

SketchEntity Slic3r::GUI::anonymous_namespace{McpControl.cpp}::sketch_entity_from ( const json & j)
1225{
1226 const std::string t = j.value("type", std::string(""));
1227 SketchEntity e;
1228 auto p = [&](const char* k, double dx, double dy) {
1229 if (!j.contains(k)) return Vec2d(dx, dy);
1230 const json& a = j.at(k);
1231 if (!a.is_array() || a.size() < 2) throw std::runtime_error(std::string(k) + " must be [x, y]");
1232 return Vec2d(a[0].get<double>(), a[1].get<double>());
1233 };
1234 e.construction = j.value("construction", false);
1235 // A circle and an arc are defined BY their centre, so a request that does not carry one is
1236 // incomplete, not a request for a circle at the origin. Defaulting it silently put geometry
1237 // somewhere the caller never asked for and then reported perfectly consistent loops, areas
1238 // and hole attribution ABOUT THAT WRONG GEOMETRY — which is far more expensive to disbelieve
1239 // than an error would have been. `p0` is accepted as an alias because that is exactly what a
1240 // circle stores internally (e.p0 = e.center below), so a caller who writes p0 means centre.
1241 auto centre_of = [&](const char* what) {
1242 if (j.contains("center")) return p("center", 0, 0);
1243 if (j.contains("centre")) return p("centre", 0, 0);
1244 if (j.contains("p0")) return p("p0", 0, 0);
1245 throw std::runtime_error(std::string(what) + " needs a 'center' (or 'p0')");
1246 };
1247 if (t == "line") {
1249 e.p0 = p("p0", 0, 0); e.p1 = p("p1", 0, 0);
1250 } else if (t == "circle") {
1252 e.center = centre_of("circle");
1253 e.radius = j.value("radius", 0.0);
1254 e.p0 = e.center;
1255 if (e.radius <= 0.0) throw std::runtime_error("circle needs a positive 'radius'");
1256 } else if (t == "arc") {
1258 e.center = centre_of("arc");
1259 e.radius = j.value("radius", 0.0);
1260 e.start_angle = j.value("start_angle", 0.0);
1261 e.end_angle = j.value("end_angle", 0.0);
1262 if (e.radius <= 0.0) throw std::runtime_error("arc needs a positive 'radius'");
1263 e.p0 = e.center + e.radius * Vec2d(std::cos(e.start_angle), std::sin(e.start_angle));
1264 e.p1 = e.center + e.radius * Vec2d(std::cos(e.end_angle), std::sin(e.end_angle));
1265 } else if (t == "point") {
1267 e.p0 = p("p", 0, 0);
1268 } else {
1269 throw std::runtime_error("unknown entity type '" + t + "' (line, arc, circle, point)");
1270 }
1271 return e;
1272}
double start_angle
Definition SketchEngine.hpp:37
double end_angle
Definition SketchEngine.hpp:38
@ Point
Definition SketchEngine.hpp:31
@ Arc
Definition SketchEngine.hpp:31
@ Circle
Definition SketchEngine.hpp:31
Vec2d center
Definition SketchEngine.hpp:35
double radius
Definition SketchEngine.hpp:36

References Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::SketchEntity::construction, Slic3r::SketchEntity::end_angle, Slic3r::SketchEntity::Line, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::Point, Slic3r::SketchEntity::radius, sketch_entity_from(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by action_sketch_add(), and sketch_entity_from().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sketch_entity_to()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::sketch_entity_to ( const SketchEntity & e,
int index )
1275{
1276 json j{{"index", index}, {"construction", e.construction}};
1277 switch (e.type) {
1279 j["type"] = "line";
1280 j["p0"] = json::array({e.p0.x(), e.p0.y()});
1281 j["p1"] = json::array({e.p1.x(), e.p1.y()});
1282 j["length"] = (e.p1 - e.p0).norm();
1283 break;
1285 j["type"] = "circle";
1286 j["center"] = json::array({e.center.x(), e.center.y()});
1287 j["radius"] = e.radius;
1288 break;
1290 j["type"] = "arc";
1291 j["center"] = json::array({e.center.x(), e.center.y()});
1292 j["radius"] = e.radius;
1293 j["start_angle"] = e.start_angle;
1294 j["end_angle"] = e.end_angle;
1295 j["p0"] = json::array({e.p0.x(), e.p0.y()});
1296 j["p1"] = json::array({e.p1.x(), e.p1.y()});
1297 break;
1299 j["type"] = "point";
1300 j["p"] = json::array({e.p0.x(), e.p0.y()});
1301 break;
1302 // Ellipses and splines used to serialise as a TYPE NAME and nothing else, so every
1303 // parameter they have was invisible to the only read-back this project has. A ladder could
1304 // count them and grade the faceted area of the loop they close (2e-2, the faceting error) —
1305 // it could not check a single axis, angle or pole. "Precise definition of every aspect"
1306 // cannot be asserted about an entity whose aspects the instrument cannot see.
1308 j["type"] = "ellipse";
1309 j["center"] = json::array({e.center.x(), e.center.y()});
1310 j["radius"] = e.radius; // semi-major (a)
1311 j["rminor"] = e.rminor; // semi-minor (b)
1312 j["rotation"] = e.rotation; // major-axis angle, radians
1313 break;
1315 j["type"] = "ellipse_arc";
1316 j["center"] = json::array({e.center.x(), e.center.y()});
1317 j["radius"] = e.radius;
1318 j["rminor"] = e.rminor;
1319 j["rotation"] = e.rotation;
1320 j["start_angle"] = e.start_angle;
1321 j["end_angle"] = e.end_angle;
1322 j["p0"] = json::array({e.p0.x(), e.p0.y()});
1323 j["p1"] = json::array({e.p1.x(), e.p1.y()});
1324 break;
1326 j["type"] = "spline";
1327 json poles = json::array();
1328 for (const Vec2d& c : e.ctrl) poles.push_back(json::array({c.x(), c.y()}));
1329 j["ctrl"] = poles;
1330 j["p0"] = json::array({e.p0.x(), e.p0.y()});
1331 j["p1"] = json::array({e.p1.x(), e.p1.y()});
1332 break;
1333 }
1334 }
1335 return j;
1336}
std::vector< Vec2d > ctrl
Definition SketchEngine.hpp:42
@ Ellipse
Definition SketchEngine.hpp:31
@ EllipseArc
Definition SketchEngine.hpp:31
@ BSpline
Definition SketchEngine.hpp:31
double rotation
Definition SketchEngine.hpp:41
double rminor
Definition SketchEngine.hpp:40

References Slic3r::SketchEntity::Arc, Slic3r::SketchEntity::BSpline, Slic3r::SketchEntity::center, Slic3r::SketchEntity::Circle, Slic3r::SketchEntity::construction, Slic3r::SketchEntity::ctrl, Slic3r::SketchEntity::Ellipse, Slic3r::SketchEntity::EllipseArc, Slic3r::SketchEntity::end_angle, Slic3r::SketchEntity::Line, Slic3r::SketchEntity::p0, Slic3r::SketchEntity::p1, Slic3r::SketchEntity::Point, Slic3r::SketchEntity::radius, Slic3r::SketchEntity::rminor, Slic3r::SketchEntity::rotation, sketch_entity_to(), Slic3r::SketchEntity::start_angle, and Slic3r::SketchEntity::type.

Referenced by action_sketch_describe(), and sketch_entity_to().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sketch_report()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::sketch_report ( DesignSketchTool & t)
1499{
1500 const auto rep = t.loop_report();
1501 json loops = json::array();
1502 for (const auto& l : rep.loops) {
1503 json holes = json::array();
1504 for (int h : l.holes) holes.push_back(h);
1505 loops.push_back(json{{"entities", l.ents}, {"holes", holes},
1506 {"closed", l.closed}, {"area", l.area}});
1507 }
1508 json open_ends = json::array();
1509 for (const Vec2d& p : rep.open_ends) open_ends.push_back(json::array({p.x(), p.y()}));
1510 // A profile is buildable when at least one loop closed, nothing is left dangling and no loop
1511 // crosses or folds back on itself.
1512 json defects = json::array();
1513 for (const auto& l : rep.loops)
1514 if (l.defect) defects.push_back(json::array({l.defect_at.x(), l.defect_at.y()}));
1515 const bool buildable = !rep.loops.empty() && rep.open_ends.empty() && defects.empty();
1516 return json{{"closed_loops", loops}, {"open_ends", open_ends}, {"defects", defects}, {"buildable", buildable}};
1517}
LoopReport loop_report() const
Definition DesignSketchTool.cpp:10492
const Polygons & holes(const ExPolygon &p)
Definition AGGRaster.hpp:31

References Slic3r::holes(), Slic3r::GUI::DesignSketchTool::loop_report(), and sketch_report().

Referenced by action_sketch_describe(), action_sketch_heal(), action_sketch_set_value(), action_sketch_validate(), and sketch_report().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ sketch_targets()

std::vector< int > Slic3r::GUI::anonymous_namespace{McpControl.cpp}::sketch_targets ( const json & params,
DesignSketchTool & t,
bool all_if_empty )
1342{
1343 std::vector<int> out;
1344 if (params.contains("entities")) {
1345 for (const auto& v : params.at("entities")) out.push_back(v.get<int>());
1346 return out;
1347 }
1348 out = t.selection();
1349 if (out.empty() && all_if_empty)
1350 for (int i = 0; i < int(t.entities().size()); ++i) out.push_back(i);
1351 return out;
1352}

References Slic3r::GUI::DesignSketchTool::entities(), Slic3r::GUI::DesignSketchTool::selection(), and sketch_targets().

Referenced by action_sketch_construction(), action_sketch_delete(), action_sketch_mirror(), action_sketch_offset(), and sketch_targets().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ slice_body()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::slice_body ( DesignPanel * panel,
const json & params )
633{
634 const TopoDS_Shape& shape = body_shape(panel, params);
635 const std::string plane_name = params.value("plane", std::string("XY"));
636 const double offset = params.value("offset", 0.0);
637 // Base plane normal; offset shifts the plane along it.
638 gp_Dir n = plane_name == "XZ" ? gp_Dir(0, 1, 0)
639 : plane_name == "YZ" ? gp_Dir(1, 0, 0)
640 : gp_Dir(0, 0, 1);
641 gp_Pnt o(n.X() * offset, n.Y() * offset, n.Z() * offset);
642 BRepAlgoAPI_Section sect(shape, gp_Pln(o, n), false);
643 sect.ComputePCurveOn1(false);
644 sect.Approximation(true);
645 sect.Build();
646 if (!sect.IsDone()) throw std::runtime_error("section failed");
647 std::vector<std::vector<Vec3d>> segs;
648 for (TopExp_Explorer ex(sect.Shape(), TopAbs_EDGE); ex.More(); ex.Next()) {
649 std::vector<Vec3d> pts = GeometryEngine::sample_edge_world(TopoDS::Edge(ex.Current()));
650 if (pts.size() >= 2) segs.push_back(std::move(pts));
651 }
652 const int raw = int(segs.size());
653 auto contours = chain_segments(std::move(segs), 1e-3);
654 json jcont = json::array();
655 int closed_n = 0;
656 for (auto& pc : contours) {
657 if (pc.second) ++closed_n;
658 json pts = json::array();
659 for (const Vec3d& p : pc.first) pts.push_back(vec3(p));
660 jcont.push_back(json{{"closed", pc.second}, {"points", std::move(pts)}});
661 }
662 return json{{"body", params.value("body", 0)}, {"plane", plane_name}, {"offset", offset},
663 {"segment_count", raw}, {"contour_count", int(contours.size())},
664 {"closed_count", closed_n}, {"contours", std::move(jcont)}};
665}
std::vector< std::pair< std::vector< Vec3d >, bool > > chain_segments(std::vector< std::vector< Vec3d > > segs, double tol)
Definition McpControl.cpp:602

References body_shape(), chain_segments(), Slic3r::offset(), Slic3r::GeometryEngine::sample_edge_world(), slice_body(), and vec3().

Referenced by handle_on_main(), and slice_body().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ target_body_arg()

int Slic3r::GUI::anonymous_namespace{McpControl.cpp}::target_body_arg ( const json & params,
const CadDocument & doc )
870{
871 int bi = params.value("body", -1);
872 if (bi >= int(doc.bodies.size()))
873 throw std::runtime_error("body index out of range (have " + std::to_string(doc.bodies.size()) + ")");
874 return bi; // <0 -> kernel uses the last body
875}

References Slic3r::CadDocument::bodies, and target_body_arg().

Referenced by action_chamfer(), action_delete_face(), action_draft(), action_fillet(), action_mirror(), action_pattern(), action_pattern_on_curve(), action_rib(), action_shell(), action_split(), action_surface_offset(), action_thicken(), action_thicken_surface(), action_transform(), and target_body_arg().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ validate_against()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::validate_against ( DesignPanel * panel,
const json & params )
761{
762 const TopoDS_Shape& cand = body_shape(panel, params); // candidate = the reconstruction
763 if (!params.contains("reference")) throw std::runtime_error("validate_against needs 'reference' {step|body}");
764 const json& r = params["reference"];
765
766 TopoDS_Shape ref;
767 if (r.contains("step")) {
768 std::string err;
769 std::vector<TopoDS_Shape> solids = GeometryEngine::read_step_solids(r["step"].get<std::string>(), err);
770 if (solids.empty()) throw std::runtime_error(err.empty() ? "reference STEP has no solids" : err);
771 BRep_Builder b; TopoDS_Compound comp; b.MakeCompound(comp);
772 for (const TopoDS_Shape& s : solids) if (!s.IsNull()) b.Add(comp, s);
773 ref = comp;
774 } else if (r.contains("body")) {
775 CadDocument& doc = panel->mcp_doc();
776 int idx = r["body"].get<int>();
777 if (idx < 0 || idx >= int(doc.bodies.size()) || doc.bodies[idx].shape.IsNull())
778 throw std::runtime_error("reference body index out of range / null");
779 ref = doc.bodies[idx].shape;
780 } else {
781 throw std::runtime_error("reference must be {\"step\": path} or {\"body\": id}");
782 }
783
784 ShapeMetrics a = shape_metrics(cand), b = shape_metrics(ref);
785 double dv = b.volume > 0 ? (a.volume - b.volume) / b.volume * 100.0 : 0.0;
786 Vec3d coff = a.centroid - b.centroid;
787 Vec3d dmin = a.bmin - b.bmin, dmax = a.bmax - b.bmax;
788 // Surface-level deviation (one-sided Hausdorff, candidate vertices -> reference solid):
789 // catches local shape error that matching volume + bbox can hide.
790 GeometryEngine::Deviation dev = GeometryEngine::surface_deviation(cand, ref);
791 return json{
792 {"volume", a.volume}, {"volume_reference", b.volume}, {"volume_delta_pct", dv},
793 {"centroid_offset", vec3(coff)}, {"centroid_offset_mm", coff.norm()},
794 {"bbox", json{{"min", vec3(a.bmin)}, {"max", vec3(a.bmax)}}},
795 {"bbox_reference", json{{"min", vec3(b.bmin)}, {"max", vec3(b.bmax)}}},
796 {"bbox_delta", json{{"min", vec3(dmin)}, {"max", vec3(dmax)}}},
797 {"surface_deviation", json{{"max_mm", dev.max_mm}, {"mean_mm", dev.mean_mm},
798 {"rms_mm", dev.rms_mm}, {"samples", dev.sample_count}}},
799 };
800}
static Deviation surface_deviation(const TopoDS_Shape &candidate, const TopoDS_Shape &reference, double linear_deflection=0.5)
Definition GeometryEngine.cpp:458
ShapeMetrics shape_metrics(const TopoDS_Shape &s)
Definition McpControl.cpp:751

References Slic3r::GUI::anonymous_namespace{McpControl.cpp}::ShapeMetrics::bmax, Slic3r::GUI::anonymous_namespace{McpControl.cpp}::ShapeMetrics::bmin, Slic3r::CadDocument::bodies, body_shape(), Slic3r::GUI::anonymous_namespace{McpControl.cpp}::ShapeMetrics::centroid, Slic3r::GeometryEngine::Deviation::max_mm, Slic3r::GUI::DesignPanel::mcp_doc(), Slic3r::GeometryEngine::Deviation::mean_mm, Slic3r::GeometryEngine::read_step_solids(), Slic3r::GeometryEngine::Deviation::rms_mm, Slic3r::GeometryEngine::Deviation::sample_count, shape_metrics(), Slic3r::GeometryEngine::surface_deviation(), validate_against(), vec3(), and Slic3r::GUI::anonymous_namespace{McpControl.cpp}::ShapeMetrics::volume.

Referenced by handle_on_main(), and validate_against().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ vec3()

json Slic3r::GUI::anonymous_namespace{McpControl.cpp}::vec3 ( const Vec3d & v)
inline
449{ return json::array({v.x(), v.y(), v.z()}); }

References vec3().

Referenced by measure(), query_topology(), slice_body(), validate_against(), and vec3().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ verb_is_modal()

bool Slic3r::GUI::anonymous_namespace{McpControl.cpp}::verb_is_modal ( const char * id)
1648{
1649 static const char* kModal[] = { "sk_text", "sk_svg", "colour" };
1650 for (const char* m : kModal)
1651 if (std::strcmp(m, id) == 0) return true;
1652 return false;
1653}

References verb_is_modal().

Referenced by action_list_verbs(), action_run_verb(), and verb_is_modal().

Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ g_sock_path

std::string Slic3r::GUI::anonymous_namespace{McpControl.cpp}::g_sock_path