This file is indexed.

/usr/share/pyshared/tvtk/array_handler.py is in mayavi2 4.1.0-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
"""
This module contains all the array handling code for TVTK.

The most important functions provided by this module involve the
conversion of numpy arrays/Python lists to different VTK data arrays
and vice-versa.

Warning: Numpy Character arrays will not work properly since there
seems no unique one-to-one VTK data array type to map it to.

"""
# Author: Prabhu Ramachandran <prabhu_r@users.sf.net>
# Copyright (c) 2004-2008,  Enthought, Inc.
# License: BSD Style.

import types
import sys

import vtk
from vtk.util import vtkConstants
try:
    from vtk.util import numpy_support
except ImportError:
    numpy_support = None

import numpy

# Enthought library imports.
from tvtk.array_ext import set_id_type_array

# Useful constants for VTK arrays.
VTK_ID_TYPE_SIZE = vtk.vtkIdTypeArray().GetDataTypeSize()
if VTK_ID_TYPE_SIZE == 4:
    ID_TYPE_CODE = numpy.int32
elif VTK_ID_TYPE_SIZE == 8:
    ID_TYPE_CODE = numpy.int64

VTK_LONG_TYPE_SIZE = vtk.vtkLongArray().GetDataTypeSize()
if VTK_LONG_TYPE_SIZE == 4:
    LONG_TYPE_CODE = numpy.int32
    ULONG_TYPE_CODE = numpy.uint32
elif VTK_LONG_TYPE_SIZE == 8:
    LONG_TYPE_CODE = numpy.int64
    ULONG_TYPE_CODE = numpy.uint64

BASE_REFERENCE_COUNT = vtk.vtkObject().GetReferenceCount()


######################################################################
# The array cache.
######################################################################
class ArrayCache(object):

    """Caches references to numpy arrays that are not copied but views
    of which are converted to VTK arrays.  The caching prevents the user
    from deleting or resizing the numpy array after it has been sent
    down to VTK.  The cached arrays are automatically removed when the
    VTK array destructs."""

    ######################################################################
    # `object` interface.
    ######################################################################
    def __init__(self):
        # The cache.
        self._cache = {}

    def __len__(self):
        return len(self._cache)

    def __contains__(self, vtk_arr):
        key = vtk_arr.__this__
        return self._cache.has_key(key)

    ######################################################################
    # `ArrayCache` interface.
    ######################################################################
    def add(self, vtk_arr, np_arr):
        """Add numpy array corresponding to the vtk array to the
        cache."""
        key = vtk_arr.__this__
        cache = self._cache

        # Setup a callback so this cached array reference is removed
        # when the VTK array is destroyed.  Passing the key to the
        # `lambda` function is necessary because the callback will not
        # receive the object (it will receive `None`) and thus there
        # is no way to know which array reference one has to remove.
        vtk_arr.AddObserver('DeleteEvent', lambda o, e, key=key: \
                            self._remove_array(key))

        # Cache the array
        cache[key] = np_arr

    def get(self, vtk_arr):
        """Return the cached numpy array given a VTK array."""
        key = vtk_arr.__this__
        return self._cache[key]

    ######################################################################
    # Non-public interface.
    ######################################################################
    def _remove_array(self, key):
        """Private function that removes the cached array.  Do not
        call this unless you know what you are doing."""
        try:
            del self._cache[key]
        except KeyError:
            pass


######################################################################
# Setup a global `_array_cache`.  The array object cache caches all the
# converted numpy arrays that are not copied.  This prevents the user
# from deleting or resizing the numpy array after it has been sent down
# to VTK.
######################################################################

_dummy = None
# This makes the cache work even when the module is reloaded.
for name in ['array_handler', 'tvtk.array_handler']:
    if sys.modules.has_key(name):
        mod = sys.modules[name]
        if hasattr(mod, '_array_cache'):
            _dummy = mod._array_cache
        del mod
        break

if _dummy:
    _array_cache = _dummy
else:
    _array_cache = ArrayCache()
del _dummy



