仿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内还有内容
}
}
}
}
(未完待续)