I’ve now checked in for my flight to Las Vegas – and, thanks to Jeremy Tammik’s recent troubles, I luckily renewed my ESTA – so I’m pretty much all set for my trip to AU 2010, at least from a travel perspective. I’m just keeping my fingers crossed that the gastric 'flu my kids seem to have come down with doesn’t hit me before I leave (or once I’m at AU… what a grim thought).
I was going to keep today’s post light, just like the last one, but then decided to dip into my email folder of externally contributed posts. This little nugget from Jamie Robertson shows how to add a simple 2D spatial filter to an external reference, effectively duplicating the XCLIP command (although this basic sample doesn’t handle non-World UCSs, block rotation/scaling, etc.).
At some point I may look at implementing a more complete version of this command, but even as it stands I have no doubt it’ll be of use to many of you. Many thanks for contributing this code, Jamie!
Here’s the C# code, with minor modifications to fit this blog:
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices.Filters;
using Autodesk.AutoCAD.Runtime;
using System;
namespace SpatialFiltering
{
public class ClipBlock
{
const string filterDictName = "ACAD_FILTER";
const string spatialName = "SPATIAL";
[CommandMethod("2DXCLIP")]
public static void clipBlockTest()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Database db = doc.Database;
Editor ed = doc.Editor;
// Select a block to clip
PromptEntityOptions peo =
new PromptEntityOptions(
"\nSelect a block reference to clip:"
);
peo.AllowNone = false;
peo.SetRejectMessage("\nNot a block reference.");
peo.AddAllowedClass(typeof(BlockReference), false);
PromptEntityResult per = ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return;
// Select rectangle to clip
PromptPointOptions ppo =
new PromptPointOptions(
"\nSelect first clip corner: "
);
ppo.AllowNone = false;
PromptPointResult ppr = ed.GetPoint(ppo);
if (ppr.Status != PromptStatus.OK)
return;
Point3d pt1 = ppr.Value;
PromptCornerOptions pco =
new PromptCornerOptions(
"\nSelect second clip corner: ", pt1
);
ppr = ed.GetCorner(pco);
if (ppr.Status != PromptStatus.OK)
return;
Point3d pt2 = ppr.Value;
Transaction tr = db.TransactionManager.StartTransaction();
using (tr)
{
// Transform and re-order points
BlockReference br =
(BlockReference)tr.GetObject(
per.ObjectId, OpenMode.ForRead
);
pt1 = pt1.TransformBy(br.BlockTransform.Inverse());
pt2 = pt2.TransformBy(br.BlockTransform.Inverse());
Point2d rectMin =
new Point2d(
Math.Min(pt1.X, pt2.X),
Math.Min(pt1.Y, pt2.Y)
);
Point2d rectMax =
new Point2d(
Math.Max(pt1.X, pt2.X),
Math.Max(pt1.Y, pt2.Y)
);
Point2dCollection pts =
new Point2dCollection(2){ rectMin, rectMax };
// Create spatial filter
// Just zeroes for the elevation and clip depths
SpatialFilterDefinition sfd =
new SpatialFilterDefinition(
pts, Vector3d.ZAxis, 0.0, 0.0, 0.0, true
);
SpatialFilter sf = new SpatialFilter();
sf.Definition = sfd;
// Create extension dictionary if doesn't exist
if (br.ExtensionDictionary == ObjectId.Null)
{
br.UpgradeOpen();
br.CreateExtensionDictionary();
br.DowngradeOpen();
}
// Add spatial filter to extension dictionary
DBDictionary xDict =
(DBDictionary)tr.GetObject(
br.ExtensionDictionary, OpenMode.ForWrite
);
if (xDict.Contains(filterDictName))
{
DBDictionary fDict =
(DBDictionary)tr.GetObject(
xDict.GetAt(filterDictName), OpenMode.ForWrite
);
if (fDict.Contains(spatialName))
fDict.Remove(spatialName);
fDict.SetAt(spatialName, sf);
}
else
{
DBDictionary fDict = new DBDictionary();
xDict.SetAt(filterDictName, fDict);
tr.AddNewlyCreatedDBObject(fDict, true);
fDict.SetAt(spatialName, sf);
}
tr.AddNewlyCreatedDBObject(sf, true);
tr.Commit();
}
ed.Regen();
}
}
}
Here’s an xrefed drawing – the venerable HVAC Architectural sample drawing, no less:
And here’s the effect of running the 2DXCLIP command, selecting the Xref (the grey geometry) and a window to which to clip:
That’s it until AU – I’m looking forward to catching up with many of you in Las Vegas! :-)