Kean Walmsley


  • About the Author
    Kean on Google+

August 2014

Sun Mon Tue Wed Thu Fri Sat
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            








« Controlling interactive polyline creation - Part 2 | Main | Advanced jigging with AutoCAD .NET - adding keywords »

November 14, 2006

Controlling interactive polyline creation - Part 3

During the first two parts of this series we looked at different techniques for creating polylines programmatically in AutoCAD (while allowing the user to select the various vertices).

In this post look at the most advanced technique yet, the use of a "Jig". A Jig is a special construct in AutoCAD that hosts an object - in our case a polyline - and feeds user input information into this object, which then determines what graphics gets displayed. This is especially useful when dealing with complex objects, such as polylines with arc segments.

We're going to start with a fairly basic Jig, one that simply collects vertices and creates straight-line segments, but I'd quite like to take this further to support a number of different advanced capabilities: arc segments (which will require keyword implementation), dynamic dimensions, and possibly even undo (a request that just came in as a comment to the previous post).

Anyway, here's the C# code of the basic Jig implementation:

using Autodesk.AutoCAD.ApplicationServices;

using Autodesk.AutoCAD.DatabaseServices;

using Autodesk.AutoCAD.EditorInput;

using Autodesk.AutoCAD.Runtime;

using Autodesk.AutoCAD.Geometry;


namespace MyPlineApp

{

  public class MyPlineCmds

  {

    class PlineJig : EntityJig

    {

      // Maintain a list of vertices...

      // Not strictly necessary, as these will be stored in the

      // polyline, but will not adversely impact performance

      Point3dCollection m_pts;

      // Use a separate variable for the most recent point...

      // Again, not strictly necessary, but easier to reference

      Point3d m_tempPoint;

      Plane m_plane;


      public PlineJig(Matrix3d ucs)

        : base(new Polyline())

      {

        // Create a point collection to store our vertices

        m_pts = new Point3dCollection();


        // Create a temporary plane, to help with calcs

        Point3d origin = new Point3d(0, 0, 0);

        Vector3d normal = new Vector3d(0, 0, 1);

        normal = normal.TransformBy(ucs);

        m_plane = new Plane(origin, normal);


        // Create polyline, set defaults, add dummy vertex

        Polyline pline = Entity as Polyline;

        pline.SetDatabaseDefaults();

        pline.Normal = normal;

        pline.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0);

      }


      protected override SamplerStatus Sampler(JigPrompts prompts)

      {

        JigPromptPointOptions jigOpts =

          new JigPromptPointOptions();

        jigOpts.UserInputControls =

          (UserInputControls.Accept3dCoordinates |

          UserInputControls.NullResponseAccepted |

          UserInputControls.NoNegativeResponseAccepted

          );


        if (m_pts.Count == 0)

        {

          // For the first vertex, just ask for the point

          jigOpts.Message =

            "\nStart point of polyline: ";

        }

        else if (m_pts.Count > 0)

        {

          // For subsequent vertices, use a base point

          jigOpts.BasePoint = m_pts[m_pts.Count - 1];

          jigOpts.UseBasePoint = true;

          jigOpts.Message = "\nPolyline vertex: ";

        }

        else // should never happen

          return SamplerStatus.Cancel;


        // Get the point itself

        PromptPointResult res =

          prompts.AcquirePoint(jigOpts);


        // Check if it has changed or not

        // (reduces flicker)

        if (m_tempPoint == res.Value)

        {

          return SamplerStatus.NoChange;

        }

        else if (res.Status == PromptStatus.OK)

        {

          m_tempPoint = res.Value;

          return SamplerStatus.OK;

        }

        return SamplerStatus.Cancel;

      }


      protected override bool Update()

      {

        // Update the dummy vertex to be our

        // 3D point projected onto our plane

        Polyline pline = Entity as Polyline;

        pline.SetPointAt(

          pline.NumberOfVertices - 1,

          m_tempPoint.Convert2d(m_plane)

        );

        return true;

      }


      public Entity GetEntity()

      {

        return Entity;

      }


      public void AddLatestVertex()

      {

        // Add the latest selected point to

        // our internal list...

        // This point will already be in the

        // most recently added pline vertex

        m_pts.Add(m_tempPoint);

        Polyline pline = Entity as Polyline;

        // Create a new dummy vertex...

        // can have any initial value

        pline.AddVertexAt(

          pline.NumberOfVertices,

          new Point2d(0,0),

          0,0,0

        );

      }


      public void RemoveLastVertex()

      {

        // Let's remove our dummy vertex

        Polyline pline = Entity as Polyline;

        pline.RemoveVertexAt(m_pts.Count);

      }

    }


    [CommandMethod("MYPOLY")]

    public void MyPolyJig()

    {

      Document doc =

        Application.DocumentManager.MdiActiveDocument;

      Editor ed = doc.Editor;


      // Get the current UCS, to pass to the Jig

      Matrix3d ucs =

        ed.CurrentUserCoordinateSystem;


      // Create our Jig object

      PlineJig jig = new PlineJig(ucs);


      // Loop to set the vertices directly on the polyline

      bool bSuccess = true, bComplete = false;

      do

      {

        PromptResult res = ed.Drag(jig);

        bSuccess =

          (res.Status == PromptStatus.OK);

        // A new point was added

        if (bSuccess)

          jig.AddLatestVertex();

        // Null input terminates the command

        bComplete =

          (res.Status == PromptStatus.None);

        if (bComplete)

          // Let's clean-up the polyline before adding it

          jig.RemoveLastVertex();

      } while (bSuccess && !bComplete);


      // If the jig completed successfully, add the polyline

      if (bComplete)

      {

        // Append entity

        Database db = doc.Database;

        Transaction tr =

          db.TransactionManager.StartTransaction();

        using (tr)

        {

          BlockTable bt =

            (BlockTable)tr.GetObject(

              db.BlockTableId,

              OpenMode.ForRead,

              false

            );

          BlockTableRecord btr =

            (BlockTableRecord)tr.GetObject(

              bt[BlockTableRecord.ModelSpace],

              OpenMode.ForWrite,

              false

            );

          btr.AppendEntity(jig.GetEntity());

          tr.AddNewlyCreatedDBObject(jig.GetEntity(), true);

          tr.Commit();

        }

      }

    }

  }

}

That's it for the basic Jig implementation. For further information on Jigs, I suggest taking a look at the "EllipseJig" sample on the ObjectARX SDK (under samples/dotNet) and the ObjectARX Developer's Guide (the C++ documentation is much more extensive for now). I'll also take a closer look in future posts, so please keep your questions coming.

Update

For an updated implementation that supports keywords, arc segments and has better support for non-standard UCS settings, please see this post.

TrackBack

TrackBack URL for this entry:
http://www.typepad.com/services/trackback/6a00d83452464869e200d834c82c2653ef

Listed below are links to weblogs that reference Controlling interactive polyline creation - Part 3:

blog comments powered by Disqus

10 Random Posts