Monday, March 23, 2015

Centroid ObjectSnap

During drafting process, sometimes an AutoCAD user would wish he.she could easily find out where the centroid of an polygon (assuming it is a closed Polyline), and better yet, he/she could snap the mouse cursor at the centroid.

With Autodesk.AutoCAD.DatabaseServices.OspanOverrule, this is actually a very easy achievable thing to do. 

Here is the code sample of the custom OsnapOverrule:

using System;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
 
namespace CentroidSnap
{
    public class MyCentroidSnap : OsnapOverrule 
    {
        private static MyCentroidSnap _instance = null;
        private bool _overruling = false;
        private bool _started = false;
 
        public static MyCentroidSnap Instance
        {
            get
            {
                if (_instance == null) _instance = new MyCentroidSnap();
                return _instance;
            }
        }
 
        public bool Started
        {
            get { return _started; }
        }
 
        public void StartOSnap()
        {
            _overruling = Overruling;
 
            Overrule.AddOverrule(RXClass.GetClass(typeof(Curve)), thistrue);
            Overruling = true;
            _started = true;
        }
 
        public void StopOSnap()
        {
            Overrule.RemoveOverrule(RXClass.GetClass(typeof(Curve)), this);
            Overruling = _overruling;
            _started = false;
        }
 
        #region overriden methods
 
        public override void GetObjectSnapPoints(
            Entity entity, ObjectSnapModes snapMode, IntPtr gsSelectionMark,
            Point3d pickPoint, Point3d lastPoint, Matrix3d viewTransform,
            Point3dCollection snapPoints, IntegerCollection geometryIds)
        {
            bool hasCentre = true;
            Point3d snapPt = new Point3d();
 
            if (entity is Polyline)
            {
                Polyline pl = (Polyline)entity;
                if (pl.Closed)
                {
                    snapPt = GetPolylineCentre(pl);
                }
                else
                {
                    hasCentre = false;
                }
            }
            else if (entity is Circle)
            {
                snapPt = ((Circle)entity).Center;
            }
            else
            {
                hasCentre = false;
            }
            
            if (hasCentre)
            {
                //Clear all possible existing snap points
                snapPoints.Clear();
 
                //Set OSnap mode to NEA
                snapMode = ObjectSnapModes.ModeNear;
                snapPoints.Add(snapPt);
            }
        }
 
        public override bool IsContentSnappable(Entity entity)
        {
            return false;
        }
 
        #endregion
 
        #region private methods
 
        private Point3d GetPolylineCentre(Polyline pl)
        {
            double x = 0.0, y = 0.0, z = 0.0;
            for (int i=0; i<pl.NumberOfVertices; i++)
            {
                Point3d p = pl.GetPoint3dAt(i);
                x += p.X;
                y += p.Y;
                z += p.Z;
            }
 
            return new Point3d(
                x / pl.NumberOfVertices, 
                y / pl.NumberOfVertices, 
                z / pl.NumberOfVertices);
        }
 
        #endregion
    }
}

Here is the command class to start/stop the custom MyCentroidSnap overrule:

using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using CadApp = Autodesk.AutoCAD.ApplicationServices.Application;
 
[assemblyCommandClass(typeof(CentroidSnap.MyCadCommands))]
 
namespace CentroidSnap
{
    public class MyCadCommands 
    {
 
        [CommandMethod("CSnap")]
        public static void RunMyCadCommand()
        {
            Document dwg = CadApp.DocumentManager.MdiActiveDocument;
            Editor ed = dwg.Editor;
 
            if (!MyCentroidSnap.Instance.Started)
            {
                MyCentroidSnap.Instance.StartOSnap();
                ed.WriteMessage(
                    "\nMYCentroidOSnap is started.");
            }
            else
            {
                MyCentroidSnap.Instance.StopOSnap();
                ed.WriteMessage(
                    "\nMYCentroidOSnap is stopped.");
            }
 
            Autodesk.AutoCAD.Internal.Utils.PostCommandPrompt();
        }
    }
}

I also posted on the same topic a couple of years ago herehere and here. Obviously, I could have also create this MyCentroidSnap class by deriving it from Autodesk.AutoCAD.GraphicsInterface.Glyph class. 

As usual, see this video clip for the MyCentroidSnap's action.

1 comment:

asd said...

Hi, I would like to ask you some things. Please contact me if ever. Thank You

email: d.richardcarl@gmail.com

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.