XCLIP xrefs using ObjectARX
By Xiaodong Liang
The AcDbSpatialFilter class was designed to do this. This class is used to define a spatial filter that AutoCAD uses to define the clip volume of the block reference to the xref in the host drawing.
AutoCAD uses this spatial filter to decide what object IDs will be processed during regen.
The sample below is a small demo. Note: the commands needs to be defined with the options ACRX_CMD_NOINTERNALLOCK:
static void YTMYJCMDMyClip(void) { // Add your code for command YTMYJCMD.MyClip here ads_point pt1,pt2; ads_name ent; if (acedEntSel(_T("Select xref:"),ent,pt1)!=RTNORM) return; AcDbObjectId idXref; if (acdbGetObjectId(idXref,ent)!=Acad::eOk) return; AcDbObjectPointer<AcDbBlockReference> pRef(idXref,AcDb::kForRead); if (pRef.openStatus()!=Acad::eOk) { acutPrintf(_T("Not an xref!\n")); return; } AcGePoint2dArray pts; if (acedGetPoint(NULL,_T("First point:"),pt1)!=RTNORM) return; //the ECS of the vertices must be defined in the //coordinate system of the _block_ so let's calculate //transform all points to that coordinate system AcGeMatrix3d mat(pRef->blockTransform()); mat.invert(); AcGePoint3d pt3d(asPnt3d(pt1)); pt3d.transformBy(mat); pts.append(AcGePoint2d(pt3d.x,pt3d.y)); while (acedGetPoint(pt1,_T("Next point:"),pt2)==RTNORM) { acedGrDraw(pt1,pt2,1,1); pt3d = asPnt3d(pt2); pt3d.transformBy(mat); pts.append(AcGePoint2d(pt3d.x,pt3d.y)); memcpy(pt1,pt2,sizeof(ads_point)); } acedRedraw(NULL,0); AcDbDatabase* pDb = acdbHostApplicationServices()->workingDatabase(); AcGeVector3d normal; double elev; if (pDb->tilemode()) { normal = pDb->ucsxdir().crossProduct(pDb->ucsydir()); elev = pDb->elevation(); } else { normal = pDb->pucsxdir().crossProduct(pDb->pucsydir()); elev = pDb->pelevation(); } normal.normalize(); Acad::ErrorStatus es = pRef.object()->upgradeOpen(); if (es !=Acad::eOk) return; //create the filter AcDbSpatialFilter* pFilter = new AcDbSpatialFilter; if (pFilter->setDefinition(pts,normal,elev, ACDB_INFINITE_XCLIP_DEPTH,-ACDB_INFINITE_XCLIP_DEPTH,true)!=Acad::eOk) { delete pFilter; return; } //add it to the extension dictionary of the block reference //the AcDbIndexFilterManger class provides convenient utility functions if (AcDbIndexFilterManager::addFilter(pRef.object(),pFilter)!=Acad::eOk) delete pFilter; else { acutPrintf(_T("Filter has been succesfully added!\n")); pFilter->close(); } }
An Xref that is clipped has entries like this:
(102 . "{ACAD_XDICTIONARY")
(360 . <Entity name: 7ed01cd0>)
(102 . "}")
in its (entget) entity data, which an Xref that is not clipped does not have.
一个有切分的图块,其属性中有上述的组码
(defun c:test () (vl-load-com) (if (and (setq a (vlax-ename->vla-object (car (entsel)))) (eq (vla-get-objectname a) "AcDbBlockReference") (eq (vla-get-HasExtensionDictionary a) :vlax-true)) (vlax-for itm (vlax-invoke a 'GetExtensionDictionary) (if ( = (vla-get-name itm) "ACAD_FILTER") (vlax-for itm_ itm (if (eq (vla-get-objectname itm_) "AcDbSpatialFilter") (princ "\nObject is Clipped: ") ) ) ) )(princ "\nObject is Not Clipped: ") )(princ) )
I'm pretty sure there's an easier way than this :
XDATA perhaps
or:
(defun c:test (/ b) (cond ((and (setq b (car (entsel))) (eq (cdr (assoc 0 (setq b (entget b)))) "INSERT") (if (assoc 360 b) (princ "\nObject is Clipped: ") (princ "\nObject is Not Clipped: ") ) ) ) ) (princ) )
Here is another function to return the XClip Boundary of an Insert - will return nil if the Block/XRef is not Clipped.
;; XClip Boundary - Lee Mac ;; Returns the XClip Boundary (if present) defined relative to the Block Definition ;; of the supplied Insert entity. (defun LM:XClipBoundary ( ename / xdict ) (if (setq xdict (cdr (assoc 360 (entget ename)))) (LM:XClipBoundary xdict) (if (and (eq "SPATIAL_FILTER" (cdr (assoc 0 (setq ename (entget ename))))) (eq 1 (cdr (assoc 71 ename))) ) ( (lambda ( massoc ) (massoc 10 ename)) (lambda ( key elist / item ) (if (setq item (assoc key elist)) (cons (cdr item) (massoc key (cdr (member item elist)))) ) ) ) ) ) )
It could be used with a calling function in the following way:
(defun c:test ( / ent ) (if (and (setq ent (car (entsel "\nSelect Block/XRef: "))) (eq "INSERT" (cdr (assoc 0 (entget ent)))) ) (if (LM:XClipBoundary ent) (princ "\nSelected Block/XRef is Clipped.") (princ "\nSelected Block/XRef is not Clipped.") ) ) (princ) )
文章评论