1

Greetings Community of experts, I am trying to synchronize the movement and zoom in two windows of AutoCAD models, that is, in two different planes open .dwg divided into two windows one active and the other inactive synchronize the zoom (scroll + or -) or the movement (PAN) from the active window to the inactive one (In model with two open planes in AutoCAD M3D -> SYSWINDOWS :: tile Vertical), I was researching and I found this code that does what I want but only with one plane, the problem is that I can not make it work in VS2019 c ++, I get an error in the lines with "WinCallBack" indicating that BOOL cannot become a constant, I appreciate your help in advance.

#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

1 Answers1

0

I found two apps that solve the question in question, DWGsync (free and compatible until 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