Some explanations. To make things simple, I decide to draw a polyline with multiple segments (e.g. with more than 2 vertices) so that every other segment is visible; also, the Overrule would only apply to polylines that are on certain layer; and the Overrule itself can be turn on or off, regardless if there is other custom Overrule taking effect.
Here is the code:
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.Runtime;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
[assembly: CommandClass(typeof(HidePartialPLine.MyCommands))]
namespace HidePartialPLine
{
public class MyCommands
{
private const string OR_LAYER="Overruled_PLine";
private static MyPLineOverrule _myOR=null;
[CommandMethod("MyOR")]
public static void ToggleMyOverrule()
{
Document dwg = Application.DocumentManager.MdiActiveDocument;
Editor ed = dwg.Editor;
if (_myOR==null)
{
_myOR=new MyPLineOverrule();
_myOR.StartOverrule();
ed.WriteMessage("\nMyPLineOverrule is on.\n");
}
else
{
if (!_myOR.OverruleOn)
{
_myOR.StartOverrule();
ed.WriteMessage("\nMyPLineOverrule is on.\n");
}
else
{
_myOR.StopOverrule();
ed.WriteMessage("\nMyPLineOverrule is off.\n");
}
}
}
[CommandMethod("SetOR")]
public static void SetMyOverruleToPolyline()
{
Document dwg = Application.DocumentManager.MdiActiveDocument;
Editor ed = dwg.Editor;
ObjectId id = SelectPolyline(ed);
if (id == ObjectId.Null)
{
ed.WriteMessage("\n*Cancel*\n");
return;
}
SetPolylineLayer(id, OR_LAYER, dwg.Database);
}
#region private methods
private static ObjectId SelectPolyline(Editor ed)
{
PromptEntityOptions opt=new PromptEntityOptions("\nPick a polyline");
opt.SetRejectMessage("You must pick a polyline. ");
opt.AddAllowedClass(
typeof(Autodesk.AutoCAD.DatabaseServices.Polyline),true);
PromptEntityResult res=ed.GetEntity(opt);
if (res.Status==PromptStatus.OK)
{
return res.ObjectId;
}
else
{
return ObjectId.Null;
}
}
private static void SetPolylineLayer(
ObjectId entId, string layerName, Database db)
{
using (Transaction tran = db.TransactionManager.StartTransaction())
{
Entity ent = (Entity)tran.GetObject(entId, OpenMode.ForRead);
if (ent.Layer.ToUpper() != OR_LAYER.ToUpper())
{
ent.UpgradeOpen();
ent.Layer = OR_LAYER;
}
tran.Commit();
}
}
#endregion
}
public class MyPLineOverrule : DrawableOverrule
{
private const string OR_LAYER = "Overruled_PLine";
private bool _overruling=false;
private bool _oldOverruling=false;
public MyPLineOverrule()
{
_overruling=false;
}
public bool OverruleOn
{
get { return _overruling; }
}
public void StartOverrule()
{
_overruling=true;
_oldOverruling = Overrule.Overruling;
Overrule.AddOverrule(RXObject.GetClass(
typeof(Autodesk.AutoCAD.DatabaseServices.Polyline)),
this, false);
//Set custom filter, so that code in overriden IsApplicable()
//will run to do the filtering
this.SetCustomFilter();
Overrule.Overruling=true;
Application.DocumentManager.MdiActiveDocument.Editor.Regen();
}
public void StopOverrule()
{
_overruling = false;
//Cause Overrule redraw the polyline to its original shape
//before the overrule is stopped
Application.DocumentManager.MdiActiveDocument.Editor.Regen();
Overrule.RemoveOverrule(RXObject.GetClass(
typeof(Autodesk.AutoCAD.DatabaseServices.Polyline)), this);
Overrule.Overruling=_oldOverruling;
}
#region Override overrule methods
public override bool IsApplicable(RXObject overruledSubject)
{
//Only apply this overrule to polyline on layer "Overruled_PLine"
Entity ent=overruledSubject as Entity;
return ent.Layer.ToUpper() == OR_LAYER.ToUpper();
}
public override bool WorldDraw(Drawable drawable, WorldDraw wd)
{
Autodesk.AutoCAD.DatabaseServices.Polyline pl = drawable
as Autodesk.AutoCAD.DatabaseServices.Polyline;
//If the polyline only has one segment, draw itself
if (pl.NumberOfVertices < 3)
{
return base.WorldDraw(drawable, wd);
}
if (_overruling)
{
//Get polyline's vertices
Point3d[] pts = new Point3d[pl.NumberOfVertices];
for (int i = 0; i < pl.NumberOfVertices; i++)
{
pts[i] = pl.GetPoint3dAt(i);
}
//Draw every other segement
int n = 0;
while (n < pts.Length)
{
wd.Geometry.WorldLine(pts[n], pts[n + 1]);
n += 2;
}
return true;
}
else
{
return base.WorldDraw(drawable, wd);
}
}
#endregion
}
}
The code pretty much explains itself. To test the code, I started AutoCAD, created a layer named as "Overruled_PLine". Then I drew a few polylines on layer 0. After the code being "netload"ed, I can toggle MyPLineOverrule on/off. When it is on, move polyline to layer "Overruled_PLine" will make the segments of a polyline visible/invisible alternately.
The effect can be watched in this video clip.
Loved reaading this thanks
ReplyDelete