cad.net 外部参照和相对路径转换
外部参照
namespace JoinBox;
public class XrefCommands {
[CommandMethod(nameof(CmdAttachXref))]
public void CmdAttachXref() {
Env.Print("\n插入附着参照到当前图纸");
var xMap = XrefHelper.GetXrefPair(db)
.ToDictionary(pair => pair.Key);
using DBTrans tr = new(db);
var filePath = @"D:\桌面\01.饰施图\03.平面图\01.平面图.dwg";
var fileNameWE = System.IO.Path.GetFileNameWithoutExtension(filePath);
// 附着外部参照 参照名称已存在就会报错
if (xMap.ContainsKey(fileNameWE))
return;
var acXrefId = tr.Database.AttachXref(filePath, fileNameWE);
// 有效引用则继续
if (acXrefId.IsNull) return;
// 插入的基点
var brf = new BlockReference(new Point3d(0, 0, 0), acXrefId);
// 用事务栈加入
db.CurrentSpace.UpgradeOpen();
db.CurrentSpace.AppendEntity(brf);
tr.AddNewlyCreatedDBObject(brf, true);
}
[CommandMethod(nameof(CmdChangeXref))]
public void CmdChangeXref() {
Env.Print("\n卸载/重载/拆离/绑定");
SetXref(db, MyXrefStatus.UnloadXrefs);
SetXref(db, MyXrefStatus.ReloadXrefs);
SetXref(db, MyXrefStatus.DetachXref);
SetXref(db, MyXrefStatus.BindXrefs);
}
// 获取外部参照引用,
// 转为多叉树节点,判断是否构成环
[CommandMethod(nameof(CmdGetXrefFile))]
public void CmdGetXrefFile() {
Env.Print("\n外部参照是否构成环");
// map<数据库路径, 外部参照路径>
var map = new Dictionary<string, HashSet<string>>();
var db = HostApplicationServices.WorkingDatabase;
XrefHelper.GetXrefFile(db, map);
foreach(var pair in pair) {
Env.Print(pair.Key);
}
}
[CommandMethod(nameof(CmdChangeToOverlay))]
public void CmdChangeToOverlay() {
Env.Print("\n外部参照是附加型就设置为覆盖型");
using DBTrans tr = new();
tr.BlockTable.ForEach(btRec => {
// 不是外部参照,跳过
if (!btRec.IsFromExternalReference) return;
btRec.UpgradeOpen();
btRec.IsFromOverlayReference = true;
/* 这是什么?
var xdb = btRec.GetXrefDatabase(false);
if (xdb is null) return;
// 恢复原始外部参照符号表
// 撤销对外部参照的所有操作
xdb.RestoreOriginalXrefSymbols();
// 恢复转发外部参照符号表,
// 真正撤销对外部参照的修改到分离状态
xdb.RestoreForwardingXrefSymbols();
*/
}
}
}
[Flags]
public enum MyXrefStatus : int {
[Description("卸载")]
UnloadXrefs,
[Description("重载")]
ReloadXrefs,
[Description("拆离")]
DetachXref,
[Description("绑定")]
BindXrefs
}
public static class XrefHelper {
public static IEnumerable<KeyValuePair<string, ObjectId>> GetXrefPair(Database db) {
// 解析外部参照(线性引擎,只做新的)
db.ResolveXrefs(false, true);
// 参数:包含僵尸参照
var xg = db.GetHostDwgXrefGraph(true);
for (int i = 0; i < xg.NumNodes; i++) {
var xNode = (XrefGraphNode)xg.GetXrefNode(i);
var xId = xNode.BlockTableRecordId;
if (!DBTrans.IsOk(xId)) continue;
// xNode.XrefStatus != XrefStatus.Resolved // 状态判断
// xNode.IsNested // 是嵌套参照
yield return new KeyValuePair<string, ObjectId>(xNode.Name, xId);
}
}
// 获取有效的外部参照,避免获取包围盒报错
public static IEnumerable<KeyValuePair<string, ObjectId>> GetXrefPairForValid(Database db) {
var pairs = XrefHelper.GetXrefPair(db);
using var tr = new DBTrans(db);
foreach(var pair in pairs) {
using var btRec = (BlockTableRecord)tr.GetObject(pair.Value);
if (btRec.XrefStatus is XrefStatus.FileNotFound or XrefStatus.Unresolved)
continue;
yield return pair;
}
}
// 获取已经丢失/未加载的外部参照
public static IEnumerable<KeyValuePair<string, ObjectId>> GetXrefPairForInvalid(Database db) {
var pairs = XrefHelper.GetXrefPair(db);
using var tr = new DBTrans(db);
foreach(var pair in pairs) {
using var btRec = (BlockTableRecord)tr.GetObject(pair.Value);
if (btRec.XrefStatus is XrefStatus.FileNotFound or XrefStatus.Unresolved)
yield return pair;
}
}
public static void GetXrefFile(Database db, Dictionary<string, HashSet<string>> map) {
var xIds = XrefHelper.GetXrefPairForValid(db)
.Select(pair => pair.Value)
.ToHashSet();
HashSet<Database> dbset = new();
using (var tr = new DBTrans(db)) {
foreach(var xId in xIds) {
using var btRec = (BlockTableRecord)tr.GetObject(xId);
var xdb = btRec.GetXrefDatabase(false);
if (xdb is not null) dbset.Add(xdb);
}
}
// 处理过的外部参照跳过,它表示成为环了.
var xdbs = dbset.Where(xdb => !map.ContainsKey(xdb.Filename));
foreach(var xdb in xdbs) {
if (!map.TryGetValue(db.Filename, out var files)) {
files = new();
map.Add(db.Filename, files);
}
files.Add(xdb.Filename);
GetXrefFile(xdb, map);
}
}
/// <summary>
/// 修改外部参照
/// </summary>
/// <param name="db">数据库</param>
/// <param name="xe">设置的枚举状态</param>
/// <param name="nameSet">要获取参照名称,null获取所有</param>
public static void SetXref(Database db, MyXrefStatus xe, HashSet<string>? nameSet = null) {
var xIds = XrefHelper.GetXrefPair(db);
if (nameSet is not null) {
xIds = xIds.Where(pair => nameSet.Contains(pair.Key))
}
var ids = xIds.Select(pair => pair.Value).ToList();
if (ids.Count == 0) return;
switch (xe) {
case MyXrefStatus.BindXrefs: // 绑定后会自动拆离
using var idc = new ObjectIdCollection(ids);
db.BindXrefs(idc, true);
break;
case MyXrefStatus.DetachXref: // 拆离
foreach (ObjectId item in ids)
db.DetachXref(item);
break;
case MyXrefStatus.UnloadXrefs: // 卸载
using var idc = new ObjectIdCollection(ids);
db.UnloadXrefs(idc);
break;
case MyXrefStatus.ReloadXrefs: // 重载
using var idc = new ObjectIdCollection(ids);
db.ReloadXrefs(idc);
break;
}
}
}
相对路径转换
using System;
using System.IO;
using System.Linq;
using System.Text;
namespace JoinBox.BasalCurrency;
public static partial class StringHelper {
// https://blog.csdn.net/my98800/article/details/51450696
// https://blog.csdn.net/lishuangquan1987/article/details/53678215
// https://www.cnblogs.com/hont/p/5412340.html
#if true
// StringHelper.GetRelativePath(@"D:\MyProj\Release", @"D:\MyProj\Log\MyFile.txt");
// StringHelper.GetRelativePath("G:\\A1.项目\\20190920金山谷黄宅\\01.饰施图\\03.平面图", "G:\\A1.项目\\20190920金山谷黄宅\\01.饰施图\\01.辅助文件\\图框\\A3图框.dwg");
/// <summary>
/// 绝对路径->相对路径
/// </summary>
/// <param name="strDbPath">绝对路径</param>
/// <param name="strXrefPath">相对关系</param>
/// <returns></returns>
public static string GetRelativePath(string strDbPath, string strXrefPath) {
string[] strDbPaths = strDbPath.Split('\\');
string[] strXrefPaths = strXrefPath.Split('\\');
// 获取两条路径中的最短路径
int length = strDbPaths.Length < strXrefPaths.Length ?
strDbPaths.Length : strXrefPaths.Length;
// 用于确定我们退出的循环中的位置。
int lastCommonRoot = -1;
int index;
// 找到共根
for (index = 0; index < length; index++) {
if (strDbPaths[index] == strXrefPaths[index])
lastCommonRoot = index;
else
break;
}
// 如果我们没有找到一个共同的前缀,那么抛出
if (lastCommonRoot == -1)
throw new ArgumentException("路径没有公共相同路径部分");
// 建立相对路径
var sb = new StringBuilder();
for (index = lastCommonRoot + 1; index < strDbPaths.Length; index++) {
if (strDbPaths[index].Length > 0)
sb.Append("..\\"); // 上级目录加入
}
// 添加文件夹
for (index = lastCommonRoot + 1; index < strXrefPaths.Length - 1; index++)
sb.Append(strXrefPaths[index] + "\\");
// 本级目录
if (sb.Length == 0) sb.Append(".\\");
// 下级目录加入
sb.Append(strXrefPaths[strXrefPaths.Length - 1]);
return sb.ToString();
}
#else
/// <summary>
/// 绝对路径->相对路径
/// StringHelper.GetRelativePath(@"D:\MyProj\Release", @"D:\MyProj\Log\MyFile.txt");
/// StringHelper.GetRelativePath("G:\\A1.项目\\20190920金山谷黄宅\\01.饰施图\\03.平面图", "G:\\A1.项目\\20190920金山谷黄宅\\01.饰施图\\01.辅助文件\\图框\\A3图框.dwg");
/// </summary>
/// <param name="strDbPath">绝对路径</param>
/// <param name="strXrefPath">相对关系</param>
/// <returns></returns>
public static string GetRelativePath(string strDbPath, string strXrefPath)
{
Uri uri1 = new Uri(strXrefPath);
Uri uri2 = new Uri(strDbPath);
// 测试例子变成
// 01.%E8%BE%85%E5%8A%A9%E6%96%87%E4%BB%B6/%E5%9B%BE%E6%A1%86/A3%E5%9B%BE%E6%A1%86.dwg
Uri relativeUri = uri2.MakeRelativeUri(uri1);
string str = relativeUri.ToString();
// 因为这里不会实现".\A.dwg"而是"A.dwg",
// 所以加入这个操作,满足同目录文件
var strs = str.Split('\\');
if (strs.Length == 1) str = ".\\" + str;
return str;
}
#endif
/// <summary>
/// 相对路径->绝对路径
/// </summary>
/// <param name="path_dwg">dwg基础路径</param>
/// <param name="xiangdui">相对路径</param>
/// <returns>完整路径</returns>
public static string GetCompletePath(string path_dwg, string xiangdui) {
string re_path_opend;
var path_dwgs = path_dwg.Split('\\');
path_dwgs = path_dwgs.Where(s => !string.IsNullOrEmpty(s)).ToArray();//清理空数组
var path_xiangduis = Path.GetDirectoryName(xiangdui).Split('\\');
// 判断向上删除几个
int inx = 0;
foreach (var item in path_xiangduis) {
if (item == "..") inx++;
else break;
}
// 前段
var pathA = new StringBuilder();
for (int i = 0; i < path_dwgs.Length - inx; i++)
pathA.Append(path_dwgs[i] + "\\");
// 后段
var pathB = new StringBuilder();
foreach (var item in path_xiangduis) {
if (item != "." && item != "..")
pathB.Append(item + "\\");
}
if (!string.IsNullOrEmpty(xiangdui) && xiangdui[0] == '.')
re_path_opend = pathA.ToString() + pathB.ToString() + Path.GetFileName(xiangdui);
else
re_path_opend = xiangdui;
return re_path_opend;
}
}
(完)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)