Author Topic: Custom osnap  (Read 2291 times)

0 Members and 1 Guest are viewing this topic.

gile

  • Gator
  • Posts: 2520
  • Marseille, France
Custom osnap
« on: January 22, 2010, 06:54:58 AM »
Hi,

I'm trying to create some custom osnaps and I'd like them to be transparently callable as the built in ones.

Here's an example which adds a snap on polyline centroid. I can get it work for lines polylines invoking 'CTR on each prompt for a point, but it doesn' work for the third point in the ARC command (3points) nor for the second point of the RECTANG command.

As anyone an idea ?

Thanks

Code: [Select]
using System;
using Autodesk.AutoCAD.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.GraphicsInterface;
using Autodesk.AutoCAD.Runtime;

[assembly: ExtensionApplication(typeof(CentroidOsnap.CtrOsnap))]

namespace CentroidOsnap
{
    public class CtrOsnap : IExtensionApplication
    {
        private CtrOsnapInfo m_info = new CtrOsnapInfo();
        private CtrGlyph m_glyph = new CtrGlyph();
        private CustomObjectSnapMode m_mode;

        public void Initialize()
        {
            m_mode = new CustomObjectSnapMode("Centroid", "Centroid", "Centroid", m_glyph);
            m_mode.ApplyToEntityType(
                RXObject.GetClass(typeof(Polyline)),
                new AddObjectSnapInfo(m_info.SnapInfoPolyline));
            m_mode.ApplyToEntityType(
                RXObject.GetClass(typeof(Entity)),
                new AddObjectSnapInfo(m_info.SnapInfoEntity));
        }

        public void Terminate()
        {
            if (Command.Status == 1)
                CustomObjectSnapMode.Deactivate("_Centroid");
        }
    }

    public class Command
    {
        Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
        private static int m_status = 0;
        private bool m_tmp = false;
        private object m_osmode;

        public static int Status
        {
            get { return m_status; }
            set { m_status = value; }
        }

        [CommandMethod("CTROSNAP")]
        public void PermCtrOsnap()
        {
            PromptIntegerOptions pio = new PromptIntegerOptions(
                "\nEnter an new value for Centroid Osnap: ");
            pio.DefaultValue = m_status;
            pio.LowerLimit = 0;
            pio.UpperLimit = 1;
            pio.UseDefaultValue = true;
            PromptIntegerResult pir = ed.GetInteger(pio);
            if (pir.Status != PromptStatus.OK)
                return;
            if (m_status == pir.Value)
                return;
            m_status = pir.Value;
            if (m_status == 1)
                CustomObjectSnapMode.Activate("_Centroid");
            else
                CustomObjectSnapMode.Deactivate("_Centroid");
        }

        [CommandMethod("CTR", CommandFlags.Transparent)]
        public void TmpCtrOsnap()
        {
            m_osmode = Application.GetSystemVariable("OSMODE");
            Application.SetSystemVariable("OSMODE", 0);
            ed.PromptedForPoint += new PromptPointResultEventHandler(ed_PromptedForPoint);
            if (m_status == 0 && !m_tmp)
                CustomObjectSnapMode.Activate("_Centroid");
            m_tmp = true;
        }

        void ed_PromptedForPoint(object sender, PromptPointResultEventArgs e)
        {
            Application.SetSystemVariable("OSMODE", m_osmode);
            ed.PromptedForPoint -= new PromptPointResultEventHandler(ed_PromptedForPoint);
            if (m_status == 0)
                CustomObjectSnapMode.Deactivate("_Centroid");
            m_tmp = false;
        }
    }

    public class CtrGlyph : Glyph
    {
        private Point3d m_pt;

        public override void SetLocation(Point3d point)
        {
            m_pt = point;
        }

        public override void ViewportDraw(ViewportDraw vd)
        {
            int glyphPixels = CustomObjectSnapMode.GlyphSize;
            Point2d glyphSize = vd.Viewport.GetNumPixelsInUnitSquare(m_pt);
            double distance = (glyphPixels / glyphSize.Y) * 0.75;
            Matrix3d e2w = vd.Viewport.EyeToWorldTransform;
            vd.Geometry.Circle(m_pt.TransformBy(e2w), distance, vd.Viewport.ViewDirection);
        }
    }

    public class CtrOsnapInfo
    {
        public void SnapInfoPolyline(ObjectSnapContext context, ObjectSnapInfo result)
        {
            Polyline pl = context.PickedObject as Polyline;
            if (pl == null)
                return;
            result.SnapPoints.Add(PolylineCentroid.GetCentroid(pl));
        }

