How to Get Viewport Bounds in AutoCAD Model Space

<?xml encoding=”UTF-8″>By Madhukar Moogala

When working with viewports in AutoCAD, particularly when translating between paper space and model space, it is
often necessary to determine the viewport boundaries within the model space. This blog post will guide you through
obtaining viewport extents and transforming them appropriately.

Understanding the Viewport Transformation

AutoCAD viewports in paper space define a window into model space. To retrieve the viewport bounds in model space,
we need to apply a transformation matrix that accounts for scaling, rotation, and translation.

Key Steps:

  1. Retrieve viewport properties – Extract viewport size, center, and transformation
    parameters.
  2. Compute transformation matrix – Convert from Paper Space Display Coordinate System
    (PSDCS) to the World Coordinate System (WCS).
  3. Transform viewport extents – Apply the matrix to get accurate model space boundaries.

  4. Create a bounding polyline – Draw a rectangle representing the viewport bounds.

Implementation

Below is the C++ implementation using ObjectARX APIs to extract the viewport bounds in model space.

Setting Viewport Properties

    
static void SetViewportProperties(AcDbViewport* pVp,
AcDbViewTableRecord& vwRec)
{
vwRec.setHeight(pVp->height());
vwRec.setWidth(pVp->width());
vwRec.setCenterPoint(AcGePoint2d(pVp->centerPoint().x,
pVp->centerPoint().y));
vwRec.setViewDirection(pVp->viewDirection());
vwRec.setTarget(pVp->viewTarget());
vwRec.setLensLength(pVp->lensLength());
vwRec.setViewTwist(pVp->twistAngle());
vwRec.setFrontClipDistance(pVp->frontClipDistance());
vwRec.setBackClipDistance(pVp->backClipDistance());
vwRec.setPerspectiveEnabled(pVp->isPerspectiveOn());
vwRec.setFrontClipEnabled(pVp->isFrontClipOn());
vwRec.setBackClipEnabled(pVp->isBackClipOn());
vwRec.setFrontClipAtEye(pVp->isFrontClipAtEyeOn());
vwRec.setViewAssociatedToViewport(pVp->isUcsSavedWithViewport());
vwRec.setVisualStyle(pVp->visualStyleId());
vwRec.setIsPaperspaceView(true);
}

Computing the Transformation Matrix

    
static AcGeMatrix3d GetTransformationMatrix(AcDbViewport* pVpPtr) {
if (!pVpPtr) return AcGeMatrix3d::kIdentity;
// Extract viewport properties
AcGePoint3d viewCenterPSDCS(pVpPtr->viewCenter().x, pVpPtr->viewCenter().y, 0.0);
AcGePoint3d viewCenterDCS = pVpPtr->centerPoint();
double scale = 1.0 / pVpPtr->customScale();
// Transform from PSDCS to DCS
AcGeMatrix3d transformPSDCSToDCS = AcGeMatrix3d::scaling(scale, viewCenterDCS) *
AcGeMatrix3d::translation(viewCenterDCS - viewCenterPSDCS);
// Retrieve view properties
AcDbViewTableRecord vwRec;
SetViewportProperties(pVpPtr, vwRec);
AcGeVector3d targetDirection = vwRec.target() - AcGePoint3d::kOrigin;
AcGeMatrix3d translation = AcGeMatrix3d::translation(targetDirection);
double twistAngle = vwRec.viewTwist();
AcGeVector3d viewDirection = vwRec.viewDirection();
AcGePoint3d pointOfRotation = vwRec.target();
AcGeMatrix3d rotation = AcGeMatrix3d::rotation(-twistAngle,
viewDirection,
pointOfRotation);
// Transform from DCS to WCS
AcGeMatrix3d transformDCSToWCS = AcGeMatrix3d::planeToWorld(viewDirection)
* translation
* rotation;
return transformDCSToWCS * transformPSDCSToDCS;
}

Retrieving Viewport Bounds in Model Space

Once we have the transformation matrix, we can apply it to the viewport extents to get the bounds in model space.

    
static AcDbExtents GetViewportBoundsInMS(AcDbViewport* pVp) {
AcGeMatrix3d xform = GetTransformationMatrix(pVp);
AcDbExtents vpExtents;
pVp->getGeomExtents(vpExtents);
AcGePoint3d minPt = vpExtents.minPoint();
AcGePoint3d maxPt = vpExtents.maxPoint();
vpExtents.transformBy(xform);
return vpExtents;
}

Test Method

Finally, we can create a test method or run through a Command to execute the above functions and visualize the
viewport bounds.

    
void runGetVpBoundsInMS() {
auto workingDb = acdbHostApplicationServices()->workingDatabase();
if (workingDb->tilemode() == Adesk::kTrue) {
acutPrintf(_T("nTilemode is on! Execute in PAPERSPACE"));
return;
}
AcDbObjectPointer <AcDbViewport> pViewportPtr(workingDb->paperSpaceVportId(),
AcDb::kForRead);
if (!eOkVerify(pViewportPtr.openStatus())) return;
AcDbObjectPointer <AcDbLayout> pLayoutPtr(workingDb->currentLayoutId(), AcDb::kForRead);
if (!eOkVerify(pLayoutPtr.openStatus())) return;
AcDbObjectIdArray vpIds = pLayoutPtr->getViewportArray();
if (vpIds.length() < 2) {
acutPrintf(_T("nNo viewports found in paperspace"));
return;
}
AcDbObjectPointer <AcDbViewport> pVpPtr(vpIds[1], AcDb::kForRead);
if (!eOkVerify(pVpPtr.openStatus())) return;
AcDbExtents vpExtents = GetViewportBoundsInMS(pVpPtr.object());
AcGePoint3d minPt = vpExtents.minPoint();
AcGePoint3d maxPt = vpExtents.maxPoint();
AcDbPolyline* pPoly = new AcDbPolyline(4);
pPoly->addVertexAt(0, AcGePoint2d(minPt.x, minPt.y));
pPoly->addVertexAt(1, AcGePoint2d(maxPt.x, minPt.y));
pPoly->addVertexAt(2, AcGePoint2d(maxPt.x, maxPt.y));
pPoly->addVertexAt(3, AcGePoint2d(minPt.x, maxPt.y));
pPoly->setClosed(true);
pPoly->setColorIndex(3);
addToDb(pPoly, workingDb);
}

Here is video


Comments

2 responses to “How to Get Viewport Bounds in AutoCAD Model Space”

  1. Great news.

  2. I copied and pasted the code, but it does not work
    I changed workingDb->currentLayoutId() to

    static AcDbObjectId getCurrentLayoutId(AcDbDatabase* pDb)
    {
    auto man = acdbHostApplicationServices()->layoutManager();
    AcString name;
    AcDbObjectId entryId;
    man->getActiveLayoutName(name, true);
    AcDbDictionaryPointer pDict(pDb->layoutDictionaryId());
    pDict->getAt(name, entryId);
    return entryId;
    }
    

    But the transformation is way off

Leave a Reply to DanCancel reply

Discover more from Autodesk Developer Blog

Subscribe now to keep reading and get access to the full archive.

Continue reading