Mirroring AutoCAD entities using .NET

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

      }

    }

  }

}

14 responses to “Mirroring AutoCAD entities using .NET”

  1. Hi Kean,

    I created something similar using your example above. I am iterating thru all entities in a database then mirroring them. I there a way to not have the text itself mirror. I set mirrtext property to 0 but it still mirrors the text itself.

    Thanks,

    Ed

  2. Kean Walmsley Avatar

    Hi Ed,

    When you open each entity you will need to check whether it's a DBText or MText you're dealing with (depending on what you care about), and then choose whether or not to mirror it.

    You might want to check the IsMirroredInX and/or IsMirroredInY properties on the DBText class, to help with this decision.

    Regards,

    Kean

  3. Mohammad Afghari Avatar

    Hi Kean,
    It seems that there is an annoying bug to mirroring entities by this method,
    1- draw a closed polyline and mirror it by this method.
    2- type pe in command line to edit polyline select mirrored poly and type E, by default autocad should show a X shape on each vertex by pressing enter but X icon is not correctly on polyline vertex! am I right?
    Why? and what is the solution?
    (tested it in Autocad 2010 using VS2008)

  4. Hi Mohammed,

    I don't have time to investigate this issue (and I don't believe it's specific to my code, although it's possible it might be).

    Please post the issue via standard channels (whether to the ADN team or the AutoCAD .NET Discussion Group).

    Kean

  5. Hello Kean!
    This has been a very useful post for me as a new AutoCAD developer taking over projects from other devs.
    That being said, did you ever write that post regarding mirroring text?

    That's my big hangup at the moment.

    Thanks for the helpful posts

    Fredrik

  6. Hello Fredrik,

    Strange - I was sure I'd responded to this, but it seems the comment didn't go through.

    I was saying that I'd ask Philippe if he'd found time to put something together (and I made some quip about it only being 5 years since I published the post, and that it might take some more time... ;-).

    Anyway, Philippe responded very quickly by posting this over on the AutoCAD DevBlog:

    adndevblog.typepad.com/autocad/2013/10/mirroring-a-dbtext-entity.html

    I hope this helps,

    Kean

  7. Hi Kean,
    How to get the co-ordinates of the Mirrored enity [ Say for example we have mirrored a point]

    1. Kean Walmsley Avatar

      Hi Ranjan,

      AutoCAD entities don't have an inherent position - you would have to get whatever data member makes sense for your type of object. But yes, once mirrored you should find that set to the new coordinates.

      Regards,

      Kean

  8. Kean,
    I am trying to identify if a polyline has been mirrored. How can I tell?

    1. James,

      The easiest way to check is to LIST the properties, MIRROR it and then LIST it again. As far as I recall mirroring changes the vertices but typically not the direction, but I could have that wrong.

      Kean

      1. In case anyone else ends up here hoping to learn how to identify if a polyline has been mirrored, this is where I found code that worked for me. Look for _gile's post.
        forums.autodesk.com/

  9. Hi Kean,
    Number one, thanks for the code help.
    Number two:
    I'm trying to build a command that will mirror objects about a mirror line that is derived from an aisle distance that I provide. Essentially so I can specify the final distance I would like between the objects, rather than a mirror line. This is because, a lot of times, the mirror line I want does not exist (there's nothing to snap to). This leaves me to mirror, select what I mirrored, and move it from a certain point to create the aisle that I want between the objects. I would not decline any general tips you have about the code to achieve that. I have a lot of the process on paper, in plain English, I just need to learn to code it. I'm fairly new to this (coding).
    Why I'm commenting is this: I have a few things to prompt the user for initially. (The objects. A keyword for mirroring left, right, up, or down. And a point I'm calling farthest point: essentially the point from which I will calculate the mirror line. It should be a point on the object with the greatest, or least, x or y coordinate, depending upon which way you are looking to mirror the object.) So I prompt the user for all that, but I would like, if the user gives an invalid response, for the prompt to simply reappear, until they enter something valid. Of course they can hit escape at anytime and exit the command. Any help with that feature would be greatly appreciated.
    Thanks,
    Mike

    1. Kean Walmsley Avatar
      Kean Walmsley

      Hi Mike,

      Unfortunately I'm not currently working on projects related to AutoCAD: I suggest reaching out via the AutoCAD .NET forum to see whether someone there is interested in working with you on this.

      Best,

      Kean

      1. Will do, thanks.

Leave a Reply

Your email address will not be published. Required fields are marked *