C#/AutoCAD API

[C#/AutoCAD] Rectangle Jig

Watertight 2023. 9. 8. 06:09

command 'rect'와 동일한 효과를 .net API로 구현하려면 아래의 코드대로 구현한다.

using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Geometry;
using Autodesk.AutoCAD.Runtime;
using static System.Math;
using AcAp = Autodesk.AutoCAD.ApplicationServices.Core.Application;
using AcGi = Autodesk.AutoCAD.GraphicsInterface;

[assembly: CommandClass(typeof(RectangleJigSample.Commands))]

namespace RectangleJigSample
{
    public class Commands
    {
        [CommandMethod("TEST")]
        public void Test()
        {
            var doc = AcAp.DocumentManager.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            var ppr = ed.GetPoint("\nSpecify first corner point: ");
            if (ppr.Status != PromptStatus.OK)
                return;
            var pt = ppr.Value;
            using (var tr = db.TransactionManager.StartTransaction())
            using (var pline = new Polyline(4))
            {
                pline.AddVertexAt(0, new Point2d(pt.X, pt.Y), 0.0, 0.0, 0.0);
                pline.AddVertexAt(1, new Point2d(pt.X + 1.0, pt.Y), 0.0, 0.0, 0.0);
                pline.AddVertexAt(2, new Point2d(pt.X + 1.0, pt.Y + 1.0), 0.0, 0.0, 0.0);
                pline.AddVertexAt(3, new Point2d(pt.X, pt.Y + 1.0), 0.0, 0.0, 0.0);
                pline.Closed = true;
                pline.Elevation = pt.Z;
                var ucs = ed.CurrentUserCoordinateSystem;
                pline.TransformBy(ucs);

                // create a RectangleJig
                var rectJig = new RectangleJig(pline, 0.0);

                // Loop while the user specify other corner or cancel
                while (true)
                {
                    var pr = ed.Drag(rectJig);
                    // Other corner is specified
                    if (pr.Status == PromptStatus.OK)
                    {
                        var curSpace = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
                        curSpace.AppendEntity(pline);
                        tr.AddNewlyCreatedDBObject(pline, true);
                        break;
                    }
                    // Rotation option
                    if (pr.Status == PromptStatus.Keyword)
                    {
                        // use a RotationJig to get the rectangle rotation
                        var rotJig = new RotationJig(pline, pline.GetPoint3dAt(0), pline.Normal);
                        var result = ed.Drag(rotJig);
                        if (result.Status == PromptStatus.OK)
                            rectJig = new RectangleJig(pline, rotJig.Rotation);
                        else
                            break;
                    }
                    // Cancel
                    else
                        break;
                }
                tr.Commit();
            }
        }
    }

    public struct Rectangle
    {
        public Point2d Point0 { get; }
        public Point2d Point1 { get; }
        public Point2d Point2 { get; }
        public Point2d Point3 { get; }

        public Rectangle(Point2d firstCorner, Point2d oppositeCorner, double rotation)
        {
            Vector2d u = new Vector2d(Cos(rotation), Sin(rotation));
            Vector2d v = new Vector2d(-Sin(rotation), Cos(rotation));
            Vector2d diag = firstCorner.GetVectorTo(oppositeCorner);
            Point0 = firstCorner;
            Point1 = firstCorner + u * u.DotProduct(diag);
            Point2 = oppositeCorner;
            Point3 = firstCorner + v * v.DotProduct(diag);
        }
    }

    public class RectangleJig : EntityJig
    {
        Polyline pline;
        double ucsRot, rotation;
        Plane plane;
        Point3d dragPt, basePt;
        Point2d pt2D;
        Editor ed;
        CoordinateSystem3d ucs;

        public RectangleJig(Polyline pline, double rotation) : base(pline)
        {
            this.pline = pline;
            this.rotation = rotation;
            plane = new Plane(Point3d.Origin, pline.Normal);
            basePt = pline.GetPoint3dAt(0);
            pt2D = pline.GetPoint2dAt(0);
            ed = AcAp.DocumentManager.MdiActiveDocument.Editor;
            ucs = ed.CurrentUserCoordinateSystem.CoordinateSystem3d;
            Matrix3d mat = Matrix3d.WorldToPlane(plane);
            ucsRot = Vector3d.XAxis.GetAngleTo(ucs.Xaxis.TransformBy(mat), Vector3d.ZAxis);
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            var msg = "\nSpecify other corner point or [Rotation]: ";
            var options = new JigPromptPointOptions(msg, "Rotation");
            options.AppendKeywordsToMessage = true;
            options.UseBasePoint = true;
            options.BasePoint = basePt;
            options.UserInputControls =
                UserInputControls.Accept3dCoordinates |
                UserInputControls.UseBasePointElevation;
            PromptPointResult result = prompts.AcquirePoint(options);
            if (result.Status == PromptStatus.Keyword)
            {
                pline.TransformBy(Matrix3d.Rotation(-rotation, pline.Normal, basePt));
                return SamplerStatus.OK;
            }
            if (result.Value.IsEqualTo(dragPt))
                return SamplerStatus.NoChange;

            dragPt = result.Value;
            return SamplerStatus.OK;
        }

        protected override bool Update()
        {
            var rectangle = new Rectangle(pt2D, dragPt.Convert2d(plane), rotation + ucsRot);
            pline.SetPointAt(1, rectangle.Point1);
            pline.SetPointAt(2, rectangle.Point2);
            pline.SetPointAt(3, rectangle.Point3);
            return true;
        }
    }

    public class RotationJig : DrawJig
    {
        Entity entity;
        double rotation;
        Point3d basePoint;
        Vector3d normal;

        public double Rotation => rotation;

        public RotationJig(Entity entity, Point3d basePoint, Vector3d normal)
        {
            this.entity = entity;
            this.basePoint = basePoint;
            this.normal = normal;
        }

        protected override SamplerStatus Sampler(JigPrompts prompts)
        {
            var options = new JigPromptAngleOptions("\nSpecify rotation angle: ");
            options.BasePoint = basePoint;
            options.UseBasePoint = true;
            options.Cursor = CursorType.RubberBand;
            options.UserInputControls =
                UserInputControls.Accept3dCoordinates |
                UserInputControls.UseBasePointElevation;
            var result = prompts.AcquireAngle(options);
            if (result.Value == rotation)
                return SamplerStatus.NoChange;
            rotation = result.Value;
            return SamplerStatus.OK;
        }

        protected override bool WorldDraw(AcGi.WorldDraw draw)
        {
            AcGi.WorldGeometry geom = draw.Geometry;
            if (geom != null)
            {
                geom.PushModelTransform(Matrix3d.Rotation(rotation, normal, basePoint));
                geom.Draw(entity);
                geom.PopModelTransform();
            }
            return true;
        }
    }
}

출처 : https://forums.autodesk.com/t5/net/rectanglejig-question/td-p/7412563