Monday, September 30, 2013

Client side digitize polyline

Triggers are fired on the database when you use the digitize method found within the Topobase API. This forced me to look for a client side alternative to accomplish the same without triggering.
The following class prompts the user to draw a polyline. The result is stored within the class. An event allows you to fetch the result after the command has ended.

The actual class

    /// <summary>
    /// Class that prompts the user to draw a polyline.
    /// When the command has ended it fires an event and the polyline gets cleaned up.
    /// The class holds the result of the user input.
    /// </summary>
    public class DigitizePolyline
    {
        #region Variables & Properties
        private readonly int _startObjectCount;
        private int _endObjectCount;

        public Polyline Polyline { get; private set; }

        /// <summary>
        /// Get the active Autocad drawing document
        /// </summary>
        public Document Document { get { return Application.DocumentManager.MdiActiveDocument; } }
        #endregion

        #region Constructors
        public DigitizePolyline()
        {
            Document.CommandEnded += PlineCommandEnded;
            Document.CommandCancelled += DocOnCommandCancelled;
            _startObjectCount = CountObjects();
        }
        #endregion

        #region Events
        public event EventHandler DrawEnded;
        protected virtual void OnDrawEnded(EventArgs e)
        {
            if (DrawEnded != null)
            {
                DrawEnded(this, e);
            }
        }

        private void DocOnCommandCancelled(object sender, CommandEventArgs e)
        {
            if (e.GlobalCommandName.ToUpper() == "PLINE")
            {
                _endObjectCount = CountObjects();

                if (_endObjectCount != _startObjectCount)
                {
                    //TO DO : Replace this with a method called from the framework!
                    Polyline = GetInsertedPolyLine();
                }

                Remove();

                Document.CommandCancelled -= DocOnCommandCancelled;
                Document.CommandEnded -= PlineCommandEnded;
            }
        }

        private void PlineCommandEnded(object sender, CommandEventArgs e)
        {
            if (e.GlobalCommandName.ToUpper() == "PLINE")
            {
                Polyline = GetInsertedPolyLine();

                Remove();

                Document.CommandEnded -= PlineCommandEnded;
                Document.CommandCancelled -= DocOnCommandCancelled;

                OnDrawEnded(e);
            }
        }
        #endregion

        #region Public Methods
        public void Draw()
        {
            Document.SendStringToExecute("_PLINE ", false, false, false);
        }
        #endregion

        #region Private Methods
        private void Remove()
        {
            if (Polyline != null)
            {
                //Failure to lock the document in certain contexts will cause a lock violation during the modification of the database.
                using (Document.LockDocument())
                {
                    // Start a transaction
                    using (Transaction tr = Document.Database.TransactionManager.StartTransaction())
                    {
                        //Get the entity from the database providing the objectId
                        var ent = tr.GetObject(Polyline.ObjectId, OpenMode.ForWrite) as Entity;
                        //Remove the entity from the database
                        if (ent != null)
                            ent.Erase(true);
                        //Commit the previously opened transaction
                        tr.Commit();
                    }
                }  
            }
        }

        private Polyline GetInsertedPolyLine()
        {
            var lastRes = Document.Editor.SelectLast();

            Polyline pl;
            ObjectId objectId = lastRes.Value[0].ObjectId;

            //To prevent conflicts with other requests, you are responsible for locking a document before you modify it.
            //Failure to lock the document in certain contexts will cause a lock violation during the modification of the database.
            using (Document.LockDocument())
            {
                // Start a transaction
                using (Document.Database.TransactionManager.StartTransaction())
                {
                    //check what sort of entity you are dealing with
                    pl = objectId.GetObject(OpenMode.ForRead) as Polyline;
                }
            }
            return pl;
        }

        public int CountObjects()
        {
            var count = 0;

            using (var tr =
                Document.Database.TransactionManager.StartTransaction())
            {
                using (Document.LockDocument())
                {
                    //Get the BlockTable for the database
                    var blockTable = tr.GetObject(Document.Database.BlockTableId, OpenMode.ForRead) as BlockTable;
                    //Get the modalspace block table record
                    var modalspace =
                        tr.GetObject(blockTable[BlockTableRecord.ModelSpace], OpenMode.ForRead) as BlockTableRecord;

                    if (modalspace != null)
                    {
                        //Loop through the entitys in modelspace
                        count += modalspace.Cast<ObjectId>().Count();
                    }
                }
            }
            return count;
        }
        #endregion
    }

The Class In Action

public class MyCommands
    {
        private DigitizePolyline _digitizePolyline;
        [CommandMethod("DigitizePolyline")]
        public void DigitizePolyline()
        {
            try
            {
                _digitizePolyline = new DigitizePolyline();
                _digitizePolyline.Draw();
                _digitizePolyline.DrawEnded += PlOnDrawEnded;
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
           
        }

        private void PlOnDrawEnded(object sender, EventArgs eventArgs)
        {
            _digitizePolyline.Document.Editor.WriteMessage("Polyline ObjectId = " + _digitizePolyline.Polyline.ObjectId);
        }
    }