==Python API==
[blender.git] / source / blender / python / api2_2x / CurNurb.c
1 /*
2  * $Id$
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * This is a new part of Blender.
26  *
27  * Contributor(s): Stephen Swaney, Campbell Barton, Ken Hughes
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31
32 #include "CurNurb.h" /*This must come first */
33
34 #include "BKE_curve.h"
35 #include "BDR_editcurve.h"      /* for convertspline */
36 #include "MEM_guardedalloc.h"
37 #include "gen_utils.h"
38 #include "BezTriple.h"
39
40 /* Only for ME_SMOOTH */
41 #include "DNA_meshdata_types.h"
42
43 /*
44  * forward declarations go here
45  */
46
47 static PyObject *M_CurNurb_New( PyObject * self, PyObject * args );
48 static PyObject *CurNurb_oldsetMatIndex( BPy_CurNurb * self, PyObject * args );
49 static int CurNurb_setMatIndex( BPy_CurNurb * self, PyObject * args );
50 static PyObject *CurNurb_getMatIndex( BPy_CurNurb * self );
51 static PyObject *CurNurb_getFlagU( BPy_CurNurb * self );
52 static PyObject *CurNurb_oldsetFlagU( BPy_CurNurb * self, PyObject * args );
53 static int CurNurb_setFlagU( BPy_CurNurb * self, PyObject * args );
54 static PyObject *CurNurb_getFlagV( BPy_CurNurb * self );
55 static PyObject *CurNurb_oldsetFlagV( BPy_CurNurb * self, PyObject * args );
56 static int CurNurb_setFlagV( BPy_CurNurb * self, PyObject * args );
57 static PyObject *CurNurb_getType( BPy_CurNurb * self );
58 static PyObject *CurNurb_oldsetType( BPy_CurNurb * self, PyObject * args );
59 static int CurNurb_setType( BPy_CurNurb * self, PyObject * args );
60 static PyObject *CurNurb_getKnotsU( BPy_CurNurb * self );
61 static PyObject *CurNurb_getKnotsV( BPy_CurNurb * self );
62 static PyObject *CurNurb_getPoints( BPy_CurNurb * self );
63 /* static PyObject* CurNurb_setXXX( BPy_CurNurb* self, PyObject* args ); */
64 static int CurNurb_setPoint( BPy_CurNurb * self, int index, PyObject * ob );
65 static int CurNurb_length( PyInstanceObject * inst );
66 static PyObject *CurNurb_getIter( BPy_CurNurb * self );
67 static PyObject *CurNurb_iterNext( BPy_CurNurb * self );
68 PyObject *CurNurb_append( BPy_CurNurb * self, PyObject * value );
69
70 static PyObject *CurNurb_isNurb( BPy_CurNurb * self );
71 static PyObject *CurNurb_isCyclic( BPy_CurNurb * self );
72 static PyObject *CurNurb_dump( BPy_CurNurb * self );
73 static PyObject *CurNurb_switchDirection( BPy_CurNurb * self );
74 static PyObject *CurNurb_recalc( BPy_CurNurb * self );
75 static PyObject *CurNurb_getFlagBits( BPy_CurNurb * self, void *type );
76 static int CurNurb_setFlagBits( BPy_CurNurb * self, PyObject *value, void *type );
77 char M_CurNurb_doc[] = "CurNurb";
78
79
80 /*      
81   CurNurb_Type callback function prototypes:                          
82 */
83
84 static int CurNurb_compare( BPy_CurNurb * a, BPy_CurNurb * b );
85 static PyObject *CurNurb_repr( BPy_CurNurb * self );
86
87 /*
88    table of module methods
89    these are the equivalent of class or static methods.
90    you do not need an object instance to call one.
91   
92 */
93
94 static PyMethodDef M_CurNurb_methods[] = {
95 /*   name, method, flags, doc_string                */
96         {"New", ( PyCFunction ) M_CurNurb_New, METH_VARARGS | METH_KEYWORDS,
97          " () - doc string"},
98 /*  {"Get", (PyCFunction) M_CurNurb_method, METH_NOARGS, " () - doc string"}, */
99 /*   {"method", (PyCFunction) M_CurNurb_method, METH_NOARGS, " () - doc string"}, */
100
101         {NULL, NULL, 0, NULL}
102 };
103
104
105
106 /*
107  * method table
108  * table of instance methods
109  * these methods are invoked on an instance of the type.
110 */
111
112 static PyMethodDef BPy_CurNurb_methods[] = {
113 /*   name,     method,                    flags,         doc               */
114 /*  {"method", (PyCFunction) CurNurb_method, METH_NOARGS, " () - doc string"} */
115         {"setMatIndex", ( PyCFunction ) CurNurb_oldsetMatIndex, METH_VARARGS,
116          "( index ) - set index into materials list"},
117         {"getMatIndex", ( PyCFunction ) CurNurb_getMatIndex, METH_NOARGS,
118          "( ) - get current material index"},
119         {"setFlagU", ( PyCFunction ) CurNurb_oldsetFlagU, METH_VARARGS,
120          "( index ) - set flagU and recalculate the knots (0: uniform, 1: endpoints, 2: bezier)"},
121         {"getFlagU", ( PyCFunction ) CurNurb_getFlagU, METH_NOARGS,
122          "( ) - get flagU of the knots"},
123         {"setFlagV", ( PyCFunction ) CurNurb_oldsetFlagV, METH_VARARGS,
124          "( index ) - set flagV and recalculate the knots (0: uniform, 1: endpoints, 2: bezier)"},
125         {"getFlagV", ( PyCFunction ) CurNurb_getFlagV, METH_NOARGS,
126          "( ) - get flagV of the knots"},
127         {"setType", ( PyCFunction ) CurNurb_oldsetType, METH_VARARGS,
128          "( type ) - change the type of the curve (Poly: 0, Bezier: 1, NURBS: 4)"},
129         {"getType", ( PyCFunction ) CurNurb_getType, METH_NOARGS,
130          "( ) - get the type of the curve (Poly: 0, Bezier: 1, NURBS: 4)"},
131         {"append", ( PyCFunction ) CurNurb_append, METH_O,
132          "( point ) - add a new point.  arg is BezTriple or list of x,y,z,w floats"},
133         {"isNurb", ( PyCFunction ) CurNurb_isNurb, METH_NOARGS,
134          "( ) - boolean function tests if this spline is type nurb or bezier"},
135         {"isCyclic", ( PyCFunction ) CurNurb_isCyclic, METH_NOARGS,
136          "( ) - boolean function tests if this spline is cyclic (closed) or not (open)"},
137         {"dump", ( PyCFunction ) CurNurb_dump, METH_NOARGS,
138          "( ) - dumps Nurb data)"},
139         {"switchDirection", ( PyCFunction ) CurNurb_switchDirection, METH_NOARGS,
140          "( ) - swaps curve beginning and end)"},
141         {"recalc", ( PyCFunction ) CurNurb_recalc, METH_NOARGS,
142          "( ) - recalc Nurb data)"},
143         {NULL, NULL, 0, NULL}
144 };
145
146 /* 
147  *   methods for CurNurb as sequece
148  */
149
150 static PySequenceMethods CurNurb_as_sequence = {
151         ( inquiry ) CurNurb_length,     /* sq_length   */
152         ( binaryfunc ) 0,       /* sq_concat */
153         ( intargfunc ) 0,       /* sq_repeat */
154         ( intargfunc ) CurNurb_getPoint,        /* sq_item */
155         ( intintargfunc ) 0,    /* sq_slice */
156         ( intobjargproc ) CurNurb_setPoint,     /* sq_ass_item */
157         0,                      /* sq_ass_slice */
158         ( objobjproc ) 0,       /* sq_contains */
159         0,
160         0
161 };
162
163 static PyGetSetDef BPy_CurNurb_getseters[] = {
164         {"mat_index",
165          (getter)CurNurb_getMatIndex, (setter)CurNurb_setMatIndex,
166          "CurNurb's material index",
167          NULL},
168         {"points",
169          (getter)CurNurb_getPoints, (setter)NULL,
170          "The number of curve points",
171          NULL},
172         {"flagU",
173          (getter)CurNurb_getFlagU, (setter)CurNurb_setFlagU,
174          "The knot type in the U direction",
175          NULL},
176         {"flagV",
177          (getter)CurNurb_getFlagV, (setter)CurNurb_setFlagV,
178          "The knot type in the V direction",
179          NULL},
180         {"type",
181          (getter)CurNurb_getType, (setter)CurNurb_setType,
182          "The curve type (poly: bezier, or NURBS)",
183          NULL},
184         {"knotsU",
185          (getter)CurNurb_getKnotsU, (setter)NULL,
186          "The The knot vector in the U direction",
187          NULL},
188         {"knotsV",
189          (getter)CurNurb_getKnotsV, (setter)NULL,
190          "The The knot vector in the V direction",
191          NULL},
192         {"smooth",
193          (getter)CurNurb_getFlagBits, (setter)CurNurb_setFlagBits,
194          "The smooth bool setting",
195          (void *)ME_SMOOTH},
196         {NULL,NULL,NULL,NULL,NULL}  /* Sentinel */
197 };
198
199 /*
200   Object Type definition
201   full blown 2.3 struct
202   if you are having trouble building with an earlier version of python,
203    this is why.
204 */
205
206 PyTypeObject CurNurb_Type = {
207         PyObject_HEAD_INIT( NULL ) /* required py macro */
208         0,      /* ob_size */
209         /*  For printing, in format "<module>.<name>" */
210         "CurNurb",              /* char *tp_name; */
211         sizeof( CurNurb_Type ), /* int tp_basicsize, */
212         0,                      /* tp_itemsize;  For allocation */
213
214         /* Methods to implement standard operations */
215
216         NULL,                                   /*    destructor tp_dealloc; */
217         NULL,                                   /*    printfunc tp_print; */
218         NULL,                                   /*    getattrfunc tp_getattr; */
219         NULL,                                   /*    setattrfunc tp_setattr; */
220         ( cmpfunc ) CurNurb_compare,    /*    cmpfunc tp_compare; */
221         ( reprfunc ) CurNurb_repr,      /*    reprfunc tp_repr; */
222
223         /* Method suites for standard classes */
224
225         0,                      /*    PyNumberMethods *tp_as_number; */
226         &CurNurb_as_sequence,   /*    PySequenceMethods *tp_as_sequence; */
227         0,                      /*    PyMappingMethods *tp_as_mapping; */
228
229         /* More standard operations (here for binary compatibility) */
230
231         0,                      /*    hashfunc tp_hash; */
232         0,                      /*    ternaryfunc tp_call; */
233         0,                      /*    reprfunc tp_str; */
234         0,                      /*    getattrofunc tp_getattro; */
235         0,                      /*    setattrofunc tp_setattro; */
236
237         /* Functions to access object as input/output buffer */
238         0,                      /*    PyBufferProcs *tp_as_buffer; */
239
240   /*** Flags to define presence of optional/expanded features ***/
241         Py_TPFLAGS_DEFAULT,     /*    long tp_flags; */
242
243         0,                      /*  char *tp_doc;  Documentation string */
244   /*** Assigned meaning in release 2.0 ***/
245         /* call function for all accessible objects */
246         0,                      /*    traverseproc tp_traverse; */
247
248         /* delete references to contained objects */
249         0,                      /*    inquiry tp_clear; */
250
251   /***  Assigned meaning in release 2.1 ***/
252   /*** rich comparisons ***/
253         0,                      /*  richcmpfunc tp_richcompare; */
254
255   /***  weak reference enabler ***/
256         0,                      /* long tp_weaklistoffset; */
257
258   /*** Added in release 2.2 ***/
259         /*   Iterators */
260         ( getiterfunc ) CurNurb_getIter,        /*    getiterfunc tp_iter; */
261         ( iternextfunc ) CurNurb_iterNext,      /*    iternextfunc tp_iternext; */
262
263   /*** Attribute descriptor and subclassing stuff ***/
264         BPy_CurNurb_methods,    /*    struct PyMethodDef *tp_methods; */
265         0,                      /*    struct PyMemberDef *tp_members; */
266         BPy_CurNurb_getseters,                  /*    struct PyGetSetDef *tp_getset; */
267         0,                      /*    struct _typeobject *tp_base; */
268         0,                      /*    PyObject *tp_dict; */
269         0,                      /*    descrgetfunc tp_descr_get; */
270         0,                      /*    descrsetfunc tp_descr_set; */
271         0,                      /*    long tp_dictoffset; */
272         0,                      /*    initproc tp_init; */
273         0,                      /*    allocfunc tp_alloc; */
274         0,                      /*    newfunc tp_new; */
275         /*  Low-level free-memory routine */
276         0,                      /*    freefunc tp_free;  */
277         /* For PyObject_IS_GC */
278         0,                      /*    inquiry tp_is_gc;  */
279         0,                      /*    PyObject *tp_bases; */
280         /* method resolution order */
281         0,                      /*    PyObject *tp_mro;  */
282         0,                      /*    PyObject *tp_cache; */
283         0,                      /*    PyObject *tp_subclasses; */
284         0,                      /*    PyObject *tp_weaklist; */
285         0
286 };
287
288 /*
289   compare
290   in this case, we consider two CurNurbs equal, if they point to the same
291   blender data.
292 */
293
294 static int CurNurb_compare( BPy_CurNurb * a, BPy_CurNurb * b )
295 {
296         Nurb *pa = a->nurb;
297         Nurb *pb = b->nurb;
298
299         return ( pa == pb ) ? 0 : -1;
300 }
301
302
303 /*
304   factory method to create a BPy_CurNurb from a Blender Nurb
305 */
306
307 PyObject *CurNurb_CreatePyObject( Nurb * blen_nurb )
308 {
309         BPy_CurNurb *pyNurb;
310
311         pyNurb = ( BPy_CurNurb * ) PyObject_NEW( BPy_CurNurb, &CurNurb_Type );
312
313         if( !pyNurb )
314                 return EXPP_ReturnPyObjError( PyExc_MemoryError,
315                                               "could not create BPy_CurNurb PyObject" );
316
317         pyNurb->nurb = blen_nurb;
318         return ( PyObject * ) pyNurb;
319 }
320
321
322 /*
323  *  CurNurb_repr
324  */
325 static PyObject *CurNurb_repr( BPy_CurNurb * self )
326 {                               /* used by 'repr' */
327
328         return PyString_FromFormat( "[CurNurb \"%d\"]", self->nurb->type );
329 }
330
331 /* XXX Can't this be simply removed? */
332 static PyObject *M_CurNurb_New( PyObject * self, PyObject * args )
333 {
334         return ( PyObject * ) 0;
335
336 }
337
338 /*
339  *      Curve.getType
340  */
341 static PyObject *CurNurb_getType( BPy_CurNurb * self )
342 {
343         /* type is on 3 first bits only */
344         return PyInt_FromLong( self->nurb->type & 7 );
345 }
346
347 /*
348  *      Curve.setType
349  *
350  *      Convert the curve using Blender's convertspline fonction
351  */
352 static int CurNurb_setType( BPy_CurNurb * self, PyObject * args )
353 {
354         PyObject* integer = PyNumber_Int( args );
355         short value;
356
357         if( !integer )
358                 return EXPP_ReturnIntError( PyExc_TypeError,
359                                 "expected integer argument" );
360
361         value = ( short )PyInt_AS_LONG( integer );
362         Py_DECREF( integer );
363
364         /* parameter value checking */
365         if (value != CU_POLY && value != CU_BEZIER && value != CU_NURBS)
366                 return EXPP_ReturnIntError( PyExc_ValueError,
367                                 "expected integer argument" );
368
369         /* convert and raise error if impossible */
370         if (convertspline(value, self->nurb))
371                 return EXPP_ReturnIntError( PyExc_ValueError,
372                                 "Conversion Impossible" );
373
374         return 0;
375 }
376
377 /*
378  * CurNurb_getKnotsU
379  *
380  * returns curve's knotsU in a tuple. Empty tuple is returned if curve
381  * isn't Nurbs or it doesn't have knots in U
382  */
383
384 static PyObject *CurNurb_getKnotsU( BPy_CurNurb * self )
385 {
386         if(self->nurb->knotsu) {
387                 int len = KNOTSU(self->nurb);
388                 int i;
389                 PyObject *knotsu = PyTuple_New(len);
390                 if( !knotsu )
391                         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
392                                         "could not get CurNurb.knotsU attribute" );
393
394                 for(i = 0; i < len; ++i)
395                         PyTuple_SetItem(knotsu, i,
396                                         PyFloat_FromDouble(self->nurb->knotsu[i]));
397
398                 return knotsu;
399         }
400         return PyTuple_New(0);
401 }
402
403 /*
404  * CurNurb_getKnotsV
405  *
406  * returns curve's knotsV in a tuple. Empty tuple is returned if curve doesn't have knots in V
407  */
408
409 static PyObject *CurNurb_getKnotsV( BPy_CurNurb * self )
410 {
411         if(self->nurb->knotsv) {
412                 int len = KNOTSV(self->nurb);
413                 int i;
414                 PyObject *knotsv = PyTuple_New(len);
415                 if( !knotsv )
416                         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
417                                         "could not get CurNurb.knotsV index" );
418
419                 for(i = 0; i < len; ++i)
420                         PyTuple_SetItem(knotsv, i,
421                                         PyFloat_FromDouble(self->nurb->knotsv[i] ));
422         
423                 return knotsv;
424         }
425         return PyTuple_New(0);
426 }
427
428 static PyObject *CurNurb_getPoints( BPy_CurNurb * self )
429 {
430         return PyInt_FromLong( ( long ) self->nurb->pntsu );
431 }
432
433 static PyObject *CurNurb_getFlagBits( BPy_CurNurb * self, void *type )
434 {
435         return EXPP_getBitfield( (void *)&self->nurb->flag,
436                                                           (int)type, 'h' );
437 }
438
439 static int CurNurb_setFlagBits( BPy_CurNurb * self, PyObject *value,
440                                                                         void *type )
441 {
442         return EXPP_setBitfield( value, (void *)&self->nurb->flag,
443                                                          (int)type, 'h' );
444 }
445
446 /*
447  * CurNurb_append( point )
448  * append a new point to a nurb curve.
449  * arg is BezTriple or list of xyzw floats 
450  */
451
452 PyObject *CurNurb_append( BPy_CurNurb * self, PyObject * value )
453 {
454         return CurNurb_appendPointToNurb( self->nurb, value );
455 }
456
457
458 /*
459  * CurNurb_appendPointToNurb
460  * this is a non-bpy utility func to add a point to a given nurb.
461  * notice the first arg is Nurb*.
462  */
463
464 PyObject *CurNurb_appendPointToNurb( Nurb * nurb, PyObject * value )
465 {
466
467         int i;
468         int size;
469         int npoints = nurb->pntsu;
470
471         /*
472            do we have a list of four floats or a BezTriple?
473         */
474         
475         /* if curve is empty, adjust type depending on input type */
476         if (nurb->bezt==NULL && nurb->bp==NULL) {
477                 if (BPy_BezTriple_Check( value ))
478                         nurb->type |= CU_BEZIER;
479                 else if (PySequence_Check( value ))
480                         nurb->type |= CU_NURBS;
481                 else
482                         return( EXPP_ReturnPyObjError( PyExc_TypeError,
483                                           "Expected a BezTriple or a Sequence of 4 (or 5) floats" ) );
484         }
485
486
487
488         if ((nurb->type & 7)==CU_BEZIER) {
489                 BezTriple *tmp;
490
491                 if( !BPy_BezTriple_Check( value ) )
492                         return( EXPP_ReturnPyObjError( PyExc_TypeError,
493                                           "Expected a BezTriple\n" ) );
494
495 /*              printf("\ndbg: got a BezTriple\n"); */
496                 tmp = nurb->bezt;       /* save old points */
497                 nurb->bezt =
498                         ( BezTriple * ) MEM_mallocN( sizeof( BezTriple ) *
499                                                      ( npoints + 1 ),
500                                                      "CurNurb_append2" );
501
502                 if( !nurb->bezt )
503                         return ( EXPP_ReturnPyObjError
504                                  ( PyExc_MemoryError, "allocation failed" ) );
505
506                 /* copy old points to new */
507                 if( tmp ) {
508                         memmove( nurb->bezt, tmp, sizeof( BezTriple ) * npoints );
509                         MEM_freeN( tmp );
510                 }
511
512                 nurb->pntsu++;
513                 /* add new point to end of list */
514                 memcpy( nurb->bezt + npoints,
515                         BezTriple_FromPyObject( value ), sizeof( BezTriple ) );
516
517         }
518         else if( PySequence_Check( value ) ) {
519                 size = PySequence_Size( value );
520 /*              printf("\ndbg: got a sequence of size %d\n", size );  */
521                 if( size == 4 || size == 5 ) {
522                         BPoint *tmp;
523
524                         tmp = nurb->bp; /* save old pts */
525
526                         nurb->bp =
527                                 ( BPoint * ) MEM_mallocN( sizeof( BPoint ) *
528                                                           ( npoints + 1 ),
529                                                           "CurNurb_append1" );
530                         if( !nurb->bp )
531                                 return ( EXPP_ReturnPyObjError
532                                          ( PyExc_MemoryError,
533                                            "allocation failed" ) );
534
535                         memmove( nurb->bp, tmp, sizeof( BPoint ) * npoints );
536                         if( tmp )
537                                 MEM_freeN( tmp );
538
539                         ++nurb->pntsu;
540                         /* initialize new BPoint from old */
541                         memcpy( nurb->bp + npoints, nurb->bp,
542                                 sizeof( BPoint ) );
543
544                         for( i = 0; i < 4; ++i ) {
545                                 PyObject *item = PySequence_GetItem( value, i );
546
547                                 if (item == NULL)
548                                         return NULL;
549
550
551                                 nurb->bp[npoints].vec[i] = ( float ) PyFloat_AsDouble( item );
552                                 Py_DECREF( item );
553                         }
554
555                         if (size == 5) {
556                                 PyObject *item = PySequence_GetItem( value, i );
557
558                                 if (item == NULL)
559                                         return NULL;
560
561                                 nurb->bp[npoints].alfa = ( float ) PyFloat_AsDouble( item );
562                                 Py_DECREF( item );
563                         }
564                         else {
565                                 nurb->bp[npoints].alfa = 0.0f;
566                         }
567
568                         makeknots( nurb, 1, nurb->flagu >> 1 );
569
570                 } else {
571                         return EXPP_ReturnPyObjError( PyExc_TypeError,
572                                         "expected a sequence of 4 or 5 floats" );
573                 }
574
575         } else {
576                 /* bail with error */
577                 return EXPP_ReturnPyObjError( PyExc_TypeError,
578                                         "expected a sequence of 4 or 5 floats" );
579
580         }
581
582         Py_RETURN_NONE;
583 }
584
585
586 /*
587  *  CurNurb_setMatIndex
588  *
589  *  set index into material list
590  */
591
592 static int CurNurb_setMatIndex( BPy_CurNurb * self, PyObject * args )
593 {
594         printf ("%d\n", self->nurb->mat_nr);
595         return EXPP_setIValueRange( args, &self->nurb->mat_nr, 0, 15, 'h' );
596 }
597
598 /*
599  * CurNurb_getMatIndex
600  *
601  * returns index into material list
602  */
603
604 static PyObject *CurNurb_getMatIndex( BPy_CurNurb * self )
605 {
606         PyObject *index = PyInt_FromLong( ( long ) self->nurb->mat_nr );
607
608         if( index )
609                 return index;
610
611         return EXPP_ReturnPyObjError( PyExc_RuntimeError,
612                         "could not get material index" );
613 }
614
615 /*
616  * CurNurb_getFlagU
617  *
618  * returns curve's flagu
619  */
620
621 static PyObject *CurNurb_getFlagU( BPy_CurNurb * self )
622 {
623         PyObject *flagu = PyInt_FromLong( ( long ) self->nurb->flagu );
624
625         if( flagu )
626                 return flagu;
627
628         return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
629                                         "could not get CurNurb.flagu index" ) );
630 }
631
632 /*
633  *  CurNurb_setFlagU
634  *
635  *  set curve's flagu and recalculate the knots
636  *
637  *  Possible values: 0 - uniform, 2 - endpoints, 4 - bezier
638  *    bit 0 controls CU_CYCLIC
639  */
640
641 static int CurNurb_setFlagU( BPy_CurNurb * self, PyObject * args )
642 {
643         PyObject* integer = PyNumber_Int( args );
644         short value;
645
646         if( !integer )
647                 return EXPP_ReturnIntError( PyExc_TypeError,
648                                 "expected integer argument" );
649
650         value = ( short )PyInt_AS_LONG( integer );
651         Py_DECREF( integer );
652
653         if( value < 0 || value > 5 )
654                 return EXPP_ReturnIntError( PyExc_ValueError,
655                                 "expected integer argument in range [0,5]" );
656
657         if( self->nurb->flagu != value ) {
658                 self->nurb->flagu = (short)value;
659                 makeknots( self->nurb, 1, self->nurb->flagu >> 1 );
660         }
661
662         return 0;
663 }
664
665 /*
666  * CurNurb_getFlagV
667  *
668  * returns curve's flagu
669  */
670
671 static PyObject *CurNurb_getFlagV( BPy_CurNurb * self )
672 {
673         PyObject *flagv = PyInt_FromLong( ( long ) self->nurb->flagv );
674
675         if( flagv )
676                 return flagv;
677
678         return ( EXPP_ReturnPyObjError( PyExc_RuntimeError,
679                                         "could not get CurNurb.flagv" ) );
680 }
681
682 /*
683  *  CurNurb_setFlagV
684  *
685  *  set curve's flagu and recalculate the knots
686  *
687  *  Possible values: 0 - uniform, 1 - endpoints, 2 - bezier
688  */
689
690 static int CurNurb_setFlagV( BPy_CurNurb * self, PyObject * args )
691 {
692         PyObject* integer = PyNumber_Int( args );
693         short value;
694
695         if( !integer )
696                 return EXPP_ReturnIntError( PyExc_TypeError,
697                                 "expected integer argument" );
698
699         value = ( short )PyInt_AS_LONG( integer );
700         Py_DECREF( integer );
701
702         if( value < 0 || value > 5 )
703                 return EXPP_ReturnIntError( PyExc_ValueError,
704                                 "expected integer argument in range [0,5]" );
705
706         if( self->nurb->flagv != value ) {
707                 self->nurb->flagv = (short)value;
708                 makeknots( self->nurb, 2, self->nurb->flagv >> 1 );
709         }
710
711         return 0;
712 }
713
714 /*
715  * CurNurb_getIter
716  *
717  * create an iterator for our CurNurb.
718  * this iterator returns the points for this CurNurb.
719  */
720
721 static PyObject *CurNurb_getIter( BPy_CurNurb * self )
722 {
723         self->bp = self->nurb->bp;
724         self->bezt = self->nurb->bezt;
725         self->atEnd = 0;
726         self->nextPoint = 0;
727
728         /* set exhausted flag if both bp and bezt are zero */
729         if( ( !self->bp ) && ( !self->bezt ) )
730                 self->atEnd = 1;
731
732         Py_INCREF( self );
733         return ( PyObject * ) self;
734 }
735
736
737 static PyObject *CurNurb_iterNext( BPy_CurNurb * self )
738 {
739         PyObject *po;           /* return value */
740         Nurb *pnurb = self->nurb;
741         int npoints = pnurb->pntsu;
742
743         /* are we at end already? */
744         if( self->atEnd )
745                 return ( EXPP_ReturnPyObjError( PyExc_StopIteration,
746                                                 "iterator at end" ) );
747
748         if( self->nextPoint < npoints ) {
749
750                 po = CurNurb_pointAtIndex( self->nurb, self->nextPoint );
751                 self->nextPoint++;
752
753                 return po;
754
755         } else {
756                 self->atEnd = 1;        /* set flag true */
757         }
758
759         return ( EXPP_ReturnPyObjError( PyExc_StopIteration,
760                                         "iterator at end" ) );
761 }
762
763
764
765 /*
766  * CurNurb_isNurb()
767  * test whether spline nurb or bezier
768  */
769
770 static PyObject *CurNurb_isNurb( BPy_CurNurb * self )
771 {
772         /* NOTE: a Nurb has bp and bezt pointers
773          * depending on type.
774          * It is possible both are NULL if no points exist.
775          * in that case, we return False
776          */
777
778         if( self->nurb->bp ) {
779                 return EXPP_incr_ret_True();
780         } else {
781                 return EXPP_incr_ret_False();
782         }
783 }
784
785 /*
786  * CurNurb_isCyclic()
787  * test whether spline cyclic (closed) or not (open)
788  */
789
790 static PyObject *CurNurb_isCyclic( BPy_CurNurb * self )
791 {
792         /* supposing that the flagu is always set */ 
793
794         if( self->nurb->flagu & CU_CYCLIC ) {
795                 return EXPP_incr_ret_True();
796         } else {
797                 return EXPP_incr_ret_False();
798         }
799 }
800
801 /*
802  * CurNurb_length
803  * returns the number of points in a Nurb
804  * this is a tp_as_sequence method, not a regular instance method.
805  */
806
807 static int CurNurb_length( PyInstanceObject * inst )
808 {
809         Nurb *nurb;
810         int len;
811
812         if( BPy_CurNurb_Check( ( PyObject * ) inst ) ) {
813                 nurb = ( ( BPy_CurNurb * ) inst )->nurb;
814                 len = nurb->pntsu;
815                 return len;
816         }
817
818         return EXPP_ReturnIntError( PyExc_RuntimeError,
819                                     "arg is not a BPy_CurNurb" );
820 }
821
822 /*
823  * CurNurb_getPoint
824  * returns the Nth point in a Nurb
825  * this is one of the tp_as_sequence methods, hence the int N argument.
826  * it is called via the [] operator, not as a usual instance method.
827  */
828
829 PyObject *CurNurb_getPoint( BPy_CurNurb * self, int index )
830 {
831         Nurb *myNurb;
832
833         int npoints;
834
835         /* for convenince */
836         myNurb = self->nurb;
837         npoints = myNurb->pntsu;
838
839         /* DELETED: bail if index < 0 */
840         /* actually, this check is not needed since python treats */
841         /* negative indices as starting from the right end of a sequence */
842         /* 
843         THAT IS WRONG, when passing a negative index, python adjusts it to be positive
844         BUT it can still overflow in the negatives if the index is too small.
845         For example, list[-6] when list contains 5 items means index = -1 in here.
846         (theeth)
847         */
848
849         /* bail if no Nurbs in Curve */
850         if( npoints == 0 )
851                 return ( EXPP_ReturnPyObjError( PyExc_IndexError,
852                                                 "no points in this CurNurb" ) );
853
854         /* check index limits */
855         if( index >= npoints || index < 0 )
856                 return ( EXPP_ReturnPyObjError( PyExc_IndexError,
857                                                 "index out of range" ) );
858
859         return CurNurb_pointAtIndex( myNurb, index );
860 }
861
862 /*
863  * CurNurb_setPoint
864  * modifies the Nth point in a Nurb
865  * this is one of the tp_as_sequence methods, hence the int N argument.
866  * it is called via the [] = operator, not as a usual instance method.
867  */
868 static int CurNurb_setPoint( BPy_CurNurb * self, int index, PyObject * pyOb )
869 {
870         Nurb *nurb = self->nurb;
871         int size;
872
873         /* check index limits */
874         if( index < 0 || index >= nurb->pntsu )
875                 return EXPP_ReturnIntError( PyExc_IndexError,
876                                             "array assignment index out of range" );
877
878
879         /* branch by curve type */
880         if ((nurb->type & 7)==CU_BEZIER) {      /* BEZIER */
881                 /* check parameter type */
882                 if( !BPy_BezTriple_Check( pyOb ) )
883                         return EXPP_ReturnIntError( PyExc_TypeError,
884                                                         "expected a BezTriple" );
885
886                 /* copy bezier in array */
887                 memcpy( nurb->bezt + index,
888                         BezTriple_FromPyObject( pyOb ), sizeof( BezTriple ) );
889
890                 return 0;       /* finished correctly */
891         }
892         else {  /* NURBS or POLY */
893                 int i;
894
895                 /* check parameter type */
896                 if (!PySequence_Check( pyOb ))
897                         return EXPP_ReturnIntError( PyExc_TypeError,
898                                                         "expected a list of 4 (or optionally 5 if the curve is 3D) floats" );
899
900                 size = PySequence_Size( pyOb );
901
902                 /* check sequence size */
903                 if( size != 4 && size != 5 ) 
904                         return EXPP_ReturnIntError( PyExc_TypeError,
905                                                         "expected a list of 4 (or optionally 5 if the curve is 3D) floats" );
906
907                 /* copy x, y, z, w */
908                 for( i = 0; i < 4; ++i ) {
909                         PyObject *item = PySequence_GetItem( pyOb, i );
910
911                         if (item == NULL)
912                                 return -1;
913
914                         nurb->bp[index].vec[i] = ( float ) PyFloat_AsDouble( item );
915                         Py_DECREF( item );
916                 }
917
918                 if (size == 5) {        /* set tilt, if present */
919                         PyObject *item = PySequence_GetItem( pyOb, i );
920
921                         if (item == NULL)
922                                 return -1;
923
924                         nurb->bp[index].alfa = ( float ) PyFloat_AsDouble( item );
925                         Py_DECREF( item );
926                 }
927                 else {                          /* if not, set default  */
928                         nurb->bp[index].alfa = 0.0f;
929                 }
930
931                 return 0;       /* finished correctly */
932         }
933 }
934
935
936 /* 
937  * this is an internal routine.  not callable directly from python
938  */
939
940 PyObject *CurNurb_pointAtIndex( Nurb * nurb, int index )
941 {
942         PyObject *pyo;
943
944         if( nurb->bp ) {        /* we have a nurb curve */
945                 int i;
946
947                 /* add Tilt only if curve is 3D */
948                 if (nurb->flag & CU_3D)
949                         pyo = PyList_New( 5 );
950                 else
951                         pyo = PyList_New( 4 );
952
953                 for( i = 0; i < 4; i++ ) {
954                         PyList_SetItem( pyo, i,
955                                         PyFloat_FromDouble( nurb->bp[index].vec[i] ) );
956                 }
957
958                 /* add Tilt only if curve is 3D */
959                 if (nurb->flag & CU_3D)
960                         PyList_SetItem( pyo, 4, PyFloat_FromDouble( nurb->bp[index].alfa ) );
961
962         } else if( nurb->bezt ) {       /* we have a bezier */
963                 /* if an error occurs, we just pass it on */
964                 pyo = BezTriple_CreatePyObject( &( nurb->bezt[index] ) );
965
966         } else                  /* something is horribly wrong */
967                 /* neither bp or bezt is set && pntsu != 0 */
968                 return EXPP_ReturnPyObjError( PyExc_SystemError,
969                                                 "inconsistant structure found" );
970
971         return pyo;
972 }
973
974 /*
975   dump nurb
976 */
977
978 PyObject *CurNurb_dump( BPy_CurNurb * self )
979 {
980         BPoint *bp = NULL;
981         BezTriple *bezt = NULL;
982         Nurb *nurb = self->nurb;
983         int npoints = 0;
984
985         if( !self->nurb )
986                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
987                                 "no Nurb in this CurNurb");
988
989         printf(" type: %d, mat_nr: %d hide: %d flag: %d",
990                    nurb->type, nurb->mat_nr, nurb->hide, nurb->flag);
991         printf("\n pntsu: %d, pntsv: %d, resolu: %d resolv: %d",
992                    nurb->pntsu, nurb->pntsv, nurb->resolu, nurb->resolv );
993         printf("\n orderu: %d  orderv: %d", nurb->orderu, nurb->orderv );
994         printf("\n flagu: %d flagv: %d",
995                    nurb->flagu, nurb->flagv );
996
997         npoints = nurb->pntsu;
998
999         if( nurb->bp ) { /* we have a BPoint  */
1000                 int n;
1001                 for( n = 0, bp = nurb->bp;
1002                          n < npoints;
1003                          n++, bp++ )
1004                 {
1005                         /* vec[4] */
1006                         printf( "\ncoords[%d]: ", n);
1007                         {
1008                                 int i;
1009                                 for( i = 0; i < 4; i++){
1010                                         printf("%10.3f ", bp->vec[i] );
1011                                 }
1012                         }
1013                 
1014                         /* alfa, s[2] */
1015                         printf("\n alpha: %5.2f", bp->alfa);
1016                         /* f1, hide */
1017                         printf(" f1 %d  hide %d", bp->f1, bp->hide );
1018                         printf("\n");
1019                 }
1020         }
1021         else { /* we have a BezTriple */
1022                 int n;
1023                 for( n = 0, bezt = nurb->bezt;
1024                          n < npoints;
1025                          n++, bezt++ )
1026                 {
1027                         int i, j;
1028                         printf("\npoint %d: ", n);
1029                         for( i = 0; i < 3; i++ ) {
1030                                 printf("\nvec[%i] ",i );
1031                                 for( j = 0; j < 3; j++ ) {
1032                                         printf(" %5.2f ", bezt->vec[i][j] );
1033                                 }
1034                         }
1035                                 
1036
1037                 }
1038                 printf("\n");
1039         }
1040
1041         Py_RETURN_NONE;
1042 }
1043
1044 /*
1045   recalc nurb
1046 */
1047
1048 static PyObject *CurNurb_recalc( BPy_CurNurb * self )
1049 {
1050         calchandlesNurb ( self->nurb );
1051         Py_RETURN_NONE;
1052 }
1053
1054 PyObject *CurNurb_switchDirection( BPy_CurNurb * self )
1055 {
1056         if( !self->nurb )
1057                 return EXPP_ReturnPyObjError( PyExc_RuntimeError,
1058                                 "no Nurb in this CurNurb");
1059         
1060         switchdirectionNurb( self->nurb );
1061         
1062         Py_RETURN_NONE;
1063 }
1064
1065 PyObject *CurNurb_Init( void )
1066 {
1067         if( PyType_Ready( &CurNurb_Type ) < 0)
1068                 return NULL;
1069
1070         return Py_InitModule3( "Blender.CurNurb", M_CurNurb_methods,
1071                                 M_CurNurb_doc );
1072 }
1073
1074 /* #####DEPRECATED###### */
1075
1076 static PyObject *CurNurb_oldsetType( BPy_CurNurb * self, PyObject * args )
1077 {
1078         return EXPP_setterWrapper( (void *)self, args,
1079                         (setter)CurNurb_setType );
1080 }
1081
1082 static PyObject *CurNurb_oldsetMatIndex( BPy_CurNurb * self, PyObject * args )
1083 {
1084         return EXPP_setterWrapper( (void *)self, args,
1085                         (setter)CurNurb_setMatIndex );
1086 }
1087
1088 static PyObject *CurNurb_oldsetFlagU( BPy_CurNurb * self, PyObject * args )
1089 {
1090         return EXPP_setterWrapper( (void *)self, args,
1091                         (setter)CurNurb_setFlagU );
1092 }
1093
1094 static PyObject *CurNurb_oldsetFlagV( BPy_CurNurb * self, PyObject * args )
1095 {
1096         return EXPP_setterWrapper( (void *)self, args,
1097                         (setter)CurNurb_setFlagV );
1098 }