找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 2767|回复: 0

[分享] Overruling explode in AutoCAD 2010 using .NET

[复制链接]

已领礼包: 6个

财富等级: 恭喜发财

发表于 2013-5-27 01:37:28 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

I am really starting to love the new Overrule API in AutoCAD 2010, and I still feel as though I’m just scratching the surface. This question came in overnight from Danny Polkinhorn (thanks, Danny! :-) :

It's exciting to see a very usable implementation of 'custom' objects in .NET. Obviously, this implementation protects what could be proprietary business intelligence from being sent around, but it brings up a question. What process would you use to 'explode' these elements so that you could send the drawing to someone without your code, but with the custom elements in it?

My first thought was to just see what happened when the EXPLODE command encountered the overruled lines & circles created with the code in the last post. At first I was a little discouraged:

Command: EXPLODE
Select objects: Specify opposite corner: 9 found
9 were not able to be exploded.
Select objects: *Cancel*
None found.
My worry, at this stage, was that the EXPLODE command was excluding “simple” objects such as lines and circles during its selection process, which would mean that even if we were able to overrule the explode behaviour of our special lines & circles we would have difficulty getting our code called. Thankfully this is not the case, but I only found this out as I implemented a TransformOverrule and overruled Explode for my lines and circles.

Before looking into the specifics, here’s a quick list of the various Overrules available in AutoCAD 2010 with their overrideable methods:


Overrule (the base class)
  • GripOverrule
    • GetGripPoints
    • GetStretchPoints
    • MoveGripPointsAt
    • MoveStretchPointsAt
    • OnGripStatusChanged
  • OsnapOverrule
    • GetObjectSnapPoints
    • IsContentSnappable
  • SubentityOverrule
    • AddSubentPaths
    • DeleteSubentPaths
    • GetCompoundObjectTransform
    • GetGripPointsAtSubentPath
    • GetGsMarkersAtSubentPath
      GetSubentClassId
    • GetSubentPathGeomExtents
    • GetSubentPathsAtGsMarker
    • MoveGripPointsAtSubentPaths
    • OnSubentGripStatusChanged
    • SubentPtr
    • TransformSubentPathsBy
  • TransformOverrule
    • CloneMeForDragging
    • Explode
    • GetTransformedCopy
    • HideMeForDragging
    • TransformBy
  • GeometryOverrule
    • GetGeomExtents
    • IntersectWith
  • PropertiesOverrule
    • GetClassID
    • List
  • ObjectOverrule
    • Cancel
    • Close
    • DeepClone
    • Erase
    • Open
    • WblockClone
  • DrawableOverrule
    • SetAttributes
    • ViewportDraw
    • ViewportDrawLogicalFlags
    • WorldDraw

So far we’ve only actually used the DrawableOverrule, implementing SetAttributes() and WorldDraw().

[Aside: as I compiled the above list I had one of those “woah” moments. It was bit like the feeling I remember as a child while reading “The Elfstones of Shannara”, the – much better – sequel to “The Sword of Shannara” (Terry Brooks’ first fantasy novel). In “The Sword of Shannara” the main character used some elfstones for protection, but it’s only in the sequel that you find out just how powerful they are, and that they’re actually only one of several different varieties of elfstones. Anyone who hasn’t been a fantasy/sci-fi geek in their time is almost certainly rolling their eyes (if they’re not being physically sick) at this point, so I’d better get back on track. I still enjoy a good sci-fi novel, by the way, but these days I find I can’t do fantasy that isn’t Tolkien.]

It’s clear that to customize the explode for our lines and circles we’re going to need a TransformOverrule.

Here’s the C# code from the last post, with our additional TransformOverrules. I’ve changed a few of the class names to reflect the fact they are overrule draw behaviour vs. transform behaviour, but otherwise the code is basically the same as last time, apart from the addition of the LinePipeTransformOverrule and CirclePipeTransformOverrule classes (and the code to register/unregister them).

