zoukankan      html  css  js  c++  java
  • cad.net 动态编译生成命令+获取在位编辑块内图元

    首先问你一个问题,如果你要用命令改图元颜色,那么cad有256个颜色,你需要写256个命令来达到目的吗?
    答案:不.
    程序员都是喜欢偷懒的.那么如何实现呢?看本文就知道了.

    Lisp和c#的例子有点相似,都是利用了解释器进行动态编译.
    由于想要尽可能兼容所有cad版本,就不采用AddCommand函数,因为低版本没有.
    Arx的例子就有点不一样了,任何版本都有AddCommand函数,触发命令后在函数做对应的操作即可.
    至于c#能不能在 [DllImport "acad.exe" Entpoint ="??"]调用内置arx的AddCommand函数,我就不知道了.
    有知道的可以留言.

    那它有什么可拓展的方向呢?
    可以写一个配置文件作为快速定义命令的文件,例如:

    ls1,螺栓1,./标准/模块.dwg,5,10
    ls2,螺栓2,./标准/模块.dwg,6,20
    ls3,螺栓3,./标准/模块.dwg,7,30...
    

    命令,块名,工具箱某个目录下的dwg文件,插入时候的颜色,动态块拉伸距离(m10螺栓直径)
    我们只需要修改这个配置文件就可以配置多个插入的图块.

    Lisp的例子

    ;;;desc:修改对象颜色
    (apply
      '(lambda ( / cishu feilingyanse) ;匿名函数( 传递变量 / 局部变量 )
         (setq cishu 0)              ;设置循环次数初始值
         (repeat 255                 ;循环次数代表颜色数量
           (setq cishu (1+ cishu)               ;循环计数
                     feilingyanse (itoa cishu) ;循环数转化成字符串
           )
           (eval        ;求值运行程序
             (read      ;去掉双引号,返回整个程序
               (strcat  ;合并多个字符串
                 "(defun c:"
                 feilingyanse   ;颜色
                 " ()(BF-yansemokuai "
                 feilingyanse
                 " ))"
               );注意反义斜杠能去掉引号作用
             )
           )
         )
       )
      nil ;匿名函数,空参数
    )
    
    ;;;name:BF-yansemokuai
    ;;;desc:修改颜色的模板
    ;;;arg:
    ;;;return:
    ;;;example:(BF-yansemokuai 5)
    (defun BF-yansemokuai(tuyuanyanse / ss)
      ;(BF-GO (list 'cmdecho 0) nil 1);出错编组
      (if (setq ss (ssget))
          (progn
            (command "change" ss "" "p" "c" tuyuanyanse "")
            ;;;现在使用命令模式,因vla-put-Color在在位编辑的时候会修改块外.
            ;;;(setq ss (BF-ss->vlass ss));转为vla对象
            ;;;(vlax-for ^se ss ;循环体
            ;;;  (vla-put-Color ^se tuyuanyanse) ;修改颜色
            ;;;);这里会修改到块外面的东西
          )
      )
      ;(BF-End);调用恢复错误处理
    )
    

    c#的例子

    中间段的命令代码,及命令的实现

    #if !HC2020
    using Autodesk.AutoCAD.DatabaseServices;
    using Autodesk.AutoCAD.EditorInput;
    using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
    #else
    using GrxCAD.DatabaseServices;
    using GrxCAD.EditorInput;
    using GrxCAD.Geometry;
    using GrxCAD.ApplicationServices;
    using Acap = GrxCAD.ApplicationServices.Application;
    #endif
    using System;
    using System.Text;
    using JoinBoxCurrency;
    
    
    //要注意.本cs文件的命名空间,类名是和动态编译字符串关联的,要修改的时候记得一起改.
    //AutoGo.JoinBoxEnName = "JoinBox"
    namespace JoinBox
    {
        public class DynamicEntityColor : IAutoGo
        { 
            const string DynamicStr = "DynamicEntityColor";
            public Sequence SequenceId()
            {
                return Sequence.Last;
            }
            public void Terminate()
            {
                try
                {
                    AppDomain.CurrentDomain.AssemblyResolve -= RunTimeCurrentDomain.DefaultAssemblyResolve;
                }
                catch
                {
                    System.Windows.Forms.MessageBox.Show($"动态编译{DynamicStr}卸载出错", "惊惊连盒");
                }
            }
    
    
            // 动态编译命令 
            public void Initialize()
            {
                try
                {
                    AppDomain.CurrentDomain.AssemblyResolve += RunTimeCurrentDomain.DefaultAssemblyResolve;
    
                    var code = new StringBuilder();
                    for (int i = 0; i < 256; i++)
                    {
                        AddDynamicCommand(i.ToString(), code);
                    }
                    DynamicAssembly.Go(code, DynamicStr);
                }
                catch (Exception e)
                {
                    Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;//命令栏交互 
                    ed.WriteMessage(Environment.NewLine + $"动态编译{DynamicStr}出错::" + e.Message);
                }
            }
    
            /// <summary>
            /// 生成编译的命令部分的字符串
            /// </summary> 
            /// <param name="command">命令</param> 
            private void AddDynamicCommand(string command, StringBuilder code)
            {
                code.Append("[CommandMethod("");
                code.Append(command);
                code.Append("", CommandFlags.Modal | CommandFlags.UsePickSet | CommandFlags.Redraw | CommandFlags.DocExclusiveLock)]");
                code.Append("public static void ");
                code.Append($"{DynamicStr}FuncName" + command);
                code.Append("(){");
                code.Append(AutoGo.JoinBoxEnName);
                code.Append($".{DynamicStr}.CommandChangeEntityColor("{command}");");
                code.Append("}");
            }
             
            /// <summary>
            /// 选择图元修改颜色
            /// </summary>
            /// <param name="dwgPath"></param>
            public static void CommandChangeEntityColor(string colorIndex)
            {
                Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;//命令栏交互
                Database db = HostApplicationServices.WorkingDatabase;//当前的数据库 
                ed.WriteMessage("
    这是动态编译的修改图元颜色哟,颜色是::" + colorIndex);
                var psr = ed.GetSelection();//手选
                if (psr.Status != PromptStatus.OK)
                {
                    return;
                }
                db.Action(tr =>
                {
                    foreach (var item in psr.Value.GetObjectIds())
                    {
                        var ent = tr.GetObject(item, OpenMode.ForWrite) as Entity;
                        if (ent != null)
                        {
                            ent.ColorIndex = int.Parse(colorIndex); 
                        }
                    }
                });
            }
        }
    }
    

    执行动态编译

    #if !HC2020
    using Autodesk.AutoCAD.EditorInput;
    using Acap = Autodesk.AutoCAD.ApplicationServices.Application;
    #else
    using GrxCAD.EditorInput;
    using Acap = GrxCAD.ApplicationServices.Application;
    #endif
    using System;
    using System.CodeDom.Compiler;
    using System.IO;
    using System.Text;
    using Microsoft.CSharp;
    
    namespace JoinBox
    {
        public class DynamicAssembly
        {
            /// <summary>
            /// 开始进行编译
            /// </summary>
            /// <param name="midCode">中间的代码段</param>
            /// <param name="dynamicStr">命名空间的字符串</param>
            public static void Go(StringBuilder midCode, string dynamicStr)
            {
                //生成驻留内存的动态程序集
                var pars = new CompilerParameters
                {
                    CompilerOptions = "/target:library /optimize", //编译器选项  
                    GenerateExecutable = false, //生成可执行文件
                    GenerateInMemory = true     //在内存中生成
                };
                var acpath = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory); //获取当前cad运行路径 "C:\Program Files (x86)\AutoCAD 2008\"
                var asslst = pars.ReferencedAssemblies;  //添加引用
    
                //获取程序集的位置
                string configPathAll = Assembly.GetExecutingAssembly().CodeBase;
                configPathAll = codeBase.Substring(8, codeBase.Length - 8);    // 8是file:// 的长度   
                asslst.Add(configPathAll); //当前的dll的路径 "G:/K01.惊惊连盒/net35/JoinBox.dll"
    
                string st = acpath.ToString();
    #if !HC2020
                asslst.Add(st + @"acdbmgd.dll");
                asslst.Add(st + @"acmgd.dll");
    #else
                asslst.Add(st + @"gmap.dll");
                asslst.Add(st + @"gmdb.dll");
    #endif
    #if !HC2020 && !AC2008 && !AC2009 && !AC2010 && !AC2011 && !AC2012
                asslst.Add(st + @"accoremgd.dll");
    #endif
    
                var code = new StringBuilder();
                code.Append("using System;");
                code.Append("using System.Reflection;");
                code.Append("using System.Collections.Generic;");
                code.Append("using System.IO;");
                code.Append("using System.Text;");
    #if !HC2020
                code.Append("using Autodesk.AutoCAD.Runtime;");
                code.Append("using Autodesk.AutoCAD.ApplicationServices;");
                code.Append("using Autodesk.AutoCAD.DatabaseServices;");
                code.Append("using Autodesk.AutoCAD.EditorInput;");
                code.Append("using Autodesk.AutoCAD.Geometry;");
    #else
                code.Append("using GrxCAD.Runtime;");
                code.Append("using GrxCAD.ApplicationServices;");
                code.Append("using GrxCAD.DatabaseServices;");
                code.Append("using GrxCAD.EditorInput;");
                code.Append("using GrxCAD.Geometry;");
    #endif
                code.Append($"using {AutoGo.JoinBoxEnName};");
                code.Append($"namespace {AutoGo.JoinBoxEnName + dynamicStr}");//不给插入到相同命名空间内
                code.Append("{");
                code.Append("public partial class " + dynamicStr + "{");
                code.Append(midCode);
                code.Append("}}");
    
                //编译
                using (var comp = new CSharpCodeProvider())
                {
                    var cr = comp.CompileAssemblyFromSource(pars, code.ToString());
                    if (cr.Errors.HasErrors)
                    {
                        Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor;
                        ed.WriteMessage(Environment.NewLine + $"动态编译{dynamicStr}错误:");
                        foreach (CompilerError err in cr.Errors)
                        {
                            ed.WriteMessage(Environment.NewLine + err.ErrorText);
                        }
                    }
                }
            }
        }
    }
    

    子函数

    RunTimeCurrentDomain.DefaultAssemblyResolve 在:运行域事件
    db.Action 在:委托的学习
    IAutoGo接口 在:cad.net IExtensionApplication接口的妙用

    处理在位编辑块的方法

    在位编辑块时候,块外的图元(褪色的)也可以改到,或许可以通过以下来处理:

    var dm = Application.DocumentManager;
    var md = dm.MdiActiveDocument;
    
    // 命令反应器命令前触发(全局)
    dm.DocumentLockModeChanged += Dc_VetoCommand; 
    // 命令反应器命令后触发
    md.CommandEnded += HatchEvent.Md_CommandEnded;
    
    // 利用命令反应器 Refedit 启动之前创建选择集
    private static List<ObjectId> _refeditSS_Before = new List<ObjectId>() { };
    // 利用命令反应器 Refedit 启动之后做差集,就是在位编辑的时候内部的图元
    private static List<ObjectId> _refeditSS_Interior = new List<ObjectId>() { };
    

    两个反应器写法

    /// <summary>
    /// 反应器->命令否决触发命令前(不可锁文档)
    /// </summary>       
    public static void Dc_VetoCommand(object sender, DocumentLockModeChangedEventArgs e)
    {
        Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
        //这里不可以声明database...不然关闭文档的时候,再打开会引发致命错误
        if (string.IsNullOrEmpty(e.GlobalCommandName) || e.GlobalCommandName == "#")
        {
            return;
        }
        switch (e.GlobalCommandName.ToUpper())
        {
            case "REFEDIT":
                {
                    //在位编辑命令,使用前获取当前空间所有图元
                    PromptSelectionResult prompt = ed.SelectAll(_filter);//全选 
                    if (prompt.Status == PromptStatus.OK)
                    {
                        _refeditSS_Before = prompt.Value.GetObjectIds().ToList();
                    }
                }
                break;
        }
     }
    
    /// <summary>
    /// 反应器->command命令完成后(内锁文档)
    /// </summary>
    public static void Md_CommandEnded(object sender, CommandEventArgs e)
    {
        Editor ed = Application.DocumentManager.MdiActiveDocument.Editor;
        if (string.IsNullOrEmpty(e.GlobalCommandName) || e.GlobalCommandName == "#")
        {
            return;
        }
        switch (e.GlobalCommandName.ToUpper())
        {
            case "REFEDIT":
                {
                    //在位编辑命令,使用后获取当前空间所有图元 
                    PromptSelectionResult prompt = ed.SelectAll(_filter);//全选 
                    if (prompt.Status != PromptStatus.OK)
                    {
                        return;
                    }
                    _refeditSS_Interior = prompt.Value.GetObjectIds().Except(_refeditSS_Before).ToList();
                    foreach (var item in _refeditSS_Interior)
                    {
                        ed.WriteMessage(item.ToString());
                    }
                }
                break;
            case "REFSET": //加减在位编辑图元
                {
                    //完成后必然有上次选择集
                    PromptSelectionResult psr = ed.SelectPrevious();//上次选择集
                    if (psr.Status != PromptStatus.OK)
                    {
                        return;
                    }
                    var ids = psr.Value.GetObjectIds();
                    Database db = ids[0].Database;
                    var haIds = new List<ObjectId>();
                    using (Transaction tr = db.TransactionManager.StartTransaction())
                    {
                        foreach (var item in ids)
                        {
                            Entity ent = item.ToEntity(tr);
                            if (ent is Hatch ha)
                            {
                                haIds.Add(item);
                            }
                        }
                    }
                    if (haIds.Count > 0)
                    {
                        //获取命令历史,最后一行看是加还是减
                        string last = CadSystem.Getvar("lastprompt"); //再获取最后一行命令
    
                        if (last.Contains("添加") || last.Contains("Added"))
                        {
                            _refeditSS_Before = _refeditSS_Before.Except(haIds).ToList();//差集
                            _refeditSS_Interior = _refeditSS_Interior.Union(haIds).ToList();//消重+合并
                        }
                        else if (last.Contains("删除") || last.Contains("Removed"))
                        {
                            _refeditSS_Interior = _refeditSS_Interior.Except(haIds).ToList();//差集
                            _refeditSS_Before = _refeditSS_Before.Union(haIds).ToList();//消重+合并 
                        }
                    }
                }
                break;
            case "REFCLOSE"://保存块,清空集合
                {
                    _refeditSS_Interior.Clear(); 
                }
                break;
        }
    }
    

    Arx的例子

    节选自edata聊天记录,我发现他博客没写过就拿过来了...

    //256个颜色命令
    namespace JJBox命令 {
        //获取变量
        void GetVar(CString command, CString* sCmd)
        {
            struct resbuf var;
            acedGetVar(command, &var);
            //通过指针的方式存入内容
            (*sCmd).Append(var.resval.rstring);
        }
    
        //颜色命令最后都会调用到这个组
        void sk_ChColor()
        {
            CString sCmd;
            GetVar(_T("CMDNAMES"), &sCmd);//获取是什么数字触发的.
    
            if (sCmd == "")
            {
                return;
            }
            int nColor = _ttoi(sCmd);
            if (nColor < 0 || nColor > 256)
            {
                return;
            }
            ads_name ss;
            int nRet = acedSSGet(NULL, NULL, NULL, NULL, ss);
            if (RTCAN == nRet)//取消
            {
                return;
            }
            if (RTNORM != nRet)//回车
            {
                //设置默认颜色
                AcCmColor col;
                col.setColorIndex(nColor);
                acdbHostApplicationServices()->workingDatabase()->setCecolor(col);
            }
    
            Adesk::Int32 nSSLenght = 0;
            acedSSLength(ss, &nSSLenght);
            for (int i = 0; i < nSSLenght; i++)
            {
                ads_name ent;
                AcDbObjectId objId;
                acedSSName(ss, i, ent);
                acdbGetObjectId(objId, ent);
                AcDbEntityPointer pEnt(objId, AcDb::kForWrite);
                if (Acad::eOk != pEnt.openStatus())
                {
                    continue;
                }
                pEnt->setColorIndex(nColor);
            }
        }
    
        //由于是顺序编译,所以这里的命令定义只能够放最下面
        //定义颜色命令
        void jjarx_AddCommands()
        {
            for (int i = 0; i <= 256; i++)
            {
                CString strCmdName;
                strCmdName.Format(_T("%d"), i);
                acedRegCmds->addCommand(_T("sk_ChColor"), strCmdName, strCmdName, ACRX_CMD_TRANSPARENT | ACRX_CMD_USEPICKSET, sk_ChColor);
            }
        }
    }
    

    (完)

  • 相关阅读:
    Appium+python自动化13-native和webview切换【转载】
    Appium+python自动化12-appium元素定位【转载】
    Appium+python自动化11-adb必知必会的几个指令【转载】
    Appium+python自动化10-AVD 模拟器【转载】
    Appium+python自动化9-SDK Manager【转载】
    Appium+python自动化8-Appium Python API【转载】
    Appium+python自动化7-输入中文【转载】
    Appium+python自动化6-Remote远程控制【转载】
    Appium+python自动化5-Appium Inspector【转载】
    Centos-内核核心组成
  • 原文地址:https://www.cnblogs.com/JJBox/p/14487646.html
Copyright © 2011-2022 走看看