cad.net 所有的克隆方式

cad所有克隆方式:

这并不是扫盲贴,而是总结贴...

你可能需要把本博客有关委托的学习看完,并且已经会选择集调用之类的...

内存克隆

最简单的克隆,它可以将图元克隆一份在内存中,不在数据库上,扔掉权限,
所以ObjectId,Handle(句柄),UnmanagedObject(非安全指针)都不一样,实现用后即弃.

Autodesk.AutoCAD.Runtime.RXObject.Clone();

例子: 在多边形视口处理时,你必须要放弃原有视口的多段线,否则会出问题(大概是报错吧...我忘了)

Entity entClone = null; //视口边界
db.Action(tr => 
{
    if (entity is Viewport vp && vp.NonRectClipEntityId.IsOk())
    {
        //取出视口的多边形多段线图元(它是个映射图元)
        using var nonRect = tr.GetObject(vp.NonRectClipEntityId, OpenMode.ForRead) as Entity;
        //克隆边界,会到内存上,不在数据库上
        entClone = nonRect.Clone() as Entity; 
        //以下赋值是为了把边界设置和视口一样,才能显示一致
        entClone.Color = vp.Color;
        entClone.Layer = vp.Layer;
        entClone.Linetype = vp.Linetype;
        entClone.LinetypeScale = vp.LinetypeScale;

        //创建视口or原有视口改
        Viewport vp = new Viewport();
        ObjectId id = tr.AddEntityToMsPs(db, vp);

        vp.NonRectClipEntityId = tr.AddEntityToMsPs(db, ent);//加入多边形线
        vp.NonRectClipOn = true;//不受约束的,多边形视口所需
    }
});
// 然后 entClone 加入到其他数据储存的类

群友 Neil:
此方式不能在用于数据库图元Clone后,再把Clone的加入数据库,
但是new的图元则可以Clone后,再把Clone的加入数据库.
Clone就会把图元置为可写状态,Clone之后就是一个新实体了,可写状态可以理解.
问题是为什么Clone之后的图元不down就会出问题?
而新建一个实体不down就没问题,这就很奇怪了.
至于解决办法就是down一下就行了.
down==entClone.DowngradeOpen()

我也只是用这方法把图元Clone之后等于扔掉了权限管理,
然后再放入数据类中,免得我需要读取的时候存在权限,导致要用事务打开图元...

矩阵复制(绝对不要用)

矩阵复制这个函数会令动态块信息丢失,而李小科居然把它当成教程一部分...

最好用<克隆图元到块表记录>代替.

/// <summary>
/// 复制图形
/// </summary>
/// <param name="entId">图元</param>
/// <param name="sourcePoint">原点</param>
/// <param name="targetPoint">目标点</param>
/// <returns>图元,已加入图形数据库</returns>
public static Entity CopyEntity(this ObjectId entId, Point3d sourcePoint, Point3d targetPoint)
{
    Entity ent2;//声明图形对象 
    using (Transaction tr = entId.Database.TransactionManager.StartTransaction())
    {
        //打开块表
        using BlockTable bt = (BlockTable)tr.GetObject(entId.Database.BlockTableId, OpenMode.ForRead);
        //打开块表记录
        using BlockTableRecord btRec = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite);
        //打开图形
        using Entity ent = (Entity)entId.GetObject(OpenMode.ForWrite);
        //计算变换矩阵
        Vector3d vector = sourcePoint.GetVectorTo(targetPoint);
        Matrix3d mt = Matrix3d.Displacement(vector);
        ent2 = ent.GetTransformedCopy(mt); //复制,返回值 
        btRec.AppendEntity(ent2);
        tr.AddNewlyCreatedDBObject(ent2, true);
        ent.DowngradeOpen();
        btRec.DowngradeOpen();        
        tr.Commit();//提交事务
    }
    return ent2;
}

克隆图元到块表记录

