切分图块 XCLIP xrefs using ObjectARX

作者: admin 分类: C++,CAD,ObjectARX 发布时间: 2020-10-13 15:02

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();
}
}

图块切分.png

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)
)

如果觉得我的文章对您有用,请随意赞赏。您的支持将鼓励我继续创作!

发表评论

标签云