The Explode functions take pretty much the same geometry we used to draw the “enhanced” objects, but this time it gets returned to the system and is used to replace the original entities. This code doesn’t do anything fancy about the entity colour, etc., but we could certainly do so, if we chose.

  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.DatabaseServices;
  4. using Autodesk.AutoCAD.EditorInput;
  5. using Autodesk.AutoCAD.Geometry;
  6. using Autodesk.AutoCAD.GraphicsInterface;
  7. using Autodesk.AutoCAD.Colors;

  8. namespace Overrules
  9. {
  10.   public abstract class PipeDrawOverrule : DrawableOverrule
  11.   {
  12.     const string regAppName = "TTIF_PIPE";

  13.     public PipeDrawOverrule()
  14.     {
  15.       // Tell AutoCAD to filter on our application name
  16.       // (this means our overrule will only be called
  17.       // on objects possessing XData with this name)

  18.       SetXDataFilter(regAppName);
  19.     }

  20.     // Get the XData for a particular object
  21.     // and return the "pipe radius" if it exists

  22.     public static double PipeRadiusForObject(DBObject obj)
  23.     {
  24.       double res = 0.0;

  25.       ResultBuffer rb = obj.XData;
  26.       if (rb != null)
  27.       {
  28.         bool foundStart = false;

  29.         foreach (TypedValue tv in rb)
  30.         {
  31.           if (tv.TypeCode == (int)DxfCode.ExtendedDataRegAppName &&
  32.               tv.Value.ToString() == regAppName)
  33.             foundStart = true;
  34.           else
  35.           {
  36.             if (foundStart == true)
  37.             {
  38.               if (tv.TypeCode == (int)DxfCode.ExtendedDataReal)
  39.               {
  40.                 res = (double)tv.Value;
  41.                 break;
  42.               }
  43.             }
  44.           }
  45.         }
  46.         rb.Dispose();
  47.       }
  48.       return res;
  49.     }

  50.     // Set the "pipe radius" in the XData of a particular object

  51.     public static void SetPipeRadiusOnObject(
  52.       Transaction tr, DBObject obj, double radius
  53.     )
  54.     {
  55.       Database db = obj.Database;

  56.       // Make sure the application is registered
  57.       // (we could separate this out to be called
  58.       // only once for a set of operations)

  59.       RegAppTable rat =
  60.         (RegAppTable)tr.GetObject(
  61.           db.RegAppTableId,
  62.           OpenMode.ForRead
  63.         );

  64.       if (!rat.Has(regAppName))
  65.       {
  66.         rat.UpgradeOpen();
  67.         RegAppTableRecord ratr = new RegAppTableRecord();
  68.         ratr.Name = regAppName;
  69.         rat.Add(ratr);
  70.         tr.AddNewlyCreatedDBObject(ratr, true);
  71.       }

  72.       // Create the XData and set it on the object

  73.       ResultBuffer rb =
  74.         new ResultBuffer(
  75.           new TypedValue(
  76.             (int)DxfCode.ExtendedDataRegAppName, regAppName
  77.           ),
  78.           new TypedValue(
  79.             (int)DxfCode.ExtendedDataReal, radius
  80.           )
  81.         );
  82.       obj.XData = rb;
  83.       rb.Dispose();
  84.     }
  85.   }

  86.   // An overrule to make a pipe out of line

  87.   public class LinePipeDrawOverrule : PipeDrawOverrule
  88.   {
  89.     static public LinePipeDrawOverrule theOverrule =
  90.       new LinePipeDrawOverrule();

  91.     private SweepOptions sweepOpts = new SweepOptions();

  92.     public override bool WorldDraw(Drawable d, WorldDraw wd)
  93.     {
  94.       double radius = 0.0;

  95.       if (d is DBObject)
  96.         radius = PipeRadiusForObject((DBObject)d);

  97.       if (radius > 0.0)
  98.       {
  99.         Line line = d as Line;

  100.         if (line != null)
  101.         {
  102.           // Draw the line as is, with overruled attributes

  103.           base.WorldDraw(line, wd);
  104.           if (!line.Id.IsNull && line.Length > 0.0)
  105.           {
  106.             // Draw a pipe around the line

  107.             EntityColor c =
  108.               wd.SubEntityTraits.TrueColor;
  109.             wd.SubEntityTraits.TrueColor =
  110.               new EntityColor(0x00AfAfff);
  111.             wd.SubEntityTraits.LineWeight =
  112.               LineWeight.LineWeight000;
  113.             Circle clr =
  114.               new Circle(
  115.                 line.StartPoint,
  116.                 line.EndPoint - line.StartPoint,
  117.                 radius
  118.               );
  119.             ExtrudedSurface pipe = new ExtrudedSurface();
  120.             try
  121.             {
  122.               pipe.CreateExtrudedSurface(
  123.                 clr, line.EndPoint - line.StartPoint, sweepOpts
  124.               );
  125.             }
  126.             catch
  127.             {
  128.               Document doc =
  129.                 Application.DocumentManager.MdiActiveDocument;
  130.               doc.Editor.WriteMessage(
  131.                 "\nFailed with CreateExtrudedSurface."
  132.               );
  133.             }
  134.             clr.Dispose();
  135.             pipe.WorldDraw(wd);
  136.             pipe.Dispose();
  137.             wd.SubEntityTraits.TrueColor = c;
  138.           }
  139.           return true;
  140.         }
  141.       }
  142.       return base.WorldDraw(d, wd);
  143.     }

  144.     public override int SetAttributes(Drawable d, DrawableTraits t)
  145.     {
  146.       int b = base.SetAttributes(d, t);

  147.       double radius = 0.0;

  148.       if (d is DBObject)
  149.         radius = PipeRadiusForObject((DBObject)d);

  150.       if (radius > 0.0)
  151.       {
  152.         // Set color to index 6

  153.         t.Color = 6;

  154.         // and lineweight to .40 mm

  155.         t.LineWeight = LineWeight.LineWeight040;
  156.       }
  157.       return b;
  158.     }
  159.   }

  160.   // An overrule to make a pipe out of circle

  161.   public class CirclePipeDrawOverrule : PipeDrawOverrule
  162.   {
  163.     static public CirclePipeDrawOverrule theOverrule =
  164.       new CirclePipeDrawOverrule();

  165.     private SweepOptions sweepOpts = new SweepOptions();

  166.     public override bool WorldDraw(Drawable d, WorldDraw wd)
  167.     {
  168.       double radius = 0.0;

  169.       if (d is DBObject)
  170.         radius = PipeRadiusForObject((DBObject)d);

  171.       if (radius > 0.0)
  172.       {
  173.         Circle circle = d as Circle;

  174.         if (circle != null)
  175.         {
  176.           // Draw the circle as is, with overruled attributes

  177.           base.WorldDraw(circle, wd);

  178.           // Needed to avoid ill-formed swept surface

  179.           if (circle.Radius > radius)
  180.           {
  181.             // Draw a pipe around the cirle

  182.             EntityColor c = wd.SubEntityTraits.TrueColor;
  183.             wd.SubEntityTraits.TrueColor =
  184.               new EntityColor(0x3fffe0e0);
  185.             wd.SubEntityTraits.LineWeight =
  186.               LineWeight.LineWeight000;
  187.             Vector3d normal =
  188.               (circle.Center - circle.StartPoint).
  189.                 CrossProduct(circle.Normal);
  190.             Circle clr =
  191.               new Circle(
  192.                 circle.StartPoint, normal, radius
  193.               );
  194.             SweptSurface pipe = new SweptSurface();
  195.             pipe.CreateSweptSurface(clr, circle, sweepOpts);
  196.             clr.Dispose();
  197.             pipe.WorldDraw(wd);
  198.             pipe.Dispose();
  199.             wd.SubEntityTraits.TrueColor = c;
  200.           }
  201.           return true;
  202.         }
  203.       }
  204.       return base.WorldDraw(d, wd);
  205.     }

  206.     public override int SetAttributes(Drawable d, DrawableTraits t)
  207.     {
  208.       int b = base.SetAttributes(d, t);

  209.       double radius = 0.0;

  210.       if (d is DBObject)
  211.         radius = PipeRadiusForObject((DBObject)d);

  212.       if (radius > 0.0)
  213.       {
  214.         // Set color to index 2

  215.         t.Color = 2;

  216.         // and lineweight to .60 mm

  217.         t.LineWeight = LineWeight.LineWeight060;
  218.       }
  219.       return b;
  220.     }
  221.   }

  222.   public class LinePipeTransformOverrule : TransformOverrule
  223.   {
  224.     static public LinePipeTransformOverrule theOverrule =
  225.       new LinePipeTransformOverrule();

  226.     private SweepOptions sweepOpts = new SweepOptions();

  227.     public override void Explode(Entity e, DBObjectCollection objs)
  228.     {
  229.       double radius = 0.0;

  230.       if (e is DBObject)
  231.         radius = PipeDrawOverrule.PipeRadiusForObject(e);

  232.       if (radius > 0.0)
  233.       {
  234.         Line line = e as Line;

  235.         if (line != null)
  236.         {
  237.           if (!line.Id.IsNull && line.Length > 0.0)
  238.           {
  239.             // Draw a pipe around the line

  240.             Circle clr =
  241.               new Circle(
  242.                 line.StartPoint,
  243.                 line.EndPoint - line.StartPoint,
  244.                 radius
  245.               );
  246.             ExtrudedSurface pipe = new ExtrudedSurface();
  247.             try
  248.             {
  249.               pipe.CreateExtrudedSurface(
  250.                 clr, line.EndPoint - line.StartPoint, sweepOpts
  251.               );
  252.             }
  253.             catch
  254.             {
  255.               Document doc =
  256.                 Application.DocumentManager.MdiActiveDocument;
  257.               doc.Editor.WriteMessage(
  258.                 "\nFailed with CreateExtrudedSurface."
  259.               );
  260.             }
  261.             clr.Dispose();
  262.             objs.Add(pipe);
  263.           }
  264.           return;
  265.         }
  266.       }
  267.       base.Explode(e, objs);
  268.     }
  269.   }

  270.   public class CirclePipeTransformOverrule : TransformOverrule
  271.   {
  272.     static public CirclePipeTransformOverrule theOverrule =
  273.       new CirclePipeTransformOverrule();

  274.     private SweepOptions sweepOpts = new SweepOptions();

  275.     public override void Explode(Entity e, DBObjectCollection objs)
  276.     {
  277.       double radius = 0.0;

  278.       if (e is DBObject)
  279.         radius = PipeDrawOverrule.PipeRadiusForObject(e);

  280.       if (radius > 0.0)
  281.       {
  282.         Circle circle = e as Circle;

  283.         if (circle != null)
  284.         {
  285.           // Needed to avoid ill-formed swept surface

  286.           if (circle.Radius > radius)
  287.           {
  288.             // Draw a pipe around the cirle

  289.             Vector3d normal =
  290.               (circle.Center - circle.StartPoint).
  291.                 CrossProduct(circle.Normal);
  292.             Circle clr =
  293.               new Circle(
  294.                 circle.StartPoint, normal, radius
  295.               );
  296.             SweptSurface pipe = new SweptSurface();
  297.             pipe.CreateSweptSurface(clr, circle, sweepOpts);
  298.             clr.Dispose();
  299.             objs.Add(pipe);
  300.           }
  301.           return;
  302.         }
  303.       }
  304.       base.Explode(e, objs);
  305.     }
  306.   }

  307.   public class Commands
  308.   {
  309.     private double _radius = 0.0;

  310.     public void Overrule(bool enable)
  311.     {
  312.       // Regen to see the effect
  313.       // (turn on/off Overruling and LWDISPLAY)

  314.       DrawableOverrule.Overruling = enable;
  315.       if (enable)
  316.         Application.SetSystemVariable("LWDISPLAY", 1);
  317.       else
  318.         Application.SetSystemVariable("LWDISPLAY", 0);

  319.       Document doc =
  320.         Application.DocumentManager.MdiActiveDocument;
  321.       doc.SendStringToExecute("REGEN3\n", true, false, false);
  322.       doc.Editor.Regen();
  323.     }

  324.     [CommandMethod("OVERRULE1")]
  325.     public void OverruleStart()
  326.     {
  327.       ObjectOverrule.AddOverrule(
  328.         RXClass.GetClass(typeof(Line)),
  329.         LinePipeDrawOverrule.theOverrule,
  330.         true
  331.       );
  332.       ObjectOverrule.AddOverrule(
  333.         RXClass.GetClass(typeof(Circle)),
  334.         CirclePipeDrawOverrule.theOverrule,
  335.         true
  336.       );
  337.       ObjectOverrule.AddOverrule(
  338.         RXClass.GetClass(typeof(Line)),
  339.         LinePipeTransformOverrule.theOverrule,
  340.         true
  341.       );
  342.       ObjectOverrule.AddOverrule(
  343.         RXClass.GetClass(typeof(Circle)),
  344.         CirclePipeTransformOverrule.theOverrule,
  345.         true
  346.       );
  347.       Overrule(true);
  348.     }

  349.     [CommandMethod("OVERRULE0")]
  350.     public void OverruleEnd()
  351.     {
  352.       ObjectOverrule.RemoveOverrule(
  353.         RXClass.GetClass(typeof(Line)),
  354.         LinePipeDrawOverrule.theOverrule
  355.       );
  356.       ObjectOverrule.RemoveOverrule(
  357.         RXClass.GetClass(typeof(Circle)),
  358.         CirclePipeDrawOverrule.theOverrule
  359.       );
  360.       ObjectOverrule.RemoveOverrule(
  361.         RXClass.GetClass(typeof(Line)),
  362.         LinePipeTransformOverrule.theOverrule
  363.       );
  364.       ObjectOverrule.RemoveOverrule(
  365.         RXClass.GetClass(typeof(Circle)),
  366.         CirclePipeTransformOverrule.theOverrule
  367.       );
  368.       Overrule(false);
  369.     }

  370.     [CommandMethod("MP", CommandFlags.UsePickSet)]
  371.     public void MakePipe()
  372.     {
  373.       Document doc =
  374.         Application.DocumentManager.MdiActiveDocument;
  375.       Database db = doc.Database;
  376.       Editor ed = doc.Editor;

  377.       // Ask the user to select the entities to make into pipes

  378.       PromptSelectionOptions pso =
  379.         new PromptSelectionOptions();
  380.       pso.AllowDuplicates = false;
  381.       pso.MessageForAdding =
  382.         "\nSelect objects to turn into pipes: ";

  383.       PromptSelectionResult selRes =
  384.         doc.Editor.GetSelection(pso);

  385.       // If the user didn't make valid selection, we return

  386.       if (selRes.Status != PromptStatus.OK)
  387.         return;

  388.       SelectionSet ss = selRes.Value;

  389.       // Ask the user for the pipe radius to set

  390.       PromptDoubleOptions pdo =
  391.         new PromptDoubleOptions(
  392.           "\nSpecify pipe radius:"
  393.         );

  394.       // Use the previous value, if if already called

  395.       if (_radius > 0.0)
  396.       {
  397.         pdo.DefaultValue = _radius;
  398.         pdo.UseDefaultValue = true;
  399.       }
  400.       pdo.AllowNegative = false;
  401.       pdo.AllowZero = false;

  402.       PromptDoubleResult pdr =
  403.         ed.GetDouble(pdo);

  404.       // Return if something went wrong

  405.       if (pdr.Status != PromptStatus.OK)
  406.         return;

  407.       // Set the "last radius" value for when
  408.       // the command is called next

  409.       _radius = pdr.Value;

  410.       // Use a transaction to edit our various objects

  411.       Transaction tr =
  412.         db.TransactionManager.StartTransaction();
  413.       using (tr)
  414.       {
  415.         // Lop through the selected objects

  416.         foreach (SelectedObject o in ss)
  417.         {
  418.           // We could choose only to add XData to the objects
  419.           // we know will use it (Lines and Circles, for now)

  420.           DBObject obj =
  421.             tr.GetObject(o.ObjectId, OpenMode.ForWrite);
  422.           PipeDrawOverrule.SetPipeRadiusOnObject(tr, obj, _radius);
  423.         }
  424.         tr.Commit();
  425.       }
  426.     }
  427.   }
  428. }

As before we can create a bunch of lines and circles, assign them radii using the MP command, and then display them using the OVERRULE1 command:


0.jpg

Now when we perform our EXPLODE, selecting the various objects, and instead of a rejection message we get a set of Solid3D objects replacing our lines and circles:

1.jpg

Too cool! :-)

As you can hopefully see, the more you look at the Overrule API in AutoCAD 2010, the more power you uncover. Keep the comments & questions coming – it’s fun to see how this little application is evolving based on your feedback.


论坛插件加载方法
发帖求助前要善用【论坛搜索】功能,那里可能会有你要找的答案;
如果你在论坛求助问题,并且已经从坛友或者管理的回复中解决了问题,请把帖子标题加上【已解决】;
如何回报帮助你解决问题的坛友,一个好办法就是给对方加【D豆】,加分不会扣除自己的积分,做一个热心并受欢迎的人!
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|申请友链|Archiver|手机版|小黑屋|辽公网安备|晓东CAD家园 ( 辽ICP备15016793号 )

GMT+8, 2024-11-17 22:19 , Processed in 0.167003 second(s), 30 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表