/// <summary>
/// 克隆图元到块表记录(原地克隆)
/// </summary>
/// <param name="tr">事务</param>
/// <param name="objIds">id集合,注意所有id都要在同一个空间中</param>
/// <param name="btRec">
/// <see langword="null"/>克隆到当前块表记录,相当于原地克隆
/// |<see langword="!null"/>内部提权必须<see langword="OpenMode.ForRead"/>,克隆到目标块表记录内,相当于制作新块</param>
/// <returns></returns>
public static List<ObjectId> EntityClone(this Transaction tr, IEnumerable<ObjectId> objIds, BlockTableRecord btRec = null)
{
    var rels = new List<ObjectId>();
    if (objIds.IsNull())
        return rels;

    var objId = objIds.ToArray();
    var db = objId[0].Database;
    if (btRec == null)
        using btRec = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;
    else
        btRec.UpgradeOpen();

    using var mapping = new IdMapping();
    using var blockIds = new ObjectIdCollection(objId);//集合类型更改
    try
    {
        db.DeepCloneObjects(blockIds.Collection, btRec.ObjectId, mapping, false);//深度克隆
        foreach (ObjectId item in blockIds)
        {
            var id = mapping[item].Value;
            rels.Add(id);  //获取克隆键值对(旧块名,新块名)
        }
    }
    catch (System.Exception e)
    {
        var ed = Acap.DocumentManager.MdiActiveDocument.Editor;
        ed.WriteMessage($"{Environment.NewLine}克隆错误: {e.Message}");//可能是Acad08的问题?
    }
    btRec.DowngradeOpen();
    return rels;
}

例子: 创建块参照

db.Action(tr => 
{
    //获得块表记录,只读模式   
    using var bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable;
    bt.UpgradeOpen();

    //添加一个新的块表记录,这个记录将存放块参照的所有图元
    var btrNew = new BlockTableRecord { Name = "北京时间...." };
    bt.Add(btrNew);
    tr.AddNewlyCreatedDBObject(btrNew, true);//添加新创建的数据库对象
    ...获取选择集图元转换为idRankingList省略....
    var ids = tr.EntityClone(idRankingList, btrNew);//克隆一份到新建块
    
    //新建块参照加入到当前空间
    var br = new BlockReference(Point3d.Origin, btrNew.ObjectId)
    using var btrCu = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord;//这里可以处理块编辑器内部
    brId = btrCu.AppendEntity(br);       //加入块表记录
    tr.AddNewlyCreatedDBObject(br, true);//这句如果在变形之后,将导致浩辰不可以选择块,因为空的块参照不能
    //变换图形....
});

克隆时候可能出现一个错误: DeepCloneObjects 会弹出报错 WasErased

我不解,没分析出原因,分裂标注的时候当出现了一种标注,这种标注不能用lisp断分,然后只是某种状态?
选择不了又删除不掉的状态(权限打开未关闭?就直接允许用户交互了??)....关开dwg就会消失这个状态....

貌似这个错误很严重,又不是必显问题..

跨文件克隆图元图块

首先要说明的是:
db.wblock输出 和 db.Insert插入
这两个函数都是建立在 db.wblockcloneobjec 的基础上,所以只需要学习它你就能理解跨文件克隆的方式了.

db.wblock说明:
首先 新建数据库,然后克隆 伪代码:

目标数据库 = new Database();
来源数据库.wblockcloneobjec(目标数据库);

db.Insert说明:
将 旧数据库克隆到当前来 伪代码:

来源数据库 = 后台打开dwg;
目标数据库 = 当前数据库;
来源数据库.wblockcloneobjec(目标数据库);

由于此功能与文章相同,另见: 解决方案2

e大说了一个情况:

他在Arx实现db.wblockcloneobject(msobjids...模型克隆到模型的时候会丢失这些标注,
标注也类似这样的状态,无法修改,但是关开dwg后又正常了....

lisp克隆

;;;name:各种
;;;desc:常量,以全局变量为函数
;;;arg:各种
;;;return:各种
;;;example:各种
(setq
  *En2Obj* vlax-Ename->vla-Object       ;lisp转为vla对象
  *Obj2En* vlax-vla-object->ename       ;vla转lisp对象
  *2PI* (* PI 2)                        ;圆周率*2
  *0.5PI* (/ PI 2)                      ;圆周率*0.5
  *0.25PI* (/ PI 4)                     ;圆周率*0.25
  ;常用VLA对象、集合
  *ACAD* (vlax-get-acad-object)         ;取得CAD作为根对象
  *DOCS* (vla-get-Documents *ACAD*)     ;取得文档集合
  *DOC* (vla-get-ActiveDocument *ACAD*) ;取得当前活动文档
  *MS* (vla-get-modelSpace *DOC*)       ;                的模型空间集合
  *PS* (vla-get-paperSpace *DOC*)       ;                的布局空间集合
  *BLKS* (vla-get-Blocks *DOC*)         ;                的块表
  *LAYS* (vla-get-Layers *DOC*)         ;                的图层集合
  *LTS* (vla-get-Linetypes *DOC*)       ;                的线型集合
  *STS* (vla-get-TextStyles *DOC*)      ;                的字体集合
  *GRPS* (vla-get-groups *DOC*)         ;                的组集合
  *DIMS* (vla-get-DimStyles *DOC*)      ;                的标注集合
  *LOUTS* (vla-get-Layouts *DOC*)       ;                的布局集合
  *VPS* (vla-get-Viewports *DOC*)       ;                的视口集合
  *VS* (vla-get-Views *DOC*)            ;                的图纸集合
  *DICS* (vla-get-Dictionaries *DOC*)   ;                的词典集合
  ;常用的几个外部接口对象
  *FSO* (vlax-get-or-create-object "Scripting.FileSystemObject")
  *WSH* (vlax-get-or-create-object "wscript.shell")
  *SHELL* (vlax-get-or-create-object "Shell.Application");系统程序
  *SCR* (vlax-get-or-create-object "ScriptControl")
  *WBEM* (vlax-get-or-create-object "WbemScripting.SWbemLocator")
  ;防止高版本调整命令
  *CMDF* (if vl-cmdf vl-cmdf command)  ;command-s
  *ERROR-A* vl-catch-all-apply         ;截获错误
  *ERROR-P* vl-catch-all-error-p       ;截获的东西是不是存在错误
  *ERROR-M* vl-catch-all-error-message ;输出错误信息
)

;;;name: BF-CopyBlock
;;;desc: 复制路径中的块到当前图纸
;;;arg:  路径
;;;arg:  块名称
;;;return: 成功当前图纸的块表记录,没有nil
;;;example: (BF-CopyBlock (BF-Catalog "03.用户配置\\00.制图规范.dwg") "SD_剖断线")
(defun BF-CopyBlocks (#DwgName #BlkName / DBXDOC acver aa)
  (setq DBXDOC
        (vla-GetInterfaceObject
           *ACAD*
           (if (< (setq acVer (atoi (getvar "ACADVER"))) 16)
             "ObjectDBX.AxDbDocument"
             (strcat "ObjectDBX.AxDbDocument." (itoa acVer));;增加判断CAD版本
           )
         )
  )
  (if (and (findfile #DwgName);判断是否路径和块名存在
           (not (*ERROR-P* (*ERROR-A* 'vla-open (list DBXDOC #DwgName))));打开没有错误
           (progn
             (vlax-for ^zibiao (vla-get-blocks DBXDOC)
               (if (= #BlkName (vla-get-name ^zibiao));判断DBX图纸含有这个块
                   (setq aa T)
               )
             )
             aa
           );这个progn防止vlax-for运行结束返回nil
      )
      (progn
        (vla-CopyObjects ;深度克隆
          DBXDOC         ;DBX图纸的数据
          (vlax-safearray-fill                                ;保存数据-块表记录的数据保存到新变体中
            (vlax-make-safearray vlax-vbObject'(0 . 0))       ;创建数组;obj类型;上界下界
            (list (vla-item (vla-get-blocks DBXDOC) #BlkName));块表记录
          )
          *BLKS*         ;粘贴到本图的块表中
        )
;;      (progn ;这个只能复制到块内的图元,动态块无法复制
;;         (vla-add *BLKS* (vlax-3d-point '(0 0 0)) bname) ;把块信息加入块集合,基点,块名称->返回块表记录
;;         (setq objs nil);块内图元数量计数器
;;         (vlax-invoke
;;           DBXDOC       ;在DBX中
;;           'CopyObjects ;复制
;;           (vlax-for ^a (vla-item (vla-get-blocks DBXDOC) bname);块集合->块表记录->块内的所有图元
;;             (setq objs (cons ^a objs))
;;           )
;;           (vla-item *BLKS* bname);到本图的块中
;;         )
;;      )
        (vlax-release-object DBXDOC);关闭图纸
        (vla-item *BLKS* #BlkName);返回值
      )
  )
)

(完)

posted @ 2019-04-15 20:48  惊惊  阅读(2577)  评论(3编辑  收藏  举报