Я пытаюсь связать Python с библиотекой Bullet Physics C++, используя Cython. Я хотел бы сделать это на скорости C или близкой к скорости C с минимальной упаковкой и распаковкой переменных из Python. Я смог использовать этот подход для создания интерфейса Cython для OpenGL (хотя OpenGL имеет гораздо более простой, не объектно-ориентированный C API, по сравнению с Bullet Physics). Мои интерфейсы OpenGL работают хорошо, но работа над взаимодействием с Bullet Physics идет медленно.
Я прочитал учебник Cython C++ и другие связанные сообщения здесь, но пока не повезло.
Организация Bullet Physics немного сложна, но для этого примера, надеюсь, будет достаточно знать, что btDbvtBroadphase — это структура, производная от класса btBroadphaseInterface. Как вы, наверное, знаете, структуры могут быть производными от классов (наследоваться от них), и между ними не так уж много различий — по крайней мере, в C++. Однако Cython, похоже, позволяет делать «новые» только в классах, а не в структурах. Я думаю, что это приводит к моей первой проблеме.
Объявления в файлах Bullet Physics .h выглядят следующим образом:
class btBroadphaseInterface
{
...
а также
struct btDbvtBroadphase : btBroadphaseInterface
{
...
Вот очень простая строка кода C++, которую я пытаюсь эффективно воспроизвести в Cython:
btBroadphaseInterface* broadphase = new btDbvtBroadphase();
Итак, поскольку в Cython я не могу создать "новую" структуру btDbvtBroadphase, как это делается в C++, как мне создать экземпляр этой структуры, производной от класса, чтобы вызывались все инициализаторы и устанавливались методы внутри?
Я видел несколько упоминаний об ограничениях наследования в Cython.
Очевидно, я могу использовать функцию malloc() для выделения пространства для структуры, но, думаю, это мне мало поможет. Я не вижу, как какой-либо кастинг может помочь.
У меня есть материал Cython ".pxd", показывающий, как я делаю extern cdef из файла .h, но я не думаю, что это поможет прояснить этот вопрос, поэтому я пропущу это, если кто-то не думает, что это может быть полезно.
Я пробовал много вариантов cdefs без везения. Вот как это выглядит сейчас:
cdef extern from "bullet/btBulletDynamicsCommon.h":
cdef cppclass btBroadphaseInterface:
pass
cdef cppclass btDbvtBroadphase(btBroadphaseInterface):
pass
Когда я пытаюсь написать конструктор, который будет делать "новое" в этой структуре, полученной из класса, например:
cdef class PbtDbvtBroadphase:
cdef btBroadphaseInterface *bp
def __cinit__(self):
self.bp=<btBroadphaseInterface *> new btDbvtBroadphase()
Компилятор терпит неудачу с:
Ошибка при компиляции файла Cython: ------------------------------------------------------------ --------------- ...
класс cdef PbtDbvtBroadphase: cdef btBroadphaseInterface *bp
def __cinit__(self): self.bp=<btBroadphaseInterface *> new btDbvtBroadphase()
^
fun4.pyx:173:46: новый оператор может применяться только к классу C++.
Изменить: улучшенный заголовок, который я изначально ввел как строку ключевых слов.
Edit2: добавлены cdefs и вывод компилятора
Я принимаю очень терпеливый ответ @DavidW, поскольку он продемонстрировал, что все должно работать. Я думаю, что произошло то, что у меня был бродячий файл .pxd с тем же базовым именем, что и у моего файла .pyx, и он был интегрирован в сборку, хотя я использовал не distutils, а просто cython из команды строка. .pxd остался от более раннего теста, когда я подумал, что мой метод сборки может не давать таких же результатов, как подход distutils/setup.py. Я убедился, что мой метод сборки не связан с проблемой, и вернулся к моему предпочтительному подходу (помещение cdefs в файл .pyx и просто компиляция и компоновка с помощью простого сценария оболочки, как показано в одном из моих комментариев ниже), но файл . pxd все еще был рядом, и компилятор cython без моего ведома все еще загружал его. Я обнаружил это, когда заметил, что при компиляции получаю "переобъявленные" ошибки. Я пропустил «повторно объявленные», которые прокручивались, и видел ошибки только при попытках нового конструктора.