######################################################################
# Array conversion functions.
######################################################################
def get_vtk_array_type(numeric_array_type):
    """Returns a VTK typecode given a numpy array."""
    # This is a Mapping from numpy array types to VTK array types.
    _arr_vtk = {numpy.dtype(numpy.character):vtkConstants.VTK_UNSIGNED_CHAR,
                numpy.dtype(numpy.uint8):vtkConstants.VTK_UNSIGNED_CHAR,
                numpy.dtype(numpy.uint16):vtkConstants.VTK_UNSIGNED_SHORT,
                numpy.dtype(numpy.int8):vtkConstants.VTK_CHAR,
                numpy.dtype(numpy.int16):vtkConstants.VTK_SHORT,
                numpy.dtype(numpy.int32):vtkConstants.VTK_INT,
                numpy.dtype(numpy.uint32):vtkConstants.VTK_UNSIGNED_INT,
                numpy.dtype(numpy.float32):vtkConstants.VTK_FLOAT,
                numpy.dtype(numpy.float64):vtkConstants.VTK_DOUBLE,
                numpy.dtype(numpy.complex64):vtkConstants.VTK_FLOAT,
                numpy.dtype(numpy.complex128):vtkConstants.VTK_DOUBLE,
                }
    _extra = {numpy.dtype(ID_TYPE_CODE):vtkConstants.VTK_ID_TYPE,
              numpy.dtype(ULONG_TYPE_CODE):vtkConstants.VTK_UNSIGNED_LONG,
              numpy.dtype(LONG_TYPE_CODE):vtkConstants.VTK_LONG,
             }
    for t in _extra:
        if t not in _arr_vtk:
            _arr_vtk[t] = _extra[t]

    try:
        return _arr_vtk[numeric_array_type]
    except KeyError:
        for key in _arr_vtk:
            if numpy.issubdtype(numeric_array_type, key):
                return _arr_vtk[key]
    raise TypeError, "Couldn't translate array's type to VTK"

def get_vtk_to_numeric_typemap():
    """Returns the VTK array type to numpy array type mapping."""
    _vtk_arr = {vtkConstants.VTK_BIT:numpy.bool,
                vtkConstants.VTK_CHAR:numpy.int8,
                vtkConstants.VTK_UNSIGNED_CHAR:numpy.uint8,
                vtkConstants.VTK_SHORT:numpy.int16,
                vtkConstants.VTK_UNSIGNED_SHORT:numpy.uint16,
                vtkConstants.VTK_INT:numpy.int32,
                vtkConstants.VTK_UNSIGNED_INT:numpy.uint32,
                vtkConstants.VTK_LONG:LONG_TYPE_CODE,
                vtkConstants.VTK_UNSIGNED_LONG:ULONG_TYPE_CODE,
                vtkConstants.VTK_ID_TYPE:ID_TYPE_CODE,
                vtkConstants.VTK_FLOAT:numpy.float32,
                vtkConstants.VTK_DOUBLE:numpy.float64}
    return _vtk_arr


def get_numeric_array_type(vtk_array_type):
    """Returns a numpy array typecode given a VTK array type."""
    return get_vtk_to_numeric_typemap()[vtk_array_type]


def get_sizeof_vtk_array(vtk_array_type):
    """Returns the size of a VTK array type."""
    _size_dict = {vtkConstants.VTK_BIT : 1,
                  vtkConstants.VTK_CHAR : 1,
                  vtkConstants.VTK_UNSIGNED_CHAR : 1,
                  vtkConstants.VTK_SHORT : 2,
                  vtkConstants.VTK_UNSIGNED_SHORT : 2,
                  vtkConstants.VTK_INT : 4,
                  vtkConstants.VTK_UNSIGNED_INT : 4,
                  vtkConstants.VTK_LONG : VTK_LONG_TYPE_SIZE,
                  vtkConstants.VTK_UNSIGNED_LONG : VTK_LONG_TYPE_SIZE,
                  vtkConstants.VTK_ID_TYPE : VTK_ID_TYPE_SIZE,
                  vtkConstants.VTK_FLOAT : 4,
                  vtkConstants.VTK_DOUBLE : 8 }
    return _size_dict[vtk_array_type]


def create_vtk_array(vtk_arr_type):
    """Internal function used to create a VTK data array from another
    VTK array given the VTK array type.
    """
    tmp = vtk.vtkDataArray.CreateDataArray(vtk_arr_type)
    # CreateDataArray sets the refcount to 3 and this causes a severe
    # memory leak.
    tmp.SetReferenceCount(BASE_REFERENCE_COUNT)
    return tmp


