The code used as the basis for this post was from a recent response sent out by Philippe Leefsma, from our European DevTech team. Thanks, Philippe!
It's very common to want to manipulate an entity programmatically in AutoCAD, and often the best way to do so is to "transform" it. The technique is very straightforward: you create a transformation matrix using the static members of the Matrix3d class (Displacement(), Rotation(), Scaling(), Mirroring(), or the possibly less commonly needed AlignCoordinateSystem(), Projection(), PlaneToWorld() and WorldToPlane()), you make sure your entity is open for write, and then simply pass the matrix into the entity's TransformBy() method.
And that's really all there is to it. The below code demonstrates a very simplistic usage of TransformBy(): we want to make a mirrored copy of an entity. We use the Clone() method to generate a "shallow" copy of the original entity - which means that you may have less success with more complex entities that require "deep" cloning - and we then apply a mirror transformation to the clone (having asked the user to specify the mirror line). Please don't take this as a definitive approach to mirroring - there are probably lots of cases that it doesn't handle, in fact I've just seen a follow-up response from Philippe covering the case of mirroring text, which I'll no doubt steal for a future post :-) - but this should give an overall indication of how to use matrices to transform entities.
Here's the C# code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
namespace EntityTransformation
{
public class Commands
{
[CommandMethod("MENT")]
static public void MirrorEntity()
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Editor ed = doc.Editor;
// Prompt for the entity to mirror
PromptEntityOptions peo =
new PromptEntityOptions(
"\nSelect an entity:"
);
PromptEntityResult per =
ed.GetEntity(peo);
if (per.Status != PromptStatus.OK)
return;
// Get the points defining the mirror line
PromptPointOptions ppo =
new PromptPointOptions(
"\nSelect first point of mirror line:"
);
PromptPointResult ppr =
ed.GetPoint(ppo);
if (ppr.Status != PromptStatus.OK)
return;
Point3d pt1 = ppr.Value;
ppo.BasePoint = pt1;
ppo.UseBasePoint = true;
ppo.Message =
"\nSelect second point of mirror line:";
ppr = ed.GetPoint(ppo);
if (ppr.Status != PromptStatus.OK)
return;
Point3d pt2 = ppr.Value;
// Create the mirror line and the transformation matrix
Line3d ml =
new Line3d(pt1, pt2);
MirrorEntity(doc.Database, per.ObjectId, ml, false);
}
// Helper function to mirror an entity
private static void MirrorEntity(
Database db,
ObjectId id,
Line3d line,
bool erase
)
{
Document doc =
Application.DocumentManager.MdiActiveDocument;
Matrix3d mm =
Matrix3d.Mirroring(line);
Transaction tr =
db.TransactionManager.StartTransaction();
using (tr)
{
// Get the entity to mirror
Entity ent =
tr.GetObject(
id,
OpenMode.ForRead
) as Entity;
// Clone it
Entity me = ent.Clone() as Entity;
// Apply the mirror transformation
me.TransformBy(mm);
// Add mirrored entity to the database
BlockTable bt =
(BlockTable)tr.GetObject(
db.BlockTableId,
OpenMode.ForRead
);
BlockTableRecord btr =
(BlockTableRecord)tr.GetObject(
bt[BlockTableRecord.ModelSpace],
OpenMode.ForWrite
);
btr.AppendEntity(me);
tr.AddNewlyCreatedDBObject(me, true);
if (erase)
{
// Finally erase the original entity (if needed)
ent.UpgradeOpen();
ent.Erase();
}
tr.Commit();
}
}
}
}