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);返回值
)
)
)
(完)