找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 991|回复: 0

[分享] Using an AutoCAD 2010 overrule to control the copying of XData using .NET

[复制链接]

已领礼包: 6个

财富等级: 恭喜发财

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

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

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

×



It’s quite common for AutoCAD developers to use Extended Entity Data (XData) to tag objects their application cares about. This is certainly the approach taken in the recent series showing how to overrule the graphics display for an object – we store a “pipe radius” in XData attached to the Line or Circle we want to have a 3D profile.

That’s fine, but what if we’re storing a unique identifier with an object in XData that we do not want copied with the object? The Overrule API in AutoCAD 2010 allows you to hook into the DeepClone of an object and control what data gets copied with the object, whether via the COPY command or some other process that chooses to copy your object.

Here’s an example CopyOverrule class that makes use of the XData functions we previously defined as part of the PipeDrawOverrule class:

  1. public class CopyOverrule : ObjectOverrule
  2. {
  3.   static public CopyOverrule theOverrule =
  4.     new CopyOverrule();

  5.   public override DBObject DeepClone(
  6.     DBObject dbObject, DBObject ownerObject,
  7.     IdMapping idMap, bool isPrimary
  8.   )
  9.   {
  10.     // First we deep clone the object via the parent

  11.     DBObject res =
  12.       base.DeepClone(dbObject, ownerObject, idMap, isPrimary);

  13.     // Then we check for our XData

  14.     if (PipeDrawOverrule.PipeRadiusForObject(res) > 0.0)
  15.     {
  16.       // A transaction is needed by the set function to access
  17.       // the RegApp table - we could also assume the app name
  18.       // is registered and have a separate implementation
  19.       // not taking the transaction...      
  20.       // Just as we might also have chosen to remove the XData

  21.       Transaction tr =
  22.         dbObject.Database.TransactionManager.StartTransaction();
  23.       using (tr)
  24.       {
  25.         PipeDrawOverrule.SetPipeRadiusOnObject(tr, res, 0.0);
  26.         tr.Commit();
  27.       }
  28.     }
  29.     return res;
  30.   }
  31. }
  32. In this code we call the DeepClone implementation in the parent class and set the result – the copy of our object – to the res variable. If there any additional objects were copied during the DeepClone process, there should be IdPair entries in the idMap variable referring to both the originator and the copy. In this code we just check the XData on the returned object, but we might also iterate through and check the contents of the idMap.

  33. Also, rather than removing the XData – which some people might prefer to do, depending on the behaviour of their application – we just set it to 0. Which is enough to make sure the object’s graphic display doesn’t make use of a pipe radius.

  34. Here’s the complete code, including the code to register and unregister the overrule in the OVERRULE0 and OVERRULE1 commands:

  35. using Autodesk.AutoCAD.ApplicationServices;
  36. using Autodesk.AutoCAD.Runtime;
  37. using Autodesk.AutoCAD.DatabaseServices;
  38. using Autodesk.AutoCAD.EditorInput;
  39. using Autodesk.AutoCAD.Geometry;
  40. using Autodesk.AutoCAD.GraphicsInterface;
  41. using Autodesk.AutoCAD.Colors;

  42. namespace DrawOverrules
  43. {
  44.   public abstract class PipeDrawOverrule : DrawableOverrule
  45.   {
  46.     const string regAppName = "TTIF_PIPE";

  47.     public PipeDrawOverrule()
  48.     {
  49.       // Tell AutoCAD to filter on our application name
  50.       // (this means our overrule will only be called
  51.       // on objects possessing XData with this name)

  52.       SetXDataFilter(regAppName);
  53.     }

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

  56.     public static double PipeRadiusForObject(DBObject obj)
  57.     {
  58.       double res = 0.0;

  59.       ResultBuffer rb = obj.XData;
  60.       if (rb != null)
  61.       {
  62.         bool foundStart = false;

  63.         foreach (TypedValue tv in rb)
  64.         {
  65.           if (tv.TypeCode == (int)DxfCode.ExtendedDataRegAppName &&
  66.               tv.Value.ToString() == regAppName)
  67.             foundStart = true;
  68.           else
  69.           {
  70.             if (foundStart == true)
  71.             {
  72.               if (tv.TypeCode == (int)DxfCode.ExtendedDataReal)
  73.               {
  74.                 res = (double)tv.Value;
  75.                 break;
  76.               }
  77.             }
  78.           }
  79.         }
  80.         rb.Dispose();
  81.       }
  82.       return res;
  83.     }

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

  85.     public static void SetPipeRadiusOnObject(
  86.       Transaction tr, DBObject obj, double radius
  87.     )
  88.     {
  89.       Database db = obj.Database;

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

  93.       RegAppTable rat =
  94.         (RegAppTable)tr.GetObject(
  95.           db.RegAppTableId,
  96.           OpenMode.ForRead
  97.         );

  98.       if (!rat.Has(regAppName))
  99.       {
  100.         rat.UpgradeOpen();
  101.         RegAppTableRecord ratr = new RegAppTableRecord();
  102.         ratr.Name = regAppName;
  103.         rat.Add(ratr);
  104.         tr.AddNewlyCreatedDBObject(ratr, true);
  105.       }

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

  107.       ResultBuffer rb =
  108.         new ResultBuffer(
  109.           new TypedValue(
  110.             (int)DxfCode.ExtendedDataRegAppName, regAppName
  111.           ),
  112.           new TypedValue(
  113.             (int)DxfCode.ExtendedDataReal, radius
  114.           )
  115.         );
  116.       obj.XData = rb;
  117.       rb.Dispose();
  118.     }
  119.   }

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

  121.   public class LinePipeDrawOverrule : PipeDrawOverrule
  122.   {
  123.     static public LinePipeDrawOverrule theOverrule =
  124.       new LinePipeDrawOverrule();

  125.     private SweepOptions sweepOpts = new SweepOptions();

  126.     public override bool WorldDraw(Drawable d, WorldDraw wd)
  127.     {
  128.       double radius = 0.0;

  129.       if (d is DBObject)
  130.         radius = PipeRadiusForObject((DBObject)d);

  131.       if (radius > 0.0)
  132.       {
  133.         Line line = d as Line;

  134.         if (line != null)
  135.         {
  136.           // Draw the line as is, with overruled attributes

  137.           base.WorldDraw(line, wd);
  138.           if (!line.Id.IsNull && line.Length > 0.0)
  139.           {
  140.             // Draw a pipe around the line

  141.             EntityColor c =
  142.               wd.SubEntityTraits.TrueColor;
  143.             wd.SubEntityTraits.TrueColor =
  144.               new EntityColor(0x00AfAfff);
  145.             wd.SubEntityTraits.LineWeight =
  146.               LineWeight.LineWeight000;
  147.             Circle clr =
  148.               new Circle(
  149.                 line.StartPoint,
  150.                 line.EndPoint - line.StartPoint,
  151.                 radius
  152.               );
  153.             ExtrudedSurface pipe = new ExtrudedSurface();
  154.             try
  155.             {
  156.               pipe.CreateExtrudedSurface(
  157.                 clr, line.EndPoint - line.StartPoint, sweepOpts
  158.               );
  159.             }
  160.             catch
  161.             {
  162.               Document doc =
  163.                 Application.DocumentManager.MdiActiveDocument;
  164.               doc.Editor.WriteMessage(
  165.                 "\nFailed with CreateExtrudedSurface."
  166.               );
  167.             }
  168.             clr.Dispose();
  169.             pipe.WorldDraw(wd);
  170.             pipe.Dispose();
  171.             wd.SubEntityTraits.TrueColor = c;
  172.           }
  173.           return true;
  174.         }
  175.       }
  176.       return base.WorldDraw(d, wd);
  177.     }

  178.     public override int SetAttributes(Drawable d, DrawableTraits t)
  179.     {
  180.       int b = base.SetAttributes(d, t);

  181.       double radius = 0.0;

  182.       if (d is DBObject)
  183.         radius = PipeRadiusForObject((DBObject)d);

  184.       if (radius > 0.0)
  185.       {
  186.         // Set color to index 6

  187.         t.Color = 6;

  188.         // and lineweight to .40 mm

  189.         t.LineWeight = LineWeight.LineWeight040;
  190.       }
  191.       return b;
  192.     }
  193.   }

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

  195.   public class CirclePipeDrawOverrule : PipeDrawOverrule
  196.   {
  197.     static public CirclePipeDrawOverrule theOverrule =
  198.       new CirclePipeDrawOverrule();

  199.     private SweepOptions sweepOpts = new SweepOptions();

  200.     public override bool WorldDraw(Drawable d, WorldDraw wd)
  201.     {
  202.       double radius = 0.0;

  203.       if (d is DBObject)
  204.         radius = PipeRadiusForObject((DBObject)d);

  205.       if (radius > 0.0)
  206.       {
  207.         Circle circle = d as Circle;

  208.         if (circle != null)
  209.         {
  210.           // Draw the circle as is, with overruled attributes

  211.           base.WorldDraw(circle, wd);

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

  213.           if (circle.Radius > radius)
  214.           {
  215.             // Draw a pipe around the cirle

  216.             EntityColor c = wd.SubEntityTraits.TrueColor;
  217.             wd.SubEntityTraits.TrueColor =
  218.               new EntityColor(0x3fffe0e0);
  219.             wd.SubEntityTraits.LineWeight =
  220.               LineWeight.LineWeight000;
  221.             Vector3d normal =
  222.               (circle.Center - circle.StartPoint).
  223.                 CrossProduct(circle.Normal);
  224.             Circle clr =
  225.               new Circle(
  226.                 circle.StartPoint, normal, radius
  227.               );
  228.             SweptSurface pipe = new SweptSurface();
  229.             pipe.CreateSweptSurface(clr, circle, sweepOpts);
  230.             clr.Dispose();
  231.             pipe.WorldDraw(wd);
  232.             pipe.Dispose();
  233.             wd.SubEntityTraits.TrueColor = c;
  234.           }
  235.           return true;
  236.         }
  237.       }
  238.       return base.WorldDraw(d, wd);
  239.     }

  240.     public override int SetAttributes(Drawable d, DrawableTraits t)
  241.     {
  242.       int b = base.SetAttributes(d, t);

  243.       double radius = 0.0;

  244.       if (d is DBObject)
  245.         radius = PipeRadiusForObject((DBObject)d);

  246.       if (radius > 0.0)
  247.       {
  248.         // Set color to index 2

  249.         t.Color = 2;

  250.         // and lineweight to .60 mm

  251.         t.LineWeight = LineWeight.LineWeight060;
  252.       }
  253.       return b;
  254.     }
  255.   }

  256.   public class LinePipeTransformOverrule : TransformOverrule
  257.   {
  258.     static public LinePipeTransformOverrule theOverrule =
  259.       new LinePipeTransformOverrule();

  260.     private SweepOptions sweepOpts = new SweepOptions();

  261.     public override void Explode(Entity e, DBObjectCollection objs)
  262.     {
  263.       double radius = 0.0;

  264.       if (e is DBObject)
  265.         radius = PipeDrawOverrule.PipeRadiusForObject(e);

  266.       if (radius > 0.0)
  267.       {
  268.         Line line = e as Line;

  269.         if (line != null)
  270.         {
  271.           if (!line.Id.IsNull && line.Length > 0.0)
  272.           {
  273.             // Draw a pipe around the line

  274.             Circle clr =
  275.               new Circle(
  276.                 line.StartPoint,
  277.                 line.EndPoint - line.StartPoint,
  278.                 radius
  279.               );
  280.             ExtrudedSurface pipe = new ExtrudedSurface();
  281.             try
  282.             {
  283.               pipe.CreateExtrudedSurface(
  284.                 clr, line.EndPoint - line.StartPoint, sweepOpts
  285.               );
  286.             }
  287.             catch
  288.             {
  289.               Document doc =
  290.                 Application.DocumentManager.MdiActiveDocument;
  291.               doc.Editor.WriteMessage(
  292.                 "\nFailed with CreateExtrudedSurface."
  293.               );
  294.             }
  295.             clr.Dispose();
  296.             objs.Add(pipe);
  297.           }
  298.           return;
  299.         }
  300.       }
  301.       base.Explode(e, objs);
  302.     }
  303.   }

  304.   public class CirclePipeTransformOverrule : TransformOverrule
  305.   {
  306.     static public CirclePipeTransformOverrule theOverrule =
  307.       new CirclePipeTransformOverrule();

  308.     private SweepOptions sweepOpts = new SweepOptions();

  309.     public override void Explode(Entity e, DBObjectCollection objs)
  310.     {
  311.       double radius = 0.0;

  312.       if (e is DBObject)
  313.         radius = PipeDrawOverrule.PipeRadiusForObject(e);

  314.       if (radius > 0.0)
  315.       {
  316.         Circle circle = e as Circle;

  317.         if (circle != null)
  318.         {
  319.           // Needed to avoid ill-formed swept surface

  320.           if (circle.Radius > radius)
  321.           {
  322.             // Draw a pipe around the cirle

  323.             Vector3d normal =
  324.               (circle.Center - circle.StartPoint).
  325.                 CrossProduct(circle.Normal);
  326.             Circle clr =
  327.               new Circle(
  328.                 circle.StartPoint, normal, radius
  329.               );
  330.             SweptSurface pipe = new SweptSurface();
  331.             pipe.CreateSweptSurface(clr, circle, sweepOpts);
  332.             clr.Dispose();
  333.             objs.Add(pipe);
  334.           }
  335.           return;
  336.         }
  337.       }
  338.       base.Explode(e, objs);
  339.     }
  340.   }

  341.   public class CopyOverrule : ObjectOverrule
  342.   {
  343.     static public CopyOverrule theOverrule =
  344.       new CopyOverrule();

  345.     public override DBObject DeepClone(
  346.       DBObject dbObject, DBObject ownerObject,
  347.       IdMapping idMap, bool isPrimary
  348.     )
  349.     {
  350.       // First we deep clone the object via the parent

  351.       DBObject res =
  352.         base.DeepClone(dbObject, ownerObject, idMap, isPrimary);

  353.       // Then we check for our XData

  354.       if (PipeDrawOverrule.PipeRadiusForObject(res) > 0.0)
  355.       {
  356.         // A transaction is needed by the set function to access
  357.         // the RegApp table - we could also assume the app name
  358.         // is registered and have a separate implementation
  359.         // not taking the transaction...      
  360.         // Just as we might also have chosen to remove the XData

  361.         Transaction tr =
  362.           dbObject.Database.TransactionManager.StartTransaction();
  363.         using (tr)
  364.         {
  365.           PipeDrawOverrule.SetPipeRadiusOnObject(tr, res, 0.0);
  366.           tr.Commit();
  367.         }
  368.       }
  369.       return res;
  370.     }
  371.   }

  372.   public class Commands
  373.   {
  374.     private double _radius = 0.0;

  375.     public void Overrule(bool enable)
  376.     {
  377.       // Regen to see the effect
  378.       // (turn on/off Overruling and LWDISPLAY)

  379.       DrawableOverrule.Overruling = enable;
  380.       if (enable)
  381.         Application.SetSystemVariable("LWDISPLAY", 1);
  382.       else
  383.         Application.SetSystemVariable("LWDISPLAY", 0);

  384.       Document doc =
  385.         Application.DocumentManager.MdiActiveDocument;
  386.       doc.SendStringToExecute("REGEN3\n", true, false, false);
  387.       doc.Editor.Regen();
  388.     }

  389.     [CommandMethod("OVERRULE1")]
  390.     public void OverruleStart()
  391.     {
  392.       ObjectOverrule.AddOverrule(
  393.         RXClass.GetClass(typeof(Line)),
  394.         LinePipeDrawOverrule.theOverrule,
  395.         true
  396.       );
  397.       ObjectOverrule.AddOverrule(
  398.         RXClass.GetClass(typeof(Circle)),
  399.         CirclePipeDrawOverrule.theOverrule,
  400.         true
  401.       );
  402.       ObjectOverrule.AddOverrule(
  403.         RXClass.GetClass(typeof(Line)),
  404.         LinePipeTransformOverrule.theOverrule,
  405.         true
  406.       );
  407.       ObjectOverrule.AddOverrule(
  408.         RXClass.GetClass(typeof(Circle)),
  409.         CirclePipeTransformOverrule.theOverrule,
  410.         true
  411.       );
  412.       ObjectOverrule.AddOverrule(
  413.         RXClass.GetClass(typeof(Entity)),
  414.         CopyOverrule.theOverrule,
  415.         true
  416.       );
  417.       Overrule(true);
  418.     }

  419.     [CommandMethod("OVERRULE0")]
  420.     public void OverruleEnd()
  421.     {
  422.       ObjectOverrule.RemoveOverrule(
  423.         RXClass.GetClass(typeof(Line)),
  424.         LinePipeDrawOverrule.theOverrule
  425.       );
  426.       ObjectOverrule.RemoveOverrule(
  427.         RXClass.GetClass(typeof(Circle)),
  428.         CirclePipeDrawOverrule.theOverrule
  429.       );
  430.       ObjectOverrule.RemoveOverrule(
  431.         RXClass.GetClass(typeof(Line)),
  432.         LinePipeTransformOverrule.theOverrule
  433.       );
  434.       ObjectOverrule.RemoveOverrule(
  435.         RXClass.GetClass(typeof(Circle)),
  436.         CirclePipeTransformOverrule.theOverrule
  437.       );
  438.       ObjectOverrule.RemoveOverrule(
  439.         RXClass.GetClass(typeof(Entity)),
  440.         CopyOverrule.theOverrule
  441.       );
  442.       Overrule(false);
  443.     }

  444.     [CommandMethod("MP", CommandFlags.UsePickSet)]
  445.     public void MakePipe()
  446.     {
  447.       Document doc =
  448.         Application.DocumentManager.MdiActiveDocument;
  449.       Database db = doc.Database;
  450.       Editor ed = doc.Editor;

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

  452.       PromptSelectionOptions pso =
  453.         new PromptSelectionOptions();
  454.       pso.AllowDuplicates = false;
  455.       pso.MessageForAdding =
  456.         "\nSelect objects to turn into pipes: ";

  457.       PromptSelectionResult selRes =
  458.         doc.Editor.GetSelection(pso);

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

  460.       if (selRes.Status != PromptStatus.OK)
  461.         return;

  462.       SelectionSet ss = selRes.Value;

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

  464.       PromptDoubleOptions pdo =
  465.         new PromptDoubleOptions(
  466.           "\nSpecify pipe radius:"
  467.         );

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

  469.       if (_radius > 0.0)
  470.       {
  471.         pdo.DefaultValue = _radius;
  472.         pdo.UseDefaultValue = true;
  473.       }
  474.       pdo.AllowNegative = false;
  475.       pdo.AllowZero = false;

  476.       PromptDoubleResult pdr =
  477.         ed.GetDouble(pdo);

  478.       // Return if something went wrong

  479.       if (pdr.Status != PromptStatus.OK)
  480.         return;

  481.       // Set the "last radius" value for when
  482.       // the command is called next

  483.       _radius = pdr.Value;

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

  485.       Transaction tr =
  486.         db.TransactionManager.StartTransaction();
  487.       using (tr)
  488.       {
  489.         // Loop through the selected objects

  490.         foreach (SelectedObject o in ss)
  491.         {
  492.           // We could choose only to add XData to the objects
  493.           // we know will use it (Lines and Circles, for now)

  494.           DBObject obj =
  495.             tr.GetObject(o.ObjectId, OpenMode.ForWrite);
  496.           PipeDrawOverrule.SetPipeRadiusOnObject(tr, obj, _radius);
  497.         }
  498.         tr.Commit();
  499.       }
  500.     }
  501.   }
  502. }


Let’s see what happens when we attempt to copy a circular pipe using the standard COPY command (after having first created it using MP and have it display using OVERRULE1). We can see that as we select the location, the circle is displayed with a pipe radius:


ith a pipe radius:

0.jpg

But once we specify the location, the circle’s radius is removed:

1.jpg


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

本版积分规则

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

GMT+8, 2024-11-17 22:47 , Processed in 0.264717 second(s), 31 queries , Gzip On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

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