def array2vtk(num_array, vtk_array=None):
    """Converts a real numpy Array (or a Python list) to a VTK array
    object.

    This function only works for real arrays.  Complex arrays are NOT
    handled.  It also works for multi-component arrays.  However, only
    1, and 2 dimensional arrays are supported.  This function is very
    efficient, so large arrays should not be a problem.

    Even in cases when no copy of the numpy array data is performed,
    a reference to the array is cached.  The passed array can
    therefore be deleted safely in all circumstances.

    Parameters
    ----------

    - num_array : numpy array or Python list/tuple

      The input array must be 1 or 2D.  A copy of the numeric array
      data passed is made in the following circumstances:

       1. A Python list/tuple was passed.
       2. A non-contiguous numpy array was passed.
       3. A `vtkBitArray` instance was passed as the second argument.
       4. The types of the `vtk_array` and the `num_array` are not
          equivalent to each other.  For example if one is an integer
          array and the other a float.


    - vtk_array : `vtkDataArray` (default: `None`)

      If an optional `vtkDataArray` instance, is passed as an argument
      then a new array is not created and returned.  The passed array
      is itself returned.

    """

    z = numpy.asarray(num_array)

    shape = z.shape
    assert len(shape) < 3, \
           "Only arrays of dimensionality 2 or lower are allowed!"
    assert not numpy.issubdtype(z.dtype, complex), \
           "Complex numpy arrays cannot be converted to vtk arrays."\
           "Use real() or imag() to get a component of the array before"\
           " passing it to vtk."

    # First create an array of the right type by using the typecode.
    # Bit arrays need special casing.
    bit_array = False
    if vtk_array is None:
        vtk_typecode = get_vtk_array_type(z.dtype)
        result_array = create_vtk_array(vtk_typecode)
    elif vtk_array.GetDataType() == vtkConstants.VTK_BIT:
        vtk_typecode = vtkConstants.VTK_CHAR
        result_array = create_vtk_array(vtkConstants.VTK_CHAR)
        bit_array = True
    else:
        vtk_typecode = vtk_array.GetDataType()
        result_array = vtk_array

    # Find the shape and set number of components.
    if len(shape) == 1:
        result_array.SetNumberOfComponents(1)
    else:
        result_array.SetNumberOfComponents(shape[1])

    result_array.SetNumberOfTuples(shape[0])

    # Ravel the array appropriately.
    arr_dtype = get_numeric_array_type(vtk_typecode)
    if numpy.issubdtype(z.dtype, arr_dtype):
        z_flat = numpy.ravel(z)
    else:
        z_flat = numpy.ravel(z).astype(arr_dtype)

    # Point the VTK array to the numpy data.  The last argument (1)
    # tells the array not to deallocate.
    result_array.SetVoidArray(numpy.getbuffer(z_flat), len(z_flat), 1)

    if bit_array:
        # Handle bit arrays -- they have to be copied.  Note that bit
        # arrays are used ONLY when the user has passed one as an
        # argument to this function.
        vtk_array.SetNumberOfTuples(result_array.GetNumberOfTuples())
        vtk_array.SetNumberOfComponents(result_array.GetNumberOfComponents())
        for i in range(result_array.GetNumberOfComponents()):
            vtk_array.CopyComponent(i, result_array, i)
        result_array = vtk_array
    else:
        # Save a reference to the flatted array in the array cache.
        # This prevents the user from deleting or resizing the array
        # and getting into serious trouble.  This is only done for
        # non-bit array cases where the data is not copied.
        global _array_cache
        _array_cache.add(result_array, z_flat)

    return result_array


