ADN Open CIS
Сообщество программистов Autodesk в СНГ

26/08/2014

Синхронизация видов Пространства Модели

Это пример кода синхронизирующий параметры двух ВЭкранов пространства Модели. Для простоты код подразумевает, что Пространство Модели уже разделено вертикально на два ВЭкрана одинаковой ширины. Если ширина ВЭкранов не одинакова код сделает её одинаковой перед синхронизацией параметров ВЭкранов.

Чтобы получить оповещение об изменении параметров ВЭкрана код подписывается на событие AcEditorReactor::viewChanged. Так как изменение ВЭкрана  при операциях PAN и ZOOM при помощи колесика мыши не приводят к появлению события AcEditorReactor::viewChanged понадобится отслеживать еще и операции с мышью. После того, как ВЭкран изменяется, мы выполняем операцию синхронизации ВЭкранов при первой возможности, когда AutoCAD перейдет в состояние ожидания.

Вот соответствующие куски кода. Полный проект можно скачать отсюда: ПримерПроекта-1

Код - C++: [Выделить]
  1. // Команда для синхронизации параметров видов Просторанства Модели
  2. static  void  AdskMyTestSyncVTR()
  3. {
  4.   // Обновляем записи таблицы видов (VTR)
  5.   acedVports2VportTableRecords();
  6.  
  7.   // Мы обновим запись таблицы видов только если
  8.   // параметры вида изменились
  9.   Adesk::Boolean updateNeeded = Adesk::kFalse;
  10.  
  11.   Acad::ErrorStatus es;
  12.   AcDbDatabase *pDb
  13.     = acdbHostApplicationServices()->workingDatabase();
  14.  
  15.   AcApDocument *pDoc = acDocManager->document(pDb);
  16.   if ( pDoc == NULL )
  17.     return ;
  18.   es = acDocManager->lockDocument(pDoc);
  19.  
  20.   // Этот код может работать только с двумя видами Пространства Модели
  21.   // разделенными пополам вертикально
  22.   if (pDb->tilemode() == Adesk::kFalse)
  23.   {
  24.     struct  resbuf rb;
  25.     if (ads_getvar(_T("cvport" ), &rb) != RTNORM)
  26.     {
  27.       acutPrintf(_T("\\nОшибка использования ads_getvar().\\n" ));
  28.       return ;
  29.     }
  30.  
  31.     if (rb.resval.rint == 1)
  32.     {
  33.       // Может работать только в Пространстве Модели
  34.       return ;
  35.     }
  36.   }
  37.  
  38.   AcDbViewportTable *pVT = NULL;
  39.   pDb->getViewportTable(pVT,AcDb::kForRead);
  40.  
  41.   // Определяем левый и правый виды
  42.   AcDbViewportTableRecord *pLeftVTR = NULL;
  43.   AcDbViewportTableRecord *pRightVTR = NULL;
  44.  
  45.   AcDbViewportTableIterator *pIter = NULL;
  46.   es = pVT->newIterator(pIter);
  47.   if (es == Acad::eOk)
  48.   {
  49.     for  (;!pIter->done();pIter->step())
  50.     {
  51.       AcDbViewportTableRecord *pVTR = NULL;
  52.       es = pIter->getRecord(pVTR, AcDb::kForRead);
  53.       if (es == Acad::eOk)
  54.       {
  55.         AcGePoint2d ll = pVTR->lowerLeftCorner();
  56.         AcGePoint2d ur = pVTR->upperRightCorner();
  57.  
  58.         if (ll.isEqualTo(AcGePoint2d(0, 0)))
  59.         {// Левый вид
  60.           pLeftVTR = pVTR;
  61.         }
  62.         else  if (ur.isEqualTo(AcGePoint2d(1.0, 1.0)))
  63.         {// Правый вид
  64.           pRightVTR = pVTR;
  65.         }
  66.         else
  67.           pVTR->close();
  68.       }
  69.     }
  70.  
  71.     // Если по каким-то причинам видов не два
  72.     // завершаем работу
  73.     if (pLeftVTR == NULL)
  74.     {
  75.       if (pRightVTR != NULL)
  76.         pRightVTR->close();
  77.       return ;
  78.     }
  79.     if (pRightVTR == NULL)
  80.     {
  81.       if (pLeftVTR != NULL)
  82.         pLeftVTR->close();
  83.       return ;
  84.     }
  85.  
  86.     // Убеждаемся что два вида разделены вертикально
  87.     // пополам.
  88.     // Если это не так, то параметры вида не могут быть
  89.     // применены непосредственно с
  90.     // использованием этого кода.
  91.     // Если виды изменены вручную
  92.     // сделаем их одинаковыми программно.
  93.     AcGePoint2d ll1 = pLeftVTR->lowerLeftCorner();
  94.     AcGePoint2d ur1 = pLeftVTR->upperRightCorner();
  95.  
  96.     AcGePoint2d ll2 = pRightVTR->lowerLeftCorner();
  97.     AcGePoint2d ur2 = pRightVTR->upperRightCorner();
  98.  
  99.     if (ll1.isEqualTo(AcGePoint2d(0.0, 0.0)) == false )
  100.     {
  101.       if (! pLeftVTR->isWriteEnabled())
  102.         pLeftVTR->upgradeOpen();
  103.  
  104.       pLeftVTR->setLowerLeftCorner
  105.         (AcGePoint2d(0.0, 0.0));
  106.     }
  107.  
  108.     if (ur1.isEqualTo(AcGePoint2d(0.5, 1.0)) == false )
  109.     {
  110.       if (! pLeftVTR->isWriteEnabled())
  111.         pLeftVTR->upgradeOpen();
  112.  
  113.       pLeftVTR->setUpperRightCorner
  114.         (AcGePoint2d(0.5, 1.0));
  115.     }
  116.  
  117.     if (ll2.isEqualTo(AcGePoint2d(0.5, 0.0)) == false )
  118.     {
  119.       if (! pRightVTR->isWriteEnabled())
  120.         pRightVTR->upgradeOpen();
  121.  
  122.       pRightVTR->setLowerLeftCorner
  123.         (AcGePoint2d(0.5, 0.0));
  124.     }
  125.  
  126.     if (ur2.isEqualTo(AcGePoint2d(1.0, 1.0)) == false )
  127.     {
  128.       if (! pRightVTR->isWriteEnabled())
  129.         pRightVTR->upgradeOpen();
  130.  
  131.       pRightVTR->setUpperRightCorner
  132.         (AcGePoint2d(1.0, 1.0));
  133.     }
  134.  
  135.     // Получаем активный вид Пространства Модели
  136.     struct  resbuf res;
  137.     acedGetVar(L"CVPORT" , &res);
  138.     short  vpnumber = res.resval.rint;
  139.  
  140.     // Определяем вид из/в который
  141.     // установки будут скопированы.
  142.     // Активный вид - это вид исз которого
  143.     // будут копироваться установки
  144.     AcDbViewportTableRecord *pFromVTR = NULL;
  145.     AcDbViewportTableRecord *pToVTR = NULL;
  146.  
  147.     if (pLeftVTR->number() == vpnumber)
  148.     {
  149.       pFromVTR = pLeftVTR;
  150.       pToVTR = pRightVTR;
  151.     }
  152.     if (pRightVTR->number() == vpnumber)
  153.     {
  154.       pFromVTR = pRightVTR;
  155.       pToVTR = pLeftVTR;
  156.     }
  157.  
  158.     // Увы, но мы не смогли идентифицировать
  159.     // активный вид.
  160.     if (pFromVTR == NULL || pToVTR == NULL)
  161.       return ;
  162.  
  163.     // Копируем установки VTR из одного вида в другой
  164.     // только если они различны. Установим допуск в достаточно
  165.     // малое значение, чтобы не зациклится
  166.  
  167.     AcGeTol newTol;
  168.     newTol.setEqualPoint (0.00001);
  169.     newTol.setEqualVector(0.00001);
  170.  
  171.     // Направление взгляда
  172.     AcGeVector3d fromViewDir = pFromVTR->viewDirection();
  173.     AcGeVector3d toViewDir = pToVTR->viewDirection();
  174.     if (pFromVTR->viewDirection().isEqualTo(
  175.       pToVTR->viewDirection(), newTol) == false )
  176.     {
  177.       if (! pToVTR->isWriteEnabled())
  178.         pToVTR->upgradeOpen();
  179.  
  180.       pToVTR->setViewDirection(
  181.         pFromVTR->viewDirection());
  182.       updateNeeded = Adesk::kTrue;
  183.     }
  184.  
  185.     // Поворот вида
  186.     if (abs(pFromVTR->viewTwist()
  187.       - pToVTR->viewTwist()) > 0.01)
  188.     {
  189.       if (! pToVTR->isWriteEnabled())
  190.         pToVTR->upgradeOpen();
  191.  
  192.       pToVTR->setViewTwist(pFromVTR->viewTwist());
  193.       updateNeeded = Adesk::kTrue;
  194.     }
  195.  
  196.     // Точка цели
  197.     if (pFromVTR->target().isEqualTo(
  198.       pToVTR->target(), newTol) == false )
  199.     {
  200.       if (! pToVTR->isWriteEnabled())
  201.         pToVTR->upgradeOpen();
  202.  
  203.       pToVTR->setTarget(pFromVTR->target());
  204.       updateNeeded = Adesk::kTrue;
  205.     }
  206.  
  207.     // Задняя подрезка
  208.     if (pFromVTR->backClipEnabled()
  209.       != pToVTR->backClipEnabled())
  210.     {
  211.       if (! pToVTR->isWriteEnabled())
  212.         pToVTR->upgradeOpen();
  213.       pToVTR->setBackClipEnabled(
  214.         pFromVTR->backClipEnabled());
  215.       updateNeeded = Adesk::kTrue;
  216.     }
  217.  
  218.     // Глубина задней плоскости
  219.     if (abs(pFromVTR->backClipDistance()
  220.       - pToVTR->backClipDistance()) > 0.01)
  221.     {
  222.       if (! pToVTR->isWriteEnabled())
  223.         pToVTR->upgradeOpen();
  224.  
  225.       pToVTR->setBackClipDistance(
  226.         pFromVTR->backClipDistance());
  227.       updateNeeded = Adesk::kTrue;
  228.     }
  229.  
  230.     // Передняя подрезка
  231.     if (pFromVTR->frontClipEnabled()
  232.       != pToVTR->frontClipEnabled())
  233.     {
  234.       if (! pToVTR->isWriteEnabled())
  235.         pToVTR->upgradeOpen();
  236.       pToVTR->setFrontClipEnabled(
  237.         pFromVTR->frontClipEnabled());
  238.       updateNeeded = Adesk::kTrue;
  239.     }
  240.  
  241.     // Глубина передней плоскости
  242.     if (abs(pFromVTR->frontClipDistance()
  243.       - pToVTR->frontClipDistance()) > 0.01)
  244.     {
  245.       if (! pToVTR->isWriteEnabled())
  246.         pToVTR->upgradeOpen();
  247.  
  248.       pToVTR->setFrontClipDistance(
  249.         pFromVTR->frontClipDistance());
  250.       updateNeeded = Adesk::kTrue;
  251.     }
  252.  
  253.     // Уровень
  254.     if (abs(pFromVTR->elevation()
  255.       - pToVTR->elevation()) > 0.01)
  256.     {
  257.       if (! pToVTR->isWriteEnabled())
  258.         pToVTR->upgradeOpen();
  259.  
  260.       pToVTR->setElevation(pFromVTR->elevation());
  261.       updateNeeded = Adesk::kTrue;
  262.     }
  263.  
  264.     // Точка центра
  265.     if (pFromVTR->centerPoint().isEqualTo(
  266.       pToVTR->centerPoint(), newTol) == false )
  267.     {
  268.       if (! pToVTR->isWriteEnabled())
  269.         pToVTR->upgradeOpen();
  270.  
  271.       pToVTR->setCenterPoint(pFromVTR->centerPoint());
  272.       updateNeeded = Adesk::kTrue;
  273.     }
  274.  
  275.     // Высота
  276.     if (abs(pFromVTR->height() - pToVTR->height()) > 0.01)
  277.     {
  278.       if (! pToVTR->isWriteEnabled())
  279.         pToVTR->upgradeOpen();
  280.  
  281.       pToVTR->setHeight(pFromVTR->height());
  282.       updateNeeded = Adesk::kTrue;
  283.     }
  284.  
  285.     // Ширина
  286.     if (abs(pFromVTR->width() - pToVTR->width()) > 0.01)
  287.     {
  288.       if (! pToVTR->isWriteEnabled())
  289.         pToVTR->upgradeOpen();
  290.  
  291.       pToVTR->setWidth(pFromVTR->width());
  292.       updateNeeded = Adesk::kTrue;
  293.     }
  294.  
  295.     // Заканчиваем сVTR
  296.     pLeftVTR->close();
  297.     pRightVTR->close();
  298.  
  299.     delete  pIter;
  300.   }
  301.   es = pVT->close();
  302.  
  303.   es = acDocManager->unlockDocument(pDoc);
  304.  
  305.   // Обновляем ВЭкраны если что-то поменяли
  306.   if (updateNeeded)
  307.   {
  308.     acedVportTableRecords2Vports();
  309.   }
  310. }
  311.  
  312. // Оповещение об изменении вида не возникает
  313. // если PAN или ZOOM выполняется при помощи мыши.
  314. // Так что идентифицируем их при помощи WM сообщений в фильтре.
  315. BOOL WinCallBack(MSG *pMsg)
  316. {
  317.   if (     pMsg->message == WM_VSCROLL                      ||
  318.     pMsg->message == WM_HSCROLL                  ||
  319.     pMsg->message == WM_MOUSEWHEEL   ||
  320.     pMsg->message == WM_MBUTTONUP)
  321.   {
  322.     // Синхронизуем ВЭкраны Пространства модели
  323.     acDocManager->sendStringToExecute(
  324.       acDocManager->mdiActiveDocument(),
  325.       ACRX_T("SyncVTR " ),
  326.       false , true , false );
  327.   }
  328.   return  FALSE;
  329. }
  330.  
  331. // Устанавливаем реакторы и фильтр сообщений
  332. virtual  AcRx::AppRetCode On_kInitAppMsg (void  *pkt)
  333. {
  334.   AcRx::AppRetCode retCode
  335.     = AcRxArxApp::On_kInitAppMsg (pkt) ;
  336.  
  337.   // Реактор редактора для получения сообщений ViewChanged
  338.   pEditorReactor = new  AcMyEditorReactor(true );
  339.  
  340.   // Реактор InputContext для получения сообщения о входе
  341.   // в состояние ожидание
  342.   pInputContextReactor = new  AcMyInputContextReactor();
  343.  
  344.   // Viewchanged реакция на действия мышью
  345.   acedRegisterFilterWinMsg(WinCallBack);
  346.  
  347.   return  (retCode);
  348. }
  349.  
  350. // Чистим реакторы и фильтр сообщений
  351. virtual  AcRx::AppRetCode On_kUnloadAppMsg (void  *pkt)
  352. {
  353.   AcRx::AppRetCode retCode
  354.     = AcRxArxApp::On_kUnloadAppMsg (pkt) ;
  355.  
  356.   // чистим
  357.   if (pEditorReactor)
  358.   {
  359.     delete  pEditorReactor;
  360.     pEditorReactor = NULL;
  361.   }
  362.  
  363.   if (pInputContextReactor)
  364.   {
  365.     delete  pInputContextReactor;
  366.     pInputContextReactor = NULL;
  367.   }
  368.  
  369.   acedRemoveFilterWinMsg(WinCallBack);
  370.  
  371.   return  (retCode);
  372. }
  373.  
  374. // Переопределяем метод beginQuiescentState для запуска синхронизации
  375. void  AcMyInputContextReactor::beginQuiescentState()
  376. {
  377.   // Проверяем изменился ли вид
  378.   if (_viewChanged)
  379.   {
  380.     // Синхронизация однократная, чтобы не зацикливаться
  381.     _viewChanged = false ;
  382.  
  383.     // Запускаем команду синхнонизации
  384.     acDocManager->sendStringToExecute(
  385.       acDocManager->mdiActiveDocument(),
  386.       ACRX_T("SyncVTR " ),
  387.       false , true , false );
  388.   }
  389. }
  390.  
  391. // Переопределяем метод viewChanged чтобы узнать что вид изменился
  392. void  AcMyEditorReactor::viewChanged()
  393. {
  394.   AcMyInputContextReactor::_viewChanged = true ;
  395. }

 

Источник: http://adndevblog.typepad.com/autocad/2014/07/synchronizing-model-space-viewports.html

Обсуждение: http://adn-cis.org/forum/index.php?topic=930

Опубликовано 26.08.2014
Отредактировано 26.08.2014 в 09:16:37