Tuesday, August 14, 2012

Using DrawJig to Move/Rotate Attribute in Block

When publishing my previous post (Creating Linked Entities with DrawJig) I found one of my not published post drafts was also about DrawJig, which I started quite a while ago but did finished for some reason that I could not remember (it was very likely that I was to lazy to find time to completed it then:-().

Now that my mind is still a bit fresh on DrawJig, I though why not to get it done, hence this post.

More often than not, user may want to move or rotate an attribute of an inserted block. There used to be a command in AutoCAD (may it still be there, but I could not remember its name - I do not use AutoCAD for drafting/designing for so many years and simply do not remember most the commands) to allow user move Attribute of an inserted block. My code shown here does the similar thing using DrawJig: user can pick an Attribute and choose to move or rotate it. Here is the class AttributeDrawJig:

Code Snippet
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.DatabaseServices;
  3. using Autodesk.AutoCAD.EditorInput;
  4. using Autodesk.AutoCAD.Geometry;
  5. using Autodesk.AutoCAD.GraphicsInterface;
  6.  
  7. namespace MoveAttribute
  8. {
  9.     public class AttributeDrawJig : DrawJig
  10.     {
  11.         private enum JigType
  12.         {
  13.             Move = 0,
  14.             Rotate = 1,
  15.         }
  16.  
  17.         private Document _dwg;
  18.         private Database _db;
  19.         private Editor _ed;
  20.         private ObjectId _attRefId = ObjectId.Null;
  21.         private Point3d _attPosition;
  22.         private JigType _jigType = JigType.Move;
  23.  
  24.         private AttributeReference _visualAtt;
  25.         private Point3d _currentPoint;
  26.         private Point3d _prevPoint;
  27.  
  28.         private double _currentAngle;
  29.         private double _prevAngle;
  30.  
  31.         public AttributeDrawJig(Document dwg)
  32.         {
  33.             _dwg = dwg;
  34.             _db = dwg.Database;
  35.             _ed = dwg.Editor;
  36.         }
  37.  
  38.         #region public methods
  39.  
  40.         public bool MoveAttribute()
  41.         {
  42.             if (!PickAttribute()) return false;
  43.             HighlightAttribute(true);
  44.  
  45.             try
  46.             {
  47.                 bool go = true;
  48.                 while (go)
  49.                 {
  50.                     bool repicked = false;
  51.  
  52.                     PromptKeywordOptions kOpt = new PromptKeywordOptions(
  53.                         "\nPick attribute transform option:");
  54.                     kOpt.Keywords.Add("Move");
  55.                     kOpt.Keywords.Add("Rotate");
  56.                     kOpt.Keywords.Add("Pick");
  57.                     kOpt.Keywords.Add("eXit");
  58.                     kOpt.Keywords.Default = "Move";
  59.                     kOpt.AppendKeywordsToMessage = true;
  60.  
  61.                     PromptResult res = _ed.GetKeywords(kOpt);
  62.  
  63.                     if (res.Status == PromptStatus.OK)
  64.                     {
  65.                         switch(res.StringResult.ToUpper())
  66.                         {
  67.                             case "MOVE":
  68.                                 _jigType = JigType.Move;
  69.                                 break;
  70.                             case "ROTATE":
  71.                                 _jigType = JigType.Rotate;
  72.                                 break;
  73.                             case "PICK":
  74.                                 HighlightAttribute(false);
  75.                                 if (!PickAttribute()) return false;
  76.                                 HighlightAttribute(true);
  77.                                 repicked = true;
  78.                                 break;
  79.                             default:
  80.                                 go = false;
  81.                                 break;
  82.                         }
  83.                     }
  84.                     else
  85.                     {
  86.                         return false;
  87.                     }
  88.  
  89.                     if (repicked || !go) continue;
  90.  
  91.                     //Create Visual Attribute
  92.                     CreateVisualAttribute();
  93.  
  94.                     _currentPoint = _attPosition;
  95.                     _prevPoint = _attPosition;
  96.                     _currentAngle = 0.0;
  97.                     _prevAngle = 0.0;
  98.  
  99.                     //Drag visual attribute
  100.                     PromptResult jigresult =_ed.Drag(this);
  101.  
  102.                     //Update the selected attribute
  103.                     //if the drag status returns OK
  104.                     if (jigresult.Status == PromptStatus.OK)
  105.                     {
  106.                         if (_jigType == JigType.Move)
  107.                         {
  108.                             MoveAttribute(_currentPoint);
  109.                             _ed.WriteMessage(
  110.                                 "\nSelected attribute has been moved.");
  111.  
  112.                             //Update attribute position
  113.                             _attPosition = GetAttributePosition(_attRefId);
  114.                         }
  115.  
  116.                         if (_jigType == JigType.Rotate)
  117.                         {
  118.                             RotateAttribute(_currentAngle);
  119.                             _ed.WriteMessage(
  120.                                 "\nSelected attribute has been ratated");
  121.                         }
  122.                     }
  123.                     else
  124.                     {
  125.                         return false;
  126.                     }
  127.                 }
  128.             }
  129.             catch
  130.             {
  131.                 throw;
  132.             }
  133.             finally
  134.             {
  135.                 HighlightAttribute(false);
  136.                 if (_visualAtt != null) _visualAtt.Dispose();
  137.             }
  138.  
  139.             return true;
  140.         }
  141.  
  142.         #endregion
  143.  
  144.         #region DrawJig Overrides
  145.  
  146.         protected override bool WorldDraw(WorldDraw draw)
  147.         {
  148.             draw.Geometry.Draw(_visualAtt);
  149.             return true;
  150.         }
  151.  
  152.         protected override SamplerStatus Sampler(JigPrompts prompts)
  153.         {
  154.             if (_jigType == JigType.Move)
  155.             {
  156.                 JigPromptPointOptions opt = new JigPromptPointOptions(
  157.                     "\nPick point to move attribute:");
  158.                 opt.UseBasePoint = true;
  159.                 opt.BasePoint = _attPosition;
  160.                 opt.Cursor = CursorType.RubberBand;
  161.                 PromptPointResult res = prompts.AcquirePoint(opt);
  162.  
  163.                 if (res.Status == PromptStatus.OK)
  164.                 {
  165.                     _currentPoint = res.Value;
  166.                     if (_currentPoint == _prevPoint)
  167.                     {
  168.                         return SamplerStatus.NoChange;
  169.                     }
  170.                     else
  171.                     {
  172.                         Matrix3d mt = Matrix3d.Displacement(
  173.                             _prevPoint.GetVectorTo(_currentPoint));
  174.                         _visualAtt.TransformBy(mt);
  175.  
  176.                         _prevPoint = _currentPoint;
  177.                         return SamplerStatus.OK;
  178.                     }
  179.                 }
  180.                 else
  181.                 {
  182.                     return SamplerStatus.Cancel;
  183.                 }
  184.             }
  185.  
  186.             if (_jigType == JigType.Rotate)
  187.             {
  188.                 JigPromptAngleOptions opt = new JigPromptAngleOptions(
  189.                     "\nEnter or pick rotation angle:");
  190.                 opt.UseBasePoint = true;
  191.                 opt.BasePoint = _attPosition;
  192.                 opt.Cursor = CursorType.RubberBand;
  193.                 PromptDoubleResult res =prompts.AcquireAngle(opt);
  194.  
  195.                 if (res.Status == PromptStatus.OK)
  196.                 {
  197.                     _currentAngle = res.Value;
  198.                     if (_currentAngle == _prevAngle)
  199.                     {
  200.                         return SamplerStatus.NoChange;
  201.                     }
  202.                     else
  203.                     {
  204.                         Matrix3d mt = Matrix3d.Rotation(
  205.                             _currentAngle, Vector3d.ZAxis, _attPosition);
  206.                         _visualAtt.TransformBy(mt);
  207.  
  208.                         _prevAngle = _currentAngle;
  209.                         return SamplerStatus.OK;
  210.                     }
  211.                 }
  212.                 else
  213.                 {
  214.                     return SamplerStatus.Cancel;
  215.                 }
  216.             }
  217.  
  218.             return SamplerStatus.OK;
  219.         }
  220.  
  221.         #endregion
  222.  
  223.         #region private methods
  224.  
  225.         private bool PickAttribute()
  226.         {
  227.             while (true)
  228.             {
  229.                 PromptNestedEntityOptions opt = new
  230.                     PromptNestedEntityOptions("\nPick an attribute:");
  231.                 opt.AllowNone = false;
  232.  
  233.                 PromptNestedEntityResult res = _ed.GetNestedEntity(opt);
  234.                 if (res.Status == PromptStatus.OK)
  235.                 {
  236.                     if (res.ObjectId.ObjectClass.DxfName.ToUpper() == "ATTRIB")
  237.                     {
  238.                         _attRefId = res.ObjectId;
  239.                         _attPosition = GetAttributePosition(_attRefId);
  240.                         return true;
  241.                     }
  242.                     else
  243.                     {
  244.                         _ed.WriteMessage("\nInvalid pick: not an attribute");
  245.                     }
  246.                 }
  247.                 else
  248.                 {
  249.                     return false;
  250.                 }
  251.             }
  252.         }
  253.  
  254.         private Point3d GetAttributePosition(ObjectId id)
  255.         {
  256.             Point3d p = new Point3d();
  257.  
  258.             using (Transaction tran =
  259.                 _db.TransactionManager.StartOpenCloseTransaction())
  260.             {
  261.                 AttributeReference att = tran.GetObject(
  262.                     id, OpenMode.ForRead) as AttributeReference;
  263.                 p = att.Position;
  264.                 tran.Commit();
  265.             }
  266.  
  267.             return p;
  268.         }
  269.  
  270.         private void HighlightAttribute(bool highlight)
  271.         {
  272.             using (Transaction tran =
  273.                 _db.TransactionManager.StartOpenCloseTransaction())
  274.             {
  275.                 Entity ent = tran.GetObject(
  276.                     _attRefId, OpenMode.ForWrite) as Entity;
  277.                 if (highlight)
  278.                     ent.Highlight();
  279.                 else
  280.                     ent.Unhighlight();
  281.  
  282.                 tran.Commit();
  283.             }
  284.         }
  285.  
  286.         private void CreateVisualAttribute()
  287.         {
  288.             if (_visualAtt != null) _visualAtt.Dispose();
  289.             _visualAtt = null;
  290.  
  291.             using (Transaction tran =
  292.                 _db.TransactionManager.StartOpenCloseTransaction())
  293.             {
  294.                 AttributeReference att =
  295.                     (AttributeReference)tran.GetObject(
  296.                     _attRefId, OpenMode.ForRead);
  297.                 _visualAtt = att.Clone() as AttributeReference;
  298.                 _visualAtt.SetDatabaseDefaults(_db);
  299.  
  300.                 tran.Commit();
  301.             }
  302.         }
  303.  
  304.         private void MoveAttribute(Point3d toPoint)
  305.         {
  306.             using (Transaction tran =
  307.                 _db.TransactionManager.StartOpenCloseTransaction())
  308.             {
  309.                 Entity ent = (Entity)tran.GetObject(
  310.                     _attRefId, OpenMode.ForWrite);
  311.  
  312.                 Matrix3d mt = Matrix3d.Displacement(
  313.                     _attPosition.GetVectorTo(toPoint));
  314.                 ent.TransformBy(mt);
  315.  
  316.                 tran.Commit();
  317.             }
  318.         }
  319.  
  320.         private void RotateAttribute(double angle)
  321.         {
  322.             using (Transaction tran =
  323.                 _db.TransactionManager.StartOpenCloseTransaction())
  324.             {
  325.                 Entity ent = (Entity)tran.GetObject(
  326.                     _attRefId, OpenMode.ForWrite);
  327.  
  328.                 Matrix3d mt = Matrix3d.Rotation(
  329.                     angle, Vector3d.ZAxis, _attPosition);
  330.                 ent.TransformBy(mt);
  331.  
  332.                 tran.Commit();
  333.             }
  334.         }
  335.  
  336.         #endregion
  337.     }
  338. }

Then here is the command class that uses the AttributeDrawJig:

Code Snippet
  1. using Autodesk.AutoCAD.ApplicationServices;
  2. using Autodesk.AutoCAD.Runtime;
  3. using Autodesk.AutoCAD.EditorInput;
  4.  
  5. [assembly: CommandClass(typeof(MoveAttribute.MoveAttributeCmd))]
  6.  
  7. namespace MoveAttribute
  8. {
  9.     public class MoveAttributeCmd
  10.     {
  11.         [CommandMethod("AttMove")]
  12.         public static void MoveAttribute()
  13.         {
  14.             Document dwg = Application.DocumentManager.MdiActiveDocument;
  15.             Editor ed = dwg.Editor;
  16.  
  17.             try
  18.             {
  19.                 AttributeDrawJig attJig = new AttributeDrawJig(dwg);
  20.                 if (!attJig.MoveAttribute())
  21.                 {
  22.                     ed.WriteMessage("\n*Cancel*");
  23.                 }  
  24.             }
  25.             catch (System.Exception ex)
  26.             {
  27.                 ed.WriteMessage("\nError: {0}", ex.Message);
  28.             }
  29.  
  30.             Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
  31.         }
  32.     }
  33. }

Here is the video clip showing the code in action.

5 comments:

M. Khateeb said...

Hello,Can you, please, post the moveattribute.dll that works with autocad 2012.
Thanks in advance
M. Khateeb

Norman Yuan said...

The code shown in this post was developed with Acad2012, thus works with Acad2012. Well, it is actually AcadMap2012, but this does not make difference at all.

What issue do you have with it?

M. Khateeb said...

Thanks for your reply.
What I wanted is a compiled dll.
Sorry, My knowledge is very limited with programming.
Thanks again

Norman Yuan said...

Hi M. Khatteb,

Sorry for replying so late. If you provide me an email address, I can send the compiled DLL.

M. Khateeb said...

Hi Norman,
No worries.
Here is my e-mail.
msk476@gmail.com
Thanks again for your help.
M.K.

Followers

About Me

My photo
After graduating from university, I worked as civil engineer for more than 10 years. It was AutoCAD use that led me to the path of computer programming. Although I now do more generic business software development, such as enterprise system, timesheet, billing, web services..., AutoCAD related programming is always interesting me and I still get AutoCAD programming tasks assigned to me from time to time. So, AutoCAD goes, I go.