如何在 AutoCAD 2020 中从模型空间同步视口?

问题描述

问候专家社区,我正在尝试同步 AutoCAD 模型的两个窗口中的移动和缩放,即在两个不同的平面中打开 .dwg 分为两个窗口,一个活动的和另一个不活动的同步缩放(滚动 +或 -) 或从活动窗口到非活动窗口的移动 (PAN)(在 AutoCAD M3D 中具有两个开放平面的模型中 -> SYSWINDOWS :: tile Vertical),我正在研究,我发现此代码可以执行我想要的操作,但是只有一个平面,问题是我不能让它在 VS2019 c++ 中工作,我在带有“WinCallBack”的行中得到一个错误,表明 BOOL 不能成为一个常量,我提前感谢你的帮助。

#include "StdAfx.h"
#include "resource.h"

#pragma warning( disable : 4278 )

#include <windows.h>
#include <stdio.h>
#include "acedCmdNF.h"
#include "AcMyEditorReactor.h"
#include "AcMyInputContextReactor.h"

// Viewchanged notification is not received during a pan or zoom using mouse wheel.
// So identify those using WM messages.
BOOL WinCallBack(MSG *pMsg)
{
   if( pMsg->message == WM_VSCROLL      ||
       pMsg->message == WM_HSCROLL      ||
       pMsg->message == WM_MOUSEWHEEL   ||
       pMsg->message == WM_MBUTTONUP)
   {
       // Sync the modelspace viewports
       acDocManager->sendStringToExecute(acDocManager->mdiActiveDocument(),ACRX_T("SyncVTR "),false,true,false);
   }
   return FALSE;
}

class CMyTest1App : public AcRxArxApp
{
private:
   AcMyEditorReactor *pEditorReactor;
   AcMyInputContextReactor *pInputContextReactor;

public:

   CMyTest1App () : AcRxArxApp ()
   {
   }

   virtual AcRx::AppRetCode On_kInitAppMsg (void *pkt)
   {
       AcRx::AppRetCode retCode =AcRxArxApp::On_kInitAppMsg (pkt) ;

       // Editor reactor to receive to ViewChanged notification
       pEditorReactor = new AcMyEditorReactor(true);

       // InputContext reactor to receive quiescent state change notification
       pInputContextReactor = new AcMyInputContextReactor();

       // Viewchanged notification is not received during a pan or zoom using mouse wheel.
       // So identify those using WM messages.
       acedRegisterFilterWinMsg(WinCallBack);

       return (retCode);
   }

   virtual AcRx::AppRetCode On_kUnloadAppMsg (void *pkt)
   {
       AcRx::AppRetCode retCode =AcRxArxApp::On_kUnloadAppMsg (pkt) ;

       // cleanup
       if(pEditorReactor)
       {
           delete pEditorReactor;
           pEditorReactor = NULL;
       }

       if(pInputContextReactor)
       {
           delete pInputContextReactor;
           pInputContextReactor = NULL;
       }

       acedRemoveFilterWinMsg(WinCallBack);

       return (retCode);
   }

   virtual AcRx::AppRetCode On_kLoadDwgMsg (void *pkt)
   {
       AcRx::AppRetCode retCode =AcRxArxApp::On_kLoadDwgMsg (pkt) ;
       return (retCode) ;
   }
   
   virtual void RegisterServerComponents ()
   {
   }

   // Command to sync the model space viewport parameters
   static void AdskMyTestSyncVTR()
   {
       // Get the VTR updated
       acedVports2VportTableRecords();

       // We will update the other VTR only if view parameters change
       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);

       // This code at present can only deal with 2 Modelspace viewports split vertically in half
       if(pDb->tilemode() == Adesk::kFalse)
       {
           struct resbuf rb;
           if(ads_getvar(_T("cvport"),&rb) != RTnorM)
           {
               acutPrintf(_T("\nError using ads_getvar().\n"));
               return;
           }

           if(rb.resval.rint == 1)
           {
               return; // Can only work with model space viewports.
           }
       }

       AcDbViewportTable *pVT = NULL;
       pDb->getViewportTable(pVT,AcDb::kForRead);
   
