К основному контенту

Интеграция 3D-мыши в Renga


Примерно неделю назад Александр Ершов - любитель новых технологий и двигатель прогресса в нашей команде - опубликовал статью на Хабре о том, как он интегрировал 3D-мышь в Renga. Для тех, кто еще не читал эту статью, но как Александр интересуется новыми технологиями, публикуем его статью в нашем блоге.
image   
3D-манипуляторы - это средства взаимодействия пользователя с программным обеспечением, которые обеспечивают интуитивную навигацию в трехмерном пространстве и возможность работать двумя руками одновременно. Инженеры-проектировщики и компании, которые внедрили 3D-манипуляторы, сообщают о внушительном приросте производительности. Речь в статье пойдет о 3D-мыши от компании 3DСonnexion. Вот так она выглядит (картинка из интернетов): 
image 
У 3D-мышки 6 степеней свободы: смещение по осям X, Y, Z, а также поворот вокруг осей, соответственно: Roll, Pitch, Yaw. 
image 
Степени свободы мышки: 
image 
Для интеграции 3D-мыши в ваше приложение компания 3DСonnexion предоставляет SDK. Его можно скачать с сайта производителя после регистрации.
Продемонстрирую способ интеграции 3D-мыши в приложение на основе Qt5. Создадим простое Qt приложение с помощью мастера новых проектов в Visual Studio. 
Для работы с 3D-мышью нужно включить несколько заголовочных файлов из SDK:

// Mouse 3D stuff
#include <spwmacro.h> /* Common macros used by SpaceWare functions. */
#include <si.h> /* Required for any SpaceWare support within an app.*/
#include <siapp.h> /* Required for siapp.lib symbols */
#include "virtualkeys.hpp"
Для того чтобы мышка заработала, ей нужно передать handle окна, куда мышка будет присылать сообщения. Напишем код инициализации мышки. Он будет выглядеть как-то так: 

