AutoCAD .NET API provides two concrete Jig classes for us to jig different things in different circumstances, EntityJig and DrawJig. EntityJig is to jig a specific entity as its name indicates and the DrawJig is to jig anything that has graphics to draw, which can be a single entity, a group of entities, or something that is not available natively in AutoCAD.
In this post, let us see how to use the DrawJig to move single or multiple entities which can be as many as we like and can have any types in a single group.
Here is the whole DrawJig implementation class along with a test command inside it.
#region Namespaces
using System;
using System.Text;
using System.Linq;
using System.Xml;
using System.Reflection;
using System.ComponentModel;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media.Imaging;
using System.Windows.Forms;
using System.Drawing;
using System.IO;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Windows;
using Autodesk.AutoCAD.GraphicsSystem;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.BoundaryRepresentation;
using Autodesk.AutoCAD.Colors;
using Autodesk.AutoCAD.ComponentModel;
using Autodesk.AutoCAD.Customization;
using Autodesk.AutoCAD.DataExtraction;
using Autodesk.AutoCAD.Diagnostics;
using Autodesk.AutoCAD.Internal;
using Autodesk.AutoCAD.LayerManager;
using Autodesk.AutoCAD.MacroRecorder;
using Autodesk.AutoCAD.Publishing;
using Autodesk.AutoCAD.PlottingServices;
using Autodesk.AutoCAD.Ribbon;
using MgdAcApplication = Autodesk.AutoCAD.ApplicationServices.Application;
using MgdAcDocument = Autodesk.AutoCAD.ApplicationServices.Document;
using AcWindowsNS = Autodesk.AutoCAD.Windows;
#endregion
namespace AcadNetAddinWizard_Namespace
{
public class DrawJigger7 : DrawJig
{
#region Fields
private Point3d mBase;
private Point3d mLocation;
List<Entity> mEntities;
#endregion
#region Constructors
public DrawJigger7(Point3d basePt)
{
mBase = basePt.TransformBy(UCS);
mEntities = new List<Entity>();
}
#endregion
#region Properties
public Point3d Base
{
get { return mLocation; }
set { mLocation = value; }
}
public Point3d Location
{
get { return mLocation; }
set { mLocation = value; }
}
public Matrix3d UCS
{
get
{
return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem;
}
}
#endregion
#region Methods
public void AddEntity(Entity ent)
{
mEntities.Add(ent);
}
public void TransformEntities()
{
Matrix3d mat = Matrix3d.Displacement(mBase.GetVectorTo(mLocation));
foreach (Entity ent in mEntities)
{
ent.TransformBy(mat);
}
}
#endregion
#region Overrides
protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
{
Matrix3d mat = Matrix3d.Displacement(mBase.GetVectorTo(mLocation));
WorldGeometry geo = draw.Geometry;
if (geo != null)
{
geo.PushModelTransform(mat);
foreach (Entity ent in mEntities)
{
geo.Draw(ent);
}
geo.PopModelTransform();
}
return true;
}
protected override SamplerStatus Sampler(JigPrompts prompts)
{
JigPromptPointOptions prOptions1 = new JigPromptPointOptions("\nNew location:");
prOptions1.UseBasePoint = false;
PromptPointResult prResult1 = prompts.AcquirePoint(prOptions1);
if (prResult1.Status == PromptStatus.Cancel || prResult1.Status == PromptStatus.Error)
return SamplerStatus.Cancel;
if (!mLocation.IsEqualTo(prResult1.Value, new Tolerance(10e-10, 10e-10)))
{
mLocation = prResult1.Value;
return SamplerStatus.OK;
}
else
return SamplerStatus.NoChange;
}
#endregion
#region Commands
public static DrawJigger7 jigger;
[CommandMethod("TestDrawJigger7")]
public static void TestDrawJigger7_Method()
{
try
{
Database db = HostApplicationServices.WorkingDatabase;
Editor ed = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor;
PromptSelectionResult selRes = ed.GetSelection();
if (selRes.Status != PromptStatus.OK) return;
PromptPointOptions prOpt = new PromptPointOptions("\nBase point:");
PromptPointResult pr = ed.GetPoint(prOpt);
if (pr.Status != PromptStatus.OK) return;
jigger = new DrawJigger7(pr.Value);
using (Transaction tr = db.TransactionManager.StartTransaction())
{
foreach (ObjectId id in selRes.Value.GetObjectIds())
{
Entity ent = (Entity)tr.GetObject(id, OpenMode.ForWrite);
jigger.AddEntity(ent);
}
PromptResult jigRes = MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.Drag(jigger);
if (jigRes.Status == PromptStatus.OK)
{
jigger.TransformEntities();
tr.Commit();
}
else
tr.Abort();
}
}
catch (System.Exception ex)
{
MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.WriteMessage(ex.ToString());
}
}
#endregion
}
}
After the test assembly is loaded and the test command run, we will see the jigger here behaves almost exactly the same as the native AutoCAD MOVE command.
So, with so concise code which can be condensed a bit further such as removing those unused namespaces, we have reproduced the exact behavior of the looking quite complex AutoCAD MOVE command.
A few highlights about the code may be more helpful.
• The key of the DrawJig is its WorldDraw() method. It provides the abilities to draw any graphics.
• The WorldGeometry instance provides various methods to draw anything we want.
• It also provides us a structural and easy way for us to handle any matrix transformations as we did to the displacement matrix here.
• The Sampler() override is another core method which is used to collect the user input such as the cursor position in the case.
• Though the Sampler() looks like exactly the same as the one in EntityJig, it has a fundamental difference. In the EntityJig, the collected point is in UCS unless explicitly specified with the Input Control; but in the DrawJig, the point coordinate is in WCS.
• However, the Editor.GetPoint() method returns the base point in UCS. That explains why we had to transform the base point to the WCS to make things consistent.
• The WorldGeometry can draw anything that is derived from the Drawable interface in turn the Entity class, so we can redraw the entities in the new location.
• The PushModelTransform and PopModelTransform mechanism makes our life a lot easier. We don’t have to cache the handled new location as new base point as we did before in the EntityJig for moving a single entity.
• In generally, we do not pass the entity pointer to the DrawJig as it should not only care about graphics of a particular entity, but here, we pass a list of the entity pointers into the DrawJig so as to update their graphics at the same moment.
• The WorldGeometry.Draw is so friendly and we can use it to draw the entities of concern one by one. So we have to amend some words we said earlier. We do not have to reinvent the entity drawing features if we choose so.
Enjoy it! More and cooler jigging samples and cases will be demonstrated in the future. Please stay tuned.
The leading edge AutoCAD .NET Addin Wizard (AcadNetAddinWizard) provides a coder, Draw Jigger, to help us create starter code for DrawJig implementations automatically, quickly and reliably.
Posted by: |