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;
    }
}

(完)

posted @ 2020-03-04 06:42  惊惊  阅读(2486)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示