Internals¶
Autogenerated wrappers¶
The Cython struct wrappers are generated by scripts/gen_wrappers.py
. To illustrate how the wrappers work, let’s consider a toy C structure and the corresponding generated Cython cdef class. Here’s a stripped down version of mjData
with a scalar member and a pointer (array) member:
typedef struct _mjData {
int ne;
mjtNum* qpos; // (nq x 1)
} mjData;
Here’s the corresponding generated Cython wrapper code:
cdef class PyMjData(object):
cdef mjData* ptr
cdef mjModel* _model
cdef np.ndarray _qpos
cdef void _set(self, mjData* p, mjModel* model):
self.ptr = p
self._model = model
self._qpos = _wrap_mjtNum_1d(p.qpos, model.nq)
@property
def ne(self): return self.ptr.ne
@ne.setter
def ne(self, int x): self.ptr.ne = x
@property
def qpos(self): return self._qpos
cdef PyMjData WrapMjData(mjData* p, mjModel* model):
cdef PyMjData o = PyMjData()
o._set(p, model)
return o
PyMjData
is the wrapper class for exposing the underlying Mujoco structure to Python; it doesn’t perform any memory mangement. A user writing Cython code can create this wrapper using WrapMjData
. A mjModel
pointer must be passed because the shape of a mjData
member, namely qpos
, depends on model->nq
.
Each field of mjData
corresponds to some generated piece of code in PyMjData
that depends on the type of that field. For example, ne
is a scalar integer, so it gets exposed as a pair of getter and setter methods in PyMjData
. qpos
is an array represented as a pointer to its first element, so it’s wrapped with a NumPy array by _wrap_mjtNum_1d
and is exposed with a getter for that NumPy array.
The function _wrap_mjtNum_1d
creates a Cython memoryview from the data pointer and converts it to a NumPy array pointing to the same memory:
cdef inline np.ndarray _wrap_mjtNum_1d(mjtNum* a, int shape0):
if shape0 == 0: return None
cdef mjtNum[:] b = <mjtNum[:shape0]> a
return np.asarray(b)
Similar functions for other types are also generated as required.
Keep in mind that the only reason to use these autogenerated wrappers is to allow Python users of the Cython code to easily access Mujoco data (for instance the MjSim
Cython class, found in ``cymj/cymj.pyx`). If you’re writing Cython code and you don’t need the user to access Mujoco data from Python, then there is no reason to use these wrappers.