cad.net 仿lisp函數專篇


相關閱讀

cad.net 定義lisp與發送同步命令

仿mapcar函數

提供:雪山飛狐

/// <summary>
/// 仿lisp的mapcar函數
/// </summary> 
public static IEnumerable<TR> Mapcar<T1, T2, TR>(IEnumerable<T1> lst1, IEnumerable<T2> lst2, Func<T1, T2, TR> func)
{
    var itor1 = lst1.GetEnumerator();
    var itor2 = lst2.GetEnumerator();
    while (itor1.MoveNext() && itor2.MoveNext())
        yield return func(itor1.Current, itor2.Current);
}

調用

public class TestMapcar
{
    [CommandMethod("tt")]
    public void tt()
    {
        Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;

        var st1 = new List<double> { 1, 2, 3, 4 };
        var st2 = new List<double> { 1, 2, 3, 4 };
        var numbers = Mapcar(st1, st2, (a, b) => a + b);

        foreach (var item in numbers)
        {
            ed.WriteMessage("\n" + item.ToString());
        }
    }
}
=>輸出: 2 4 6 8

您可能還需要C#中的yield關鍵字的參考.
避免判斷yield中使用linq的Count()>0

仿vlax-ldata-get函數

先看lisp如何設置和獲取一個詞典對象:

詞典上面,設置: 詞典名 mydict

(vlax-ldata-put "mydict" "mykey" "Mumbo Dumbo")
=>"Mumbo Dumbo"

詞典上面,獲取: 詞典名 mydict

(vlax-ldata-get "mydict" "mykey")
=>"Mumbo Dumbo"

圖元上面,設置:

(vlax-ldata-put (car (entsel)) "mykey" "Mumbo Dumbo")
=>"Mumbo Dumbo"

圖元上面,獲取:

(vlax-ldata-get (car (entsel)) "mykey")
=>"Mumbo Dumbo"

圖元上面,刪掉:

(vlax-ldata-delete (car (entsel)) "mykey")
=>T

動態調用dll

獲取圖元對象的詞典:參考文章

由於DllImport要寫死dll名稱,所以采取了一種動態調用dll內部方法的方式來進行優化:

#if !HC2020
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
#else
using GrxCAD.DatabaseServices;
using GrxCAD.EditorInput;
using GrxCAD.Runtime;
using Acap = GrxCAD.ApplicationServices.Application;
#endif
using System;
using System.Runtime.InteropServices;
using static Win32API.WinApi;

public struct AdsName
{
    public IntPtr name1;
    public IntPtr name2;
}

namespace JoinBox
{
    public class AcdbAdsHelper
    {
#if NET35
        //Acad2008的AcdbEntGetX參數必須加ref,
        //而Acad2020不用(中間版本沒有測試哦)..所以為了統一,就全部加了
        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acdbEntGet")]
        public static extern IntPtr AcdbEntGet(ref AdsName objName);

        [DllImport("acad.exe", CallingConvention = CallingConvention.Cdecl, EntryPoint = "acdbEntGetX")]
        public static extern IntPtr AcdbEntGetX(ref AdsName objName, IntPtr app);
#else
        [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl,EntryPoint = "acdbEntGet")]
        public static extern IntPtr AcdbEntGet(ref AdsName objName);