        public void SnapInfoEntity(ObjectSnapContext context, ObjectSnapInfo result)
        {
        }
    }

    public class PolylineCentroid
    {
        public static Point3d GetCentroid(Polyline pl)
        {
            Point2d p0 = pl.GetPoint2dAt(0);
            Point2d cen = new Point2d(0.0, 0.0);
            double area = 0.0;
            double bulge = pl.GetBulgeAt(0);
            int last = pl.NumberOfVertices - 1;
            double tmpArea;
            Point2d tmpPoint;

            if (bulge != 0.0)
            {
                double[] datas = GetArcGeom(pl, bulge, 0, 1);
                area = datas[0];
                cen = new Point2d(datas[1], datas[2]) * datas[0];
            }
            for (int i = 1; i < last; i++)
            {
                tmpArea = TriangleAlgebricArea(p0, pl.GetPoint2dAt(i), pl.GetPoint2dAt(i + 1));
                tmpPoint = TriangleCentroid(p0, pl.GetPoint2dAt(i), pl.GetPoint2dAt(i + 1));
                cen += (tmpPoint * tmpArea).GetAsVector();
                area += tmpArea;
                bulge = pl.GetBulgeAt(i);
                if (bulge != 0.0)
                {
                    double[] datas = GetArcGeom(pl, bulge, i, i + 1);
                    area += datas[0];
                    cen += new Vector2d(datas[1], datas[2]) * datas[0];
                }
            }
            bulge = pl.GetBulgeAt(last);
            if (bulge != 0.0)
            {
                double[] datas = GetArcGeom(pl, bulge, last, 0);
                area += datas[0];
                cen += new Vector2d(datas[1], datas[2]) * datas[0];
            }
            cen = cen.DivideBy(area);
            Point3d result = new Point3d(cen.X, cen.Y, pl.Elevation);
            return result.TransformBy(Matrix3d.PlaneToWorld(pl.Normal));
        }

        public static double[] GetArcGeom(Polyline pl, double bulge, int index1, int index2)
        {
            CircularArc2d arc = (pl.GetArcSegment2dAt(index1));
            double arcRadius = arc.Radius;
            Point2d arcCenter = arc.Center;
            double arcAngle = 4.0 * Math.Atan(bulge);
            double tmpArea = ArcAlgebricArea(arcRadius, arcAngle);
            Point2d tmpPoint = ArcCentroid(pl.GetPoint2dAt(index1), pl.GetPoint2dAt(index2), arcCenter, tmpArea);
            return new double[3] { tmpArea, tmpPoint.X, tmpPoint.Y };
        }

        public static Point2d TriangleCentroid(Point2d p0, Point2d p1, Point2d p2)
        {
            return (p0 + p1.GetAsVector() + p2.GetAsVector()) / 3.0;
        }

        public static double TriangleAlgebricArea(Point2d p0, Point2d p1, Point2d p2)
        {
            return (((p1.X - p0.X) * (p2.Y - p0.Y)) - ((p2.X - p0.X) * (p1.Y - p0.Y))) / 2.0;
        }

        public static Point2d ArcCentroid(Point2d start, Point2d end, Point2d cen, double area)
        {
            double chord = start.GetDistanceTo(end);
            double angle = (end - start).Angle;
            return Polar2d(cen, angle - (Math.PI / 2.0), (chord * chord * chord) / (12.0 * area));
        }

        public static double ArcAlgebricArea(double rad, double ang)
        {
            return rad * rad * (ang - Math.Sin(ang)) / 2.0;
        }

        public static Point2d Polar2d(Point2d org, double angle, double distance)
        {
            return new Point2d(org.X + distance * Math.Cos(angle), org.Y + distance * Math.Sin(angle));
        }
    }
}
« Last Edit: January 22, 2010, 07:22:07 AM by gile »
Speaking English as a French Frog

Kerry

  • Mesozoic relic
  • Seagull
  • Posts: 11654
  • class keyThumper<T>:ILazy<T>
Re: Custom osnap
« Reply #1 on: January 22, 2010, 07:22:22 AM »


gile
no ideas, sorry

kerry
kdub, kdub_nz in other timelines.
Perfection is not optional.
Everything will work just as you expect it to, unless your expectations are incorrect.
Discipline: None at all.

gile

  • Gator
  • Posts: 2520
  • Marseille, France
Re: Custom osnap
« Reply #2 on: January 22, 2010, 07:23:56 AM »
Thanks anayway, Kerry
Speaking English as a French Frog