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