        [DllImport("accore.dll", CallingConvention = CallingConvention.Cdecl,EntryPoint = "acdbEntGetX")]
        public static extern IntPtr AcdbEntGetX(ref AdsName objName, IntPtr app);
#endif


#if false  //如果版本號 acdb17.acdb18.acdb19 不確定,那么就采用反射調用
        [DllImport("acdb19.dll", CallingConvention = CallingConvention.Cdecl,
                   EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z")]
        static extern ErrorStatus AcdbGetAdsName32(out AdsName objName, ObjectId id);

        [DllImport("acdb19.dll", CallingConvention = CallingConvention.Cdecl,
               EntryPoint = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z")]
        static extern ErrorStatus AcdbGetAdsName64(out AdsName objName, ObjectId id);
#endif

        public static class Acdb
        {
            static string Version()
            {
                var acadver = Acap.GetSystemVariable("acadver").ToString();
                var ver = acadver.Substring(0, 2);
                return ver;
            }
            public static string AcdbDll()
            {
                return "acdb" + Version() + ".dll";
            }
        }

        /// <summary>
        /// 將ObjectId轉為AdsName
        /// </summary>
        /// <param name="name"></param>
        /// <param name="objId"></param>
        /// <returns></returns>
        public static ErrorStatus AcdbGetAdsName(out AdsName name, ObjectId objId)
        {
            var dllName = Acdb.AcdbDll();
            var hModule = GetModuleHandle(dllName);
            if (hModule == IntPtr.Zero)
                throw new System.Exception("AcdbGetAdsName找不到模塊:" + dllName);

            string funcName;
#if false
            // DllImport調用時候就這么直接調用就好了
            // 但是為了不每個版本都寫一個預處理,所以才去動態調用的方法.
            if (Marshal.SizeOf(IntPtr.Zero) > 4)
                return AcdbGetAdsName64(out name, objId);
            else
                return AcdbGetAdsName32(out name, objId);
#else
            // 但是動態調用就要這樣
            if (Marshal.SizeOf(IntPtr.Zero) > 4)
                funcName =
                    "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z";
            else
                funcName =
                    "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z";
#endif
            //函數指針
            var funcAdress = GetProcAddress(hModule, funcName);
            if (funcAdress == IntPtr.Zero)
                throw new System.Exception("AcdbGetAdsName沒有找到這個函數的入口點:" + funcAdress);

            //利用委托調用函數指針,從而實現對方法的調用
            var delega = Marshal.GetDelegateForFunctionPointer(funcAdress,
                                 typeof(DelegateAcdbGetAdsName)) as DelegateAcdbGetAdsName;
            return delega(out name, objId);
        }

        //委托,調用函數指針用
        delegate ErrorStatus DelegateAcdbGetAdsName(out AdsName name, ObjectId objId);
    }

    public class CmdTest_GetDictClass
    {
        [CommandMethod("CmdTest_GetDict")]
        public void CmdTest_GetDict()
        {
            var dm = Acap.DocumentManager;
            var doc = dm.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            ed.WriteMessage("像lisp一樣獲取ldata");

            var promptEntity = ed.GetEntity("\n請選擇圖元:");
            if (promptEntity.Status != PromptStatus.OK)
                return;

            doc.Database.Action(tr => {
                var obj = tr.GetObject(promptEntity.ObjectId, OpenMode.ForRead);

                //獲取對象的擴展字典
                if (!obj.ExtensionDictionary.IsOk())
                    return;

                var objExDic = tr.GetObject(obj.ExtensionDictionary, OpenMode.ForRead) as DBDictionary;
                if (objExDic == null)
                    return;

                var at = objExDic.GetAt("mykey");              //詞條id
                var bp = tr.GetObject(at, OpenMode.ForRead);   //詞條對象

                var rb = new ResultBuffer();
                AcdbAdsHelper.AcdbGetAdsName(out AdsName m_EName, bp.ObjectId);
                var getx = AcdbAdsHelper.AcdbEntGetX(ref m_EName, rb.UnmanagedObject);
                if (getx == IntPtr.Zero)
                    return;
                rb = ResultBuffer.Create(getx, true);
                ed.WriteMessage(rb.ToString());
            });
        }
    }
}

一些必要的win32API:

/// <summary>
/// 獲取一個應用程序或dll的模塊句柄
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr GetModuleHandle(string name);

/// <summary>
/// 獲取要引入的函數,將符號名或標識號轉換為DLL內部地址
/// </summary>
/// <param name="hModule">exe/dll句柄</param>
/// <param name="procName">接口名</param>
/// <returns></returns>
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true)]
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);

得到結果:

((-1,(-2173632))(0,VLO-VL)(5,1E0)(102,{ACAD_REACTORS)(330,(-2173640))(102,})(330,(-2173640))(100,vlo_VL)(90,-64512)(91,13)(92,0)(300,"Mumbo Dumbo"))

仿ssnamex函數

#if !HC2020
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
#else
using GrxCAD.DatabaseServices;
using GrxCAD.EditorInput;
using GrxCAD.Runtime;
using Acap = GrxCAD.ApplicationServices.Application;
#endif

using System;
using System.Diagnostics;

namespace JoinBox
{
    public class CmdTest_SSNamexClass
    {
        [CommandMethod("CmdTest_SSNamex", CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw)]
        public void CmdTest_SSNamex()
        {
            var dm = Acap.DocumentManager;
            var doc = dm.MdiActiveDocument;
            var db = doc.Database;
            var ed = doc.Editor;
            ed.WriteMessage(Environment.NewLine + "****驚驚連盒-仿lisp的ssnamex測試選擇集的點選位置和點選方式");

            var filList = new TypedValue[]
            {
               // new TypedValue((int)DxfCode.Start, "INSERT")
            };
            var filter = new SelectionFilter(filList);
            var pso = new PromptSelectionOptions
            {
                RejectObjectsOnLockedLayers = true, //不選擇鎖定圖層對象
                AllowDuplicates             = true, //不允許重復選擇
            };
            var ssPsr = ed.GetSelection(pso, filter);//手選
            if (ssPsr.Status != PromptStatus.OK)
                return;

            foreach (var vaItem in ssPsr.Value)
            {
                if (vaItem is CrossingOrWindowSelectedObject cows)//框選方式
                {
                    foreach (var ppd in cows.GetPickPoints())
                        Debug.WriteLine(ppd.PointOnLine);//ppd內還有內容
                }
                else if (vaItem is PickPointSelectedObject pps)//點選方式
                    Debug.WriteLine(pps.PickPoint);            //pps內還有內容
            }

            //獲取所有的id
            //foreach (var item in ssPsr.Value.GetObjectIds())
            //    Debug.WriteLine(item);
        }
    }
}

(未完待續)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM