57ec15f4150d12d89437e10518c4a8803e26162f
[blender.git] / source / blender / freestyle / intern / python / BPy_Operators.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * ***** END GPL LICENSE BLOCK *****
19  */
20
21 /** \file source/blender/freestyle/intern/python/BPy_Operators.cpp
22  *  \ingroup freestyle
23  */
24
25 #include "BPy_Operators.h"
26
27 #include "BPy_BinaryPredicate1D.h"
28 #include "BPy_UnaryPredicate0D.h"
29 #include "BPy_UnaryPredicate1D.h"
30 #include "UnaryFunction0D/BPy_UnaryFunction0DDouble.h"
31 #include "UnaryFunction1D/BPy_UnaryFunction1DVoid.h"
32 #include "Iterator/BPy_ViewEdgeIterator.h"
33 #include "Iterator/BPy_ChainingIterator.h"
34 #include "BPy_StrokeShader.h"
35 #include "BPy_Convert.h"
36
37 #ifdef __cplusplus
38 extern "C" {
39 #endif
40
41 ///////////////////////////////////////////////////////////////////////////////////////////
42
43 //-------------------MODULE INITIALIZATION--------------------------------
44 int Operators_Init(PyObject *module)
45 {
46         if (module == NULL)
47                 return -1;
48
49         if (PyType_Ready(&Operators_Type) < 0)
50                 return -1;
51         Py_INCREF(&Operators_Type);
52         PyModule_AddObject(module, "Operators", (PyObject *)&Operators_Type);
53
54         return 0;
55 }
56
57 //------------------------INSTANCE METHODS ----------------------------------
58
59 PyDoc_STRVAR(Operators_doc,
60 "Class defining the operators used in a style module.  There are five\n"
61 "types of operators: Selection, chaining, splitting, sorting and\n"
62 "creation.  All these operators are user controlled through functors,\n"
63 "predicates and shaders that are taken as arguments.");
64
65 static void Operators_dealloc(BPy_Operators *self)
66 {
67         Py_TYPE(self)->tp_free((PyObject *)self);
68 }
69
70 PyDoc_STRVAR(Operators_select_doc,
71 ".. staticmethod:: select(pred)\n"
72 "\n"
73 "   Selects the ViewEdges of the ViewMap verifying a specified\n"
74 "   condition.\n"
75 "\n"
76 "   :arg pred: The predicate expressing this condition.\n"
77 "   :type pred: :class:`UnaryPredicate1D`");
78
79 static PyObject *Operators_select(BPy_Operators *self, PyObject *args, PyObject *kwds)
80 {
81         static const char *kwlist[] = {"pred", NULL};
82         PyObject *obj = 0;
83
84         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &UnaryPredicate1D_Type, &obj))
85                 return NULL;
86         if (!((BPy_UnaryPredicate1D *)obj)->up1D) {
87                 PyErr_SetString(PyExc_TypeError, "Operators.select(): 1st argument: invalid UnaryPredicate1D object");
88                 return NULL;
89         }
90         if (Operators::select(*(((BPy_UnaryPredicate1D *)obj)->up1D)) < 0) {
91                 if (!PyErr_Occurred())
92                         PyErr_SetString(PyExc_RuntimeError, "Operators.select() failed");
93                 return NULL;
94         }
95         Py_RETURN_NONE;
96 }
97
98 PyDoc_STRVAR(Operators_chain_doc,
99 ".. staticmethod:: chain(it, pred, modifier)\n"
100 "\n"
101 "   Builds a set of chains from the current set of ViewEdges.  Each\n"
102 "   ViewEdge of the current list starts a new chain.  The chaining\n"
103 "   operator then iterates over the ViewEdges of the ViewMap using the\n"
104 "   user specified iterator.  This operator only iterates using the\n"
105 "   increment operator and is therefore unidirectional.\n"
106 "\n"
107 "   :arg it: The iterator on the ViewEdges of the ViewMap. It contains\n"
108 "      the chaining rule.\n"
109 "   :type it: :class:`ViewEdgeIterator`\n"
110 "   :arg pred: The predicate on the ViewEdge that expresses the\n"
111 "      stopping condition.\n"
112 "   :type pred: :class:`UnaryPredicate1D`\n"
113 "   :arg modifier: A function that takes a ViewEdge as argument and\n"
114 "      that is used to modify the processed ViewEdge state (the\n"
115 "      timestamp incrementation is a typical illustration of such a\n"
116 "      modifier).\n"
117 "   :type modifier: :class:`UnaryFunction1DVoid`\n"
118 "\n"
119 ".. staticmethod:: chain(it, pred)\n"
120 "\n"
121 "   Builds a set of chains from the current set of ViewEdges.  Each\n"
122 "   ViewEdge of the current list starts a new chain.  The chaining\n"
123 "   operator then iterates over the ViewEdges of the ViewMap using the\n"
124 "   user specified iterator.  This operator only iterates using the\n"
125 "   increment operator and is therefore unidirectional.  This chaining\n"
126 "   operator is different from the previous one because it doesn't take\n"
127 "   any modifier as argument.  Indeed, the time stamp (insuring that a\n"
128 "   ViewEdge is processed one time) is automatically managed in this\n"
129 "   case.\n"
130 "\n"
131 "   :arg it: The iterator on the ViewEdges of the ViewMap. It contains\n"
132 "      the chaining rule. \n"
133 "   :type it: :class:`ViewEdgeIterator`\n"
134 "   :arg pred: The predicate on the ViewEdge that expresses the\n"
135 "      stopping condition.\n"
136 "   :type pred: :class:`UnaryPredicate1D`");
137
138 static PyObject *Operators_chain(BPy_Operators *self, PyObject *args, PyObject *kwds)
139 {
140         static const char *kwlist[] = {"it", "pred", "modifier", NULL};
141         PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0;
142
143         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!|O!", (char **)kwlist,
144                                          &ChainingIterator_Type, &obj1,
145                                          &UnaryPredicate1D_Type, &obj2,
146                                          &UnaryFunction1DVoid_Type, &obj3))
147         {
148                 return NULL;
149         }
150         if (!((BPy_ChainingIterator *)obj1)->c_it) {
151                 PyErr_SetString(PyExc_TypeError, "Operators.chain(): 1st argument: invalid ChainingIterator object");
152                 return NULL;
153         }
154         if (!((BPy_UnaryPredicate1D *)obj2)->up1D) {
155                 PyErr_SetString(PyExc_TypeError, "Operators.chain(): 2nd argument: invalid UnaryPredicate1D object");
156                 return NULL;
157         }
158         if (!obj3) {
159                 if (Operators::chain(*(((BPy_ChainingIterator *)obj1)->c_it),
160                                      *(((BPy_UnaryPredicate1D *)obj2)->up1D)) < 0)
161                 {
162                         if (!PyErr_Occurred())
163                                 PyErr_SetString(PyExc_RuntimeError, "Operators.chain() failed");
164                         return NULL;
165                 }
166         }
167         else {
168                 if (!((BPy_UnaryFunction1DVoid *)obj3)->uf1D_void) {
169                         PyErr_SetString(PyExc_TypeError, "Operators.chain(): 3rd argument: invalid UnaryFunction1DVoid object");
170                         return NULL;
171                 }
172                 if (Operators::chain(*(((BPy_ChainingIterator *)obj1)->c_it),
173                                      *(((BPy_UnaryPredicate1D *)obj2)->up1D),
174                                      *(((BPy_UnaryFunction1DVoid *)obj3)->uf1D_void)) < 0)
175                 {
176                         if (!PyErr_Occurred())
177                                 PyErr_SetString(PyExc_RuntimeError, "Operators.chain() failed");
178                         return NULL;
179                 }
180         }
181         Py_RETURN_NONE;
182 }
183
184 PyDoc_STRVAR(Operators_bidirectional_chain_doc,
185 ".. staticmethod:: bidirectional_chain(it, pred)\n"
186 "\n"
187 "   Builds a set of chains from the current set of ViewEdges.  Each\n"
188 "   ViewEdge of the current list potentially starts a new chain.  The\n"
189 "   chaining operator then iterates over the ViewEdges of the ViewMap\n"
190 "   using the user specified iterator.  This operator iterates both using\n"
191 "   the increment and decrement operators and is therefore bidirectional.\n"
192 "   This operator works with a ChainingIterator which contains the\n"
193 "   chaining rules.  It is this last one which can be told to chain only\n"
194 "   edges that belong to the selection or not to process twice a ViewEdge\n"
195 "   during the chaining.  Each time a ViewEdge is added to a chain, its\n"
196 "   chaining time stamp is incremented.  This allows you to keep track of\n"
197 "   the number of chains to which a ViewEdge belongs to.\n"
198 "\n"
199 "   :arg it: The ChainingIterator on the ViewEdges of the ViewMap.  It\n"
200 "      contains the chaining rule.\n"
201 "   :type it: :class:`ChainingIterator`\n"
202 "   :arg pred: The predicate on the ViewEdge that expresses the\n"
203 "      stopping condition.\n"
204 "   :type pred: :class:`UnaryPredicate1D`\n"
205 "\n"
206 ".. staticmethod:: bidirectional_chain(it)\n"
207 "\n"
208 "   The only difference with the above bidirectional chaining algorithm\n"
209 "   is that we don't need to pass a stopping criterion.  This might be\n"
210 "   desirable when the stopping criterion is already contained in the\n"
211 "   iterator definition.  Builds a set of chains from the current set of\n"
212 "   ViewEdges.  Each ViewEdge of the current list potentially starts a new\n"
213 "   chain.  The chaining operator then iterates over the ViewEdges of the\n"
214 "   ViewMap using the user specified iterator.  This operator iterates\n"
215 "   both using the increment and decrement operators and is therefore\n"
216 "   bidirectional.  This operator works with a ChainingIterator which\n"
217 "   contains the chaining rules.  It is this last one which can be told to\n"
218 "   chain only edges that belong to the selection or not to process twice\n"
219 "   a ViewEdge during the chaining.  Each time a ViewEdge is added to a\n"
220 "   chain, its chaining time stamp is incremented.  This allows you to\n"
221 "   keep track of the number of chains to which a ViewEdge belongs to.\n"
222 "\n"
223 "   :arg it: The ChainingIterator on the ViewEdges of the ViewMap.  It\n"
224 "      contains the chaining rule.\n"
225 "   :type it: :class:`ChainingIterator`");
226
227 static PyObject *Operators_bidirectional_chain(BPy_Operators *self, PyObject *args, PyObject *kwds)
228 {
229         static const char *kwlist[] = {"it", "pred", NULL};
230         PyObject *obj1 = 0, *obj2 = 0;
231
232         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!|O!", (char **)kwlist,
233                                          &ChainingIterator_Type, &obj1, &UnaryPredicate1D_Type, &obj2))
234         {
235                 return NULL;
236         }
237         if (!((BPy_ChainingIterator *)obj1)->c_it) {
238                 PyErr_SetString(PyExc_TypeError,
239                                 "Operators.bidirectional_chain(): 1st argument: invalid ChainingIterator object");
240                 return NULL;
241         }
242         if (!obj2) {
243                 if (Operators::bidirectionalChain(*(((BPy_ChainingIterator *)obj1)->c_it)) < 0) {
244                         if (!PyErr_Occurred())
245                                 PyErr_SetString(PyExc_RuntimeError, "Operators.bidirectional_chain() failed");
246                         return NULL;
247                 }
248         }
249         else {
250                 if (!((BPy_UnaryPredicate1D *)obj2)->up1D) {
251                         PyErr_SetString(PyExc_TypeError,
252                                         "Operators.bidirectional_chain(): 2nd argument: invalid UnaryPredicate1D object");
253                         return NULL;
254                 }
255                 if (Operators::bidirectionalChain(*(((BPy_ChainingIterator *)obj1)->c_it),
256                                                   *(((BPy_UnaryPredicate1D *)obj2)->up1D)) < 0)
257                 {
258                         if (!PyErr_Occurred())
259                                 PyErr_SetString(PyExc_RuntimeError, "Operators.bidirectional_chain() failed");
260                         return NULL;
261                 }
262         }
263         Py_RETURN_NONE;
264 }
265
266 PyDoc_STRVAR(Operators_sequential_split_doc,
267 ".. staticmethod:: sequential_split(starting_pred, stopping_pred, sampling=0.0)\n"
268 "\n"
269 "   Splits each chain of the current set of chains in a sequential way.\n"
270 "   The points of each chain are processed (with a specified sampling)\n"
271 "   sequentially. Each time a user specified starting condition is\n"
272 "   verified, a new chain begins and ends as soon as a user-defined\n"
273 "   stopping predicate is verified. This allows chains overlapping rather\n"
274 "   than chains partitioning. The first point of the initial chain is the\n"
275 "   first point of one of the resulting chains. The splitting ends when\n"
276 "   no more chain can start.\n"
277 "\n"
278 "   :arg starting_pred: The predicate on a point that expresses the\n"
279 "      starting condition.\n"
280 "   :type starting_pred: :class:`UnaryPredicate0D`\n"
281 "   :arg stopping_pred: The predicate on a point that expresses the\n"
282 "      stopping condition.\n"
283 "   :type stopping_pred: :class:`UnaryPredicate0D`\n"
284 "   :arg sampling: The resolution used to sample the chain for the\n"
285 "      predicates evaluation. (The chain is not actually resampled;\n"
286 "      a virtual point only progresses along the curve using this\n"
287 "      resolution.)\n"
288 "   :type sampling: float\n"
289 "\n"
290 ".. staticmethod:: sequential_split(pred, sampling=0.0)\n"
291 "\n"
292 "   Splits each chain of the current set of chains in a sequential way.\n"
293 "   The points of each chain are processed (with a specified sampling)\n"
294 "   sequentially and each time a user specified condition is verified,\n"
295 "   the chain is split into two chains.  The resulting set of chains is a\n"
296 "   partition of the initial chain\n"
297 "\n"
298 "   :arg pred: The predicate on a point that expresses the splitting\n"
299 "      condition.\n"
300 "   :type pred: :class:`UnaryPredicate0D`\n"
301 "   :arg sampling: The resolution used to sample the chain for the\n"
302 "      predicate evaluation. (The chain is not actually resampled; a\n"
303 "      virtual point only progresses along the curve using this\n"
304 "      resolution.)\n"
305 "   :type sampling: float");
306
307 static PyObject *Operators_sequential_split(BPy_Operators *self, PyObject *args, PyObject *kwds)
308 {
309         static const char *kwlist_1[] = {"starting_pred", "stopping_pred", "sampling", NULL};
310         static const char *kwlist_2[] = {"pred", "sampling", NULL};
311         PyObject *obj1 = 0, *obj2 = 0;
312         float f = 0.0f;
313
314         if (PyArg_ParseTupleAndKeywords(args, kwds, "O!O!|f", (char **)kwlist_1,
315                                         &UnaryPredicate0D_Type, &obj1, &UnaryPredicate0D_Type, &obj2, &f))
316         {
317                 if (!((BPy_UnaryPredicate0D *)obj1)->up0D) {
318                         PyErr_SetString(PyExc_TypeError,
319                                         "Operators.sequential_split(): 1st argument: invalid UnaryPredicate0D object");
320                         return NULL;
321                 }
322                 if (!((BPy_UnaryPredicate0D *)obj2)->up0D) {
323                         PyErr_SetString(PyExc_TypeError,
324                                         "Operators.sequential_split(): 2nd argument: invalid UnaryPredicate0D object");
325                         return NULL;
326                 }
327                 if (Operators::sequentialSplit(*(((BPy_UnaryPredicate0D *)obj1)->up0D),
328                                                *(((BPy_UnaryPredicate0D *)obj2)->up0D),
329                                                f) < 0)
330                 {
331                         if (!PyErr_Occurred())
332                                 PyErr_SetString(PyExc_RuntimeError, "Operators.sequential_split() failed");
333                         return NULL;
334                 }
335         }
336         else if (PyErr_Clear(), (f = 0.0f),
337                  PyArg_ParseTupleAndKeywords(args, kwds, "O!|f", (char **)kwlist_2,
338                                              &UnaryPredicate0D_Type, &obj1, &f))
339         {
340                 if (!((BPy_UnaryPredicate0D *)obj1)->up0D) {
341                         PyErr_SetString(PyExc_TypeError,
342                                         "Operators.sequential_split(): 1st argument: invalid UnaryPredicate0D object");
343                         return NULL;
344                 }
345                 if (Operators::sequentialSplit(*(((BPy_UnaryPredicate0D *)obj1)->up0D), f) < 0) {
346                         if (!PyErr_Occurred())
347                                 PyErr_SetString(PyExc_RuntimeError, "Operators.sequential_split() failed");
348                         return NULL;
349                 }
350         }
351         else {
352                 PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
353                 return NULL;
354         }
355         Py_RETURN_NONE;
356 }
357
358 PyDoc_STRVAR(Operators_recursive_split_doc,
359 ".. staticmethod:: recursive_split(func, pred_1d, sampling=0.0)\n"
360 "\n"
361 "   Splits the current set of chains in a recursive way.  We process the\n"
362 "   points of each chain (with a specified sampling) to find the point\n"
363 "   minimizing a specified function.  The chain is split in two at this\n"
364 "   point and the two new chains are processed in the same way.  The\n"
365 "   recursivity level is controlled through a predicate 1D that expresses\n"
366 "   a stopping condition on the chain that is about to be processed.\n"
367 "\n"
368 "   :arg func: The Unary Function evaluated at each point of the chain.\n"
369 "     The splitting point is the point minimizing this function.\n"
370 "   :type func: :class:`UnaryFunction0DDouble`\n"
371 "   :arg pred_1d: The Unary Predicate expressing the recursivity stopping\n"
372 "      condition.  This predicate is evaluated for each curve before it\n"
373 "      actually gets split.  If pred_1d(chain) is true, the curve won't be\n"
374 "      split anymore.\n"
375 "   :type pred_1d: :class:`UnaryPredicate1D`\n"
376 "   :arg sampling: The resolution used to sample the chain for the\n"
377 "      predicates evaluation. (The chain is not actually resampled, a\n"
378 "      virtual point only progresses along the curve using this\n"
379 "      resolution.)\n"
380 "   :type sampling: float\n"
381 "\n"
382 ".. staticmethod:: recursive_split(func, pred_0d, pred_1d, sampling=0.0)\n"
383 "\n"
384 "   Splits the current set of chains in a recursive way.  We process the\n"
385 "   points of each chain (with a specified sampling) to find the point\n"
386 "   minimizing a specified function.  The chain is split in two at this\n"
387 "   point and the two new chains are processed in the same way.  The user\n"
388 "   can specify a 0D predicate to make a first selection on the points\n"
389 "   that can potentially be split.  A point that doesn't verify the 0D\n"
390 "   predicate won't be candidate in realizing the min.  The recursivity\n"
391 "   level is controlled through a predicate 1D that expresses a stopping\n"
392 "   condition on the chain that is about to be processed.\n"
393 "\n"
394 "   :arg func: The Unary Function evaluated at each point of the chain.\n"
395 "      The splitting point is the point minimizing this function.\n"
396 "   :type func: :class:`UnaryFunction0DDouble`\n"
397 "   :arg pred_0d: The Unary Predicate 0D used to select the candidate\n"
398 "      points where the split can occur.  For example, it is very likely\n"
399 "      that would rather have your chain splitting around its middle\n"
400 "      point than around one of its extremities.  A 0D predicate working\n"
401 "      on the curvilinear abscissa allows to add this kind of constraints.\n"
402 "   :type pred_0d: :class:`UnaryPredicate0D`\n"
403 "   :arg pred_1d: The Unary Predicate expressing the recursivity stopping\n"
404 "      condition. This predicate is evaluated for each curve before it\n"
405 "      actually gets split.  If pred_1d(chain) is true, the curve won't be\n"
406 "      split anymore.\n"
407 "   :type pred_1d: :class:`UnaryPredicate1D`\n"
408 "   :arg sampling: The resolution used to sample the chain for the\n"
409 "      predicates evaluation. (The chain is not actually resampled; a\n"
410 "      virtual point only progresses along the curve using this\n"
411 "      resolution.)\n"
412 "   :type sampling: float");
413
414 static PyObject *Operators_recursive_split(BPy_Operators *self, PyObject *args, PyObject *kwds)
415 {
416         static const char *kwlist_1[] = {"func", "pred_1d", "sampling", NULL};
417         static const char *kwlist_2[] = {"func", "pred_0d", "pred_1d", "sampling", NULL};
418         PyObject *obj1 = 0, *obj2 = 0, *obj3 = 0;
419         float f = 0.0f;
420
421         if (PyArg_ParseTupleAndKeywords(args, kwds, "O!O!|f", (char **)kwlist_1,
422                                         &UnaryFunction0DDouble_Type, &obj1, &UnaryPredicate1D_Type, &obj2, &f))
423         {
424                 if (!((BPy_UnaryFunction0DDouble *)obj1)->uf0D_double) {
425                         PyErr_SetString(PyExc_TypeError,
426                                         "Operators.recursive_split(): 1st argument: invalid UnaryFunction0DDouble object");
427                         return NULL;
428                 }
429                 if (!((BPy_UnaryPredicate1D *)obj2)->up1D) {
430                         PyErr_SetString(PyExc_TypeError,
431                                         "Operators.recursive_split(): 2nd argument: invalid UnaryPredicate1D object");
432                         return NULL;
433                 }
434                 if (Operators::recursiveSplit(*(((BPy_UnaryFunction0DDouble *)obj1)->uf0D_double),
435                                               *(((BPy_UnaryPredicate1D *)obj2)->up1D),
436                                               f) < 0)
437                 {
438                         if (!PyErr_Occurred())
439                                 PyErr_SetString(PyExc_RuntimeError, "Operators.recursive_split() failed");
440                         return NULL;
441                 }
442         }
443         else if (PyErr_Clear(), (f = 0.0f),
444                  PyArg_ParseTupleAndKeywords(args, kwds, "O!O!O!|f", (char **)kwlist_2,
445                                         &UnaryFunction0DDouble_Type, &obj1, &UnaryPredicate0D_Type, &obj2,
446                                         &UnaryPredicate1D_Type, &obj3, &f))
447         {
448                 if (!((BPy_UnaryFunction0DDouble *)obj1)->uf0D_double) {
449                         PyErr_SetString(PyExc_TypeError,
450                                         "Operators.recursive_split(): 1st argument: invalid UnaryFunction0DDouble object");
451                         return NULL;
452                 }
453                 if (!((BPy_UnaryPredicate0D *)obj2)->up0D) {
454                         PyErr_SetString(PyExc_TypeError,
455                                         "Operators.recursive_split(): 2nd argument: invalid UnaryPredicate0D object");
456                         return NULL;
457                 }
458                 if (!((BPy_UnaryPredicate1D *)obj3)->up1D) {
459                         PyErr_SetString(PyExc_TypeError,
460                                         "Operators.recursive_split(): 3rd argument: invalid UnaryPredicate1D object");
461                         return NULL;
462                 }
463                 if (Operators::recursiveSplit(*(((BPy_UnaryFunction0DDouble *)obj1)->uf0D_double),
464                                               *(((BPy_UnaryPredicate0D *)obj2)->up0D),
465                                               *(((BPy_UnaryPredicate1D *)obj3)->up1D),
466                                               f) < 0)
467                 {
468                         if (!PyErr_Occurred())
469                                 PyErr_SetString(PyExc_RuntimeError, "Operators.recursive_split() failed");
470                         return NULL;
471                 }
472         }
473         else {
474                 PyErr_SetString(PyExc_TypeError, "invalid argument(s)");
475                 return NULL;
476         }
477         Py_RETURN_NONE;
478 }
479
480 PyDoc_STRVAR(Operators_sort_doc,
481 ".. staticmethod:: sort(pred)\n"
482 "\n"
483 "   Sorts the current set of chains (or viewedges) according to the\n"
484 "   comparison predicate given as argument.\n"
485 "\n"
486 "   :arg pred: The binary predicate used for the comparison.\n"
487 "   :type pred: :class:`BinaryPredicate1D`");
488
489 static PyObject *Operators_sort(BPy_Operators *self, PyObject *args, PyObject *kwds)
490 {
491         static const char *kwlist[] = {"pred", NULL};
492         PyObject *obj = 0;
493
494         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!", (char **)kwlist, &BinaryPredicate1D_Type, &obj))
495                 return NULL;
496         if (!((BPy_BinaryPredicate1D *)obj)->bp1D) {
497                 PyErr_SetString(PyExc_TypeError, "Operators.sort(): 1st argument: invalid BinaryPredicate1D object");
498                 return NULL;
499         }
500         if (Operators::sort(*(((BPy_BinaryPredicate1D *)obj)->bp1D)) < 0) {
501                 if (!PyErr_Occurred())
502                         PyErr_SetString(PyExc_RuntimeError, "Operators.sort() failed");
503                 return NULL;
504         }
505         Py_RETURN_NONE;
506 }
507
508 PyDoc_STRVAR(Operators_create_doc,
509 ".. staticmethod:: create(pred, shaders)\n"
510 "\n"
511 "   Creates and shades the strokes from the current set of chains.  A\n"
512 "   predicate can be specified to make a selection pass on the chains.\n"
513 "\n"
514 "   :arg pred: The predicate that a chain must verify in order to be\n"
515 "      transform as a stroke.\n"
516 "   :type pred: :class:`UnaryPredicate1D`\n"
517 "   :arg shaders: The list of shaders used to shade the strokes.\n"
518 "   :type shaders: list of :class:`StrokeShader` objects");
519
520 static PyObject *Operators_create(BPy_Operators *self, PyObject *args, PyObject *kwds)
521 {
522         static const char *kwlist[] = {"pred", "shaders", NULL};
523         PyObject *obj1 = 0, *obj2 = 0;
524
525         if (!PyArg_ParseTupleAndKeywords(args, kwds, "O!O!", (char **)kwlist,
526                                          &UnaryPredicate1D_Type, &obj1, &PyList_Type, &obj2))
527         {
528                 return NULL;
529         }
530         if (!((BPy_UnaryPredicate1D *)obj1)->up1D) {
531                 PyErr_SetString(PyExc_TypeError, "Operators.create(): 1st argument: invalid UnaryPredicate1D object");
532                 return NULL;
533         }
534         vector<StrokeShader *> shaders;
535         shaders.reserve(PyList_Size(obj2));
536         for (int i = 0; i < PyList_Size(obj2); i++) {
537                 PyObject *py_ss = PyList_GET_ITEM(obj2, i);
538                 if (!BPy_StrokeShader_Check(py_ss)) {
539                         PyErr_SetString(PyExc_TypeError, "Operators.create(): 2nd argument must be a list of StrokeShader objects");
540                         return NULL;
541                 }
542                 shaders.push_back(((BPy_StrokeShader *)py_ss)->ss);
543         }
544         if (Operators::create(*(((BPy_UnaryPredicate1D *)obj1)->up1D), shaders) < 0) {
545                 if (!PyErr_Occurred())
546                         PyErr_SetString(PyExc_RuntimeError, "Operators.create() failed");
547                 return NULL;
548         }
549         Py_RETURN_NONE;
550 }
551
552 PyDoc_STRVAR(Operators_reset_doc,
553 ".. staticmethod:: reset(delete_strokes=True)\n"
554 "\n"
555 "   Resets the line stylization process to the initial state.  The results of\n"
556 "   stroke creation are accumulated if **delete_strokes** is set to False.\n"
557 "\n"
558 "   :arg delete_strokes: Delete the strokes that are currently stored.\n"
559 "   :type delete_strokes: bool\n");
560
561 static PyObject *Operators_reset(BPy_Operators *self, PyObject *args, PyObject *kwds)
562 {
563         static const char *kwlist[] = {"delete_strokes", NULL};
564         PyObject *obj1 = 0;
565         if (PyArg_ParseTupleAndKeywords(args, kwds, "|O!", (char **)kwlist, &PyBool_Type, &obj1)) {
566                 // true is the default
567                 Operators::reset(obj1 ? bool_from_PyBool(obj1) : true);
568         }
569         else {
570                 PyErr_SetString(PyExc_RuntimeError, "Operators.reset() failed");
571                 return NULL;
572         }
573         Py_RETURN_NONE;
574 }
575
576 PyDoc_STRVAR(Operators_get_viewedge_from_index_doc,
577 ".. staticmethod:: get_viewedge_from_index(i)\n"
578 "\n"
579 "   Returns the ViewEdge at the index in the current set of ViewEdges.\n"
580 "\n"
581 "   :arg i: index (0 <= i < Operators.get_view_edges_size()).\n"
582 "   :type i: int\n"
583 "   :return: The ViewEdge object.\n"
584 "   :rtype: :class:`ViewEdge`");
585
586 static PyObject *Operators_get_viewedge_from_index(BPy_Operators *self, PyObject *args, PyObject *kwds)
587 {
588         static const char *kwlist[] = {"i", NULL};
589         unsigned int i;
590
591         if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", (char **)kwlist, &i))
592                 return NULL;
593         if (i >= Operators::getViewEdgesSize()) {
594                 PyErr_SetString(PyExc_IndexError, "index out of range");
595                 return NULL;
596         }
597         return BPy_ViewEdge_from_ViewEdge(*(Operators::getViewEdgeFromIndex(i)));
598 }
599
600 PyDoc_STRVAR(Operators_get_chain_from_index_doc,
601 ".. staticmethod:: get_chain_from_index(i)\n"
602 "\n"
603 "   Returns the Chain at the index in the current set of Chains.\n"
604 "\n"
605 "   :arg i: index (0 <= i < Operators.get_chains_size()).\n"
606 "   :type i: int\n"
607 "   :return: The Chain object.\n"
608 "   :rtype: :class:`Chain`");
609
610 static PyObject *Operators_get_chain_from_index(BPy_Operators *self, PyObject *args, PyObject *kwds)
611 {
612         static const char *kwlist[] = {"i", NULL};
613         unsigned int i;
614
615         if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", (char **)kwlist, &i))
616                 return NULL;
617         if (i >= Operators::getChainsSize()) {
618                 PyErr_SetString(PyExc_IndexError, "index out of range");
619                 return NULL;
620         }
621         return BPy_Chain_from_Chain(*(Operators::getChainFromIndex(i)));
622 }
623
624 PyDoc_STRVAR(Operators_get_stroke_from_index_doc,
625 ".. staticmethod:: get_stroke_from_index(i)\n"
626 "\n"
627 "   Returns the Stroke at the index in the current set of Strokes.\n"
628 "\n"
629 "   :arg i: index (0 <= i < Operators.get_strokes_size()).\n"
630 "   :type i: int\n"
631 "   :return: The Stroke object.\n"
632 "   :rtype: :class:`Stroke`");
633
634 static PyObject *Operators_get_stroke_from_index(BPy_Operators *self, PyObject *args, PyObject *kwds)
635 {
636         static const char *kwlist[] = {"i", NULL};
637         unsigned int i;
638
639         if (!PyArg_ParseTupleAndKeywords(args, kwds, "I", (char **)kwlist, &i))
640                 return NULL;
641         if (i >= Operators::getStrokesSize()) {
642                 PyErr_SetString(PyExc_IndexError, "index out of range");
643                 return NULL;
644         }
645         return BPy_Stroke_from_Stroke(*(Operators::getStrokeFromIndex(i)));
646 }
647
648 PyDoc_STRVAR(Operators_get_view_edges_size_doc,
649 ".. staticmethod:: get_view_edges_size()\n"
650 "\n"
651 "   Returns the number of ViewEdges.\n"
652 "\n"
653 "   :return: The number of ViewEdges.\n"
654 "   :rtype: int");
655
656 static PyObject *Operators_get_view_edges_size(BPy_Operators *self)
657 {
658         return PyLong_FromLong(Operators::getViewEdgesSize());
659 }
660
661 PyDoc_STRVAR(Operators_get_chains_size_doc,
662 ".. staticmethod:: get_chains_size()\n"
663 "\n"
664 "   Returns the number of Chains.\n"
665 "\n"
666 "   :return: The number of Chains.\n"
667 "   :rtype: int");
668
669 static PyObject *Operators_get_chains_size(BPy_Operators *self)
670 {
671         return PyLong_FromLong(Operators::getChainsSize());
672 }
673
674 PyDoc_STRVAR(Operators_get_strokes_size_doc,
675 ".. staticmethod:: get_strokes_size()\n"
676 "\n"
677 "   Returns the number of Strokes.\n"
678 "\n"
679 "   :return: The number of Strokes.\n"
680 "   :rtype: int");
681
682 static PyObject *Operators_get_strokes_size(BPy_Operators *self)
683 {
684         return PyLong_FromLong(Operators::getStrokesSize());
685 }
686
687 /*----------------------Operators instance definitions ----------------------------*/
688 static PyMethodDef BPy_Operators_methods[] = {
689         {"select", (PyCFunction) Operators_select, METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_select_doc},
690         {"chain", (PyCFunction) Operators_chain, METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_chain_doc},
691         {"bidirectional_chain", (PyCFunction) Operators_bidirectional_chain, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
692                                 Operators_bidirectional_chain_doc},
693         {"sequential_split", (PyCFunction) Operators_sequential_split, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
694                              Operators_sequential_split_doc},
695         {"recursive_split", (PyCFunction) Operators_recursive_split, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
696                             Operators_recursive_split_doc},
697         {"sort", (PyCFunction) Operators_sort, METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_sort_doc},
698         {"create", (PyCFunction) Operators_create, METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_create_doc},
699         {"reset", (PyCFunction) Operators_reset, METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_reset_doc},
700         {"get_viewedge_from_index", (PyCFunction) Operators_get_viewedge_from_index,
701                                     METH_VARARGS | METH_KEYWORDS | METH_STATIC, Operators_get_viewedge_from_index_doc},
702         {"get_chain_from_index", (PyCFunction) Operators_get_chain_from_index, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
703                                  Operators_get_chain_from_index_doc},
704         {"get_stroke_from_index", (PyCFunction) Operators_get_stroke_from_index, METH_VARARGS | METH_KEYWORDS | METH_STATIC,
705                                   Operators_get_stroke_from_index_doc},
706         {"get_view_edges_size", (PyCFunction) Operators_get_view_edges_size, METH_NOARGS | METH_STATIC,
707                                 Operators_get_view_edges_size_doc},
708         {"get_chains_size", (PyCFunction) Operators_get_chains_size, METH_NOARGS | METH_STATIC,
709                             Operators_get_chains_size_doc},
710         {"get_strokes_size", (PyCFunction) Operators_get_strokes_size, METH_NOARGS | METH_STATIC,
711                              Operators_get_strokes_size_doc},
712         {NULL, NULL, 0, NULL}
713 };
714
715 /*-----------------------BPy_Operators type definition ------------------------------*/
716
717 PyTypeObject Operators_Type = {
718         PyVarObject_HEAD_INIT(NULL, 0)
719         "Operators",                    /* tp_name */
720         sizeof(BPy_Operators),          /* tp_basicsize */
721         0,                              /* tp_itemsize */
722         (destructor)Operators_dealloc,  /* tp_dealloc */
723         0,                              /* tp_print */
724         0,                              /* tp_getattr */
725         0,                              /* tp_setattr */
726         0,                              /* tp_reserved */
727         0,                              /* tp_repr */
728         0,                              /* tp_as_number */
729         0,                              /* tp_as_sequence */
730         0,                              /* tp_as_mapping */
731         0,                              /* tp_hash  */
732         0,                              /* tp_call */
733         0,                              /* tp_str */
734         0,                              /* tp_getattro */
735         0,                              /* tp_setattro */
736         0,                              /* tp_as_buffer */
737         Py_TPFLAGS_DEFAULT,             /* tp_flags */
738         Operators_doc,                  /* tp_doc */
739         0,                              /* tp_traverse */
740         0,                              /* tp_clear */
741         0,                              /* tp_richcompare */
742         0,                              /* tp_weaklistoffset */
743         0,                              /* tp_iter */
744         0,                              /* tp_iternext */
745         BPy_Operators_methods,          /* tp_methods */
746         0,                              /* tp_members */
747         0,                              /* tp_getset */
748         0,                              /* tp_base */
749         0,                              /* tp_dict */
750         0,                              /* tp_descr_get */
751         0,                              /* tp_descr_set */
752         0,                              /* tp_dictoffset */
753         0,                              /* tp_init */
754         0,                              /* tp_alloc */
755         PyType_GenericNew,              /* tp_new */
756 };
757
758 ///////////////////////////////////////////////////////////////////////////////////////////
759
760 #ifdef __cplusplus
761 }
762 #endif