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