September 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        








« Controlling interactive polyline creation - Part 3 | Main | Two methods for selecting entities at a particular location »

November 17, 2006

Advanced jigging with AutoCAD .NET - adding keywords

This post extends the polyline-creation jig shown in the previous entry to support the use of keywords both for arc segments and for undo.

A few notes:

  • I removed the use of a separate vertex list, as it proved to be less necessary than needed
  • This implementation supports Undo, and the toggling between Line segment and Arc segment entry
  • Arc segments have a fixed bulge of 1.0, which is actually quite useful if drawing a cloud, but not really useful for much else. Generally the bulge should be adjusted according to the position of the cursor relative to the previous point, which may be something I attempt in a future post
  • I've also streamlined some of the other parts of code (such as using the basepoint in the jig - which we don't actually need, as we allow the polyline to draw itself)

The code has become quite a bit more complex, and could probably do with some additional performance tuning, but it should allow you to get the idea of what can be done (and one way of approaching it). I should also say that - and this holds true for any of the code samples posted in this blog - it should be thoroughly tested before being integrated into your own application. Hopefully that goes without saying...

Here's the C# code:

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

    {

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

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

      Point3d m_tempPoint;

      Plane m_plane;

      bool m_isArcSeg = false;

      bool m_isUndoing = false;


      // At this stage, weour arc segments will

      // have a fixed bulge of 1.0...

      // Later we may update the routine to determine

      // the bulge based on the relative location

      // of the cursor

      const double kBulge = 1.0;


      public PlineJig(Matrix3d ucs)

        : base(new Polyline())

      {

        // 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;

        AddDummyVertex();

      }


      protected override SamplerStatus Sampler(JigPrompts prompts)

      {

        JigPromptPointOptions jigOpts =

          new JigPromptPointOptions();

        jigOpts.UserInputControls =

          (UserInputControls.Accept3dCoordinates |

          UserInputControls.NullResponseAccepted |

          UserInputControls.NoNegativeResponseAccepted

          );


        m_isUndoing = false;


        Polyline pline = Entity as Polyline;

        if (pline.NumberOfVertices == 1)

        {

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

          jigOpts.Message =

            "\nStart point of polyline: ";

        }

        else if (pline.NumberOfVertices > 1)

        {

          // For subsequent vertices, use a base point

          if (m_isArcSeg)

          {

            jigOpts.SetMessageAndKeywords(

              "\nSpecify endpoint of arc or [Line/Undo]: ",

              "Line Undo"

            );

          }

          else

          {

            jigOpts.SetMessageAndKeywords(

              "\nSpecify next point or [Arc/Undo]: ",

              "Arc Undo"

            );

          }

        }

        else // should never happen

          return SamplerStatus.Cancel;


        // Get the point itself

        PromptPointResult res =

          prompts.AcquirePoint(jigOpts);


        if (res.Status == PromptStatus.Keyword)

        {

          if (res.StringResult == "Arc")

          {

            m_isArcSeg = true;

          }

          else if (res.StringResult == "Line")

          {

            m_isArcSeg = false;

          }

          else if (res.StringResult == "Undo")

          {

            m_isUndoing = true;

          }

          return SamplerStatus.OK;

        }

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

        {

          // Check if it has changed or not

          // (reduces flicker)

          if (m_tempPoint == res.Value)

          {

            return SamplerStatus.NoChange;

          }

          else

          {

            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)

        );


        // If it's supposed to be an arc segment,

        // set the bulge appropriately

        if (m_isArcSeg)

        {

          pline.SetBulgeAt(

            pline.NumberOfVertices-1,

            kBulge

          );

        }

        // Otherwise, it's a line, so set the bulge

        // to zero

        else

        {

          pline.SetBulgeAt(

            pline.NumberOfVertices-1,

            0

          );

        }

        return true;

      }


      public Entity GetEntity()

      {

        return Entity;

      }


      public bool IsArcSegment()

      {

        return m_isArcSeg;

      }


      public bool IsUndoing()

      {

        return m_isUndoing;

      }


      public void AddDummyVertex()

      {

        // Create a new dummy vertex...

        // can have any initial value

        Polyline pline = Entity as Polyline;

        pline.AddVertexAt(

          pline.NumberOfVertices,

          new Point2d(0,0),

          0,0,0

        );

      }


      public void RemoveDummyVertex()

      {

        Polyline pline = Entity as Polyline;

        // Let's first remove our dummy vertex       

        if (pline.NumberOfVertices > 0)

        {

          pline.RemoveVertexAt(pline.NumberOfVertices - 1);

        }

        // And then check the type of the last segment

        if (pline.NumberOfVertices >= 2)

        {

          double blg =

            pline.GetBulgeAt(pline.NumberOfVertices - 2);

          m_isArcSeg = (blg != 0);

        }

      }


      public void AdjustSegmentType(bool isArc)

      {

        // Change the bulge of the previous segment,

        // if necessary

        double bulge = 0.0;

        if (isArc)

          bulge = kBulge;


        Polyline pline = Entity as Polyline;

        if (pline.NumberOfVertices >= 2)

          pline.SetBulgeAt(pline.NumberOfVertices - 2, bulge);

      }

    }


    [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 bPoint = false;

      bool bKeyword = false;

      bool bComplete = false;

      do

      {

        PromptResult res = ed.Drag(jig);

        bPoint =

          (res.Status == PromptStatus.OK);

        // A new point was added

        if (bPoint)

          jig.AddDummyVertex();

        bKeyword =

          (res.Status == PromptStatus.Keyword);

        if (bKeyword)

        {

          if (jig.IsUndoing())

          {

            jig.RemoveDummyVertex();

          }

          else

          {

            jig.AdjustSegmentType(jig.IsArcSegment());

          }

        }

        // Null input terminates the command

        bComplete =

          (res.Status == PromptStatus.None);

        if (bComplete)

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

          jig.RemoveDummyVertex();

      } while ((bPoint || bKeyword) && !bComplete);


      // If the jig completed successfully,

      // add the polyline

      if (bComplete)

      {

        Polyline pline = jig.GetEntity() as Polyline;

        if (pline.NumberOfVertices > 1)

        {

          // 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(pline);

            tr.AddNewlyCreatedDBObject(pline, true);

            tr.Commit();

          }

        }

      }

    }

  }

}

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/6a00d83452464869e200d83538662953ef

Listed below are links to weblogs that reference Advanced jigging with AutoCAD .NET - adding keywords:

blog comments powered by Disqus

Feed/Share

10 Random Posts