development of

Tieghaに関する備忘録とおまけ

オブジェクトスナップをカスタマイズする

オブジェクトスナップを追加する

.NET API によるカスタマイズの一つとして、CustomObjectSnapMode クラスを使用することで、独自のオブジェクトスナップを追加することができます。

今回は、円オブジェクトに対して特定の角度の円周上点にスナップされる、カスタムオブジェクトスナップを追加してみました。

IJCAD にも CustomObjectSnapMode クラスは 存在していますが、IJCAD ではうまくスナップ機能が有効になりませんでしたので、今回のサンプルは AutoCAD 向けです。
ただ ObjectGRX を使用した場合は、 IJCAD でもオブジェクトスナップのカスタマイズは可能でしたので、そのうち .NET API でも AutoCAD と同じように .NET API でもカスタマイズができるようになると思います。

サンプルコード

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: CommandClass(typeof(CustomOSnapSample.CustomOSnap))]
[assembly: ExtensionApplication(typeof(CustomOSnapSample.CustomOSnap))]

namespace CustomOSnapSample
{
    public class CustomOSnap : IExtensionApplication
    {
        /// <summary>スナップされる角度</summary>
        private static double Angle { get; set; }
        /// <summary>グリフの角度</summary>
        private static Vector3d Dir { get; set; }
        /// <summary>表示されるグリフ</summary>
        private static SampleGlyph Glyph { get; set; }
        /// <summary>カスタムオブジェクトスナップの情報</summary>
        private static SampleOSnapInfo Info { get; set; }
        /// <summary>カスタムオブジェクトスナップモード</summary>
        private static CustomObjectSnapMode Mode { get; set; }

        // 初期化処理
        public void Initialize()
        {
            Angle = Math.PI / 4.0;
            Dir = Vector3d.XAxis;
            Glyph = new SampleGlyph();
            Info = new SampleOSnapInfo();
            Mode = new CustomObjectSnapMode("SAMPLEOSNAP", "SAMPLEOSNAP", "Custom object snap sample", Glyph);

            // 円オブジェクトに新しいコールバックを適用する
            Mode.ApplyToEntityType(RXClass.GetClass(typeof(Circle)), new AddObjectSnapInfo(Info.SnapInfoCircle));
        }

        // 終了処理
        public void Terminate()
        {
        }

        // カスタムオブジェクトスナップの有効/無効を切り替える
        [CommandMethod("CUSTOMOSNAP")]
        public void CustomObjectSnap()
        {
            // カスタムオブジェクトスナップが有効かどうか
            if (CustomObjectSnapMode.IsActive("SAMPLEOSNAP"))
            {
                // 有効の場合無効にする
                CustomObjectSnapMode.Deactivate("SAMPLEOSNAP");
            }
            else
            {
                // 無効の場合有効にする
                CustomObjectSnapMode.Activate("SAMPLEOSNAP");
            }
        }

        // スナップされる角度を設定する
        [CommandMethod("SNAPANGLE")]
        public void SnapAngle()
        {
            var ed = Application.DocumentManager.MdiActiveDocument.Editor;
            var opt = new PromptAngleOptions("\n角度を入力");
            opt.DefaultValue = Angle;
            opt.UseDefaultValue = true;
            var res = ed.GetAngle(opt);
            if (res.Status != PromptStatus.OK) return;
            Angle = res.Value;
        }

        /// <summary>カスタムオブジェクトスナップのグリフ</summary>
        public class SampleGlyph : Glyph
        {
            /// <summary>グリフが表示される基準点</summary>
            private Point3d Pt { get; set; }

            public override void SetLocation(Point3d point)
            {
                // 基準点としてスナップ点を取得
                Pt = point;
            }

            protected override void SubViewportDraw(ViewportDraw vd)
            {
                // ビューポートを取得
                var vport = vd.Viewport;
                // 1平方メートルあたりのピクセル数を取得
                var pixels = vport.GetNumPixelsInUnitSquare(Pt);
                // グリフサイズとピクセル数からカメラの高さに合ったグリフの高さを計算
                var glyphHeight = (CustomObjectSnapMode.GlyphSize / pixels.Y) * 2.0;
                // 基準点をWCSからDCSに変換
                var pos = Pt.TransformBy(vport.EyeToWorldTransform);
                // フォントの特性
                var font = new FontDescriptor("Meiryo", false, false, 0, 0);
                // テキストスタイルを作成
                var style = new TextStyle();
                style.Font = font;
                style.TextSize = glyphHeight;
                // テキストのグリフの位置調整用ベクトル
                var vec = (Dir.GetNormal() * glyphHeight / 2.0) + (Dir.GetPerpendicularVector().Negate().GetNormal() * glyphHeight / 2.0);
                // テキストのグリフを表示
                vd.Geometry.Text((pos + vec).TransformBy(vport.EyeToWorldTransform), vport.ViewDirection, Dir, "☜", true, style);
                // 塗りつぶし設定を変更
                vd.SubEntityTraits.FillType = FillType.FillAlways;
                // スナップ位置に黒丸のグリフを表示
                vd.Geometry.Circle(pos, glyphHeight / 4, vport.ViewDirection);
            }
        }

        /// <summary>コールバック用のクラス</summary>
        public class SampleOSnapInfo
        {
            // 円にスナップ
            public void SnapInfoCircle(ObjectSnapContext context, ObjectSnapInfo result)
            {
                // ピックされているオブジェクトを取得
                var circle = context.PickedObject as Circle;
                // オブジェクトが円かどうか
                if (circle == null) return;
                // スナップ点を取得
                var snapPt = circle.GetPointAtParameter(Angle);
                // リザルトにスナップ点を追加
                result.SnapPoints.Add(snapPt);
                // グリフの方向を更新
                Dir = circle.Center.GetVectorTo(snapPt);
            }
        }
    }
}

実行結果


AutoCAD CustomObjectSnap

.NET アセンブリをロードして、ステータスバーから追加したカスタムオブジェクトスナップを有効にすると、円に対して独自のオブジェクトスナップが使用できるようになります。