2016-10-08 6 views
0

Я пытаюсь построить интерфейс python вокруг некоторых существующих C code с CFFI. Как обычно, с C-кодом, обрезанным для производительности, он чреват обширными макросами и typedef.Создание cdata типа `REAL (* vertices) [DIM]` в CFFI

ATM Я работаю на тиражирование следующие структуры

#define DIM  3 
typedef double REAL; 
struct Object_structure { 
    int numpoints; 
    REAL (* vertices)[DIM]; 
    int * rings; 
}; 
typedef struct Object_structure * Object; 

Функция я пытаюсь позвонить ожидает аргумент типа Object.

REAL gjk_distance(
    Object obj1, REAL (* tr1)[DIM+1], 
    Object obj2, REAL (* tr2)[DIM+1], 
    REAL wpt1[DIM], REAL wpt2[DIM], 
    struct simplex_point * simplex, int use_seed 
    ); 

Я написал следующий класс питона для представления такого объекта /-структуры, но у меня возникают проблемы преобразования его в ожидаемый объект CDATA. (На данный момент я просто рассматривает UnitCube, но в конечном счете, я хочу обобщать, что.)

class Box: 
    def __init__(self, pos): 
     self._weakkeydict = weakref.WeakKeyDictionary() 
     self.numpoints = 8 
     self.rings = [ 
      8, 12, 16, 20, 24, 28, 32, 36, 
      3, 1, 4, -1, 
      0, 2, 5, -1, 
      1, 3, 6, -1, 
      2, 0, 7, -1, 
      7, 5, 0, -1, 
      4, 6, 1, -1, 
      5, 7, 2, -1, 
      6, 4, 3, -1] 
     x, y, z = pos 
     self.vertices = [ 
      [x+0, y+0, z+0], 
      [x+1, y+0, z+0], 
      [x+1, y+1, z+0], 
      [x+0, y+1, z+0], 
      [x+0, y+0, z+1], 
      [x+1, y+0, z+1], 
      [x+1, y+1, z+1], 
      [x+0, y+1, z+1], 
     ] 

    @property 
    def cdata(self): 
     self._weakkeydict.clear() 

     #ptr_numpoints = ffi.new("int", self.numpoints) 
     ptr_rings = ffi.new("int[]", self.rings) 
     vertices = [ffi.new("REAL[3]", v) for v in self.vertices] 
     ptr_vertices = ffi.new("REAL *[3]", vertices) 

     ptr_obj = ffi.new("Object", { 
      'numpoints': self.numpoints, 
      'rings': ptr_rings, 
      'vertices': ptr_vertices}) 
     self._weakkeydict[ptr_obj] = (ptr_rings, ptr_vertices, vertices) 
     return ptr_obj 

С выше я получаю IndexError: too many initializers for 'double *[3]' (got 8) в строке ptr_vertices = ffi.new("REAL *[3]", vertices) при вызове:

box1 = Box((0,0,0)) 
box2 = Box((10,0,0)) 
d = lib.gjk_distance( 
     [box1.cdata], ffi.NULL, 
     [box2.cdata], ffi.NULL, 
     ffi.NULL, ffi.NULL, 
     ffi.NULL, 0 ) 

мне кажется, что размеры как-то переключились. Так как это должен быть массив из 8 элементов с 3 элементами элемента. Я надеюсь, что кто-то может указать мне в правильном направлении.

ответ

1

Если вы создаете отдельный объект, используйте ffi.new('REAL(*)[3]', [1, 2, 3]). Важна скобка вокруг *.

В C тип REAL(*)[3] означает указатель на массив (размер = 3) REAL, а REAL*[3] означает массив (размер = 3) указателя на реальный. См. C pointer to array/array of pointers disambiguation для получения дополнительной информации.

Теперь, вы создаете массив элементов, CFFI expects an array type вместо этого, as you have already discovered. Его можно сравнить с:

ffi.new('int*', 1) # ok 
ffi.new('int[]', 1) # wrong 
ffi.new('int*', [1, 2, 3]) # wrong 
ffi.new('int[]', [1, 2, 3]) # ok 

ffi.new('REAL(*)[3]', [0.1, 0.2, 0.3]) # ok 
ffi.new('REAL[][3]', [0.1, 0.2, 0.3])  # wrong 
ffi.new('REAL(*)[3]', [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]]) # wrong 
ffi.new('REAL[][3]', [[0.1, 0.2, 0.3], [0.4, 0.5, 0.6]])  # ok 
+0

Спасибо. Не могли бы вы прокомментировать, как это относится к 'REAL [] [3]'? – PeterE

+0

Btw, 'ffi.new ('REAL (*) [3]')' здесь не работает, но 'ffi.new (" REAL [] [3] ")' делает. По-видимому, синтаксис CFFI не является синтаксисом Си. То, что должно быть сохранено, представляет собой (в данном случае) 8 на 3 двумерный (вложенный) массив, причем 3 - размер внутреннего/второго измерения. Я понимаю, что вместо определения массива с фиксированным размером 8x3 внешний размер обобщается указателем на первый 3-элементный подмассив, поэтому c-декларация является 'REAL (*) [3]'. В CFFI это, по-видимому, должно быть переведено на 'REAL [] [3]' по причинам, которые я не понимаю. – PeterE

+0

@PeterE проверка обновление. – kennytm

0

Видимо, ptr_vertices = ffi.new("REAL[][3]", self.vertices) - это путь. На данный момент он работает.