如何在 AutoCAD 2020 中同步来自模型 space 的视口?

How to sync viewports from model space in AutoCAD 2020?

问候各位专家,我正在尝试在两个windows AutoCAD 模型中同步移动和缩放,即在两个不同的平面打开.dwg 一分为二windows 一活动和另一个非活动同步缩放(滚动 + 或 -)或从活动 window 到非活动一个的移动(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, SyncVTR, ACRX_CMD_MODAL, NULL)

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

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