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("
" + 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.ApplicationServices;
using Autodesk.AutoCAD.DatabaseServices;
using Autodesk.AutoCAD.EditorInput;
using Autodesk.AutoCAD.Runtime;
using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
#endif
using System;
using System.Runtime.InteropServices;
using static JoinBox.src.试验库.AcdbAdsTool;

namespace JoinBox.src.试验库
{
    public class AcdbAdsTool
    { 
#if AC2008 
        public struct AdsName
        {
            public IntPtr name1;
            public IntPtr name2;
        }

        //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
        {
            public 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)
        {
           //获取不同版本的cad版本号
            var dllName = Acdb.AcdbDll();
            IntPtr 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
            // 动态调用就要这样
            // funcName就是DllImport的Entrypoint
            if (Marshal.SizeOf(IntPtr.Zero) > 4)
            {
                funcName = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AEAY01_JVAcDbObjectId@@@Z";
            }
            else
            {
                funcName = "?acdbGetAdsName@@YA?AW4ErrorStatus@Acad@@AAY01JVAcDbObjectId@@@Z";
            }
#endif 
            //函数指针
            IntPtr funcAdress = GetProcAddress(hModule, funcName);
            if (funcAdress == IntPtr.Zero)
                throw new System.Exception("AcdbGetAdsName没有找到这个函数的入口点:" + funcAdress);

            //利用委托调用函数指针,从而实现对方法的调用.
            var deFunc = Marshal.GetDelegateForFunctionPointer(funcAdress, typeof(DelegateAcdbGetAdsName)) as DelegateAcdbGetAdsName;
            return deFunc(out name, objId);
        }

        //委托,调用函数指针
        delegate ErrorStatus DelegateAcdbGetAdsName(out AdsName name, ObjectId objId);
    }

    public class TestGetIdata
    {
        [CommandMethod("tt")]
        public void CB_GetDict()
        {
            Document doc = Acap.DocumentManager.MdiActiveDocument;
            Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;

            var promptEntity = ed.GetEntity("
请选择图元:");
            if (promptEntity.Status != PromptStatus.OK) return;

            using (Transaction tr = doc.Database.TransactionManager.StartTransaction())
            {
                DBObject 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;
                }

                //词条id
                ObjectId at = objExDic.GetAt("mykey");
                //词条对象
                DBObject bp = tr.GetObject(at, OpenMode.ForRead);

                var rb = new ResultBuffer();
                AcdbGetAdsName(out AdsName m_EName, bp.ObjectId);
                IntPtr getx = 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函数

public class TestSsnamex
{
    //获取选择的方式和选择的角点
    [CommandMethod("tt_getssgetpick", CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw)]
    public void tt_getssgetpick()
    {
        Database db = HostApplicationServices.WorkingDatabase;//当前的数据库
        Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;
        ed.WriteMessage(Environment.NewLine + "****惊惊连盒-测试选择集的点选位置和点选方式");

        var tkids = new List<ObjectId>();

        //创建选择集过滤器,只选择块对象
        TypedValue[] filList = new TypedValue[]
        {
            // new TypedValue((int)DxfCode.Start, "INSERT")
        };

        SelectionFilter 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 item in ssPsr.Value.GetObjectIds())
        //{
        //    Debug.WriteLine(item);//所有的角点信息 
        //}

        var va = ssPsr.Value;
        foreach (var vaItem in va)
        {
            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内还有内容
            }
        } 
    }
}

(未完待续)

原文地址:https://www.cnblogs.com/JJBox/p/12426728.html