def vtk2array(vtk_array):
    """Converts a VTK data array to a numpy array.

    Given a subclass of vtkDataArray, this function returns an
    appropriate numpy array containing the same data.  The function
    is very efficient since it uses the VTK imaging pipeline to
    convert the data.  If a sufficiently new version of VTK (5.2) is
    installed then it actually uses the buffer interface to return a
    view of the VTK array in the returned numpy array.

    Parameters
    ----------

    - vtk_array : `vtkDataArray`

      The VTK data array to be converted.

    """
    typ = vtk_array.GetDataType()
    assert typ in get_vtk_to_numeric_typemap().keys(), \
           "Unsupported array type %s"%typ

    shape = vtk_array.GetNumberOfTuples(), \
            vtk_array.GetNumberOfComponents()
    if shape[0] == 0:
        dtype = get_numeric_array_type(typ)
        return numpy.array([], dtype)

    # First check if this array already has a numpy array cached, if
    # it does, reshape that and return it.
    if vtk_array in _array_cache:
        arr = _array_cache.get(vtk_array)
        if shape[1] == 1:
            shape = (shape[0], )
        arr = numpy.reshape(arr, shape)
        return arr

    # If VTK's new numpy support is available, use the buffer interface.
    if numpy_support is not None and typ != vtkConstants.VTK_BIT:
        dtype = get_numeric_array_type(typ)
        result = numpy.frombuffer(vtk_array, dtype=dtype)
        if shape[1] == 1:
            shape = (shape[0], )
        result.shape = shape
        return result

    # Setup an imaging pipeline to export the array.
    img_data = vtk.vtkImageData()
    img_data.SetDimensions(shape[0], 1, 1)
    if typ == vtkConstants.VTK_BIT:
        iarr = vtk.vtkCharArray()
        iarr.DeepCopy(vtk_array)
        img_data.GetPointData().SetScalars(iarr)
    elif typ == vtkConstants.VTK_ID_TYPE:
        # Needed since VTK_ID_TYPE does not work with VTK 4.5.
        iarr = vtk.vtkLongArray()
        iarr.SetNumberOfTuples(vtk_array.GetNumberOfTuples())
        nc = vtk_array.GetNumberOfComponents()
        iarr.SetNumberOfComponents(nc)
        for i in range(nc):
            iarr.CopyComponent(i, vtk_array, i)
        img_data.GetPointData().SetScalars(iarr)
    else:
        img_data.GetPointData().SetScalars(vtk_array)

    img_data.SetNumberOfScalarComponents(shape[1])
    if typ == vtkConstants.VTK_ID_TYPE:
        # Hack necessary because vtkImageData can't handle VTK_ID_TYPE.
        img_data.SetScalarType(vtkConstants.VTK_LONG)
        r_dtype = get_numeric_array_type(vtkConstants.VTK_LONG)
    elif typ == vtkConstants.VTK_BIT:
        img_data.SetScalarType(vtkConstants.VTK_CHAR)
        r_dtype = get_numeric_array_type(vtkConstants.VTK_CHAR)
    else:
        img_data.SetScalarType(typ)
        r_dtype = get_numeric_array_type(typ)
    img_data.Update()

    exp = vtk.vtkImageExport()
    exp.SetInput(img_data)

    # Create an array of the right size and export the image into it.
    im_arr = numpy.empty((shape[0]*shape[1],), r_dtype)
    exp.Export(im_arr)

    # Now reshape it.
    if shape[1] == 1:
        shape = (shape[0], )
    im_arr = numpy.reshape(im_arr, shape)
    return im_arr


def array2vtkCellArray(num_array, vtk_array=None):
    """Given a nested Python list or a numpy array, this method
    creates a vtkCellArray instance and returns it.

    A variety of input arguments are supported as described in the
    Parameter documentation.  If numpy arrays are given, this method
    is highly efficient.  This function is most efficient if the
    passed numpy arrays have a typecode `ID_TYPE_CODE`.  Otherwise a
    typecast is necessary and this involves an extra copy.  This
    method *always copies* the input data.

    An alternative and more efficient way to build the connectivity
    list is to create a vtkIdTypeArray having data of the form
    (npts,p0,p1,...p(npts-1), repeated for each cell) and then call
    <vtkCellArray_instance>.SetCells(n_cell, id_list).

    Parameters
    ----------

    - num_array : numpy array or Python list/tuple

      Valid values are:

        1. A Python list of 1D lists.  Each 1D list can contain one
           cell connectivity list.  This is very slow and is to be
           used only when efficiency is of no consequence.

        2. A 2D numpy array with the cell connectivity list.

        3. A Python list of 2D numpy arrays.  Each numeric array can
           have a different shape.  This makes it easy to generate a
           cell array having cells of different kinds.

    - vtk_array : `vtkCellArray` (default: `None`)

      If an optional `vtkCellArray` instance, is passed as an argument
      then a new array is not created and returned.  The passed array
      is itself modified and returned.

    Example
    -------

       >>> a = [[0], [1, 2], [3, 4, 5], [6, 7, 8, 9]]
       >>> cells = array_handler.array2vtkCellArray(a)
       >>> a = numpy.array([[0,1,2], [3,4,5], [6,7,8]], 'l')
       >>> cells = array_handler.array2vtkCellArray(a)
       >>> l_a = [a[:,:1], a[:2,:2], a]
       >>> cells = array_handler.array2vtkCellArray(l_a)

    """
    if vtk_array:
        cells = vtk_array
    else:
        cells = vtk.vtkCellArray()
    assert cells.GetClassName() == 'vtkCellArray', \
           'Second argument must be a `vtkCellArray` instance.'

    if len(num_array) == 0:
        return cells

    ########################################
    # Internal functions.
    def _slow_array2cells(z, cells):
        cells.Reset()
        vtk_ids = vtk.vtkIdList()
        for i in z:
            vtk_ids.Reset()
            for j in i:
                vtk_ids.InsertNextId(j)
            cells.InsertNextCell(vtk_ids)

    def _get_tmp_array(arr):
        try:
            tmp_arr = numpy.asarray(arr, ID_TYPE_CODE)
        except TypeError:
            tmp_arr = arr.astype(ID_TYPE_CODE)
        return tmp_arr

    def _set_cells(cells, n_cells, id_typ_arr):
        vtk_arr = vtk.vtkIdTypeArray()
        array2vtk(id_typ_arr, vtk_arr)
        cells.SetCells(n_cells, vtk_arr)
    ########################################

    msg = "Invalid argument.  Valid types are a Python list of lists,"\
          " a Python list of numpy arrays, or a numpy array."

    if issubclass(type(num_array), (types.ListType, types.TupleType)):
        assert len(num_array[0]) > 0, "Input array must be 2D."
        tp = type(num_array[0])
        if issubclass(tp, types.ListType): # Pure Python list.
            _slow_array2cells(num_array, cells)
            return cells
        elif issubclass(tp, numpy.ndarray):  # List of arrays.
            # Check shape of array and find total size.
            tot_size = 0
            n_cells = 0
            for arr in num_array:
                assert len(arr.shape) == 2, "Each array must be 2D"
                shp = arr.shape
                tot_size += shp[0]*(shp[1] + 1)
                n_cells += shp[0]
            # Create an empty array.
            id_typ_arr = numpy.empty((tot_size,), ID_TYPE_CODE)
            # Now populate it with the ids.
            count = 0
            for arr in num_array:
                tmp_arr = _get_tmp_array(arr)
                shp = arr.shape
                sz = shp[0]*(shp[1] + 1)
                set_id_type_array(tmp_arr, id_typ_arr[count:count+sz])
                count += sz
            # Now set them cells.
            _set_cells(cells, n_cells, id_typ_arr)
            return cells
        else:
            raise TypeError, msg
    elif issubclass(type(num_array), numpy.ndarray):
        assert len(num_array.shape) == 2, "Input array must be 2D."
        tmp_arr = _get_tmp_array(num_array)
        shp = tmp_arr.shape
        id_typ_arr = numpy.empty((shp[0]*(shp[1] + 1),), ID_TYPE_CODE)
        set_id_type_array(tmp_arr, id_typ_arr)
        _set_cells(cells, shp[0], id_typ_arr)
        return cells
    else:
        raise TypeError, msg


def array2vtkPoints(num_array, vtk_points=None):
    """Converts a numpy array/Python list to a vtkPoints object.

    Unless a Python list/tuple or a non-contiguous array is given, no
    copy of the data is made.  Thus the function is very efficient.

    Parameters
    ----------

    - num_array : numpy array or Python list/tuple

      The input array must be 2D with `shape[1] == 3`.

    - vtk_points : `vtkPoints` (default: `None`)

      If an optional `vtkPoints` instance, is passed as an argument
      then a new array is not created and returned.  The passed array
      is itself modified and returned.

    """
    if vtk_points:
        points  = vtk_points
    else:
        points = vtk.vtkPoints()

    arr = numpy.asarray(num_array)
    assert len(arr.shape) == 2, "Points array must be 2 dimensional."
    assert arr.shape[1] == 3, "Incorrect shape: shape[1] must be 3."
    vtk_array = array2vtk(arr)
    points.SetData(vtk_array)
    return points


def array2vtkIdList(num_array, vtk_idlist=None):
    """Converts a numpy array/Python list to a vtkIdList object.

    Parameters
    ----------

    - num_array : numpy array or Python list/tuple

      The input array must be 2D with `shape[1] == 3`.

    - vtk_idlist : `vtkIdList` (default: `None`)

      If an optional `vtkIdList` instance, is passed as an argument
      then a new array is not created and returned.  The passed array
      is itself modified and returned.

    """
    if vtk_idlist:
        ids = vtk_idlist
    else:
        ids = vtk.vtkIdList()

    arr = numpy.asarray(num_array)
    assert len(arr.shape) == 1, "Array for vtkIdList must be 1D"
    ids.SetNumberOfIds(len(arr))
    for i, j in enumerate(arr):
        ids.SetId(i, j)
    return ids


######################################################################
# Array argument handling functions.
######################################################################

def is_array(arr):
    """Returns True if the passed `arr` is a numpy array or a List."""
    if issubclass(type(arr), (numpy.ndarray, types.ListType)):
        return True
    return False


def convert_array(arr, vtk_typ=None):
    """Convert the given array to the optional type specified by
    `vtk_typ`.

    Parameters
    ----------

    - arr : numpy array/list.
    - vtk_typ : `string` or `None`
      represents the type the array is to be converted to.

    """
    if vtk_typ:
        conv = {'vtkCellArray': array2vtkCellArray,
                'vtkPoints': array2vtkPoints,
                'vtkIdList': array2vtkIdList}
        if vtk_typ in conv.keys():
            vtk_arr = getattr(vtk, vtk_typ)()
            return conv[vtk_typ](arr, vtk_arr)
        elif vtk_typ.find('Array') > -1:
            try:
                vtk_arr = getattr(vtk, vtk_typ)()
            except TypeError: # vtk_typ == 'vtkDataArray'
                return array2vtk(arr)
            else:
                return array2vtk(arr, vtk_arr)
        else:
            return arr
    else:
        return array2vtk(arr)


def is_array_sig(s):
    """Given a signature, return if the signature has an array."""
    if not isinstance(s, basestring):
        return False
    arr_types = ['Array', 'vtkPoints', 'vtkIdList']
    for i in arr_types:
        if s.find(i) > -1:
            return True
    return False


def is_array_or_vtkarray(arg):
    """Returns True if the argument is an array/Python list or if it
    is a vtk array."""

    if is_array(arg):
        return True
    else:
        if hasattr(arg, '_vtk_obj'):
            if is_array_sig(arg._vtk_obj.__class__.__name__):
                return True
    return False


def get_correct_sig(args, sigs):
    """Given a list of args and a collection of possible signatures,
    this function returns the most appropriate signature.  This
    function is only called by deref_array.  This implies that one of
    the signatures has an array type.

    """
    # First do the trivial cases.
    if sigs is None:
        return None
    if len(sigs) == 1:
        return sigs[0]
    else:
        # Non-trivial cases.
        la = len(args)
        candidate_sigs = [s for s in sigs if len(s) == la]
        count = len(candidate_sigs)
        if count == 0:
            # No sig has the right number of args.
            msg = "Insufficient number of arguments to method."\
                  "Valid arguments are:\n%s"%sigs
            raise TypeError, msg
        elif count == 1:
            # If only one of the sigs has the right number of args,
            # return it.
            return candidate_sigs[0]
        else:
            # More than one sig has the same number of args.
            # Check if args need conversion at all.
            array_idx = [i for i, a in enumerate(args) \
                         if is_array_or_vtkarray(a)]
            n_arr = len(array_idx)
            if n_arr == 0:
                # No conversion necessary so signature info is
                # useless.
                return None
            else:
                # Need to find the right sig.  This is done by finding
                # the first signature that matches all the arrays in
                # the argument.
                for sig in candidate_sigs:
                    array_in_sig = [is_array_sig(s) for s in sig]
                    if array_in_sig.count(True) != len(array_idx):
                        continue
                    bad = False
                    for i in array_idx:
                        if not array_in_sig[i]:
                            bad = True
                    if not bad:
                        return sig
                # Could not find any valid signature, so give up.
                return None


def deref_vtk(obj):
    """Dereferences the VTK object from the object if possible.  This
    is duplicated from `tvtk_base.py` because I'd like to keep this
    module independent of `tvtk_base.py`.
    """
    if hasattr(obj, '_vtk_obj'):
        return obj._vtk_obj
    else:
        return obj


def deref_array(args, sigs=None):
    """Given a bunch of arguments and optional signature information,
    this converts the arguments suitably.  If the argument is either a
    Python list or a numpy array it is converted to a suitable type
    based on the signature information.  If it is not an array, but a
    TVTK object the VTK object is dereferenced.  Otherwise nothing is
    done.  If no signature information is provided the arrays are
    automatically converted (this can sometimes go wrong).  The
    signature information is provided in the form of a list of lists.

    """
    ret = []
    sig = get_correct_sig(args, sigs)
    if sig:
        for a, s in zip(args, sig):
            if is_array(a) and is_array_sig(s):
                ret.append(convert_array(a, s))
            else:
                ret.append(deref_vtk(a))
    else:
        for a in args:
            if is_array(a):
                ret.append(convert_array(a))
            else:
                ret.append(deref_vtk(a))
    return ret