C API Capsule#
Importing the Capsule#
The PyEVSpace PyCapsule provides C API support for creating and managing
the Python layer objects when including PyEVSpace in an extension module.
Your project should include the include/pyevspace-api.hpp header
file into the module importing PyEVSpace. This file is usable for extensions
written in either C or C++. The global static variable PyEVSpace_API
can be properly filled by calling PyEVSpace_ImportCapsule(), and is
then available globally to all functions needing the capsule.
Due to C++ compatibilitiy issues, the wrapped C++
objects cannot be exposed directly, and so the capsule provides a stable
C ABI interface for managing the Python level objects defined by the module.
This is done using C primitives, and all functions allow creation, access,
or modification of Python objects using primitives, usually in arrays. There
are also definitions of the PyTypeObject structs, which supports
the ability to handle functionality of the Python objects through the CPython
layer to access methods not supported by the capsule.
All of the capsule functions are tested by building small extension modules that use these functions. They can be referenced as examples for how to use the capsule functions, but keep in mind they are farily trivial, only meant to test behavior.
Changed in version 0.16.0: Because the module is now multi-phase initialized, there is no global state, and therefore there is no global PyTypeObject* variables for use in type checking and creating new instances. While the capsule methods that create and return new PyObject* can lookup the module state, any caller already has direct access to the types via the capsule. Therefore, these functions now require the caller to pass the PyTypeObject* of the desired return type (or a subclass of the type) to the capsule method.
Capsule Utilities#
-
PyEVSPace_CAPI *PyEVSpace_API#
A global static pointer to the PyEVSpace capsule struct
PyEVSpace_CAPIThis value can be filled using thePyEVSpace_ImportCapsule()function.Removed in version 0.16.0: As the module uses multi-phase initialization there can no longer be any modifiable global state. Therefore this variable is removed and any user of the capsule needs to define a pointer to a capsule instance somewhere within their module layout.
-
int PyEVSpace_ImportCapsule(PyEVSpace_CAPI **out)#
Imports the PyEVSpace module if not already imported, and fills the out parameter to the capsule pointer attached to the PyEVSpace module. The source of the out parameter is up to the caller to define, if creating a single-phase intialized module a global static variable is most common, or within your own module’s state for multi-phased initialization is best. The
PYEVSPACE_CAPSULE_VERSIONmacro should be used to verify thePyEVSpace_CAPI.versionvalue of the capsule matches the version that is included in your extension.Changed in version 0.16.0: This function now takes a required PyEVSpace_CAPI** argument to set the capsule to, as there is no longer a global instance of this type (see
EVSpace_API).- Return values:
0 – on successful import of the capsule
-1 – if an error occurred
-
PYEVSPACE_CAPSULE_NAME#
The name of the capsule used during import. If manually importing the capsule (and not via
PyEVSpace_ImportCapsule()), this is the string value that should be passed toPyCapsule_Import().
-
PYEVSPACE_CAPSULE_VERSION#
The version of the PyEVSpace capsule defined in the header. This should be verified against
PyEVSpace_CAPI.versionto ensure the version of the imported capsule and the header definition are compatible.Changed in version 0.16.0: This value was bumped up as there are backwards incompatible changes within the capsule.
Capsule Definition#
-
struct PyEVSpace_CAPI#
The C struct containing the definition of the PyEVSpace
PyCapsule. An instance of this type is cast to a void* to create the capsule. The exact definition is shown here, and further documentation of each member is given below.typedef struct { int version; // PyTypeObjects PyTypeObject* Vector_Type; PyTypeObject* Matrix_Type; PyTypeObject* EulerAngles_Type; PyTypeObject* RotationOrder_Type; PyTypeObject* ReferenceFrame_Type; // evspace state getters int (*PyEVSpaceVector_GetState)(PyObject*, double[3]); int (*PyEVSpaceMatrix_GetState)(PyObject*, double[9]); int (*PyEVSpaceAngles_GetState)(PyObject*, double[3]); int (*PyEVSpaceOrder_GetState)(PyObject*, unsigned int[3]); int (*PyEVSpaceFrame_GetState)(PyObject*, unsigned int[3], double[3], double[3], int*); PyObject* (*PyEVSpaceFrame_GetOrder)(PyObject*); PyObject* (*PyEVSpaceFrame_GetAngles)(PyObject*); PyObject* (*PyEVSpaceFrame_GetOffset)(PyObject*); int (*PyEVSpaceFrame_GetIntrinsic)(PyObject*); // Python type constructors via state PyObject* (*PyEVSpaceVector_FromState)(PyTypeObject*, double[3]); PyObject* (*PyEVSpaceMatrix_FromState)(PyTypeObject*, double[9]); PyObject* (*PyEVSpaceAngles_FromState)(PyTypeObject*, double[3]); PyObject* (*PyEVSpaceOrder_FromState)(PyTypeObject*, unsigned int[3]); PyObject* (*PyEVSpaceFrame_FromState)(PyTypeObject*, unsigned int[3], double[3], double*, int); // Python type modifiers int (*PyEVSpaceVector_SetState)(PyObject*, double[3]); int (*PyEVSpaceMatrix_SetState)(PyObject*, double[9]); int (*PyEVSpaceAngles_SetState)(PyObject*, double[3]); int (*PyEVSpaceFrame_SetAngles)(PyObject*, double[3]); int (*PyEVSpaceFrame_SetOffset)(PyObject*, double*); } PyEVSpace_CAPI;
Changed in version 0.16.0: The PyEVSpace*_FromState methods now require a
PyTypeObjectpointer to the type they are meant to create.
Capsule Documentation#
Capsule Version#
The version of the compiled capsule imported must have the same version
as the PyEVSpace_CAPI definition included in your extension
module. This is done by comparing PyEVSpace_CAPI.version with
PYEVSPACE_CAPSULE_VERSION after importing the capsule. If they
do not match you should set an exception and return an error status.
-
int PyEVSpace_CAPI.version#
The API version of the imported capsule.
PyTypeObjects#
Changed in version 0.16.0: These are now heap types, created from PyType_Spec definitions
for each module created.
-
PyTypeObject *PyEVSpace_CAPI.Vector_Type#
The PyTypeObject for the
pyevspace.Vectortype.
-
PyTypeObject *PyEVSpace_CAPI.Matrix_Type#
The PyTypeObject for the
pyevspace.Matrixtype.
-
PyTypeObject *PyEVSpace_CAPI.EulerAngles_Type#
The PyTypeObject for the
pyevspace.EulerAnglestype.
-
PyTypeObject *PyEVSpace_CAPI.RotationOrder_Type#
The PyTypeObject for the
pyevspace.RotationOrdertype.
-
PyTypeObject *PyEVSpace_CAPI.ReferenceFrame_Type#
The PyTypeObject for the
pyevspace.ReferenceFrametype.
State Getters#
-
int PyEVSpace_CAPI.PyEVSpaceVector_GetState(PyObject *obj, double state[3])#
Get the internal state of a
pyevspace.Vectoras a PyObject into a double array. The state is a simple array containing the x, y, and z values of the vector. If successful return 0, otherwise return -1.- Parameters:
obj – the
pyevspace.Vectorinstance to get the state ofstate – the output array that will contain the vector state. This is only filled if the function succeeds
- Return values:
0 – on success
-1 – on failure with an appropriate exception set
-
int PyEVSpace_CAPI.PyEVSpaceMatrix_GetState(PyObject *obj, double state[9])#
Get the internal state of a
pyevspace.Matrixas a PyObject into a double array. The state is a 1-dimensional array of concatenated rows of the matrix components. This means the indices 0-2 contain the first row, 3-5 contain the second row, and 6-8 contain the third row. For using a 1-dimensional array in nested for loops, the index mapping is state[row * 3 + column] = value.Returns 0 on success or -1 on failure.
- Parameters:
obj – the
pyevspace.Matrixinstance to get the state ofstate – the output array containing the matrix state as a 1-dimension contiguous array. This is only filled if the function succeeds
- Return values:
0 – on success
-1 – on failure with an appropriate exception set
-
int PyEVSpace_CAPI.PyEVSpaceAngles_GetState(PyObject *obj, double state[3])#
Get the internal state of a
pyevspace.EulerAnglesas a PyObject into a double array. The state contains the three rotation angles of the container. Returns 0 on success or -1 on failure.- Parameters:
obj – the
pyevspace.EulerAnglesinstance to get the state ofstate – the output array that will contain the angles state. This is only filled if the function succeeds
- Return values:
0 – on success
-1 – on failure with an appropriate exception set
-
int PyEVSpace_CAPI.PyEVSpaceOrder_GetState(PyObject *obj, unsigned int state[3])#
Get the internal state of a
pyevspace.RotationOrderas a PyObject into a unsigned int array. The state contains the three rotation axes of the object as enumerated axis values. The values are:Axis
Value
X
0
Y
1
Z
2
Returns 0 on success or -1 on failure.
- Parameters:
obj – the
pyevspace.RotationOrderinstance to get the state ofstate – the output array that will contain the order state. This is only filled if the function succeeds
- Return values:
0 – on success
-1 – on failure with an appropriate exception set
-
int PyEVSpace_CAPI.PyEVSpaceFrame_GetState(PyObject *obj, unsigned int order[3], double angles[3], double offset[3], int *intrinsic)#
Get the internal state of a
pyevspace.ReferenceFrameas a PyObject into respective state variables. The order and angles parameters behave identically to their respective type state getters above. The offset parameter is filled as the internal state of the offset vector of the reference frame, and the intrinsic parameter is set to 1 for intrinsic and 0 for extrinsic rotations. This function returns 0 on success or -1 on failure.Note
The internal value for
pyevspace.ReferenceFrame.offsetmay beNonewhen no offset is given during construction. Since the state must be returned as a double array, there is no clean way of signaling when the value isNone. Since this value is mathematically analogous to the zero vector, when the offset isNone, all offset components will be set to zero.- Parameters:
obj – the
pyevspace.ReferenceFrameinstance to get the state oforder – the output array that will contain the order state
angles – the output array that will contain the angles state
offset – the output array that will contain the offset state
intrinsic – the output variable that will contain the intrinsic value. Note the type of this parameter is a pointer, so the address of the local intrinsic variable should be passed
- Return values:
0 – on success
-1 – on failure with an appropriate exception set
-
PyObject *PyEVSpace_CAPI.PyEVSpaceFrame_GetOrder(PyObject *obj)#
Get a PyObject version of the
pyevspace.RotationOrderfrom apyevspace.ReferenceFrametype as a PyObject. The returned object is a representation of the order only, and any modification has no affect on the original reference frame. The returned object is a new reference owned by the caller.- Parameters:
obj – the reference frame to get the rotation order of
- Returns:
a new reference to a rotation order
- Return values:
NULL – if an error occurred with an appropriate exception set
-
PyObject *PyEVSpace_CAPI.PyEVSpaceFrame_GetAngles(PyObject *obj)#
Get a PyObject version of the
pyevspace.EulerAnglesfrom apyevspace.ReferenceFrametype as a PyObject. The returned object is a representation of the angles only, and any modification has no affect on the original reference frame. The returned object is a new reference owned by the caller.- Parameters:
obj – the reference frame to get the rotation angles of
- Returns:
a new reference to a set of rotation angles
- Return values:
NULL – if an error occurred with an appropriate exception set
-
PyObject *PyEVSpace_CAPI.PyEVSpaceFrame_GetOffset(PyObject *obj)#
Get a PyObject version of the offset value from a
pyevspace.ReferenceFrametype as a PyObject. This may be apyevspace.Vectorinstance, orPy_None. The returned object is a representation of the offset only, and any modification has no affect on the original reference frame. The returned object is a new reference owned by the caller.- Parameters:
obj – the reference frame to get the offset value of
- Returns:
a new reference to the offset vector, or Py_None
- Return values:
NULL – if an error occurred with an appropriate exception set
-
int PyEVSpace_CAPI.PyEVSpaceFrame_GetIntrinsic(PyObject *obj)#
Get the value of the intrinsic variable from a
pyevspace.ReferenceFrametype as a PyObject. This will be 1 if intrinsic, 0 if extrinsic, or -1 if an exception occurred.- Parameters:
obj – the reference frame to get the intrinsic value of
- Returns:
an equivalent boolean value answering if the rotation is intrinsic
- Return values:
1 – if the reference frame rotation is intrinsic
0 – if the reference frame rotation is extrinsic
-1 – if an error occurred with an appropriate exception set
PyObject Constructors#
-
PyObject *PyEVSpace_CAPI.PyEVSpaceVector_FromState(PyTypeObject *type, double state[3])#
Creates a PyObject* for a
pyevspace.Vectoror a subclass of that type, depending on type, from the vector state as a C double. If wanting to create apyevspace.Vectorinstance, type should bePyEVSpace_CAPI.Vector_Type. The returned object is a new reference owned by the caller.- Parameters:
type – the type of instance to create. This must be exactly or a subclass of
PyEVSpace_CAPI.Vector_Typestate – the state of the vector to return
- Returns:
a new vector as a PyObject
- Return values:
NULL – if an error occurred with an appropriate exception set
Changed in version 0.16.0: This function now takes a PyTypeObject* referencing the type to create.
-
PyObject *PyEVSpace_CAPI.PyEVSpaceMatrix_FromState(PyTypeObject *type, double state[9])#
Creates a PyObject* for a
pyevspace.Matrixor a subclass of that type, depending on type, from the matrix state as a C double. If wanting to create apyevspace.Matrixinstance, type should bePyEVSpace_CAPI.Matrix_Type. The returned object is a new reference owned by the caller.- Parameters:
type – the type of instance to create. This must be exactly or a subclass of
PyEVSpace_CAPI.Matrix_Typestate – the state of the matrix to return
- Returns:
a new matrix as a PyObject
- Return values:
NULL – if an error occurred with an appropriate exception set
Changed in version 0.16.0: This function now takes a PyTypeObject* referencing the type to create.
-
PyObject *PyEVSpace_CAPI.PyEVSpaceAngles_FromState(PyTypeObject *type, double state[3])#
Creates a PyObject* for a
pyevspace.EulerAnglesor a subclass of that type, depending on type, from the angles state as a C double. If wanting to create apyevspace.EulerAnglesinstance, type should bePyEVSpace_CAPI.EulerAngles_Type. The returned object is a new reference owned by the caller.- Parameters:
type – the type of instance to create. This must be exactly or a subclass of
PyEVSpace_CAPI.EulerAngles_Typestate – the state of the Euler angles to return
- Returns:
a new Euler angles object as a PyObject
- Return values:
NULL – if an error occurred with an appropriate exception set
Changed in version 0.16.0: This function now takes a PyTypeObject* referencing the type to create.
-
PyObject *PyEVSpace_CAPI.PyEVSpaceOrder_FromState(PyTypeObject *type, unsigned int state[3])#
Creates a PyObject* for a
pyevspace.RotationOrderor a subclass of that type, depending on type, from the order state as a double. If wanting to create apyevspace.RotationOrderinstance, type should bePyEVSpace_CAPI.RotationOrder_Type. The returned object is a new reference owned by the caller.- Parameters:
type – the type of instance to create. This must be exactly or a subclass of
PyEVSpace_CAPI.RotationOrder_Typestate – the state of the rotation order to return
- Returns:
a new rotation order as a PyObject
- Return values:
NULL – if an error occurred with an appropriate exception set
Changed in version 0.16.0: This function now takes a PyTypeObject* referencing the type to create.
-
PyObject *PyEVSpace_CAPI.PyEVSpaceFrame_FromState(PyTypeObject *type, unsigned int order[3], double angles[3], double *offset, int intrinsic)#
Creates a PyObject* for a
pyevspace.ReferenceFrametype or a subclass of that type, depending on type, using the parameters similar to those asPyEVSpaceFrame_GetState(), with the exception of the offset type. As this is an input parameter and not an output parameter, offset may be NULL. Otherwise, offset is treated to have type double[3], and anything else may cause undefined behavior, or worse, crash the program.If wanting to create a
pyevspace.ReferenceFrameinstance, type should bePyEVSpace_CAPI.ReferenceFrame_Type. The returned object is a new reference owned by the caller.- Parameters:
type – the type of instance to create. This must be exactly or a subclass of
PyEVSpace_CAPI.ReferenceFrame_Typeorder – the rotation order state of the reference frame
angles – the rotation angles state of the reference frame
offset – NULL to be equivalent to
Py_None, otherwise the vector offset state of the reference frameintrinsic – 1 for an intrinsic rotation, 0 for extrinsic
- Returns:
a new reference frame as a PyObject
- Return values:
NULL – if an error occurred with an appropriate exception set
Changed in version 0.16.0: This function now takes a PyTypeObject* referencing the type to create.
PyObject Modifiers#
-
int PyEVSpace_CAPI.PyEVSpaceVector_SetState(PyObject *obj, double state[3])#
Sets the state of a
pyevspace.Vectoras a PyObject from a C double array. Returns 0 on success and -1 on failure.- Parameters:
obj – the vector object to modify
state – the state to set the vector to
- Return values:
0 – on success
-1 – on failure with an appropriate exception set
-
int PyEVSpace_CAPI.PyEVSpaceMatrix_SetState(PyObject *obj, double state[9])#
Sets the state of a
pyevspace.Matrixas a PyObject from a 1-dimensional contiguous C double array. The layout of this array is explained inPyEVSpaceMatrix_GetState(). Returns 0 on success and -1 on failure.- Parameters:
obj – the matrix object to modify
state – the state to set the matrix to
- Return values:
0 – on success
-1 – on failure with an appropriate exception set
-
int PyEVSpace_CAPI.PyEVSpaceAngles_SetState(PyObject *obj, double state[3])#
Sets the state of a
pyevspace.EulerAnglesas a PyObject from a C double array. Returns 0 on success and -1 on failure.- Parameters:
obj – the Euler angles object to modify
state – the state to set the Euler angles to
- Return values:
0 – on success
-1 – on failure with an appropriate exception set
-
int PyEVSpace_CAPI.PyEVSpaceFrame_SetAngles(PyObject *obj, double state[3])#
Sets the rotation angles state of a
pyevspace.ReferenceFrameas a PyObject from a C double array. Returns 0 on success and -1 on failure.- Parameters:
obj – the reference frame object to modify
state – the state to set the reference frame’s rotation angles to
- Return values:
0 – on success
-1 – on failure with an appropriate exception set
-
int PyEVSpace_CAPI.PyEVSpaceFrame_SetOffset(PyObject *obj, double *offset)#
Sets the offset state of a
pyevspace.ReferenceFrameas a PyObject from a C double array. offset may be NULL to set the reference frame’s offset value toPy_None, otherwise offset is treated to have type double[3], and anything else may cause undefined behavior, or worse, crash the program.Returns 0 on success and -1 on failure.
- Parameters:
obj – the reference frame object to modify
state – the state to set the offset value to (may be NULL for
Py_None)
- Return values:
0 – on success
-1 – on failure with an appropriate exception set