diff --git a/src/IFoxCAD.Cad.Shared/Runtime/AcadVersion.cs b/src/IFoxCAD.Cad.Shared/Runtime/AcadVersion.cs index 61aa6200e658d7356d96926f7880a42c57383135..d00cabab230534374bad500fb231a850eb2aef5e 100644 --- a/src/IFoxCAD.Cad.Shared/Runtime/AcadVersion.cs +++ b/src/IFoxCAD.Cad.Shared/Runtime/AcadVersion.cs @@ -1,4 +1,4 @@ -namespace IFoxCAD.Cad; +namespace IFoxCAD.Cad; /// /// cad版本号类 @@ -67,4 +67,124 @@ public static List Versions return Versions[i]; return null; } +} + +public static class VersionTool +{ + // 年号. + // 1,不用存年号数组,索引+2000就是年号了, + // 2,官方是Acad2000i,用2001年顶替 + // 3,官方没有Acad2003,但要满足1的规则,全部数组用上年数据补齐03年. + // static readonly int[] _years =>[ + // 2000, 2001, 2002, 2003/*虚拟03年*/, + // 2004, 2005, 2006, + // 2007, 2008, 2009, + // 2010, 2011, 2012, + // 2013, 2014, 2015, 2016, 2017, + // 2018, 2019, 2020, 2021, 2022, + // 2023, 2024, 2025]; + // 字段:public static readonly int[] Years; + // 构造:Years = _years; + // 异或判断数值是否一致 + // if ((_years.Length ^ DwgVers.Length ^ AcadVers.Length) != AcadVers.Length) + // throw new Exception(nameof(VersionTool) + // + "怎么长度不一样了捏?"); + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int IndexToYear(int index) + { + var year = index + 2000; + if (year < 2000) return -1; + if (year > 2000 + _acadVers.Length) return -1; + return year; + } + + // 和二分法一样, + // 没有命中时将第一个大于搜索值的索引作为返回值并取反, + // 以提供没有命中的信息(负数)和最近值取反后再插入. + // [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int YearToIndex(int year) + { + var index = year - 2000; + if (index < 0) return ~0; + if (index > _acadVers.Length - 1) + return ~(_acadVers.Length - 1); + return index; + } + + // https://www.autodesk.com.cn/support/technical/article/caas/sfdcarticles/sfdcarticles/CHS/drawing-version-codes-for-autocad.html + // DWG签名的AC号. + private static readonly int[] _dwgVers = [ + 1015, 1015, 1015, 1015 /*补齐03年*/, + 1018, 1018, 1018, + 1021, 1021, 1021, + 1024, 1024, 1024, + 1027, 1027, 1027, 1027, 1027, + 1032, 1032, 1032, 1032, 1032, + 1032, 1032, 1032 + ]; + + // CAD版本号,它与注册表和COM相关. + private static readonly string[] _acadVers = [ + "R15.0", "R15.1", "R15.2", "R15.2" /*补齐03年*/, + "R16.0", "R16.1", "R16.2", + "R17.0", "R17.1", "R17.2", + "R18.0", "R18.1", "R18.2", + "R19.0", "R19.1", "R20.0", "R20.1", "R21.0", + "R22.0", "R23.0", "R23.1", "R24.0", "R24.1", + "R24.2", "R24.3", "R25.0" + ]; + + // 运行中的CAD版本号,位移+位或. + public static readonly int AcadVerOR; + + // 这几个只读数组,有序等长,通过二分法共同索引. + public static readonly int[] AcadVers; + public static readonly int[] DwgVers; + + // 静态构造函数 + static VersionTool() + { + var major = Acap.Version.Major; + var minor = Acap.Version.Minor; + AcadVerOR = (major << 16) | minor; + + // 消除字符串从而不需要构造hashmap. + // 位移+位或,使得它们从小数映射到整数, + // 并且保持大小关系,仍然有序可以能够二分. + // 编译时:C#没有循环消除,反编译源码还能看见, + // 运行时:避免求一次循环,可以把结果再重新粘贴回代码. + // --就像快速平方根倒数,浮点数转16进制,然后粘贴到代码上,成为魔法数 + var v = new int[_acadVers.Length]; + for (var i = 0; i < _acadVers.Length; i++) + { + var s = _acadVers[i]; + var m = (s[1] - '0') * 10 + (s[2] - '0'); + var n = (s[4] - '0'); //0是R,3是小数点,所以跳到4 + v[i] = (m << 16) | n; + } + + AcadVers = v; + _acadVers = null!; // 积极释放 + DwgVers = _dwgVers; + +#if DEBUG + + // 防止开发者忘记更新数组,提供一个报错来进行维护 + var index = Array.BinarySearch(AcadVers, AcadVerOR); + if (index < 0) + { + throw new Exception(nameof(VersionTool) + + "运行中的CAD版本未记录,请维护DWG版本号/CAD版本号"); + } + + if (DwgVers.Length != AcadVers.Length) + throw new Exception(nameof(VersionTool) + + "怎么长度不一样了捏?"); + + // 解码版本号 + var major2 = AcadVerOR >> 16; + var minor2 = AcadVerOR & 0xFFFF; //位与掩码,获取低16bit + +#endif + } } \ No newline at end of file