CAM: Add annotations support to Command constructor and Python bindings

This commit introduces support for passing an 'annotations' dictionary
to the Command class constructor and its Python bindings. The annotations
dictionary can contain string or numeric values for each key, allowing for
richer metadata on CAM commands. Each annotation must be provided as a
key-value pair within a dictionary.

Examples:

cmd = Command("G1", {"X": 10.0, "Y": 5.0}, {"note": "Rapid move"})

cmd = Command("G2", {"X": 20.0, "Y": 15.0}, {"priority": 1})

cmd = Command("G3", {"X": 30.0, "Y": 25.0}, {"note": "Arc move", "speed": 1500})

cmd = Command("G0", {"X": 0.0, "Y": 0.0}, {})

cmd = Command("G0", {"X": 0.0, "Y": 0.0})

cmd = Command("G1", {"X": 10.0, "Y": 5.0}, annotations={"note": "Rapid move"})

src/Mod/CAM/App/Command.cpp:
- Added new Command constructor accepting annotations

src/Mod/CAM/App/Command.h:
- Declared new Command constructor with annotations parameter

src/Mod/CAM/App/Command.pyi:
- Updated docstring to describe annotations argument

src/Mod/CAM/App/CommandPyImp.cpp:
- Extended Python init to parse and set annotations dictionary
This commit is contained in:
Billy Huddleston
2025-11-30 13:53:40 -05:00
parent ee394d2e58
commit 047cd38c24
4 changed files with 69 additions and 4 deletions

View File

@@ -47,6 +47,16 @@ Command::Command(const char* name, const std::map<std::string, double>& paramete
, Annotations()
{}
Command::Command(
const char* name,
const std::map<std::string, double>& parameters,
const std::map<std::string, std::variant<std::string, double>>& annotations
)
: Name(name)
, Parameters(parameters)
, Annotations(annotations)
{}
Command::Command()
: Annotations()
{}

View File

@@ -44,6 +44,11 @@ public:
// constructors
Command();
Command(const char* name, const std::map<std::string, double>& parameters);
Command(
const char* name,
const std::map<std::string, double>& parameters,
const std::map<std::string, std::variant<std::string, double>>& annotations
);
~Command() override;
// from base class
unsigned int getMemSize() const override;

View File

@@ -13,10 +13,11 @@ from Base.Placement import Placement
@class_declarations("mutable Py::Dict parameters_copy_dict;")
class Command(Persistence):
"""
Command([name],[parameters]): Represents a basic Gcode command
Command([name],[parameters],[annotations]): Represents a basic Gcode command
name (optional) is the name of the command, ex. G1
parameters (optional) is a dictionary containing string:number
pairs, or a placement, or a vector
annotations (optional) is a dictionary containing string:string or string:number pairs
"""
@constmethod

View File

@@ -71,9 +71,20 @@ PyObject* CommandPy::PyMake(struct _typeobject*, PyObject*, PyObject*) // Pytho
int CommandPy::PyInit(PyObject* args, PyObject* kwd)
{
PyObject* parameters = nullptr;
PyObject* annotations = nullptr;
const char* name = "";
static const std::array<const char*, 3> kwlist {"name", "parameters", nullptr};
if (Base::Wrapped_ParseTupleAndKeywords(args, kwd, "|sO!", kwlist, &name, &PyDict_Type, &parameters)) {
static const std::array<const char*, 4> kwlist {"name", "parameters", "annotations", nullptr};
if (Base::Wrapped_ParseTupleAndKeywords(
args,
kwd,
"|sO!O!",
kwlist,
&name,
&PyDict_Type,
&parameters,
&PyDict_Type,
&annotations
)) {
std::string sname(name);
boost::to_upper(sname);
try {
@@ -112,16 +123,54 @@ int CommandPy::PyInit(PyObject* args, PyObject* kwd)
}
getCommandPtr()->Parameters[ckey] = cvalue;
}
// Parse annotations
pos = 0;
while (annotations && PyDict_Next(annotations, &pos, &key, &value)) {
std::string ckey;
if (PyUnicode_Check(key)) {
ckey = PyUnicode_AsUTF8(key);
}
else {
PyErr_SetString(
PyExc_TypeError,
"The annotations dictionary can only contain string keys"
);
return -1;
}
if (PyUnicode_Check(value)) {
std::string cvalue = PyUnicode_AsUTF8(value);
getCommandPtr()->setAnnotation(ckey, cvalue);
}
else if (PyObject_TypeCheck(value, &(PyLong_Type))) {
double cvalue = (double)PyLong_AsLong(value);
getCommandPtr()->setAnnotation(ckey, cvalue);
}
else if (PyObject_TypeCheck(value, &(PyFloat_Type))) {
double cvalue = PyFloat_AsDouble(value);
getCommandPtr()->setAnnotation(ckey, cvalue);
}
else {
PyErr_SetString(
PyExc_TypeError,
"The annotations dictionary can only contain string or number values"
);
return -1;
}
}
parameters_copy_dict.clear();
return 0;
}
PyErr_Clear(); // set by PyArg_ParseTuple()
static const std::array<const char*, 3> kwlist_placement {"name", "parameters", nullptr};
if (Base::Wrapped_ParseTupleAndKeywords(
args,
kwd,
"|sO!",
kwlist,
kwlist_placement,
&name,
&(Base::PlacementPy::Type),
&parameters