bool init3DMouse()
{
  SiOpenData oData;
 /*init the SpaceWare input library */
 if (SiInitialize() == SPW_DLL_LOAD_ERROR)
return false;

 SiOpenWinInit(&oData, (HWND)winId()); /* init Win. platform specific data */
 SiSetUiMode(mouse3DHandle, SI_UI_ALL_CONTROLS); /* Config SoftButton Win Display  */

 /* open data, which will check for device type and return the device handle
 to be used by this function */
 if ( (mouse3DHandle = SiOpen ("HabrahabrAnd3DMouse", SI_ANY_DEVICE, SI_NO_MASK, SI_EVENT, &oData)) == NULL)
{
SiTerminate(); /* called to shut down the SpaceWare input library */
return false; /* could not open device */
}
 else
{
return true; /* opened device succesfully */
}
Теперь мышка подключена к нашему приложению и будет присылать в message loop нашего окна сообщения. Сообщение от мышки имеет следующую структуру:

typedef struct /* 3DxWare event */
{
int type; /* Event type */
union
{
SiSpwData spwData;            /* Button, motion, or combo data */
SiSpwOOB spwOOB;              /* Out of band message */
SiOrientation spwOrientation; /* Which hand orientation is the device */
char exData[SI_MAXBUF];       /* Exception data. Driver use only */
SiKeyboardData spwKeyData;    /* String for keyboard data */
SiSyncPacket siSyncPacket;    /* GUI SyncPacket sent to applications */
SiHWButtonData hwButtonEvent; /* V3DKey that goes with *
                               * SI_BUTTON_PRESS/RELEASE_EVENT */
SiAppCommandData appCommandData; /* Application command event function data that *
 * goes with an SI_APP_EVENT event */
SiDeviceChangeEventData deviceChangeEventData; /* Data for connecting/disconnecting devices */
SiCmdEventData cmdEventData;   /* V3DCMD_* function data that *
                               * goes with an SI_CMD_EVENT event */
 } u;
} SiSpwEvent;
Нас интересует тип события - SiSpwEvent::type. И SiSpwData::spwData - там находится информация о нажатых кнопках, перемещении и вращении по осям.
Наша задача отфильтровать сообщения от мышки. Для этого установим наш класс в качестве фильтра событий. Отнаследуемся от QAbstractNativeEventFilter и переопределим функцию nativeEventFilter:

bool HabrahabrAnd3DMouse::nativeEventFilter(const QByteArray &eventType, void *msg, long *)
 {
  if(!mouse3DHandle)
    return false;
  MSG* winMSG = (MSG*)msg;
  bool handled = SPW_FALSE;
  SiSpwEvent Event; /* SpaceWare Event */
  SiGetEventData EData; /* SpaceWare Event Data */
  /* init Window platform specific data for a call to SiGetEvent */
  SiGetEventWinInit(&EData, winMSG->message, winMSG->wParam, winMSG->lParam);
  /* check whether msg was a 3D mouse event and process it */
  if (SiGetEvent (mouse3DHandle, SI_AVERAGE_EVENTS, &EData, &Event) == SI_IS_EVENT)
  {
     if (Event.type == SI_MOTION_EVENT)
     {
       qDebug() << "delta by X coordinate = " << Event.u.spwData.mData[SI_TX] << "\n";
       qDebug() << "delta by Y coordinate = " << Event.u.spwData.mData[SI_TY] << "\n";
       qDebug() << "delta by Z coordinate = " << Event.u.spwData.mData[SI_TZ] << "\n";
       qDebug() << "delta by Yaw = " << Event.u.spwData.mData[SI_RX] << "\n";
       qDebug() << "delta by Pitch = " << Event.u.spwData.mData[SI_RY] << "\n";
       qDebug() << "delta by Roll = " << Event.u.spwData.mData[SI_RZ] << "\n";
     }
     else if (Event.type == SI_ZERO_EVENT)
     {
       // ZERO event
     }
     else if (Event.type == SI_BUTTON_EVENT)
     {
      // misc button events
     }

     handled = SPW_TRUE; /* 3D mouse event handled */
     }

  return handled;
}
На этом подключение мышки к нашему приложению завершено. Ссылка на полный код примера.

Комментарии

Популярные сообщения из этого блога

Автоматическое заполнение основной надписи

Два месяца назад мы рассказывали о том, как и для чего использовать Информацию о проекте  в Renga, какие свойства нужно создать, чтобы задать координаты участка. В самом конце той статьи внимательный читатель мог заметить, что информацию о проекте, здании и участке можно будет использовать при оформлении документации. Сегодня рассказываем, как это будет, ведь новый выпуск уже совсем скоро. Вы должно быть знаете, что в Renga версии 4.6 появились стили оформления , с помощью которых на лист чертежа можно добавить рамку, формы основной надписи и дополнительных граф. При изменении параметров листа рамка и штамп автоматически окажутся там, где им и положено быть. Однако в 4.6 формы не заполняются текстом. Мы продолжили работу над этой функциональностью и последние полтора месяца команда Lancelot трудилась над тем, чтобы основную надпись можно было заполнить прямо на чертеже. Так, щелкнув по форме, вы сможете заполнить ячейки необходимыми данными. При этом фо

Освой электрику в Renga

Добрый день! Принципы проектирования всех инженерных систем в Renga одинаковы, однако каждая из них достойна отдельного внимания. В этой заметке мы расскажем и наглядно покажем на примере однокомнатной квартиры, как проектировать электрику в Renga. Надеемся, что вы попробуете повторить приведенную ниже инструкцию и это поможет вам оценить возможности Renga. Начинаем проектирование электрики с установки осветительных приборов, выключателей и розеток. Их можно размещать только на стенах, перекрытиях, колоннах и балках. Также хорошо, если перед проектированием электрики в модели расставлена мебель, если речь идет о жилых помещениях, или оборудование в промышленных. Модель квартиры, в которой будет происходить дальнейшая работа, уже подготовлена. Итак, скачайте проект, в котором расставлена мебель, и приступим. Откройте проект в Renga MEP. Щелкните правой кнопкой мыши на пустом месте и выберите Режим измерения > Кубический . Это необходимо, так как расставлять осветительные при

Под крышей дома моего....

Крыша - это главный атрибут любого дома, а особенно частного загородного дома, коттеджа. Она не только призвана защищать его от дождя, снега и палящего солнца, но и является украшением дома и улицы, притягивает взгляд соседей и прохожих. В Renga Architecture инструмент Крыша позволяет строить самые разные модели крыши с помощью небольшого набора команд, но с первого взгляда не всегда ясно, как сделать её той или иной формы. Поэтому мы, Арина Соболева (инженер тех.поддержки) и Анастасия Тян (технический писатель), решили рассказать о разных тонкостях и нюансах работы с этим инструментом на примере нескольких загородных домов -  от простого к сложному. Проще всего в Renga Architecture создать четырехскатную вальмовую крышу. Здесь не надо менять никаких параметров, крыша строится по точкам, непрерывно (Рисунок 1). Рисунок 1 Чтобы её создать, один раз задаем Параметры сегмента (Рисунок 2) и указываем 4 точки по углам здания на 3D Виде. Построение крыши всегда