       // Identify the left and right modelspace viewports
       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)))
                   {// Left modelspace viewport
                       pLeftVTR = pVTR;
                   }
                   else if(ur.isEqualTo(AcGePoint2d(1.0,1.0)))
                   {// Right modelspace viewport
                       pRightVTR = pVTR;
                   }
                   else
                       pVTR->close();
               }
           }

           // If for some reason,we did not have two modelspace viewports,// lets stop here.
           if(pLeftVTR == NULL)
           {
               if(pRightVTR != NULL)
                   pRightVTR->close();
               return;
           }
           if(pRightVTR == NULL)
           {
               if(pLeftVTR != NULL)
                   pLeftVTR->close();
               return;
           }

           // Ensure that the two viewports are split vertically in half.
           // If not,the view parameters when applied from one to another
           // may not apply directly using this code.
           // If the viewports were resized manually,set them right.
           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));
           }

           // Get the active model space viewport
           struct resbuf res;
           acedGetvar(L"CVPORT",&res);
           short vpnumber = res.resval.rint;

           // Identify the model space viewports  from/to which settings will be copied
           // The active modelspace viewport is the viewport from which settings will be copied
           AcDbViewportTableRecord *pFromVTR = NULL;
           AcDbViewportTableRecord *pToVTR = NULL;

           if(pLeftVTR->number() == vpnumber)
           {
               pFromVTR = pLeftVTR;
               pToVTR = pRightVTR;
           }
           if(pRightVTR->number() == vpnumber)
           {
               pFromVTR = pRightVTR;
               pToVTR = pLeftVTR;
           }

           // Sorry,we did not identify the active viewport
           // from which settings need to be copied.
           if(pFromVTR == NULL || pToVTR == NULL)
               return;

           // copy the VTR settings from one modelspace viewport to another
           // only if they are different. We will use a tolerance to ensure
           // very small differences do not get us in a soup. I meant loop :)

           AcGetol newTol;
           newTol.setEqualPoint (0.00001);
           newTol.setEqualVector(0.00001);

           // ViewDirection
           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;
           }

           // ViewTwist
           if(abs(pFromVTR->viewTwist() - pToVTR->viewTwist()) > 0.01)
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();

               pToVTR->setViewTwist(pFromVTR->viewTwist());
               updateNeeded = Adesk::kTrue;
           }

           // Target
           if(pFromVTR->target().isEqualTo(pToVTR->target(),newTol) == false)
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();

               pToVTR->setTarget(pFromVTR->target());
               updateNeeded = Adesk::kTrue;
           }

           // BackClipEnabled
           if(pFromVTR->backClipEnabled() != pToVTR->backClipEnabled())
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();
               pToVTR->setBackClipEnabled(pFromVTR->backClipEnabled());
               updateNeeded = Adesk::kTrue;
           }

           // BackClipdistance
           if(abs(pFromVTR->backClipdistance() - pToVTR->backClipdistance()) > 0.01)
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();

               pToVTR->setBackClipdistance(pFromVTR->backClipdistance());
               updateNeeded = Adesk::kTrue;
           }

           // FrontClipEnabled
           if(pFromVTR->frontClipEnabled() != pToVTR->frontClipEnabled())
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();
               pToVTR->setFrontClipEnabled(pFromVTR->frontClipEnabled());
               updateNeeded = Adesk::kTrue;
           }

           // FrontClipdistance
           if(abs(pFromVTR->frontClipdistance() - pToVTR->frontClipdistance()) > 0.01)
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();

               pToVTR->setFrontClipdistance(pFromVTR->frontClipdistance());
               updateNeeded = Adesk::kTrue;
           }

           // Elevation
           if(abs(pFromVTR->elevation() - pToVTR->elevation()) > 0.01)
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();

               pToVTR->setElevation(pFromVTR->elevation());
               updateNeeded = Adesk::kTrue;
           }

           // centerPoint
           if(pFromVTR->centerPoint().isEqualTo(pToVTR->centerPoint(),newTol) == false)
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();

               pToVTR->setCenterPoint(pFromVTR->centerPoint());
               updateNeeded = Adesk::kTrue;
           }

           // Height
           if(abs(pFromVTR->height() - pToVTR->height()) > 0.01)
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();

               pToVTR->setHeight(pFromVTR->height());
               updateNeeded = Adesk::kTrue;
           }

           // Width
           if(abs(pFromVTR->width() - pToVTR->width()) > 0.01)
           {
               if(! pToVTR->isWriteEnabled())
                   pToVTR->upgradeopen();

               pToVTR->setWidth(pFromVTR->width());
               updateNeeded = Adesk::kTrue;
           }

           // Done with the VTR
           pLeftVTR->close();
           pRightVTR->close();

           delete pIter;
       }
       es = pVT->close();

       es = acDocManager->unlockDocument(pDoc);

       // Update the Vports if we did change any of the VTR parameters
       if(updateNeeded)
       {
           acedVportTableRecords2Vports();
       }
   }
};

//-----------------------------------------------------------------------------
IMPLEMENT_ARX_ENTRYPOINT(CMyTest1App)

ACED_ARXCOMMAND_ENTRY_AUTO(CMyTest1App,AdskMyTest,SyncVTR,ACRX_CMD_MODAL,NULL)

https://adndevblog.typepad.com/autocad/2014/07/synchronizing-model-space-viewports.html

解决方法

我找到了两个解决问题的应用,DWGsync(在 2021 年之前免费且兼容)https://apps.autodesk.com/ACD/es/Detail/Index?id=2788892389049910944&appLang=en&os=Win32_64 和 Drawing Sync(已获得许可且兼容的 autocad 2018)https://apps.autodesk.com/ACD/en/Detail/Index?id=2152736212918385179&appLang=en&os=Win32_64