1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 */
16
17 /** \file
18 * \ingroup freestyle
19 */
20
21 #include "BPy_StrokeVertexIterator.h"
22
23 #include "../BPy_Convert.h"
24 #include "../Interface1D/BPy_Stroke.h"
25 #include "BPy_Interface0DIterator.h"
26
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30
31 ///////////////////////////////////////////////////////////////////////////////////////////
32
33 //------------------------INSTANCE METHODS ----------------------------------
34
35 PyDoc_STRVAR(StrokeVertexIterator_doc,
36 "Class hierarchy: :class:`Iterator` > :class:`StrokeVertexIterator`\n"
37 "\n"
38 "Class defining an iterator designed to iterate over the\n"
39 ":class:`StrokeVertex` of a :class:`Stroke`. An instance of a\n"
40 "StrokeVertexIterator can be obtained from a Stroke by calling\n"
41 "iter(), stroke_vertices_begin() or stroke_vertices_begin(). It is iterating\n"
42 "over the same vertices as an :class:`Interface0DIterator`. The difference\n"
43 "resides in the object access: an Interface0DIterator only allows\n"
44 "access to an Interface0D while one might need to access the\n"
45 "specialized StrokeVertex type. In this case, one should use a\n"
46 "StrokeVertexIterator. To call functions of the UnaryFuntion0D type,\n"
47 "a StrokeVertexIterator can be converted to an Interface0DIterator by\n"
48 "by calling Interface0DIterator(it).\n"
49 "\n"
50 ".. method:: __init__()\n"
51 " __init__(brother)\n"
52 "\n"
53 " Creates a :class:`StrokeVertexIterator` using either the\n"
54 " default constructor or the copy constructor.\n"
55 "\n"
56 " :arg brother: A StrokeVertexIterator object.\n"
57 " :type brother: :class:`StrokeVertexIterator`");
58
StrokeVertexIterator_init(BPy_StrokeVertexIterator * self,PyObject * args,PyObject * kwds)59 static int StrokeVertexIterator_init(BPy_StrokeVertexIterator *self,
60 PyObject *args,
61 PyObject *kwds)
62 {
63 static const char *kwlist_1[] = {"brother", NULL};
64 static const char *kwlist_2[] = {"stroke", NULL};
65 PyObject *brother = 0, *stroke = 0;
66
67 if (PyArg_ParseTupleAndKeywords(
68 args, kwds, "O!", (char **)kwlist_1, &StrokeVertexIterator_Type, &brother)) {
69 self->sv_it = new StrokeInternal::StrokeVertexIterator(
70 *(((BPy_StrokeVertexIterator *)brother)->sv_it));
71 self->reversed = ((BPy_StrokeVertexIterator *)brother)->reversed;
72 self->at_start = ((BPy_StrokeVertexIterator *)brother)->at_start;
73 }
74
75 else if ((void)PyErr_Clear(),
76 PyArg_ParseTupleAndKeywords(
77 args, kwds, "|O!", (char **)kwlist_2, &Stroke_Type, &stroke)) {
78 if (!stroke) {
79 self->sv_it = new StrokeInternal::StrokeVertexIterator();
80 }
81 else {
82 self->sv_it = new StrokeInternal::StrokeVertexIterator(
83 ((BPy_Stroke *)stroke)->s->strokeVerticesBegin());
84 }
85 self->reversed = false;
86 self->at_start = true;
87 }
88 else {
89 PyErr_SetString(PyExc_TypeError, "argument 1 must be StrokeVertexIterator or Stroke");
90 return -1;
91 }
92 self->py_it.it = self->sv_it;
93 return 0;
94 }
95
StrokeVertexIterator_iter(BPy_StrokeVertexIterator * self)96 static PyObject *StrokeVertexIterator_iter(BPy_StrokeVertexIterator *self)
97 {
98 Py_INCREF(self);
99 self->at_start = true;
100 return (PyObject *)self;
101 }
102
StrokeVertexIterator_iternext(BPy_StrokeVertexIterator * self)103 static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self)
104 {
105 /* Because Freestyle iterators for which it.isEnd() holds true have no valid object
106 * (they point to the past-the-end element and can't be dereferenced), we have to check
107 * iterators for validity.
108 * Additionally, the at_start attribute is used to keep Freestyle iterator objects
109 * and Python for loops in sync. */
110
111 if (self->reversed) {
112 if (self->sv_it->isBegin()) {
113 PyErr_SetNone(PyExc_StopIteration);
114 return NULL;
115 }
116 self->sv_it->decrement();
117 }
118 else {
119 /* If sv_it.isEnd() is true, the iterator can't be incremented. */
120 if (self->sv_it->isEnd()) {
121 PyErr_SetNone(PyExc_StopIteration);
122 return NULL;
123 }
124 /* If at the start of the iterator, only return the object
125 * and don't increment, to keep for-loops in sync */
126 if (self->at_start) {
127 self->at_start = false;
128 }
129 /* If sv_it.atLast() is true, the iterator is currently pointing to the final valid element.
130 * Incrementing it further would lead to a state that the iterator can't be dereferenced. */
131 else if (self->sv_it->atLast()) {
132 PyErr_SetNone(PyExc_StopIteration);
133 return NULL;
134 }
135 else {
136 self->sv_it->increment();
137 }
138 }
139 StrokeVertex *sv = self->sv_it->operator->();
140 return BPy_StrokeVertex_from_StrokeVertex(*sv);
141 }
142
143 /*----------------------StrokeVertexIterator methods ----------------------------*/
144
145 PyDoc_STRVAR(StrokeVertexIterator_incremented_doc,
146 ".. method:: incremented()\n"
147 "\n"
148 " Returns a copy of an incremented StrokeVertexIterator.\n"
149 "\n"
150 " :return: A StrokeVertexIterator pointing the next StrokeVertex.\n"
151 " :rtype: :class:`StrokeVertexIterator`");
152
StrokeVertexIterator_incremented(BPy_StrokeVertexIterator * self)153 static PyObject *StrokeVertexIterator_incremented(BPy_StrokeVertexIterator *self)
154 {
155 if (self->sv_it->isEnd()) {
156 PyErr_SetString(PyExc_RuntimeError, "cannot increment any more");
157 return NULL;
158 }
159 StrokeInternal::StrokeVertexIterator copy(*self->sv_it);
160 copy.increment();
161 return BPy_StrokeVertexIterator_from_StrokeVertexIterator(copy, self->reversed);
162 }
163
164 PyDoc_STRVAR(StrokeVertexIterator_decremented_doc,
165 ".. method:: decremented()\n"
166 "\n"
167 " Returns a copy of a decremented StrokeVertexIterator.\n"
168 "\n"
169 " :return: A StrokeVertexIterator pointing the previous StrokeVertex.\n"
170 " :rtype: :class:`StrokeVertexIterator`");
171
StrokeVertexIterator_decremented(BPy_StrokeVertexIterator * self)172 static PyObject *StrokeVertexIterator_decremented(BPy_StrokeVertexIterator *self)
173 {
174 if (self->sv_it->isBegin()) {
175 PyErr_SetString(PyExc_RuntimeError, "cannot decrement any more");
176 return NULL;
177 }
178 StrokeInternal::StrokeVertexIterator copy(*self->sv_it);
179 copy.decrement();
180 return BPy_StrokeVertexIterator_from_StrokeVertexIterator(copy, self->reversed);
181 }
182
183 PyDoc_STRVAR(StrokeVertexIterator_reversed_doc,
184 ".. method:: reversed()\n"
185 "\n"
186 " Returns a StrokeVertexIterator that traverses stroke vertices in the\n"
187 " reversed order.\n"
188 "\n"
189 " :return: A StrokeVertexIterator traversing stroke vertices backward.\n"
190 " :rtype: :class:`StrokeVertexIterator`");
191
StrokeVertexIterator_reversed(BPy_StrokeVertexIterator * self)192 static PyObject *StrokeVertexIterator_reversed(BPy_StrokeVertexIterator *self)
193 {
194 return BPy_StrokeVertexIterator_from_StrokeVertexIterator(*self->sv_it, !self->reversed);
195 }
196
197 static PyMethodDef BPy_StrokeVertexIterator_methods[] = {
198 {"incremented",
199 (PyCFunction)StrokeVertexIterator_incremented,
200 METH_NOARGS,
201 StrokeVertexIterator_incremented_doc},
202 {"decremented",
203 (PyCFunction)StrokeVertexIterator_decremented,
204 METH_NOARGS,
205 StrokeVertexIterator_decremented_doc},
206 {"reversed",
207 (PyCFunction)StrokeVertexIterator_reversed,
208 METH_NOARGS,
209 StrokeVertexIterator_reversed_doc},
210 {NULL, NULL, 0, NULL},
211 };
212
213 /*----------------------StrokeVertexIterator get/setters ----------------------------*/
214
215 PyDoc_STRVAR(StrokeVertexIterator_object_doc,
216 "The StrokeVertex object currently pointed to by this iterator.\n"
217 "\n"
218 ":type: :class:`StrokeVertex`");
219
StrokeVertexIterator_object_get(BPy_StrokeVertexIterator * self,void * UNUSED (closure))220 static PyObject *StrokeVertexIterator_object_get(BPy_StrokeVertexIterator *self,
221 void *UNUSED(closure))
222 {
223 if (self->sv_it->isEnd()) {
224 PyErr_SetString(PyExc_RuntimeError, "iteration has stopped");
225 return NULL;
226 }
227 StrokeVertex *sv = self->sv_it->operator->();
228 if (sv) {
229 return BPy_StrokeVertex_from_StrokeVertex(*sv);
230 }
231 Py_RETURN_NONE;
232 }
233
234 PyDoc_STRVAR(StrokeVertexIterator_t_doc,
235 "The curvilinear abscissa of the current point.\n"
236 "\n"
237 ":type: float");
238
StrokeVertexIterator_t_get(BPy_StrokeVertexIterator * self,void * UNUSED (closure))239 static PyObject *StrokeVertexIterator_t_get(BPy_StrokeVertexIterator *self, void *UNUSED(closure))
240 {
241 return PyFloat_FromDouble(self->sv_it->t());
242 }
243
244 PyDoc_STRVAR(StrokeVertexIterator_u_doc,
245 "The point parameter at the current point in the stroke (0 <= u <= 1).\n"
246 "\n"
247 ":type: float");
248
StrokeVertexIterator_u_get(BPy_StrokeVertexIterator * self,void * UNUSED (closure))249 static PyObject *StrokeVertexIterator_u_get(BPy_StrokeVertexIterator *self, void *UNUSED(closure))
250 {
251 return PyFloat_FromDouble(self->sv_it->u());
252 }
253
254 PyDoc_STRVAR(StrokeVertexIterator_at_last_doc,
255 "True if the iterator points to the last valid element.\n"
256 "For its counterpart (pointing to the first valid element), use it.is_begin.\n"
257 "\n"
258 ":type: bool");
259
StrokeVertexIterator_at_last_get(BPy_StrokeVertexIterator * self)260 static PyObject *StrokeVertexIterator_at_last_get(BPy_StrokeVertexIterator *self)
261 {
262 return PyBool_from_bool(self->sv_it->atLast());
263 }
264
265 static PyGetSetDef BPy_StrokeVertexIterator_getseters[] = {
266 {"object",
267 (getter)StrokeVertexIterator_object_get,
268 (setter)NULL,
269 StrokeVertexIterator_object_doc,
270 NULL},
271 {"t", (getter)StrokeVertexIterator_t_get, (setter)NULL, StrokeVertexIterator_t_doc, NULL},
272 {"u", (getter)StrokeVertexIterator_u_get, (setter)NULL, StrokeVertexIterator_u_doc, NULL},
273 {"at_last",
274 (getter)StrokeVertexIterator_at_last_get,
275 (setter)NULL,
276 StrokeVertexIterator_at_last_doc,
277 NULL},
278 {NULL, NULL, NULL, NULL, NULL} /* Sentinel */
279 };
280
281 /*-----------------------BPy_StrokeVertexIterator type definition ------------------------------*/
282
283 PyTypeObject StrokeVertexIterator_Type = {
284 PyVarObject_HEAD_INIT(NULL, 0) "StrokeVertexIterator", /* tp_name */
285 sizeof(BPy_StrokeVertexIterator), /* tp_basicsize */
286 0, /* tp_itemsize */
287 0, /* tp_dealloc */
288 0, /* tp_print */
289 0, /* tp_getattr */
290 0, /* tp_setattr */
291 0, /* tp_reserved */
292 0, /* tp_repr */
293 0, /* tp_as_number */
294 0, /* tp_as_sequence */
295 0, /* tp_as_mapping */
296 0, /* tp_hash */
297 0, /* tp_call */
298 0, /* tp_str */
299 0, /* tp_getattro */
300 0, /* tp_setattro */
301 0, /* tp_as_buffer */
302 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
303 StrokeVertexIterator_doc, /* tp_doc */
304 0, /* tp_traverse */
305 0, /* tp_clear */
306 0, /* tp_richcompare */
307 0, /* tp_weaklistoffset */
308 (getiterfunc)StrokeVertexIterator_iter, /* tp_iter */
309 (iternextfunc)StrokeVertexIterator_iternext, /* tp_iternext */
310 BPy_StrokeVertexIterator_methods, /* tp_methods */
311 0, /* tp_members */
312 BPy_StrokeVertexIterator_getseters, /* tp_getset */
313 &Iterator_Type, /* tp_base */
314 0, /* tp_dict */
315 0, /* tp_descr_get */
316 0, /* tp_descr_set */
317 0, /* tp_dictoffset */
318 (initproc)StrokeVertexIterator_init, /* tp_init */
319 0, /* tp_alloc */
320 0, /* tp_new */
321 };
322
323 ///////////////////////////////////////////////////////////////////////////////////////////
324
325 #ifdef __cplusplus
326 }
327 #endif
328