Blender V5.0
BPy_Stroke.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2004-2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include "BPy_Stroke.h"
10
11#include "../BPy_Convert.h"
12#include "../BPy_Id.h"
13#include "../BPy_MediumType.h"
17
18#include "BLI_sys_types.h"
19
20using namespace Freestyle;
21
23
24/*----------------------Stroke methods ----------------------------*/
25
26// Stroke ()
27// template<class InputVertexIterator> Stroke (InputVertexIterator begin, InputVertexIterator end)
28//
29// pb: - need to be able to switch representation: InputVertexIterator <=> position
30// - is it even used ? not even in SWIG version
31
33 /* Wrap. */
34 Stroke_doc,
35 "Class hierarchy: :class:`Interface1D` > :class:`Stroke`\n"
36 "\n"
37 "Class to define a stroke. A stroke is made of a set of 2D vertices\n"
38 "(:class:`StrokeVertex`), regularly spaced out. This set of vertices\n"
39 "defines the stroke's backbone geometry. Each of these stroke vertices\n"
40 "defines the stroke's shape and appearance at this vertex position.\n"
41 "\n"
42 ".. method:: Stroke()\n"
43 " Stroke(brother)\n"
44 "\n"
45 " Creates a :class:`Stroke` using the default constructor or copy constructor\n");
46static int Stroke_init(BPy_Stroke *self, PyObject *args, PyObject *kwds)
47{
48 static const char *kwlist[] = {"brother", nullptr};
49 PyObject *brother = nullptr;
50
51 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist, &Stroke_Type, &brother)) {
52 return -1;
53 }
54 if (!brother) {
55 self->s = new Stroke();
56 }
57 else {
58 self->s = new Stroke(*(((BPy_Stroke *)brother)->s));
59 }
60 self->py_if1D.if1D = self->s;
61 self->py_if1D.borrowed = false;
62 return 0;
63}
64
65static PyObject *Stroke_iter(PyObject *self)
66{
67 StrokeInternal::StrokeVertexIterator sv_it(((BPy_Stroke *)self)->s->strokeVerticesBegin());
69}
70
71static Py_ssize_t Stroke_sq_length(BPy_Stroke *self)
72{
73 return self->s->strokeVerticesSize();
74}
75
76static PyObject *Stroke_sq_item(BPy_Stroke *self, Py_ssize_t keynum)
77{
78 if (keynum < 0) {
79 keynum += Stroke_sq_length(self);
80 }
81 if (keynum < 0 || keynum >= Stroke_sq_length(self)) {
82 PyErr_Format(PyExc_IndexError, "Stroke[index]: index %d out of range", keynum);
83 return nullptr;
84 }
85 return BPy_StrokeVertex_from_StrokeVertex(self->s->strokeVerticeAt(keynum));
86}
87
89 /* Wrap. */
90 Stroke_compute_sampling_doc,
91 ".. method:: compute_sampling(n)\n"
92 "\n"
93 " Compute the sampling needed to get N vertices. If the\n"
94 " specified number of vertices is less than the actual number of\n"
95 " vertices, the actual sampling value is returned. (To remove Vertices,\n"
96 " use the RemoveVertex() method of this class.)\n"
97 "\n"
98 " :arg n: The number of stroke vertices we eventually want\n"
99 " in our Stroke.\n"
100 " :type n: int\n"
101 " :return: The sampling that must be used in the Resample(float)\n"
102 " method.\n"
103 " :rtype: float\n");
104static PyObject *Stroke_compute_sampling(BPy_Stroke *self, PyObject *args, PyObject *kwds)
105{
106 static const char *kwlist[] = {"n", nullptr};
107 int i;
108
109 if (!PyArg_ParseTupleAndKeywords(args, kwds, "i", (char **)kwlist, &i)) {
110 return nullptr;
111 }
112 return PyFloat_FromDouble(self->s->ComputeSampling(i));
113}
114
116 /* Wrap. */
117 Stroke_resample_doc,
118 ".. method:: resample(n)\n"
119 " resample(sampling)\n"
120 "\n"
121 " Resamples the stroke so using one of two methods with the goal\n"
122 " of creating a stroke with fewer points and the same shape.\n"
123 "\n"
124 " :arg n: Resamples the stroke so that it eventually has N points. That means\n"
125 " it is going to add N-vertices_size, where vertices_size is the\n"
126 " number of points we already have. If vertices_size >= N, no\n"
127 " resampling is done.\n"
128 " :type n: int\n"
129 " :arg sampling: Resamples the stroke with a given sampling value. If the\n"
130 " sampling is smaller than the actual sampling value, no resampling is done.\n"
131 " :type sampling: float\n");
132static PyObject *Stroke_resample(BPy_Stroke *self, PyObject *args, PyObject *kwds)
133{
134 static const char *kwlist_1[] = {"n", nullptr};
135 static const char *kwlist_2[] = {"sampling", nullptr};
136 int i;
137 float f;
138
139 if (PyArg_ParseTupleAndKeywords(args, kwds, "i", (char **)kwlist_1, &i)) {
140 if (self->s->Resample(i) < 0) {
141 PyErr_SetString(PyExc_RuntimeError, "Stroke resampling (by vertex count) failed");
142 return nullptr;
143 }
144 }
145 else if ((void)PyErr_Clear(),
146 PyArg_ParseTupleAndKeywords(args, kwds, "f", (char **)kwlist_2, &f))
147 {
148 if (self->s->Resample(f) < 0) {
149 PyErr_SetString(PyExc_RuntimeError, "Stroke resampling (by vertex interval) failed");
150 return nullptr;
151 }
152 }
153 else {
154 PyErr_SetString(PyExc_TypeError, "invalid argument");
155 return nullptr;
156 }
157 Py_RETURN_NONE;
158}
159
161 /* Wrap. */
162 Stroke_insert_vertex_doc,
163 ".. method:: insert_vertex(vertex, next)\n"
164 "\n"
165 " Inserts the StrokeVertex given as argument into the Stroke before the\n"
166 " point specified by next. The length and curvilinear abscissa are\n"
167 " updated consequently.\n"
168 "\n"
169 " :arg vertex: The StrokeVertex to insert in the Stroke.\n"
170 " :type vertex: :class:`StrokeVertex`\n"
171 " :arg next: A StrokeVertexIterator pointing to the StrokeVertex\n"
172 " before which vertex must be inserted.\n"
173 " :type next: :class:`StrokeVertexIterator`\n");
174static PyObject *Stroke_insert_vertex(BPy_Stroke *self, PyObject *args, PyObject *kwds)
175{
176 static const char *kwlist[] = {"vertex", "next", nullptr};
177 PyObject *py_sv = nullptr, *py_sv_it = nullptr;
178
179 if (!PyArg_ParseTupleAndKeywords(args,
180 kwds,
181 "O!O!",
182 (char **)kwlist,
184 &py_sv,
186 &py_sv_it))
187 {
188 return nullptr;
189 }
190
191 /* Make the wrapped StrokeVertex internal. */
192 ((BPy_StrokeVertex *)py_sv)->py_cp.py_if0D.borrowed = true;
193
194 StrokeVertex *sv = ((BPy_StrokeVertex *)py_sv)->sv;
196 self->s->InsertVertex(sv, sv_it);
197 Py_RETURN_NONE;
198}
199
201 /* Wrap. */
202 Stroke_remove_vertex_doc,
203 ".. method:: remove_vertex(vertex)\n"
204 "\n"
205 " Removes the StrokeVertex given as argument from the Stroke. The length\n"
206 " and curvilinear abscissa are updated consequently.\n"
207 "\n"
208 " :arg vertex: the StrokeVertex to remove from the Stroke.\n"
209 " :type vertex: :class:`StrokeVertex`\n");
210static PyObject *Stroke_remove_vertex(BPy_Stroke *self, PyObject *args, PyObject *kwds)
211{
212 static const char *kwlist[] = {"vertex", nullptr};
213 PyObject *py_sv = nullptr;
214
215 if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &StrokeVertex_Type, &py_sv))
216 {
217 return nullptr;
218 }
219 if (((BPy_StrokeVertex *)py_sv)->sv) {
220 self->s->RemoveVertex(((BPy_StrokeVertex *)py_sv)->sv);
221 }
222 else {
223 PyErr_SetString(PyExc_TypeError, "invalid argument");
224 return nullptr;
225 }
226 Py_RETURN_NONE;
227}
228
230 /* Wrap. */
231 Stroke_remove_all_vertices_doc,
232 ".. method:: remove_all_vertices()\n"
233 "\n"
234 " Removes all vertices from the Stroke.\n");
236{
237 self->s->RemoveAllVertices();
238 Py_RETURN_NONE;
239}
240
242 /* Wrap. */
243 Stroke_update_length_doc,
244 ".. method:: update_length()\n"
245 "\n"
246 " Updates the 2D length of the Stroke.\n");
248{
249 self->s->UpdateLength();
250 Py_RETURN_NONE;
251}
252
254 /* Wrap. */
255 Stroke_stroke_vertices_begin_doc,
256 ".. method:: stroke_vertices_begin(t=0.0)\n"
257 "\n"
258 " Returns a StrokeVertexIterator pointing on the first StrokeVertex of\n"
259 " the Stroke. One can specify a sampling value to re-sample the Stroke\n"
260 " on the fly if needed.\n"
261 "\n"
262 " :arg t: The resampling value with which we want our Stroke to be\n"
263 " resampled. If 0 is specified, no resampling is done.\n"
264 " :type t: float\n"
265 " :return: A StrokeVertexIterator pointing on the first StrokeVertex.\n"
266 " :rtype: :class:`StrokeVertexIterator`\n");
267static PyObject *Stroke_stroke_vertices_begin(BPy_Stroke *self, PyObject *args, PyObject *kwds)
268{
269 static const char *kwlist[] = {"t", nullptr};
270 float f = 0.0f;
271
272 if (!PyArg_ParseTupleAndKeywords(args, kwds, "|f", (char **)kwlist, &f)) {
273 return nullptr;
274 }
275 StrokeInternal::StrokeVertexIterator sv_it(self->s->strokeVerticesBegin(f));
277}
278
280 /* Wrap. */
281 Stroke_stroke_vertices_end_doc,
282 ".. method:: stroke_vertices_end()\n"
283 "\n"
284 " Returns a StrokeVertexIterator pointing after the last StrokeVertex\n"
285 " of the Stroke.\n"
286 "\n"
287 " :return: A StrokeVertexIterator pointing after the last StrokeVertex.\n"
288 " :rtype: :class:`StrokeVertexIterator`\n");
290{
291 StrokeInternal::StrokeVertexIterator sv_it(self->s->strokeVerticesEnd());
293}
294
296 /* Wrap. */
297 Stroke_reversed_doc,
298 ".. method:: __reversed__()\n"
299 "\n"
300 " Returns a StrokeVertexIterator iterating over the vertices of the Stroke\n"
301 " in the reversed order (from the last to the first).\n"
302 "\n"
303 " :return: A StrokeVertexIterator pointing after the last StrokeVertex.\n"
304 " :rtype: :class:`StrokeVertexIterator`\n");
306{
307 StrokeInternal::StrokeVertexIterator sv_it(self->s->strokeVerticesEnd());
309}
310
312 /* Wrap. */
313 Stroke_stroke_vertices_size_doc,
314 ".. method:: stroke_vertices_size()\n"
315 "\n"
316 " Returns the number of StrokeVertex constituting the Stroke.\n"
317 "\n"
318 " :return: The number of stroke vertices.\n"
319 " :rtype: int\n");
321{
322 return PyLong_FromLong(self->s->strokeVerticesSize());
323}
324
325#ifdef __GNUC__
326# ifdef __clang__
327# pragma clang diagnostic push
328# pragma clang diagnostic ignored "-Wcast-function-type"
329# else
330# pragma GCC diagnostic push
331# pragma GCC diagnostic ignored "-Wcast-function-type"
332# endif
333#endif
334
335static PyMethodDef BPy_Stroke_methods[] = {
336 {"compute_sampling",
337 (PyCFunction)Stroke_compute_sampling,
338 METH_VARARGS | METH_KEYWORDS,
339 Stroke_compute_sampling_doc},
340 {"resample", (PyCFunction)Stroke_resample, METH_VARARGS | METH_KEYWORDS, Stroke_resample_doc},
341 {"remove_all_vertices",
342 (PyCFunction)Stroke_remove_all_vertices,
343 METH_NOARGS,
344 Stroke_remove_all_vertices_doc},
345 {"remove_vertex",
346 (PyCFunction)Stroke_remove_vertex,
347 METH_VARARGS | METH_KEYWORDS,
348 Stroke_remove_vertex_doc},
349 {"insert_vertex",
350 (PyCFunction)Stroke_insert_vertex,
351 METH_VARARGS | METH_KEYWORDS,
352 Stroke_insert_vertex_doc},
353 {"update_length", (PyCFunction)Stroke_update_length, METH_NOARGS, Stroke_update_length_doc},
354 {"stroke_vertices_begin",
355 (PyCFunction)Stroke_stroke_vertices_begin,
356 METH_VARARGS | METH_KEYWORDS,
357 Stroke_stroke_vertices_begin_doc},
358 {"stroke_vertices_end",
359 (PyCFunction)Stroke_stroke_vertices_end,
360 METH_NOARGS,
361 Stroke_stroke_vertices_end_doc},
362 {"__reversed__", (PyCFunction)Stroke_reversed, METH_NOARGS, Stroke_reversed_doc},
363 {"stroke_vertices_size",
364 (PyCFunction)Stroke_stroke_vertices_size,
365 METH_NOARGS,
366 Stroke_stroke_vertices_size_doc},
367 {nullptr, nullptr, 0, nullptr},
368};
369
370#ifdef __GNUC__
371# ifdef __clang__
372# pragma clang diagnostic pop
373# else
374# pragma GCC diagnostic pop
375# endif
376#endif
377
378/*----------------------Stroke get/setters ----------------------------*/
379
381 /* Wrap. */
382 Stroke_medium_type_doc,
383 "The MediumType used for this Stroke.\n"
384 "\n"
385 ":type: :class:`MediumType`\n");
386static PyObject *Stroke_medium_type_get(BPy_Stroke *self, void * /*closure*/)
387{
388 return BPy_MediumType_from_MediumType(self->s->getMediumType());
389}
390
391static int Stroke_medium_type_set(BPy_Stroke *self, PyObject *value, void * /*closure*/)
392{
393 if (!BPy_MediumType_Check(value)) {
394 PyErr_SetString(PyExc_TypeError, "value must be a MediumType");
395 return -1;
396 }
397 self->s->setMediumType(MediumType_from_BPy_MediumType(value));
398 return 0;
399}
400
402 /* Wrap. */
403 Stroke_texture_id_doc,
404 "The ID of the texture used to simulate th marks system for this Stroke.\n"
405 "\n"
406 ":type: int\n");
407static PyObject *Stroke_texture_id_get(BPy_Stroke *self, void * /*closure*/)
408{
409 return PyLong_FromLong(self->s->getTextureId());
410}
411
412static int Stroke_texture_id_set(BPy_Stroke *self, PyObject *value, void * /*closure*/)
413{
414 uint i = PyLong_AsUnsignedLong(value);
415 if (PyErr_Occurred()) {
416 return -1;
417 }
418 self->s->setTextureId(i);
419 return 0;
420}
421
423 /* Wrap. */
424 Stroke_tips_doc,
425 "True if this Stroke uses a texture with tips, and false otherwise.\n"
426 "\n"
427 ":type: bool\n");
428static PyObject *Stroke_tips_get(BPy_Stroke *self, void * /*closure*/)
429{
430 return PyBool_from_bool(self->s->hasTips());
431}
432
433static int Stroke_tips_set(BPy_Stroke *self, PyObject *value, void * /*closure*/)
434{
435 if (!PyBool_Check(value)) {
436 return -1;
437 }
438 self->s->setTips(bool_from_PyBool(value));
439 return 0;
440}
441
443 /* Wrap. */
444 Stroke_length_2d_doc,
445 "The 2D length of the Stroke.\n"
446 "\n"
447 ":type: float\n");
448static PyObject *Stroke_length_2d_get(BPy_Stroke *self, void * /*closure*/)
449{
450 return PyFloat_FromDouble(self->s->getLength2D());
451}
452
453static int Stroke_length_2d_set(BPy_Stroke *self, PyObject *value, void * /*closure*/)
454{
455 float scalar;
456 if ((scalar = PyFloat_AsDouble(value)) == -1.0f && PyErr_Occurred()) {
457 /* parsed item not a number */
458 PyErr_SetString(PyExc_TypeError, "value must be a number");
459 return -1;
460 }
461 self->s->setLength(scalar);
462 return 0;
463}
464
466 /* Wrap. */
467 Stroke_id_doc,
468 "The Id of this Stroke.\n"
469 "\n"
470 ":type: :class:`Id`\n");
471static PyObject *Stroke_id_get(BPy_Stroke *self, void * /*closure*/)
472{
473 Id id(self->s->getId());
474 return BPy_Id_from_Id(id); // return a copy
475}
476
477static int Stroke_id_set(BPy_Stroke *self, PyObject *value, void * /*closure*/)
478{
479 if (!BPy_Id_Check(value)) {
480 PyErr_SetString(PyExc_TypeError, "value must be an Id");
481 return -1;
482 }
483 self->s->setId(*(((BPy_Id *)value)->id));
484 return 0;
485}
486
487static PyGetSetDef BPy_Stroke_getseters[] = {
488 {"medium_type",
491 Stroke_medium_type_doc,
492 nullptr},
493 {"texture_id",
494 (getter)Stroke_texture_id_get,
495 (setter)Stroke_texture_id_set,
496 Stroke_texture_id_doc,
497 nullptr},
498 {"tips", (getter)Stroke_tips_get, (setter)Stroke_tips_set, Stroke_tips_doc, nullptr},
499 {"length_2d",
500 (getter)Stroke_length_2d_get,
501 (setter)Stroke_length_2d_set,
502 Stroke_length_2d_doc,
503 nullptr},
504 {"id", (getter)Stroke_id_get, (setter)Stroke_id_set, Stroke_id_doc, nullptr},
505 {nullptr, nullptr, nullptr, nullptr, nullptr} /* Sentinel */
506};
507
508/*-----------------------BPy_Stroke type definition ------------------------------*/
509
510static PySequenceMethods BPy_Stroke_as_sequence = {
511 /*sq_length*/ (lenfunc)Stroke_sq_length,
512 /*sq_concat*/ nullptr,
513 /*sq_repeat*/ nullptr,
514 /*sq_item*/ (ssizeargfunc)Stroke_sq_item,
515 /*was_sq_slice*/ nullptr, /* DEPRECATED. */
516 /*sq_ass_item*/ nullptr,
517 /*was_sq_ass_slice*/ nullptr, /* DEPRECATED. */
518 /*sq_contains*/ nullptr,
519 /*sq_inplace_concat*/ nullptr,
520 /*sq_inplace_repeat*/ nullptr,
521};
522
523PyTypeObject Stroke_Type = {
524 /*ob_base*/ PyVarObject_HEAD_INIT(nullptr, 0)
525 /*tp_name*/ "Stroke",
526 /*tp_basicsize*/ sizeof(BPy_Stroke),
527 /*tp_itemsize*/ 0,
528 /*tp_dealloc*/ nullptr,
529 /*tp_vectorcall_offset*/ 0,
530 /*tp_getattr*/ nullptr,
531 /*tp_setattr*/ nullptr,
532 /*tp_as_async*/ nullptr,
533 /*tp_repr*/ nullptr,
534 /*tp_as_number*/ nullptr,
535 /*tp_as_sequence*/ &BPy_Stroke_as_sequence,
536 /*tp_as_mapping*/ nullptr,
537 /*tp_hash*/ nullptr,
538 /*tp_call*/ nullptr,
539 /*tp_str*/ nullptr,
540 /*tp_getattro*/ nullptr,
541 /*tp_setattro*/ nullptr,
542 /*tp_as_buffer*/ nullptr,
543 /*tp_flags*/ Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
544 /*tp_doc*/ Stroke_doc,
545 /*tp_traverse*/ nullptr,
546 /*tp_clear*/ nullptr,
547 /*tp_richcompare*/ nullptr,
548 /*tp_weaklistoffset*/ 0,
549 /*tp_iter*/ (getiterfunc)Stroke_iter,
550 /*tp_iternext*/ nullptr,
551 /*tp_methods*/ BPy_Stroke_methods,
552 /*tp_members*/ nullptr,
553 /*tp_getset*/ BPy_Stroke_getseters,
554 /*tp_base*/ &Interface1D_Type,
555 /*tp_dict*/ nullptr,
556 /*tp_descr_get*/ nullptr,
557 /*tp_descr_set*/ nullptr,
558 /*tp_dictoffset*/ 0,
559 /*tp_init*/ (initproc)Stroke_init,
560 /*tp_alloc*/ nullptr,
561 /*tp_new*/ nullptr,
562};
563
unsigned int uint
PyObject * BPy_StrokeVertexIterator_from_StrokeVertexIterator(StrokeInternal::StrokeVertexIterator &sv_it, bool reversed)
PyObject * BPy_Id_from_Id(Id &id)
bool bool_from_PyBool(PyObject *b)
PyObject * BPy_StrokeVertex_from_StrokeVertex(StrokeVertex &sv)
PyObject * BPy_MediumType_from_MediumType(Stroke::MediumType n)
Stroke::MediumType MediumType_from_BPy_MediumType(PyObject *obj)
PyObject * PyBool_from_bool(bool b)
#define BPy_Id_Check(v)
Definition BPy_Id.h:23
PyTypeObject Interface1D_Type
#define BPy_MediumType_Check(v)
PyTypeObject StrokeVertexIterator_Type
PyTypeObject StrokeVertex_Type
static PyObject * Stroke_remove_vertex(BPy_Stroke *self, PyObject *args, PyObject *kwds)
static int Stroke_medium_type_set(BPy_Stroke *self, PyObject *value, void *)
static PyObject * Stroke_update_length(BPy_Stroke *self)
static Py_ssize_t Stroke_sq_length(BPy_Stroke *self)
static PyObject * Stroke_texture_id_get(BPy_Stroke *self, void *)
PyTypeObject Stroke_Type
static PyObject * Stroke_iter(PyObject *self)
static PyObject * Stroke_remove_all_vertices(BPy_Stroke *self)
static PyObject * Stroke_resample(BPy_Stroke *self, PyObject *args, PyObject *kwds)
static int Stroke_length_2d_set(BPy_Stroke *self, PyObject *value, void *)
static PyObject * Stroke_stroke_vertices_end(BPy_Stroke *self)
static PyObject * Stroke_medium_type_get(BPy_Stroke *self, void *)
static PySequenceMethods BPy_Stroke_as_sequence
static PyObject * Stroke_stroke_vertices_begin(BPy_Stroke *self, PyObject *args, PyObject *kwds)
static PyObject * Stroke_insert_vertex(BPy_Stroke *self, PyObject *args, PyObject *kwds)
static PyObject * Stroke_length_2d_get(BPy_Stroke *self, void *)
static PyMethodDef BPy_Stroke_methods[]
static int Stroke_id_set(BPy_Stroke *self, PyObject *value, void *)
static int Stroke_tips_set(BPy_Stroke *self, PyObject *value, void *)
PyDoc_STRVAR(Stroke_doc, "Class hierarchy: :class:`Interface1D` > :class:`Stroke`\n" "\n" "Class to define a stroke. A stroke is made of a set of 2D vertices\n" "(:class:`StrokeVertex`), regularly spaced out. This set of vertices\n" "defines the stroke's backbone geometry. Each of these stroke vertices\n" "defines the stroke's shape and appearance at this vertex position.\n" "\n" ".. method:: Stroke()\n" " Stroke(brother)\n" "\n" " Creates a :class:`Stroke` using the default constructor or copy constructor\n")
static PyObject * Stroke_tips_get(BPy_Stroke *self, void *)
static PyObject * Stroke_reversed(BPy_Stroke *self)
static int Stroke_texture_id_set(BPy_Stroke *self, PyObject *value, void *)
static PyObject * Stroke_stroke_vertices_size(BPy_Stroke *self)
static PyObject * Stroke_compute_sampling(BPy_Stroke *self, PyObject *args, PyObject *kwds)
static int Stroke_init(BPy_Stroke *self, PyObject *args, PyObject *kwds)
static PyGetSetDef BPy_Stroke_getseters[]
static PyObject * Stroke_sq_item(BPy_Stroke *self, Py_ssize_t keynum)
static PyObject * Stroke_id_get(BPy_Stroke *self, void *)
PyObject * self
inherits from class Rep
Definition AppCanvas.cpp:20
i
Definition text_draw.cc:230