Синхронизация видов Пространства Модели
Это пример кода синхронизирующий параметры двух ВЭкранов пространства Модели. Для простоты код подразумевает, что Пространство Модели уже разделено вертикально на два ВЭкрана одинаковой ширины. Если ширина ВЭкранов не одинакова код сделает её одинаковой перед синхронизацией параметров ВЭкранов.
Чтобы получить оповещение об изменении параметров ВЭкрана код подписывается на событие AcEditorReactor::viewChanged. Так как изменение ВЭкрана при операциях PAN и ZOOM при помощи колесика мыши не приводят к появлению события AcEditorReactor::viewChanged понадобится отслеживать еще и операции с мышью. После того, как ВЭкран изменяется, мы выполняем операцию синхронизации ВЭкранов при первой возможности, когда AutoCAD перейдет в состояние ожидания.
Вот соответствующие куски кода. Полный проект можно скачать отсюда: ПримерПроекта-1
- // Команда для синхронизации параметров видов Просторанства Модели
- static void AdskMyTestSyncVTR()
- {
- // Обновляем записи таблицы видов (VTR)
- acedVports2VportTableRecords();
- // Мы обновим запись таблицы видов только если
- // параметры вида изменились
- Adesk::Boolean updateNeeded = Adesk::kFalse;
- Acad::ErrorStatus es;
- AcDbDatabase *pDb
- = acdbHostApplicationServices()->workingDatabase();
- AcApDocument *pDoc = acDocManager->document(pDb);
- if ( pDoc == NULL )
- return ;
- es = acDocManager->lockDocument(pDoc);
- // Этот код может работать только с двумя видами Пространства Модели
- // разделенными пополам вертикально
- if (pDb->tilemode() == Adesk::kFalse)
- {
- struct resbuf rb;
- if (ads_getvar(_T("cvport" ), &rb) != RTNORM)
- {
- acutPrintf(_T("\\nОшибка использования ads_getvar().\\n" ));
- return ;
- }
- if (rb.resval.rint == 1)
- {
- // Может работать только в Пространстве Модели
- return ;
- }
- }
- AcDbViewportTable *pVT = NULL;
- pDb->getViewportTable(pVT,AcDb::kForRead);
- // Определяем левый и правый виды
- AcDbViewportTableRecord *pLeftVTR = NULL;
- AcDbViewportTableRecord *pRightVTR = NULL;
- AcDbViewportTableIterator *pIter = NULL;
- es = pVT->newIterator(pIter);
- if (es == Acad::eOk)
- {
- for (;!pIter->done();pIter->step())
- {
- AcDbViewportTableRecord *pVTR = NULL;
- es = pIter->getRecord(pVTR, AcDb::kForRead);
- if (es == Acad::eOk)
- {
- AcGePoint2d ll = pVTR->lowerLeftCorner();
- AcGePoint2d ur = pVTR->upperRightCorner();
- if (ll.isEqualTo(AcGePoint2d(0, 0)))
- {// Левый вид
- pLeftVTR = pVTR;
- }
- else if (ur.isEqualTo(AcGePoint2d(1.0, 1.0)))
- {// Правый вид
- pRightVTR = pVTR;
- }
- else
- pVTR->close();
- }
- }
- // Если по каким-то причинам видов не два
- // завершаем работу
- if (pLeftVTR == NULL)
- {
- if (pRightVTR != NULL)
- pRightVTR->close();
- return ;
- }
- if (pRightVTR == NULL)
- {
- if (pLeftVTR != NULL)
- pLeftVTR->close();
- return ;
- }
- // Убеждаемся что два вида разделены вертикально
- // пополам.
- // Если это не так, то параметры вида не могут быть
- // применены непосредственно с
- // использованием этого кода.
- // Если виды изменены вручную
- // сделаем их одинаковыми программно.
- AcGePoint2d ll1 = pLeftVTR->lowerLeftCorner();
- AcGePoint2d ur1 = pLeftVTR->upperRightCorner();
- AcGePoint2d ll2 = pRightVTR->lowerLeftCorner();
- AcGePoint2d ur2 = pRightVTR->upperRightCorner();
- if (ll1.isEqualTo(AcGePoint2d(0.0, 0.0)) == false )
- {
- if (! pLeftVTR->isWriteEnabled())
- pLeftVTR->upgradeOpen();
- pLeftVTR->setLowerLeftCorner
- (AcGePoint2d(0.0, 0.0));
- }
- if (ur1.isEqualTo(AcGePoint2d(0.5, 1.0)) == false )
- {
- if (! pLeftVTR->isWriteEnabled())
- pLeftVTR->upgradeOpen();
- pLeftVTR->setUpperRightCorner
- (AcGePoint2d(0.5, 1.0));
- }
- if (ll2.isEqualTo(AcGePoint2d(0.5, 0.0)) == false )
- {
- if (! pRightVTR->isWriteEnabled())
- pRightVTR->upgradeOpen();
- pRightVTR->setLowerLeftCorner
- (AcGePoint2d(0.5, 0.0));
- }
- if (ur2.isEqualTo(AcGePoint2d(1.0, 1.0)) == false )
- {
- if (! pRightVTR->isWriteEnabled())
- pRightVTR->upgradeOpen();
- pRightVTR->setUpperRightCorner
- (AcGePoint2d(1.0, 1.0));
- }
- // Получаем активный вид Пространства Модели
- struct resbuf res;
- acedGetVar(L"CVPORT" , &res);
- short vpnumber = res.resval.rint;
- // Определяем вид из/в который
- // установки будут скопированы.
- // Активный вид - это вид исз которого
- // будут копироваться установки
- AcDbViewportTableRecord *pFromVTR = NULL;
- AcDbViewportTableRecord *pToVTR = NULL;
- if (pLeftVTR->number() == vpnumber)
- {
- pFromVTR = pLeftVTR;
- pToVTR = pRightVTR;
- }
- if (pRightVTR->number() == vpnumber)
- {
- pFromVTR = pRightVTR;
- pToVTR = pLeftVTR;
- }
- // Увы, но мы не смогли идентифицировать
- // активный вид.
- if (pFromVTR == NULL || pToVTR == NULL)
- return ;
- // Копируем установки VTR из одного вида в другой
- // только если они различны. Установим допуск в достаточно
- // малое значение, чтобы не зациклится
- AcGeTol newTol;
- newTol.setEqualPoint (0.00001);
- newTol.setEqualVector(0.00001);
- // Направление взгляда
- AcGeVector3d fromViewDir = pFromVTR->viewDirection();
- AcGeVector3d toViewDir = pToVTR->viewDirection();
- if (pFromVTR->viewDirection().isEqualTo(
- pToVTR->viewDirection(), newTol) == false )
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setViewDirection(
- pFromVTR->viewDirection());
- updateNeeded = Adesk::kTrue;
- }
- // Поворот вида
- if (abs(pFromVTR->viewTwist()
- - pToVTR->viewTwist()) > 0.01)
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setViewTwist(pFromVTR->viewTwist());
- updateNeeded = Adesk::kTrue;
- }
- // Точка цели
- if (pFromVTR->target().isEqualTo(
- pToVTR->target(), newTol) == false )
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setTarget(pFromVTR->target());
- updateNeeded = Adesk::kTrue;
- }
- // Задняя подрезка
- if (pFromVTR->backClipEnabled()
- != pToVTR->backClipEnabled())
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setBackClipEnabled(
- pFromVTR->backClipEnabled());
- updateNeeded = Adesk::kTrue;
- }
- // Глубина задней плоскости
- if (abs(pFromVTR->backClipDistance()
- - pToVTR->backClipDistance()) > 0.01)
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setBackClipDistance(
- pFromVTR->backClipDistance());
- updateNeeded = Adesk::kTrue;
- }
- // Передняя подрезка
- if (pFromVTR->frontClipEnabled()
- != pToVTR->frontClipEnabled())
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setFrontClipEnabled(
- pFromVTR->frontClipEnabled());
- updateNeeded = Adesk::kTrue;
- }
- // Глубина передней плоскости
- if (abs(pFromVTR->frontClipDistance()
- - pToVTR->frontClipDistance()) > 0.01)
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setFrontClipDistance(
- pFromVTR->frontClipDistance());
- updateNeeded = Adesk::kTrue;
- }
- // Уровень
- if (abs(pFromVTR->elevation()
- - pToVTR->elevation()) > 0.01)
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setElevation(pFromVTR->elevation());
- updateNeeded = Adesk::kTrue;
- }
- // Точка центра
- if (pFromVTR->centerPoint().isEqualTo(
- pToVTR->centerPoint(), newTol) == false )
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setCenterPoint(pFromVTR->centerPoint());
- updateNeeded = Adesk::kTrue;
- }
- // Высота
- if (abs(pFromVTR->height() - pToVTR->height()) > 0.01)
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setHeight(pFromVTR->height());
- updateNeeded = Adesk::kTrue;
- }
- // Ширина
- if (abs(pFromVTR->width() - pToVTR->width()) > 0.01)
- {
- if (! pToVTR->isWriteEnabled())
- pToVTR->upgradeOpen();
- pToVTR->setWidth(pFromVTR->width());
- updateNeeded = Adesk::kTrue;
- }
- // Заканчиваем сVTR
- pLeftVTR->close();
- pRightVTR->close();
- delete pIter;
- }
- es = pVT->close();
- es = acDocManager->unlockDocument(pDoc);
- // Обновляем ВЭкраны если что-то поменяли
- if (updateNeeded)
- {
- acedVportTableRecords2Vports();
- }
- }
- // Оповещение об изменении вида не возникает
- // если PAN или ZOOM выполняется при помощи мыши.
- // Так что идентифицируем их при помощи WM сообщений в фильтре.
- BOOL WinCallBack(MSG *pMsg)
- {
- if ( pMsg->message == WM_VSCROLL ||
- pMsg->message == WM_HSCROLL ||
- pMsg->message == WM_MOUSEWHEEL ||
- pMsg->message == WM_MBUTTONUP)
- {
- // Синхронизуем ВЭкраны Пространства модели
- acDocManager->sendStringToExecute(
- acDocManager->mdiActiveDocument(),
- ACRX_T("SyncVTR " ),
- false , true , false );
- }
- return FALSE;
- }
- // Устанавливаем реакторы и фильтр сообщений
- virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt)
- {
- AcRx::AppRetCode retCode
- = AcRxArxApp::On_kInitAppMsg (pkt) ;
- // Реактор редактора для получения сообщений ViewChanged
- pEditorReactor = new AcMyEditorReactor(true );
- // Реактор InputContext для получения сообщения о входе
- // в состояние ожидание
- pInputContextReactor = new AcMyInputContextReactor();
- // Viewchanged реакция на действия мышью
- acedRegisterFilterWinMsg(WinCallBack);
- return (retCode);
- }
- // Чистим реакторы и фильтр сообщений
- virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt)
- {
- AcRx::AppRetCode retCode
- = AcRxArxApp::On_kUnloadAppMsg (pkt) ;
- // чистим
- if (pEditorReactor)
- {
- delete pEditorReactor;
- pEditorReactor = NULL;
- }
- if (pInputContextReactor)
- {
- delete pInputContextReactor;
- pInputContextReactor = NULL;
- }
- acedRemoveFilterWinMsg(WinCallBack);
- return (retCode);
- }
- // Переопределяем метод beginQuiescentState для запуска синхронизации
- void AcMyInputContextReactor::beginQuiescentState()
- {
- // Проверяем изменился ли вид
- if (_viewChanged)
- {
- // Синхронизация однократная, чтобы не зацикливаться
- _viewChanged = false ;
- // Запускаем команду синхнонизации
- acDocManager->sendStringToExecute(
- acDocManager->mdiActiveDocument(),
- ACRX_T("SyncVTR " ),
- false , true , false );
- }
- }
- // Переопределяем метод viewChanged чтобы узнать что вид изменился
- void AcMyEditorReactor::viewChanged()
- {
- AcMyInputContextReactor::_viewChanged = true ;
- }
Источник: 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