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
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));
}
}
}