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 scale 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 DrawJigger12 : DrawJig
{
#region Fields
private Point3d mBase;
private double mScaleFactor;
List<Entity> mEntities;
#endregion
#region Constructors
public DrawJigger12(Point3d basePt)
{
mScaleFactor = 1;
mBase = basePt.TransformBy(UCS);
mEntities = new List<Entity>();
}
#endregion
#region Properties
public Point3d Base
{
get { return mBase; }
set { mBase = value; }
}
public double Angle
{
get { return mScaleFactor; }
set { mScaleFactor = value; }
}
public Matrix3d UCS
{
get
{
return MgdAcApplication.DocumentManager.MdiActiveDocument.Editor.CurrentUserCoordinateSystem;
}
}
public Matrix3d Transformation
{
get
{
return Matrix3d.Scaling(mScaleFactor, mBase);
}
}
#endregion
#region Methods
public void AddEntity(Entity ent)
{
mEntities.Add(ent);
}
public void TransformEntities()
{
Matrix3d mat = Transformation;
foreach (Entity ent in mEntities)
{
ent.TransformBy(mat);
}
}
#endregion
#region Overrides
protected override bool WorldDraw(Autodesk.AutoCAD.GraphicsInterface.WorldDraw draw)
{
Matrix3d mat = Transformation;
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)
{
JigPromptDistanceOptions prOptions1 = new JigPromptDistanceOptions("\nScale factor:");
prOptions1.BasePoint = mBase;
prOptions1.UseBasePoint = true;
PromptDoubleResult prResult1 = prompts.AcquireDistance(prOptions1);
if (prResult1.Status == PromptStatus.Cancel || prResult1.Status == PromptStatus.Error)
return SamplerStatus.Cancel;
if (Math.Abs(mScaleFactor - prResult1.Value) > 10e-10)
{
mScaleFactor = prResult1.Value;
return SamplerStatus.OK;
}
else
return SamplerStatus.NoChange;
}
#endregion
#region Commands
public static DrawJigger12 jigger;
[CommandMethod("TestDrawJigger12")]
public static void TestDrawJigger12_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 DrawJigger12(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 Scale command.
So, with so concise code which can be condensed a bit further such as removing those unused namespaces, we have reproduced almost the exact behavior of the looking quite profound AutoCAD Scale 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 scale matrix here.
• The Sampler() override is another core method which is used to collect the user input such as the base point and the scale factor 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.
• The WorldGeometry can draw anything that is derived from the Drawable interface in turn the Entity class, so we can redraw the entities with the new scale factor.
• The PushModelTransform and PopModelTransform mechanism makes our life a lot easier. We don’t have to cache the scale factor.
• 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: |