1 /*=========================================================================
2 
3   Program:   Visualization Toolkit
4   Module:    PyVTKObject.cxx
5 
6   Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7   All rights reserved.
8   See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9 
10      This software is distributed WITHOUT ANY WARRANTY; without even
11      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12      PURPOSE.  See the above copyright notice for more information.
13 
14 =========================================================================*/
15 /*-----------------------------------------------------------------------
16   The PyVTKObject was created in Oct 2000 by David Gobbi for VTK 3.2.
17   Support for weakref added in July 2005 by Prabhu Ramachandran.
18   Buffer interface for vtk arrays added in Feb 2008 by Berk Geveci.
19 
20   A PyVTKObject is a python object that represents a VTK object.
21   Its methods are stored in the __dict__ of its associated PyVTKClass
22   and superclasses.  The PyVTKObject also has a __dict__ of its own
23   that can be used to store arbitrary attributes.
24 
25   Memory management is done as follows. Each PyVTKObject has
26   an entry along with a smart pointer to its vtkObjectBase in
27   the vtkPythonUtil::ObjectMap.  When a PyVTKObject is destructed,
28   it is removed along with the smart pointer from the ObjectMap.
29 -----------------------------------------------------------------------*/
30 
31 #include "PyVTKObject.h"
32 #include "vtkPythonUtil.h"
33 #include "vtkObjectBase.h"
34 #include "vtkDataArray.h"
35 #include "vtkPythonCommand.h"
36 
37 #include <stddef.h>
38 #include <vtksys/ios/sstream>
39 #include <vtksys/cstddef>
40 
41 //--------------------------------------------------------------------
PyVTKObject_String(PyObject * op)42 static PyObject *PyVTKObject_String(PyObject *op)
43 {
44   PyObject *func = PyObject_GetAttrString(op, (char*)"__str__");
45 
46   if (func)
47     {
48     PyObject *res = PyEval_CallObject(func, (PyObject *)NULL);
49     Py_DECREF(func);
50     return res;
51     }
52   PyErr_Clear();
53 
54   vtksys_ios::ostringstream vtkmsg_with_warning_C4701;
55   ((PyVTKObject *)op)->vtk_ptr->Print(vtkmsg_with_warning_C4701);
56   vtkmsg_with_warning_C4701.put('\0');
57   PyObject *res = PyString_FromString(vtkmsg_with_warning_C4701.str().c_str());
58   return res;
59 }
60 
61 //--------------------------------------------------------------------
PyVTKObject_Repr(PyObject * op)62 static PyObject *PyVTKObject_Repr(PyObject *op)
63 {
64   PyObject *func = PyObject_GetAttrString(op, (char*)"__repr__");
65 
66   if (func)
67     {
68     PyObject *res = PyEval_CallObject(func, (PyObject *)NULL);
69     Py_DECREF(func);
70     return res;
71     }
72   PyErr_Clear();
73 
74   char buf[255];
75   sprintf(buf,"(%s)%p",
76           PyString_AS_STRING(((PyVTKObject *)op)->vtk_class->vtk_name),
77           op);
78 
79   return PyString_FromString(buf);
80 }
81 
82 //--------------------------------------------------------------------
PyVTKObject_SetAttr(PyObject * op,PyObject * attr,PyObject * value)83 static int PyVTKObject_SetAttr(PyObject *op, PyObject *attr, PyObject *value)
84 {
85   PyVTKObject *self = (PyVTKObject *)op;
86   char *name = PyString_AsString(attr);
87 
88   if (name[0] == '_' && name[1] == '_')
89     {
90     if (strcmp(name, "__dict__") == 0)
91       {
92       PyErr_SetString(PyExc_RuntimeError,
93                       "__dict__ is a read-only attribute");
94       return -1;
95       }
96     if (strcmp(name, "__class__") == 0)
97       {
98       PyErr_SetString(PyExc_RuntimeError,
99                       "__class__ is a read-only attribute");
100       return -1;
101       }
102     }
103 
104   if (value)
105     {
106     PyObject *func = self->vtk_class->vtk_setattr;
107     if (func)
108       {
109       PyObject *args = Py_BuildValue((char*)"(OOO)", self, attr, value);
110       PyObject *res = PyEval_CallObject(func, args);
111       Py_DECREF(args);
112       if (res)
113         {
114         Py_DECREF(res);
115         return 0;
116         }
117       return -1;
118       }
119     return PyDict_SetItem(self->vtk_dict, attr, value);
120     }
121   else
122     {
123     PyObject *func = self->vtk_class->vtk_delattr;
124     if (func)
125       {
126       PyObject *args = Py_BuildValue((char*)"(OO)", self, attr);
127       PyObject *res = PyEval_CallObject(func, args);
128       Py_DECREF(args);
129       if (res)
130         {
131         Py_DECREF(res);
132         return 0;
133         }
134       return -1;
135       }
136     int rv = PyDict_DelItem(self->vtk_dict, attr);
137     if (rv < 0)
138       {
139       PyErr_SetString(PyExc_AttributeError,
140                       "delete non-existing class attribute");
141       }
142     return rv;
143     }
144 }
145 
146 //--------------------------------------------------------------------
PyVTKObject_GetAttr(PyObject * op,PyObject * attr)147 static PyObject *PyVTKObject_GetAttr(PyObject *op, PyObject *attr)
148 {
149   PyVTKObject *self = (PyVTKObject *)op;
150   char *name = PyString_AsString(attr);
151   PyVTKClass *pyclass = self->vtk_class;
152   PyObject *bases;
153   PyObject *value;
154 
155   if ((value = PyDict_GetItem(self->vtk_dict, attr)))
156     {
157     Py_INCREF(value);
158     return value;
159     }
160 
161   if (name[0] == '_')
162     {
163     if (strcmp(name,"__class__") == 0)
164       {
165       Py_INCREF(self->vtk_class);
166       return (PyObject *)self->vtk_class;
167       }
168 
169     if (strcmp(name,"__this__") == 0)
170       {
171       const char *classname = self->vtk_ptr->GetClassName();
172       const char *cp = classname;
173       char buf[1024];
174       if (isalpha(*cp) || *cp == '_')
175         {
176         do { cp++; } while (isalnum(*cp) || *cp == '_');
177         }
178       if (*cp != '0')
179         {
180         classname = ((PyVTKClass *)self->vtk_class)->vtk_mangle;
181         }
182       sprintf(buf, "p_%.500s", classname);
183       return PyString_FromString(
184         vtkPythonUtil::ManglePointer(self->vtk_ptr, buf));
185       }
186 
187     if (strcmp(name,"__doc__") == 0)
188       {
189       Py_INCREF(pyclass->vtk_doc);
190       return pyclass->vtk_doc;
191       }
192 
193     if (strcmp(name,"__dict__") == 0)
194       {
195       Py_INCREF(self->vtk_dict);
196       return self->vtk_dict;
197       }
198     }
199 
200   while (pyclass != NULL)
201     {
202     value = PyDict_GetItem(PyVTKClass_GetDict((PyObject *)pyclass), attr);
203 
204     if (value)
205       {
206       if (PyCFunction_Check(value))
207         {
208         return PyCFunction_New(((PyCFunctionObject *)value)->m_ml,
209                                (PyObject *)self);
210         }
211       else if (PyCallable_Check(value))
212         {
213         return PyMethod_New(value, (PyObject *)self,
214                             (PyObject *)self->vtk_class);
215         }
216       Py_INCREF(value);
217       return value;
218       }
219 
220     bases = pyclass->vtk_bases;
221     pyclass = NULL;
222     if (PyTuple_Size(bases))
223       {
224       pyclass = (PyVTKClass *)PyTuple_GetItem(bases,0);
225       }
226     }
227 
228   // try the __getattr__ attribute if set
229   pyclass = self->vtk_class;
230   if (pyclass->vtk_getattr)
231     {
232     PyObject *args = Py_BuildValue((char*)"(OO)", self, attr);
233     PyObject *res = PyEval_CallObject(pyclass->vtk_getattr, args);
234     Py_DECREF(args);
235     return res;
236     }
237 
238   PyErr_SetString(PyExc_AttributeError, name);
239   return NULL;
240 }
241 
242 //--------------------------------------------------------------------
243 #if PY_MAJOR_VERSION >= 2
PyVTKObject_Traverse(PyObject * o,visitproc visit,void * arg)244 static int PyVTKObject_Traverse(PyObject *o, visitproc visit, void *arg)
245 {
246   PyVTKObject *self = (PyVTKObject *)o;
247   PyObject *members[2];
248   int err = 0;
249   int i;
250 
251   members[0] = (PyObject *)self->vtk_class;
252   members[1] = self->vtk_dict;
253 
254   for (i = 0; i < 2 && err == 0; i++)
255     {
256     if (members[i])
257       {
258       err = visit(members[i], arg);
259       }
260     }
261 
262   if (self->vtk_observers != 0)
263     {
264     unsigned long *olist = self->vtk_observers;
265     while (err == 0 && *olist != 0)
266       {
267       vtkObject *op = static_cast<vtkObject *>(self->vtk_ptr);
268       vtkCommand *c = op->GetCommand(*olist);
269       if (c == 0)
270         {
271         // observer is gone, remove from list
272         unsigned long *tmp = olist;
273         do { tmp++; } while (*tmp != 0);
274         *olist = *--tmp;
275         *tmp = 0;
276         }
277       else
278         {
279         // visit the observer
280         vtkPythonCommand *cbc = static_cast<vtkPythonCommand *>(c);
281         err = visit(cbc->obj, arg);
282         olist++;
283         }
284       }
285     }
286 
287   return err;
288 }
289 #endif
290 
291 //--------------------------------------------------------------------
PyVTKObject_Delete(PyObject * op)292 static void PyVTKObject_Delete(PyObject *op)
293 {
294   PyVTKObject *self = (PyVTKObject *)op;
295 
296 #if PY_VERSION_HEX >= 0x02020000
297   PyObject_GC_UnTrack(op);
298 #endif
299 
300 #if PY_VERSION_HEX >= 0x02010000
301   if (self->vtk_weakreflist != NULL)
302     {
303     PyObject_ClearWeakRefs(op);
304     }
305 #endif
306 
307   // A python object owning a VTK object reference is getting
308   // destroyed.  Remove the python object's VTK object reference.
309   vtkPythonUtil::RemoveObjectFromMap(op);
310 
311   Py_DECREF((PyObject *)self->vtk_class);
312   Py_DECREF(self->vtk_dict);
313   delete [] self->vtk_observers;
314 
315 #if PY_VERSION_HEX >= 0x02020000
316   PyObject_GC_Del(op);
317 #elif PY_MAJOR_VERSION >= 2
318   PyObject_Del(op);
319 #else
320   PyMem_DEL(op);
321 #endif
322 }
323 
324 //--------------------------------------------------------------------
325 // The following methods and struct define the "buffer" protocol
326 // for PyVTKObject, so that python can read from a vtkDataArray.
327 // This is particularly useful for NumPy.
328 
329 //--------------------------------------------------------------------
330 static Py_ssize_t
PyVTKObject_AsBuffer_GetSegCount(PyObject * op,Py_ssize_t * lenp)331 PyVTKObject_AsBuffer_GetSegCount(PyObject *op, Py_ssize_t *lenp)
332 {
333   PyVTKObject *self = (PyVTKObject*)op;
334   vtkDataArray *da = vtkDataArray::SafeDownCast(self->vtk_ptr);
335   if (da)
336     {
337     if (lenp)
338       {
339       *lenp = da->GetNumberOfTuples()*
340         da->GetNumberOfComponents()*
341         da->GetDataTypeSize();
342       }
343 
344     return 1;
345     }
346 
347   if (lenp)
348     {
349     *lenp = 0;
350     }
351   return 0;
352 }
353 
354 //--------------------------------------------------------------------
355 static Py_ssize_t
PyVTKObject_AsBuffer_GetReadBuf(PyObject * op,Py_ssize_t segment,void ** ptrptr)356 PyVTKObject_AsBuffer_GetReadBuf(
357   PyObject *op, Py_ssize_t segment, void **ptrptr)
358 {
359   if (segment != 0)
360     {
361     PyErr_SetString(PyExc_ValueError,
362                     "accessing non-existing array segment");
363     return -1;
364     }
365 
366   PyVTKObject *self = (PyVTKObject*)op;
367   vtkDataArray *da = vtkDataArray::SafeDownCast(self->vtk_ptr);
368   if (da)
369     {
370     *ptrptr = da->GetVoidPointer(0);
371     return da->GetNumberOfTuples()*
372       da->GetNumberOfComponents()*
373       da->GetDataTypeSize();
374     }
375   return -1;
376 }
377 
378 //--------------------------------------------------------------------
379 static Py_ssize_t
PyVTKObject_AsBuffer_GetWriteBuf(PyObject * op,Py_ssize_t segment,void ** ptrptr)380 PyVTKObject_AsBuffer_GetWriteBuf(
381   PyObject *op, Py_ssize_t segment, void **ptrptr)
382 {
383   return PyVTKObject_AsBuffer_GetReadBuf(op, segment, ptrptr);
384 }
385 
386 //--------------------------------------------------------------------
387 static PyBufferProcs PyVTKObject_AsBuffer = {
388 #if PY_VERSION_HEX >= 0x02050000
389   PyVTKObject_AsBuffer_GetReadBuf,       // bf_getreadbuffer
390   PyVTKObject_AsBuffer_GetWriteBuf,      // bf_getwritebuffer
391   PyVTKObject_AsBuffer_GetSegCount,      // bf_getsegcount
392   0,                                     // bf_getcharbuffer
393  #if PY_VERSION_HEX >= 0x02060000
394   0,                                     // bf_getbuffer
395   0                                      // bf_releasebuffer
396  #endif
397 #else
398   PyVTKObject_AsBuffer_GetReadBuf,       // bf_getreadbuffer
399   PyVTKObject_AsBuffer_GetWriteBuf,      // bf_getwritebuffer
400   PyVTKObject_AsBuffer_GetSegCount,      // bf_getsegcount
401   0,                                     // bf_getcharbuffer
402 #endif
403 };
404 
405 //--------------------------------------------------------------------
406 PyTypeObject PyVTKObject_Type = {
407   PyObject_HEAD_INIT(&PyType_Type)
408   0,
409   (char*)"vtkobject",                    // tp_name
410   sizeof(PyVTKObject),                   // tp_basicsize
411   0,                                     // tp_itemsize
412   PyVTKObject_Delete,                    // tp_dealloc
413   0,                                     // tp_print
414   0,                                     // tp_getattr
415   0,                                     // tp_setattr
416   0,                                     // tp_compare
417   PyVTKObject_Repr,                      // tp_repr
418   0,                                     // tp_as_number
419   0,                                     // tp_as_sequence
420   0,                                     // tp_as_mapping
421   0,                                     // tp_hash
422   0,                                     // tp_call
423   PyVTKObject_String,                    // tp_string
424   PyVTKObject_GetAttr,                   // tp_getattro
425   PyVTKObject_SetAttr,                   // tp_setattro
426   &PyVTKObject_AsBuffer,                 // tp_as_buffer
427 #if PY_VERSION_HEX >= 0x02020000
428   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, // tp_flags
429 #elif PY_VERSION_HEX >= 0x02010000
430   Py_TPFLAGS_HAVE_WEAKREFS,              // tp_flags
431 #else
432   0,                                     // tp_flags
433 #endif
434   (char*)"Use help(x.__class__) to get full documentation.",  // tp_doc
435 #if PY_MAJOR_VERSION >= 2
436   PyVTKObject_Traverse,                  // tp_traverse
437   0,                                     // tp_clear
438   0,                                     // tp_richcompare
439 #if PY_VERSION_HEX >= 0x02010000
440   offsetof(PyVTKObject, vtk_weakreflist),// tp_weaklistoffset
441 #else
442   0,                                     // tp_weaklistoffset
443 #endif
444 #else
445   0, 0, 0, 0,                            // reserved
446 #endif
447 #if PY_VERSION_HEX >= 0x02020000
448   0,                                     // tp_iter
449   0,                                     // tp_iternext
450   0,                                     // tp_methods
451   0,                                     // tp_members
452   0,                                     // tp_getset
453   0,                                     // tp_base
454   0,                                     // tp_dict
455   0,                                     // tp_descr_get
456   0,                                     // tp_descr_set
457   0,                                     // tp_dictoffset
458   0,                                     // tp_init
459   0,                                     // tp_alloc
460   0,                                     // tp_new
461   0,                                     // tp_free
462   0,                                     // tp_is_gc
463   0,                                     // tp_bases
464   0,                                     // tp_mro
465   0,                                     // tp_cache
466   0,                                     // tp_subclasses
467   0,                                     // tp_weaklist
468 #endif
469   VTK_WRAP_PYTHON_SUPRESS_UNINITIALIZED
470 };
471 
PyVTKObject_New(PyObject * pyvtkclass,PyObject * pydict,vtkObjectBase * ptr)472 PyObject *PyVTKObject_New(
473   PyObject *pyvtkclass, PyObject *pydict, vtkObjectBase *ptr)
474 {
475   PyVTKClass *vtkclass = (PyVTKClass *)pyvtkclass;
476   PyObject *dict = 0;
477   PyObject *cls = 0;
478 
479   bool haveRef = false;
480   if (!ptr)
481     {
482     // Create a new instance of this class since we were not given one.
483     if(vtkclass->vtk_new)
484       {
485       ptr = vtkclass->vtk_new();
486       if (!ptr)
487         {
488         // The vtk_new() method returns null when a factory class has no
489         // implementation (i.e. cannot provide a concrete class instance.)
490         // NotImplementedError indicates a pure virtual method call.
491         PyErr_SetString(
492           PyExc_NotImplementedError,
493           (char*)"no concrete implementation exists for this class");
494         return 0;
495         }
496       haveRef = true;
497       }
498     else
499       {
500       PyErr_SetString(
501         PyExc_TypeError,
502         (char*)"this is an abstract class and cannot be instantiated");
503       return 0;
504       }
505     }
506 
507   // We want to find the class that best matches GetClassName(), since
508   // the object might have been created by a factory and might therefore
509   // not be of the type of the class that New() was called on.
510   // There are two situations where we don't want to do this, though.
511   // If pydict is set, then the object is being recreated from a ghost
512   // and we must keep the original class. Also, if vtk_methods is NULL
513   // then the class is a special custom class and must be kept.
514   if (pydict == NULL && vtkclass->vtk_methods != NULL)
515     {
516     cls = vtkPythonUtil::FindClass(ptr->GetClassName());
517     }
518 
519   // Use the class that was passed as an argument
520   if (cls == NULL)
521     {
522     cls = (PyObject *)vtkclass;
523     }
524 
525   Py_INCREF(cls);
526 
527   if (pydict)
528     {
529     Py_INCREF(pydict);
530     dict = pydict;
531     }
532   else
533     {
534     dict = PyDict_New();
535     }
536 
537 #if PY_VERSION_HEX >= 0x02020000
538   PyVTKObject *self = PyObject_GC_New(PyVTKObject, &PyVTKObject_Type);
539 #elif PY_MAJOR_VERSION >= 2
540   PyVTKObject *self = PyObject_New(PyVTKObject, &PyVTKObject_Type);
541 #else
542   PyVTKObject *self = PyObject_NEW(PyVTKObject, &PyVTKObject_Type);
543 #endif
544 
545   self->vtk_ptr = ptr;
546   self->vtk_flags = 0;
547   self->vtk_class = (PyVTKClass *)cls;
548   self->vtk_dict = dict;
549   self->vtk_observers = 0;
550 
551 #if PY_VERSION_HEX >= 0x02010000
552   self->vtk_weakreflist = NULL;
553 #endif
554 
555 #if PY_VERSION_HEX >= 0x02020000
556   PyObject_GC_Track((PyObject *)self);
557 #endif
558 
559   // A python object owning a VTK object reference is getting
560   // created.  Add the python object's VTK object reference.
561   vtkPythonUtil::AddObjectToMap((PyObject *)self, ptr);
562 
563   // The hash now owns a reference so we can free ours.
564   if (haveRef)
565     {
566     ptr->Delete();
567     }
568 
569   return (PyObject *)self;
570 }
571 
PyVTKObject_GetObject(PyObject * obj)572 vtkObjectBase *PyVTKObject_GetObject(PyObject *obj)
573 {
574   return ((PyVTKObject *)obj)->vtk_ptr;
575 }
576 
PyVTKObject_AddObserver(PyObject * obj,unsigned long id)577 void PyVTKObject_AddObserver(PyObject *obj, unsigned long id)
578 {
579   unsigned long *olist = ((PyVTKObject *)obj)->vtk_observers;
580   unsigned long n = 0;
581   if (olist == 0)
582     {
583     olist = new unsigned long[8];
584     ((PyVTKObject *)obj)->vtk_observers = olist;
585     }
586   else
587     {
588     // count the number of items
589     while (olist[n] != 0) { n++; }
590     // check if n+1 is a power of two (base allocation is 8)
591     unsigned long m = n+1;
592     if (m >= 8 && (n & m) == 0)
593       {
594       unsigned long *tmp = olist;
595       olist = new unsigned long[2*m];
596       for (unsigned long i = 0; i < n; i++)
597         {
598         olist[i] = tmp[i];
599         }
600       delete [] tmp;
601       ((PyVTKObject *)obj)->vtk_observers = olist;
602       }
603     }
604   olist[n++] = id;
605   olist[n] = 0;
606 }
607 
PyVTKObject_GetFlags(PyObject * obj)608 unsigned int PyVTKObject_GetFlags(PyObject *obj)
609 {
610   return ((PyVTKObject *)obj)->vtk_flags;
611 }
612 
PyVTKObject_SetFlag(PyObject * obj,unsigned int flag,int val)613 void PyVTKObject_SetFlag(PyObject *obj, unsigned int flag, int val)
614 {
615   if (val)
616     {
617     ((PyVTKObject *)obj)->vtk_flags |= flag;
618     }
619   else
620     {
621     ((PyVTKObject *)obj)->vtk_flags &= ~flag;
622     }
623 }
624