Lets say you want to control the loading and unloading of the Raster images when the user is zooming or panning. The Images should load or unload on two factors:
1) The zoom scale.
2) The Image is in visible area or not.
This can be achieved by adding an editor reactor that checks for the command “ZOOM” and “PAN”. If the user has invoked either of the command then do the following:
1) Scan for all the Raster Images in the drawing.
2) Check if a Raster Image is fully, partially or non visible in the current view.
3) If the Raster Image is fully or partially visible, check for ratio (Image diagonal /View diagonal). If this ratio lies with in the specified limit, then load the Image otherwise unload it. Also unload the image if it does not lie in the current view.
To check for visibility of the Raster Image in the current view:
1) Build a transformation matrix for the DCS coordinate system.
2) Get the view centre using VIEWCTR sysvar. This lies in the current UCS. Project the point onto the DCS XY plane.
3) Get the view height using VIEWSIZE and calculate the view width using the window aspect ratio "SCREENSIZE".
4) Calculate the extents in DCS XY plane using view centre and height/width.
5) To check if an entity lies fully in the current view, get the bounding box of the entity and project the maximum and minimum points of the extents onto DCS XY plane. Check if the projected points lie fully in the bounding box defined by DCS extents. If they do the entity is fully visible in the current view else check if the DCS extents lies fully in the entities extents bounding box. If yes then it means that the image fully covers the current view. If not, go to next step.
6) Create a polyline that forms rectangle with DCS extents as the corners. Test for the intersection of the polyline and the projected entity in DCS XY plane. If they intersect, the entity is partially visible. If not then the entity is not visible at all.
There are two major functions in the code provided below. First one is fCheckEntitiesInDispArea(). This function takes an object ID array as in parameter. It checks for visibility of the entities specified in the array and populates three object ID arrays and they contain entities that are fully visible, partially visible and not visible at all, respectively. The second function is fTest(), which actually iterates the AcDbRasterImage entities in the model space and then tests for the visibility, checks for the diagonal size of the image and loads or unloads depending on the size.
The snippets provided below has the complete code to do all the above. In the code, I defines a command "test" and also implements an editor reactor that reacts to "ZOOM" and “PAN" command. The program essentially unloads any the raster image which is smaller than 1/5 size and bigger than 10 times the size of the current view and also if they are not lying in the current view. The command “setratio” allows the user to change the minimum and maximum Image/View diagonal ratio.
Finally, this blog post will be useful in case you need to react to Real-time Zoom also:
/////////////////////////////////////////////////////////////////////////// //global variable to hold the max and minimum valid size for the raster double gnMaxSize = 10.0; //Raster should not ten times the screen size double gnMinSize = 0.20; //Raster should not less than 1/5th of screen size /////////////////////////////////////////////////////////////////////////// //globals //editor reactor AsdkEdReactor *pEdReact = NULL; //======================================================== //======================================================== void fTest() { Acad::ErrorStatus mEs; AcDbBlockTable *pBT; AcDbBlockTableRecord *pBTR; AcDbBlockTableRecordIterator *pBTIter; acdbHostApplicationServices()->workingDatabase()-> getBlockTable(pBT,AcDb::kForRead); pBT->getAt(ACDB_MODEL_SPACE,pBTR,AcDb::kForRead); pBTR->newIterator(pBTIter); pBT->close(); pBTR->close(); //array to hold the entities AcDbObjectIdArray aNoDispEntArray; AcDbObjectIdArray mFullDispEntArray; AcDbObjectIdArray mPartialDispArray; AcDbEntity *pEnt; AcDbRasterImage *pRastImg; //populate the aNoDispEntArray with all //entites that are RasterImage while (!(pBTIter->done())) { pBTIter->getEntity(pEnt,AcDb::kForRead); pRastImg = AcDbRasterImage::cast(pEnt); if(NULL != pRastImg) { aNoDispEntArray.append(pRastImg->objectId()); } pEnt->close(); pBTIter->step(); } //check for display of entities in the current view fCheckEntitiesInDispArea(aNoDispEntArray, mFullDispEntArray,mPartialDispArray); acutPrintf( _T("nNo of Images not lying in the current View : %d"), aNoDispEntArray.length()); acutPrintf( _T("nNo of Images lying fully in the current View : %d"), mFullDispEntArray.length()); acutPrintf( _T("nNo of Images lying partially in the curre
nt View : %d"), mPartialDispArray.length()); //unload the images depending on their visibility long mCtr; //number of entities AcDbRasterImageDef *pImgDef; for(mCtr = 0;mCtr < aNoDispEntArray.length();mCtr++) { mEs = acdbOpenObject(pRastImg, aNoDispEntArray.at(mCtr),AcDb::kForRead); if(Acad::eOk == acdbOpenObject(pImgDef, pRastImg->imageDefId(),AcDb::kForRead)) { if(Adesk::kTrue == pImgDef->isLoaded()) { pImgDef->upgradeOpen(); pImgDef->unload(); } pImgDef->close(); } pRastImg->close(); } //load or unload depending upon the VIEWSIZE //for fully visible or partially visible entities //get the view center struct resbuf rs; double nHeight; double nWidth; double nScreenDiag; //get the view height acedGetVar(_T("VIEWSIZE"),&rs); nHeight = rs.resval.rreal; //get the screen size acedGetVar(_T("SCREENSIZE"),&rs); nWidth = nHeight*(rs.resval.rpoint[0] / rs.resval.rpoint[1]); //get the dialgonal length nScreenDiag = sqrt(pow(nHeight,2) + pow(nWidth,2)); //append the full display entities //with the partial displayed entities //as we want similar behaviuor for both for(mCtr = 0;mCtr < mPartialDispArray.length();mCtr++) { mFullDispEntArray.append(mPartialDispArray.at(mCtr)); } //hold Object ID from the array AcDbObjectId aObjID; double nDiagRatio; for(mCtr = 0;mCtr < mFullDispEntArray.length();mCtr++) { AcDbExtents mImgExts; //try opening the object for read if(Acad::eOk != acdbOpenObject(pRastImg, mFullDispEntArray.at(mCtr),AcDb::kForRead)) continue; aObjID = pRastImg->imageDefId(); pRastImg->getGeomExtents(mImgExts); pRastImg->close(); //open the image definition if(Acad::eOk
!= acdbOpenObject(pImgDef,aObjID, AcDb::kForRead)) continue; //the ratio is equal to raster size/screen size nDiagRatio = (mImgExts.maxPoint(). distanceTo(mImgExts.minPoint())/nScreenDiag); //print the values on screen //char buf[255];//wb ACHAR buf[255]; aObjID.handle().getIntoAsciiBuffer(buf); acutPrintf(_T("nImage handle: %s , Diagonal Ratio: %f"), buf,nDiagRatio); // //if the Image diagonal is less than //gnMinSize or greater gnMaxSize, then unload if((nDiagRatio >= gnMinSize) && (nDiagRatio isLoaded()) { pImgDef->upgradeOpen(); pImgDef->load(); //image is sufficently zoomed } } else { if(Adesk::kTrue == pImgDef->isLoaded()) { pImgDef->upgradeOpen(); //image is too small or too large to display pImgDef->unload(); } } pImgDef->close(); } //clean up delete pBTIter; } //////////////////////////////////////////////////////////////// //Description: fCheckEntitiesInDispArea //////////////////////////////////////////////////////////////// void fCheckEntitiesInDispArea(AcDbObjectIdArray &aNoDispEntArray, AcDbObjectIdArray &aFullDispEntArray, AcDbObjectIdArray &aPartDispEntArray) { //get the display properties CDcsProp mDcsPty; //create a pline to check for the interference AcDbPolyline *paPline = new AcDbPolyline(4); fGetDCSBoundary(&mDcsPty,paPline); long mCtr; //number of entitie AcDbObjectId aObjID; AcDbObjectIdArray mTempEntArray; for(mCtr = 0;mCtr < aNoDispEntArray.length();mCtr++) { aObjID = aNoDispEntArray.at(mCtr); //check if entity lies completely in the current display area if(Adesk::kTrue== fLiesCompleteyInView(aObjID,mDcsPty)) { aFullDispEntArray.append(aObjID); } else 
60; { //check if it lies partially if(Adesk::kTrue== fLiesPartiallyInView(aObjID, paPline,mDcsPty)) { aPartDispEntArray.append(aObjID); } else { //completely out of display mTempEntArray.append(aObjID); } } } aNoDispEntArray = mTempEntArray; //clean up delete paPline; } ////////////////////////////////////////////////////////////// //Description: fGetDCSBoundary ////////////////////////////////////////////////////////////// void fGetDCSBoundary(CDcsProp *paDcsPty,AcDbPolyline *paPline) { AcGeMatrix3d mMatDCS2WCS; AcGePoint3d mPtMax; AcGePoint3d mPtMin; //returns DCS2WCS matrix and the extents in DCS coords fGetViewCornersInDcs(mMatDCS2WCS,mPtMax,mPtMin); //get the projection plane AcGePlane pPlnDCSXY = fGetXYPlane(mMatDCS2WCS); //create a box paPline->addVertexAt(0,AcGePoint2d(mPtMin.x,mPtMin.y)); paPline->addVertexAt(1,AcGePoint2d(mPtMax.x,mPtMin.y)); paPline->addVertexAt(2,AcGePoint2d(mPtMax.x,mPtMax.y)); paPline->addVertexAt(3,AcGePoint2d(mPtMin.x,mPtMax.y)); paPline->setClosed(Adesk::kTrue); paPline->transformBy(mMatDCS2WCS); //add the pline to MS //fAddToMS((AcDbEntity *)pPolyline); //prepare the DCS poperties paDcsPty->m_matMatrix = mMatDCS2WCS; paDcsPty->fCalculate(); paDcsPty->m_maxPt = mPtMax; paDcsPty->m_minPt = mPtMin; } ////////////////////////////////////////////////////////////// //Description: fLiesPartiallyInView ////////////////////////////////////////////////////////////// Adesk::Boolean fLiesPartiallyInView(AcDbObjectId aObjID, AcDbPolyline *paPline,const CDcsProp aDcsPty) { //area, so check if lies partially AcGePoint3dArray mInterPoints; AcDbEntity *pEnt; //try opening the object for read if(Acad::eOk != acdbOpenObject(pEnt,aObjID, AcDb::kForRead)) return Adesk::kFalse; //check for intersection paPline->intersectWith(pEnt,AcDb::kOnBothOperands, aDcsPty.m_PlnXY ,mInterPoints); //close the entity pEnt->close(); //how many points are intersecting? if (0 != mInterPoints.length()) return Adesk::kTrue; //intersects else return Adesk::kFalse; //does not intersect } ///////////////////////////////////////////////////////// //Description: fLiesCompleteyInView ///////////////////////////////////////////////////////// Adesk::Boolean fLiesCompleteyInView(AcDbObjectId aObjID, const CDcsProp aDcsPty) { AcDbEntity *pEnt; //try opening the object for read if(Acad::eOk != acdbOpenObject( pEnt,aObjID,AcDb::kForRead)) return Adesk::kFalse; //check if the entity lies in the display area completely AcDbExtents mEntExts; pEnt->getGeomExtents(mEntExts); //close the entity pEnt->close(); AcGePoint3d mPtExtMax; AcGePoint3d mPtExtMin; mPtExtMax = mEntExts.maxPoint(); mPtExtMin = mEntExts.minPoint(); mPtExtMax = mPtExtMax.project(aDcsPty.m_PlnXY, aDcsPty.m_PlnXY.normal()); mPtExtMin = mPtExtMin.project(aDcsPty.m_PlnXY, aDcsPty.m_PlnXY.normal()); //transform the extents mPtExtMax.transformBy(aDcsPty.m_matMatrix.inverse()); mPtExtMin.transformBy(aDcsPty.m_matMatrix.inverse()); //lies in the display area if((aDcsPty.m_minPt.x

Leave a Reply