diff --git a/IFoxCAD.sln b/IFoxCAD.sln index ed2cf939f56bf1a7beeccff400c698cb08b0c0fe..8b9d772194969843ac6842ac33ccc16608fb0f74 100644 --- a/IFoxCAD.sln +++ b/IFoxCAD.sln @@ -3,11 +3,29 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 17 VisualStudioVersion = 17.8.34309.116 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "IFoxCAD.AutoCad", "IFoxCAD.AutoCad\IFoxCAD.AutoCad.csproj", "{6B29955A-5796-4035-9297-210FA15D3846}" +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{AE09C3B7-58AC-4A68-9884-1F93FDA5D785}" + ProjectSection(SolutionItems) = preProject + src\Directory.Build.props = src\Directory.Build.props + EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Test", "Test\Test.csproj", "{0C01F295-0985-436B-A15D-228877C60F1D}" +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "CADShared", "src\CADShared\CADShared.shproj", "{5178502E-9A78-4588-B849-33ED439976B2}" EndProject -Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "CADShared", "CADShared\CADShared.shproj", "{5178502E-9A78-4588-B849-33ED439976B2}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IFoxCAD.AutoCad", "src\IFoxCAD.AutoCad\IFoxCAD.AutoCad.csproj", "{9A0A144F-6820-4D15-9D39-43B7298195E3}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IFoxCAD.ZwCad", "src\IFoxCAD.ZwCad\IFoxCAD.ZwCad.csproj", "{8546C2AC-815C-47A1-9D8C-A6470DF44AD9}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{46F3EDA8-A6D1-4707-8D03-731CADB41A56}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestAcad2025", "tests\TestAcad2025\TestAcad2025.csproj", "{47C42AB4-C2F4-475B-899C-71FDE57D926E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestZcad2025", "tests\TestZcad2025\TestZcad2025.csproj", "{0B4601B4-CBDA-4FD8-9B31-C1E292D03068}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "docs", "docs", "{7145708C-A65B-470E-A8DA-ED79AC9A42D7}" + ProjectSection(SolutionItems) = preProject + docs\关于IFoxCAD的架构说明.md = docs\关于IFoxCAD的架构说明.md + EndProjectSection +EndProject +Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "TestShared", "tests\TestShared\TestShared.shproj", "{CED63D2D-0AF6-4831-806D-5E8E9B0D0A07}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -15,14 +33,22 @@ Global Release|Any CPU = Release|Any CPU EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {6B29955A-5796-4035-9297-210FA15D3846}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6B29955A-5796-4035-9297-210FA15D3846}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6B29955A-5796-4035-9297-210FA15D3846}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6B29955A-5796-4035-9297-210FA15D3846}.Release|Any CPU.Build.0 = Release|Any CPU - {0C01F295-0985-436B-A15D-228877C60F1D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0C01F295-0985-436B-A15D-228877C60F1D}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0C01F295-0985-436B-A15D-228877C60F1D}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0C01F295-0985-436B-A15D-228877C60F1D}.Release|Any CPU.Build.0 = Release|Any CPU + {9A0A144F-6820-4D15-9D39-43B7298195E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A0A144F-6820-4D15-9D39-43B7298195E3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A0A144F-6820-4D15-9D39-43B7298195E3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A0A144F-6820-4D15-9D39-43B7298195E3}.Release|Any CPU.Build.0 = Release|Any CPU + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9}.Release|Any CPU.Build.0 = Release|Any CPU + {47C42AB4-C2F4-475B-899C-71FDE57D926E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {47C42AB4-C2F4-475B-899C-71FDE57D926E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {47C42AB4-C2F4-475B-899C-71FDE57D926E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {47C42AB4-C2F4-475B-899C-71FDE57D926E}.Release|Any CPU.Build.0 = Release|Any CPU + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -34,4 +60,12 @@ Global CADShared\CADShared.projitems*{5178502e-9a78-4588-b849-33ed439976b2}*SharedItemsImports = 13 CADShared\CADShared.projitems*{6b29955a-5796-4035-9297-210fa15d3846}*SharedItemsImports = 5 EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9A0A144F-6820-4D15-9D39-43B7298195E3} = {AE09C3B7-58AC-4A68-9884-1F93FDA5D785} + {8546C2AC-815C-47A1-9D8C-A6470DF44AD9} = {AE09C3B7-58AC-4A68-9884-1F93FDA5D785} + {47C42AB4-C2F4-475B-899C-71FDE57D926E} = {46F3EDA8-A6D1-4707-8D03-731CADB41A56} + {0B4601B4-CBDA-4FD8-9B31-C1E292D03068} = {46F3EDA8-A6D1-4707-8D03-731CADB41A56} + {CED63D2D-0AF6-4831-806D-5E8E9B0D0A07} = {46F3EDA8-A6D1-4707-8D03-731CADB41A56} + {5178502E-9A78-4588-B849-33ED439976B2} = {AE09C3B7-58AC-4A68-9884-1F93FDA5D785} + EndGlobalSection EndGlobal diff --git a/Test/GlobalUsings.cs b/Test/GlobalUsings.cs deleted file mode 100644 index a7b8c491d0200fa34f9114e2cbfa3ec2d3395cb3..0000000000000000000000000000000000000000 --- a/Test/GlobalUsings.cs +++ /dev/null @@ -1,7 +0,0 @@ -global using IFoxCAD.Cad; -global using Acap =Autodesk.AutoCAD.ApplicationServices.Application; -global using Autodesk.AutoCAD.DatabaseServices; -global using Autodesk.AutoCAD.Geometry; -global using Autodesk.AutoCAD.Runtime; -global using System.ComponentModel; -global using System.Runtime.InteropServices; \ No newline at end of file diff --git a/Test/Test.csproj b/Test/Test.csproj deleted file mode 100644 index 9ffaa05159ad86db977008a4f79cf2b4ee63068e..0000000000000000000000000000000000000000 --- a/Test/Test.csproj +++ /dev/null @@ -1,27 +0,0 @@ - - - - net48 - true - preview - enable - - - - x64 - - - - x64 - - - - - - - - - - - - diff --git "a/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" "b/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" index b282930055e78cca9a804f689b5f2ba0d4e80524..ee3a985ec0fb36b41e94505d3f8f96379e1c029b 100644 --- "a/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" +++ "b/docs/\345\205\263\344\272\216IFoxCAD\347\232\204\346\236\266\346\236\204\350\257\264\346\230\216.md" @@ -72,22 +72,26 @@ IFoxCAD是基于NFOX类库的重制版,主要是提供一个最小化的内核 - IFoxCAD ``` - ├───CADShared -- 共享项目,所有的代码都在这里 - │ ├───Basal -- 一些基础类的函数 - │ │ ├───General - │ │ ├───Nullable - │ │ └───Win - │ ├───ExtensionMethod -- 扩展函数 - │ │ ├───Entity - │ │ ├───Geomerty - │ │ └───Jig - │ ├───Initialize -- 初始化 - │ ├───ResultData -- 扩展数据 - │ ├───Runtime -- 核心类 - │ └───SelectionFilter -- 选择集过滤器类 - ├───docs -- 架构及api定义说明文档 - ├───IFoxCAD.AutoCad -- AutoCAD的类库,内部除了globalusing外无其他代码 - └───Test -- 测试类 +├───bin -- 用于放置生成的nuget包和dll +├───docs -- 架构及api定义说明文档 +├───src -- 源码目录 +│ ├───CADShared -- 共享项目,所有的代码都在这里 +│ │ ├───Algorithms -- 基础算法和数据结构 +│ │ ├───Assoc -- 关联函数 +│ │ ├───Basal -- 一些基础类的函数 +│ │ ├───ExtensionMethod -- 扩展函数 +│ │ ├───Initialize -- 初始化 +│ │ ├───PE -- PE +│ │ ├───ResultData -- 扩展数据 +│ │ ├───Runtime -- 核心类 +│ │ └───SelectionFilter -- 选择集过滤器类 +│ ├───IFoxCAD.AutoCad -- AutoCAD的类库,内部除了globalusing外无其他代码 +│ └───IFoxCAD.ZwCad -- AutoCAD的类库,内部除了globalusing外无其他代码 +└───tests -- 测试类 + ├───TestAcad2025 -- autocad测试 + ├───TestShared -- 共享项目,所有的测试代码都在这里 + └───TestZcad2025 -- zwcad测试 + ``` ## 二、关于DBTrans类的说明 diff --git a/CADShared/Algorithms/QuadTree/QuadEntity.cs b/src/CADShared/Algorithms/QuadTree/QuadEntity.cs similarity index 100% rename from CADShared/Algorithms/QuadTree/QuadEntity.cs rename to src/CADShared/Algorithms/QuadTree/QuadEntity.cs diff --git a/CADShared/Algorithms/QuadTree/QuadTree.cs b/src/CADShared/Algorithms/QuadTree/QuadTree.cs similarity index 100% rename from CADShared/Algorithms/QuadTree/QuadTree.cs rename to src/CADShared/Algorithms/QuadTree/QuadTree.cs diff --git a/CADShared/Algorithms/QuadTree/QuadTreeEvn.cs b/src/CADShared/Algorithms/QuadTree/QuadTreeEvn.cs similarity index 100% rename from CADShared/Algorithms/QuadTree/QuadTreeEvn.cs rename to src/CADShared/Algorithms/QuadTree/QuadTreeEvn.cs diff --git a/CADShared/Algorithms/QuadTree/QuadTreeNode.cs b/src/CADShared/Algorithms/QuadTree/QuadTreeNode.cs similarity index 100% rename from CADShared/Algorithms/QuadTree/QuadTreeNode.cs rename to src/CADShared/Algorithms/QuadTree/QuadTreeNode.cs diff --git a/CADShared/Algorithms/QuadTree/QuadTreeSelectMode.cs b/src/CADShared/Algorithms/QuadTree/QuadTreeSelectMode.cs similarity index 100% rename from CADShared/Algorithms/QuadTree/QuadTreeSelectMode.cs rename to src/CADShared/Algorithms/QuadTree/QuadTreeSelectMode.cs diff --git a/CADShared/Algorithms/QuadTree/Rect.cs b/src/CADShared/Algorithms/QuadTree/Rect.cs similarity index 98% rename from CADShared/Algorithms/QuadTree/Rect.cs rename to src/CADShared/Algorithms/QuadTree/Rect.cs index 60f92f97b6566f8c401575dc0145a9487c951a6a..1366442ee833adbd4aa9f6b84572abaa17637089 100644 --- a/CADShared/Algorithms/QuadTree/Rect.cs +++ b/src/CADShared/Algorithms/QuadTree/Rect.cs @@ -1,6 +1,8 @@ using System.Diagnostics; using System.Runtime.CompilerServices; - +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif namespace IFoxCAD.Cad; /// @@ -413,8 +415,7 @@ public static bool IsRectAngle(List? ptList, double tolerance = 1e-8) { //if (ptList == null) // throw new ArgumentNullException(nameof(ptList)); - - ArgumentNullEx.ThrowIfNull(ptList); + ArgumentNullException.ThrowIfNull(ptList); var pts = ptList.ToList(); /* * 消重,不这里设置,否则这不是一个正确的单元测试 @@ -469,7 +470,7 @@ public static bool IsRect(List? ptList, double tolerance = 1e-10) { //if (ptList == null) // throw new ArgumentNullException(nameof(ptList)); - ArgumentNullEx.ThrowIfNull(ptList); + ArgumentNullException.ThrowIfNull(ptList); var pts = ptList.ToList(); if (ptList.Count == 5) { @@ -519,7 +520,7 @@ public static bool RectAnglePointOrder(List? pts) { //if (pts == null) // throw new ArgumentNullException(nameof(pts)); - ArgumentNullEx.ThrowIfNull(pts); + ArgumentNullException.ThrowIfNull(pts); if (!IsRectAngle(pts)) return false; @@ -722,7 +723,7 @@ public string ToString(string? format = null, IFormatProvider? formatProvider = /// /// /// - public int CompareTo(Rect rect) + public int CompareTo(Rect? rect) { if (rect == null) return -1; diff --git a/CADShared/Assoc/AssocPersSubentityIdPEEx.cs b/src/CADShared/Assoc/AssocPersSubentityIdPEEx.cs similarity index 100% rename from CADShared/Assoc/AssocPersSubentityIdPEEx.cs rename to src/CADShared/Assoc/AssocPersSubentityIdPEEx.cs diff --git a/CADShared/Assoc/AssocUtils.cs b/src/CADShared/Assoc/AssocUtils.cs similarity index 92% rename from CADShared/Assoc/AssocUtils.cs rename to src/CADShared/Assoc/AssocUtils.cs index 8781c079404141a706b1aa12cc8f1331423ed149..c8c400185834c4b68949885419962c2a455d856a 100644 --- a/CADShared/Assoc/AssocUtils.cs +++ b/src/CADShared/Assoc/AssocUtils.cs @@ -1,4 +1,9 @@ -using ErrorStatus = Autodesk.AutoCAD.Runtime.ErrorStatus; +#if acad +using ErrorStatus = Autodesk.AutoCAD.Runtime.ErrorStatus; +#elif zcad +using ErrorStatus = ZwSoft.ZwCAD.Runtime.ErrorStatus; +#endif + namespace IFoxCAD.Cad.Assoc; diff --git a/CADShared/Basal/General/ArrayEx.cs b/src/CADShared/Basal/General/ArrayEx.cs similarity index 100% rename from CADShared/Basal/General/ArrayEx.cs rename to src/CADShared/Basal/General/ArrayEx.cs diff --git a/CADShared/Basal/General/DebugHelper.cs b/src/CADShared/Basal/General/DebugHelper.cs similarity index 100% rename from CADShared/Basal/General/DebugHelper.cs rename to src/CADShared/Basal/General/DebugHelper.cs diff --git a/CADShared/Basal/General/EnumEx.cs b/src/CADShared/Basal/General/EnumEx.cs similarity index 97% rename from CADShared/Basal/General/EnumEx.cs rename to src/CADShared/Basal/General/EnumEx.cs index 4d1cb6cee8ad9f6d86783463b030d097c611aea3..0f761ce3577bc19cb0f52cbf6642fad16c2870cf 100644 --- a/CADShared/Basal/General/EnumEx.cs +++ b/src/CADShared/Basal/General/EnumEx.cs @@ -31,7 +31,7 @@ public static void CleanCache() if (Cache.TryGetValue(eFullName, out var attribute1)) return attribute1; - var fieldInfo = eType.GetField(Enum.GetName(eType, e)); + var fieldInfo = eType.GetField(Enum.GetName(eType, e) ?? string.Empty); if (fieldInfo == null) return null!; diff --git a/CADShared/Basal/General/LinqEx.cs b/src/CADShared/Basal/General/LinqEx.cs similarity index 98% rename from CADShared/Basal/General/LinqEx.cs rename to src/CADShared/Basal/General/LinqEx.cs index 746bacf2eaf0e585aa9b983c210e23ae724e71af..30036a163457105fc0093ca030f0f276f6f12a33 100644 --- a/CADShared/Basal/General/LinqEx.cs +++ b/src/CADShared/Basal/General/LinqEx.cs @@ -288,9 +288,12 @@ internal SpecComparer(Comparison comp) } #region IComparer 成员 - public int Compare(T x, T y) + + public int Compare(T? x, T? y) { - return _comp(x, y); + if (x is not null && y is not null) + return _comp(x, y); + return 0; } #endregion IComparer 成员 } diff --git a/CADShared/Basal/General/LoopList.cs b/src/CADShared/Basal/General/LoopList.cs similarity index 100% rename from CADShared/Basal/General/LoopList.cs rename to src/CADShared/Basal/General/LoopList.cs diff --git a/CADShared/Basal/General/LoopState.cs b/src/CADShared/Basal/General/LoopState.cs similarity index 100% rename from CADShared/Basal/General/LoopState.cs rename to src/CADShared/Basal/General/LoopState.cs diff --git a/CADShared/Basal/Nullable/ArgumentNullEx.cs b/src/CADShared/Basal/Nullable/ArgumentNullEx.cs similarity index 96% rename from CADShared/Basal/Nullable/ArgumentNullEx.cs rename to src/CADShared/Basal/Nullable/ArgumentNullEx.cs index 8552c44535b5158a00c6b03e469ad1f9039a84f4..7fb7763d155fe169740d82758ebdd19763ac4f61 100644 --- a/CADShared/Basal/Nullable/ArgumentNullEx.cs +++ b/src/CADShared/Basal/Nullable/ArgumentNullEx.cs @@ -1,4 +1,5 @@  +#if a2024 || zcad namespace IFoxCAD.Basal; /// @@ -23,4 +24,5 @@ public static void ThrowIfNull([NotNull] object? argument, [DoesNotReturn] private static void Throw(string? paramName) => throw new ArgumentNullException(paramName); -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/CADShared/Basal/Nullable/CallerArgumentExpressionAttribute.cs b/src/CADShared/Basal/Nullable/CallerArgumentExpressionAttribute.cs similarity index 91% rename from CADShared/Basal/Nullable/CallerArgumentExpressionAttribute.cs rename to src/CADShared/Basal/Nullable/CallerArgumentExpressionAttribute.cs index 6fb3c493c0bad4d8ec12ef85476b63dbbb522dc0..e6f566041731582fb5e2e0544ff199d4024257b3 100644 --- a/CADShared/Basal/Nullable/CallerArgumentExpressionAttribute.cs +++ b/src/CADShared/Basal/Nullable/CallerArgumentExpressionAttribute.cs @@ -1,5 +1,6 @@ -namespace System.Runtime.CompilerServices; - + +#if a2024 || zcad +namespace System.Runtime.CompilerServices; /// /// 指示参数将为另一个参数传递的表达式捕获为字符串。 /// @@ -20,4 +21,5 @@ public CallerArgumentExpressionAttribute(string parameterName) /// // ReSharper disable once UnusedAutoPropertyAccessor.Global public string ParameterName { get; } -} \ No newline at end of file +} +#endif \ No newline at end of file diff --git a/CADShared/Basal/Win/Enums.cs b/src/CADShared/Basal/Win/Enums.cs similarity index 100% rename from CADShared/Basal/Win/Enums.cs rename to src/CADShared/Basal/Win/Enums.cs diff --git a/CADShared/Basal/Win/PInvokeUser32.cs b/src/CADShared/Basal/Win/PInvokeUser32.cs similarity index 99% rename from CADShared/Basal/Win/PInvokeUser32.cs rename to src/CADShared/Basal/Win/PInvokeUser32.cs index c3df3f9cde217ed10f0ad8f671929755cf62e8f9..ef4dd5d8fad75f0491fd948b1efa315750aa85b3 100644 --- a/CADShared/Basal/Win/PInvokeUser32.cs +++ b/src/CADShared/Basal/Win/PInvokeUser32.cs @@ -221,7 +221,7 @@ public struct GuiThreadInfo public static GuiThreadInfo Create(uint windowThreadProcessId) { if (windowThreadProcessId == 0) - throw new ArgumentNullException(nameof(windowThreadProcessId)); + throw new System.ArgumentNullException(nameof(windowThreadProcessId)); GuiThreadInfo gti = new(); gti.cbSize = Marshal.SizeOf(gti); diff --git a/CADShared/Basal/Win/SystemEx.cs b/src/CADShared/Basal/Win/SystemEx.cs similarity index 100% rename from CADShared/Basal/Win/SystemEx.cs rename to src/CADShared/Basal/Win/SystemEx.cs diff --git a/CADShared/Basal/Win/WindowsAPI.cs b/src/CADShared/Basal/Win/WindowsAPI.cs similarity index 97% rename from CADShared/Basal/Win/WindowsAPI.cs rename to src/CADShared/Basal/Win/WindowsAPI.cs index bd20e90165f69da5e1de4d43ad496b2be37de6de..5125d471e94c218224c4df83e8c5517ef2be4700 100644 --- a/CADShared/Basal/Win/WindowsAPI.cs +++ b/src/CADShared/Basal/Win/WindowsAPI.cs @@ -1,6 +1,8 @@ #pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释 #define Marshal - +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif namespace IFoxCAD.Basal; public partial class WindowsAPI @@ -81,12 +83,12 @@ public partial class WindowsAPI /// 锁定数据对象指针 /// 返回锁定的内存片段指针,锁定期间执行任务 /// 是否锁定成功 - /// + /// public static bool GlobalLockTask(IntPtr data, Action task) { //if (task == null) // throw new ArgumentNullException(nameof(task)); - ArgumentNullEx.ThrowIfNull(task); + ArgumentNullException.ThrowIfNull(task); if (data == IntPtr.Zero) return false; @@ -130,7 +132,7 @@ public static bool GlobalLockTask(IntPtr data, Action task) Marshal.Copy(bytes, 0, structPtr, typeSize); // 将内存空间转换为目标结构体; // 转类型的时候会拷贝一次,看它们地址验证 &result != &structPtr - var result = (T)Marshal.PtrToStructure(structPtr, structType); + var result = (T)Marshal.PtrToStructure(structPtr, structType)!; // 释放内存空间 Marshal.FreeHGlobal(structPtr); @@ -324,7 +326,7 @@ public struct KeyboardHookStruct public static KeyboardHookStruct Create(IntPtr lParam) { - return (KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)); + return (KeyboardHookStruct)(Marshal.PtrToStructure(lParam, typeof(KeyboardHookStruct)) ?? throw new InvalidOperationException()); } public void ToPtr(IntPtr lParam) @@ -492,7 +494,7 @@ public Point3D(double x, double y, double z) public static Point3D Create(IntPtr lParam) { - return (Point3D)Marshal.PtrToStructure(lParam, typeof(Point3D)); + return (Point3D)(Marshal.PtrToStructure(lParam, typeof(Point3D)) ?? throw new InvalidOperationException()); } public void ToPtr(IntPtr lParam) diff --git a/CADShared/CADShared.projitems b/src/CADShared/CADShared.projitems similarity index 100% rename from CADShared/CADShared.projitems rename to src/CADShared/CADShared.projitems diff --git a/CADShared/CADShared.shproj b/src/CADShared/CADShared.shproj similarity index 100% rename from CADShared/CADShared.shproj rename to src/CADShared/CADShared.shproj diff --git a/CADShared/ExtensionMethod/BaseEx.cs b/src/CADShared/ExtensionMethod/BaseEx.cs similarity index 100% rename from CADShared/ExtensionMethod/BaseEx.cs rename to src/CADShared/ExtensionMethod/BaseEx.cs diff --git a/CADShared/ExtensionMethod/BulgeVertexWidth.cs b/src/CADShared/ExtensionMethod/BulgeVertexWidth.cs similarity index 100% rename from CADShared/ExtensionMethod/BulgeVertexWidth.cs rename to src/CADShared/ExtensionMethod/BulgeVertexWidth.cs diff --git a/CADShared/ExtensionMethod/CollectionEx.cs b/src/CADShared/ExtensionMethod/CollectionEx.cs similarity index 100% rename from CADShared/ExtensionMethod/CollectionEx.cs rename to src/CADShared/ExtensionMethod/CollectionEx.cs diff --git a/CADShared/ExtensionMethod/DBDictionaryEx.cs b/src/CADShared/ExtensionMethod/DBDictionaryEx.cs similarity index 100% rename from CADShared/ExtensionMethod/DBDictionaryEx.cs rename to src/CADShared/ExtensionMethod/DBDictionaryEx.cs diff --git a/CADShared/ExtensionMethod/DBObjectEx.cs b/src/CADShared/ExtensionMethod/DBObjectEx.cs similarity index 100% rename from CADShared/ExtensionMethod/DBObjectEx.cs rename to src/CADShared/ExtensionMethod/DBObjectEx.cs diff --git a/CADShared/ExtensionMethod/DBTransEx.cs b/src/CADShared/ExtensionMethod/DBTransEx.cs similarity index 100% rename from CADShared/ExtensionMethod/DBTransEx.cs rename to src/CADShared/ExtensionMethod/DBTransEx.cs diff --git a/CADShared/ExtensionMethod/DatabaseEx.cs b/src/CADShared/ExtensionMethod/DatabaseEx.cs similarity index 99% rename from CADShared/ExtensionMethod/DatabaseEx.cs rename to src/CADShared/ExtensionMethod/DatabaseEx.cs index c3bf399aaeec07f7612956c59282654f6d943162..d4b535010dc99c52806f416aa72b77630e7ab307 100644 --- a/CADShared/ExtensionMethod/DatabaseEx.cs +++ b/src/CADShared/ExtensionMethod/DatabaseEx.cs @@ -120,7 +120,7 @@ public static void SaveFile(this Database db, DwgVersion version = DwgVersion.AC #endif #if zcad // 中望这里没有测试 - db.DxfOut(saveAsFile, 7, version, true); + db.DxfOut(saveAsFile, 7, version); #endif return; } diff --git a/CADShared/ExtensionMethod/DocumentLockManager.cs b/src/CADShared/ExtensionMethod/DocumentLockManager.cs similarity index 100% rename from CADShared/ExtensionMethod/DocumentLockManager.cs rename to src/CADShared/ExtensionMethod/DocumentLockManager.cs diff --git a/CADShared/ExtensionMethod/DwgMark.cs b/src/CADShared/ExtensionMethod/DwgMark.cs similarity index 100% rename from CADShared/ExtensionMethod/DwgMark.cs rename to src/CADShared/ExtensionMethod/DwgMark.cs diff --git a/CADShared/ExtensionMethod/EditorEx.cs b/src/CADShared/ExtensionMethod/EditorEx.cs similarity index 99% rename from CADShared/ExtensionMethod/EditorEx.cs rename to src/CADShared/ExtensionMethod/EditorEx.cs index eaaba65cb0c4bd854c1e127a06a87d79d1a80516..9d2f6c8e1b844bfc81f64ac1668c06ab7de5d301 100644 --- a/CADShared/ExtensionMethod/EditorEx.cs +++ b/src/CADShared/ExtensionMethod/EditorEx.cs @@ -1,3 +1,5 @@ +using ArgumentNullException = System.ArgumentNullException; + namespace IFoxCAD.Cad; /// @@ -171,8 +173,7 @@ public static void SsgetAddKeys(this PromptSelectionOptions pso, if (dicActions[item] != dicActions[key]) dicActions[item] += dicActions[key]; } - else - tmp.Add(item, value); + else if (value != null) tmp.Add(item, value); } dicActions.Remove(key); @@ -1088,7 +1089,7 @@ public enum RunLispFlag : byte /// 保存文件 /// 选择集的对象,为null时候手选 /// 是否清空选择集 - /// + /// public static void ComExportWMF(this Editor editor, string saveFile, ObjectId[]? ids = null, bool wmfSetDel = false) { @@ -1102,7 +1103,7 @@ public static void ComExportWMF(this Editor editor, string saveFile, ObjectId[]? return; // 剔除后缀 - saveFile = Path.Combine(Path.GetDirectoryName(saveFile), + saveFile = Path.Combine(Path.GetDirectoryName(saveFile) ?? string.Empty, Path.GetFileNameWithoutExtension(saveFile)); // ActiveSelectionSet: // 第一次执行会触发选择,再次重复命令执行的时候,它会无法再选择(即使清空选择集). diff --git a/CADShared/ExtensionMethod/Entity/ArcEx.cs b/src/CADShared/ExtensionMethod/Entity/ArcEx.cs similarity index 100% rename from CADShared/ExtensionMethod/Entity/ArcEx.cs rename to src/CADShared/ExtensionMethod/Entity/ArcEx.cs diff --git a/CADShared/ExtensionMethod/Entity/BlockReferenceEx.cs b/src/CADShared/ExtensionMethod/Entity/BlockReferenceEx.cs similarity index 95% rename from CADShared/ExtensionMethod/Entity/BlockReferenceEx.cs rename to src/CADShared/ExtensionMethod/Entity/BlockReferenceEx.cs index 2bd61cc75f351a243aee871567509abe8a7d1be8..39ad840c361bb10b9628b76c61b3ea5e73c11c36 100644 --- a/CADShared/ExtensionMethod/Entity/BlockReferenceEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/BlockReferenceEx.cs @@ -1,4 +1,8 @@ -namespace IFoxCAD.Cad; +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; /// /// 块参照扩展类 @@ -195,12 +199,12 @@ public static BlockTableRecord GetBlockTableRecord(this BlockReference brf) /// 名字 public static string GetBlockName(this BlockReference blk) { - ArgumentNullEx.ThrowIfNull(blk); + ArgumentNullException.ThrowIfNull(blk); if (blk.IsDynamicBlock) { var btrId = blk.DynamicBlockTableRecord; var tr = btrId.Database.TransactionManager.TopTransaction; - ArgumentNullEx.ThrowIfNull(tr); + ArgumentNullException.ThrowIfNull(tr); var btr = (BlockTableRecord)tr.GetObject(btrId); return btr.Name; } @@ -245,7 +249,7 @@ public static string GetBlockName(this BlockReference blk) [DebuggerStepThrough] public static void ForEach(this BlockReference brf, Action action) { - ArgumentNullEx.ThrowIfNull(action); + ArgumentNullException.ThrowIfNull(action); var tr = DBTrans.GetTopTransaction(brf.Database); if (tr.GetObject(brf.BlockTableRecord) is BlockTableRecord btr) { @@ -258,11 +262,11 @@ public static void ForEach(this BlockReference brf, Action action) /// /// /// - /// + /// [DebuggerStepThrough] public static void ForEach(this BlockReference brf, Action action) { - ArgumentNullEx.ThrowIfNull(action); + ArgumentNullException.ThrowIfNull(action); var tr = DBTrans.GetTopTransaction(brf.Database); if (tr.GetObject(brf.BlockTableRecord) is BlockTableRecord btr) { @@ -275,11 +279,11 @@ public static void ForEach(this BlockReference brf, Action /// /// /// - /// + /// [DebuggerStepThrough] public static void ForEach(this BlockReference brf, Action action) { - ArgumentNullEx.ThrowIfNull(action); + ArgumentNullException.ThrowIfNull(action); var tr = DBTrans.GetTopTransaction(brf.Database); if (tr.GetObject(brf.BlockTableRecord) is BlockTableRecord btr) { diff --git a/CADShared/ExtensionMethod/Entity/BoundingInfo.cs b/src/CADShared/ExtensionMethod/Entity/BoundingInfo.cs similarity index 100% rename from CADShared/ExtensionMethod/Entity/BoundingInfo.cs rename to src/CADShared/ExtensionMethod/Entity/BoundingInfo.cs diff --git a/CADShared/ExtensionMethod/Entity/CircleEx.cs b/src/CADShared/ExtensionMethod/Entity/CircleEx.cs similarity index 100% rename from CADShared/ExtensionMethod/Entity/CircleEx.cs rename to src/CADShared/ExtensionMethod/Entity/CircleEx.cs diff --git a/CADShared/ExtensionMethod/Entity/CurveEx.cs b/src/CADShared/ExtensionMethod/Entity/CurveEx.cs similarity index 98% rename from CADShared/ExtensionMethod/Entity/CurveEx.cs rename to src/CADShared/ExtensionMethod/Entity/CurveEx.cs index 494666ac5628cc65a31dd7e9ed9e7be9ba0c811e..14a51130884167c72f1099ce11dd0396dc90a847 100644 --- a/CADShared/ExtensionMethod/Entity/CurveEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/CurveEx.cs @@ -1,5 +1,9 @@ // ReSharper disable ForCanBeConvertedToForeach +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + namespace IFoxCAD.Cad; /// @@ -48,7 +52,7 @@ public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable x); @@ -88,7 +92,7 @@ public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable { @@ -107,7 +111,7 @@ public static IEnumerable GetSplitCurves(this Curve curve, IEnumerable打断后的曲线列表 public static List BreakCurve(this List curves) { - ArgumentNullEx.ThrowIfNull(curves); + ArgumentNullException.ThrowIfNull(curves); var tol = new Tolerance(0.01, 0.01); @@ -174,11 +178,11 @@ public static List BreakCurve(this List curves) /// /// 曲线列表 /// 打断后的曲线列表 - /// 传入的曲线列表错误 + /// 传入的曲线列表错误 public static List BreakCurveOnZPlane(this List curves) { if (curves is null) - throw new ArgumentNullException(nameof(curves)); + throw new System.ArgumentNullException(nameof(curves)); var zPlane = new Plane(Point3d.Origin, Vector3d.ZAxis); var curvesTemp = curves.Select(c => c.GetProjectedCurve(zPlane, Vector3d.ZAxis)).ToList(); List geCurves = []; // 存储曲线转换后的复合曲线 diff --git a/CADShared/ExtensionMethod/Entity/DBTextEx.cs b/src/CADShared/ExtensionMethod/Entity/DBTextEx.cs similarity index 92% rename from CADShared/ExtensionMethod/Entity/DBTextEx.cs rename to src/CADShared/ExtensionMethod/Entity/DBTextEx.cs index 00042bf05b8c0223a8d0751761e5533189077036..97a65112694af26d58b23cd655d9fc08621a4898 100644 --- a/CADShared/ExtensionMethod/Entity/DBTextEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/DBTextEx.cs @@ -1,4 +1,6 @@ -namespace IFoxCAD.Cad; +using ArgumentNullException = System.ArgumentNullException; + +namespace IFoxCAD.Cad; /// /// 单行文字扩展类 @@ -15,7 +17,7 @@ public static class DBTextEx /// 文字所在的数据库 /// 文字属性设置委托 /// 文字对象 - /// + /// public static DBText CreateDBText(Point3d position, string text, double height, AttachmentPoint justify = AttachmentPoint.BaseLeft, Database? database = null, Action? action = null) diff --git a/CADShared/ExtensionMethod/Entity/EntityBoundingInfo.cs b/src/CADShared/ExtensionMethod/Entity/EntityBoundingInfo.cs similarity index 100% rename from CADShared/ExtensionMethod/Entity/EntityBoundingInfo.cs rename to src/CADShared/ExtensionMethod/Entity/EntityBoundingInfo.cs diff --git a/CADShared/ExtensionMethod/Entity/EntityEx.cs b/src/CADShared/ExtensionMethod/Entity/EntityEx.cs similarity index 100% rename from CADShared/ExtensionMethod/Entity/EntityEx.cs rename to src/CADShared/ExtensionMethod/Entity/EntityEx.cs diff --git a/CADShared/ExtensionMethod/Entity/MTextEx.cs b/src/CADShared/ExtensionMethod/Entity/MTextEx.cs similarity index 93% rename from CADShared/ExtensionMethod/Entity/MTextEx.cs rename to src/CADShared/ExtensionMethod/Entity/MTextEx.cs index 027793c369150d416ea6ec37ae3fabeecdb72acc..52c85a97c627360d2b00e06f6e05fae4a733e465 100644 --- a/CADShared/ExtensionMethod/Entity/MTextEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/MTextEx.cs @@ -1,4 +1,6 @@ -namespace IFoxCAD.Cad; +using ArgumentNullException = System.ArgumentNullException; + +namespace IFoxCAD.Cad; /// /// 多行文字扩展类 @@ -14,7 +16,7 @@ public static class MTextEx /// 文字所在的数据库 /// 文字属性设置委托 /// 文字对象id - /// + /// public static MText CreateMText(Point3d position, string text, double height, Database? database = null, Action? action = null) { diff --git a/CADShared/ExtensionMethod/Entity/PolylineEx.cs b/src/CADShared/ExtensionMethod/Entity/PolylineEx.cs similarity index 100% rename from CADShared/ExtensionMethod/Entity/PolylineEx.cs rename to src/CADShared/ExtensionMethod/Entity/PolylineEx.cs diff --git a/CADShared/ExtensionMethod/Entity/RegionEx.cs b/src/CADShared/ExtensionMethod/Entity/RegionEx.cs similarity index 94% rename from CADShared/ExtensionMethod/Entity/RegionEx.cs rename to src/CADShared/ExtensionMethod/Entity/RegionEx.cs index c78753b89e09506e2e975bef69817817ba3cd865..6cb3c0d703502b31f8bb444574576d7e63c0a6fa 100644 --- a/CADShared/ExtensionMethod/Entity/RegionEx.cs +++ b/src/CADShared/ExtensionMethod/Entity/RegionEx.cs @@ -1,5 +1,8 @@ -using Autodesk.AutoCAD.BoundaryRepresentation; - +#if acad +using Autodesk.AutoCAD.BoundaryRepresentation; +#elif zcad +using ZwSoft.ZwCAD.BoundaryRepresentation; +#endif namespace IFoxCAD.Cad; /// diff --git a/CADShared/ExtensionMethod/Enums.cs b/src/CADShared/ExtensionMethod/Enums.cs similarity index 100% rename from CADShared/ExtensionMethod/Enums.cs rename to src/CADShared/ExtensionMethod/Enums.cs diff --git a/CADShared/ExtensionMethod/ErrorInfoEx.cs b/src/CADShared/ExtensionMethod/ErrorInfoEx.cs similarity index 100% rename from CADShared/ExtensionMethod/ErrorInfoEx.cs rename to src/CADShared/ExtensionMethod/ErrorInfoEx.cs diff --git a/CADShared/ExtensionMethod/Geomerty/Curve2dEx.cs b/src/CADShared/ExtensionMethod/Geomerty/Curve2dEx.cs similarity index 100% rename from CADShared/ExtensionMethod/Geomerty/Curve2dEx.cs rename to src/CADShared/ExtensionMethod/Geomerty/Curve2dEx.cs diff --git a/CADShared/ExtensionMethod/Geomerty/Curve3dEx.cs b/src/CADShared/ExtensionMethod/Geomerty/Curve3dEx.cs similarity index 100% rename from CADShared/ExtensionMethod/Geomerty/Curve3dEx.cs rename to src/CADShared/ExtensionMethod/Geomerty/Curve3dEx.cs diff --git a/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs b/src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs similarity index 99% rename from CADShared/ExtensionMethod/Geomerty/GeometryEx.cs rename to src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs index 46e9c6d1b2cf433bd878e64fc9ed9d3244b82fe7..3558994a741017c644dabd6108f8061d63aad111 100644 --- a/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs +++ b/src/CADShared/ExtensionMethod/Geomerty/GeometryEx.cs @@ -1,3 +1,7 @@ +#if a2024 +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + namespace IFoxCAD.Cad; using System.Drawing; @@ -292,7 +296,7 @@ private static double CalArea(IEnumerable pnts) { using var itor = pnts.GetEnumerator(); if (!itor.MoveNext()) - throw new ArgumentNullException(nameof(pnts)); + throw new System.ArgumentNullException(nameof(pnts)); var start = itor.Current; var p2 = start; double area = 0; diff --git a/CADShared/ExtensionMethod/Geomerty/PointEx.cs b/src/CADShared/ExtensionMethod/Geomerty/PointEx.cs similarity index 98% rename from CADShared/ExtensionMethod/Geomerty/PointEx.cs rename to src/CADShared/ExtensionMethod/Geomerty/PointEx.cs index c6455b1d0bac795ae02516183fedb5c904bcb826..f920a3cd0bf8aca0f3b82e8d8dd72a22119175e3 100644 --- a/CADShared/ExtensionMethod/Geomerty/PointEx.cs +++ b/src/CADShared/ExtensionMethod/Geomerty/PointEx.cs @@ -1,3 +1,7 @@ +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + namespace IFoxCAD.Cad; /// @@ -230,7 +234,7 @@ public static double Distance2dTo(this Point3d pt1, Point3d pt2) [DebuggerStepThrough] public static void End2End(this Point2dCollection ptCollection) { - ArgumentNullEx.ThrowIfNull(ptCollection); + ArgumentNullException.ThrowIfNull(ptCollection); if (ptCollection.Count == 0 || ptCollection[0].Equals(ptCollection[^1])) // 首尾相同直接返回 return; @@ -251,7 +255,7 @@ public static void End2End(this Point2dCollection ptCollection) [DebuggerStepThrough] public static void End2End(this Point3dCollection ptCollection) { - ArgumentNullEx.ThrowIfNull(ptCollection); + ArgumentNullException.ThrowIfNull(ptCollection); if (ptCollection.Count == 0 || ptCollection[0].Equals(ptCollection[^1])) // 首尾相同直接返回 return; diff --git a/CADShared/ExtensionMethod/Hatch/HatchConverter.cs b/src/CADShared/ExtensionMethod/Hatch/HatchConverter.cs similarity index 98% rename from CADShared/ExtensionMethod/Hatch/HatchConverter.cs rename to src/CADShared/ExtensionMethod/Hatch/HatchConverter.cs index 915cda8f91df6f8dee16c405ae29ff7e61a5a9b0..fe79a623bd4dda12f333b6cbab53c6ad20401976 100644 --- a/CADShared/ExtensionMethod/Hatch/HatchConverter.cs +++ b/src/CADShared/ExtensionMethod/Hatch/HatchConverter.cs @@ -1,6 +1,10 @@ // ReSharper disable CompareOfFloatsByEqualityOperator // ReSharper disable ForCanBeConvertedToForeach +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + namespace IFoxCAD.Cad; using PointV = Point2d; @@ -174,8 +178,8 @@ static void HatchLoopIsPolyline(HatchLoop loop, HatchConverterData hcData) //if (hcData is null) // throw new ArgumentNullException(nameof(hcData)); - ArgumentNullEx.ThrowIfNull(loop); - ArgumentNullEx.ThrowIfNull(hcData); + ArgumentNullException.ThrowIfNull(loop); + ArgumentNullException.ThrowIfNull(hcData); // 判断为圆形: @@ -205,7 +209,7 @@ static void HatchLoopIsPolyline(HatchLoop loop, HatchConverterData hcData) //if (loop is null) // throw new ArgumentNullException(nameof(loop)); - ArgumentNullEx.ThrowIfNull(loop); + ArgumentNullException.ThrowIfNull(loop); if (loop.Curves.Count != 2) throw new ArgumentException("边界非多段线,而且点数!=2,点数为:" + nameof(loop.Curves.Count) + diff --git a/CADShared/ExtensionMethod/Hatch/HatchEx.cs b/src/CADShared/ExtensionMethod/Hatch/HatchEx.cs similarity index 100% rename from CADShared/ExtensionMethod/Hatch/HatchEx.cs rename to src/CADShared/ExtensionMethod/Hatch/HatchEx.cs diff --git a/CADShared/ExtensionMethod/Hatch/HatchInfo.cs b/src/CADShared/ExtensionMethod/Hatch/HatchInfo.cs similarity index 98% rename from CADShared/ExtensionMethod/Hatch/HatchInfo.cs rename to src/CADShared/ExtensionMethod/Hatch/HatchInfo.cs index 88c088635bd1c2b3b7d4573317907070ecd8fc8b..f836615f30fabe9e69cd6f853899ebb89f4e6bad 100644 --- a/CADShared/ExtensionMethod/Hatch/HatchInfo.cs +++ b/src/CADShared/ExtensionMethod/Hatch/HatchInfo.cs @@ -1,5 +1,9 @@  +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + namespace IFoxCAD.Cad; /* @@ -296,7 +300,7 @@ public HatchInfo AppendLoop(Point2dCollection pts, { //if (pts == null) // throw new ArgumentNullException(nameof(pts)); - ArgumentNullEx.ThrowIfNull(pts); + ArgumentNullException.ThrowIfNull(pts); pts.End2End(); // 2011新增API,可以不生成图元的情况下加入边界, // 通过这里进入的话,边界 _boundaryIds 是空的,那么 Build() 时候就需要过滤空的 diff --git a/CADShared/ExtensionMethod/IFoxUtils.cs b/src/CADShared/ExtensionMethod/IFoxUtils.cs similarity index 100% rename from CADShared/ExtensionMethod/IFoxUtils.cs rename to src/CADShared/ExtensionMethod/IFoxUtils.cs diff --git a/CADShared/ExtensionMethod/Jig/JigEx.cs b/src/CADShared/ExtensionMethod/Jig/JigEx.cs similarity index 98% rename from CADShared/ExtensionMethod/Jig/JigEx.cs rename to src/CADShared/ExtensionMethod/Jig/JigEx.cs index f484156d6434dd06640b453f067df746b6d7171f..0e6b1af28cc60fb1721dd14b57fd274e795942ad 100644 --- a/CADShared/ExtensionMethod/Jig/JigEx.cs +++ b/src/CADShared/ExtensionMethod/Jig/JigEx.cs @@ -1,4 +1,8 @@ -namespace IFoxCAD.Cad; +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; /* 封装jig * 20220726 隐藏事件,利用函数进行数据库图元重绘 @@ -293,7 +297,7 @@ static JigPromptPointOptions JigPointOptions() public void SetSpaceIsKeyword() { var opt = _options; - ArgumentNullEx.ThrowIfNull(opt); + ArgumentNullException.ThrowIfNull(opt); if ((opt.UserInputControls & UserInputControls.NullResponseAccepted) == UserInputControls.NullResponseAccepted) opt.UserInputControls ^= UserInputControls.NullResponseAccepted; // 输入了鼠标右键,结束jig if ((opt.UserInputControls & UserInputControls.AnyBlankTerminatesInput) == UserInputControls.AnyBlankTerminatesInput) diff --git a/CADShared/ExtensionMethod/Jig/JigExTransient.cs b/src/CADShared/ExtensionMethod/Jig/JigExTransient.cs similarity index 100% rename from CADShared/ExtensionMethod/Jig/JigExTransient.cs rename to src/CADShared/ExtensionMethod/Jig/JigExTransient.cs diff --git a/CADShared/ExtensionMethod/ObjectIdEx.cs b/src/CADShared/ExtensionMethod/ObjectIdEx.cs similarity index 100% rename from CADShared/ExtensionMethod/ObjectIdEx.cs rename to src/CADShared/ExtensionMethod/ObjectIdEx.cs diff --git a/CADShared/ExtensionMethod/PaneEx.cs b/src/CADShared/ExtensionMethod/PaneEx.cs similarity index 100% rename from CADShared/ExtensionMethod/PaneEx.cs rename to src/CADShared/ExtensionMethod/PaneEx.cs diff --git a/CADShared/ExtensionMethod/PromptOptionsEx.cs b/src/CADShared/ExtensionMethod/PromptOptionsEx.cs similarity index 99% rename from CADShared/ExtensionMethod/PromptOptionsEx.cs rename to src/CADShared/ExtensionMethod/PromptOptionsEx.cs index 8b61d5a6d280eb3ed50ceb8ab08df943bdea0782..45c53416ad0587bfa1195c35d5a8ac9982f1cad2 100644 --- a/CADShared/ExtensionMethod/PromptOptionsEx.cs +++ b/src/CADShared/ExtensionMethod/PromptOptionsEx.cs @@ -1,5 +1,5 @@ // ReSharper disable UnusedAutoPropertyAccessor.Global -namespace IFoxCAD.CAD; +namespace IFoxCAD.Cad; /// /// 交互设置扩展 diff --git a/CADShared/ExtensionMethod/RandomEx.cs b/src/CADShared/ExtensionMethod/RandomEx.cs similarity index 100% rename from CADShared/ExtensionMethod/RandomEx.cs rename to src/CADShared/ExtensionMethod/RandomEx.cs diff --git a/CADShared/ExtensionMethod/RedrawEx.cs b/src/CADShared/ExtensionMethod/RedrawEx.cs similarity index 100% rename from CADShared/ExtensionMethod/RedrawEx.cs rename to src/CADShared/ExtensionMethod/RedrawEx.cs diff --git a/CADShared/ExtensionMethod/SelectionSetEx.cs b/src/CADShared/ExtensionMethod/SelectionSetEx.cs similarity index 94% rename from CADShared/ExtensionMethod/SelectionSetEx.cs rename to src/CADShared/ExtensionMethod/SelectionSetEx.cs index b4d22e45ff93dfb45c9c2b4ad046053e4026f4bb..3d152fb2bd7f2f7b965fc5be5c6a7d8e046b58bd 100644 --- a/CADShared/ExtensionMethod/SelectionSetEx.cs +++ b/src/CADShared/ExtensionMethod/SelectionSetEx.cs @@ -1,4 +1,8 @@ -namespace IFoxCAD.Cad; +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; /// /// 选择集扩展类 @@ -90,7 +94,7 @@ public static void ForEach(this SelectionSet ss, /// 打开模式 /// 是否打开已删除对象,默认为不打开 /// 是否打开锁定图层对象,默认为不打开 - /// + /// [DebuggerStepThrough] public static void ForEach(this SelectionSet ss, Action action, @@ -98,7 +102,7 @@ public static void ForEach(this SelectionSet ss, bool openErased = false, bool openLockedLayer = false) where T : Entity { - ArgumentNullEx.ThrowIfNull(action); + ArgumentNullException.ThrowIfNull(action); LoopState state = new(); var ents = ss.GetEntities(openMode, openErased, openLockedLayer); diff --git a/CADShared/ExtensionMethod/SingleKeyWordHook.cs b/src/CADShared/ExtensionMethod/SingleKeyWordHook.cs similarity index 100% rename from CADShared/ExtensionMethod/SingleKeyWordHook.cs rename to src/CADShared/ExtensionMethod/SingleKeyWordHook.cs diff --git a/CADShared/ExtensionMethod/SymbolTableEx.cs b/src/CADShared/ExtensionMethod/SymbolTableEx.cs similarity index 99% rename from CADShared/ExtensionMethod/SymbolTableEx.cs rename to src/CADShared/ExtensionMethod/SymbolTableEx.cs index 867c9be1a7a256614d4f6b63fa2d73c733a99390..f780fd663274b97e0b25bf8c6ef27b5f0be8751e 100644 --- a/CADShared/ExtensionMethod/SymbolTableEx.cs +++ b/src/CADShared/ExtensionMethod/SymbolTableEx.cs @@ -1,4 +1,6 @@ -namespace IFoxCAD.Cad; +using ArgumentNullException = System.ArgumentNullException; + +namespace IFoxCAD.Cad; /// /// 符号表类扩展函数 diff --git a/CADShared/ExtensionMethod/SymbolTableRecordEx.cs b/src/CADShared/ExtensionMethod/SymbolTableRecordEx.cs similarity index 97% rename from CADShared/ExtensionMethod/SymbolTableRecordEx.cs rename to src/CADShared/ExtensionMethod/SymbolTableRecordEx.cs index 42cadaa282e9607b73f835c9a28e21935a24ba56..4aa3a5ab2547dd5385ed6f7080514f863dfe5e5e 100644 --- a/CADShared/ExtensionMethod/SymbolTableRecordEx.cs +++ b/src/CADShared/ExtensionMethod/SymbolTableRecordEx.cs @@ -1,4 +1,9 @@ -namespace IFoxCAD.Cad; + +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; /// /// 符号表记录扩展类 @@ -27,7 +32,7 @@ public static class SymbolTableRecordEx public static void DeepCloneEx(this BlockTableRecord btr, ObjectIdCollection objIds, IdMapping maoOut) { if (objIds is null || objIds.Count == 0) - throw new ArgumentNullException(nameof(objIds)); + throw new System.ArgumentNullException(nameof(objIds)); var db = objIds[0].Database; using (btr.ForWrite()) @@ -57,7 +62,7 @@ public static void DeepCloneEx(this BlockTableRecord btr, ObjectIdCollection obj public static IdMapping DeepCloneEx(this BlockTableRecord btr, ObjectIdCollection objIds) { if (objIds is null || objIds.Count == 0) - throw new ArgumentNullException(nameof(objIds)); + throw new System.ArgumentNullException(nameof(objIds)); var db = objIds[0].Database; IdMapping mapOut = new(); @@ -347,7 +352,7 @@ public static void ForEach(this TRecord record, Action /// 关闭时减掉事件 /// - private static void WindowOnClosed(object sender, EventArgs e) + private static void WindowOnClosed(object? sender, EventArgs e) { if (sender is not Window window) return; @@ -85,7 +85,8 @@ public static void SetSizeByScreenResolution(this PaletteSet paletteSet, int wid var newHeight = Convert.ToInt32(height * scale); if (newHeight > size.Height) newHeight = size.Height; - paletteSet.SetSize(new Size(newWidth, newHeight)); + // paletteSet.SetSize(new Size(newWidth, newHeight)); // 中望2025 这样调用报错找不到setsize函数 + WindowExtension.SetSize(paletteSet, new Size(newWidth, newHeight)); // 中望2025这样调用没有问题 } /// diff --git a/CADShared/ExtensionMethod/XrefEx.cs b/src/CADShared/ExtensionMethod/XrefEx.cs similarity index 98% rename from CADShared/ExtensionMethod/XrefEx.cs rename to src/CADShared/ExtensionMethod/XrefEx.cs index 39a3008af6cfdd0001be9dd984aa8809db7a9b3b..39f78892771fbcbc3a5fdbe3d062b1e940350162 100644 --- a/CADShared/ExtensionMethod/XrefEx.cs +++ b/src/CADShared/ExtensionMethod/XrefEx.cs @@ -1,4 +1,9 @@ // ReSharper disable ForCanBeConvertedToForeach + +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + namespace IFoxCAD.Cad; #region 参照工厂 @@ -471,7 +476,7 @@ public XrefPath(BlockReference brf, DBTrans tr) { //if (brf == null) // throw new ArgumentNullException(nameof(brf)); - ArgumentNullEx.ThrowIfNull(brf); + ArgumentNullException.ThrowIfNull(brf); CurrentDatabasePath = Path.GetDirectoryName(tr.Database.Filename); var btRec = tr.GetObject(brf.BlockTableRecord); // 块表记录 @@ -519,8 +524,8 @@ public XrefPath(BlockReference brf, DBTrans tr) //if (fileRelations == null) // throw new ArgumentNullException(nameof(fileRelations)); - ArgumentNullEx.ThrowIfNull(directory); - ArgumentNullEx.ThrowIfNull(fileRelations); + ArgumentNullException.ThrowIfNull(directory); + ArgumentNullException.ThrowIfNull(fileRelations); string? result = null; switch (converterModes) diff --git a/CADShared/Initialize/AcadEMR.cs b/src/CADShared/Initialize/AcadEMR.cs similarity index 99% rename from CADShared/Initialize/AcadEMR.cs rename to src/CADShared/Initialize/AcadEMR.cs index 18eac5a114564896fd69ec6ae17218054eb17a5c..3fcfc03fff2675748c74849adbb9cdf22f26b09e 100644 --- a/CADShared/Initialize/AcadEMR.cs +++ b/src/CADShared/Initialize/AcadEMR.cs @@ -1,4 +1,5 @@ -#if true +#if true +#if acad namespace IFoxCAD.Cad; // 作者: [VB.net]福萝卜 莱昂纳多·胖子 @@ -148,4 +149,5 @@ static bool CheckFunc(ref IntPtr address, byte val, int len) return false; } } +#endif #endif \ No newline at end of file diff --git a/CADShared/Initialize/AssemInfo.cs b/src/CADShared/Initialize/AssemInfo.cs similarity index 95% rename from CADShared/Initialize/AssemInfo.cs rename to src/CADShared/Initialize/AssemInfo.cs index 18296224a94d4bba5c15ad379b92701c68843d72..de3f40debb2552222f27ebe1cd53b3a1bb728bb3 100644 --- a/CADShared/Initialize/AssemInfo.cs +++ b/src/CADShared/Initialize/AssemInfo.cs @@ -13,8 +13,8 @@ public struct AssemInfo public AssemInfo(Assembly assembly) { Loader = assembly.Location; - Fullname = assembly.FullName; - Name = assembly.GetName().Name; + Fullname = assembly.FullName!; + Name = assembly.GetName().Name!; LoadType = AssemLoadType.Starting; } diff --git a/CADShared/Initialize/AutoReg.cs b/src/CADShared/Initialize/AutoReg.cs similarity index 96% rename from CADShared/Initialize/AutoReg.cs rename to src/CADShared/Initialize/AutoReg.cs index b84d3f3b75fb73ff6d106a02993b2bd870aefa31..8e9b1f594b23c818002d703b75937ebcaa38b1d5 100644 --- a/CADShared/Initialize/AutoReg.cs +++ b/src/CADShared/Initialize/AutoReg.cs @@ -55,7 +55,7 @@ public static void RegApp(AssemInfo info) /// 程序集 public static void RegApp(Assembly? assembly = null) { - assembly ??= Assembly.GetCallingAssembly(); + assembly ??= Assembly.GetExecutingAssembly(); var info = new AssemInfo(assembly); RegApp(info); } @@ -81,7 +81,7 @@ public static bool UnRegApp(AssemInfo info) /// 程序集 public static void UnRegApp(Assembly? assembly = null) { - assembly ??= Assembly.GetCallingAssembly(); + assembly ??= Assembly.GetExecutingAssembly(); var info = new AssemInfo(assembly); UnRegApp(info); } diff --git a/CADShared/Initialize/AutoRegAssem.cs b/src/CADShared/Initialize/AutoRegAssem.cs similarity index 91% rename from CADShared/Initialize/AutoRegAssem.cs rename to src/CADShared/Initialize/AutoRegAssem.cs index 5431ecbd8b73ae48fa35b2ad87aa8f19b0cfc823..eeecf3c769c2cc1c6f0c17086589bba05435b9c3 100644 --- a/CADShared/Initialize/AutoRegAssem.cs +++ b/src/CADShared/Initialize/AutoRegAssem.cs @@ -1,4 +1,8 @@ -namespace IFoxCAD.Cad; +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; /// /// 注册中心 @@ -37,7 +41,7 @@ public abstract class AutoRegAssem : IExtensionApplication /// 路径对象 public static DirectoryInfo? GetDirectory(Assembly? assem) { - ArgumentNullEx.ThrowIfNull(assem); + ArgumentNullException.ThrowIfNull(assem); return new FileInfo(assem.Location).Directory; } @@ -55,8 +59,8 @@ protected AutoRegAssem(AutoRegConfig autoRegConfig) var info = new AssemInfo { Loader = assem.Location, - Fullname = assem.FullName, - Name = assem.GetName().Name, + Fullname = assem.FullName!, + Name = assem.GetName().Name!, LoadType = AssemLoadType.Starting }; @@ -66,8 +70,10 @@ protected AutoRegAssem(AutoRegConfig autoRegConfig) AutoReg.RegApp(info); } +#if acad if ((autoRegConfig & AutoRegConfig.RemoveEMR) == AutoRegConfig.RemoveEMR) AcadEMR.Remove(); +#endif // 实例化了 AutoClass 之后会自动执行 IFoxAutoGo 接口下面的类, // 以及自动执行特性 [IFoxInitialize] diff --git a/CADShared/Initialize/CheckFactory.cs b/src/CADShared/Initialize/CheckFactory.cs similarity index 100% rename from CADShared/Initialize/CheckFactory.cs rename to src/CADShared/Initialize/CheckFactory.cs diff --git a/CADShared/Initialize/IAutoGo.cs b/src/CADShared/Initialize/IAutoGo.cs similarity index 100% rename from CADShared/Initialize/IAutoGo.cs rename to src/CADShared/Initialize/IAutoGo.cs diff --git a/CADShared/Initialize/MethodInfoHelper.cs b/src/CADShared/Initialize/MethodInfoHelper.cs similarity index 92% rename from CADShared/Initialize/MethodInfoHelper.cs rename to src/CADShared/Initialize/MethodInfoHelper.cs index 2da1d702cd55624ba1273eacd0aaafa82ca2d33d..79bede79fc9af4b5e429dc9830a571a587dfbe54 100644 --- a/CADShared/Initialize/MethodInfoHelper.cs +++ b/src/CADShared/Initialize/MethodInfoHelper.cs @@ -1,4 +1,8 @@ -namespace IFoxCAD.Cad; +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + +namespace IFoxCAD.Cad; internal static class MethodInfoHelper { @@ -13,7 +17,7 @@ internal static class MethodInfoHelper /// 已经外部创建的对象,为空则此处创建 public static object? Invoke(this MethodInfo methodInfo, ref object? instance) { - ArgumentNullEx.ThrowIfNull(methodInfo); + ArgumentNullException.ThrowIfNull(methodInfo); object? result = null; if (methodInfo.IsStatic) { diff --git a/CADShared/PE/AcadPeInfo.cs b/src/CADShared/PE/AcadPeInfo.cs similarity index 96% rename from CADShared/PE/AcadPeInfo.cs rename to src/CADShared/PE/AcadPeInfo.cs index ffda2d50aa79d150b5d38bae401b736ffd9ade26..fbec0a6bee1666202bda69b4d37a0cf189dc7dfa 100644 --- a/CADShared/PE/AcadPeInfo.cs +++ b/src/CADShared/PE/AcadPeInfo.cs @@ -63,7 +63,9 @@ public static PeInfo? PeForAcadExe if (_PeForAcadExe is null) { // 获取此acad.exe获取所有的函数名 - var file = Process.GetCurrentProcess().MainModule.FileName; + var processModule = Process.GetCurrentProcess().MainModule; + if (processModule == null) return _PeForAcadExe; + var file = processModule.FileName; _PeForAcadExe = new PeInfo(file); } return _PeForAcadExe; @@ -81,7 +83,7 @@ public static PeInfo? PeForAccoreDll if (_PeForAccoreDll is null) { // 获取此dll所有的函数名 - var file = Process.GetCurrentProcess().MainModule.FileName; + var file = Process.GetCurrentProcess().MainModule!.FileName; var dll = Path.GetDirectoryName(file) + "\\accore.dll"; if (File.Exists(dll))// 08没有,高版本分离的 _PeForAccoreDll = new PeInfo(dll); @@ -101,7 +103,7 @@ public static PeInfo? PeForAcdbDll if (_PeForAcdbDll is null) { // 获取此dll所有的函数名 - var file = Process.GetCurrentProcess().MainModule.FileName; + var file = Process.GetCurrentProcess().MainModule!.FileName; var dll = Path.GetDirectoryName(file) + $"\\acdb{Acaop.Version.Major}.dll"; if (File.Exists(dll)) _PeForAcdbDll = new PeInfo(dll); @@ -235,9 +237,9 @@ GetMethodErrorNum GetPeMethod(PeInfo? peInfo) // 排序,最少长度原则本身就是让完全相同字符串在最前面 // 这里替换为有序哈希,因为我总是需要不带修饰的返回函数,所以是排序长度的第一个 - _Methods = _Methods.OrderBy(str => str.CName?.Length) - .ThenBy(str => str.MethodName.Length) - .ToList(); + _Methods = _Methods?.OrderBy(str => str.CName?.Length) + .ThenBy(str => str.MethodName.Length) + .ToList(); func = Marshal.GetDelegateForFunctionPointer(Methods.First().GetProcAddress(), typeof(TDelegate)) as TDelegate; return func; diff --git a/CADShared/PE/DBmod.cs b/src/CADShared/PE/DBmod.cs similarity index 100% rename from CADShared/PE/DBmod.cs rename to src/CADShared/PE/DBmod.cs diff --git a/CADShared/PE/PostCmd.cs b/src/CADShared/PE/PostCmd.cs similarity index 100% rename from CADShared/PE/PostCmd.cs rename to src/CADShared/PE/PostCmd.cs diff --git a/CADShared/PE/ProgramPE.cs b/src/CADShared/PE/ProgramPE.cs similarity index 100% rename from CADShared/PE/ProgramPE.cs rename to src/CADShared/PE/ProgramPE.cs diff --git a/CADShared/ResultData/LispList.cs b/src/CADShared/ResultData/LispList.cs similarity index 100% rename from CADShared/ResultData/LispList.cs rename to src/CADShared/ResultData/LispList.cs diff --git a/CADShared/ResultData/TypedValueList.cs b/src/CADShared/ResultData/TypedValueList.cs similarity index 100% rename from CADShared/ResultData/TypedValueList.cs rename to src/CADShared/ResultData/TypedValueList.cs diff --git a/CADShared/ResultData/XDataList.cs b/src/CADShared/ResultData/XDataList.cs similarity index 100% rename from CADShared/ResultData/XDataList.cs rename to src/CADShared/ResultData/XDataList.cs diff --git a/CADShared/ResultData/XRecordDataList.cs b/src/CADShared/ResultData/XRecordDataList.cs similarity index 100% rename from CADShared/ResultData/XRecordDataList.cs rename to src/CADShared/ResultData/XRecordDataList.cs diff --git a/CADShared/Runtime/AcPreferences.cs b/src/CADShared/Runtime/AcPreferences.cs similarity index 100% rename from CADShared/Runtime/AcPreferences.cs rename to src/CADShared/Runtime/AcPreferences.cs diff --git a/CADShared/Runtime/DBTrans.cs b/src/CADShared/Runtime/DBTrans.cs similarity index 97% rename from CADShared/Runtime/DBTrans.cs rename to src/CADShared/Runtime/DBTrans.cs index 9f3cbaa45c0f95ea5fb208e3348611da63bed3b8..a1a4cb44a0f84ccdfe11037b060187efc417d306 100644 --- a/CADShared/Runtime/DBTrans.cs +++ b/src/CADShared/Runtime/DBTrans.cs @@ -1,5 +1,7 @@ namespace IFoxCAD.Cad; - +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif using System.Diagnostics; using System.IO; @@ -23,7 +25,7 @@ public sealed class DBTrans : IDisposable /// 事务对象 public static Transaction GetTopTransaction(Database database) { - ArgumentNullEx.ThrowIfNull(database); + ArgumentNullException.ThrowIfNull(database); return database.TransactionManager.TopTransaction ?? throw new Exception("没有顶层事务!"); } @@ -36,9 +38,9 @@ public static Transaction GetTopTransaction(Database database) public static DBTrans GetTop(Database? database = null) { database ??= HostApplicationServices.WorkingDatabase; - ArgumentNullEx.ThrowIfNull(database); + ArgumentNullException.ThrowIfNull(database); var trans = database.TransactionManager.TopTransaction; - ArgumentNullEx.ThrowIfNull(trans); + ArgumentNullException.ThrowIfNull(trans); foreach (var item in _dBTrans) { @@ -108,7 +110,7 @@ internal static DBTrans Top // 由于大量的函数依赖本属性,强迫用户先开启事务 if (_dBTrans.Count == 0) - throw new ArgumentNullException("事务栈没有任何事务,请在调用前创建:" + nameof(DBTrans)); + throw new System.ArgumentNullException("事务栈没有任何事务,请在调用前创建:" + nameof(DBTrans)); var trans = _dBTrans.Peek(); return trans; } @@ -191,7 +193,7 @@ public DBTrans(string fileName, bool commit = true, string? password = null, bool activeOpen = false) { if (string.IsNullOrWhiteSpace(fileName)) - throw new ArgumentNullException(nameof(fileName)); + throw new System.ArgumentNullException(nameof(fileName)); _fileName = fileName.Replace("/", "\\"); // doc.Name总是"D:\\JX.dwg" @@ -538,7 +540,7 @@ public DBObject GetObject(ObjectId id, OpenMode openMode = OpenMode.ForRead, // ReSharper disable once InconsistentNaming public void Task(Action action, bool handlingDBTextDeviation = true) { - ArgumentNullEx.ThrowIfNull(action); + ArgumentNullException.ThrowIfNull(action); // 前台开图 || 后台直接处理 if (Document != null || !handlingDBTextDeviation) { diff --git a/CADShared/Runtime/Env.cs b/src/CADShared/Runtime/Env.cs similarity index 98% rename from CADShared/Runtime/Env.cs rename to src/CADShared/Runtime/Env.cs index caa38dd945305b501a3539c0ec4c6e6bbf4a05a1..3f88e3678d53491b5de373bce35a2faa9f0478cc 100644 --- a/CADShared/Runtime/Env.cs +++ b/src/CADShared/Runtime/Env.cs @@ -1,4 +1,7 @@ using System.Security; +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif // ReSharper disable StringLiteralTypo @@ -627,10 +630,10 @@ public static void RemoveSupportPath(params string[] folders) /// 目录 public static void AppendTrustedPath(params string[] folders) { - if (!folders.Any()) return; + if (folders.Length == 0) return; var trustedPath = GetVar("TRUSTEDPATHS").ToString(); var trustedPathLowerArr = - trustedPath + trustedPath! .ToLower() .Split(';') .Where(item => item != "") @@ -656,7 +659,7 @@ public static void AppendTrustedPath(params string[] folders) public static void RemoveTrustedPath(params string[] folders) { if (!folders.Any()) return; - var trustedPathArr = GetVar("TRUSTEDPATHS").ToString().Split(';').ToList(); + var trustedPathArr = GetVar("TRUSTEDPATHS").ToString()!.Split(';').ToList(); foreach (var folder in folders) { var folderLower = @@ -812,7 +815,7 @@ public static string GetAcapVersionDll(string str = "acdb") /// /// /// 成功返回当前值,失败null - /// + /// public static object? SetVarEx(string key, string value) { var currentVar = GetVar(key); @@ -844,7 +847,7 @@ public static string GetAcapVersionDll(string str = "acdb") /// 返回现有变量词典,然后下次就可以利用它进行设置回来了 public static Dictionary SaveCadVar(Dictionary args) { - ArgumentNullEx.ThrowIfNull(args); + ArgumentNullException.ThrowIfNull(args); var dict = new Dictionary(); foreach (var item in args) { @@ -852,7 +855,7 @@ public static Dictionary SaveCadVar(Dictionary a var ok = SetVarEx(item.Key, item.Value); if (ok is not null) { - dict.Add(item.Key, ok.ToString()); + dict.Add(item.Key, $"{ok}"); continue; } diff --git a/CADShared/Runtime/IdleAction.cs b/src/CADShared/Runtime/IdleAction.cs similarity index 95% rename from CADShared/Runtime/IdleAction.cs rename to src/CADShared/Runtime/IdleAction.cs index 77796411c3bec4954ab29a5db846c017370da10d..b3e0bd49f9aff60ce9e4ef0750a354fb1f502483 100644 --- a/CADShared/Runtime/IdleAction.cs +++ b/src/CADShared/Runtime/IdleAction.cs @@ -43,7 +43,7 @@ public static void Add(Action action) /// /// Acap /// 事件参数 - private static void Acap_Idle(object sender, EventArgs e) + private static void Acap_Idle(object? sender, EventArgs e) { if (Count == 0) { diff --git a/CADShared/Runtime/IdleNoCommandAction.cs b/src/CADShared/Runtime/IdleNoCommandAction.cs similarity index 96% rename from CADShared/Runtime/IdleNoCommandAction.cs rename to src/CADShared/Runtime/IdleNoCommandAction.cs index 0767ea4a5fde62daf6647caba3fcee7501ba1297..72a60b96c364fc1b334e0503e37534c4b5fe9248 100644 --- a/CADShared/Runtime/IdleNoCommandAction.cs +++ b/src/CADShared/Runtime/IdleNoCommandAction.cs @@ -44,7 +44,7 @@ public static void Add(Action action) /// /// Acap /// 事件参数 - private static void Acap_Idle(object sender, EventArgs e) + private static void Acap_Idle(object? sender, EventArgs e) { if (Count == 0) { diff --git a/CADShared/Runtime/SymbolTable.cs b/src/CADShared/Runtime/SymbolTable.cs similarity index 97% rename from CADShared/Runtime/SymbolTable.cs rename to src/CADShared/Runtime/SymbolTable.cs index aef1d3cd49ac01f3f177cb78108246e08d381359..ad73274b0ddd15dca062e4dafc790bae63d62eaa 100644 --- a/CADShared/Runtime/SymbolTable.cs +++ b/src/CADShared/Runtime/SymbolTable.cs @@ -1,5 +1,9 @@ // ReSharper disable RedundantNameQualifier +#if a2024 || zcad +using ArgumentNullException = IFoxCAD.Basal.ArgumentNullEx; +#endif + namespace IFoxCAD.Cad; /// @@ -218,11 +222,9 @@ public void Remove(ObjectId id) public void Change(string name, Action action) { var record = GetRecord(name); - if (record is not null) - { - using (record.ForWrite()) - action.Invoke(record); - } + if (record is null) return; + using (record.ForWrite()) + action.Invoke(record); } /// @@ -319,7 +321,7 @@ public IEnumerable GetRecordNames(Func filter) /// 对象id private ObjectId GetRecordFrom(SymbolTable table, string name, bool over) { - ArgumentNullEx.ThrowIfNull(table); + ArgumentNullException.ThrowIfNull(table); var rid = this[name]; var has = rid != ObjectId.Null; @@ -399,7 +401,7 @@ public void ForEach(Action task, OpenMode openMode = Op { //if (task == null) // throw new ArgumentNullException(nameof(task)); - ArgumentNullEx.ThrowIfNull(task); + ArgumentNullException.ThrowIfNull(task); LoopState state = new(); /*这种方式比Action改Func更友好*/ var i = 0; foreach (var id in this) diff --git a/CADShared/Runtime/SystemVariableManager.cs b/src/CADShared/Runtime/SystemVariableManager.cs similarity index 98% rename from CADShared/Runtime/SystemVariableManager.cs rename to src/CADShared/Runtime/SystemVariableManager.cs index c065bb815aa3c46ad74609d7570edc8507ecc700..a418ea7fde8f4d8cf545b947a30e134a80cd5102 100644 --- a/CADShared/Runtime/SystemVariableManager.cs +++ b/src/CADShared/Runtime/SystemVariableManager.cs @@ -61,7 +61,7 @@ public int Auprec /// /// 用于设置当前空间的当前注释比例的值 /// - public static string CanNoScale => Acaop.GetSystemVariable(nameof(CanNoScale)).ToString(); + public static string CanNoScale => Acaop.GetSystemVariable(nameof(CanNoScale)).ToString()!; /// /// 用于显示当前的注释性比例 @@ -79,7 +79,7 @@ public int Auprec /// public static string CEColor { - get => Acaop.GetSystemVariable(nameof(CEColor)).ToString(); + get => Acaop.GetSystemVariable(nameof(CEColor)).ToString()!; set => Acaop.SetSystemVariable(nameof(CEColor), value); } @@ -97,7 +97,7 @@ public static double CELtScale /// public static string CELType { - get => Acaop.GetSystemVariable(nameof(CELType)).ToString(); + get => Acaop.GetSystemVariable(nameof(CELType)).ToString()!; set => Acaop.SetSystemVariable(nameof(CELType), value); } @@ -124,7 +124,7 @@ public static double CircleRad /// public static string CLayer { - get => Acaop.GetSystemVariable(nameof(CLayer)).ToString(); + get => Acaop.GetSystemVariable(nameof(CLayer)).ToString()!; set => Acaop.SetSystemVariable(nameof(CLayer), value); } @@ -165,14 +165,14 @@ public static bool CmdEcho /// /// 当前的命令 /// - public static string CmdNames => Acaop.GetSystemVariable(nameof(CmdNames)).ToString(); + public static string CmdNames => Acaop.GetSystemVariable(nameof(CmdNames)).ToString()!; /// /// 返回图形中的当前选项卡(模型或布局)的名称 /// public static string CTab { - get => Acaop.GetSystemVariable(nameof(CTab)).ToString(); + get => Acaop.GetSystemVariable(nameof(CTab)).ToString()!; set => Acaop.SetSystemVariable(nameof(CTab), value); } diff --git a/CADShared/SelectionFilter/OpComp.cs b/src/CADShared/SelectionFilter/OpComp.cs similarity index 100% rename from CADShared/SelectionFilter/OpComp.cs rename to src/CADShared/SelectionFilter/OpComp.cs diff --git a/CADShared/SelectionFilter/OpEqual.cs b/src/CADShared/SelectionFilter/OpEqual.cs similarity index 100% rename from CADShared/SelectionFilter/OpEqual.cs rename to src/CADShared/SelectionFilter/OpEqual.cs diff --git a/CADShared/SelectionFilter/OpFilter.cs b/src/CADShared/SelectionFilter/OpFilter.cs similarity index 100% rename from CADShared/SelectionFilter/OpFilter.cs rename to src/CADShared/SelectionFilter/OpFilter.cs diff --git a/CADShared/SelectionFilter/OpList.cs b/src/CADShared/SelectionFilter/OpList.cs similarity index 100% rename from CADShared/SelectionFilter/OpList.cs rename to src/CADShared/SelectionFilter/OpList.cs diff --git a/CADShared/SelectionFilter/OpLogi.cs b/src/CADShared/SelectionFilter/OpLogi.cs similarity index 100% rename from CADShared/SelectionFilter/OpLogi.cs rename to src/CADShared/SelectionFilter/OpLogi.cs diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000000000000000000000000000000000000..a5a1f772b348d334db6287ec93d39ffac3fcffdd --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,37 @@ + + + + 0.9.2-preview1 + 增加net8支持,增加zwcad2025支持 + + + + preview + enable + true + true + true + True + True + x64 + IFoxCAD.CAD + true + true + ..\..\bin\$(Configuration)\ + + + + InspireFunction + xsfhlzh;vicwjb;liuqihong;DYH + InspireFunction + 基于.NET的二次开发基本类库. + true + https://gitee.com/inspirefunction/ifoxcad + https://gitee.com/inspirefunction/ifoxcad.git + git + IFox;cad;AutoCad;C#;NET;ZwCad + readme.md + LICENSE + + + \ No newline at end of file diff --git a/IFoxCAD.AutoCad/GlobalUsings.cs b/src/IFoxCAD.AutoCad/GlobalUsings.cs similarity index 100% rename from IFoxCAD.AutoCad/GlobalUsings.cs rename to src/IFoxCAD.AutoCad/GlobalUsings.cs diff --git a/IFoxCAD.AutoCad/IFoxCAD.AutoCad.csproj b/src/IFoxCAD.AutoCad/IFoxCAD.AutoCad.csproj similarity index 52% rename from IFoxCAD.AutoCad/IFoxCAD.AutoCad.csproj rename to src/IFoxCAD.AutoCad/IFoxCAD.AutoCad.csproj index 7a48fc4077f76eff14af8a588ca7de82aac2e0df..d2d9d1c636f430eca3c4119001b2a4df8690eba2 100644 --- a/IFoxCAD.AutoCad/IFoxCAD.AutoCad.csproj +++ b/src/IFoxCAD.AutoCad/IFoxCAD.AutoCad.csproj @@ -1,61 +1,48 @@  - net48 - Preview - enable - x64 - IFoxCAD.CAD - true - true - true + net48;net8.0-windows - true - true IFox.CAD.ACAD IFox.CAD.ACAD IFox.CAD.ACAD - 0.9.1.10 - xsfhlzh, vicwjb, liuqihong, DYH - 基于.NET的二次开发基本类库. - https://www.nuget.org/packages/IFox.CAD.ACAD/ - https://gitee.com/inspirefunction/ifoxcad - git - IFox,Cad,AutoCad,C#,NET, - InspireFunction - readme.md - 修复region同环曲线不闭合的问题 - LICENSE none True - $(DefineConstants);acad none false - $(DefineConstants);acad bin\Release\IFoxCAD.AutoCad.xml + + $(Configuration);acad;a2024 + + + + $(Configuration);acad;a2025 + true + + - + True \ - + True \ - + @@ -63,9 +50,11 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - + + + + diff --git a/src/IFoxCAD.ZwCad/GlobalUsings.cs b/src/IFoxCAD.ZwCad/GlobalUsings.cs new file mode 100644 index 0000000000000000000000000000000000000000..a3365f56a2c6baa8b18683d5b5e54487f6ffbb4a --- /dev/null +++ b/src/IFoxCAD.ZwCad/GlobalUsings.cs @@ -0,0 +1,52 @@ +global using ZwSoft.ZwCAD.ApplicationServices; +global using ZwSoft.ZwCAD.DatabaseServices; +global using ZwSoft.ZwCAD.EditorInput; +global using ZwSoft.ZwCAD.Geometry; +global using ZwSoft.ZwCAD.GraphicsInterface; +global using ZwSoft.ZwCAD.Runtime; +global using ZwSoft.ZwCAD.Windows; +global using ZwSoft.ZwCAD.Colors; +global using ZwSoft.ZwCAD.DatabaseServices.Filters; +global using ZwSoft.ZwCAD.GraphicsSystem; +global using LineWeight = ZwSoft.ZwCAD.DatabaseServices.LineWeight; +global using Viewport = ZwSoft.ZwCAD.DatabaseServices.Viewport; +global using Color = ZwSoft.ZwCAD.Colors.Color; +global using Acap = ZwSoft.ZwCAD.ApplicationServices.Application; +global using Acaop = ZwSoft.ZwCAD.ApplicationServices.Core.Application; +global using Polyline = ZwSoft.ZwCAD.DatabaseServices.Polyline; +global using Group = ZwSoft.ZwCAD.DatabaseServices.Group; +global using CursorType = ZwSoft.ZwCAD.EditorInput.CursorType; +global using ColorDialog = ZwSoft.ZwCAD.Windows.ColorDialog; +global using StatusBar = ZwSoft.ZwCAD.Windows.StatusBar; +global using Utils = ZwSoft.ZwCAD.Internal.Utils; +global using SystemVariableChangedEventArgs = ZwSoft.ZwCAD.ApplicationServices.SystemVariableChangedEventArgs; +global using AcException = ZwSoft.ZwCAD.Runtime.Exception; +global using System; +global using System.Reflection; +global using System.Collections; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Threading; +global using System.Text; +global using System.Runtime.InteropServices; +global using System.ComponentModel; +global using Exception = System.Exception; +global using DrawingColor = System.Drawing.Color; +global using Registry = Microsoft.Win32.Registry; +global using RegistryKey = Microsoft.Win32.RegistryKey; +global using Region = ZwSoft.ZwCAD.DatabaseServices.Region; +global using Microsoft.Win32; +global using System.Linq.Expressions; +global using System.Collections.ObjectModel; +// 系统引用 +global using System.Text.RegularExpressions; +global using System.Runtime.CompilerServices; +global using System.Windows.Input; +global using System.Globalization; +global using System.Diagnostics; + +// global using System.Windows.Data; +global using System.Net; +global using System.Diagnostics.CodeAnalysis; +global using IFoxCAD.Basal; \ No newline at end of file diff --git a/src/IFoxCAD.ZwCad/IFoxCAD.ZwCad.csproj b/src/IFoxCAD.ZwCad/IFoxCAD.ZwCad.csproj new file mode 100644 index 0000000000000000000000000000000000000000..4b659bef5716b847b13970b17f675cddffc5a990 --- /dev/null +++ b/src/IFoxCAD.ZwCad/IFoxCAD.ZwCad.csproj @@ -0,0 +1,49 @@ + + + net48 + + + + IFox.CAD.ZCAD + IFox.CAD.ZCAD + IFox.CAD.ZCAD + + + + none + True + + + + none + false + bin\Release\IFoxCAD.ZwCad.xml + + + + $(Configuration);zcad;z2025 + + + + + True + \ + + + True + \ + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + diff --git a/tests/TestAcad2025/GlobalUsings.cs b/tests/TestAcad2025/GlobalUsings.cs new file mode 100644 index 0000000000000000000000000000000000000000..045196f703ea51e14af47638509ed97287167b95 --- /dev/null +++ b/tests/TestAcad2025/GlobalUsings.cs @@ -0,0 +1,50 @@ +/// 系统引用 +global using System; +global using System.Collections; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Text; +global using System.Reflection; +global using System.Text.RegularExpressions; +global using Microsoft.Win32; +global using System.ComponentModel; +global using System.Runtime.InteropServices; +global using System.Collections.Specialized; +global using System.Threading; +global using Exception = System.Exception; + +global using Registry = Microsoft.Win32.Registry; +global using RegistryKey = Microsoft.Win32.RegistryKey; + +/// autocad 引用 +global using Autodesk.AutoCAD.ApplicationServices; +global using Autodesk.AutoCAD.EditorInput; +global using Autodesk.AutoCAD.Colors; +global using Autodesk.AutoCAD.DatabaseServices; +global using Autodesk.AutoCAD.Geometry; +global using Autodesk.AutoCAD.Runtime; +global using Acap = Autodesk.AutoCAD.ApplicationServices.Application; +global using Acaop = Autodesk.AutoCAD.ApplicationServices.Core.Application; +global using Acgi = Autodesk.AutoCAD.GraphicsInterface; + +global using Autodesk.AutoCAD.DatabaseServices.Filters; +global using Autodesk.AutoCAD; + +// jig命名空间会引起Viewport/Polyline等等重义,最好逐个引入 using Autodesk.AutoCAD.GraphicsInterface +global using WorldDraw = Autodesk.AutoCAD.GraphicsInterface.WorldDraw; +global using Manager = Autodesk.AutoCAD.GraphicsSystem.Manager; +global using Group = Autodesk.AutoCAD.DatabaseServices.Group; +global using Viewport = Autodesk.AutoCAD.DatabaseServices.Viewport; +global using Autodesk.AutoCAD.GraphicsInterface; +global using Polyline = Autodesk.AutoCAD.DatabaseServices.Polyline; +global using Cad_DwgFiler = Autodesk.AutoCAD.DatabaseServices.DwgFiler; +global using Cad_DxfFiler = Autodesk.AutoCAD.DatabaseServices.DxfFiler; +global using Cad_ErrorStatus = Autodesk.AutoCAD.Runtime.ErrorStatus; + + +/// ifoxcad +global using IFoxCAD.Cad; +global using IFoxCAD.Basal; + +global using Test; diff --git a/tests/TestAcad2025/TestAcad2025.csproj b/tests/TestAcad2025/TestAcad2025.csproj new file mode 100644 index 0000000000000000000000000000000000000000..126352d70dc681ed1b0df50713aad572978c0805 --- /dev/null +++ b/tests/TestAcad2025/TestAcad2025.csproj @@ -0,0 +1,60 @@ + + + preview + enable + + net48;net8.0-windows + true + true + x64 + True + 1.0.0.* + 1.0.0.0 + false + + + + none + false + + + + none + true + + + + $(Configuration);acad;a2024 + + + + $(Configuration);acad;a2025 + true + + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/TestShared/CmdINI.cs b/tests/TestShared/CmdINI.cs new file mode 100644 index 0000000000000000000000000000000000000000..e4deab7421abeb2990a02f75dbac0bbf64dc6f90 --- /dev/null +++ b/tests/TestShared/CmdINI.cs @@ -0,0 +1,193 @@ +//#define givePeopleTest +#if false +using System.Diagnostics; + +namespace Test; + +/// +/// 注册中心(自动执行接口): +/// +/// 继承虚函数后才能使用
+/// 0x01 netload加载之后自动执行,写入启动注册表,下次就不需要netload了
+/// 0x02 反射调用特性和接口
+/// 启动cad后的执行顺序为:
+/// 1:构造函数
+/// 2:特性..多个
+/// 3:接口..多个
+/// 4:本类的构造函数
+/// +/// **** 警告 **** +/// 如果不写一个 储存这个对象, +/// 而是直接写卸载命令在此, +/// 第一次加载的时候会初始化完成,然后这个类生命就结束了, +/// 第二次通过命令进入,会引发构造函数再次执行,留意构造函数的打印信息即可发现 +/// +///
+///
+public class AutoRegAssemEx : AutoRegAssem +{ + public AutoRegAssemEx() : base(AutoRegConfig.All) + { + CmdInit.AutoRegAssemEx = this; +#if givePeopleTest +#if Debug + // 此处用来反射本程序集,检查是否存在重复命令 + AutoReflection.DebugCheckCmdRecurrence(); +#endif + Env.Printl($"{nameof(AutoRegAssemEx)}构造函数,开始自动执行\r\n"); +#endif + } +} + + +public class CmdInit +{ + public static AutoRegAssemEx? AutoRegAssemEx; + + /// 如果netload之后用 删除注册表, + /// 由于不是也不能卸载dll,再netload是无法执行自动接口的, + /// 所以此时会产生无法再注册的问题...因此需要暴露此注册函数(硬来) + [CommandMethod(nameof(IFoxAddReg))] + public void IFoxAddReg() + { + Env.Printl($"加入注册表"); + + AutoRegAssemEx ??= new(); + AutoRegAssemEx.RegApp(); + } + + /// + /// 卸载注册表信息 + /// + [CommandMethod(nameof(IFoxRemoveReg))] + public void IFoxRemoveReg() + { + Env.Printl($"卸载注册表"); + + // 防止卸载两次,不然会报错的 + AutoRegAssemEx?.UnRegApp(); + AutoRegAssemEx = null; + } + + [CommandMethod(nameof(Debugx))] + public void Debugx() + { + var flag = Environment.GetEnvironmentVariable("debugx", EnvironmentVariableTarget.User); + if (flag == null || flag == "0") + { + Environment.SetEnvironmentVariable("debugx", "1", EnvironmentVariableTarget.User); + Env.Printl($"vs输出 -- 已启用"); + } + else + { + Environment.SetEnvironmentVariable("debugx", "0", EnvironmentVariableTarget.User); + Env.Printl($"vs输出 -- 已禁用"); + } + } +} + +#if givePeopleTest +/* + * 自动执行:特性 + */ +public class Cmd_IFoxInitialize +{ + int TestInt = 0; + + [IFoxInitialize] + public void Initialize() + { + Env.Printl($"开始自动执行,可以分开多个类和多个函数:{nameof(Cmd_IFoxInitialize)}.{nameof(Initialize)}+{TestInt}"); + } + + [IFoxInitialize] + public void Initialize2() + { + Env.Printl($"开始自动执行,可以分开多个类和多个函数,又一次测试:{nameof(Cmd_IFoxInitialize)}.{nameof(Initialize2)}"); + } + + //[IFoxInitialize(isInitialize: false)] + //public void Terminate() + //{ + // try + // { + // // 注意此时编辑器已经回收,所以此句引发错误 + // // 您可以写一些其他的释放动作,例如资源回收之类的 + // Env.Printl($"\n 结束自动执行 Terminate \r\n"); + // // 改用 + // Debugx.Printl($"\n 结束自动执行 Terminate \r\n"); + // } + // catch (System.Exception e) + // { + // System.Windows.Forms.MessageBox.Show(e.Message); + // } + //} + + [IFoxInitialize] + public static void StaticInitialize() + { + Env.Printl($"开始自动执行,静态调用:{nameof(Cmd_IFoxInitialize)}.{nameof(StaticInitialize)}"); + } +} + + +/* + * 自动执行:接口 + */ +public class Cmd_IFoxInitializeInterface : IFoxAutoGo +{ + int TestInt = 0; + public Cmd_IFoxInitializeInterface() + { + Env.Printl($"开始自动执行,{nameof(IFoxAutoGo)}接口调用:{nameof(Cmd_IFoxInitializeInterface)}::{TestInt}"); + } + + public Sequence SequenceId() + { + return Sequence.Last; + } + + public void Initialize() + { + Env.Printl($"开始自动执行,{nameof(IFoxAutoGo)}接口调用:{nameof(Initialize)}::{TestInt}"); + } + + public void Terminate() + { + Debugx.Printl($"开始自动执行,{nameof(IFoxAutoGo)}接口调用:{nameof(Terminate)}::{TestInt}"); + // try + // { + // // 注意此时编辑器已经回收,所以此句没用,并引发错误 + // Env.Printl($"结束自动执行 {nameof(Cmd_IFoxInitializeInterface)}.Terminate \r\n"); + // } + // catch (System.Exception e) + // { + // System.Windows.Forms.MessageBox.Show(e.Message); + // } + } +} +#endif + + + +#endif + +public class Init +{ + [CommandMethod(nameof(Initialize))] + public void Initialize() + { + + // var assembly= Assembly.GetExecutingAssembly(); + // Env.Printl(assembly.GetName().Name); + // var info = new AssemInfo(assembly); + // Env.Printl(info.ToString()); + // AutoReg.RegApp(info); + AutoReg.RegApp(); + } + + public void Terminate() + { + + } +} \ No newline at end of file diff --git a/tests/TestShared/Copyclip.cs b/tests/TestShared/Copyclip.cs new file mode 100644 index 0000000000000000000000000000000000000000..370936c4a4158fbc94fca8b843d321bfefa97382 --- /dev/null +++ b/tests/TestShared/Copyclip.cs @@ -0,0 +1,881 @@ +#define test +#define COPYCLIP +#define PASTECLIP +#if false +namespace Test; +using System; +using System.Diagnostics; +using System.Drawing.Imaging; +using System.Threading; +using System.Windows; + +/* + * 0x01 (已完成) + * 跨cad复制,由于高版本会保存为当前dwg格式,所以我们将所有都保存为07格式(有动态块), + * 就可以多个版本cad相互复制粘贴了 + * + * 0x02 + * 设置一个粘贴板栈,用tmp.config储存(路径和粘贴基点), + * ctrl+shfit+v v v 就是三次前的剪贴板内容;也可以制作一个剪贴板窗口更好给用户交互 + * + * 0x03 + * 天正图元的复制粘贴出错原因 + * + * 引用技术贴: + * https://forums.autodesk.com/t5/net/paste-list-of-objects-from-clipboard-on-dwg-file-using-c-net/td-p/6797606 + */ +public class Copyclip +{ + #region 命令 +#if test + static bool _IsRunIFoxCopyClip = false; + [IFoxInitialize] // 惊惊: 遇到了高版本无法导出WMF,放弃此功能,等待有缘人 + public void Init() + { + Acap.DocumentManager.DocumentLockModeChanged += Dm_VetoCommand; + Env.Printl($"※剪贴板控制※\n{nameof(Copyclip_Switch)} - 切换开关\n"); + } + + [CommandMethod(nameof(Copyclip_Switch))] + public void Copyclip_Switch() + { + _IsRunIFoxCopyClip = !_IsRunIFoxCopyClip; + Env.Printl("已经 " + (_IsRunIFoxCopyClip ? "开启" : "禁用") + " 剪贴板+"); + } + + /// + /// 反应器->命令否决触发命令前(不可锁文档) + /// + /// + /// + void Dm_VetoCommand(object sender, DocumentLockModeChangedEventArgs e) + { + if (string.IsNullOrEmpty(e.GlobalCommandName) || e.GlobalCommandName == "#") + return; + if (!_IsRunIFoxCopyClip) + return; + + var up = e.GlobalCommandName.ToUpper(); + + string? cmd = null; +#if COPYCLIP + if (up == "COPYCLIP")// 复制 + { + e.Veto(); + cmd = nameof(IFoxCopyClip); + } + else if (up == "COPYBASE") //ctrl+shift+c 带基点复制 + { + e.Veto(); + cmd = nameof(IFoxCopyBase); + } + else if (up == "CUTCLIP") // 剪切 + { + e.Veto(); + cmd = nameof(IFoxCutclip); + } +#endif +#if PASTECLIP + if (up == "PASTECLIP")// 粘贴 + { + // === 完成之后此处将会移除 + // 粘贴文本的生成单行文字/多行文字,这些还需要自己去实现 + var getClip = ClipTool.GetClipboard(ClipboardEnv.CadVer, out TagClipboardInfo tag); + if (!getClip) + return; + //=== 完成之后此处将会移除 + + e.Veto(); + cmd = nameof(IFoxPasteClip); + } + else if (up == "PASTEBLOCK") //ctrl+shift+v 粘贴为块 + { + // === 完成之后此处将会移除 + var getClip = ClipTool.GetClipboard(ClipboardEnv.CadVer, out TagClipboardInfo tag); + if (!getClip) + return; + //=== 完成之后此处将会移除 + + e.Veto(); + cmd = nameof(IFoxPasteBlock); + } +#endif + if (cmd != null) + { + var dm = Acap.DocumentManager; + if (dm.Count == 0) + return; + var doc = dm.MdiActiveDocument; + // 发送命令是因为com导出WMF需要命令形式,否则将报错 + // 但是发送命令会导致选择集被取消了,那么就需要设置 CommandFlags.Redraw + doc.SendStringToExecute(cmd + "\n", true, false, false); + } + } + + + /// + /// 复制 + /// + [CommandMethod(nameof(IFoxCopyClip), CommandFlags.UsePickSet | CommandFlags.Redraw)] + public void IFoxCopyClip() + { + Copy(false); + } + /// + /// 带基点复制 + /// + [CommandMethod(nameof(IFoxCopyBase), CommandFlags.UsePickSet | CommandFlags.Redraw)] + public void IFoxCopyBase() + { + Copy(true); + } + /// + /// 剪切 + /// + [CommandMethod(nameof(IFoxCutclip), CommandFlags.UsePickSet | CommandFlags.Redraw)] + public void IFoxCutclip() + { + Copy(false, true); + } + + + /// + /// 粘贴 + /// + [CommandMethod(nameof(IFoxPasteClip))] + public void IFoxPasteClip() + { + Paste(false); + } + /// + /// 粘贴为块 + /// + [CommandMethod(nameof(IFoxPasteBlock))] + public void IFoxPasteBlock() + { + Paste(true); + } +#endif + #endregion + + // 想要重启cad之后还可以继续用剪贴板,那么就不要这个: + // [IFoxInitialize(isInitialize: false)] + // 会出现永远存在临时文件夹的情况: + // 0x01 复制的时候,无法删除占用中的, + // 0x02 调试期间直接退出 acad.exe + public void Terminate() + { + // 此处要先去删除tmp文件夹的上次剪贴板产生的dwg文件 + for (int i = _delFile.Count - 1; i >= 0; i--) + { + try + { + if (File.Exists(_delFile[i])) + File.Delete(_delFile[i]); + _delFile.RemoveAt(i); + } + catch { Env.Printl("无法删除(是否占用):" + _delFile[i]); } + } + } + + + /// + /// 读写锁,当资源处于写入模式时,
+ /// 其他线程写入需要等待本次写入结束之后才能继续写入 + /// 参考链接 + ///
+ static readonly ReaderWriterLockSlim _rwLock = new(); + + /// + /// 储存准备删除的文件 + /// 也可以用txt代替 + /// 如果删除出错(占用),将一直在这个集合中,直到cad关闭 + /// + readonly List _delFile = new(); + + /// + /// 复制 + /// + /// + void Copy(bool getPoint, bool isEraseSsget = false) + { + try + { + if (!_rwLock.IsWriteLockHeld) + _rwLock.EnterWriteLock(); // 进入写入锁 + + var dm = Acap.DocumentManager; + if (dm.Count == 0) + return; + var doc = dm.MdiActiveDocument; + if (doc == null) + return; + + ObjectId[] idArray; +#if true + var psr = doc.Editor.SelectImplied();// 预选 + if (psr.Status != PromptStatus.OK) + psr = doc.Editor.GetSelection();// 手选 + if (psr.Status != PromptStatus.OK) + return; + idArray = psr.Value.GetObjectIds(); +#endif + + // 设置基点 + Point3d pt = Point3d.Origin; + var tempFile = CreateTempFileName(); + while (File.Exists(tempFile) || + File.Exists(Path.ChangeExtension(tempFile, "wmf"))) + { + tempFile = CreateTempFileName(); + Thread.Sleep(1); + } + + using DBTrans tr = new(); + + + #region 写入 WMF 数据 + /* + * 通过cadCom导出wmf(免得自己转换每种图元), + * 再将wmf转为emf,然后才能写入剪贴板 + * wmf生成(win32api): https://www.cnblogs.com/5iedu/p/4706324.html + */ + IntPtr hMetaFile = IntPtr.Zero; + { + var wmf = Path.ChangeExtension(tempFile, "wmf"); + Env.Editor.ComExportWMF(wmf, idArray); + if (File.Exists(wmf)) + { + hMetaFile = PlaceableMetaHeader.Wmf2Emf(wmf);//emf文件句柄 + try { File.Delete(wmf); } + catch (Exception e) { Env.Printl(e); } + } + else + { + Env.Printl("没有创建wmf,失败"); + } + } + if (hMetaFile != IntPtr.Zero) + { + // 克隆一个,并写入描述...此处尚未完成 + // EmfTool.SetEnhMetaFileDescriptionEx(ref hMetaFile, "这是阿惊的emf"); + } + + // 保存文件 + //var emfsave = Path.ChangeExtension(cadClipType.File, ".emf"); + //EmfTool.Save(emf, emfsave); + #endregion + + #region 写入 AutoCAD.R17 数据 + if (getPoint) + { + var pr = doc.Editor.GetPoint("\n选择基点"); + if (pr.Status != PromptStatus.OK) + return; + pt = pr.Value; + } + else + { + // 遍历块内 + // 获取左下角点作为基点 + double minx = double.MaxValue; + double miny = double.MaxValue; + double minz = double.MaxValue; + foreach (var id in idArray) + { + var ent = tr.GetObject(id); + if (ent == null) + continue; + var info = ent.GetBoundingBoxEx(); + if (info != null) + { + if (ent is BlockReference brf) + info.Value.Move(brf.Position, Point3d.Origin); + minx = minx > info.Value.MinX ? info.Value.MinX : minx; + miny = miny > info.Value.MinY ? info.Value.MinY : miny; + minz = minz > info.Value.MinZ ? info.Value.MinZ : minz; + } + } + pt = new(minx, miny, minz); + } + + var cadClipType = new TagClipboardInfo(tempFile, pt); + + // 克隆到目标块表内 + using (DBTrans fileTr = new(cadClipType.File)) + { + fileTr.Task(() => { + using IdMapping map = new(); + using ObjectIdCollection ids = new(idArray); + tr.Database.WblockCloneObjects( + ids, + fileTr.ModelSpace.ObjectId, + map, + DuplicateRecordCloning.Replace, + false); + }); + + // 大于dwg07格式的,保存为07,以实现高低版本通用剪贴板 + // 小于dwg07格式的,本工程没有支持cad06dll + if ((int)DwgVersion.Current >= 27) + fileTr.Database.SaveFile((DwgVersion)27, false); + else + throw new ArgumentException($"版本过低,无法保存,版本号:{DwgVersion.Current}"); + } + #endregion + + // 必须一次性写入剪贴板,详见 OpenClipboardTask + var cadClipFormat = ClipTool.RegisterClipboardFormat(ClipboardEnv.CadVer); + + // 剪贴板需要的指针: 克隆一个新的,不释放内存,不锁定内存(否则高频触发时候卡死) + var cadClipData = cadClipType.CloneToPtr(); + + bool getFlag = ClipTool.OpenClipboardTask(true, () => { + // 写入剪贴板: cad图元 + ClipTool.SetClipboardData(cadClipFormat, cadClipData); + + // 写入剪贴板: wmf,使得在粘贴链接的时候可以用 + if (hMetaFile != IntPtr.Zero) + ClipTool.SetClipboardData((uint)ClipboardFormat.CF_ENHMETAFILE, hMetaFile); + }); + if (hMetaFile != IntPtr.Zero) + EmfTool.DeleteEnhMetaFile(hMetaFile); + + // 成功拷贝就删除上一次的临时文件 + if (getFlag) + Terminate(); + + // 加入删除队列,下次删除 + if (!_delFile.Contains(cadClipType.File)) + _delFile.Add(cadClipType.File); + + // 剪切时候删除 + if (isEraseSsget) + { + idArray.ForEach(id => { + id.Erase(); + }); + } + } + catch (Exception e) + { + Debugger.Break(); + throw e; + } + finally + { + if (_rwLock.IsWriteLockHeld) + _rwLock.ExitWriteLock(); // 退出写入锁 + } + } + + + /// + /// 粘贴 + /// + /// + void Paste(bool isBlock) + { + try + { + if (!_rwLock.IsWriteLockHeld) + _rwLock.EnterWriteLock(); // 进入写入锁 + + var dm = Acap.DocumentManager; + if (dm.Count == 0) + return; + + var getClip = ClipTool.GetClipboard(ClipboardEnv.CadVer, out TagClipboardInfo tag); + if (!getClip) + { + // 在没有安装插件的高版本cad中复制,此时剪贴板是当前版本的, + // 那么在安装了插件的cad中需要识别这个同版本的剪贴板内容 + // 例如天正只在某个启动的cad中加载插件,而不是全部 + getClip = ClipTool.GetClipboard(ClipboardEnv.CadCurrentVer, out tag); + if (!getClip) + return; + } + + var cadClipType = tag; + Env.Print("粘贴来源: " + cadClipType.File); + + if (!File.Exists(cadClipType.File)) + { + Env.Print("文件不存在"); + return; + } + + // 获取临时文件的图元id + List fileEntityIds = []; + using (DBTrans fileTr = new(cadClipType.File, commit: false, + fileOpenMode: FileOpenMode.OpenForReadAndAllShare)) + { + fileTr.ModelSpace.ForEach(id => { + if (id.IsOk()) + fileEntityIds.Add(id); + }); + } + if (fileEntityIds.Count == 0) + return; + + using DBTrans tr = new(); + tr.Editor?.SetImpliedSelection(new ObjectId[0]); // 清空选择集 + + // 新建块表记录 + var btr = CreateBlockTableRecord(tr, cadClipType.File); + if (btr == null) + return; + + /// 克隆进块表记录 + /// 动态块粘贴之后,用ctrl+z导致动态块特性无法恢复, + /// 是因为它: + using IdMapping map = new(); + using ObjectIdCollection idc = new(fileEntityIds.ToArray()); + tr.Task(() => { + tr.Database.WblockCloneObjects( + idc, + btr.ObjectId, // tr.Database.BlockTableId, // 粘贴目标 + map, + DuplicateRecordCloning.Ignore, + false); + }); + + // 移动块内,从基点到原点 + foreach (var id in btr) + { + if (!id.IsOk()) + { + Env.Printl("jig预览块内有克隆失败的脏东西,是否天正克隆期间导致?"); + continue; + } + var ent = tr.GetObject(id); + if (ent == null) + continue; + using (ent.ForWrite()) + ent.Move(cadClipType.Point, Point3d.Origin); + } + + // 预览并获取交互点 + // 天正此处可能存在失败:天正图元不给你jig接口调用之类的 + using var moveJig = new JigEx((mousePoint, drawEntitys) => { + var brf = new BlockReference(Point3d.Origin, btr.ObjectId); + brf.Move(Point3d.Origin, mousePoint); + drawEntitys.Enqueue(brf); + }); + var jppo = moveJig.SetOptions(cadClipType.Point); + jppo.Keywords.Add(" ", " ", "<空格取消>"); + jppo.Keywords.Add("A", "A", "引线点粘贴(A)"); + + var dr = moveJig.Drag(); + Point3d moveTo = Point3d.Origin; + if (dr.Status == PromptStatus.Keyword) + moveTo = cadClipType.Point; + else if (dr.Status == PromptStatus.OK) + moveTo = moveJig.MousePointWcsLast; + else + { + // 删除jig预览的块表记录 + using (btr.ForWrite()) + btr.Erase(); + return; + } + + if (isBlock) + { + PasteIsBlock(tr, moveJig.Entitys, moveJig.MousePointWcsLast, moveTo); + } + else + { + PasteNotBlock(tr, btr, Point3d.Origin, moveTo); + // 删除jig预览的块表记录 + using (btr.ForWrite()) + btr.Erase(); + } + + try + { + #region 读取剪贴板WMF + var msg = new StringBuilder(); + + int a3 = 0; + a3 = 2 | 4; + if ((a3 & 1) == 1) + { + // win32api 不成功 + ClipTool.OpenClipboardTask(false, () => { + // 剪贴板数据保存目标数据列表 + List _bytes = new(); + var cf = (uint)ClipboardFormat.CF_ENHMETAFILE; + var clipTypeData = ClipTool.GetClipboardData(cf); + if (clipTypeData == IntPtr.Zero) + { + Env.Printl("失败:粘贴剪贴板emf1"); + return; + } + + // 无法锁定剪贴板emf内存,也无法获取GlobalSize + bool locked = WindowsAPI.GlobalLockTask(clipTypeData, prt => { + uint size = WindowsAPI.GlobalSize(prt); + if (size > 0) + { + var buffer = new byte[size]; + Marshal.Copy(prt, buffer, 0, buffer.Length); + _bytes.Add(buffer); + } + }); + if (!locked) + Env.Printl("锁定内存失败"); + }); + } + if ((a3 & 2) == 2) + { + ClipTool.OpenClipboardTask(false, () => { + // 无法锁定剪贴板emf内存,也无法获取GlobalSize + // 需要直接通过指针跳转到指定emf结构位置 + var cf = (uint)ClipboardFormat.CF_ENHMETAFILE; + var clipTypeData = ClipTool.GetClipboardData(cf); + if (clipTypeData == IntPtr.Zero) + { + Env.Printl("失败:粘贴剪贴板emf2"); + return; + } + + int a4 = 1; + //int a4 = 1 | 2 | 4; + if ((a4 & 1) == 1) + { + // 获取描述 + var desc = EmfTool.GetEnhMetaFileDescriptionEx(clipTypeData); + if (!string.IsNullOrEmpty(desc)) + msg.AppendLine("DescriptionEx::" + desc); + } + if ((a4 & 2) == 2) + { + // 获取文件信息 + var obj = EnhMetaHeader.Create(clipTypeData); + msg.AppendLine("EnhMetaHeader::" + obj.ToString()); + } + if ((a4 & 4) == 4) + { + // 保存文件 + //var emfsave = Path.ChangeExtension(cadClipType.File, ".emf"); + //EmfTool.Save(clipTypeData, emfsave); + } + }); + } + if ((a3 & 4) == 4) + { + // c# 读取成功,win32直接读取剪贴板的话是不成功的 + if (Clipboard.ContainsData(DataFormats.EnhancedMetafile)) + { + var iData = Clipboard.GetDataObject();//从剪切板获取数据 + if (!iData.GetDataPresent(DataFormats.EnhancedMetafile)) + return; + var metafile = (Metafile)iData.GetData(DataFormats.EnhancedMetafile); + /* + // 为什么序列化失败了呢 + var formatter = new BinaryFormatter(); + //using MemoryStream stream = new(); + Stream stream = new FileStream("MyFile.bin", FileMode.Create, FileAccess.Write, FileShare.None); + formatter.Serialize(stream, metafile); + stream.Close(); + //Metafile obj = (Metafile)formatter.Deserialize(stream); + */ + msg.AppendLine($"c# Metafile::{metafile.Size}"); + } + } + + if (msg.Length != 0) + Env.Printl(msg); + #endregion + } + catch (Exception e) + { + Debugger.Break(); + DebugEx.Printl(e); + } + } + catch (Exception e)//{"剪贴板上的数据无效 (异常来自 HRESULT:0x800401D3 (CLIPBRD_E_BAD_DATA))"} + { + Debugger.Break(); + DebugEx.Printl(e); + } + finally + { + if (_rwLock.IsWriteLockHeld) + _rwLock.ExitWriteLock(); // 退出写入锁 + } + } + + /// + /// 粘贴为块 + /// + /// + /// + /// + /// + static void PasteIsBlock(DBTrans tr, Entity[] entitys, Point3d move, Point3d moveTo) + { + if (!move.IsEqualTo(moveTo, new Tolerance(1e-6, 1e-6))) + { + entitys.ForEach(ent => { + ent.Move(move, moveTo); + }); + } + tr.CurrentSpace.AddEntity(entitys); + } + + /// + /// 直接粘贴(不为块参照) + /// + /// + /// + /// 它总是为 + /// 目标点 + static void PasteNotBlock(DBTrans tr, BlockTableRecord btr, Point3d move, Point3d moveTo) + { + using ObjectIdCollection ids = new(); + foreach (var id in btr) + { + if (!id.IsOk()) + continue; + ids.Add(id); + } + + // 深度克隆,然后平移到当前目标点位置 + using IdMapping map = new(); + tr.CurrentSpace.DeepCloneEx(ids, map); + + map.GetValues().ForEach(id => { + if (!id.IsOk()) + return; + var ent = tr.GetObject(id); + if (ent == null) + return; + using (ent.ForWrite()) + ent.Move(move, moveTo); + }); + } + + /// + /// 创建块表记录 + /// + /// + /// 此名称若已在块表存在,就会自动用时间名称代替 + /// + BlockTableRecord? CreateBlockTableRecord(DBTrans tr, string tempFile) + { + var blockNameNew = Path.GetFileNameWithoutExtension(tempFile); + while (tr.BlockTable.Has(blockNameNew)) + { + tempFile = CreateTempFileName(); + blockNameNew = Path.GetFileNameWithoutExtension(tempFile); + Thread.Sleep(1); + } + var btrIdNew = tr.BlockTable.Add(blockNameNew); + return tr.GetObject(btrIdNew); + } + + /// + /// 创建临时路径的时间文件名 + /// + /// 格式,X是16进制 + /// + static string CreateTempFileName(string format = "X") + { + var t1 = DateTime.Now.ToString("yyyyMMddHHmmssfffffff"); + t1 = Convert.ToInt32(t1.GetHashCode()).ToString(format); + var t2 = Convert.ToInt32(t1.GetHashCode()).ToString(format);// 这里是为了满足长度而做的 + return Path.GetTempPath() + "A$" + t1 + t2[0] + ".DWG"; + } +} + + +public class TestImageFormat +{ + public ImageFormat GetFormat(string filename) + { + string ext = Path.GetExtension(filename).ToLower(); + var imf = ext switch + { + ".bmp" => ImageFormat.Bmp, + ".gif" => ImageFormat.Gif, + ".jpg" => ImageFormat.Jpeg, + ".tif" => ImageFormat.Tiff, + ".wmf" => ImageFormat.Wmf, + ".png" => ImageFormat.Png, + _ => throw new NotImplementedException(), + }; + return imf; + } + + // 此处相当于截图,后台没有doc不可用 + // https://www.cnblogs.com/shangdishijiao/p/15166499.html + [CommandMethod(nameof(CreatePreviewImage))] + public void CreatePreviewImage() + { + using DBTrans tr = new(); + if (tr.Document == null) + return; + + var doc = tr.Document; + + var size = doc.Window.DeviceIndependentSize; + using var bmp = doc.CapturePreviewImage( + Convert.ToUInt32(size.Width), + Convert.ToUInt32(size.Height)); + + //保存wmf会变png,看二进制签名 + var outFile = Path.ChangeExtension(tr.Database.Filename, ".bmp"); + bmp.Save(outFile, GetFormat(outFile)); + Env.Printl($"保存文件:{outFile}"); + Env.Printl($"保存后缀:{GetFormat(outFile)}"); + + // 利用winAPI截图 + bool getFlag = ClipTool.OpenClipboardTask(true, () => { + BitmapTool.CaptureWndImage(doc.Window.Handle, bitmapHandle => { + // 写入剪贴板: BMP位图,这是截图,不是WMF转BMP,不对 + ClipTool.SetClipboardData((uint)ClipboardFormat.CF_BITMAP, bitmapHandle); + }); + }); + } +} + + +public class OleTestClass +{ + // https://adndevblog.typepad.com/autocad/2012/04/update-linked-ole-object-from-net.html + + /// + /// 更新ole链接 + /// 如果 OLE 对象在另一个应用程序中打开,则上面的代码似乎不会更新该对象 + /// 例如,位图在 Microsoft 画图中打开 + /// + /// + /// + [DllImport("mfc90u.dll", CallingConvention = CallingConvention.ThisCall, + EntryPoint = "#6766")] + public static extern int COleClientItem_UpdateLink(IntPtr thisClientItem); + + [DllImport("acdb18.dll", CallingConvention = CallingConvention.ThisCall, + EntryPoint = "?getOleClientItem@AcDbOle2Frame@@QBEPAVCOleClientItem@@XZ")] + public static extern IntPtr AcDbOle2Frame_getOleClientItem(IntPtr thisOle2Frame); + + [CommandMethod(nameof(UpdateOleClient))] + public void UpdateOleClient() + { + var per = Env.Editor.GetEntity("\n选择OLE更新链接"); + if (per.Status != PromptStatus.OK) + return; + + using DBTrans tr = new(); + var ole2frame = tr.GetObject(per.ObjectId); + if (ole2frame == null) + return; + using (ole2frame.ForWrite()) + { + IntPtr ptrClientItem = AcDbOle2Frame_getOleClientItem(ole2frame.UnmanagedObject); + COleClientItem_UpdateLink(ptrClientItem); + } + } + + + // https://adndevblog.typepad.com/autocad/2012/06/iterating-ole-linked-entities.html + // 获取OLE路径 + [CommandMethod(nameof(GetOlePath))] + public void GetOlePath() + { + using DBTrans tr = new(); + foreach (ObjectId id in tr.CurrentSpace) + { + if (!id.IsOk()) + continue; + + var ole2frame = tr.GetObject(id); + if (ole2frame == null) + continue; + switch (ole2frame.Type) + { + case Ole2Frame.ItemType.Static: + Env.Editor.WriteMessage("\n" + "Static"); + break; + case Ole2Frame.ItemType.Embedded: + Env.Editor.WriteMessage("\n" + "Embedded"); + break; + case Ole2Frame.ItemType.Link: + Env.Editor.WriteMessage("\n" + "Link"); + Env.Editor.WriteMessage("\n" + ole2frame.LinkPath); + break; + } + } + } + + [CommandMethod(nameof(SetOle))] + public void SetOle() + { + //var pr = Env.Editor.GetPoint("\n选择基点"); + //if (pr.Status != PromptStatus.OK) + // return; + //var pt = pr.Value; + + using DBTrans tr = new(); + + // https://forums.autodesk.com/t5/net/how-to-create-an-ole-object-with-ole2frame/td-p/3203222 + var oo = new Ole2Frame(); + oo.SetDatabaseDefaults(); + //oo.CopyFrom() + oo.Position2d = new(0, 0, 100, 100); + + // 打印质量? https://learn.microsoft.com/zh-cn/dotnet/api/system.printing.outputquality?view=windowsdesktop-6.0 + //oo.OutputQuality = + //oo.AutoOutputQuality = + oo.Rotation = 0.0; + //oo.WcsWidth = ; + //oo.WcsHeight = ; + //oo.ScaleWidth = ; + //oo.ScaleHeight = ; + + //宽高比锁定 + oo.LockAspect = true; + } + +#if true2 + // https://forums.autodesk.com/t5/net/how-can-i-read-data-from-ole2frame-object-excel-through-api/td-p/7944241 + public void GetOleForOffice() + { + using DBTrans tr = new(); + foreach (ObjectId id in tr.CurrentSpace) + { + if (!id.IsOk()) + continue; + + var ole2frame = tr.GetObject(id); + if (ole2frame == null) + continue; + + var wb = (Microsoft.Office.Interop.Excel.Workbook)ole2frame.OleObject; + var ws = (Microsoft.Office.Interop.Excel.Worksheet)wb.ActiveSheet; + var range = (Microsoft.Office.Interop.Excel.Range)ws.UsedRange; + + tb.SetSize(range.Rows.Count, range.Columns.Count); + tb.SetRowHeight(range.RowHeight); + tb.SetColumnWidth(range.ColumnWidth); + tb.Position = new Point3d(ole2frame.Location.X, ole2frame.Location.Y, ole2frame.Location.Z); + for (int row = 0; row < range.Rows.Count; row++) + { + for (int col = 0; col < range.Columns.Count; col++) + { + tb.Cells[row, col].TextHeight = 1; + var aa = (Microsoft.Office.Interop.Excel.Range)range.Cells[row + 1, col + 1]; + var bb = Convert.ToString(aa.Value2); + tb.SetTextString(row, col, bb ?? ""); + tb.Cells[row, col].Alignment = CellAlignment.MiddleCenter; + } + } + tb.GenerateLayout(); + } + } +#endif +} + +#endif \ No newline at end of file diff --git a/Test/TestAddEntity.cs b/tests/TestShared/TestAddEntity.cs similarity index 81% rename from Test/TestAddEntity.cs rename to tests/TestShared/TestAddEntity.cs index 70cb05fecaa40ea4079ced50d80b908f9e5faba8..123ba77b7c46ef0d7960697ec7a8d38925a32628 100644 --- a/Test/TestAddEntity.cs +++ b/tests/TestShared/TestAddEntity.cs @@ -1,7 +1,19 @@ -namespace Test; +namespace Test; public partial class Test { + + + + + + + + + + + + [CommandMethod(nameof(Test_Rec))] public void Test_Rec() { @@ -19,10 +31,9 @@ public void Test_Rec() const double pi90 = Math.PI / 2; - Env.Print(pi90); + pi90.Print(); - Tools.TestTimes(1000000, "对角线", () => - { + Tools.TestTimes(1000000, "对角线", () => { var result = false; if (Math.Abs(p13.Length - p24.Length) <= 1e8) { @@ -31,15 +42,13 @@ public void Test_Rec() }); #pragma warning disable CS0219 // 变量已被赋值,但从未使用过它的值 - Tools.TestTimes(1000000, "三次点乘", () => - { + Tools.TestTimes(1000000, "三次点乘", () => { bool result = Math.Abs(p12.DotProduct(p23)) < 1e8 && Math.Abs(p23.DotProduct(p34)) < 1e8 && Math.Abs(p34.DotProduct(p41)) < 1e8; }); - Tools.TestTimes(1000000, "三次垂直", () => - { + Tools.TestTimes(1000000, "三次垂直", () => { bool result = p12.IsParallelTo(p23) && p23.IsParallelTo(p34) && p34.IsParallelTo(p41); @@ -47,6 +56,8 @@ public void Test_Rec() #pragma warning restore CS0219 // 变量已被赋值,但从未使用过它的值 } + + [CommandMethod(nameof(Test_EntRoration))] public void Test_EntRoration() @@ -65,22 +76,19 @@ public void Test_TypeSpeed() { var line = new Line(); var line1 = line as Entity; - Tools.TestTimes(100000, "is 匹配:", () => - { + Tools.TestTimes(100000, "is 匹配:", () => { var t = line1 is Line; }); - Tools.TestTimes(100000, "name 匹配:", () => - { + Tools.TestTimes(100000, "name 匹配:", () => { // var t = line.GetType().Name; var tt = line1.GetType().Name == nameof(Line); }); - Tools.TestTimes(100000, "dxfname 匹配:", () => - { + Tools.TestTimes(100000, "dxfname 匹配:", () => { // var t = line.GetType().Name; var tt = line1.GetRXClass().DxfName == nameof(Line); }); } - // 测试延迟刷新 + [CommandMethod(nameof(Test_sleeptrans))] public static void Test_sleeptrans() { @@ -88,11 +96,14 @@ public static void Test_sleeptrans() for (int i = 0; i < 100; i++) { var cir = CircleEx.CreateCircle(new Point3d(i, i, 0), 0.5); - + if (cir is null) + { + return; + } cir.ColorIndex = i; tr.CurrentSpace.AddEntity(cir); tr.Editor?.Redraw(cir); - Thread.Sleep(10); + System.Threading.Thread.Sleep(10); } } } \ No newline at end of file diff --git a/tests/TestShared/TestBlock.cs b/tests/TestShared/TestBlock.cs new file mode 100644 index 0000000000000000000000000000000000000000..20baa825524e98a23c29a8e527db295beaa9513e --- /dev/null +++ b/tests/TestShared/TestBlock.cs @@ -0,0 +1,864 @@ + +namespace Test; + +public class TestBlock +{ + // 一个命令就把块编辑搞定,减少用户记忆命令 + [CommandMethod(nameof(Test_Refedit), CommandFlags.Redraw | CommandFlags.Session)] + public void Test_Refedit() + { + Env.Printl($"{nameof(Test_Refedit)}-在位编辑块/在位保存块"); + + // 全部用lisp发送命令是为了空格还是本命令 + // 打开了块编辑器,就关闭掉,保存提示 + if ((short)Env.GetVar("BlockEditor") == 1) + { + Env.Editor.RunLisp("(command \"_.bclose\")"); + return; + } + // 0x01 非在位编辑状态: 先选择块参照,然后在位编辑 + // 0x02 在位编辑状态: 关闭并保存 + if (Env.GetVar("RefEditName").ToString() == "")//显示正在编辑的参照名称 + Env.Editor.RunLisp("(command \"_.refedit\")");//直接点选可以有嵌套层次 + else + Env.Editor.RunLisp("(command \"_.refclose\" \"s\")"); + } + + [CommandMethod(nameof(Test_GetBoundingBoxEx))] + public void Test_GetBoundingBoxEx() + { + using DBTrans tr = new(); + var ents = Env.Editor.SSGet().Value?.GetEntities(); + if (ents == null) + return; + foreach (var item in ents) + { + var box = item?.GetBoundingBoxEx(); + Env.Print("min:" + box?.BottomLeft + ";max" + box?.TopRight); + if (box != null) + tr.CurrentSpace.AddEntity(new Line(box.Value.BottomLeft, box.Value.TopRight)); + } + } + + // 前台块定义 + [CommandMethod(nameof(Test_BlockDef))] + public void Test_BlockDef() + { + using DBTrans tr = new(); + // var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + tr.BlockTable.Add("test", + btr => + { + btr.Origin = new Point3d(0, 0, 0); + }, + () => // 图元 + new List { new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)) }, + () => // 属性定义 + { + var id1 = new AttributeDefinition() { Position = new Point3d(0, 0, 0), Tag = "start", Height = 0.2 }; + var id2 = new AttributeDefinition() { Position = new Point3d(1, 1, 0), Tag = "end", Height = 0.2 }; + return new List { id1, id2 }; + } + ); + // ObjectId objectId = tr.BlockTable.Add("a");// 新建块 + // objectId.GetObject().AddEntity();// 测试添加空实体 + tr.BlockTable.Add("test1", + btr => + { + btr.Origin = new Point3d(0, 0, 0); + }, + () => + { + var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + var acText = DBTextEx.CreateDBText(Point3d.Origin, "123", 2.5); + return new List { line, acText }; + }); + } + + // 后台块定义 + [CommandMethod(nameof(Test_BlockDefbehind))] + public void Test_BlockDefbehind() + { + using DBTrans tr = new(@"C:\Users\vic\Desktop\test.dwg"); + // var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + tr.BlockTable.Add("test", + btr => + { + btr.Origin = new Point3d(0, 0, 0); + }, + () => // 图元 + { + return new List { new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)) }; + }, + () => // 属性定义 + { + var id1 = new AttributeDefinition() { Position = new Point3d(0, 0, 0), Tag = "start", Height = 0.2 }; + var id2 = new AttributeDefinition() { Position = new Point3d(1, 1, 0), Tag = "end", Height = 0.2 }; + return new List { id1, id2 }; + } + ); + // ObjectId objectId = tr.BlockTable.Add("a");// 新建块 + // objectId.GetObject().AddEntity();// 测试添加空实体 + tr.BlockTable.Add("test1", + btr => + { + btr.Origin = new Point3d(0, 0, 0); + }, + () => + { + var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + var acText = DBTextEx.CreateDBText(Point3d.Origin, "12345", 2.5); + + return new List { line, acText }; + }); + tr.Database.SaveDwgFile(); + } + + + + // 修改块定义 + [CommandMethod(nameof(Test_BlockDefChange))] + public void Test_BlockDefChange() + { + using DBTrans tr = new(); + // var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + // tr.BlockTable.Change("test", btr => + // { + // btr.Origin = new Point3d(5, 5, 0); + // btr.AddEntity(new Circle(new Point3d(0, 0, 0), Vector3d.ZAxis, 2)); + // btr.GetEntities() + // .ToList() + // .ForEach(e => e.Flush()); // 刷新块显示 + + // }); + + + tr.BlockTable.Change("test", btr => + { + foreach (var id in btr) + { + var ent = tr.GetObject(id); + using (ent!.ForWrite()) + { + switch (ent) + { + case Dimension dBText: + dBText.DimensionText = "234"; + dBText.RecomputeDimensionBlock(true); + break; + case Hatch hatch: + hatch.ColorIndex = 0; + break; + } + } + } + }); + tr.Editor?.Regen(); + } + + [CommandMethod(nameof(Test_InsertBlockDef))] + public void Test_InsertBlockDef() + { + using DBTrans tr = new(); + var line1 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + var line2 = new Line(new Point3d(0, 0, 0), new Point3d(-1, 1, 0)); + var att1 = new AttributeDefinition() { Position = new Point3d(10, 10, 0), Tag = "tagTest1", Height = 1, TextString = "valueTest1" }; + var att2 = new AttributeDefinition() { Position = new Point3d(10, 12, 0), Tag = "tagTest2", Height = 1, TextString = "valueTest2" }; + tr.BlockTable.Add("test1", line1, line2, att1, att2); + + + List ents = []; + var line5 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + var line6 = new Line(new Point3d(0, 0, 0), new Point3d(-1, 1, 0)); + ents.Add(line5); + ents.Add(line6); + tr.BlockTable.Add("test44", ents); + + + var line3 = new Line(new Point3d(5, 5, 0), new Point3d(6, 6, 0)); + var line4 = new Line(new Point3d(5, 5, 0), new Point3d(-6, 6, 0)); + var att3 = new AttributeDefinition() { Position = new Point3d(10, 14, 0), Tag = "tagTest3", Height = 1, TextString = "valueTest3" }; + var att4 = new AttributeDefinition() { Position = new Point3d(10, 16, 0), Tag = "tagTest4", Height = 1, TextString = "valueTest4" }; + tr.BlockTable.Add("test2", new List { line3, line4 }, new List { att3, att4 }); + // tr.CurrentSpace.InsertBlock(new Point3d(4, 4, 0), "test1"); // 测试默认 + // tr.CurrentSpace.InsertBlock(new Point3d(4, 4, 0), "test2"); + // tr.CurrentSpace.InsertBlock(new Point3d(4, 4, 0), "test3"); // 测试插入不存在的块定义 + // tr.CurrentSpace.InsertBlock(new Point3d(0, 0, 0), "test1", new Scale3d(2)); // 测试放大2倍 + // tr.CurrentSpace.InsertBlock(new Point3d(4, 4, 0), "test1", new Scale3d(2), Math.PI / 4); // 测试放大2倍,旋转45度 + + var def1 = new Dictionary + { + { "tagTest1", "1" }, + { "tagTest2", "2" } + }; + tr.CurrentSpace.InsertBlock(new Point3d(0, 0, 0), "test1", atts: def1); + var def2 = new Dictionary + { + { "tagTest3", "1" }, + { "tagTest4", "" } + }; + tr.CurrentSpace.InsertBlock(new Point3d(10, 10, 0), "test2", atts: def2); + tr.CurrentSpace.InsertBlock(new Point3d(20, 20, 0), "test2"); + tr.CurrentSpace.InsertBlock(new Point3d(-10, 0, 0), "test44"); + } + + [CommandMethod(nameof(Test_InsertBlockWithDoubleDatabase))] + public void Test_InsertBlockWithDoubleDatabase() + { + using var tr = new DBTrans(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "test.dwg")); + using var trans = new DBTrans(); + + tr.BlockTable.Add("test456", + btr => + { + btr.Origin = new(0, 0, 0); + }, + () => + { + var line = new Line(new(0, 0, 0), new(1, 1, 0)); + var actext = DBTextEx.CreateDBText(Point3d.Origin, "123", 2.5, database: tr.Database); + + return new List { line, actext }; + + }); + tr.CurrentSpace.InsertBlock(Point3d.Origin, "test456"); + tr.Database.SaveDwgFile(); + } + + + + [CommandMethod(nameof(Test_AddAttsDef))] + public void Test_AddAttsDef() + { + using DBTrans tr = new(); + var blockid = Env.Editor.GetEntity("pick block:").ObjectId; + var btf = tr.GetObject(blockid); + if (btf is null) + return; + var att1 = new AttributeDefinition() { Position = new Point3d(20, 20, 0), Tag = "addtagTest1", Height = 1, TextString = "valueTest1" }; + var att2 = new AttributeDefinition() { Position = new Point3d(10, 12, 0), Tag = "tagTest2", Height = 1, TextString = "valueTest2" }; + tr.BlockTable.AddAttsToBlocks(btf.BlockTableRecord, new() { att1, att2 }); + } + + [CommandMethod(nameof(Test_BlockNullBug))] + public void Test_BlockNullBug() + { + using DBTrans tr = new(); + + List ents = []; + var line5 = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + var line6 = new Line(new Point3d(0, 0, 0), new Point3d(-1, 1, 0)); + ents.Add(line5); + ents.Add(line6); + tr.BlockTable.Add("test44", ents); + tr.CurrentSpace.InsertBlock(new Point3d(0, 0, 0), "test44"); + } + + [CommandMethod(nameof(Test_BlockFile))] + public void Test_BlockFile() + { + using DBTrans tr = new(); + var id = tr.BlockTable.GetBlockFrom(@"C:\Users\vic\Desktop\test.dwg", false); + tr.CurrentSpace.InsertBlock(Point3d.Origin, id); + } + + [CommandMethod(nameof(Test_BlockFiledxf))] + public void Test_BlockFiledxf() + { + string [] files; + var folder= new System.Windows.Forms.FolderBrowserDialog(); + if (folder.ShowDialog() == System.Windows.Forms.DialogResult.OK) + { + files = Directory.GetFiles(folder.SelectedPath,"*.dxf",SearchOption.AllDirectories); + using DBTrans tr = new(); + foreach (var item in files) + { + var id = tr.BlockTable.GetBlockFrom(item, false); + var pt = Env.Editor.GetPoint("pick pt"); + if (pt.Status == PromptStatus.OK) + { + tr.CurrentSpace.InsertBlock(pt.Value, id); + Env.Editor.Redraw(); + } + + } + + } + + + } + + [CommandMethod(nameof(Test_ClipBlock))] + public void Test_ClipBlock() + { + using DBTrans tr = new(); + tr.BlockTable.Add("test1", btr => + { + btr.Origin = new Point3d(0, 0, 0); + btr.AddEntity(new Line(new Point3d(0, 0, 0), new Point3d(10, 10, 0)), + new Line(new Point3d(10, 10, 0), new Point3d(10, 0, 0))); + }); + // tr.BlockTable.Add("hah"); + var id = tr.CurrentSpace.InsertBlock(new Point3d(0, 0, 0), "test1"); + var brf1 = tr.GetObject(id)!; + var pts = new List { new Point3d(3, 3, 0), new Point3d(7, 3, 0), new Point3d(7, 7, 0), new Point3d(3, 7, 0) }; + brf1.XClip(pts); + + var id1 = tr.CurrentSpace.InsertBlock(new Point3d(20, 20, 0), "test1"); + var brf2 = tr.GetObject(id); + brf2?.XClip(new Point3d(13, 13, 0), new Point3d(17, 17, 0)); + } + + + [CommandMethod(nameof(Test_ClipBlock1))] + public void Test_ClipBlock1() + { + using DBTrans tr = new(); + var ent = Env.Editor.GetEntity("pick block"); + if (ent.Status != PromptStatus.OK) return; + + var brf1 = tr.GetObject(ent.ObjectId)!; + var pts = new List { new Point3d(3, 3, 0), new Point3d(7, 3, 0), new Point3d(7, 7, 0), new Point3d(3, 7, 0) }; + brf1.XClip(pts); + + } + + + + // 给用户的测试程序,不知道对错 + [CommandMethod(nameof(Test_Block_ej))] + public void Test_Block_ej() + { + using (DBTrans tr = new()) + { + // Point3d.Origin.AddBellowToModelSpace(100, 100, 5, 3, 30);// 画波纹管 + + // Database db2 = new Database(false, true); + // string fullFileName = @".\MyBlockDwgFile\001.dwg"; + // db2.ReadDwgFile(fullFileName, System.IO.FileShare.Read, true, null); + // db2.CloseInput(true); + // string blockName = "test"; + // if (!tr.BlockTable.Has(blockName)) + // { + // // tr.Database.Insert(blockName, db2, false);// 插入块 + // db.Insert(blockName, db2, false); + + // } + + string fullFileName = @"C:\Users\vic\Desktop\001.dwg"; + var blockdef = tr.BlockTable.GetBlockFrom(fullFileName, false); + + tr.Database.Clayer = tr.LayerTable["0"];// 当前图层切换为0图层 + tr.LayerTable.Change(tr.Database.Clayer, ltr => + { + ltr.Color = Color.FromColorIndex(ColorMethod.ByAci, 2); // ColorMethod.ByAci可以让我们使用AutoCAD ACI颜色索引……这里为2(表示黄色) + }); + + var id = tr.ModelSpace.InsertBlock(Point3d.Origin, blockdef);// 插入块参照 + var brf = tr.GetObject(id); + brf?.Draw(); + } + + using DBTrans tr2 = new(); + PromptEntityOptions peo = new("\n请选择一个块"); + peo.SetRejectMessage("\n对象必须是块"); + peo.AddAllowedClass(typeof(BlockReference), true); + + var per = Env.Editor.GetEntity(peo); + if (per.Status != PromptStatus.OK) + return; + + var brf2 = tr2.GetObject(per.ObjectId)!; + // var BTR = tr.GetObject(Bref.BlockTableRecord, OpenMode.ForWrite); + //// 如果知道块名字BTRName + // BlockTableRecord BTR = tr.GetObject(tr.BlockTable[blockName], OpenMode.ForWrite); + + var btr = tr2.BlockTable[brf2.Name]; + + tr2.BlockTable.Change(btr, ltr => + { + foreach (ObjectId oid in ltr) + { + var ent = tr2.GetObject(oid); + if (ent is MText mText) + { + using (ent.ForWrite()) + switch (mText.Text) + { + case "$$A": + mText.Contents = "hahaha"; + break; + case "$$B": + break; + default: + break; + } + } + else if (ent is DBText dBText) + { + using (ent.ForWrite()) + dBText.TextString = "haha"; + } + else if (ent is Dimension dimension) + { + using (ent.ForWrite()) + switch (dimension.DimensionText) + { + case "$$pipeLen": + dimension.DimensionText = "350"; + dimension.RecomputeDimensionBlock(true); + break; + default: + break; + } + } + } + }); + tr2.Editor?.Regen(); + } + + [CommandMethod(nameof(Test_QuickBlockDef2))] + public void Test_QuickBlockDef2() + { + // Database db = HostApplicationServices.WorkingDatabase; + Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor; + PromptSelectionOptions promptOpt = new() + { + MessageForAdding = "请选择需要快速制作块的对象" + }; + string blockName = "W_BLOCK_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"); + // var rss = ed.GetSelection(promptOpt); + var rss = Env.Editor.GetSelection(promptOpt); + using DBTrans tr = new(); + if (rss.Status == PromptStatus.OK) + { + // SelectionSet ss = rss.Value; + // ObjectId[] ids = ss.GetObjectIds(); + // List> ents = []; + // var extents = new Extents3d(); + // foreach (var id in ids) + // { + // Entity ent = tr.GetObject(id); + // if (ent is null) + // continue; + // try + // { + // extents.AddExtents(ent.GeometricExtents); + // var order = id.Handle.Value; + // var newEnt = ent.Clone() as Entity; + // ents.Add(new KeyValuePair(newEnt, order)); + // ent.UpgradeOpen(); + // ent.Erase(); + // ent.DowngradeOpen(); + // } + // catch (System.Exception exc) + // { + // ed.WriteMessage(exc.Message); + // } + // } + // ents = ents.OrderBy(x => x.Value).ToList(); + var ents = rss.Value.GetEntities(); + // ents.ForEach(ent => extents.AddExtents(ent.GeometricExtents)); + var extents = ents!.GetExtents(); + Point3d pt = extents.MinPoint; + Matrix3d matrix = Matrix3d.Displacement(Point3d.Origin - pt); + // List newEnts = []; + // foreach (var ent in ents) + // { + // var newEnt = ent.Key; + // newEnt.TransformBy(matrix); + // newEnts.Add(newEnt); + // } + // if (tr.BlockTable.Has(blockName)) + // { + // Acap.ShowAlertDialog(Environment.NewLine + "块名重复,程序退出!"); + // return; + // } + ents.ForEach(ent => + ent?.ForWrite(e => e?.TransformBy(matrix))); + // var newents = ents.Select(ent => + // { + // var maping = new IdMapping(); + // return ent.DeepClone(ent, maping, true) as Entity; + // }); + var newents = ents.Select(ent => ent?.Clone() as Entity); + + // ents.ForEach(ent => ent.ForWrite(e => e.Erase(true))); // 删除实体就会卡死,比较奇怪,估计是Clone()函数的问题 + // 经过测试不是删除的问题 + var btrId = tr.BlockTable.Add(blockName, newents!); + ents.ForEach(ent => ent?.ForWrite(e => e?.Erase(true))); + var bId = tr.CurrentSpace.InsertBlock(pt, blockName); + // tr.GetObject(bId, OpenMode.ForWrite).Move(Point3d.Origin, Point3d.Origin); + // var ed = Acap.DocumentManager.MdiActiveDocument.Editor; + // ed.Regen(); + // tr.Editor.Regen(); + // 调用regen() 卡死 + } + // tr.Editor.Regen(); + // ed.Regen(); + // using (var tr = new DBTrans()) + // { + // tr.CurrentSpace.InsertBlock(Point3d.Origin, blockName); + // tr.Editor.Regen(); + // } + } + + [CommandMethod(nameof(Test_QuickBlockDef1))] + public void Test_QuickBlockDef1() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var db = doc.Database; + var ed = doc.Editor; + + PromptSelectionOptions promptOpt = new() + { + MessageForAdding = "请选择需要快速制作块的对象" + }; + string blockName = "W_BLOCK_" + DateTime.Now.ToString("yyyyMMdd_HHmmss"); + var rss = Env.Editor.GetSelection(promptOpt); + if (rss.Status != PromptStatus.OK) + return; + + using var tr = db.TransactionManager.StartTransaction(); + var ids = rss.Value.GetObjectIds(); + var bt = tr.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; + var btr = new BlockTableRecord + { + Name = blockName + }; + foreach (var item in ids) + { + var ent = tr.GetObject(item, OpenMode.ForRead) as Entity; + btr.AppendEntity(ent!.Clone() as Entity); + ent.ForWrite(e => e.Erase(true)); + } + bt!.UpgradeOpen(); + bt.Add(btr); + tr.AddNewlyCreatedDBObject(btr, true); + bt.DowngradeOpen(); + // tr.Commit(); + // } + + // using (var tr1 = db.TransactionManager.StartTransaction()) + // { + // var bt = tr1.GetObject(db.BlockTableId, OpenMode.ForRead) as BlockTable; + var btr1 = tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord; + var brf = new BlockReference(Point3d.Origin, bt[blockName]) + { + ScaleFactors = default + }; + btr1!.AppendEntity(brf); + tr.AddNewlyCreatedDBObject(brf, true); + btr1.DowngradeOpen(); + ed.Regen(); + tr.Commit(); + // ed.Regen(); + } + + void Wblock() + { + var curdb = HostApplicationServices.WorkingDatabase; + PromptSelectionOptions opts = new() + { + MessageForAdding = "选择对象" + }; + var ss = Env.Editor.GetSelection(opts).Value; + using ObjectIdCollection ids = new(ss.GetObjectIds()); + var db = curdb.Wblock(ids, Point3d.Origin); + db.SaveAs(@"c:\test.dwg", DwgVersion.Current); + } + [CommandMethod(nameof(ChangeDynameicBlock))] + public void ChangeDynameicBlock() + { + var pro = new Dictionary + { + { "haha", 1 } + }; + var blockid = Env.Editor.GetEntity("选择个块").ObjectId; + using DBTrans tr = new(); + var brf = tr.GetObject(blockid)!; + brf.ChangeBlockProperty(pro); + // 这是第一个函数的用法 + } + [CommandMethod(nameof(ChangeBlockProperty))] + public void ChangeBlockProperty() + { + Dictionary? pro = new() + { + { "haha", "1" } + }; + var blockid = Env.Editor.GetEntity("选择个块").ObjectId; + using DBTrans tr = new(); + var brf = tr.GetObject(blockid)!; + brf.ChangeBlockProperty(pro); + // 这是第一个函数的用法 + } + + [CommandMethod(nameof(Test_Back))] + public void Test_Back() + { + string dir = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory); + string dwg = dir + "\\test.dwg"; + if (!File.Exists(dwg)) + { + System.Windows.Forms.MessageBox.Show(dwg, "你还没有创建此文件"); + return; + } + + using DBTrans tr = new(dwg); + tr.ModelSpace.GetEntities().ForEach(ent => + { + ent.ForWrite(e => e.ColorIndex = 3); + }); + tr.Database.SaveAs(dwg, DwgVersion.Current); + + tr.ModelSpace.GetEntities().ForEach(ent => + { + ent.ForWrite(e => e.ColorIndex = 4); + }); + tr.Database.SaveAs(dwg, DwgVersion.Current); + } + + [CommandMethod(nameof(Test_ExplodeBlock))] + public void Test_ExplodeBlock() + { + var r1 = Env.Editor.GetEntity("pick block"); + if (r1.Status != PromptStatus.OK) + return; + using var tr = new DBTrans(); + if (tr.GetObject(r1.ObjectId, OpenMode.ForWrite) is not BlockReference brf) + return; + var dboc = new DBObjectCollection(); + // brf.Explode(dboc); + brf.ExplodeToOwnerSpace(); + // foreach (Entity item in dboc) + // { + // tr.CurrentSpace.AddEntity(item); + // } + using (brf.ForWrite()) + { + brf.Erase(); + } + } +} + + + +public static class Blocks +{ + + [CommandMethod("TestExplodeToOwnerSpace3")] + public static void TestExplodeToOwnerSpace3_Method() + { + Editor ed = Application.DocumentManager.MdiActiveDocument.Editor; + try + { + PromptEntityOptions prEntOpt = new PromptEntityOptions("\nSelect an INSERT:"); + prEntOpt.SetRejectMessage("\nIt is not an INSERT!"); + prEntOpt.AddAllowedClass(typeof(BlockReference), true); + PromptEntityResult selRes = ed.GetEntity(prEntOpt); + if (selRes.Status == PromptStatus.OK) + { + ObjectIdCollection ids = ExplodeToOwnerSpace3(selRes.ObjectId); + ed.WriteMessage("{0} entities were added into database.", ids.Count); + } + else + { + ed.WriteMessage("\nEntity Selection failed!"); + } + } + catch (System.Exception ex) + { + ed.WriteMessage(ex.Message); + } + } + + public static void ExplodeToOwnerSpace2(ObjectId id, bool erase = true) + { + ExplodeToOwnerSpace3(id, erase); + } + + public static void ExplodeToOwnerSpace2(this BlockReference br) + { + ExplodeToOwnerSpace3(br); + } + + public static ObjectIdCollection ExplodeToOwnerSpace3(ObjectId id, bool erase = true) + { + ObjectIdCollection ids; + + using (Transaction tr = id.Database.TransactionManager.StartTransaction()) + { + BlockReference br = (BlockReference)tr.GetObject(id, OpenMode.ForRead); + ids = br.ExplodeToOwnerSpace3(); + + if (erase) + { + br.UpgradeOpen(); + br.Erase(); + } + + tr.Commit(); + } + + return ids; + } + + private static ObjectIdCollection idsAdded = []; + public static ObjectIdCollection ExplodeToOwnerSpace3(this BlockReference br) + { + idsAdded = new ObjectIdCollection(); + + Transaction tr = br.Database.TransactionManager.TopTransaction; + BlockTableRecord spaceBtr = (BlockTableRecord)tr.GetObject(br.BlockId, OpenMode.ForWrite); + LoopThroughInsertAndAddEntity2n3(br.BlockTransform, br, spaceBtr); + + return idsAdded; + } + // 不能用于非等比 + public static void LoopThroughInsertAndAddEntity2n3(Matrix3d mat, BlockReference br, BlockTableRecord space) + { + Transaction tr = space.Database.TransactionManager.TopTransaction; + BlockTableRecord btr = (BlockTableRecord)tr.GetObject(br.BlockTableRecord, OpenMode.ForRead); + + foreach (ObjectId id in btr) + { + DBObject obj = tr.GetObject(id, OpenMode.ForRead); + Entity? ent = obj.Clone() as Entity; + if (ent is BlockReference) + { + BlockReference br1 = (BlockReference)ent; + LoopThroughInsertAndAddEntity2n3(br1.BlockTransform.PreMultiplyBy(mat), br1, space); + } + else + { + ent?.TransformBy(mat); + space.AppendEntity(ent); + tr.AddNewlyCreatedDBObject(ent, true); + + idsAdded.Add(ent!.ObjectId); + } + } + } + +} + + +public class BlockImportClass +{ + [CommandMethod(nameof(Test_Cbll))] + public void Test_Cbll() + { + string filename = @"C:\Users\vic\Desktop\Drawing1.dwg"; + using DBTrans tr = new(); + using DBTrans tr1 = new(filename); + // tr.BlockTable.GetBlockFrom(filename, true); + string blkdefname = SymbolUtilityServices.RepairSymbolName(SymbolUtilityServices.GetSymbolNameFromPathName(filename, "dwg"), false); + tr.Database.Insert(blkdefname, tr1.Database, false); // 插入了块定义,未插入块参照 + } + + + [CommandMethod(nameof(Test_CombineBlocksIntoLibrary))] + public void Test_CombineBlocksIntoLibrary() + { + Document doc = Acap.DocumentManager.MdiActiveDocument; + Editor ed = doc.Editor; + Database destDb = doc.Database; + + PromptResult pr = ed.GetString("\nEnter the folder of source drawings: "); + + if (pr.Status != PromptStatus.OK) + return; + string pathName = pr.StringResult; + if (!Directory.Exists(pathName)) + { + ed.WriteMessage("\nDirectory does not exist: {0}", pathName); + return; + } + string[] fileNames = Directory.GetFiles(pathName, "*.dwg"); + int imported = 0, failed = 0; + foreach (string fileName in fileNames) + { + if (fileName.EndsWith(".dwg", + StringComparison.InvariantCultureIgnoreCase)) + { + // Catch exceptions at the file level to allow skipping + try + { + // Suggestion from Thorsten Meinecke... + + string destName = + SymbolUtilityServices.GetSymbolNameFromPathName( + fileName, "dwg" + ); + + // And from Dan Glassman... + + destName = + SymbolUtilityServices.RepairSymbolName( + destName, false + ); + + // Create a source database to load the DWG into + + using Database db = new(false, true); + // Read the DWG into our side database + + db.ReadDwgFile(fileName, FileShare.Read, true, ""); + bool isAnno = db.AnnotativeDwg; + + // Insert it into the destination database as + // a named block definition + + ObjectId btrId = destDb.Insert( + destName, + db, + false + ); + + if (isAnno) + { + // If an annotative block, open the resultant BTR + // and set its annotative definition status + + Transaction tr = + destDb.TransactionManager.StartTransaction(); + using (tr) + { + BlockTableRecord btr = + (BlockTableRecord)tr.GetObject( + btrId, + OpenMode.ForWrite + ); + btr.Annotative = AnnotativeStates.True; + tr.Commit(); + } + } + + // Print message and increment imported block counter + + ed.WriteMessage("\nImported from \"{0}\".", fileName); + imported++; + } + catch (System.Exception ex) + { + ed.WriteMessage( + "\nProblem importing \"{0}\": {1} - file skipped.", + fileName, ex.Message + ); + failed++; + } + } + } + + ed.WriteMessage( + "\nImported block definitions from {0} files{1} in " + + "\"{2}\" into the current drawing.", + imported, + failed > 0 ? " (" + failed + " failed)" : "", + pathName + ); + } + +} \ No newline at end of file diff --git a/tests/TestShared/TestCadFilePath.cs b/tests/TestShared/TestCadFilePath.cs new file mode 100644 index 0000000000000000000000000000000000000000..c0354d53598e2c502242888a31cdf9c84e6c5075 --- /dev/null +++ b/tests/TestShared/TestCadFilePath.cs @@ -0,0 +1,27 @@ + +namespace Test; + +public class TestCadFilePath +{ + [CommandMethod("TestCadFilePath")] + public void TestCadFilePathfun() + { + var key = HostApplicationServices.Current.UserRegistryProductRootKey; + // 计算机\HKEY_CURRENT_USER\SOFTWARE\Autodesk\AutoCAD\R24.0\ACAD-4101:804 + var ackey = Registry.CurrentUser.OpenSubKey(key); + var profileskey = ackey?.OpenSubKey("Profiles"); + + var listkey = profileskey?.GetSubKeyNames(); + if (listkey == null) return; + foreach (var item in listkey) + { + if (profileskey == null) continue; + var acadkey = profileskey.OpenSubKey($@"{item}\General", true); + const string name = "ACAD"; + var str = acadkey?.GetValue(name)?.ToString(); + if (str == null || str.Contains("nihao")) continue; + Env.Print(str); + acadkey?.SetValue(name, $@"{str}\nihao;", RegistryValueKind.String); + } + } +} diff --git a/tests/TestShared/TestConvexHull.cs b/tests/TestShared/TestConvexHull.cs new file mode 100644 index 0000000000000000000000000000000000000000..03692ae5ffc3cceec783cd35c053079e7374ba03 --- /dev/null +++ b/tests/TestShared/TestConvexHull.cs @@ -0,0 +1,76 @@ +namespace Test; + + +public class TestConvexHull +{ + [CommandMethod(nameof(Test_ConvexHull))] + public void Test_ConvexHull() + { + // using DBTrans tr = new(); + // List pts = []; + // var flag = true; + // while (flag) + // { + // var pt = tr.Editor.GetPoint("qudian"); + // if (pt.Status == PromptStatus.OK) + // { + // pts.Add(pt.Value); + // tr.CurrentSpace.AddEntity(new DBPoint(pt.Value)); + // } + // else + // { + // flag = false; + // } + + // } + + // var ptt = ConvexHull.GetConvexHull(pts); + + // Polyline pl = new Polyline(); + // for (int i = 0; i < ptt.Count; i++) + // { + // pl.AddVertexAt(i, ptt[i].Point2d(), 0, 0, 0); + // } + //// pl.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0); + //// pl.AddVertexAt(1, new Point2d(10, 10), 0, 0, 0); + //// pl.AddVertexAt(2, new Point2d(20, 20), 0, 0, 0); + //// pl.AddVertexAt(3, new Point2d(30, 30), 0, 0, 0); + //// pl.AddVertexAt(4, new Point2d(40, 40), 0, 0, 0); + // pl.Closed = true; + // pl.Color = Color.FromColorIndex(ColorMethod.ByColor, 6); + // tr.CurrentSpace.AddEntity(pl); + + // var a1 = GeometryEx.GetArea(new Point2d(0, 0), new Point2d(1, 0), new Point2d(1, 1)); + // var a2 = ConvexHull.cross(new Point3d(0, 0, 0), new Point3d(1, 0, 0), new Point3d(1, 1, 0)); + // tr.Editor.WriteMessage(a1.ToString()); + // tr.Editor.WriteMessage(a2.ToString()); + + + // var vec1 = new Vector2d(1, 1); + // var vec2 = new Vector2d(-1, 1); + + // var vec3 = vec1.GetPerpendicularVector(); + // var vec4 = vec2.GetPerpendicularVector(); + + // var area1 = vec2.DotProduct(vec1.GetPerpendicularVector()); + // var area2 = vec1.DotProduct(vec2.GetPerpendicularVector()); + + // var area3 = vec2.DotProduct(vec1); + // var area4 = vec1.DotProduct(vec2); + + var area5 = GeometryEx.GetArea(new List { new Point2d(0, 0), new Point2d(1, 1), new Point2d(-1, 1) }); + + var area6 = GeometryEx.GetArea(new List { new Point2d(0, 0), new Point2d(-1, 1), new Point2d(1, 1) }); + // Env.Editor.WriteMessage($"vec1 的法向量= {vec3} \n"); + // Env.Editor.WriteMessage($"vec2 的法向量= {vec4} \n"); + + // Env.Editor.WriteMessage($"vec2 点乘 vec1的法向量= {area1} \n"); + // Env.Editor.WriteMessage($"vec1 点乘 vec2的法向量= {area2} \n"); + + // Env.Editor.WriteMessage($"vec2 点乘 vec1= {area3} \n"); + // Env.Editor.WriteMessage($"vec1 点乘 vec2= {area4} \n"); + + Env.Editor.WriteMessage($"点集的有向面积:{area5} \n"); + Env.Editor.WriteMessage($"点集的有向面积:{area6} \n"); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestCurve.cs b/tests/TestShared/TestCurve.cs new file mode 100644 index 0000000000000000000000000000000000000000..fd75698f2af5472409a2139940e55ee400d0e113 --- /dev/null +++ b/tests/TestShared/TestCurve.cs @@ -0,0 +1,324 @@ +namespace Test; + +public class TestGraph +{ + [CommandMethod(nameof(Test_PointInDict))] + public void Test_PointInDict() + { + var pt1 = new Point3d(0.0255, 0.452, 0); + var pt2 = new Point3d(0.0255001, 0.452003, 0); + var pt3 = new Point3d(0.0255002, 0.4520001, 0); + var pt4 = new Point3d(0.0255450, 0.45287893, 0); + var pt5 = new Point3d(0.02554935, 0.452092375, 0); + var dict = new Dictionary + { + { pt1, 1 }, + { pt2, 2 }, + { pt3, 3 }, + { pt4, 4 }, + { pt5, 5 } + }; + Env.Print(dict[pt1]); + } + +#if false + [CommandMethod(nameof(Test_Graph1))] + public void Test_Graph1() + { + using DBTrans tr = new(); + var ents = Env.Editor.SSGet()?.Value?.GetEntities(); + if (ents == null) + return; + Tools.TestTimes2(1, "new", () => { + var res = ents!.GetAllCycle(); + + // res.ForEach((i, t) => t.ForWrite(e => e.ColorIndex = i + 1)); + Env.Print(res.Count()); + tr.CurrentSpace.AddEntity(res); + }); + } + + + [CommandMethod(nameof(Test_Graphspeed))] + public void Test_Graphspeed() + { + using DBTrans tr = new(); + var ents = Env.Editor.SSGet()?.Value?.GetEntities(); + if (ents == null) + return; + + var graph = new IFoxCAD.Cad.Graph(); // 为了调试先把图的访问改为internal + foreach (var curve in ents) + { + graph.AddEdge(curve!.GetGeCurve()); + } + + // 新建 dfs + var dfs = new DepthFirst(); +#if true + Tools.TestTimes2(100, "new", () => { + // 查询全部的 闭合环 + dfs.FindAll(graph); + }); + Tools.TestTimes2(1000, "new", () => { + // 查询全部的 闭合环 + dfs.FindAll(graph); + }); +#else + Tools.TestTimes2(100, "old", () => { + // 查询全部的 闭合环 + dfs.FindAll(graph); + }); + Tools.TestTimes2(1000, "old", () => { + // 查询全部的 闭合环 + dfs.FindAll(graph); + }); +#endif + // res.ForEach((i, t) => t.ForWrite(e => e.ColorIndex = i + 1)); + + // tr.CurrentSpace.AddEntity(res); + } +#endif +} + + + +public partial class TestCurve +{ + [CommandMethod(nameof(Test_CurveExtend))] + public void Test_CurveExtend() + { + using var tr = new DBTrans(); + var ent = Env.Editor.GetEntity("pick curve").ObjectId.GetObject(); + if (ent is Curve curve) + curve.ForWrite(e => e.Extend(e.EndParam + 1)); + + } + + + private Arc ToArc1(CircularArc2d a2d) + { + double startangle, endangle; + double refangle = a2d.ReferenceVector.Angle; + + if (a2d.IsClockWise) + { + startangle = -a2d.EndAngle + refangle; + endangle = -a2d.StartAngle + refangle; + } + else + { + startangle = a2d.StartAngle + refangle; + endangle = a2d.EndAngle + refangle; + } + + return + new Arc( + new Point3d(new Plane(), a2d.Center), + Vector3d.ZAxis, + a2d.Radius, + startangle, + endangle); + } + + +#if false + [CommandMethod(nameof(Test_Curve_ToArc))] + public void Test_Curve_ToArc() + { + using var tr = new DBTrans(); + var gearc = new CircularArc2d(new Point2d(0,0),new Point2d(0.5,0.5),new Point2d(1,0)); + var dbarc = gearc.ToArc(); + var dbarc1 = ToArc1(gearc); + dbarc.ColorIndex = 1; + tr.CurrentSpace.AddEntity(dbarc); + dbarc1.ColorIndex = 2; + tr.CurrentSpace.AddEntity(dbarc1); + + var gearc3 = new CircularArc3d(new(0,0,0),new(0.5,0.5,0),new Point3d(1,0,0)); + var dbarc3 = (Arc)Curve.CreateFromGeCurve(gearc3); + dbarc3.ColorIndex = 3; + tr.CurrentSpace.AddEntity(dbarc3); + + + + Polyline pl0 = new();//创建有圆弧的多段线 + + pl0.AddVertexAt(0, new(-520, 200), -0.74, 0, 0); + pl0.AddVertexAt(1, new(-100, 140), 0.52, 0, 0); + pl0.AddVertexAt(2, new(16, -120), -0.27, 0, 0); + pl0.AddVertexAt(3, new(400, -130), 0.75, 0, 0); + pl0.AddVertexAt(4, new(450, 200), -0.69, 0, 0); + tr.CurrentSpace.AddEntity(pl0); + + + for (int FFF = 0; FFF < pl0.NumberOfVertices; FFF++) + { + if (pl0.GetSegmentType(FFF) == SegmentType.Arc) + { + var bulge = pl0.GetBulgeAt(FFF); + + //将 CircularArc2d 转为Arc 颜色为红 + CircularArc2d arc2d = pl0.GetArcSegment2dAt(FFF); + + Arc arc = arc2d.ToArc(); + if (bulge < 0) arc.ReverseCurve(); + arc.ColorIndex = 1; + tr.CurrentSpace.AddEntity(arc); + Env.Printl($"arc的ge:ReferenceVector:{MathEx.ConvertRadToDeg(arc2d.ReferenceVector.Angle)}"); + Env.Printl($"arc的ge:顺时针:{arc2d.IsClockWise}"); + Env.Printl($"arc的ge:起点角度:{MathEx.ConvertRadToDeg(arc2d.StartAngle)},终点角度:{MathEx.ConvertRadToDeg(arc2d.EndAngle)}"); + Env.Printl($"arc的db:起点角度:{MathEx.ConvertRadToDeg(arc.StartAngle)},终点角度:{MathEx.ConvertRadToDeg(arc.EndAngle)}"); + + //将 CircularArc2d 转为Arc 颜色为黄 + CircularArc2d arc2d1 = pl0.GetArcSegment2dAt(FFF); + Arc arc1 = ToArc1(arc2d1); + if (bulge < 0) arc1.ReverseCurve(); + arc1.ColorIndex = 2; + tr.CurrentSpace.AddEntity(arc1); + Env.Printl($"arc1的ge:ReferenceVector:{MathEx.ConvertRadToDeg(arc2d1.ReferenceVector.Angle)}"); + Env.Printl($"arc的ge:顺时针:{arc2d1.IsClockWise}"); + Env.Printl($"arc1的ge:起点角度:{MathEx.ConvertRadToDeg(arc2d1.StartAngle)} ,终点角度: {MathEx.ConvertRadToDeg(arc2d1.EndAngle)}"); + Env.Printl($"arc1的db:起点角度:{MathEx.ConvertRadToDeg(arc1.StartAngle)} ,终点角度: {MathEx.ConvertRadToDeg(arc1.EndAngle)}"); + + //将 CircularArc3d 转为Arc 颜色为黄色 + CircularArc3d arc3d = pl0.GetArcSegmentAt(FFF); + Arc arc2 = arc3d.ToArc(); + + arc2.ColorIndex = 3; + tr.CurrentSpace.AddEntity(arc2); + Env.Printl($"arc2的ge:ReferenceVector:{MathEx.ConvertRadToDeg(arc3d.ReferenceVector.AngleOnPlane(new Plane()))}"); + Env.Printl($"arc2的ge:起点角度:{MathEx.ConvertRadToDeg(arc3d.StartAngle)} ,终点角度: {MathEx.ConvertRadToDeg(arc3d.EndAngle)}"); + Env.Printl($"arc2的db:起点角度:{MathEx.ConvertRadToDeg(arc2.StartAngle)} ,终点角度: {MathEx.ConvertRadToDeg(arc2.EndAngle)}"); + +/* + + +arc的ge: ReferenceVector:154.872779886857 +arc的ge: 顺时针:True +arc的ge:起点角度:0,终点角度:146.005764482025 +arc的db: 起点角度:334.872779886857,终点角度:120.878544368882 +arc1的ge: ReferenceVector:154.872779886857 +arc的ge: 顺时针:True +arc1的ge:起点角度:0 ,终点角度: 146.005764482025 +arc1的db: 起点角度:334.872779886857 ,终点角度: 120.878544368882 +arc2的ge: ReferenceVector:154.872779886857 +arc2的ge: 起点角度:0 ,终点角度: 146.005764482025 +arc2的db: 起点角度:25.1272201131434 ,终点角度: 171.132984595169 + + +arc的ge: ReferenceVector:149.095360016814 +arc的ge: 顺时针:False +arc的ge:起点角度:0,终点角度:109.897726505109 +arc的db: 起点角度:149.095360016814,终点角度:258.993086521922 +arc1的ge: ReferenceVector:149.095360016814 +arc的ge: 顺时针:False +arc1的ge:起点角度:0 ,终点角度: 109.897726505109 +arc1的db: 起点角度:149.095360016814 ,终点角度: 258.993086521922 +arc2的ge: ReferenceVector:149.095360016814 +arc2的ge: 起点角度:0 ,终点角度: 109.897726505109 +arc2的db: 起点角度:149.095360016814 ,终点角度: 258.993086521922 + + +arc的ge: ReferenceVector:118.727409809308 +arc的ge: 顺时针:True +arc的ge:起点角度:0,终点角度:60.4383004893619 +arc的db: 起点角度:298.727409809308,终点角度:359.16571029867 +arc1的ge: ReferenceVector:118.727409809308 +arc的ge: 顺时针:True +arc1的ge:起点角度:0 ,终点角度: 60.4383004893619 +arc1的db: 起点角度:298.727409809308 ,终点角度: 359.16571029867 +arc2的ge: ReferenceVector:118.727409809308 +arc2的ge: 起点角度:0 ,终点角度: 60.4383004893619 +arc2的db: 起点角度:61.2725901906918 ,终点角度: 121.710890680054 + + +arc的ge: ReferenceVector:277.644556524148 +arc的ge: 顺时针:False +arc的ge:起点角度:0,终点角度:147.479590583376 +arc的db: 起点角度:277.644556524148,终点角度:65.124147107524 +arc1的ge: ReferenceVector:277.644556524148 +arc的ge: 顺时针:False +arc1的ge:起点角度:0 ,终点角度: 147.479590583376 +arc1的db: 起点角度:277.644556524148 ,终点角度: 65.124147107524 +arc2的ge: ReferenceVector:277.644556524148 +arc2的ge: 起点角度:0 ,终点角度: 147.479590583376 +arc2的db: 起点角度:277.644556524148 ,终点角度: 65.124147107524 + + + + + + +*/ + } + } + + } +#endif +} + + +public partial class TestCurve +{ + [CommandMethod(nameof(Test_BreakCurve))] + public void Test_BreakCurve() + { + using DBTrans tr = new(); + var ents = Env.Editor.SSGet()?.Value.GetEntities(); + if (ents is null) + return; + var tt = CurveEx.BreakCurve(ents.ToList()!); + tt.ForEach(t => t.ForWrite(e => e.ColorIndex = 1)); + tr.CurrentSpace.AddEntity(tt); + } + + [CommandMethod(nameof(Test_CurveCurveIntersector3d))] + public void Test_CurveCurveIntersector3d() + { + using DBTrans tr = new(); + var ents = Env.Editor.SSGet()? + .Value.GetEntities() + .Select(e => e?.ToCompositeCurve3d()).ToList(); + if (ents == null) + return; + + var cci3d = new CurveCurveIntersector3d(); + for (int i = 0; i < ents.Count; i++) + { + var gc1 = ents[i]; + var int1 = gc1?.GetInterval(); + // var pars1 = paramss[i]; + for (int j = i; j < ents.Count; j++) + { + var gc2 = ents[j]; + // var pars2 = paramss[j]; + var int2 = gc2?.GetInterval(); + cci3d.Set(gc1, gc2, int1, int2, Vector3d.ZAxis); + var d = cci3d.OverlapCount(); + var a = cci3d.GetIntersectionRanges(); + Env.Print($"{a[0].LowerBound}-{a[0].UpperBound} and {a[1].LowerBound}-{a[1].UpperBound}"); + for (int m = 0; m < d; m++) + { + var b = cci3d.GetOverlapRanges(m); + Env.Print($"{b[0].LowerBound}-{b[0].UpperBound} and {b[1].LowerBound}-{b[1].UpperBound}"); + } + + for (int k = 0; k < cci3d.NumberOfIntersectionPoints; k++) + { + // var a = cci3d.GetOverlapRanges(k); + // var b = cci3d.IsTangential(k); + // var c = cci3d.IsTransversal(k); + // var d = cci3d.OverlapCount(); + // var e = cci3d.OverlapDirection(); + var pt = cci3d.GetIntersectionParameters(k); + var pts = cci3d.GetIntersectionPoint(k); + Env.Print(pts); + } + } + } + // var tt = CurveEx.Topo(ents.ToList()); + // tt.ForEach(t => t.ForWrite(e => e.ColorIndex = 1)); + // tr.CurrentSpace.AddEntity(tt); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestDBTrans.cs b/tests/TestShared/TestDBTrans.cs new file mode 100644 index 0000000000000000000000000000000000000000..41eb67d81a467ecaa1183c6e1868921d79890b9a --- /dev/null +++ b/tests/TestShared/TestDBTrans.cs @@ -0,0 +1,203 @@ +namespace Test; + +public class TestTrans +{ + [CommandMethod(nameof(Test_DBTrans))] + public void Test_DBTrans() + { + using DBTrans tr = new(); + if (tr.Editor is null) + return; + tr.Editor.WriteMessage("\n测试 Editor 属性是否工作!"); + tr.Editor.WriteMessage("\n----------开始测试--------------"); + tr.Editor.WriteMessage("\n测试document属性是否工作"); + if (tr.Document == Getdoc()) + { + tr.Editor.WriteMessage("\ndocument 正常"); + } + tr.Editor.WriteMessage("\n测试database属性是否工作"); + if (tr.Database == Getdb()) + { + tr.Editor.WriteMessage("\ndatabase 正常"); + } + } + + private static Database Getdb() + { + var db = Acaop.DocumentManager.MdiActiveDocument.Database; + return db; + } + + private static Document Getdoc() + { + var doc = Acaop.DocumentManager.MdiActiveDocument; + return doc; + } + + + + + [CommandMethod(nameof(CmdTest_DBTransActiveOpenDwg), CommandFlags.Session)] + public static void CmdTest_DBTransActiveOpenDwg() + { + using DBTrans tr = new(@"D:\桌面\AA.dwg", activeOpen: true); + } + + [CommandMethod(nameof(CmdTest_ForEachDemo))] + public static void CmdTest_ForEachDemo() + { + using DBTrans tr = new(); + + // 泛型扩展(用变量名来使用它) + tr.BlockTable.ForEach(action: (id) => { + //Debugger.Break();// 为什么cad工程不能断点进入呢? + id.Print(); + Console.WriteLine(id); + }); + + //tr.BlockTable.ForEach(asdad); + //void asdad(object id) + //{ + // id.Print(); + //} + + tr.BlockTable.ForEach(action: (id) => { + id.Print(); + }); + tr.BlockTable.ForEach(action: (id, state, index) => { + id.Print(); + }); + + // 符号表扩展(会顶替泛型扩展) + tr.BlockTable.ForEach((btr) => { // 预处理设置不进入ForEach函数体内 + btr.Print();// 此处可以设置断点 + }, OpenMode.ForRead, checkIdOk: true); + tr.BlockTable.ForEach((btr, state) => {// 预处理设置不进入ForEach函数体内 + btr.Print();// 此处可以设置断点 + }, OpenMode.ForRead, checkIdOk: true); + tr.BlockTable.ForEach((btr, state, index) => { // 预处理设置不进入ForEach函数体内 + btr.Print();// 此处可以设置断点 + }, OpenMode.ForRead, checkIdOk: true); + + // 修改:此处有缺陷:cad08会获取已经删除的块表记录,需要检查id.IsOk(),用ForEach代替 + // tr.BlockTable.Change("块表记录", btr => { + // }); + + // 修改:此处无缺陷 + tr.BlockTable.Change(tr.ModelSpace.ObjectId, modelSpace => { // 特性设置不进入函数体内 + var ents = modelSpace.GetEntities(); // 此处不会检查id.IsOk() + + modelSpace.ForEach(id => { // 利用遍历检查id.IsOk() + if (id.IsOk()) + id.Print(); + }); + }); + } + + + + // 后台:不存在路径的dwg会在桌面进行临时保存 + [CommandMethod(nameof(FileNotExist))] + public void FileNotExist() + { + using DBTrans tr = new("test.dwg"); + tr.Database.SaveFile((DwgVersion)24, false); + } + + // 前台:由于是弹出面板,此时路径不会起任何作用 + [CommandMethod(nameof(FileNotExist2))] + public void FileNotExist2() + { + using DBTrans tr = new(); + tr.Database.SaveFile(saveAsFile: "D:\\"); + } + + // 后台:只有路径,没有文件名 + [CommandMethod(nameof(FileNotExist3))] + public void FileNotExist3() + { + using DBTrans tr = new("D:\\"); + tr.Database.SaveDwgFile(); + + using DBTrans tr2 = new("D:\\"); + tr2.Database.SaveFile(saveAsFile: "D:\\"); + } + + + [CommandMethod(nameof(Test_SaveDwgFile))] + public void Test_SaveDwgFile() + { + string filename = @"C:\Users\vic\Desktop\test.dwg"; + using DBTrans tr = new(filename); + var circle = CircleEx.CreateCircle(new Point3d(10, 10, 0), 20)!; + tr.ModelSpace.AddEntity(circle); + // tr.Database.SaveAs(filename,DwgVersion.Current); + tr.Database.SaveDwgFile(); + } + [CommandMethod(nameof(Test_DBTransAbort))] + public void Test_DBTransAbort() + { + using DBTrans tr = new(); + var circle = CircleEx.CreateCircle(new Point3d(10, 10, 0), 20)!; + tr.ModelSpace.AddEntity(circle); + tr.Abort(); + // tr.Commit(); + } + + // AOP 应用 预计示例: + // 1. 无参数 + // [AOP] + // [CommandMethod(nameof(Test_AOP1))] + // public void TestAOP1() + // { + // // 不用 using DBTrans tr = new(); + // var tr = DBTrans.Top; + // tr.ModelSpace.AddCircle(new Point3d(0, 0, 0), 20); + // } + + // 2. 有参数 + // [AOP("file")] + // [CommandMethod(nameof(Test_AOP2))] + // public void TestAOP2() + // { + // // 不用 using var tr = new DBTrans(file); + // var tr = DBTrans.Top; + // tr.ModelSpace.AddCircle(new Point3d(0, 0, 0), 20); + // } + + + [CommandMethod(nameof(Test_TopTransaction))] + public void Test_TopTransaction() + { + // var pt = Env.Editor.GetPoint("pick pt:").Value; + // var pl = Env.Editor.GetEntity("pick pl").ObjectId; + + var tr1 = HostApplicationServices.WorkingDatabase.TransactionManager.TopTransaction; + using DBTrans tr2 = new(); + var tr3 = HostApplicationServices.WorkingDatabase.TransactionManager.TopTransaction; + var tr6 = Acaop.DocumentManager.MdiActiveDocument.TransactionManager.TopTransaction; + Env.Print(tr2.Transaction == tr3); + Env.Print(tr3 == tr6); + using DBTrans tr4 = new(); + var tr5 = HostApplicationServices.WorkingDatabase.TransactionManager.TopTransaction; + var tr7 = Acaop.DocumentManager.MdiActiveDocument.TransactionManager.TopTransaction; + Env.Print(tr4.Transaction == tr5); + Env.Print(tr5 == tr7); + var trm = HostApplicationServices.WorkingDatabase.TransactionManager; + + } + + [CommandMethod(nameof(Test_DBTrans_BlockCount))] + public void Test_DBTrans_BlockCount() + { + using var tr = new DBTrans(); + var i = tr.CurrentSpace + .GetEntities() + .Where(ent => ent.GetBlockName() == "自定义块"); + + var block = i.ToList()[0]; + Env.Print(i.Count()); + } + + +} \ No newline at end of file diff --git a/tests/TestShared/TestDBobject.cs b/tests/TestShared/TestDBobject.cs new file mode 100644 index 0000000000000000000000000000000000000000..f0cb142afe65c59161842eedc5ccfd0415047840 --- /dev/null +++ b/tests/TestShared/TestDBobject.cs @@ -0,0 +1,27 @@ + + +namespace TestShared +{ + public static class TestDBobject + { + [CommandMethod(nameof(TestForWrite))] + public static void TestForWrite() + { + using var tr = new DBTrans(); + var ent = Env.Editor.GetEntity("\npick entity"); + if (ent.Status is not PromptStatus.OK) return; + var entid = ent.ObjectId.GetObject()!; + Tools.TestTimes3(100000, "using:", i => { + using (entid.ForWrite()) + { + entid.ColorIndex = i % 7; + } + }); + Tools.TestTimes3(100000, "action:", i => { + entid.ForWrite(e => { + e.ColorIndex = i % 7; + }); + }); + } + } +} diff --git a/tests/TestShared/TestDwgFilerEx.cs b/tests/TestShared/TestDwgFilerEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..6513cda72b004dda51cd30719f8cd3e6f89c6f9a --- /dev/null +++ b/tests/TestShared/TestDwgFilerEx.cs @@ -0,0 +1,161 @@ +#if false +namespace Test; + +using DxfFiler = IFoxCAD.Cad.DxfFiler; + +public class CmdTestDwgFilerEx +{ + [CommandMethod(nameof(CmdTest_DwgFilerEx))] + public static void CmdTest_DwgFilerEx() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var db = doc.Database; + var ed = doc.Editor; + ed.WriteMessage("\n****测试,序列化图元"); + + var ssPsr = ed.SelectImplied();// 预选 + if (ssPsr.Status != PromptStatus.OK) + { + ssPsr = ed.GetSelection();// 手选 这里输入al会变成all,无法删除ssget的all关键字 + if (ssPsr.Status != PromptStatus.OK) + return; + } + + using DBTrans tr = new(); + var ids = ssPsr.Value.GetObjectIds(); + foreach (var id in ids) + { + if (!id.IsOk()) + continue; + var ent = tr.GetObject(id, OpenMode.ForRead); + if (ent is null) + continue; + var dwgFilerEx = new DwgFilerEx(ent); + ed.WriteMessage(Environment.NewLine + dwgFilerEx.ToString()); + } + } + + [CommandMethod(nameof(CmdTest_EntDxfout))] + public static void CmdTest_EntDxfout() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var db = doc.Database; + var ed = doc.Editor; + + // 定义选择集选项 + var pso = new PromptSelectionOptions + { + RejectObjectsOnLockedLayers = true, // 不选择锁定图层对象 + AllowDuplicates = true, // 不允许重复选择 + }; + var ssPsr = ed.GetSelection(pso);// 手选 这里输入al会变成all,无法删除ssget的all关键字 + if (ssPsr.Status != PromptStatus.OK) + return; + + using DBTrans tr = new(); + var ids = ssPsr.Value.GetObjectIds(); + foreach (var id in ids) + { + if (!id.IsOk()) + continue; + var ent = tr.GetObject(id, OpenMode.ForRead); + if (ent is null) + continue; + // ResultBuffer rbDxf = new(); + var filer = new DxfFiler(ent.UnmanagedObject, true);/// 这里有问题 + ent.DxfOut(filer); + } + } + + + [CommandMethod(nameof(CmdTest_TextOut))] + public static void CmdTest_TextOut() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var db = doc.Database; + var ed = doc.Editor; + +#if true + var peo1 = new PromptEntityOptions(Environment.NewLine + "点选源TCH_WIREDIM2:") + { + AllowObjectOnLockedLayer = false, + AllowNone = false + }; + var gt1 = ed.GetEntity(peo1); + if (gt1.Status != PromptStatus.OK) + return; +#else + var peo2 = new PromptEntityOptions(Environment.NewLine + "点选目标TCH_WIREDIM2:") + { + AllowObjectOnLockedLayer = false, + AllowNone = false + }; + var gt2 = ed.GetEntity(peo2); + if (gt2.Status != PromptStatus.OK) + return; +#endif + + using DBTrans tr = new(); + var dwgFilerEx = new DwgFilerEx(); + var bText = tr.GetObject(gt1.ObjectId, OpenMode.ForRead); + if (bText is null) + return; + + // DwgFilerEx.StringList[0] = "1@2@3@4@5@6@7@"; + // 复制 TCH_WIREDIM2 不行,TEXT 也不行,直接崩溃。line等线就没事 + bText.DwgOut(dwgFilerEx.DwgFiler); + + int testNum = 1 | 2 | 4 | 8; + + if ((testNum & 1) == 1) + { + // 错误,原地克隆也是不行的,它会生成在了模型中. + var sIds = new List + { + bText.ObjectId + }; + // 克隆到目标块表内 + using ObjectIdCollection bindIds = new(sIds.ToArray()); + using IdMapping map = new(); + + tr.CurrentSpace.DeepCloneEx(bindIds, map); + var newTexts = map.GetValues().GetObject(); + newTexts.ForEach(nText => { + if (nText == null) + return; + // 通过上面的克隆就已经在块表上面了.所以下面的设置也跟设置到已有图元上一样报错. + nText.UpgradeOpen(); + nText.DwgIn(dwgFilerEx); + tr.CurrentSpace.AddEntity(nText); + nText.DowngradeOpen(); + }); + } + if ((testNum & 2) == 2) + { + // 出错 + // 直接设置 + bText.DwgIn(dwgFilerEx); + } + if ((testNum & 4) == 4) + { + // 出错 + // 此时是内存中对象.... + var nText = (DBText)bText.Clone(); + nText.DwgIn(dwgFilerEx); + tr.CurrentSpace.AddEntity(nText); + } + if ((testNum & 8) == 8) + { + // 新对象相当于克隆,是ok的 + DBText nText = new(); + nText.SetDatabaseDefaults(); + nText.DwgIn(dwgFilerEx); + tr.CurrentSpace.AddEntity(nText); + } + } +} + +#endif \ No newline at end of file diff --git a/tests/TestShared/TestDwgMark.cs b/tests/TestShared/TestDwgMark.cs new file mode 100644 index 0000000000000000000000000000000000000000..cf0d712a10b0a146bf02f9985329a7b2ad7eb4b4 --- /dev/null +++ b/tests/TestShared/TestDwgMark.cs @@ -0,0 +1,11 @@ +namespace Test; +using IFoxCAD.Cad; +public class TestDwgMark { + [CommandMethod(nameof(DwgMarktest))] + public void DwgMarktest() { + FileInfo file = new FileInfo(@"D:\TEST\1.dwg"); + DwgMark.AddMark(file, 0x4D); + DwgMark.RemoveMark(file); + int A = DwgMark.GetMark(file); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestEditor.cs b/tests/TestShared/TestEditor.cs new file mode 100644 index 0000000000000000000000000000000000000000..5f83345d9fa456752e52a55b975c6177a1c37b6a --- /dev/null +++ b/tests/TestShared/TestEditor.cs @@ -0,0 +1,87 @@ +namespace Test; + +public class Testeditor +{ + [CommandMethod(nameof(Test_Editor))] + public void Test_Editor() + { + var pts = new List + { + new Point2d(0,0), + new Point2d(0,1), + new Point2d(1,1), + new Point2d(1,0) + }; + var res = EditorEx.GetLines(pts, false); + var res1 = EditorEx.GetLines(pts, true); + var res2 = pts.Select(pt => new TypedValue((int)LispDataType.Point2d, pt)).ToList(); + + Editor ed = Acap.DocumentManager.MdiActiveDocument.Editor; + var pt = ed.GetPoint("qudiam", new Point3d(0, 0, 0)); + var d = ed.GetDouble("qudoule"); + var i = ed.GetInteger("quint"); + var s = ed.GetString("qustr"); + Env.Editor.WriteMessage(""); + } + [CommandMethod(nameof(Test_Zoom))] + public void Test_Zoom() + { + using DBTrans tr = new(); + var res = Env.Editor.GetEntity("\npick ent:"); + if (res.Status == PromptStatus.OK) + Env.Editor.ZoomObject(res.ObjectId.GetObject()!); + } + [CommandMethod(nameof(Test_ZoomExtents))] + public void Test_ZoomExtents() + { + // using DBTrans tr = new(); + // var res = Env.Editor.GetEntity("\npick ent:"); + // if (res.Status == PromptStatus.OK) + // { + // Env.Editor.ZoomObject(res.ObjectId.GetObject()); + // } + + Env.Editor.ZoomExtents(); + } + + [CommandMethod(nameof(Test_Zoom_1))] + public void Test_Zoom_1() + { + Env.Editor.Zoom(new(0, 0, 0),200,200); + } + [CommandMethod(nameof(Test_Zoom_2))] + public void Test_Zoom_2() + { + Env.Editor.ZoomWindow(new Point3d(-100,-100,0),new(100,100,0)); + } + + [CommandMethod(nameof(Test_Ssget))] + public void Test_Ssget() + { + + var keyword = new Dictionary + { + { "D", ("你好", () => { Env.Print("this is c"); }) }, + { "B", ("hello", () => { Env.Print("this is b"); }) } + }; + + var ss = Env.Editor.SSGet(/*":S", */ messages: ("get", "del" ), + keywords: keyword); + Env.Print(ss!); + } + + [CommandMethod(nameof(Test_ExportWMF), CommandFlags.Modal | CommandFlags.UsePickSet)] + public void Test_ExportWMF() + { + var psr = Env.Editor.SelectImplied();// 预选 + if (psr.Status != PromptStatus.OK) + psr = Env.Editor.GetSelection();// 手选 + if (psr.Status != PromptStatus.OK) + return; + + var ids = psr.Value.GetObjectIds(); + // acad21(acad08没有)先选择再执行..会让你再选择一次 + // 而且只发生在启动cad之后第一次执行. + Env.Editor.ComExportWMF(@"C:\Users\vic\Desktop\aaa.dwg", ids); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestEntity/TestAddEntity.cs b/tests/TestShared/TestEntity/TestAddEntity.cs new file mode 100644 index 0000000000000000000000000000000000000000..920e6e03772c73b068e522d4d2a27374ad5c76f6 --- /dev/null +++ b/tests/TestShared/TestEntity/TestAddEntity.cs @@ -0,0 +1,157 @@ +namespace Test; + +public class TestAddEntity +{ +#region 直线 + [CommandMethod(nameof(Test_AddLinetoCurrentSpace))] + public void Test_AddLinetoCurrentSpace() + { + using DBTrans tr = new(); // 开启事务 + + Line line = new(new(0, 0, 0), new(1, 1, 0)); // 定义一个直线 + tr.CurrentSpace.AddEntity(line); // 将直线添加到当前空间 + } + + [CommandMethod(nameof(Test_AddLinetoModelSpace))] + public void Test_AddLinetoModelSpace() + { + using DBTrans tr = new(); // 开启事务 + + Line line = new(new(0, 0, 0), new(1, 1, 0)); // 定义一个直线 + tr.ModelSpace.AddEntity(line); // 将直线添加到模型空间 + } + + [CommandMethod(nameof(Test_AddLinetoPaperSpace))] + public void Test_AddLinetoPaperSpace() + { + using DBTrans tr = new(); // 开启事务 + + Line line = new(new(0, 0, 0), new(1, 1, 0)); // 定义一个直线 + tr.PaperSpace.AddEntity(line); // 将直线添加到图纸空间 + } + + [CommandMethod(nameof(Test_AddEntities))] + public void Test_AddEntities() + { + // 开启事务 + using DBTrans tr = new(); + // 定义三条直线 + Line line1 = new(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + Line line2 = new(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + Line line3 = new(new Point3d(1, 1, 0), new Point3d(3, 3, 0)); + Circle circle = new(); + // 一次性添加到当前空间 + tr.CurrentSpace.AddEntity(line2, line2, line3, circle); + // 或者可以传入个列表 + List lines = [line1, line2, line3]; + tr.CurrentSpace.AddEntity(lines); + // 或者可以传入个数组 + Line[] lines1 = [line1, line2, line3]; + tr.CurrentSpace.AddEntity(lines1); + // 图元数组 + Entity[] lines2 = [line1, line2, line3, circle]; + tr.CurrentSpace.AddEntity(lines2); + // c#12 新语法,集合表达式 + tr.CurrentSpace.AddEntity([line1, line2, circle]); + } +#endregion + +#region 圆 + [CommandMethod(nameof(Test_AddCircle))] + public void Test_AddCircle() + { + var cir = CircleEx.CreateCircle(Point3d.Origin, new(1,0,0)); // 两点创建圆 + var cir1 = CircleEx.CreateCircle(Point3d.Origin, new(1,1,0), new(2,0,0)); //三点创建圆 + var cir2 = CircleEx.CreateCircle(Point3d.Origin, 5); // 圆心半径创建圆 + + using DBTrans tr = new(); + tr.CurrentSpace.AddEntity(cir, cir2); + + // 由于三点不一定能成功创建一个圆,因此返回值是可空的,需要判空 + if (cir1 is not null) + { + tr.CurrentSpace.AddEntity(cir1); + } + } +#endregion + +#region 圆弧 + [CommandMethod(nameof(Test_AddArc))] + public void Test_AddArc() + { + using DBTrans tr = new(); + Arc arc1 = ArcEx.CreateArcSCE(new Point3d(2, 0, 0), new Point3d(0, 0, 0), new Point3d(0, 2, 0));// 起点,圆心,终点 + Arc arc2 = ArcEx.CreateArc(new Point3d(4, 0, 0), new Point3d(0, 0, 0), Math.PI / 2); // 起点,圆心,弧度 + Arc arc3 = ArcEx.CreateArc(new Point3d(1, 0, 0), new Point3d(0, 0, 0), new Point3d(0, 1, 0)); // 起点,圆上一点,终点 + tr.CurrentSpace.AddEntity(arc1, arc2, arc3); + } + +#endregion + + + + + +#region 多段线 + [CommandMethod(nameof(Test_AddPolyline1))] + public void Test_AddPolyline1() + { + using DBTrans tr = new(); + Polyline pl = new(); + pl.SetDatabaseDefaults(); + pl.AddVertexAt(0, new Point2d(0, 0), 0, 0, 0); + pl.AddVertexAt(1, new Point2d(10, 10), 0, 0, 0); + pl.AddVertexAt(2, new Point2d(20, 20), 0, 0, 0); + pl.AddVertexAt(3, new Point2d(30, 30), 0, 0, 0); + pl.AddVertexAt(4, new Point2d(40, 40), 0, 0, 0); + pl.Closed = true; + pl.Color = Color.FromColorIndex(ColorMethod.ByColor, 6); + tr.CurrentSpace.AddEntity(pl); + } + + [CommandMethod(nameof(Test_AddPolyline2))] + public void Test_AddPolyline2() + { + // 集合表达式 + List<(Point3d, double, double, double)> pts = + [ + (new Point3d(0,0,0),0,0,0), + (new Point3d(10,0,0),0,0,0), + (new Point3d(10,10,0),0,0,0), + (new Point3d(0,10,0),0,0,0), + (new Point3d(5,5,0),0,0,0) + ]; + + using DBTrans tr = new(); + var pl = pts.CreatePolyline(); + tr.CurrentSpace.AddEntity(pl); + } + + [CommandMethod(nameof(Test_AddPolyline3))] + public void Test_AddPolyline3() + { + using var tr = new DBTrans(); + + List pts = + [ + new(0, 0, 0), + new(0, 1, 0), + new(1, 1, 0), + new(1, 0, 0) + ]; + var pline = pts.CreatePolyline(); + tr.CurrentSpace.AddEntity(pline); + + // 可以通过委托,一次性的创建多段线并设置属性 + var pline1 = pts.CreatePolyline(p => + { + p.Closed = true; + p.ConstantWidth = 0.2; + p.ColorIndex = 1; + }); + tr.CurrentSpace.AddEntity(pline1); + } + +#endregion + +} diff --git a/tests/TestShared/TestEnv.cs b/tests/TestShared/TestEnv.cs new file mode 100644 index 0000000000000000000000000000000000000000..d1df3b805e85db341e0c5d2b1dac25f400984ba3 --- /dev/null +++ b/tests/TestShared/TestEnv.cs @@ -0,0 +1,184 @@ +namespace Test; + +public class Testenv +{ + [CommandMethod(nameof(Test_Enum))] + public void Test_Enum() + { + Env.CmdEcho = true; + } + [CommandMethod(nameof(Test_Enum1))] + public void Test_Enum1() + { + Env.CmdEcho = false; + } + + [CommandMethod(nameof(Test_Dimblk))] + public void Test_Dimblk() + { + Env.Dimblk = Env.DimblkType.Dot; + Env.Print(Env.Dimblk); + Env.Print(Env.GetDimblkId(Env.DimblkType.Dot)); + Env.Dimblk = Env.DimblkType.Default; + Env.Print(Env.Dimblk); + Env.Print(Env.GetDimblkId(Env.DimblkType.Default)); + Env.Dimblk = Env.DimblkType.Oblique; + Env.Print(Env.Dimblk); + Env.Print(Env.GetDimblkId(Env.DimblkType.Oblique)); + Env.Dimblk = Env.DimblkType.ArchTick; + Env.Print(Env.Dimblk); + Env.Print(Env.GetDimblkId(Env.DimblkType.ArchTick)); + } + [CommandMethod(nameof(Test_Dimblk1))] + public void Test_Dimblk1() + { + var dim = Env.Dimblk; + Env.Editor.WriteMessage(dim.ToString()); + } + + [CommandMethod(nameof(Test_Osmode))] + public void Test_Osmode() + { + // 设置osmode变量,多个值用逻辑或 + Env.OSMode = Env.OSModeType.End | Env.OSModeType.Middle; + // 也可以直接写数值,进行强转 + Env.OSMode = (Env.OSModeType)5179; + // 追加模式 + Env.OSMode |= Env.OSModeType.Center; + // 检查是否有某个模式 + var os = Env.OSMode.Include(Env.OSModeType.Center); + // 取消某个模式 + Env.OSMode ^= Env.OSModeType.Center; + Env.Editor.WriteMessage(Env.OSMode.ToString()); + } + [CommandMethod(nameof(Test_Osmode1))] + public void Test_Osmode1() + { + var dim = Env.OSMode; + Env.Editor.WriteMessage(dim.ToString()); + } +#if false + [CommandMethod(nameof(Test_Cadver))] + public void Test_Cadver() + { + // Env.Print(AcadVersion.Versions); + AcadVersion.Versions.ForEach(v => Env.Print(v)); + AcadVersion.FromApp(Acap.AcadApplication)?.Print(); + 1.Print(); + "1".Print(); + } +#endif + [CommandMethod(nameof(Test_GetVar))] + public void Test_GetVar() + { + // test getvar + var a = Env.GetVar("dbmod"); + a.Print(); + Env.SetVar("dbmod1", 1); + } + + + + //[CommandMethod(nameof(Test_DwgVersion))] + //public void TestDwgVersion() + //{ + // string filename = @"C:\Users\vic\Desktop\test.dwg"; + // var a = Helper.GetCadFileVersion(filename); + // a.Print(); + // ((DwgVersion)a).Print(); + //} + + +#if !zcad + // 通过此功能获取全部变量,尚不清楚此处如何设置,没有通过测试 + [CommandMethod(nameof(Test_GetvarAll))] + public static void Test_GetvarAll() + { + GetvarAll(); + } + + public static Dictionary GetvarAll() + { + var dict = new Dictionary(); + var en = new SystemVariableEnumerator(); + while (en.MoveNext()) + { + Console.WriteLine(en.Current.Name + "-----" + en.Current.Value);// Value会出现异常 + dict.Add(en.Current.Name, en.Current.Value); + } + return dict; + } +#endif + + [CommandMethod(nameof(Test_GetEnv))] + public static void Test_GetEnv() + { + var dir = Env.GetEnv("PrinterConfigDir"); + Env.Printl("pc3打印机位置:" + dir); + + Env.SetEnv("abc", "656"); + + var obj = Env.GetEnv("abc"); + Env.Printl("GetEnv:" + obj); + + Env.Printl("GetEnv:" + Env.GetEnv("abc")); + Env.Printl("GetEnv PATH:" + Env.GetEnv("PATH")); + + Env.Printl($"getenv-acad: {Env.GetEnv("ACAD")}"); + Env.Printl($"getvar-acad: {Env.GetVar("TRUSTEDPATHS")}"); + Env.Printl($"getenv-TRUSTEDPATHS: {Env.GetEnv("TRUSTEDPATHS")}"); + Env.Printl($"getenv-osmode: {Env.GetEnv("osmode")}"); + Env.Printl($"getvar-osmode: {Env.GetVar("osmode")}"); + } + [CommandMethod(nameof(Test_AppendPath))] + public static void Test_AppendPath() + { + Directory.Exists(@"C:\Folder4").Print(); + Env.AppendSupportPath(@"C:\Folder4", @"C:\Folder5", @"C:\Folder6"); + // Env.AppendTrustedPath(@"c:\a\x",@"c:\a\c"); + // AppendSupportPath(@"c:\a\c"); + Env.GetEnv("ACAD").Print(); + // Env.SetEnv("ACAD", @"C:\Folder1;"+Env.GetEnv("ACAD")); + Env.GetEnv("ACAD").Contains(@"C:\Folder1").Print(); + + } + + [CommandMethod(nameof(Test_RemovePath))] + public static void Test_RemovePath() + { + // var acad = Acaop.TryGetSystemVariable("ACAD").ToString(); + // acad.Print(); + // Acaop.SetSystemVariable("ACAD", acad + @";c:\a\x"); + Env.GetEnv("ACAD").Print(); + Env.RemoveSupportPath(); + // Env.RemoveTrustedPath(@"c:\a\x"); + Env.GetEnv("ACAD").Print(); + } + + public static void AppendSupportPath(string path) + { + + string key = HostApplicationServices.Current.UserRegistryProductRootKey; + // 计算机\HKEY_CURRENT_USER\SOFTWARE\Autodesk\AutoCAD\R24.0\ACAD-4101:804 + var ackey = Registry.CurrentUser.OpenSubKey($@"{key}\Profiles") ?? null; + + if (ackey != null) + { + var listkey = ackey.GetSubKeyNames(); + foreach (var item in listkey) + { + var acadkey = ackey.OpenSubKey($@"{item}\General", true); + const string name = "ACAD"; + var str = acadkey?.GetValue(name)?.ToString(); + if (str != null && !str.ToLower().Contains(path.ToLower())) + { + acadkey?.SetValue(name, $@"{str}{path};"); + } + } + } + + ackey?.Close(); + } + + +} \ No newline at end of file diff --git a/tests/TestShared/TestExtents.cs b/tests/TestShared/TestExtents.cs new file mode 100644 index 0000000000000000000000000000000000000000..96c04db04ec8d7e080b1edf6ccd797b69afcc61e --- /dev/null +++ b/tests/TestShared/TestExtents.cs @@ -0,0 +1,108 @@ +namespace TestShared; + +public class TestExtents +{ + [CommandMethod(nameof(Test_BlockExtents))] + public void Test_BlockExtents() + { + using var tr = new DBTrans(); + var ent = Env.Editor.GetEntity("pick the entity"); + if (ent.Status != PromptStatus.OK ) + { + return; + } + + var block = ent.ObjectId.GetObject(); + if (block != null && block.Bounds.HasValue) + { + var extent = block.GeometricExtents; + List pts = [ + extent.MinPoint, + new Point3d(extent.MinPoint.X,extent.MaxPoint.Y,0), + extent.MaxPoint, + new Point3d(extent.MaxPoint.X,extent.MinPoint.Y,0), + + ]; + + tr.CurrentSpace.AddEntity(pts.CreatePolyline(action: e => e.ColorIndex = 1)); + + if (block is BlockReference block1) + { + var extents = block1.GeometryExtentsBestFit(); + List pts1 = + [ + extents.MinPoint, + new Point3d(extents.MinPoint.X, extents.MaxPoint.Y, 0), + extents.MaxPoint, + new Point3d(extents.MaxPoint.X, extents.MinPoint.Y, 0), + ]; + tr.CurrentSpace.AddEntity(pts.CreatePolyline(action: e => e.ColorIndex = 2)); + + var extents2 = block1.GetBoundingBoxEx(); + tr.CurrentSpace.AddEntity(pts.CreatePolyline(action: e => e.ColorIndex = 3)); + + // 此处是计算块定义的包围盒,不是块参照的,所以一般情况下不需要使用。 + var ext = new Extents3d(); + ext.AddBlockExtents(block1.BlockTableRecord.GetObject()); + tr.CurrentSpace.AddEntity(ext.CreatePolyline(action: e => e.ColorIndex = 4)); + } + + + } + } + + [CommandMethod(nameof(Test_entextents))] + public void Test_entextents() + { + using var tr = new DBTrans(); + var a = Env.Editor.GetSelection().Value. + GetEntities(OpenMode.ForWrite); + foreach (var e in a) + { + var b = e.Bounds.HasValue; //获取是否有包围盒 + var name = e.ObjectId.ObjectClass.DxfName; + Env.Print($"{name}是否有包围盒-" + b); + if (b) + { + tr.CurrentSpace.AddEntity(e.Bounds!.Value.CreatePolyline(action: e => + { + e.ColorIndex = 4; + e.Closed = true; + })); + var ext = e.GetBoundingBoxEx(); + if (ext.HasValue) + { + tr.CurrentSpace.AddEntity( + ext.Value.Extents3d.CreatePolyline(action: e => + { + e.ColorIndex = 5; + e.Closed = true; + })); + } + + if (e is Curve spline) + { + var ge = spline.GetGeCurve(); + var box = ge.BoundBlock; + List lst = + [ + box.BasePoint, + box.BasePoint + box.Direction1, + box.BasePoint + box.Direction2, + box.BasePoint + box.Direction3, + ]; + tr.CurrentSpace.AddEntity(lst.CreatePolyline(action: e => + { + e.ColorIndex = 6; + e.Closed = true; + })); + } + + } + + + + + } + } +} \ No newline at end of file diff --git a/tests/TestShared/TestFileDatabase.cs b/tests/TestShared/TestFileDatabase.cs new file mode 100644 index 0000000000000000000000000000000000000000..e5c58c326c09c5c083598fcbe1995940e2df70c0 --- /dev/null +++ b/tests/TestShared/TestFileDatabase.cs @@ -0,0 +1,28 @@ +namespace Test; + +/************************************************************** +*作者:Leon +*创建时间:2022/2/11 9:55:32 +**************************************************************/ + +public class TestFileDatabase +{ + [CommandMethod(nameof(Test_FileDatabaseInit))] + public void Test_FileDatabaseInit() + { + try + { + var fileName = @"C:\Users\Administrator\Desktop\合并详图测试BUG.dwg"; + using DBTrans trans = new(fileName); + trans.ModelSpace.AddEntity(new Line(new(0, 0, 0), new(1000, 1000, 0))); + if (trans.Document is not null && trans.Document.IsActive) + trans.Document.SendStringToExecute("_qsave\n", false, true, true); + else + trans.Database.SaveAs(fileName, (DwgVersion)27); + } + catch (System.Exception e) + { + System.Windows.MessageBox.Show(e.Message); + } + } +} \ No newline at end of file diff --git a/tests/TestShared/TestHatchinfo.cs b/tests/TestShared/TestHatchinfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..e241dfba01184c80bb1a7470f8e9048f39c92296 --- /dev/null +++ b/tests/TestShared/TestHatchinfo.cs @@ -0,0 +1,16 @@ +namespace Test; + +public class TestHatchinfo +{ + [CommandMethod(" TestHatchInfo")] + public void TestHatchInfo() + { + using var tr = new DBTrans(); + var sf = new SelectionFilter(new TypedValue[] { new TypedValue(0, "*line,circle,arc") }); + var ids = Env.Editor.SSGet(null, sf).Value?.GetObjectIds(); + if (ids == null || ids.Count() <= 0) return; + var hf = new HatchInfo(ids!, false, null, 1, 0).Mode2UserDefined(); + hf.Build(tr.CurrentSpace); + } +} + diff --git a/tests/TestShared/TestId.cs b/tests/TestShared/TestId.cs new file mode 100644 index 0000000000000000000000000000000000000000..57f19cf512f635112ceef6637b3c36250ee02df5 --- /dev/null +++ b/tests/TestShared/TestId.cs @@ -0,0 +1,72 @@ +namespace Test; + +public class Testid +{ + [CommandMethod(nameof(Test_Id))] + public void Test_Id() + { + using DBTrans tr = new(); + Line line = new(new Point3d(0, 0, 0), new Point3d(1, 1, 0)); + tr.CurrentSpace.AddEntity(line); + tr.Dispose(); + + var res = Env.Editor.GetEntity("\npick ent:"); + if (res.Status == PromptStatus.OK) + { + res.ObjectId.Erase(); + } + // using (var tr = new DBTrans()) + // { + // var res = Env.Editor.GetEntity("\npick ent:"); + // if(res.Status == PromptStatus.OK) + // { + // res.ObjectId.Erase(); + // } + + // } + } + + [CommandMethod(nameof(Test_MyCommand))] + public void Test_MyCommand() + { + using DBTrans dbtrans = new(Env.Document, true, false); + using var trans = Env.Database.TransactionManager.StartTransaction(); + + var l1 = new Line(new Point3d(0, 0, 0), new Point3d(100, 100, 0)); + var blkred = trans.GetObject(Env.Database.CurrentSpaceId, OpenMode.ForWrite) as BlockTableRecord; + blkred?.AppendEntity(l1); + trans.AddNewlyCreatedDBObject(l1, true); + trans.Commit(); + // dbtrans.Dispose(); + } + [CommandMethod(nameof(Test_TextStyle))] + public void Test_TextStyle() + { + using DBTrans tr = new(); + tr.TextStyleTable.Add("宋体", "宋体.ttf", 0.8); + + tr.TextStyleTable.Add("宋体1", FontTTF.宋体, 0.8); + tr.TextStyleTable.Add("仿宋体", FontTTF.仿宋, 0.8); + tr.TextStyleTable.Add("fsgb2312", FontTTF.仿宋GB2312, 0.8); + tr.TextStyleTable.Add("arial", FontTTF.Arial, 0.8); + tr.TextStyleTable.Add("romas", FontTTF.Romans, 0.8); + + + + tr.TextStyleTable.Add("daziti", ttr => { + ttr.FileName = "ascii.shx"; + ttr.BigFontFileName = "gbcbig.shx"; + }); + } + + [CommandMethod(nameof(Test_TextStyleChange))] + public void Test_TextStyleChange() + { + using DBTrans tr = new(); + + + tr.TextStyleTable.AddWithChange("宋体1", "simfang.ttf", height: 5); + tr.TextStyleTable.AddWithChange("仿宋体", "宋体.ttf"); + tr.TextStyleTable.AddWithChange("fsgb2312", "Romans", "gbcbig"); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestJig.cs b/tests/TestShared/TestJig.cs new file mode 100644 index 0000000000000000000000000000000000000000..d0076f4fde2dd02dcf19b666e8a7bb79ba8c58b3 --- /dev/null +++ b/tests/TestShared/TestJig.cs @@ -0,0 +1,313 @@ +namespace Test; + +using System.Windows.Forms; + +public class Commands_Jig +{ + // 已在数据库的图元如何进入jig + [CommandMethod(nameof(Test_Jig33))] + public static void Test_Jig33() + { + using DBTrans tr = new(); + var per = tr.Editor?.GetEntity("\n点选圆形:"); + if (per?.Status != PromptStatus.OK) + return; + var cir = tr.GetObject(per.ObjectId, OpenMode.ForWrite); + if (cir == null) + return; + var oldSp = cir.StartPoint; + JigEx? moveJig = null; + moveJig = new JigEx((mousePoint, drawEntitys) => { + moveJig!.SetOptions(oldSp);// 回调过程中也可以修改基点 + // cir.UpgradeOpen();// 已经提权了,所以这里不需要提权 + cir.Move(cir.StartPoint, mousePoint); + // cir.DowngradeOpen(); + + // 此处会Dispose图元, + // 所以此处不加入已经在数据库的图元,而是加入new Entity的. + // drawEntitys.Enqueue(cir); + }); + moveJig.SetOptions(cir.GeometricExtents.MinPoint); + + // 此处详见方法注释 + moveJig.DatabaseEntityDraw(draw => { + draw.RawGeometry.Draw(cir); + }); + + while (true) + { + var prDrag = Env.Editor.Drag(moveJig); + if (prDrag.Status == PromptStatus.OK) + break; + } + moveJig.Dispose(); + } + + + // 不在数据库的图元如何进入jig + [CommandMethod(nameof(Test_Jig44))] + public void Test_Jig44() + { + using DBTrans tr = new(); + var per = Env.Editor.GetEntity("\n请选择一条多段线:"); + if (per.Status != PromptStatus.OK) + return; + var ent = tr.GetObject(per.ObjectId, OpenMode.ForWrite); + if (ent is not Polyline pl) + return; + + /* + * 鼠标采样器执行时修改鼠标基点 + * 原因: 多段线与鼠标垂直点作为 BasePoint,jig鼠标点为确定点 + * 所以需要先声明再传入指针,但是我发现null也可以. + */ + JigPromptPointOptions? options = null; + using var jig = new JigEx((mousePoint, drawEntitys) => { + var closestPt = pl.GetClosestPointTo(mousePoint, false); + + // 回调过程中SetOptions会覆盖配置,所以如果想增加关键字或者修改基点, + // 不要这样做: jig.SetOptions(closestPt) 而是使用底层暴露 + options!.BasePoint = closestPt; + + // 允许在循环中替换关键字,需要避免重复加入同一个关键字 + if (!options.Keywords.Contains("A")) + options.Keywords.Add("A"); + + // 生成文字 + var dictString = (pl.GetDistAtPoint(closestPt) * 0.001).ToString("0.00"); + var acText = DBTextEx.CreateDBText(closestPt, dictString, 200); + + // 加入刷新队列 + drawEntitys.Enqueue(acText); + }); + + options = jig.SetOptions(per.PickedPoint); + + // 在这里加入关键字 + // 如果没有这个,那么空格只会是 PromptStatus.None 而不是 PromptStatus.Keyword + // options.Keywords.Add(" ", " ", "空格结束啊"); + // jig.SetSpaceIsKeyword(); + options.Keywords.Add("A","A","A"); + + + bool flag = true; + while (flag) + { + var pr = Env.Editor.Drag(jig); + if (pr.Status == PromptStatus.Keyword) + { + switch (pr.StringResult) + { + case "A": + tr.Editor?.WriteMessage($"\n 您触发了关键字{pr.StringResult}"); + flag = false; + break; + case " ": + tr.Editor?.WriteMessage("\n 触发关键字空格"); + flag = false; + break; + } + } + else if (pr.Status != PromptStatus.OK)// PromptStatus.None == 右键,空格,回车,都在这里结束 + { + tr.Editor?.WriteMessage(Environment.NewLine + pr.Status.ToString()); + return; + } + else + flag = false; + } + tr.CurrentSpace.AddEntity(jig.Entities); + } + + [CommandMethod(nameof(Test_MessageFilter))] + public void Test_MessageFilter() + { + var dm = Acap.DocumentManager; + var ed = dm.MdiActiveDocument.Editor; + + // Create and add our message filter + MyMessageFilter filter = new(); + System.Windows.Forms.Application.AddMessageFilter(filter); + // Start the loop + while (true) + { + // Check for user input events + System.Windows.Forms.Application.DoEvents(); + // Check whether the filter has set the flag + if (filter.bCanceled == true) + { + ed.WriteMessage("\nLoop cancelled."); + break; + } + ed.WriteMessage($"\nInside while loop...and {filter.Key}"); + } + // We're done - remove the message filter + System.Windows.Forms.Application.RemoveMessageFilter(filter); + } + // Our message filter class + public class MyMessageFilter : IMessageFilter + { + public const int WM_KEYDOWN = 0x0100; + public bool bCanceled = false; + public Keys Key { get; private set; } + public bool PreFilterMessage(ref Message m) + { + if (m.Msg == WM_KEYDOWN) + { + // Check for the Escape keypress + Keys kc = (Keys)(int)m.WParam & Keys.KeyCode; + if (m.Msg == WM_KEYDOWN && kc == Keys.Escape) + bCanceled = true; + Key = kc; + // Return true to filter all keypresses + return true; + } + // Return false to let other messages through + return false; + } + } + + + [CommandMethod(nameof(Test_QuickText))] + static public void Test_QuickText() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var db = doc.Database; + var ed = doc.Editor; + + PromptStringOptions pso = new("\nEnter text string") + { + AllowSpaces = true + }; + var pr = ed.GetString(pso); + if (pr.Status != PromptStatus.OK) + return; + + using var tr = doc.TransactionManager.StartTransaction(); + var btr = (BlockTableRecord)tr.GetObject(db.CurrentSpaceId, OpenMode.ForWrite); + // Create the text object, set its normal and contents + + var acText = DBTextEx.CreateDBText(Point3d.Origin, pr.StringResult, 200); + + acText.Normal = ed.CurrentUserCoordinateSystem.CoordinateSystem3d.Zaxis; + btr.AppendEntity(acText); + tr.AddNewlyCreatedDBObject(acText, true); + + // Create our jig + var pj = new TextPlacementJig(tr, db, acText); + // Loop as we run our jig, as we may have keywords + var state = PromptStatus.Keyword; + while (state == PromptStatus.Keyword) + { + var res = ed.Drag(pj); + state = res.Status; + if (state != PromptStatus.OK && state != PromptStatus.Keyword) + return; + } + tr.Commit(); + } + +#if true + class TextPlacementJig : EntityJig + { + // Declare some internal state + readonly Database _db; + readonly Transaction _tr; + + Point3d _position; + double _angle, _txtSize; + + // Constructor + public TextPlacementJig(Transaction tr, Database db, Entity ent) : base(ent) + { + _db = db; + _tr = tr; + _angle = 0; + _txtSize = 1; + } + + protected override SamplerStatus Sampler(JigPrompts jp) + { + // We acquire a point but with keywords + JigPromptPointOptions po = new("\nPosition of text") + { + UserInputControls = + UserInputControls.Accept3dCoordinates | + UserInputControls.NullResponseAccepted | + UserInputControls.NoNegativeResponseAccepted | + UserInputControls.GovernedByOrthoMode + }; + po.SetMessageAndKeywords( + "\nSpecify position of text or " + + "[Bold/Italic/LArger/Smaller/" + + "ROtate90/LEft/Middle/RIght]: ", + "Bold Italic LArger Smaller " + + "ROtate90 LEft Middle RIght" + ); + + PromptPointResult ppr = jp.AcquirePoint(po); + if (ppr.Status == PromptStatus.Keyword) + { + switch (ppr.StringResult) + { + case "Bold": + break; + case "Italic": + break; + case "LArger": + { + // Multiple the text size by two + _txtSize *= 2; + break; + } + case "Smaller": + { + // Divide the text size by two + _txtSize /= 2; + break; + } + case "ROtate90": + { + // To rotate clockwise we subtract 90 degrees and + // then normalise the angle between 0 and 360 + _angle -= Math.PI / 2; + while (_angle < Math.PI * 2) + { + _angle += Math.PI * 2; + } + break; + } + case "LEft": + break; + case "RIght": + break; + case "Middle": + break; + } + return SamplerStatus.OK; + } + else if (ppr.Status == PromptStatus.OK) + { + // Check if it has changed or not (reduces flicker) + if (_position.DistanceTo(ppr.Value) < Tolerance.Global.EqualPoint) + return SamplerStatus.NoChange; + + _position = ppr.Value; + return SamplerStatus.OK; + } + return SamplerStatus.Cancel; + } + + protected override bool Update() + { + // Set properties on our text object + DBText txt = (DBText)Entity; + txt.Position = _position; + txt.Height = _txtSize; + txt.Rotation = _angle; + return true; + } + } +#endif +} \ No newline at end of file diff --git a/tests/TestShared/TestJigExTransient.cs b/tests/TestShared/TestJigExTransient.cs new file mode 100644 index 0000000000000000000000000000000000000000..52eb3f4be1f074790dfdaf2fea4e84c8a5c3dfb7 --- /dev/null +++ b/tests/TestShared/TestJigExTransient.cs @@ -0,0 +1,88 @@ + +namespace Test; + +public partial class Test +{ + [CommandMethod(nameof(Test_JigExTransient))] + public void Test_JigExTransient() + { + // 先取1点,建2个圆 + var getpt = Env.Editor.GetPoint("\n选择点"); + if (getpt.Status != PromptStatus.OK) + return; + var pt = getpt.Value.Ucs2Wcs(); + + var c1 = new Circle(pt, Vector3d.ZAxis, 100); + var c2 = new Circle(pt.Polar(0, 300), Vector3d.ZAxis, 100); + + // 创建瞬态容器 + using JigExTransient jet = new(); + + // 将c1以默认模式,c2以亮显模式加到瞬态容器,即在图纸上显示 + jet.Add(c1); + jet.Add(c2, Acgi.TransientDrawingMode.Highlight); + + // 再取一点,再建一个圆c3 + var r2 = Env.Editor.GetPoint("\n选择下一点"); + if (r2.Status != PromptStatus.OK) + return; + var pt2 = r2.Value.Ucs2Wcs(); + + // 将c1从瞬态容器中移除,将c2修改颜色,c3加入瞬态容器 + jet.Remove(c1); + + c2.ColorIndex = 1; + var c3 = new Circle(pt2, Vector3d.ZAxis, 150); + jet.Add(c3); + + // 由于c2进行了修改,所以需要更新, + // 可以单个更新或更新整个瞬态容器 + jet.Update(c2); + // jet.UpdateAll(); + + Env.Editor.GetPoint("\n此拾取无意义,仅为了暂停查看"); + + // 加到图纸中,为测试瞬态容器可以自行dispose消失,所以未全部加入 + using DBTrans tr = new(); + tr.CurrentSpace.AddEntity(c3); + + // 若想将容器中所有图元全部加入提供了Entities属性 + // tr.CurrentSpace.AddEntity(jet.Entities); + } + + [CommandMethod(nameof(Test_JigExTransentDim))] + public static void Test_JigExTransentDim() + { + PromptPointOptions ppo = new("") + { + AppendKeywordsToMessage = false, + }; + List pts = new(); + for (int i = 0; i < 3; i++) + { + ppo.Message = $"\n选择标注点{i + 1}"; + var ppr = Env.Editor.GetPoint(ppo); + if (ppr.Status != PromptStatus.OK) + return; + pts.Add(ppr.Value); + } + + using DBTrans tr = new(); + + using RotatedDimension dimension = new(); + dimension.SetDatabaseDefaults();// cad16没有这个不显示 + dimension.Rotation = 0; + dimension.XLine1Point = pts[0]; + dimension.XLine2Point = pts[1]; + dimension.DimLinePoint = pts[2]; + dimension.DimensionText = "<>"; + dimension.DimensionStyle = tr.Database.Dimstyle; + + using JigExTransient jet = new(); + jet.Add(dimension, TransientDrawingMode.Highlight); + jet.UpdateAll(); + + Env.Editor.GetPoint("\n此拾取无意义,仅为了暂停查看"); + tr.CurrentSpace.AddEntity(dimension); + } +} diff --git a/tests/TestShared/TestJson.cs b/tests/TestShared/TestJson.cs new file mode 100644 index 0000000000000000000000000000000000000000..281e1b1bce4ee8e0a21e9aa11696d9f83b7ae2fd --- /dev/null +++ b/tests/TestShared/TestJson.cs @@ -0,0 +1,27 @@ +namespace TestShared; + +public class TestJson +{ + /* + * 需要引入: + * + * + * + * + */ + [CommandMethod(nameof(JavaScriptSerializer))] + public void JavaScriptSerializer() + { + List RegisteredUsers = []; + RegisteredUsers.Add(0); + RegisteredUsers.Add(1); + RegisteredUsers.Add(2); + RegisteredUsers.Add(3); + + var serializedResult = System.Text.Json.JsonSerializer.Serialize(RegisteredUsers); + var deserializedResult = System.Text.Json.JsonSerializer.Deserialize>(serializedResult); + + + + } +} \ No newline at end of file diff --git a/tests/TestShared/TestLayer.cs b/tests/TestShared/TestLayer.cs new file mode 100644 index 0000000000000000000000000000000000000000..62df5e1bf2723132947d5374c1f7b6d20389fbce --- /dev/null +++ b/tests/TestShared/TestLayer.cs @@ -0,0 +1,66 @@ +namespace Test; + +public class TestLayer +{ + [CommandMethod(nameof(Test_LayerAdd0))] + public void Test_LayerAdd0() + { + using DBTrans tr = new(); + tr.LayerTable.Add("1"); + tr.LayerTable.Add("2", lt => { + lt.Color = Color.FromColorIndex(ColorMethod.ByColor, 1); + lt.LineWeight = LineWeight.LineWeight030; + }); + tr.LayerTable.Remove("3"); + tr.LayerTable.Delete("0"); + tr.LayerTable.Change("4", lt => { + lt.Color = Color.FromColorIndex(ColorMethod.ByColor, 2); + }); + } + + + // 添加图层 + [CommandMethod(nameof(Test_LayerAdd1))] + public void Test_LayerAdd1() + { + using DBTrans tr = new(); + tr.LayerTable.Add("test1", Color.FromColorIndex(ColorMethod.ByColor, 1)); + } + + // 添加图层 + [CommandMethod(nameof(Test_LayerAdd2))] + public void Test_LayerAdd2() + { + using DBTrans tr = new(); + tr.LayerTable.Add("test2", 2); + // tr.LayerTable["3"] = new LayerTableRecord(); + } + // 删除图层 + [CommandMethod(nameof(Test_LayerDel))] + public void Test_LayerDel() + { + using DBTrans tr = new(); + tr.LayerTable.Remove("0"); // 删除图层 0 + tr.LayerTable.Remove("Defpoints");// 删除图层 Defpoints + tr.LayerTable.Remove("1"); // 删除不存在的图层 1 + tr.LayerTable.Remove("2"); // 删除有图元的图层 2 + tr.LayerTable.Remove("3"); // 删除图层 3 // 删除图层 3 + + tr.LayerTable.Remove("2"); // 测试是否能强制删除 + } + + [CommandMethod(nameof(Test_PrintLayerName))] + public void Test_PrintLayerName() + { + using DBTrans tr = new(); + foreach (var layerRecord in tr.LayerTable.GetRecords()) + { + Env.Printl(layerRecord.Name); + } + foreach (var layerRecord in tr.LayerTable.GetRecords()) + { + Env.Printl(layerRecord.Name); + break; + } + } +} \ No newline at end of file diff --git a/tests/TestShared/TestLisp.cs b/tests/TestShared/TestLisp.cs new file mode 100644 index 0000000000000000000000000000000000000000..4bd7b193b39beb6d5b61f31a5d4b7945ee7551f6 --- /dev/null +++ b/tests/TestShared/TestLisp.cs @@ -0,0 +1,122 @@ +namespace Test; + +public class TestLisp +{ + // 定义lisp函数 + [LispFunction(nameof(LispTest_RunLisp))] + public static object LispTest_RunLisp(ResultBuffer rb) + { + CmdTest_RunLisp(); + return null!; + } + + // 模态命令,只有当CAD发出命令提示或当前没有其他的命令或程序活动的时候才可以被触发 + [CommandMethod("CmdTest_RunLisp1")] + // 透明命令,可以在一个命令提示输入的时候触发例如正交切换,zoom等 + [CommandMethod("CmdTest_RunLisp2", CommandFlags.Transparent)] + // 选择图元之后执行命令将可以从 获取图元 + [CommandMethod("CmdTest_RunLisp3", CommandFlags.UsePickSet)] + // 命令执行前已选中部分实体.在命令执行过程中这些标记不会被清除 + [CommandMethod("CmdTest_RunLisp4", CommandFlags.Redraw)] + // 命令不能在透视图中使用 + [CommandMethod("CmdTest_RunLisp5", CommandFlags.NoPerspective)] + // 命令不能通过 MULTIPLE命令 重复触发 + [CommandMethod("CmdTest_RunLisp6", CommandFlags.NoMultiple)] + // 不允许在模型空间使用命令 + [CommandMethod("CmdTest_RunLisp7", CommandFlags.NoTileMode)] + // 不允许在布局空间使用命令 + [CommandMethod("CmdTest_RunLisp8", CommandFlags.NoPaperSpace)] + // 命令不能在OEM产品中使用 + [CommandMethod("CmdTest_RunLisp9", CommandFlags.NoOem)] + // 不能直接使用命令名调用,必须使用 组名.全局名 调用 + [CommandMethod("CmdTest_RunLisp10", CommandFlags.Undefined)] + // 定义lisp方法.已废弃 请使用lispfunction + [CommandMethod("CmdTest_RunLisp11", CommandFlags.Defun)] + // 命令不会被存储在新的命令堆上 + [CommandMethod("CmdTest_RunLisp12", CommandFlags.NoNewStack)] + // 命令不能被内部锁定(命令锁) + [CommandMethod("CmdTest_RunLisp13", CommandFlags.NoInternalLock)] + // 调用命令的文档将会被锁定为只读 + [CommandMethod("CmdTest_RunLisp14", CommandFlags.DocReadLock)] + // 调用命令的文档将会被锁定,类似document.lockdocument + [CommandMethod("CmdTest_RunLisp15", CommandFlags.DocExclusiveLock)] + // 命令在CAD运行期间都能使用,而不只是在当前文档 + [CommandMethod("CmdTest_RunLisp16", CommandFlags.Session)] + // 获取用户输入时,可以与属性面板之类的交互 + [CommandMethod("CmdTest_RunLisp17", CommandFlags.Interruptible)] + // 命令不会被记录在命令历史记录 + [CommandMethod("CmdTest_RunLisp18", CommandFlags.NoHistory)] +#if (!zcad) + // 命令不会被 UNDO取消 + [CommandMethod("CmdTest_RunLisp19", CommandFlags.NoUndoMarker)] + // 不能在参照块中使用命令 + [CommandMethod("CmdTest_RunLisp20", CommandFlags.NoBlockEditor)] + + // acad09增,不会被动作录制器 捕捉到 + [CommandMethod("CmdTest_RunLisp21", CommandFlags.NoActionRecording)] + // acad09增,会被动作录制器捕捉 + [CommandMethod("CmdTest_RunLisp22", CommandFlags.ActionMacro)] + + + // 推断约束时不能使用命令 + [CommandMethod("CmdTest_RunLisp23", CommandFlags.NoInferConstraint)] + // 命令允许在选择图元时临时显示动态尺寸 + [CommandMethod("CmdTest_RunLisp24", CommandFlags.TempShowDynDimension)] +#endif + public static void CmdTest_RunLisp() + { + // 测试方法1: (command "CmdTest_RunLisp1") + // 测试方式2: (LispTest_RunLisp) + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var ed = doc.Editor; + + var sb = new StringBuilder(); + foreach (var item in Enum.GetValues(typeof(EditorEx.RunLispFlag))) + { + sb.Append((byte)item); + sb.Append(','); + } + sb.Remove(sb.Length - 1, 1); + var option = new PromptIntegerOptions($"\n输入RunLispFlag枚举值:[{sb}]"); + var ppr = ed.GetInteger(option); + + if (ppr.Status != PromptStatus.OK) + return; + var flag = (EditorEx.RunLispFlag)ppr.Value; + + if (flag == EditorEx.RunLispFlag.AdsQueueexpr) + { + // 同步 + Env.Editor.RunLisp("(setq a 10)(princ)", + EditorEx.RunLispFlag.AdsQueueexpr); + Env.Editor.RunLisp("(princ a)", + EditorEx.RunLispFlag.AdsQueueexpr);// 成功输出 + } + else if (flag == EditorEx.RunLispFlag.AcedEvaluateLisp) + { + // 使用(command "CmdTest_RunLisp1")发送,然后 !b 查看变量,acad08是有值的,高版本是null + var strlisp0 = "(setq b 20)"; + var res0 = Env.Editor.RunLisp(strlisp0, + EditorEx.RunLispFlag.AcedEvaluateLisp); // 有lisp的返回值 + + var strlisp1 = "(defun f1( / )(princ \"aa\"))"; + var res1 = Env.Editor.RunLisp(strlisp1, + EditorEx.RunLispFlag.AcedEvaluateLisp); // 有lisp的返回值 + + var strlisp2 = "(defun f2( / )(command \"line\"))"; + var res2 = Env.Editor.RunLisp(strlisp2, + EditorEx.RunLispFlag.AcedEvaluateLisp); // 有lisp的返回值 + } + else if (flag == EditorEx.RunLispFlag.SendStringToExecute) + { + // 测试异步 + // (command "CmdTest_RunLisp1")和(LispTest_RunLisp)4都是异步 + var str = "(setq c 40)(princ)"; + Env.Editor.RunLisp(str, + EditorEx.RunLispFlag.SendStringToExecute); // 异步,后发送 + Env.Editor.RunLisp("(princ c)", + EditorEx.RunLispFlag.AdsQueueexpr); // 同步,先发送了,输出是null + } + } +} \ No newline at end of file diff --git a/tests/TestShared/TestLoop.cs b/tests/TestShared/TestLoop.cs new file mode 100644 index 0000000000000000000000000000000000000000..438253ae5a8b7e03c3a0660e9d31409db966afb8 --- /dev/null +++ b/tests/TestShared/TestLoop.cs @@ -0,0 +1,25 @@ +namespace Test; +public class TestLoop +{ + [CommandMethod(nameof(Test_LoopList))] + public void Test_LoopList() + { + var loop = new LoopList + { + 0, + 1, + 2, + 3, + 4, + 5 + }; + + Env.Print(loop); + + loop.SetFirst(loop.Last!); + Env.Print(loop); + Env.Print(loop.Min()); + loop.SetFirst(new LoopListNode(loop.Min(), loop)); + Env.Print(loop); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestMarshal.cs b/tests/TestShared/TestMarshal.cs new file mode 100644 index 0000000000000000000000000000000000000000..80398e2910a1312defdfbd13c97c6b5cf2c834b1 --- /dev/null +++ b/tests/TestShared/TestMarshal.cs @@ -0,0 +1,123 @@ +using System.Diagnostics; +using static IFoxCAD.Basal.WindowsAPI; + +namespace TestShared; + +public class TestMarshal +{ + [CommandMethod(nameof(TestToBytes))] + public void TestToBytes() + { + var ptA = new Point3d(123, 456, 789); + var bytes = StructToBytes(ptA); + var ptB = BytesToStruct(bytes); + Env.Printl(ptB); + } + + [CommandMethod(nameof(Test_ChangeLinePoint))] + public void Test_ChangeLinePoint() + { + var prs = Env.Editor.SSGet("\n 选择直线"); + if (prs.Status != PromptStatus.OK) + return; + + using DBTrans tr = new(); + + prs.Value.GetObjectIds().ForEach(id => { + var line = id.GetObject(); + if (line == null) + return; + using (line.ForWrite()) + unsafe + { + // 不允许直接 &这个表达式进行取址(因为它是属性,不是字段) + // 实际上就是默认拷贝一份副本出来 + var p1 = line.StartPoint; + ((Point3D*)&p1)->X = 0; + ((Point3D*)&p1)->Y = 0; + ((Point3D*)&p1)->Z = 0; + line.StartPoint = p1;// 又放回去,节省了一个变量 + + var p2 = line.EndPoint; + ((Point3D*)&p2)->X = 100; + ((Point3D*)&p2)->Y = 100; + ((Point3D*)&p2)->Z = 0; + line.EndPoint = p2; + } + }); + } + + [CommandMethod(nameof(Test_ImplicitPoint3D))] + public void Test_ImplicitPoint3D() + { + // 无法用指针转换类型,所以隐式转换是无法不new的, + // 貌似是因为 + // 如果发生了获取对象的成员引用指针,没有new的话,会发生引用不计数...造成GC释放失效... + // 而微软没有提供一种计数转移的方法...造成我无法实现此操作... + unsafe + { + Point3d pt1 = new(1, 56, 89); + var a1 = (Point3D*)&pt1; + DebugEx.Printl("指针类型转换,获取x::" + a1->X); + + var pt2 = Point3D.Create(new IntPtr(&pt1)); + DebugEx.Printl("pt1地址::" + (int)&pt1); + DebugEx.Printl("pt2地址::" + (int)&pt2); + Debug.Assert(&pt1 == &pt2);//不相等,是申请了新内存 + } + } + + [CommandMethod(nameof(Test_Marshal))] + public void Test_Marshal() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var ed = doc.Editor; + // 0x01 如何修改Point3d内容? + Point3d pt = new(100, 50, 0); + ed.WriteMessage("\n原始:" + pt.ToString()); + + // 0x02 最佳方法: + // 将Point3d内存转为Point3D,以此避开get保护,实现修改内部值 + // 为了避免在安全类型中转换,多了栈帧(无法内联),直接用指针处理 + unsafe + { + ((Point3D*)&pt)->X = 12345;//必须强转成这个指针类型,不然它为(Point3d*) + } + ed.WriteMessage("\n指针法:" + pt.ToString()); + + // 0x03 此方法仍然需要不安全操作,而且多了几个函数调用... + unsafe + { + var p = new IntPtr(&pt); + var result2 = Point3D.Create(p); + result2.X = 220; + result2.ToPtr(p); + } + "封送法:".Print(); + pt.Print(); + + // 拷贝到数组,还原指针到结构,最后将内存空间转换为目标结构体 + // 浪费内存,这不闹嘛~ + int typeSize = Marshal.SizeOf(pt); + byte[] bytes = new byte[typeSize]; + IntPtr structPtr = Marshal.AllocHGlobal(Marshal.SizeOf(pt)); + Marshal.StructureToPtr(pt, structPtr, true); + Marshal.Copy(structPtr, bytes, 0, typeSize); + var result = (Point3d)(Marshal.PtrToStructure(structPtr, typeof(Point3d)) ?? throw new InvalidOperationException()); + "内存拷贝:".Print(); + result.Print(); + + //这个是不对的,会获取类型的指针,替换了就错误了 + //RuntimeTypeHandle handle = structObj.GetType().TypeHandle; + //IntPtr ptr = handle.Value; + //var result3 = (Point3D)Marshal.PtrToStructure(ptr, typeof(Point3D)); + //result3.SetX(330); + //Marshal.StructureToPtr(result3, ptr, true); + //"打印D:".Print(); + //structObj.Print(); + + // 释放内存 + Marshal.FreeHGlobal(structPtr); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestMirrorFile.cs b/tests/TestShared/TestMirrorFile.cs new file mode 100644 index 0000000000000000000000000000000000000000..76ac0337f5b8d657fbe37014ed74e07d24699c46 --- /dev/null +++ b/tests/TestShared/TestMirrorFile.cs @@ -0,0 +1,73 @@ +namespace Test; + +public class MirrorFile +{ + const string file = "D:/JX.dwg"; + const string fileSave = "D:/JX222.dwg"; + + /// + /// 测试:后台打开图纸,镜像文字是否存在文字偏移 + /// 答案:不存在 + /// + [CommandMethod(nameof(CmdTest_MirrorFile))] + public static void CmdTest_MirrorFile() + { + var yaxis = new Point3d(0, 1, 0); + using DBTrans tr = new(file, fileOpenMode: FileOpenMode.OpenForReadAndReadShare); + tr.BlockTable.Change(tr.ModelSpace.ObjectId, modelSpace => { + modelSpace.ForEach(entId => { + var dbText = tr.GetObject(entId, OpenMode.ForRead)!; + if (dbText is null) + return; + + dbText.UpgradeOpen(); + var pos = dbText.Position; + // text.Move(pos, Point3d.Origin); + // Y轴 + dbText.Mirror(Point3d.Origin, yaxis); + // text.Move(Point3d.Origin, pos); + dbText.DowngradeOpen(); + }); + }); + var ver = (DwgVersion)27;/*AC1021 AutoCAD 2007/2008/2009.*/ + tr.Database.SaveAs(fileSave, ver); + } + + /// + /// 测试:后台设置 dbText.IsMirroredInX 属性会令文字偏移 + /// 答案:存在,并提出解决方案 + /// + [CommandMethod(nameof(CmdTest_MirrorFile2))] + public static void CmdTest_MirrorFile2() + { + using DBTrans tr = new(file); + + tr.Task(() => { + var yaxis = new Point3d(0, 1, 0); + tr.BlockTable.Change(tr.ModelSpace.ObjectId, modelSpace => { + modelSpace.ForEach(entId => { + var entity = tr.GetObject(entId, OpenMode.ForWrite)!; + if (entity is DBText dbText) + { + dbText.Mirror(Point3d.Origin, yaxis); + dbText.IsMirroredInX = true; // 这句将导致文字偏移 + + // 指定文字的垂直对齐方式 + if (dbText.VerticalMode == TextVerticalMode.TextBase) + dbText.VerticalMode = TextVerticalMode.TextBottom; + + // 指定文字的水平对齐方式 + dbText.HorizontalMode = dbText.HorizontalMode switch + { + TextHorizontalMode.TextLeft => TextHorizontalMode.TextRight, + TextHorizontalMode.TextRight => TextHorizontalMode.TextLeft, + _ => dbText.HorizontalMode + }; + dbText.AdjustAlignment(tr.Database); + } + }); + }); + }); + tr.Database.SaveAs(fileSave, (DwgVersion)27 /*AC1021 AutoCAD 2007/2008/2009.*/); + } +} \ No newline at end of file diff --git a/tests/TestShared/TestPoint.cs b/tests/TestShared/TestPoint.cs new file mode 100644 index 0000000000000000000000000000000000000000..b69afeaec8a2e1a781ed669b371fee360d94c7e9 --- /dev/null +++ b/tests/TestShared/TestPoint.cs @@ -0,0 +1,204 @@ +namespace Test; +public class TestPoint +{ +#if false + [CommandMethod(nameof(Test_GetAngle))] + public void Test_GetAngle() + { + var pt1 = new Point2d(0, 0); + var pt2 = new Point2d(1, 1); + var angle_pt1_pt2 = pt1.GetAngle(pt2); + var angle_pt2_pt1 = pt2.GetAngle(pt1); + Env.Printl($"pt1-pt2 angle is : {angle_pt1_pt2}, 角度是: {MathEx.ConvertRadToDeg(angle_pt1_pt2)}"); + Env.Printl($"pt2-pt1 angle is : {angle_pt2_pt1}, 角度是: {MathEx.ConvertRadToDeg(angle_pt2_pt1)}"); + + var polar = pt1.Polar(Math.PI / 2, 10); + Env.Printl($"pt1 90° 距离10的点是: {polar}"); + + } +#endif + [CommandMethod(nameof(Test_Endtoend))] + public void Test_Endtoend() + { + var pts = new Point2dCollection + { + new(0, 0), + new(0, 1), + new(1, 1), + new(1, 0) + }; + + + foreach (Point2d pt in pts) + { + Env.Printl($"X={pt.X},Y={pt.Y}"); + } + pts.End2End(); + Env.Printl("-------"); + foreach (Point2d pt in pts) + { + Env.Printl($"X={pt.X},Y={pt.Y}"); + } + Env.Printl("--------"); + var ptss = new Point3dCollection + { + new(0, 0,0), + new(0, 1,0), + new(1, 1,0), + new(1, 0,0) + }; + + foreach (Point3d pt in ptss) + { + Env.Printl($"X={pt.X},Y={pt.Y},Z={pt.Z}"); + } + ptss.End2End(); + Env.Printl("-------"); + foreach (Point3d pt in ptss) + { + Env.Printl($"X={pt.X},Y={pt.Y},Z={pt.Z}"); + } + + } + + /// + /// 红黑树排序点集 + /// + [CommandMethod(nameof(Test_PtSortedSet))] + public void Test_PtSortedSet() + { + var ss1 = new SortedSet + { + new Point2d(1, 1), + new Point2d(4.6, 2), + new Point2d(8, 3), + new Point2d(4, 3), + new Point2d(5, 40), + new Point2d(6, 5), + new Point2d(1, 6), + new Point2d(7, 6), + new Point2d(9, 6) + }; + + /*判断区间,超过就中断*/ + foreach (var item in ss1) + { + if (item.X > 3 && item.X < 7) + DebugEx.Printl(item); + else if (item.X >= 7) + break; + } + } + + + + [CommandMethod(nameof(Test_PtGethash))] + public void Test_PtGethash() + { + // test + var pt = Env.Editor.GetPoint("pick pt").Value; + // Tools.TestTimes2(1_000_000, "新语法", () => { + // pt.GetHashString2(); + // }); + Tools.TestTimes2(1_000_000, "旧语法", () => { + pt.GetHashString(); + }); + } + + [CommandMethod(nameof(Test_Point3dHash))] + public void Test_Point3dHash() + { + Env.Print($"4位小数的hash:{new Point3d(0.0_001, 0.0_002, 0.0).GetHashCode()}"); + Env.Print($"5位小数的hash:{new Point3d(0.00_001, 0.00_002, 0.0).GetHashCode()}"); + Env.Print($"6位小数的hash:{new Point3d(0.000_001, 0.000_002, 0.0).GetHashCode()}"); + Env.Print($"7位小数的hash:{new Point3d(0.000_0_001, 0.000_0_002, 0.0).GetHashCode()}"); + Env.Print($"8位小数的hash:{new Point3d(0.000_00_001, 0.000_00_002, 0.0).GetHashCode()}"); + Env.Print($"9位小数的hash:{new Point3d(0.000_000_001, 0.000_000_002, 0.0).GetHashCode()}"); + Env.Print($"10位小数的hash:{new Point3d(0.000_000_0001, 0.000_000_0002, 0.0).GetHashCode()}"); + Env.Print($"10位小数的hash:{new Point3d(0.000_000_0001, 0.000_000_0001, 0.0).GetHashCode()}"); + + Env.Print($"11位小数的hash:{new Point3d(0.000_000_000_01, 0.000_000_000_02, 0.0).GetHashCode()}"); + Env.Print($"11位小数的hash:{new Point3d(0.000_000_000_01, 0.000_000_000_01, 0.0).GetHashCode()}"); + + Env.Print($"12位小数的hash:{new Point3d(0.000_000_000_001, 0.000_000_000_002, 0.0).GetHashCode()}"); + Env.Print($"12位小数的hash:{new Point3d(0.000_000_000_001, 0.000_000_000_001, 0.0).GetHashCode()}"); + + Env.Print($"13位小数的hash:{new Point3d(0.000_000_000_0001, 0.000_000_000_0002, 0.0).GetHashCode()}"); + Env.Print($"13位小数的hash:{new Point3d(0.000_000_000_0001, 0.000_000_000_0001, 0.0).GetHashCode()}"); + + Env.Print($"14位小数的hash:{new Point3d(0.000_000_000_000_01, 0.000_000_000_000_02, 0.0).GetHashCode()}"); + Env.Print($"14位小数的hash:{new Point3d(0.000_000_000_000_01, 0.000_000_000_000_01, 0.0).GetHashCode()}"); + + Env.Print($"15位小数的hash:{new Point3d(0.000_000_000_000_001, 0.000_000_000_000_002, 0.0).GetHashCode()}"); + Env.Print($"15位小数的hash:{new Point3d(0.000_000_000_000_001, 0.000_000_000_000_001, 0.0).GetHashCode()}"); + + Env.Print($"16位小数的hash:{new Point3d(0.000_000_000_000_000_1, 0.000_000_000_000_000_2, 0.0).GetHashCode()}"); + Env.Print($"16位小数的hash:{new Point3d(0.000_000_000_000_000_1, 0.000_000_000_000_000_1, 0.0).GetHashCode()}"); + + Env.Print($"17位小数的hash:{new Point3d(0.000_000_000_000_000_01, 0.000_000_000_000_000_02, 0.0).GetHashCode()}"); + Env.Print($"17位小数的hash:{new Point3d(0.000_000_000_000_000_01, 0.000_000_000_000_000_01, 0.0).GetHashCode()}"); + + Env.Print($"18位小数的hash:{new Point3d(0.000_000_000_000_000_001, 0.000_000_000_000_000_002, 0.0).GetHashCode()}"); + Env.Print($"18位小数的hash:{new Point3d(0.000_000_000_000_000_001, 0.000_000_000_000_000_001, 0.0).GetHashCode()}"); + + Env.Print($"19位小数的hash:{new Point3d(0.000_000_000_000_000_000_1, 0.000_000_000_000_000_000_2, 0.0).GetHashCode()}"); + Env.Print($"19位小数的hash:{new Point3d(0.000_000_000_000_000_000_1, 0.000_000_000_000_000_000_1, 0.0).GetHashCode()}"); + + Env.Print($"20位小数的hash:{new Point3d(0.000_000_000_000_000_000_01, 0.000_000_000_000_000_000_02, 0.0).GetHashCode()}"); + Env.Print($"20位小数的hash:{new Point3d(0.000_000_000_000_000_000_01, 0.000_000_000_000_000_000_01, 0.0).GetHashCode()}"); + } + + [CommandMethod(nameof(Test_ListEqualspeed))] + public void Test_ListEqualspeed() + { + var lst1 = new List { 1, 2, 3, 4 }; + var lst2 = new List { 1, 2, 3, 4 }; + lst1.SequenceEqual(null!); + Tools.TestTimes2(1000000, "eqaulspeed:", () => { + lst1.SequenceEqual(lst2); + }); + } + + [CommandMethod(nameof(Test_Contains))] + public void Test_Contains() + { + // test list and dict contains speed + var lst = new List { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + var hashset = new HashSet { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 }; + var dict = new Dictionary + { + { 1, 0 }, + { 2, 1 }, + { 3, 2 }, + { 4, 3 }, + { 5, 4 }, + { 6, 5 }, + { 7, 6 }, + { 8, 7 }, + { 9, 8 }, + { 10, 9 }, + { 11, 11 }, + { 12, 12 }, + { 13, 13 }, + { 14, 14 }, + { 15, 15 }, + { 16, 16 }, + { 17, 17 }, + { 18, 18 }, + { 19, 19 }, + { 20, 20 }, + }; + + Tools.TestTimes2(100_0000, "list:", () => { + lst.Contains(20); + }); + + Tools.TestTimes2(100_0000, "hashset:", () => { + hashset.Contains(20); + }); + + Tools.TestTimes2(100_0000, "dict:", () => { + dict.ContainsKey(20); + }); + } +} \ No newline at end of file diff --git a/Test/TestPointEx.cs b/tests/TestShared/TestPointEx.cs similarity index 100% rename from Test/TestPointEx.cs rename to tests/TestShared/TestPointEx.cs diff --git a/tests/TestShared/TestQuadTree.cs b/tests/TestShared/TestQuadTree.cs new file mode 100644 index 0000000000000000000000000000000000000000..1c2e2a880eac3880a65558d5475e90cb187fae59 --- /dev/null +++ b/tests/TestShared/TestQuadTree.cs @@ -0,0 +1,457 @@ +namespace Test; + +/* + * 这里属于用户调用例子, + * 调用时候必须要继承它,再提供给四叉树 + * 主要是用户可以扩展属性 + */ +public class CadEntity : QuadEntity +{ + public ObjectId ObjectId; + // 这里加入其他字段 + public List? Link;// 碰撞链 + public System.Drawing.Color Color; + public double Angle; + public CadEntity(ObjectId objectId, Rect box) : base(box) + { + ObjectId = objectId; + } + public int CompareTo(CadEntity? other) + { + if (other == null) + return -1; + return GetHashCode() ^ other.GetHashCode(); + } + public override int GetHashCode() + { + return (base.GetHashCode(), ObjectId.GetHashCode()).GetHashCode(); + } +} + + + + + +public partial class TestQuadTree +{ + QuadTree? _quadTreeRoot; + #region 四叉树创建并加入 + [CommandMethod(nameof(Test_QuadTree))] + public void Test_QuadTree() + { + using DBTrans tr = new(); + + Rect dbExt; + // 使用数据库边界来进行 + var dbExtent = tr.Database.GetValidExtents3d(); + if (dbExtent == null) + { + // throw new ArgumentException("画一个矩形"); + + // 这个初始值的矩形是很有意义, + // 主要是四叉树分裂过程中产生多个Rect,Rect内有很多重复的double值,是否可以内存复用,以此减少内存大小? + // 接着想了一下,Rect可以是int,long,这样可以利用位运算它扩展和缩小, + // 最小就是1,并且可以控制四叉树深度,不至于无限递归. + // 而且指针长度跟值是一样的,所以就不需要复用了,毕竟跳转一个函数地址挺麻烦的. + // 但是因为啊惊懒的原因,并没有单独制作这样的矩形, + // 而且非常糟糕的是,c#不支持模板约束运算符,使得值类型之间需要通过一层接口来委婉处理,拉低了效率..引用类型倒是无所谓.. + // 要么忍着,要么换c++去搞四叉树吧 + dbExt = new Rect(0, 0, 1 << 10, 1 << 10); + } + else + { + var a = new Point2d(dbExtent.Value.MinPoint.X, dbExtent.Value.MinPoint.Y); + var b = new Point2d(dbExtent.Value.MaxPoint.X, dbExtent.Value.MaxPoint.Y); + dbExt = new Rect(a, b); + } + + // 创建四叉树 + _quadTreeRoot = new QuadTree(dbExt); + + // 数据库边界 + var pl = dbExt.ToPoints(); + var databaseBoundary = new List<(Point3d, double, double, double)> + { + (new Point3d(pl[0].X,pl[0].Y,0),0,0,0), + (new Point3d(pl[1].X,pl[1].Y,0),0,0,0), + (new Point3d(pl[2].X,pl[2].Y,0),0,0,0), + (new Point3d(pl[3].X,pl[3].Y,0),0,0,0), + }; + tr.CurrentSpace.AddEntity(databaseBoundary.CreatePolyline(action: e => e.Closed = true)); + + // 生成多少个图元,导致cad会令undo出错(八叉树深度过大 treemax) + // int maximumItems = 30_0000; + int maximumItems = 1000; + + // 随机图元生成 + List ces = new(); // 用于随机获取图元 + Tools.TestTimes(1, "画圆消耗时间:", () => { + // 生成外边界和随机圆形 + var grc = GenerateRandomCircle(maximumItems, dbExt); + foreach (var ent in grc) + { + // 初始化图元颜色 + ent!.ColorIndex = 1; // Color.FromRgb(0, 0, 0);// 黑色 + var edge = ent.GeometricExtents; + // 四叉树数据 + var entRect = new Rect(edge.MinPoint.X, edge.MinPoint.Y, edge.MaxPoint.X, edge.MaxPoint.Y); + var entId = tr.CurrentSpace.AddEntity(ent); + + var ce = new CadEntity(entId, entRect) + { + Color = RandomEx.NextColor() + }; + ces.Add(ce); + /*加入随机点*/ + var p = edge.MinPoint + new Vector3d(10, 10, 0); + entRect = new Rect(p.Point2d(), p.Point2d()); + entId = tr.CurrentSpace.AddEntity(new DBPoint(p)); + var dbPointCe = new CadEntity(entId, entRect); + ces.Add(dbPointCe); + } + });// 30万图元±3秒.cad2021 + + // 测试只加入四叉树的时间 + Tools.TestTimes(1, "插入四叉树时间:", () => { + for (int i = 0; i < ces.Count; i++) + _quadTreeRoot.Insert(ces[i]); + });// 30万图元±0.7秒.cad2021 + + tr.Editor?.WriteMessage($"\n加入图元数量:{maximumItems}"); + } + + /// + /// 创建随机圆形 + /// + /// 创建数量 + /// 数据库边界 + static IEnumerable GenerateRandomCircle(int createNumber, Rect dbExt) + { + var x1 = (int)dbExt.X; + var x2 = (int)(dbExt.X + dbExt.Width); + var y1 = (int)dbExt.Y; + var y2 = (int)(dbExt.Y + dbExt.Height); + + var rand = RandomEx.GetRandom(); + for (int i = 0; i < createNumber; i++) + { + var x = rand.Next(x1, x2) + rand.NextDouble(); + var y = rand.Next(y1, y2) + rand.NextDouble(); + yield return CircleEx.CreateCircle(new Point3d(x, y, 0), rand.Next(1, 100)); // 起点,终点 + } + } + + /* 啊惊: 有点懒不想改了*/ +#if true2 + + // 选择加入到四叉树 + [CommandMethod(nameof(CmdTest_QuadTree21))] + public void CmdTest_QuadTree21() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var db = doc.Database; + var ed = doc.Editor; + ed.WriteMessage("\n选择单个图元加入已有的四叉树"); + + var ss = ed.Ssget(); + if (ss.Count == 0) + return; + + AddQuadTreeRoot(db, ed, ss); + } + + // 自动加入全图到四叉树 + [CommandMethod(nameof(CmdTest_QuadTree20))] + public void CmdTest_QuadTree20() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var db = doc.Database; + var ed = doc.Editor; + ed.WriteMessage("\n自动加入全图到四叉树"); + + List ss = []; + int entnum = 0; + var time1 = Timer.RunTime(() => { + db.Action(tr => { + db.TraverseBlockTable(tr, btRec => { + if (!btRec.IsLayout)// 布局跳过 + return false; + + foreach (var item in btRec) + { + // var ent = item.ToEntity(tr); + ss.Add(item); + ++entnum;// 图元数量:100000, 遍历全图时间:0.216秒 CmdTest_QuadTree2 + } + return false; + }); + }); + }); + ed.WriteMessage($"\n图元数量:{entnum}, 遍历全图时间:{time1 / 1000.0}秒"); + + // 清空原有的 + _quadTreeRoot = null; + AddQuadTreeRoot(db, ed, ss); + } + + void AddQuadTreeRoot(Database db, Editor ed, List ss) + { + if (_quadTreeRoot is null) + { + ed.WriteMessage("\n四叉树是空的,重新初始化"); + + Rect dbExt; + // 使用数据库边界来进行 + var dbExtent = db.GetValidExtents3d(); + if (dbExtent == null) + { + // throw new ArgumentException("画一个矩形"); + + // 测试时候画个矩形,在矩形内画随机坐标的圆形 + dbExt = new Rect(0, 0, 32525, 32525); + } + else + { + dbExt = new Rect(dbExtent.Value.MinPoint.Point2d(), dbExtent.Value.MaxPoint.Point2d()); + } + _quadTreeRoot = new(dbExt); + } + + /* 测试: + * 为了测试删除内容释放了分支,再重复加入是否报错 + * 先创建 CmdTest_QuadTree1 + * 再减去 CmdTest_QuadTree0 + * 然后原有黑色边界,再生成边界 CmdTest_Create00,对比删除效果. + * 然后加入 CmdTest_QuadTree2 + * 然后原有黑色边界,再生成边界 CmdTest_Create00,对比删除效果. + */ + + List ces = new(); + db.Action(tr => { + ss.ForEach(entId => { + var ent = entId.ToEntity(tr); + if (ent is null) + return; + var edge = new EdgeEntity(ent); + // 四叉树数据 + var ce = new CadEntity(entId, edge.Edge) + { + Color = Utility.RandomColor + }; + ces.Add(ce); + + edge.Dispose(); + }); + }); + + var time2 = Timer.RunTime(() => { + _quadTreeRoot.Insert(ces); + }); + ed.WriteMessage($"\n图元数量:{ces.Count}, 加入四叉树时间:{time2 / 1000.0}秒"); + } +#endif + + #endregion + + /* 啊惊: 有点懒不想改了*/ +#if true2 + + #region 节点边界显示 + // 四叉树减去节点 + [CommandMethod(nameof(CmdTest_QuadTree0))] + public void CmdTest_QuadTree0() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + // var db = doc.Database; + var ed = doc.Editor; + ed.WriteMessage("\n四叉树减区"); + + if (_quadTreeRoot is null) + { + ed.WriteMessage("\n四叉树是空的"); + return; + } + var rect = GetCorner(ed); + if (rect is null) + return; + _quadTreeRoot.Remove(rect); + } + + // 创建节点边界 + [CommandMethod(nameof(CmdTest_CreateNodesRect))] + public void CmdTest_CreateNodesRect() + { + var dm = Acap.DocumentManager; + var doc = dm.MdiActiveDocument; + var db = doc.Database; + var ed = doc.Editor; + ed.WriteMessage("\n创建边界"); + + if (_quadTreeRoot is null) + { + ed.WriteMessage("\n四叉树是空的"); + return; + } + + // 此处发现了一个事务处理的bug,提交数量过多的时候,会导致 ctrl+z 无法回滚, + // 需要把事务放在循环体内部 + // 报错: 0x6B00500A (msvcr80.dll)处(位于 acad.exe 中)引发的异常: 0xC0000005: 写入位置 0xFFE00000 时发生访问冲突。 + // 画出所有的四叉树节点边界,因为事务放在外面引起 + List nodeRects = []; + _quadTreeRoot.ForEach(node => { + nodeRects.Add(node); + return false; + }); + List rectIds = []; + foreach (var item in nodeRects)// Count = 97341 当数量接近这个量级 + { + db.Action(tr => { + var pts = item.ToPoints(); + var rec = EntityAdd.AddPolyLineToEntity(pts.ToPoint2d()); + rec.ColorIndex = 250; + rectIds.Add(tr.AddEntityToMsPs(db, rec)); + }); + } + db.Action(tr => { + db.CoverGroup(tr, rectIds); + }); + + // 获取四叉树深度 + int dep = 0; + _quadTreeRoot.ForEach(node => { + dep = dep > node.Depth ? dep : node.Depth; + return false; + }); + ed.WriteMessage($"\n四叉树深度是: {dep}"); + } + #endregion + +#endif + + #region 四叉树查询节点 + // 选择范围改图元颜色 + [CommandMethod(nameof(CmdTest_QuadTree3))] + public void CmdTest_QuadTree3() + { + Ssget(QuadTreeSelectMode.IntersectsWith); + } + + [CommandMethod(nameof(CmdTest_QuadTree4))] + public void CmdTest_QuadTree4() + { + Ssget(QuadTreeSelectMode.Contains); + } + + /// + /// 改颜色 + /// + /// + void Ssget(QuadTreeSelectMode mode) + { + if (_quadTreeRoot is null) + return; + + using DBTrans tr = new(); + if (tr.Editor is null) + return; + var rect = GetCorner(tr.Editor); + if (rect is null) + return; + + tr.Editor.WriteMessage("选择模式:" + mode); + + // 仿选择集 + var ces = _quadTreeRoot.Query(rect, mode); + ces.ForEach(item => { + var ent = tr.GetObject(item.ObjectId, OpenMode.ForWrite); + ent!.Color = Color.FromColor(item.Color); + ent.DowngradeOpen(); + ent.Dispose(); + }); + } + + /// + /// 交互获取 + /// + /// + /// + public static Rect? GetCorner(Editor ed) + { + var optionsA = new PromptPointOptions($"{Environment.NewLine}起点位置:"); + var pprA = ed.GetPoint(optionsA); + if (pprA.Status != PromptStatus.OK) + return null; + var optionsB = new PromptCornerOptions(Environment.NewLine + "输入矩形角点2:", pprA.Value) + { + UseDashedLine = true,// 使用虚线 + AllowNone = true,// 回车 + }; + var pprB = ed.GetCorner(optionsB); + if (pprB.Status != PromptStatus.OK) + return null!; + + return new Rect(new Point2d(pprA.Value.X, pprA.Value.Y), + new Point2d(pprB.Value.X, pprB.Value.Y), + true); + } + #endregion +} + +// public partial class TestQuadTree +// { +// public void Cmd_tt6() +// { +// using DBTrans tr = new(); +// var ed = tr.Editor; +// // 创建四叉树,默认参数无所谓 +// var TreeRoot = new QuadTree(new Rect(0, 0, 32525, 32525)); + +// var fil = OpFilter.Build(e => e.Dxf(0) == "LINE"); +// var psr = ed.SSGet("\n 选择需要连接的直线", fil); +// if (psr.Status != PromptStatus.OK) return; +// var LineEnts = new List(psr.Value.GetEntities(OpenMode.ForWrite)!); +// // 将实体插入到四岔树 +// foreach (var line in LineEnts) +// { +// var edge = line.GeometricExtents; +// var entRect = new Rect(edge.MinPoint.X, edge.MinPoint.Y, edge.MaxPoint.X, edge.MaxPoint.Y); +// var ce = new CadEntity(line.Id, entRect) +// { +// // 四叉树数据 +// Angle = line.Angle +// }; +// TreeRoot.Insert(ce); +// } + +// var ppo = new PromptPointOptions(Environment.NewLine + "\n指定标注点:<空格退出>") +// { +// AllowArbitraryInput = true,// 任意输入 +// AllowNone = true // 允许回车 +// }; +// var ppr = ed.GetPoint(ppo);// 用户点选 +// if (ppr.Status != PromptStatus.OK) +// return; +// var rect = new Rect(ppr.Value.Point2d(), 100, 100); +// tr.CurrentSpace.AddEntity(rect.ToPolyLine());// 显示选择靶标范围 + +// var nent = TreeRoot.FindNearEntity(rect);// 查询最近实体,按逆时针 +// var ent = tr.GetObject(nent.ObjectId, OpenMode.ForWrite);// 打开实体 +// ent.ColorIndex = Utility.GetRandom().Next(1, 256);// 1~256随机色 +// ent.DowngradeOpen();// 实体降级 +// ent.Dispose(); + +// var res = TreeRoot.Query(rect, QuadTreeSelectMode.IntersectsWith);// 查询选择靶标范围相碰的ID +// res.ForEach(item => { +// if (item.Angle == 0 || item.Angle == Math.PI) // 过滤直线角度为0或180的直线 +// { +// var ent = tr.GetObject(item.ObjectId, OpenMode.ForWrite); +// ent.ColorIndex = Utility.GetRandom().Next(1, 7); +// ent.DowngradeOpen(); +// ent.Dispose(); +// } +// }); +// } +// } \ No newline at end of file diff --git a/tests/TestShared/TestSelectfilter.cs b/tests/TestShared/TestSelectfilter.cs new file mode 100644 index 0000000000000000000000000000000000000000..cab6c92c10c3b97915bf39ac743edb9e938e1031 --- /dev/null +++ b/tests/TestShared/TestSelectfilter.cs @@ -0,0 +1,58 @@ +namespace Test; + +public class Testselectfilter +{ + [CommandMethod(nameof(Test_Filter))] + public void Test_Filter() + { + var p = new Point3d(10, 10, 0); + var f = OpFilter.Build( + e => !(e.Dxf(0) == "line" & e.Dxf(8) == "0") + | e.Dxf(0) != "circle" & e.Dxf(8) == "2" & e.Dxf(10) >= p); + + + var f2 = OpFilter.Build( + e => e.Or( + !e.And(e.Dxf(0) == "line", e.Dxf(8) == "0"), + e.And(e.Dxf(0) != "circle", e.Dxf(8) == "2", + e.Dxf(10) <= new Point3d(10, 10, 0)))); + + SelectionFilter f3 = f; + SelectionFilter f4 = f2; + + Env.Editor.WriteMessage(""); + } + + [CommandMethod(nameof(Test_Selectanpoint))] + public void Test_Selectanpoint() + { + var sel2 = Env.Editor.SelectAtPoint(new Point3d(0, 0, 0)); + Env.Editor.WriteMessage(""); + } +} + +public class TestSelectObjectType +{ + [CommandMethod(nameof(Test_Select_type))] + public void Test_Select_type() + { + var sel = Env.Editor.SSGet(); + if (sel.Status != PromptStatus.OK) return; + var ids = sel.Value.GetObjectIds(); + foreach (var item in ids) + { + item.Print(); + } + + var dxfName = RXObject.GetClass(typeof(Dimension)).DxfName; + dxfName.Print(); + var idss = sel.Value.GetObjectIds(); + foreach (var item in idss) + { + item.Print(); + item.ObjectClass.DxfName.Print(); + } + + } + +} \ No newline at end of file diff --git a/tests/TestShared/TestShared.projitems b/tests/TestShared/TestShared.projitems new file mode 100644 index 0000000000000000000000000000000000000000..4ca3fc150128a98ad48d29e3d91353bdd59ea0a7 --- /dev/null +++ b/tests/TestShared/TestShared.projitems @@ -0,0 +1,52 @@ + + + + $(MSBuildAllProjects);$(MSBuildThisFileFullPath) + true + ced63d2d-0af6-4831-806d-5e8e9b0d0a07 + + + TestShared + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/TestShared/TestShared.shproj b/tests/TestShared/TestShared.shproj new file mode 100644 index 0000000000000000000000000000000000000000..31ea779a25d8b662fbe52cf640dbcceff700c326 --- /dev/null +++ b/tests/TestShared/TestShared.shproj @@ -0,0 +1,13 @@ + + + + ced63d2d-0af6-4831-806d-5e8e9b0d0a07 + 14.0 + + + + + + + + diff --git a/tests/TestShared/TestSingleKeyWordHook.cs b/tests/TestShared/TestSingleKeyWordHook.cs new file mode 100644 index 0000000000000000000000000000000000000000..73fe216cf7e19ba408589117d8f99a58290527bb --- /dev/null +++ b/tests/TestShared/TestSingleKeyWordHook.cs @@ -0,0 +1,48 @@ +namespace TestShared; +public static class TestSingleKeyWordHook +{ + [CommandMethod(nameof(TestSingleKeyWordHookDemo))] + public static void TestSingleKeyWordHookDemo() + { + var line1 = new Line(Point3d.Origin, new Point3d(100, 100, 0)); + line1.SetDatabaseDefaults(); + using var j1 = new JigEx((mpw, _) => { + line1.Move(line1.StartPoint, mpw); + }); + j1.DatabaseEntityDraw(wd => wd.Geometry.Draw(line1)); + var jppo = j1.SetOptions("\n选择位置或"); + jppo.Keywords.Add("A", "A", "旋转90°(A)"); + jppo.Keywords.Add("D", "D", "旋转45°(D)"); + // 创建关键字钩子 + using var skwh = new SingleKeyWordHook(); + // 添加关键字 + skwh.AddKeys(jppo.Keywords); + while (true) + { + // 循环开始时复位 + skwh.Reset(); + var r1 = Env.Editor.Drag(j1); + if (skwh.IsResponsed || r1.Status == PromptStatus.Keyword) + { + // 此钩子完整保留了原关键字的鼠标点击功能,所以要同时支持两种情况,也方便在已经写好的关键字功能上扩展 + // 如果响应了关键字 + switch (skwh.IsResponsed ? skwh.StringResult : r1.StringResult.ToUpper()) + { + case "A": + line1.Rotation(line1.StartPoint, Math.PI * 0.5, Vector3d.ZAxis); + break; + case "D": + line1.Rotation(line1.StartPoint, Math.PI * 0.25, Vector3d.ZAxis); + break; + } + continue; + } + if (r1.Status == PromptStatus.OK) + { + using var tr = new DBTrans(); + tr.CurrentSpace.AddEntity(line1); + } + return; + } + } +} diff --git a/tests/TestShared/TestText.cs b/tests/TestShared/TestText.cs new file mode 100644 index 0000000000000000000000000000000000000000..b25dab69dab226d5dbcbc7708afb9c7bb8240209 --- /dev/null +++ b/tests/TestShared/TestText.cs @@ -0,0 +1,49 @@ + +namespace TestShared; + +public class TestText +{ + + [CommandMethod(nameof(TestDBText))] + public void TestDBText() + { + using var tr = new DBTrans(); + tr.CurrentSpace.AddEntity(DBTextEx.CreateDBText(new(-1, -1, 0), "123", 2.5, action:t=> t.ColorIndex = 1)); + + tr.CurrentSpace.AddEntity(DBTextEx.CreateDBText(new(-1, -1, 0), "123", 2.5, action: t => { + t.Justify = AttachmentPoint.BaseCenter; + t.AlignmentPoint = new(1, 1, 0); + t.ColorIndex = 2; + })); + } + + [CommandMethod(nameof(TestBackDBText))] + public void TestBackDBText() + { + using var tr = new DBTrans(@"C:\Users\vic\Desktop\test.dwg"); + tr.CurrentSpace.AddEntity(DBTextEx.CreateDBText(new(-1, -1, 0), "123", 2.5, action: t => t.ColorIndex = 1)); + + tr.CurrentSpace.AddEntity(DBTextEx.CreateDBText(new(-1, -1, 0), "123", 2.5, action: t => + { + t.Justify = AttachmentPoint.BaseCenter; + t.AlignmentPoint = new(1, 1, 0); + t.ColorIndex = 2; + })); + tr.Database.SaveDwgFile(); + } + + + + [CommandMethod(nameof(TestMText))] + public void TestMText() + { + using var tr = new DBTrans(); + tr.CurrentSpace.AddEntity(MTextEx.CreateMText(new(5, 5, 0), "123", 2.5, action: t => t.ColorIndex = 1)); + + tr.CurrentSpace.AddEntity(MTextEx.CreateMText(new(5, 5, 0), "123", 2.5, action: t => { + t.Attachment = AttachmentPoint.TopCenter; + t.ColorIndex = 2; + })); + } + +} diff --git a/tests/TestShared/TestXRecord.cs b/tests/TestShared/TestXRecord.cs new file mode 100644 index 0000000000000000000000000000000000000000..1fcb85c819ed51ebc0a1629dddd4447f88ed5b5a --- /dev/null +++ b/tests/TestShared/TestXRecord.cs @@ -0,0 +1,252 @@ +//#define ExtendedDataBinaryChunk +#define XTextString + +#if NewtonsoftJson +using System.Diagnostics; +using Newtonsoft.Json; +using static IFoxCAD.Cad.WindowsAPI; + +namespace Test_XRecord; + +public class TestCmd_XRecord +{ + [CommandMethod(nameof(TestSerializeSetXRecord))] + public void TestSerializeSetXRecord() + { + var prs = Env.Editor.SSGet("\n 序列化,选择多段线:"); + if (prs.Status != PromptStatus.OK) + return; + + using var tr = new DBTrans(); + var pls = prs.Value.GetEntities(); + Tools.TestTimes(1, nameof(TestSerializeSetXRecord), () => { + foreach (var pl in pls) + { + if (pl == null) + continue; + + TestABCList datas = new(); + for (int i = 0; i < 1000; i++) + { + datas.Add(new() + { + AAA = i, + BBB = i.ToString(), + CCCC = i * 0.5, + DDDD = i % 2 != 0, + EEEE = new(0, i, 0) + }); + } + + using (pl.ForWrite()) + pl.SerializeToXRecord(datas); + } + }); + } + + [CommandMethod(nameof(TestDeserializeGetXRecord))] + public void TestDeserializeGetXRecord() + { + var prs = Env.Editor.GetEntity("\n 反序列化,选择多段线:"); + if (prs.Status != PromptStatus.OK) + return; + + using var tr = new DBTrans(); + + TestABCList? datas = null; + Tools.TestTimes(1, nameof(TestDeserializeGetXRecord), () => { + var pl = prs.ObjectId.GetObject(); + if (pl == null) + return; +#if XTextString + datas = pl.DeserializeToXRecord(); +#endif + +#if ExtendedDataBinaryChunk + // 这里有数据容量限制,而且很小 + var xd = pl.GetXDictionary(); + if (xd == null) + return; + if (xd.XData == null) + return; + + XDataList data = xd.XData; + var sb = new StringBuilder(); + data.ForEach(a => { + if (a.TypeCode == (short)DxfCode.ExtendedDataBinaryChunk) + if (a.Value is byte[] bytes) + sb.Append(Encoding.UTF8.GetString(bytes)); + }); + datas = JsonConvert.DeserializeObject(sb.ToString(), XRecordHelper._sset); +#endif + }); + if (datas == null) + { + Env.Printl("没有反序列的东西"); + return; + } + + var sb = new StringBuilder(); + for (int i = 0; i < datas.Count; i++) + sb.Append(datas[i]); + Env.Printl(sb); + } +} + +public static class XRecordHelper +{ + #region 序列化方式 + internal static JsonSerializerSettings _sset = new() + { + Formatting = Formatting.Indented, + TypeNameHandling = TypeNameHandling.Auto + }; + + /// + /// 设定信息 + /// + /// 储存对象 + /// 储存数据 + public static void SerializeToXRecord(this DBObject dbo, T data) + { + var xd = dbo.GetXDictionary(); + if (xd == null) + return; + + // XRecordDataList 不能超过2G大小 + const int GigaByte2 = 2147483647; + // 单条只能 16KiBit => 2048 * 16 == 32768 + const int KiBit16 = (2048 * 16) - 1; + + // 就算这个写法支持,计算机也不一定有那么多内存,所以遇到此情况最好换成内存拷贝 + var json = JsonConvert.SerializeObject(data, _sset);// 此时内存占用了2G + var buffer = Encoding.UTF8.GetBytes(json); // 此时内存又占用了2G.. + + BytesTask(buffer, GigaByte2, bts => { +#if XTextString + XRecordDataList datas = new(); + BytesTask(buffer, KiBit16, bts => { + datas.Add(DxfCode.XTextString, Encoding.UTF8.GetString(bts)); // 这对的 + // datas.Add(DxfCode.XTextString, bts);//这样 bts 变成 "System.Byte[]" + }); + xd.SetXRecord(typeof(T).FullName, datas); +#endif + +#if ExtendedDataBinaryChunk + // 这里有数据容量限制,而且很小 + var appname = typeof(T).FullName; + DBTrans.Top.RegAppTable.Add(appname); + + XDataList datas = new(); + datas.Add(DxfCode.ExtendedDataRegAppName, appname); + BytesTask(buffer, KiBit16, bts => { + datas.Add(DxfCode.ExtendedDataBinaryChunk, bts); + }); + using (xd.ForWrite()) + xd.XData = datas; // Autodesk.AutoCAD.Runtime.Exception:“eXdataSizeExceeded” +#endif + }); + } + + [DebuggerHidden] + static void BytesTask(byte[] buffer, int max, Action action) + { + int index = 0; + while (index < buffer.Length) + { + // 每次 max,然后末尾剩余就单独 + byte[] bts; + if (buffer.Length - index > max) + bts = new byte[max]; + else + bts = new byte[buffer.Length - index]; + + for (int i = 0; i < bts.Length; i++) + bts[i] = buffer[index++]; + + action.Invoke(bts); + } + } + + /// + /// 提取信息 + /// + /// 类型 + /// 储存对象 + /// 提取数据生成的对象 + public static T? DeserializeToXRecord(this DBObject dbo) + { + var xd = dbo.GetXDictionary(); + if (xd == null) + return default; + + var datas = xd.GetXRecord(typeof(T).FullName); + if (datas == null) + return default; + + var sb = new StringBuilder(); + for (int i = 0; i < datas.Count; i++) + sb.Append(datas[i].Value); + + return JsonConvert.DeserializeObject(sb.ToString(), _sset); + } + #endregion + + + /// + /// 设置描述(容量无限) + /// + /// + /// + /// + public static void SetSummaryInfoAtt(this Database db, string key, object value) + { + var info = new DatabaseSummaryInfoBuilder(db.SummaryInfo); + if (!info.CustomPropertyTable.Contains(key)) + info.CustomPropertyTable.Add(key, value); + else + info.CustomPropertyTable[key] = value; + db.SummaryInfo = info.ToDatabaseSummaryInfo(); + } + /// + /// 获取描述 + /// + /// + /// + /// + public static object? GetSummaryInfoAtt(this Database db, string key) + { + var info = new DatabaseSummaryInfoBuilder(db.SummaryInfo); + if (info.CustomPropertyTable.Contains(key)) + return info.CustomPropertyTable[key]; + return null; + } + +} + +public class TestABCList : List +{ +} + +[ComVisible(true)] +[Serializable] +[DebuggerDisplay("{DebuggerDisplay,nq}")] +[DebuggerTypeProxy(typeof(TestABC))] +[StructLayout(LayoutKind.Sequential, Pack = 4)] +public class TestABC +{ + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string DebuggerDisplay => ToString(); + + public int AAA; + public string? BBB; + public double CCCC; + public bool DDDD; + public Point3D EEEE; + + public override string ToString() + { + return JsonConvert.SerializeObject(this, XRecordHelper._sset); + } +} +#endif \ No newline at end of file diff --git a/tests/TestShared/TestXdata.cs b/tests/TestShared/TestXdata.cs new file mode 100644 index 0000000000000000000000000000000000000000..a0c10afdeafa950b4893b6ef0445bfb9baa7fb32 --- /dev/null +++ b/tests/TestShared/TestXdata.cs @@ -0,0 +1,132 @@ +namespace Test; + +public class TestXdata +{ + // 测试扩展数据 + private const string Appname = "myapp2"; + + // 增 + [CommandMethod(nameof(Test_AddXdata))] + public void Test_AddXdata() + { + using DBTrans tr = new(); + + tr.RegAppTable.Add("myapp1"); + tr.RegAppTable.Add(Appname); // add函数会默认的在存在这个名字的时候返回这个名字的regapp的id,不存在就新建 + tr.RegAppTable.Add("myapp3"); + tr.RegAppTable.Add("myapp4"); + + var line = new Line(new Point3d(0, 0, 0), new Point3d(1, 1, 0)) + { + XData = new XDataList() + { + { DxfCode.ExtendedDataRegAppName, "myapp1" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "xxxxxxx" }, + {1070, 12 }, + { DxfCode.ExtendedDataRegAppName, Appname }, // 可以用dxfcode和int表示组码,移除中间的测试 + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + {1070, 12 }, + { DxfCode.ExtendedDataRegAppName, "myapp3" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "aaaaaaaaa" }, + {1070, 12 }, + { DxfCode.ExtendedDataRegAppName, "myapp4" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "bbbbbbbbb" }, + {1070, 12 } + } + }; + + var line1 = new Line(new(0, 0, 0), new(2, 0, 0)); + line1.XData = new XDataList() + { + { DxfCode.ExtendedDataRegAppName, "myapp1" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "xxxxxxx" }, + { 1070, 12 }, + { DxfCode.ExtendedDataRegAppName, Appname }, // 可以用dxfcode和int表示组码,移除中间的测试 + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { DxfCode.ExtendedDataAsciiString, "要移除的我" }, + { 1070, 12 }, + { DxfCode.ExtendedDataRegAppName, "myapp3" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "aaaaaaaaa" }, + { DxfCode.ExtendedDataAsciiString, "ccccccccc" }, + { 1070, 12 }, + { DxfCode.ExtendedDataRegAppName, "myapp4" }, // 可以用dxfcode和int表示组码 + { DxfCode.ExtendedDataAsciiString, "bbbbbbbbb" }, + { 1070, 12 } + }; + + tr.CurrentSpace.AddEntity(line,line1); + } + // 删 + [CommandMethod(nameof(Test_RemoveXdata))] + public void Test_RemoveXdata() + { + var res = Env.Editor.GetEntity("\n select the entity:"); + if (res.Status != PromptStatus.OK) return; + + using DBTrans tr = new(); + var ent = tr.GetObject(res.ObjectId); + if (ent == null || ent.XData == null) + return; + + Env.Printl("\n移除前:" + ent.XData); + + ent.RemoveXData(Appname, DxfCode.ExtendedDataAsciiString); + Env.Printl("\n移除成员后:" + ent.XData); + + ent.RemoveXData(Appname); + Env.Printl("\n移除appName后:" + ent.XData); + } + // 查 + [CommandMethod(nameof(Test_GetXdata))] + public void Test_GetXdata() + { + using DBTrans tr = new(); + tr.RegAppTable.ForEach(id => + id.GetObject()?.Name.Print()); + tr.RegAppTable.GetRecords().ForEach(rec => rec.Name.Print()); + tr.RegAppTable.GetRecordNames().ForEach(name => name.Print()); + tr.RegAppTable.ForEach(reg => reg.Name.Print(), checkIdOk: false); + + // 查询appName里面是否含有某个 + + var res = Env.Editor.GetEntity("\n select the entity:"); + if (res.Status != PromptStatus.OK) return; + + var ent = tr.GetObject(res.ObjectId); + if (ent == null || ent.XData == null) + return; + + XDataList data = ent.XData; + if (data.Contains(Appname)) + Env.Printl("含有appName:" + Appname); + else + Env.Printl("不含有appName:" + Appname); + + const string str = "要移除的我"; + if (data.Contains(Appname, str)) + Env.Printl("含有内容:" + str); + else + Env.Printl("不含有内容:" + str); + } + // 改 + [CommandMethod(nameof(Test_ChangeXdata))] + public void Test_ChangeXdata() + { + var res = Env.Editor.GetEntity("\n select the entity:"); + if (res.Status != PromptStatus.OK) return; + + using DBTrans tr = new(); + var data = tr.GetObject(res.ObjectId)!; + data.ChangeXData(Appname, DxfCode.ExtendedDataAsciiString, "change"); + + if (data.XData == null) + return; + Env.Printl(data.XData.ToString()); + } + +} \ No newline at end of file diff --git a/tests/TestShared/TestXrefEx.cs b/tests/TestShared/TestXrefEx.cs new file mode 100644 index 0000000000000000000000000000000000000000..7fa7f3e8b7ae0542f611061f082e48ac44c44130 --- /dev/null +++ b/tests/TestShared/TestXrefEx.cs @@ -0,0 +1,24 @@ +namespace Test; + +public class TestCmd_BindXrefs +{ + //后台绑定 + [CommandMethod(nameof(Test_Bind1))] + public static void Test_Bind1() + { + string fileName = @"D:\Test.dwg"; + using var tr = new DBTrans(fileName, + fileOpenMode: FileOpenMode.OpenForReadAndAllShare/*后台绑定特别注意*/); + tr.XrefFactory(XrefModes.Bind); + tr.Database.SaveDwgFile(); + } + + //前台绑定 + [CommandMethod(nameof(Test_Bind2))] + public static void Test_Bind2() + { + using var tr = new DBTrans(); + tr.XrefFactory(XrefModes.Bind); + tr.Database.SaveDwgFile(); + } +} \ No newline at end of file diff --git a/Test/Timer.cs b/tests/TestShared/Timer.cs similarity index 100% rename from Test/Timer.cs rename to tests/TestShared/Timer.cs diff --git a/Test/Tools.cs b/tests/TestShared/Tools.cs similarity index 100% rename from Test/Tools.cs rename to tests/TestShared/Tools.cs diff --git a/tests/TestShared/readme.md b/tests/TestShared/readme.md new file mode 100644 index 0000000000000000000000000000000000000000..81b106fd2b210f7fc23c9a0297d73b54fc171b46 --- /dev/null +++ b/tests/TestShared/readme.md @@ -0,0 +1,20 @@ +# 测试项目文件结构 +- 图元类 - TestEntity + + TestAddEntity.cs + + TestRemoveEntity.cs + + .... +- 事务类 - TestDBtrans +- 符号表类 - TestSymTable + + TestLayer.cs + + TestTextStyle.cs + + ... +- 选择集类 +- 扩展数据类 +- editor类 +- 数据库对象类 +- env类 +- jig类 +- 数据交互类 +- lisp类 +- 算法类 +- \ No newline at end of file diff --git a/tests/TestZcad2025/GlobalUsings.cs b/tests/TestZcad2025/GlobalUsings.cs new file mode 100644 index 0000000000000000000000000000000000000000..2c24797f6c0cde2a403ff8c6672248a0cb46058e --- /dev/null +++ b/tests/TestZcad2025/GlobalUsings.cs @@ -0,0 +1,49 @@ +/// 系统引用 +global using System; +global using System.Collections; +global using System.Collections.Generic; +global using System.IO; +global using System.Linq; +global using System.Text; +global using System.Reflection; +global using System.Text.RegularExpressions; +global using Microsoft.Win32; +global using System.ComponentModel; +global using System.Runtime.InteropServices; +global using System.Collections.Specialized; +global using System.Threading; +global using System.Diagnostics; +global using Exception = System.Exception; +global using System.Runtime.CompilerServices; +global using Registry = Microsoft.Win32.Registry; +global using RegistryKey = Microsoft.Win32.RegistryKey; + +// cad 引用 +global using ZwSoft.ZwCAD.ApplicationServices; +global using ZwSoft.ZwCAD.EditorInput; +global using ZwSoft.ZwCAD.Colors; +global using ZwSoft.ZwCAD.DatabaseServices; +global using ZwSoft.ZwCAD.Geometry; +global using ZwSoft.ZwCAD.Runtime; +global using Acap = ZwSoft.ZwCAD.ApplicationServices.Application; +global using Acaop = ZwSoft.ZwCAD.ApplicationServices.Application; +global using AcException = ZwSoft.ZwCAD.Runtime.Exception; +global using ZwSoft.ZwCAD.DatabaseServices.Filters; +global using Acgi = ZwSoft.ZwCAD.GraphicsInterface; +// jig命名空间会引起Viewport/Polyline等等重义,最好逐个引入 using ZwSoft.ZwCAD.GraphicsInterface +global using ZwSoft.ZwCAD.GraphicsInterface; +global using WorldDraw = ZwSoft.ZwCAD.GraphicsInterface.WorldDraw; +global using Manager = ZwSoft.ZwCAD.GraphicsSystem.Manager; +global using Group = ZwSoft.ZwCAD.DatabaseServices.Group; +global using Viewport = ZwSoft.ZwCAD.DatabaseServices.Viewport; +global using Polyline = ZwSoft.ZwCAD.DatabaseServices.Polyline; +global using Cad_DwgFiler = ZwSoft.ZwCAD.DatabaseServices.DwgFiler; +global using Cad_DxfFiler = ZwSoft.ZwCAD.DatabaseServices.DxfFiler; +global using Cad_ErrorStatus = ZwSoft.ZwCAD.Runtime.ErrorStatus; + + +/// ifoxcad +global using IFoxCAD.Cad; +global using IFoxCAD.Basal; + +global using Test; \ No newline at end of file diff --git a/tests/TestZcad2025/TestZcad2025.csproj b/tests/TestZcad2025/TestZcad2025.csproj new file mode 100644 index 0000000000000000000000000000000000000000..89cf1ba77f1ba02466d1bbf49e7be9c975a259b0 --- /dev/null +++ b/tests/TestZcad2025/TestZcad2025.csproj @@ -0,0 +1,36 @@ + + + preview + enable + + NET48 + true + true + x64 + True + + + + $(Configuration);zcad + + + + + + + + + + + + + + + + + + + + + +