• macad.core解析exchange


    1.exchange

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using Macad.Core;
    5. namespace Macad.Core
    6. {
    7. // 交换器注册表
    8. public static class ExchangeRegistry
    9. {
    10. // 交换器字典
    11. static readonly Dictionary> _Exchangers = new Dictionary>();
    12. // 设置面板字典
    13. static readonly Dictionary _ExchangerSettingPanels = new Dictionary();
    14. // 枚举和创建区域
    15. // 枚举指定类型的所有交换器
    16. public static IEnumerable<T> EnumerateExchanger<T>() where T : IExchanger
    17. {
    18. if (_Exchangers.TryGetValue(typeof(T), out var list))
    19. return list.Cast();
    20. return new List();
    21. }
    22. // 查找指定类型的交换器
    23. public static T FindExchanger<T>(string extension) where T : class, IExchanger
    24. {
    25. if (!_Exchangers.TryGetValue(typeof(T), out var list))
    26. return null;
    27. var lowerExtension = extension.ToLower();
    28. return list.FirstOrDefault(exchanger => exchanger.Extensions.Contains(lowerExtension)) as T;
    29. }
    30. // 判断指定类型的交换器是否支持导出到剪贴板
    31. public static bool CanExportToClipboard<T>() where T : IExchanger
    32. {
    33. if (!_Exchangers.TryGetValue(typeof(T), out var list))
    34. return false;
    35. return list.Any(exchanger => exchanger.CanExportToClipboard());
    36. }
    37. // 判断指定类型的交换器是否支持从剪贴板导入
    38. public static bool CanImportFromClipboard<T>(Clipboard clipboard) where T : IExchanger
    39. {
    40. if (!_Exchangers.TryGetValue(typeof(T), out var list))
    41. return false;
    42. return list.Any(exchanger => exchanger.CanImportFromClipboard(clipboard));
    43. }
    44. // 注册区域
    45. // 添加交换器到字典
    46. static void _AddExchanger(IExchanger exchanger, Type interfaceType)
    47. {
    48. if (!_Exchangers.TryGetValue(interfaceType, out var list))
    49. {
    50. list = new List();
    51. _Exchangers.Add(interfaceType, list);
    52. }
    53. if (list.Exists(ex => ex.GetType() == exchanger.GetType()))
    54. {
    55. Messages.Warning($"Exchanger {exchanger.GetType().FullName} already registered for type {interfaceType.Name}");
    56. return;
    57. }
    58. list.Add(exchanger);
    59. }
    60. // 注册交换器
    61. public static void Register(IExchanger exchanger)
    62. {
    63. var interfaces = exchanger.GetType().GetInterfaces();
    64. foreach (var interfaceType in interfaces)
    65. {
    66. _AddExchanger(exchanger, interfaceType);
    67. }
    68. }
    69. // 注册设置面板
    70. public static void Register(IExchangerSettingsPanelCreator panelCreator)
    71. {
    72. if (_ExchangerSettingPanels.TryGetValue(panelCreator.ExchangerType, out var firstPanel))
    73. {
    74. Messages.Error($"Multiple setting panels registered for exchanger {panelCreator.ExchangerType.FullName}: {firstPanel.GetType().FullName} / {panelCreator.GetType().FullName}.");
    75. return;
    76. }
    77. _ExchangerSettingPanels.Add(panelCreator.ExchangerType, panelCreator);
    78. }
    79. // 查找交换器设置面板
    80. public static IExchangerSettingsPanelCreator FindExchangerSettingsPanel(IExchanger exchanger)
    81. {
    82. if (_ExchangerSettingPanels.TryGetValue(exchanger.GetType(), out var panelCreator))
    83. {
    84. return panelCreator;
    85. }
    86. return null;
    87. }
    88. // 设置区域
    89. // 保存设置
    90. public static void SaveSettings()
    91. {
    92. try
    93. {
    94. var settingsList = new Dictionary<string, IExchangerSettings>();
    95. var exchangers = _Exchangers.Values.SelectMany(list => list).Distinct();
    96. foreach (var exchanger in exchangers)
    97. {
    98. if (exchanger.Settings != null)
    99. settingsList.Add(exchanger.GetType().Name, exchanger.Settings);
    100. }
    101. CoreContext.Current.SaveLocalSettings("ExchangerSettings", settingsList);
    102. }
    103. catch (Exception)
    104. {
    105. return;
    106. }
    107. }
    108. // 加载设置
    109. public static void LoadSettings()
    110. {
    111. try
    112. {
    113. var settingsList = CoreContext.Current.LoadLocalSettingsstring, IExchangerSettings>>("ExchangerSettings");
    114. if (settingsList == null || settingsList.Count == 0)
    115. return;
    116. var exchangers = _Exchangers.Values.SelectMany(list => list).Distinct();
    117. foreach (var exchanger in exchangers)
    118. {
    119. if (settingsList.TryGetValue(exchanger.GetType().Name, out var settingObj))
    120. exchanger.Settings = settingObj;
    121. }
    122. }
    123. catch (Exception)
    124. {
    125. return;
    126. }
    127. }
    128. }
    129. }

    这段代码实现了一个交换器注册表,其中包含了注册、枚举、查找、设置保存和加载等功能:

    • 注册区域:包括注册交换器和注册设置面板。
    • 枚举和创建区域:包括枚举指定类型的所有交换器和查找指定类型的交换器。
    • 设置区域:包括保存设置和加载设置。

    2.

    1. using System;
    2. using System.Collections.Generic;
    3. using Macad.Common.Serialization;
    4. namespace Macad.Core
    5. {
    6. // 交换器设置接口
    7. [SerializeType]
    8. public interface IExchangerSettings
    9. {}
    10. //--------------------------------------------------------------------------------------------------
    11. // 交换器接口
    12. public interface IExchanger
    13. {
    14. string Description { get; } // 获取交换器描述
    15. string[] Extensions { get; } // 获取支持的文件扩展名
    16. IExchangerSettings Settings { get; set; } // 获取或设置交换器设置
    17. // 判断是否可以导出到剪贴板
    18. bool CanExportToClipboard();
    19. // 判断是否可以从剪贴板导入
    20. bool CanImportFromClipboard(Clipboard clipboard);
    21. }
    22. //--------------------------------------------------------------------------------------------------
    23. // 实体导出器接口
    24. public interface IBodyExporter : IExchanger
    25. {
    26. // 导出实体
    27. bool DoExport(string fileName, IEnumerable bodies);
    28. }
    29. //--------------------------------------------------------------------------------------------------
    30. // 实体导入器接口
    31. public interface IBodyImporter : IExchanger
    32. {
    33. // 导入实体
    34. bool DoImport(string fileName, out IEnumerable bodies);
    35. }
    36. //--------------------------------------------------------------------------------------------------
    37. // 草图导出器接口
    38. public interface ISketchExporter : IExchanger
    39. {
    40. // 导出草图到文件
    41. bool DoExport(string fileName, Shapes.Sketch sketch);
    42. // 导出草图到剪贴板
    43. bool DoExport(Clipboard clipboard, Shapes.Sketch sketch);
    44. }
    45. //--------------------------------------------------------------------------------------------------
    46. // 草图导入器接口
    47. public interface ISketchImporter : IExchanger
    48. {
    49. // 从文件导入草图
    50. bool DoImport(string fileName, out IDictionary<int, Occt.Pnt2d> points, out IDictionary<int, Shapes.SketchSegment> segments,
    51. out IEnumerable constraints);
    52. // 从剪贴板导入草图
    53. bool DoImport(Clipboard clipboard, out IDictionary<int, Occt.Pnt2d> points, out IDictionary<int, Shapes.SketchSegment> segments,
    54. out IEnumerable constraints);
    55. }
    56. //--------------------------------------------------------------------------------------------------
    57. // 绘图导出器接口
    58. public interface IDrawingExporter : IExchanger
    59. {
    60. // 导出绘图
    61. bool DoExport(string fileName, Drawing.Drawing drawing);
    62. }
    63. //--------------------------------------------------------------------------------------------------
    64. // 交换器设置面板创建器接口
    65. public interface IExchangerSettingsPanelCreator
    66. {
    67. Type ExchangerType { get; } // 获取交换器类型
    68. object CreatePanel<T>(IExchanger exchanger); // 创建交换器设置面板
    69. }
    70. //--------------------------------------------------------------------------------------------------
    71. }

    这段代码定义了一系列交换器接口,包括实体导入导出器、草图导入导出器、绘图导出器以及交换器设置面板创建器。每个接口都定义了相应的方法,用于实现具体的导入导出操作。

    3.framework

    1. using System;
    2. using Macad.Occt;
    3. namespace Macad.Core
    4. {
    5. // Bnd_Box 类型的扩展方法
    6. public static class BndBoxExtensions
    7. {
    8. // 获取边界框的中心点
    9. public static Pnt Center(this Bnd_Box box)
    10. {
    11. double xMin = 0, yMin = 0, zMin = 0, xMax = 0, yMax = 0, zMax = 0;
    12. box.Get(ref xMin, ref yMin, ref zMin, ref xMax, ref yMax, ref zMax );
    13. return new Pnt(
    14. xMin + (xMax - xMin) / 2,
    15. yMin + (yMax - yMin) / 2,
    16. zMin + (zMax - zMin) / 2 );
    17. }
    18. //--------------------------------------------------------------------------------------------------
    19. // 获取边界框的尺寸
    20. public static (double X, double Y, double Z) Extents(this Bnd_Box box)
    21. {
    22. double xMin = 0, yMin = 0, zMin = 0, xMax = 0, yMax = 0, zMax = 0;
    23. box.Get(ref xMin, ref yMin, ref zMin, ref xMax, ref yMax, ref zMax );
    24. return (Math.Abs(xMax - xMin), Math.Abs(yMax - yMin), Math.Abs(zMax - zMin));
    25. }
    26. //--------------------------------------------------------------------------------------------------
    27. // 获取边界框的最小和最大坐标值
    28. public static (double minX, double minY, double minZ, double maxX, double maxY, double maxZ) MinMax(this Bnd_Box box)
    29. {
    30. double xMin = 0, yMin = 0, zMin = 0, xMax = 0, yMax = 0, zMax = 0;
    31. box.Get(ref xMin, ref yMin, ref zMin, ref xMax, ref yMax, ref zMax );
    32. return (xMin, yMin, zMin, xMax, yMax, zMax);
    33. }
    34. //--------------------------------------------------------------------------------------------------
    35. }
    36. }

    这段代码定义了针对 Bnd_Box 类型的扩展方法。这些方法使得可以方便地获取边界框的中心点、尺寸以及最小和最大坐标值。

    4.

    1. using System;
    2. using Macad.Occt;
    3. namespace Macad.Core
    4. {
    5. // gp 类型的扩展方法
    6. public static class gpExtensions
    7. {
    8. #region Pnt
    9. // 将点坐标各维度取整
    10. public static Pnt Rounded(this Pnt pnt)
    11. {
    12. return new Pnt(pnt.X.Round(), pnt.Y.Round(), pnt.Z.Round());
    13. }
    14. //--------------------------------------------------------------------------------------------------
    15. // 交换两个点的值
    16. public static void Swap(this ref Pnt value, ref Pnt other)
    17. {
    18. Pnt temp = value;
    19. value = other;
    20. other = temp;
    21. }
    22. //--------------------------------------------------------------------------------------------------
    23. // 缩放点坐标
    24. public static Pnt Scaled(this Pnt pnt, double scale)
    25. {
    26. return new Pnt(pnt.X * scale, pnt.Y * scale, pnt.Z * scale);
    27. }
    28. //--------------------------------------------------------------------------------------------------
    29. #endregion
    30. #region Pnt2d
    31. // 将二维点坐标各维度取整
    32. public static Pnt2d Rounded(this Pnt2d pnt)
    33. {
    34. return new (pnt.X.Round(), pnt.Y.Round());
    35. }
    36. //--------------------------------------------------------------------------------------------------
    37. // 交换两个二维点的值
    38. public static void Swap(this ref Pnt2d value, ref Pnt2d other)
    39. {
    40. Pnt2d temp = value;
    41. value = other;
    42. other = temp;
    43. }
    44. //--------------------------------------------------------------------------------------------------
    45. // 两点之间进行线性插值
    46. public static Pnt2d Lerped(this Pnt2d value, Pnt2d other, double amount)
    47. {
    48. return new Pnt2d(value.X.Lerp(other.X, amount), value.Y.Lerp(other.Y, amount));
    49. }
    50. //--------------------------------------------------------------------------------------------------
    51. #endregion
    52. #region Vec2d
    53. // 两向量之间进行线性插值
    54. public static Vec2d Lerped(this Vec2d value, Vec2d other, double amount)
    55. {
    56. return new Vec2d(value.X.Lerp(other.X, amount), value.Y.Lerp(other.Y, amount));
    57. }
    58. //--------------------------------------------------------------------------------------------------
    59. #endregion
    60. #region Dir
    61. // 两个方向之间进行球形线性插值
    62. public static Dir Slerped(this Dir value, Dir other, double amount)
    63. {
    64. double dotProduct = value.Dot(other);
    65. // 确定两个向量之间的最短旋转方向
    66. if (dotProduct < 0)
    67. {
    68. other.Reverse();
    69. dotProduct = -dotProduct;
    70. }
    71. double angle = Math.Acos(dotProduct);
    72. if (Math.Abs(angle) < 0.000001f)
    73. {
    74. return value;
    75. }
    76. double invSinAngle = 1f / Math.Sin(angle);
    77. double factorA = Math.Sin((1f - amount) * angle) * invSinAngle;
    78. double factorB = Math.Sin(amount * angle) * invSinAngle;
    79. return new Dir(value.ToVec(factorA) + other.ToVec(factorB));
    80. }
    81. //--------------------------------------------------------------------------------------------------
    82. #endregion
    83. #region Pln
    84. // 获取平面的旋转四元数
    85. public static Quaternion Rotation(this Pln plane)
    86. {
    87. var mat = new Mat(
    88. plane.XAxis.Direction.Coord,
    89. plane.YAxis.Direction.Coord,
    90. plane.Axis.Direction.Coord);
    91. return new Quaternion(mat);
    92. }
    93. //--------------------------------------------------------------------------------------------------
    94. // 检查两个平面是否相等
    95. public static bool IsEqual(this Pln pln1, Pln pln2)
    96. {
    97. return pln1.Location.IsEqual(pln2.Location, Double.Epsilon)
    98. && pln1.Rotation().IsEqual(pln2.Rotation());
    99. }
    100. //--------------------------------------------------------------------------------------------------
    101. // 计算点在平面上的参数值
    102. public static Pnt2d Parameters(this Pln pln, Pnt pnt)
    103. {
    104. double u = 0, v = 0;
    105. ElSLib.Parameters(pln, pnt, ref u, ref v);
    106. return new Pnt2d(u, v);
    107. }
    108. //--------------------------------------------------------------------------------------------------
    109. // 计算平面上参数对应的点坐标
    110. public static Pnt Value(this Pln pln, Pnt2d uv)
    111. {
    112. return ElSLib.Value(uv.X, uv.Y, pln);
    113. }
    114. //--------------------------------------------------------------------------------------------------
    115. #endregion
    116. #region Quaternion
    117. // 将四元数转换为轴-角表示
    118. public static Ax3 ToAx3(this Quaternion rotation, Pnt location)
    119. {
    120. return new Ax3(location,
    121. rotation.Multiply(new Vec(0, 0, 1)).ToDir(),
    122. rotation.Multiply(new Vec(1, 0, 0)).ToDir());
    123. }
    124. //--------------------------------------------------------------------------------------------------
    125. // 将四元数转换为欧拉角表示
    126. public static (double yaw, double pitch, double roll) ToEuler(this Quaternion rotation)
    127. {
    128. double y = 0, p = 0, r = 0;
    129. rotation.GetEulerAngles(ref y, ref p, ref r);
    130. return (y, p, r);
    131. }
    132. //--------------------------------------------------------------------------------------------------
    133. #endregion
    134. #region Ax22d
    135. // 计算二维轴的方向
    136. public static int Sense(this Ax22d ax)
    137. {
    138. return ax.YAxis.Angle(ax.XAxis) > 0 ? 1 : -1;
    139. }
    140. //--------------------------------------------------------------------------------------------------
    141. #endregion
    142. }
    143. }

    这段代码定义了针对 PntPnt2dVec2dDirPlnQuaternionAx22d 类型的扩展方法,提供了各种便捷的数学计算和操作功能。

    5.

    1. using System;
    2. using System.Collections.Generic;
    3. using Macad.Occt;
    4. namespace Macad.Core
    5. {
    6. public static class ListExtensions
    7. {
    8. ///
    9. /// 检查 IEnumerable 中是否包含与给定的 TopoDS_Shape 相同的形状对象。
    10. ///
    11. public static bool ContainsSame<T>(this IEnumerable list, TopoDS_Shape shape) where T : TopoDS_Shape
    12. {
    13. if (shape == null)
    14. {
    15. // 如果给定的形状为空,检查集合中是否存在空形状对象
    16. foreach (var item in list)
    17. {
    18. if (item == null)
    19. return true;
    20. }
    21. return false;
    22. }
    23. else
    24. {
    25. // 否则,检查集合中是否存在与给定形状相同的形状对象
    26. foreach (var item in list)
    27. {
    28. if (shape.IsSame(item))
    29. return true;
    30. }
    31. return false;
    32. }
    33. }
    34. ///
    35. /// 检查 IEnumerable 中是否包含与给定的 TopoDS_Shape 相似(partner)的形状对象。
    36. ///
    37. public static bool ContainsPartner<T>(this IEnumerable list, TopoDS_Shape shape) where T : TopoDS_Shape
    38. {
    39. if (shape == null)
    40. {
    41. // 如果给定的形状为空,检查集合中是否存在空形状对象
    42. foreach (var item in list)
    43. {
    44. if (item == null)
    45. return true;
    46. }
    47. return false;
    48. }
    49. else
    50. {
    51. // 否则,检查集合中是否存在与给定形状相似(partner)的形状对象
    52. foreach (var item in list)
    53. {
    54. if (shape.IsPartner(item))
    55. return true;
    56. }
    57. return false;
    58. }
    59. }
    60. ///
    61. /// 返回 IList 中与给定的 TopoDS_Shape 相同的形状对象的索引。
    62. ///
    63. public static int IndexOfSame<T>(this IList list, TopoDS_Shape item) where T : TopoDS_Shape
    64. {
    65. int size = list.Count;
    66. if (item == null)
    67. {
    68. // 如果给定的形状为空,返回列表中第一个空形状对象的索引
    69. for (int i = 0; i < size; i++)
    70. if (list[i] == null)
    71. return i;
    72. return -1;
    73. }
    74. else
    75. {
    76. // 否则,返回列表中与给定形状相同的形状对象的索引
    77. for (int i = 0; i < size; i++)
    78. {
    79. if (item.IsSame(list[i]))
    80. return i;
    81. }
    82. return -1;
    83. }
    84. }
    85. }
    86. }

    这段代码定义了针对 IEnumerableIList 接口的扩展方法,用于处理 TopoDS_Shape 类型的对象。

    • ContainsSame(this IEnumerable list, TopoDS_Shape shape):检查 IEnumerable 中是否包含与给定的 TopoDS_Shape 相同的形状对象。

    • ContainsPartner(this IEnumerable list, TopoDS_Shape shape):检查 IEnumerable 中是否包含与给定的 TopoDS_Shape 相似(partner)的形状对象。

    • IndexOfSame(this IList list, TopoDS_Shape item):返回 IList 中与给定的 TopoDS_Shape 相同的形状对象的索引。

    这些方法允许在集合中查找相同或相似的形状对象,并提供了方便的方式来处理形状对象的列表。

    6.

    1. using Macad.Occt;
    2. namespace Macad.Core
    3. {
    4. public static class TopLocExtension
    5. {
    6. ///
    7. /// 将 TopLoc_Location 对象转换为 Ax3 对象。
    8. ///
    9. public static Ax3 ToAx3(this TopLoc_Location rotation)
    10. {
    11. // 获取变换矩阵
    12. var trsf = rotation.Transformation();
    13. // 获取旋转部分并将其转换为 Ax3 对象,使用平移部分的 Pnt 作为位置点
    14. return trsf.GetRotation().ToAx3(trsf.TranslationPart().ToPnt());
    15. }
    16. }
    17. }

    这个扩展方法允许将 TopLoc_Location 对象转换为 Ax3 对象,从而简化了代码中的操作。

    7.

    1. using System.Collections.Generic;
    2. using System.Diagnostics;
    3. using System.Linq;
    4. using Macad.Occt;
    5. namespace Macad.Core
    6. {
    7. public static class TopoDSShapeExtensions
    8. {
    9. ///
    10. /// 获取组合实体。
    11. ///
    12. public static List CompSolids(this TopoDS_Shape shape, bool distinct = true)
    13. {
    14. // 省略内容
    15. }
    16. //--------------------------------------------------------------------------------------------------
    17. ///
    18. /// 获取实体。
    19. ///
    20. public static List Solids(this TopoDS_Shape shape, bool distinct = true)
    21. {
    22. // 省略内容
    23. }
    24. //--------------------------------------------------------------------------------------------------
    25. ///
    26. /// 获取壳体。
    27. ///
    28. public static List Shells(this TopoDS_Shape shape, bool distinct = true)
    29. {
    30. // 省略内容
    31. }
    32. //--------------------------------------------------------------------------------------------------
    33. ///
    34. /// 获取面。
    35. ///
    36. public static List Faces(this TopoDS_Shape shape, bool distinct = true)
    37. {
    38. Debug.Assert(shape != null);
    39. // 省略内容
    40. }
    41. //--------------------------------------------------------------------------------------------------
    42. ///
    43. /// 获取线框。
    44. ///
    45. public static List Wires(this TopoDS_Shape shape, bool distinct = true)
    46. {
    47. // 省略内容
    48. }
    49. //--------------------------------------------------------------------------------------------------
    50. ///
    51. /// 获取边。
    52. ///
    53. public static List Edges(this TopoDS_Shape shape, bool distinct = true)
    54. {
    55. // 省略内容
    56. }
    57. //--------------------------------------------------------------------------------------------------
    58. ///
    59. /// 获取顶点。
    60. ///
    61. public static List Vertices(this TopoDS_Shape shape, bool distinct = true)
    62. {
    63. // 省略内容
    64. }
    65. //--------------------------------------------------------------------------------------------------
    66. ///
    67. /// 获取质心。
    68. ///
    69. public static Pnt CenterOfMass(this TopoDS_Shape shape)
    70. {
    71. // 省略内容
    72. }
    73. //--------------------------------------------------------------------------------------------------
    74. ///
    75. /// 获取面积。
    76. ///
    77. public static double Area(this TopoDS_Shape shape)
    78. {
    79. // 省略内容
    80. }
    81. //--------------------------------------------------------------------------------------------------
    82. ///
    83. /// 获取体积。
    84. ///
    85. public static double Volume(this TopoDS_Shape shape)
    86. {
    87. // 省略内容
    88. }
    89. //--------------------------------------------------------------------------------------------------
    90. ///
    91. /// 获取包围盒。
    92. ///
    93. public static Bnd_Box BoundingBox(this TopoDS_Shape shape)
    94. {
    95. // 省略内容
    96. }
    97. //--------------------------------------------------------------------------------------------------
    98. // 省略其他扩展方法
    99. }
    100. }

    这些扩展方法用于检索给定形状(TopoDS_Shape)中包含的不同类型的子形状,例如组合实体、实体、壳体、面、线框、边和顶点。此外,还提供了一些计算几何特性的方法,如质心、面积、体积和包围盒。

    8.

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Collections.ObjectModel;
    4. using System.ComponentModel;
    5. using System.Linq;
    6. using System.Runtime.CompilerServices;
    7. using Macad.Core.Topology;
    8. using Macad.Occt;
    9. using Macad.Occt.Helper;
    10. namespace Macad.Core
    11. {
    12. public sealed class MessageHandler : IDisposable
    13. {
    14. #region Properties
    15. ///
    16. /// 获取或设置消息项集合。
    17. ///
    18. public ObservableCollection MessageItems
    19. {
    20. get { return _MessageItems; }
    21. set
    22. {
    23. if (_MessageItems != value)
    24. {
    25. _MessageItems = value;
    26. RaiseStaticPropertyChanged();
    27. }
    28. }
    29. }
    30. //--------------------------------------------------------------------------------------------------
    31. ///
    32. /// 获取当前引用实体。
    33. ///
    34. public Entity CurrentReferenceEntity
    35. {
    36. get { return _ProcessingEntitiesStack.Count > 0 ? _ProcessingEntitiesStack.Peek() : null; }
    37. }
    38. //--------------------------------------------------------------------------------------------------
    39. #endregion
    40. #region Member
    41. ObservableCollection _MessageItems;
    42. ConditionalWeakTable> _EntityMessages;
    43. readonly Stack _ProcessingEntitiesStack = new Stack();
    44. MessageRouter _MessageRouter;
    45. [ThreadStatic]
    46. static readonly bool _IsMainThread = true;
    47. //--------------------------------------------------------------------------------------------------
    48. #endregion
    49. #region Initialization and Property handling
    50. ///
    51. /// 构造函数。
    52. ///
    53. public MessageHandler()
    54. {
    55. _MessageItems = new ObservableCollection();
    56. _EntityMessages = new ConditionalWeakTable>();
    57. _MessageRouter = new MessageRouter();
    58. _MessageRouter.MessageArrived += _MessageRouter_MessageArrived;
    59. _MessageRouter.TraceLevel = Message_Gravity.Warning;
    60. }
    61. //--------------------------------------------------------------------------------------------------
    62. ///
    63. /// 析构函数。
    64. ///
    65. ~MessageHandler()
    66. {
    67. Dispose(false);
    68. }
    69. //--------------------------------------------------------------------------------------------------
    70. ///
    71. /// 释放资源。
    72. ///
    73. public void Dispose()
    74. {
    75. Dispose(true);
    76. GC.SuppressFinalize(this);
    77. }
    78. //--------------------------------------------------------------------------------------------------
    79. void Dispose(bool disposing)
    80. {
    81. _MessageRouter?.Dispose();
    82. _MessageRouter = null;
    83. }
    84. //--------------------------------------------------------------------------------------------------
    85. void _MessageRouter_MessageArrived(string text, Message_Gravity gravity)
    86. {
    87. if (!_IsMainThread)
    88. {
    89. // 只接受主线程之外的其他线程发送的消息
    90. return;
    91. }
    92. MessageSeverity severity;
    93. switch (gravity)
    94. {
    95. case Message_Gravity.Trace:
    96. severity = MessageSeverity.Trace;
    97. break;
    98. case Message_Gravity.Info:
    99. severity = MessageSeverity.Info;
    100. break;
    101. case Message_Gravity.Warning:
    102. case Message_Gravity.Alarm:
    103. severity = MessageSeverity.Warning;
    104. break;
    105. case Message_Gravity.Fail:
    106. severity = MessageSeverity.Error;
    107. break;
    108. default:
    109. throw new ArgumentOutOfRangeException(nameof(gravity), gravity, null);
    110. }
    111. AddMessage(new MessageItem(severity, text));
    112. }
    113. //--------------------------------------------------------------------------------------------------
    114. public event EventHandler StaticPropertyChanged;
    115. public void RaiseStaticPropertyChanged([CallerMemberName] String propertyName = "")
    116. {
    117. StaticPropertyChanged?.Invoke(null, new PropertyChangedEventArgs(propertyName));
    118. }
    119. //--------------------------------------------------------------------------------------------------
    120. #endregion
    121. #region Messages
    122. public event EventHandler MessageThrown;
    123. //--------------------------------------------------------------------------------------------------
    124. ///
    125. /// 添加消息项。
    126. ///
    127. public void AddMessage(MessageItem message)
    128. {
    129. if (message.Sender != null && message.Sender.TryGetTarget(out var entity))
    130. {
    131. var list = _EntityMessages.GetValue(entity, key => new List());
    132. list.Add(message);
    133. }
    134. _MessageItems.Add(message);
    135. MessageThrown?.Invoke(message.Sender, message);
    136. }
    137. //--------------------------------------------------------------------------------------------------
    138. ///
    139. /// 清除指定实体的所有消息。
    140. ///
    141. public void ClearEntityMessages(Entity entity)
    142. {
    143. if (!_EntityMessages.TryGetValue(entity, out var messages))
    144. {
    145. return;
    146. }
    147. messages.ForEach(item => _MessageItems.Remove(item));
    148. _EntityMessages.Remove(entity);
    149. }
    150. //--------------------------------------------------------------------------------------------------
    151. ///
    152. /// 清除所有实体的消息。
    153. ///
    154. public void ClearAllEntityMessages()
    155. {
    156. foreach (var item in _MessageItems.ToArray())
    157. {
    158. if(item.Sender == null)
    159. continue;
    160. _MessageItems.Remove(item);
    161. }
    162. }
    163. //--------------------------------------------------------------------------------------------------
    164. ///
    165. /// 获取指定实体的消息。
    166. ///
    167. public List GetEntityMessages(Entity entity)
    168. {
    169. return _EntityMessages.TryGetValue(entity, out var list) ? list : null;
    170. }
    171. //--------------------------------------------------------------------------------------------------
    172. #endregion
    173. #region Processing
    174. ///
    175. /// 处理消息事件的原因。
    176. ///
    177. public enum ProgressMessageEventReason
    178. {
    179. ProcessingStarted,
    180. ProcessingStopped
    181. }
    182. //--------------------------------------------------------------------------------------------------
    183. ///
    184. /// 处理消息事件参数。
    185. ///
    186. public class ProgressMessageEventArgs : EventArgs
    187. {
    188. public ProgressMessageEventReason Reason;
    189. public string Description;
    190. public ProgressMessageEventArgs(ProgressMessageEventReason reason, string description)
    191. {
    192. Reason = reason;
    193. Description = description;
    194. }
    195. }
    196. //--------------------------------------------------------------------------------------------------
    197. ///
    198. /// 进度消息事件。
    199. ///
    200. public event EventHandler ProgressMessage;
    201. //--------------------------------------------------------------------------------------------------
    202. ///
    203. /// 当处理开始时调用。
    204. ///
    205. public void OnProcessingStarted(Entity referenceEntity, string description)
    206. {
    207. _ProcessingEntitiesStack.Push(referenceEntity);
    208. if (_ProcessingEntitiesStack.Count == 1)
    209. {
    210. ProgressMessage?.Invoke(this, new ProgressMessageEventArgs(ProgressMessageEventReason.ProcessingStarted, description));
    211. }
    212. }
    213. //--------------------------------------------------------------------------------------------------
    214. ///
    215. /// 当处理结束时调用。
    216. ///
    217. public void OnProcessingStopped()
    218. {
    219. if (_ProcessingEntitiesStack.Count > 0)
    220. {
    221. _ProcessingEntitiesStack.Pop();
    222. }
    223. if (_ProcessingEntitiesStack.Count == 0)
    224. {
    225. ProgressMessage?.Invoke(this, new ProgressMessageEventArgs(ProgressMessageEventReason.ProcessingStopped, null));
    226. }
    227. }
    228. //--------------------------------------------------------------------------------------------------
    229. #endregion
    230. }
    231. }

    这是一个用于处理消息的类。它包含了一些属性和方法来管理消息集合、处理消息的事件等。其中包括了消息的添加、清除、获取等操作,以及处理过程的开始和结束。

    9.

    1. using System;
    2. using System.Text;
    3. using Macad.Core.Topology;
    4. namespace Macad.Core
    5. {
    6. ///
    7. /// 消息严重性级别枚举。
    8. ///
    9. public enum MessageSeverity
    10. {
    11. Trace = 0,
    12. Info = 1,
    13. Warning = 2,
    14. Error = 3
    15. }
    16. //--------------------------------------------------------------------------------------------------
    17. //--------------------------------------------------------------------------------------------------
    18. ///
    19. /// 消息项类。
    20. ///
    21. public class MessageItem
    22. {
    23. ///
    24. /// 获取时间戳。
    25. ///
    26. public DateTime TimeStamp { get; }
    27. ///
    28. /// 获取消息文本。
    29. ///
    30. public string Text { get; }
    31. ///
    32. /// 获取消息严重性级别。
    33. ///
    34. public MessageSeverity Severity { get; }
    35. ///
    36. /// 获取消息解释。
    37. ///
    38. public string[] Explanation { get; }
    39. ///
    40. /// 获取消息发送者的弱引用。
    41. ///
    42. public WeakReference Sender { get; }
    43. //--------------------------------------------------------------------------------------------------
    44. static readonly char[] _LineBreaks = { '\n', '\r' };
    45. //--------------------------------------------------------------------------------------------------
    46. ///
    47. /// 构造函数。
    48. ///
    49. public MessageItem(MessageSeverity severity, string text, string explanation=null, Entity sender=null)
    50. {
    51. TimeStamp = DateTime.Now;
    52. Severity = severity;
    53. Text = text;
    54. Sender = sender != null ? new WeakReference(sender) : null;
    55. Explanation = explanation?.Split(_LineBreaks, StringSplitOptions.RemoveEmptyEntries);
    56. }
    57. //--------------------------------------------------------------------------------------------------
    58. ///
    59. /// 返回消息的字符串表示形式。
    60. ///
    61. public override string ToString()
    62. {
    63. var sb = new StringBuilder();
    64. switch (Severity)
    65. {
    66. case MessageSeverity.Trace:
    67. sb.Append("Trace: ");
    68. break;
    69. case MessageSeverity.Info:
    70. sb.Append("Info: ");
    71. break;
    72. case MessageSeverity.Warning:
    73. sb.Append("Warning: ");
    74. break;
    75. case MessageSeverity.Error:
    76. sb.Append("Error: ");
    77. break;
    78. }
    79. if (Sender != null && Sender.TryGetTarget(out var senderEntity))
    80. {
    81. sb.Append('[');
    82. sb.Append(senderEntity.Name);
    83. sb.Append("] ");
    84. }
    85. sb.AppendLine(Text);
    86. if (Explanation != null)
    87. {
    88. foreach (var s in Explanation)
    89. {
    90. sb.AppendLine(s);
    91. }
    92. }
    93. return sb.ToString();
    94. }
    95. //--------------------------------------------------------------------------------------------------
    96. ///
    97. /// 返回消息的简略字符串表示形式。
    98. ///
    99. public string ToShortString()
    100. {
    101. string result;
    102. switch (Severity)
    103. {
    104. case MessageSeverity.Trace:
    105. result = "Trace: ";
    106. break;
    107. case MessageSeverity.Info:
    108. result = "Info: ";
    109. break;
    110. case MessageSeverity.Warning:
    111. result = "Warning: ";
    112. break;
    113. case MessageSeverity.Error:
    114. result = "Error: ";
    115. break;
    116. default:
    117. result = "";
    118. break;
    119. }
    120. return result + Text;
    121. }
    122. //--------------------------------------------------------------------------------------------------
    123. }
    124. }

    这段代码定义了消息项类 MessageItem 和消息严重性级别枚举 MessageSeverity。消息项类包含了消息的时间戳、文本、严重性级别、解释和发送者的信息。

    10.

    1. using System;
    2. using System.Runtime.InteropServices;
    3. using Macad.Core.Topology;
    4. using Macad.Occt;
    5. namespace Macad.Core
    6. {
    7. ///
    8. /// 消息类,提供发送各种消息的静态方法。
    9. ///
    10. public static class Messages
    11. {
    12. ///
    13. /// 发送跟踪消息。
    14. ///
    15. public static void Trace(string line, string explanation = null, Entity sender = null)
    16. {
    17. var handler = CoreContext.Current?.MessageHandler;
    18. handler?.AddMessage(new MessageItem(MessageSeverity.Trace, line, explanation, sender ?? handler.CurrentReferenceEntity));
    19. }
    20. //--------------------------------------------------------------------------------------------------
    21. ///
    22. /// 发送信息消息。
    23. ///
    24. public static void Info(string line, string explanation = null, Entity sender = null)
    25. {
    26. var handler = CoreContext.Current?.MessageHandler;
    27. handler?.AddMessage(new MessageItem(MessageSeverity.Info, line, explanation, sender ?? handler.CurrentReferenceEntity));
    28. }
    29. //--------------------------------------------------------------------------------------------------
    30. ///
    31. /// 发送警告消息。
    32. ///
    33. public static void Warning(string line, string explanation = null, Entity sender = null)
    34. {
    35. var handler = CoreContext.Current?.MessageHandler;
    36. handler?.AddMessage(new MessageItem(MessageSeverity.Warning, line, explanation, sender ?? handler.CurrentReferenceEntity));
    37. }
    38. //--------------------------------------------------------------------------------------------------
    39. ///
    40. /// 发送错误消息。
    41. ///
    42. public static void Error(string line, string explanation = null, Entity sender = null)
    43. {
    44. var handler = CoreContext.Current?.MessageHandler;
    45. handler?.AddMessage(new MessageItem(MessageSeverity.Error, line, explanation, sender ?? handler.CurrentReferenceEntity));
    46. }
    47. //--------------------------------------------------------------------------------------------------
    48. ///
    49. /// 发送异常消息。
    50. ///
    51. public static void Exception(string line, Exception exception, Entity sender = null)
    52. {
    53. string msg;
    54. if (exception is SEHException)
    55. {
    56. // 尝试从本地获取信息
    57. var info = Interop.ExceptionHelper.GetNativeExceptionInfo(Marshal.GetExceptionPointers());
    58. if (info != null)
    59. {
    60. msg = $"{info.Message} [{info.Source}]";
    61. }
    62. else
    63. {
    64. msg = "未知本地异常。";
    65. }
    66. }
    67. else
    68. {
    69. msg = $"{exception.Message} [ {exception.GetType().FullName} ]";
    70. }
    71. string expl = "异常: " + msg + "\n" + exception.StackTrace;
    72. var handler = CoreContext.Current?.MessageHandler;
    73. handler?.AddMessage(new MessageItem(MessageSeverity.Error, line, expl, sender ?? handler.CurrentReferenceEntity));
    74. }
    75. //--------------------------------------------------------------------------------------------------
    76. ///
    77. /// 发送报告消息。
    78. ///
    79. public static void Report(Message_Report report)
    80. {
    81. report.SendMessages(Message.DefaultMessenger());
    82. }
    83. //--------------------------------------------------------------------------------------------------
    84. }
    85. }

    这段代码定义了一个静态类 Messages,其中包含了用于发送各种消息的静态方法,如跟踪消息、信息消息、警告消息、错误消息、异常消息和报告消息。

    11.

    1. using System;
    2. using Macad.Core.Topology;
    3. namespace Macad.Core
    4. {
    5. ///
    6. /// 表示一个处理范围,用于在其范围内开始和结束处理。
    7. ///
    8. public sealed class ProcessingScope : IDisposable
    9. {
    10. ///
    11. /// 初始化处理范围并开始处理。
    12. ///
    13. /// 参考实体。
    14. /// 描述处理的信息。
    15. public ProcessingScope(Entity referenceEntity, string description)
    16. {
    17. CoreContext.Current?.MessageHandler?.OnProcessingStarted(referenceEntity, description);
    18. }
    19. ///
    20. /// 处理范围的析构函数,结束处理。
    21. ///
    22. ~ProcessingScope()
    23. {
    24. Dispose();
    25. }
    26. ///
    27. public void Dispose()
    28. {
    29. CoreContext.Current?.MessageHandler?.OnProcessingStopped();
    30. GC.SuppressFinalize(this);
    31. }
    32. }
    33. }

    这段代码定义了一个 ProcessingScope 类,它表示一个处理范围,用于在其范围内开始和结束处理。

    12.

    1. using System;
    2. using System.Collections.Generic;
    3. using System.Linq;
    4. using Macad.Core.Geom;
    5. using Macad.Core.Shapes;
    6. using Macad.Common;
    7. using Macad.Occt;
    8. namespace Macad.Core
    9. {
    10. #region 类 BRepTopologyTreeNodes
    11. ///
    12. /// 表示 BRepTopologyTreeNode 实例的集合。
    13. ///
    14. public class BRepTopologyTreeNodes : List<BRepTopologyTreeNode>
    15. {
    16. ///
    17. /// 使用指定的容量初始化 BRepTopologyTreeNodes 类的新实例。
    18. ///
    19. /// 列表可以包含的初始元素数。
    20. public BRepTopologyTreeNodes(int capacity)
    21. : base(capacity)
    22. {
    23. }
    24. ///
    25. /// 初始化 BRepTopologyTreeNodes 类的新实例。
    26. ///
    27. public BRepTopologyTreeNodes()
    28. {
    29. }
    30. ///
    31. /// 初始化 BRepTopologyTreeNodes 类的新实例,并将元素添加到指定的集合。
    32. ///
    33. /// 要复制到新列表中的集合的元素。
    34. public BRepTopologyTreeNodes(IEnumerable collection)
    35. : base(collection)
    36. {
    37. }
    38. }
    39. #endregion
    40. #region 类 BRepTopologyTreeProperty
    41. ///
    42. /// 表示 B-Rep 拓扑树节点的属性。
    43. ///
    44. public class BRepTopologyTreeProperty
    45. {
    46. ///
    47. /// 获取属性的类别。
    48. ///
    49. public string Category { get; }
    50. ///
    51. /// 获取属性的名称。
    52. ///
    53. public string Name { get; }
    54. ///
    55. /// 获取属性的值。
    56. ///
    57. public string Value { get; }
    58. ///
    59. /// 使用指定的类别、名称和值初始化 BRepTopologyTreeProperty 类的新实例。
    60. ///
    61. /// 属性的类别。
    62. /// 属性的名称。
    63. /// 属性的值。
    64. public BRepTopologyTreeProperty(string category, string name, string value)
    65. {
    66. Category = category;
    67. Name = name;
    68. Value = value;
    69. }
    70. }
    71. #endregion
    72. #region 类 BRepTopologyTreeNode
    73. ///
    74. /// 表示 B-Rep 拓扑树中的节点。
    75. ///
    76. public class BRepTopologyTreeNode
    77. {
    78. #region 属性
    79. ///
    80. /// 获取节点的名称。
    81. ///
    82. public string Name { get; private set; }
    83. ///
    84. /// 获取节点的子节点。
    85. ///
    86. public BRepTopologyTreeNodes Children
    87. {
    88. get
    89. {
    90. // 如果子节点尚未初始化,则初始化它们
    91. if (_Children is null)
    92. _InitChildren();
    93. return _Children;
    94. }
    95. }
    96. ///
    97. /// 获取与节点关联的 B-Rep 形状。
    98. ///
    99. public TopoDS_Shape BrepShape { get; }
    100. ///
    101. /// 获取与节点关联的属性。
    102. ///
    103. public List Properties
    104. {
    105. get
    106. {
    107. // 如果属性尚未初始化,则初始化它们
    108. if (_Properties is null)
    109. _InitProperties();
    110. return _Properties;
    111. }
    112. }
    113. ///
    114. /// 获取与节点关联的形状。
    115. ///
    116. public Shape Shape { get; }
    117. #endregion
    118. #region 构造函数和设置器
    119. ///
    120. /// 使用指定的形状初始化 BRepTopologyTreeNode 类的新实例。
    121. ///
    122. /// 与节点关联的形状。
    123. public BRepTopologyTreeNode(Shape shape)
    124. {
    125. Shape = shape;
    126. BrepShape = shape?.GetBRep();
    127. _TopLevelShape = BrepShape;
    128. Name = "无效形状";
    129. if (BrepShape != null)
    130. {
    131. Name = _GetShapeTypeName(BrepShape.ShapeType());
    132. }
    133. }
    134. ///
    135. /// 使用指定的 B-Rep 形状初始化 BRepTopologyTreeNode 类的新实例。
    136. ///
    137. /// 与节点关联的 B-Rep 形状。
    138. /// 与节点关联的顶级形状。
    139. /// 与节点关联的形状。
    140. public BRepTopologyTreeNode(TopoDS_Shape brepShape, TopoDS_Shape topLevelShape = null, Shape shape = null)
    141. {
    142. Shape = shape;
    143. BrepShape = brepShape;
    144. _TopLevelShape = topLevelShape ?? brepShape;
    145. Name = "无效形状";
    146. if (brepShape != null)
    147. {
    148. Name = _GetShapeTypeName(brepShape.ShapeType());
    149. }
    150. }
    151. ///
    152. /// 使用指定的名称、包含的节点和顶级形状初始化 BRepTopologyTreeNode 类的新实例。
    153. ///
    154. /// 节点的名称。
    155. /// 此节点中包含的子节点。
    156. /// 与节点关联的顶级形状。
    157. /// 与节点关联的形状。
    158. public BRepTopologyTreeNode(string name, BRepTopologyTreeNodes containedNodes, TopoDS_Shape topLevelShape, Shape shape = null)
    159. {
    160. Shape = shape;
    161. Name = $"{name} ({containedNodes.Count})";
    162. _Children = containedNodes;
    163. _TopLevelShape = topLevelShape;
    164. _Properties = new List();
    165. }
    166. ///
    167. /// 向节点名称添加索引前缀。
    168. ///
    169. /// 要添加为前缀的索引。
    170. public void AddIndexPrefix(int i)
    171. {
    172. Name = $"[{i}] {Name}";
    173. }
    174. #endregion
    175. #region 成员
    176. BRepTopologyTreeNodes _Children;
    177. List _Properties;
    178. readonly TopoDS_Shape _TopLevelShape;
    179. #endregion
    180. #region 子节点
    181. ///
    182. /// 初始化子节点。
    183. ///
    184. void _InitChildren()
    185. {
    186. if (_Children != null)
    187. return;
    188. if (BrepShape == null)
    189. return;
    190. _Children = new BRepTopologyTreeNodes();
    191. switch (BrepShape.ShapeType())
    192. {
    193. case TopAbs_ShapeEnum.COMPOUND:
    194. _AddShapeCollection(BrepShape.Solids(), true);
    195. _AddShapeCollection(BrepShape.Shells(), true);
    196. _AddShapeCollection(BrepShape.Faces(), true);
    197. _AddShapeCollection(BrepShape.Wires(), true);
    198. _AddShapeCollection(BrepShape.Edges(), true);
    199. _AddShapeCollection(BrepShape.Vertices(), true);
    200. break;
    201. case TopAbs_ShapeEnum.COMPSOLID:
    202. _AddShapeCollection(BrepShape.Solids());
    203. break;
    204. case TopAbs_ShapeEnum.SOLID:
    205. _AddShapeCollection(BrepShape.Shells(), true);
    206. _AddShapeCollection(BrepShape.Faces(), true);
    207. _AddShapeCollection(BrepShape.Wires(), true);
    208. _AddShapeCollection(BrepShape.Edges(), true);
    209. _AddShapeCollection(BrepShape.Vertices(), true);
    210. break;
    211. case TopAbs_ShapeEnum.SHELL:
    212. _AddShapeCollection(BrepShape.Faces(), true);
    213. _AddShapeCollection(BrepShape.Wires(), true);
    214. _AddShapeCollection(BrepShape.Edges(), true);
    215. _AddShapeCollection(BrepShape.Vertices(), true);
    216. break;
    217. case TopAbs_ShapeEnum.FACE:
    218. _AddShapeCollection(BrepShape.Wires());
    219. break;
    220. case TopAbs_ShapeEnum.WIRE:
    221. _AddShapeCollection(BrepShape.Edges());
    222. break;
    223. case TopAbs_ShapeEnum.EDGE:
    224. _AddShapeCollection(BrepShape.Vertices());
    225. break;
    226. }
    227. }
    228. #endregion
    229. #region 属性列表
    230. ///
    231. /// 初始化属性列表。
    232. ///
    233. void _InitProperties()
    234. {
    235. if (_Properties != null)
    236. return;
    237. _Properties = new List();
    238. try
    239. {
    240. _AddDefaultProperties();
    241. switch (BrepShape.ShapeType())
    242. {
    243. case TopAbs_ShapeEnum.SHELL:
    244. _AddShellProperties(BrepShape as TopoDS_Shell ?? TopoDS.Shell(BrepShape));
    245. break;
    246. case TopAbs_ShapeEnum.FACE:
    247. _AddFaceProperties(BrepShape as TopoDS_Face ?? TopoDS.Face(BrepShape));
    248. break;
    249. case TopAbs_ShapeEnum.WIRE:
    250. _AddWireProperties(BrepShape as TopoDS_Wire ?? TopoDS.Wire(BrepShape));
    251. break;
    252. case TopAbs_ShapeEnum.EDGE:
    253. _AddEdgeProperties(BrepShape as TopoDS_Edge ?? TopoDS.Edge(BrepShape));
    254. break;
    255. case TopAbs_ShapeEnum.VERTEX:
    256. _AddVertexProperties(BrepShape as TopoDS_Vertex ?? TopoDS.Vertex(BrepShape));
    257. break;
    258. }
    259. }
    260. catch (Exception e)
    261. {
    262. Messages.Exception($"获取 B-Rep 形状 {Name} 的属性时出错", e);
    263. }
    264. }
    265. #endregion
    266. #region 集合
    267. ///
    268. /// 将形状集合添加到子节点。
    269. ///
    270. /// 形状的类型。
    271. /// 要添加到子节点的形状集合。
    272. /// 指示是否对集合进行分组。
    273. void _AddShapeCollection(IReadOnlyList shapeList, bool group = false) where T: TopoDS_Shape
    274. {
    275. if (!shapeList.Any())
    276. return;
    277. var collection = group ? new BRepTopologyTreeNodes() : _Children;
    278. for (var i = 0; i < shapeList.Count; i++)
    279. {
    280. var treeNode = new BRepTopologyTreeNode(shapeList[i], _TopLevelShape, Shape);
    281. treeNode.AddIndexPrefix(i);
    282. collection.Add(treeNode);
    283. }
    284. if (group)
    285. {
    286. var name = typeof(T).Name.TrimPrefixes("TopoDS_") + "s";
    287. if (name == "Vertexs")
    288. name = "Vertices";
    289. _Children.Add(new BRepTopologyTreeNode(name, collection, _TopLevelShape, Shape));
    290. }
    291. }
    292. #endregion
    293. }
    294. #endregion
    295. }

    这段代码定义了一个名为BRepTopologyTreeNode的类,用于表示 B-Rep(Boundary Representation)拓扑树中的节点。B-Rep是一种用于描述实体几何形状的方法,它通过表示实体的边界以及边界之间的关系来描述几何形状。

    该类的主要作用包括:

    1. 表示B-Rep拓扑树中的节点,每个节点代表一个几何形状元素(如面、边、点等)或由多个子节点组成的组合形状。
    2. 可以获取节点的名称、子节点、B-Rep形状、属性等信息。
    3. 提供了初始化子节点和属性列表的方法,以便在需要时进行延迟加载。
    4. 可以添加索引前缀以标识节点在其父节点中的位置。
    5. 可以根据B-Rep形状的类型添加相应类型的子节点集合,并可选择对子节点进行分组。
    6. 提供了获取B-Rep形状的类型名称、初始化属性列表、初始化子节点、添加子节点等功能的私有辅助方法。

    总之,该类用于构建和管理B-Rep拓扑树的节点,使用户能够方便地表示和操作复杂的几何形状结构。

    13.

    1. using Macad.Common;
    2. using Macad.Occt;
    3. namespace Macad.Core
    4. {
    5. public static class OcctColorUtils
    6. {
    7. public static Color Color(Quantity_Color color)
    8. {
    9. var red = (float)color.Red();
    10. var green = (float)color.Green();
    11. var blue = (float)color.Blue();
    12. return new Color(red, green, blue);
    13. }
    14. //--------------------------------------------------------------------------------------------------
    15. public static Color Color(Quantity_NameOfColor colorName)
    16. {
    17. return Color(new Quantity_Color(colorName));
    18. }
    19. //--------------------------------------------------------------------------------------------------
    20. public static Quantity_Color ToColor(this Quantity_NameOfColor colorName)
    21. {
    22. return new Quantity_Color(colorName);
    23. }
    24. //--------------------------------------------------------------------------------------------------
    25. public static Graphic3d_MaterialAspect ToAspect(this Graphic3d_NameOfMaterial materialName)
    26. {
    27. return new Graphic3d_MaterialAspect(materialName);
    28. }
    29. //--------------------------------------------------------------------------------------------------
    30. public static Quantity_Color ToQuantityColor(this Color color)
    31. {
    32. return new Quantity_Color(color.Red, color.Green, color.Blue, Quantity_TypeOfColor.sRGB);
    33. }
    34. //--------------------------------------------------------------------------------------------------
    35. }
    36. }

    整段代码的作用是提供了一些用于颜色和材质转换的工具方法。这些方法包括:

    1. Quantity_Color类型的颜色转换为Color类型的颜色。
    2. Quantity_NameOfColor类型的颜色名称转换为Color类型的颜色。
    3. Quantity_NameOfColor类型的颜色名称转换为Quantity_Color类型的颜色。
    4. Graphic3d_NameOfMaterial类型的材质名称转换为Graphic3d_MaterialAspect类型的材质属性。
    5. Color类型的颜色转换为Quantity_Color类型的颜色。

    14.

    1. using System.Diagnostics; // 导入System.Diagnostics命名空间,提供Debug类的定义
    2. using Macad.Common.Serialization; // 导入Macad.Common.Serialization命名空间,提供序列化相关的类和接口
    3. using Macad.Occt; // 导入Macad.Occt命名空间,提供OpenCASCADE的类型定义
    4. namespace Macad.Core
    5. {
    6. public class OcctSerializers // 定义名为OcctSerializers的类,用于提供OpenCASCADE类型的序列化器
    7. {
    8. class OcctSerializer_Pnt2d : ISerializer // 定义内部类OcctSerializer_Pnt2d,实现ISerializer接口,用于Pnt2d类型的序列化
    9. {
    10. public bool Write(Writer writer, object obj, SerializationContext context)
    11. {
    12. var pnt2d = (Pnt2d)obj; // 将传入的对象转换为Pnt2d类型
    13. double[] values = { pnt2d.X, pnt2d.Y }; // 提取Pnt2d对象的坐标值
    14. return _DoubleArraySerializer.Write(writer, values, context); // 调用_DoubleArraySerializer对坐标值进行序列化
    15. }
    16. public object Read(Reader reader, object obj, SerializationContext context)
    17. {
    18. var values = (double[])_DoubleArraySerializer.Read(reader, null, context); // 从Reader中读取序列化的坐标值
    19. if ((values != null) && (values.Length == 2)) // 验证读取的坐标值是否正确
    20. {
    21. return new Pnt2d(values[0], values[1]); // 创建新的Pnt2d对象并返回
    22. }
    23. return null; // 如果读取的坐标值不正确,则返回null
    24. }
    25. }
    26. //--------------------------------------------------------------------------------------------------
    27. // 类似地定义其他OpenCASCADE类型的序列化器,包括Pnt、Vec、Dir、Quaternion、Ax1、Ax2和Pln
    28. // 每个序列化器都包括Write和Read方法,用于将对象序列化为数组或从数组中反序列化为对象
    29. //--------------------------------------------------------------------------------------------------
    30. static bool _IsInitialized; // 静态变量,标识是否已初始化
    31. static ISerializer _DoubleArraySerializer; // 静态变量,用于序列化double数组
    32. public static void Init() // 初始化方法,用于注册OpenCASCADE类型的序列化器
    33. {
    34. Debug.Assert(!_IsInitialized); // 确保尚未初始化
    35. _DoubleArraySerializer = Serializer.GetSerializer(typeof(double[])); // 获取序列化double数组的序列化器
    36. // 注册各个OpenCASCADE类型的序列化器
    37. Serializer.AddSerializer(typeof(Pnt), new OcctSerializer_Pnt());
    38. Serializer.AddSerializer(typeof(Pnt2d), new OcctSerializer_Pnt2d());
    39. Serializer.AddSerializer(typeof(Vec), new OcctSerializer_Vec());
    40. Serializer.AddSerializer(typeof(Dir), new OcctSerializer_Dir());
    41. Serializer.AddSerializer(typeof(Quaternion), new OcctSerializer_Quaternion());
    42. Serializer.AddSerializer(typeof(Ax1), new OcctSerializer_Ax1());
    43. Serializer.AddSerializer(typeof(Ax2), new OcctSerializer_Ax2());
    44. Serializer.AddSerializer(typeof(Pln), new OcctSerializer_Pln());
    45. _IsInitialized = true; // 设置初始化标志为true
    46. }
    47. //--------------------------------------------------------------------------------------------------
    48. }
    49. }

    这段代码定义了一系列用于OpenCASCADE类型的序列化器,包括PntPnt2dVecDirQuaternionAx1Ax2Pln。每个序列化器都实现了ISerializer接口,包括Write方法用于将对象序列化为数组,以及Read方法用于从数组中反序列化为对象。在初始化方法Init中,这些序列化器被注册到了全局的Serializer对象中,以便在序列化和反序列化过程中使用。

    15.

    1. using System; // 导入System命名空间,提供基本的系统类型和功能
    2. using Macad.Common.Serialization; // 导入Macad.Common.Serialization命名空间,提供序列化相关的类和接口
    3. using Macad.Occt; // 导入Macad.Occt命名空间,提供OpenCASCADE的类型定义
    4. namespace Macad.Core
    5. {
    6. [SerializeType] // 标记该枚举类型可被序列化
    7. public enum SubshapeType // 定义名为SubshapeType的枚举类型,用于表示子形状的类型
    8. {
    9. Vertex, // 顶点
    10. Edge, // 边
    11. Wire, // 线
    12. Face // 面
    13. }
    14. //--------------------------------------------------------------------------------------------------
    15. [SerializeType] // 标记该枚举类型可被序列化
    16. [Flags] // 标记该枚举为位标志枚举
    17. public enum SubshapeTypes // 定义名为SubshapeTypes的枚举类型,用于表示多个子形状的组合类型
    18. {
    19. None = 0, // 无
    20. Vertex = 1 << 0, // 顶点
    21. Edge = 1 << 1, // 边
    22. Wire = 1 << 2, // 线
    23. Face = 1 << 4, // 面
    24. All = Vertex | Edge | Wire | Face // 全部类型的组合
    25. }
    26. //--------------------------------------------------------------------------------------------------
    27. public static class SubshapeTypeHelper // 定义名为SubshapeTypeHelper的静态类,包含一些用于子形状类型操作的方法
    28. {
    29. public static SubshapeTypes GetTypes(SubshapeType topAbsShapeEnum) // 返回给定SubshapeType枚举值对应的SubshapeTypes位标志值
    30. {
    31. switch (topAbsShapeEnum)
    32. {
    33. case SubshapeType.Face:
    34. return SubshapeTypes.Face;
    35. case SubshapeType.Edge:
    36. return SubshapeTypes.Edge;
    37. case SubshapeType.Wire:
    38. return SubshapeTypes.Wire;
    39. case SubshapeType.Vertex:
    40. return SubshapeTypes.Vertex;
    41. default:
    42. throw new NotImplementedException(); // 抛出未实现异常
    43. }
    44. }
    45. //--------------------------------------------------------------------------------------------------
    46. // 类似地定义其他用于获取子形状类型的方法,包括GetType和GetTypes方法
    47. //--------------------------------------------------------------------------------------------------
    48. public static TopAbs_ShapeEnum ToTopAbs(this SubshapeType type) // 将SubshapeType枚举值转换为TopAbs_ShapeEnum值
    49. {
    50. switch (type)
    51. {
    52. case SubshapeType.Vertex:
    53. return TopAbs_ShapeEnum.VERTEX;
    54. case SubshapeType.Edge:
    55. return TopAbs_ShapeEnum.EDGE;
    56. case SubshapeType.Wire:
    57. return TopAbs_ShapeEnum.WIRE;
    58. case SubshapeType.Face:
    59. return TopAbs_ShapeEnum.FACE;
    60. default:
    61. throw new NotImplementedException(); // 抛出未实现异常
    62. }
    63. }
    64. //--------------------------------------------------------------------------------------------------
    65. // 类似地定义其他用于转换子形状类型的方法,包括ToAisSelectionMode和Count方法
    66. //--------------------------------------------------------------------------------------------------
    67. }
    68. }

    这段代码定义了用于处理子形状类型的枚举和辅助方法。首先定义了SubshapeType枚举,表示子形状的具体类型,包括顶点、边、线和面。然后定义了SubshapeTypes枚举,表示多个子形状类型的组合,使用了位标志枚举的特性。接着定义了SubshapeTypeHelper静态类,包含了一系列用于处理子形状类型的方法,包括获取子形状类型、转换类型以及计数等。这些方法可以方便地处理子形状类型的操作和转换。

    16.

    1. using System; // 导入System命名空间,提供基本的系统类型和功能
    2. using System.Collections.Generic; // 导入System.Collections.Generic命名空间,提供泛型集合类型的支持
    3. using Macad.Occt; // 导入Macad.Occt命名空间,提供OpenCASCADE的类型定义
    4. namespace Macad.Core // 声明名为Macad.Core的命名空间,该类位于Macad.Core命名空间下
    5. {
    6. public class TopoDSShapeComparer : IEqualityComparer<TopoDS_Shape> // 定义名为TopoDSShapeComparer的类,实现了IEqualityComparer接口,用于比较TopoDS_Shape对象
    7. {
    8. public enum CompareMode // 定义名为CompareMode的枚举类型,表示比较模式
    9. {
    10. Equal, // 相等
    11. Same, // 相同
    12. Partner // 伙伴
    13. }
    14. //--------------------------------------------------------------------------------------------------
    15. CompareMode _Mode = CompareMode.Equal; // 声明名为_Mode的字段,用于存储比较模式,默认为Equal
    16. //--------------------------------------------------------------------------------------------------
    17. public TopoDSShapeComparer(CompareMode mode) // 定义TopoDSShapeComparer类的构造函数,初始化比较模式
    18. {
    19. _Mode = mode; // 将传入的比较模式赋值给_Mode字段
    20. }
    21. //--------------------------------------------------------------------------------------------------
    22. public bool Equals(TopoDS_Shape x, TopoDS_Shape y) // 实现IEqualityComparer接口中的Equals方法,用于比较两个TopoDS_Shape对象是否相等
    23. {
    24. if (x == null) // 如果第一个对象为null
    25. return y == null; // 则当第二个对象也为null时返回true,否则返回false
    26. return _Mode switch // 根据比较模式进行比较
    27. {
    28. CompareMode.Equal => x.Equals(y), // 如果比较模式为Equal,则调用Equals方法比较对象是否相等
    29. CompareMode.Same => x.IsSame(y), // 如果比较模式为Same,则调用IsSame方法比较对象是否相同
    30. CompareMode.Partner => x.IsPartner(y), // 如果比较模式为Partner,则调用IsPartner方法比较对象是否为伙伴
    31. _ => false // 默认情况下返回false
    32. };
    33. }
    34. //--------------------------------------------------------------------------------------------------
    35. public int GetHashCode(TopoDS_Shape obj) // 实现IEqualityComparer接口中的GetHashCode方法,用于获取对象的哈希码
    36. {
    37. return _Mode switch // 根据比较模式获取哈希码
    38. {
    39. CompareMode.Equal => obj.GetHashCode(), // 如果比较模式为Equal,则直接返回对象的哈希码
    40. CompareMode.Same => obj.TShape().GetHashCode() ^ obj.Location().GetHashCode(), // 如果比较模式为Same,则获取对象的TShape和Location的哈希码,并进行异或操作
    41. CompareMode.Partner => obj.TShape().GetHashCode(), // 如果比较模式为Partner,则只获取对象的TShape的哈希码
    42. _ => 0 // 默认情况下返回0
    43. };
    44. }
    45. }
    46. }

    这段代码定义了一个名为TopoDSShapeComparer的类,用于比较TopoDS_Shape对象。它实现了IEqualityComparer接口,其中TTopoDS_Shape类型。类中包含了一个枚举CompareMode,表示比较模式,包括相等、相同和伙伴。类中包含了一个字段 _Mode,用于存储比较模式,默认为相等。类中包含了构造函数用于初始化比较模式,以及Equals方法用于比较两个对象是否相等,GetHashCode方法用于获取对象的哈希码。

    17.

    1. using System; // 导入System命名空间,提供基本的系统类型和功能
    2. using System.Collections.Generic; // 导入System.Collections.Generic命名空间,提供泛型集合类型的支持
    3. using System.IO; // 导入System.IO命名空间,提供文件和流的操作功能
    4. namespace Macad.Core // 声明名为Macad.Core的命名空间,该类位于Macad.Core命名空间下
    5. {
    6. internal static class ScriptCache // 声明名为ScriptCache的静态类,用于脚本缓存管理
    7. {
    8. struct CachedScriptFileInfo // 定义名为CachedScriptFileInfo的结构体,用于存储缓存的脚本文件信息
    9. {
    10. internal string FileName; // 存储文件名
    11. internal long Length; // 存储文件长度
    12. internal DateTime LastWriteTime; // 存储文件最后写入时间
    13. }
    14. class CachedScript // 定义名为CachedScript的内部类,用于存储缓存的脚本实例及其文件信息
    15. {
    16. internal ScriptInstance Instance; // 存储脚本实例
    17. internal CachedScriptFileInfo[] FileInfos; // 存储脚本文件信息数组
    18. }
    19. //--------------------------------------------------------------------------------------------------
    20. static readonly Dictionary<string, CachedScript> _CachedScripts = new Dictionary<string, CachedScript>(); // 声明名为_CachedScripts的静态只读字典,用于存储缓存的脚本信息
    21. //--------------------------------------------------------------------------------------------------
    22. internal static void Add(ScriptInstance scriptInstance, List<string> fileList) // 声明名为Add的静态方法,用于向脚本缓存中添加脚本实例及其文件信息
    23. {
    24. var entry = new CachedScript // 创建CachedScript实例
    25. {
    26. Instance = scriptInstance, // 设置脚本实例
    27. FileInfos = new CachedScriptFileInfo[fileList.Count], // 创建缓存的脚本文件信息数组
    28. };
    29. for (var i = 0; i < fileList.Count; i++) // 遍历文件列表
    30. {
    31. var fi = new FileInfo(fileList[i]); // 获取文件信息
    32. var info = new CachedScriptFileInfo() // 创建CachedScriptFileInfo实例
    33. {
    34. FileName = fileList[i], // 设置文件名
    35. Length = fi.Length, // 设置文件长度
    36. LastWriteTime = fi.LastWriteTimeUtc // 设置文件最后写入时间
    37. };
    38. entry.FileInfos[i] = info; // 将文件信息添加到缓存的文件信息数组中
    39. }
    40. _CachedScripts[scriptInstance.Path] = entry; // 将脚本实例路径及其对应的缓存信息添加到缓存字典中
    41. }
    42. //--------------------------------------------------------------------------------------------------
    43. internal static ScriptInstance Find(string filename) // 声明名为Find的静态方法,用于在缓存中查找指定路径的脚本实例
    44. {
    45. try
    46. {
    47. filename = Path.GetFullPath(filename); // 获取指定路径的绝对路径
    48. if (!_CachedScripts.TryGetValue(filename, out CachedScript entry)) // 判断缓存字典中是否包含指定路径的缓存信息
    49. return null; // 如果不包含,则返回null
    50. foreach (var info in entry.FileInfos) // 遍历缓存的文件信息数组
    51. {
    52. var fi = new FileInfo(info.FileName); // 获取文件信息
    53. if (fi.Length != info.Length // 检查文件长度和最后写入时间是否匹配
    54. || fi.LastWriteTimeUtc != info.LastWriteTime)
    55. {
    56. // Cache miss,如果不匹配,则返回null
    57. return null;
    58. }
    59. }
    60. // Cache hit,如果匹配,则返回对应的脚本实例
    61. return entry.Instance;
    62. }
    63. catch (Exception)
    64. {
    65. return null; // 发生异常时返回null
    66. }
    67. }
    68. //--------------------------------------------------------------------------------------------------
    69. internal static void Clear() // 声明名为Clear的静态方法,用于清空缓存字典
    70. {
    71. _CachedScripts.Clear(); // 清空缓存字典
    72. }
    73. //--------------------------------------------------------------------------------------------------
    74. }
    75. }

    这段代码定义了一个名为 ScriptCache 的静态类,用于管理脚本的缓存。它包含了一个内部结构 CachedScriptFileInfo,用于存储缓存的脚本文件信息,以及一个内部类 CachedScript,用于存储缓存的脚本实例及其文件信息。类中声明了一个静态只读字典 _CachedScripts,用于存储缓存的脚本信息。还包含了方法 Add 用于向缓存中添加脚本实例及其文件信息,方法 Find 用于在缓存中查找指定路径的脚本实例,以及方法 Clear 用于清空缓存字典。

    18.

    1. using System; // 导入 System 命名空间,提供基本的系统类型和功能
    2. using System.Collections.Generic; // 导入 System.Collections.Generic 命名空间,提供泛型集合类型的支持
    3. using System.Collections.Immutable; // 导入 System.Collections.Immutable 命名空间,提供不可变集合类型的支持
    4. using System.Globalization; // 导入 System.Globalization 命名空间,提供区域性特定信息的功能
    5. using System.IO; // 导入 System.IO 命名空间,提供文件和流的操作功能
    6. using System.Linq; // 导入 System.Linq 命名空间,提供 LINQ 查询功能
    7. using System.Reflection; // 导入 System.Reflection 命名空间,提供反射操作的功能
    8. using System.Runtime.Loader; // 导入 System.Runtime.Loader 命名空间,提供程序集加载器的功能
    9. using System.Text; // 导入 System.Text 命名空间,提供字符串处理功能
    10. using Microsoft.CodeAnalysis; // 导入 Microsoft.CodeAnalysis 命名空间,提供编译代码分析的功能
    11. using Microsoft.CodeAnalysis.CSharp; // 导入 Microsoft.CodeAnalysis.CSharp 命名空间,提供 C# 编译器的功能
    12. using Microsoft.CodeAnalysis.CSharp.Scripting; // 导入 Microsoft.CodeAnalysis.CSharp.Scripting 命名空间,提供 C# 脚本编译的功能
    13. using Microsoft.CodeAnalysis.Scripting; // 导入 Microsoft.CodeAnalysis.Scripting 命名空间,提供脚本编译的功能
    14. using Macad.Common; // 导入 Macad.Common 命名空间,提供通用功能
    15. using Macad.Occt; // 导入 Macad.Occt 命名空间,提供 OCC 相关功能
    16. using Microsoft.CodeAnalysis.Scripting.Hosting; // 导入 Microsoft.CodeAnalysis.Scripting.Hosting 命名空间,提供脚本主机环境的功能
    17. namespace Macad.Core // 声明名为 Macad.Core 的命名空间,该类位于 Macad.Core 命名空间下
    18. {
    19. internal sealed class ScriptCompiler // 声明名为 ScriptCompiler 的密封类,用于编译脚本
    20. {
    21. static readonly string[] _DefaultReferenceAppAssemblies = // 默认的引用应用程序集
    22. {
    23. "Macad.Occt.dll",
    24. "Macad.Managed.dll",
    25. "Macad.Common.dll",
    26. "Macad.Core.dll",
    27. "Macad.Presentation.dll",
    28. "Macad.Interaction.dll",
    29. "Macad.Resources.dll"
    30. };
    31. static readonly string[] _DefaultImports = // 默认的导入命名空间
    32. {
    33. "System",
    34. "Macad.Common",
    35. "Macad.Core",
    36. "Macad.Core.Shapes",
    37. "Macad.Core.Toolkits",
    38. "Macad.Core.Topology",
    39. "Macad.Occt",
    40. };
    41. static readonly string[] _MetadataSearchPaths = // 元数据搜索路径
    42. {
    43. Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
    44. Path.GetDirectoryName(typeof(object).Assembly.Location)
    45. };
    46. //--------------------------------------------------------------------------------------------------
    47. static float _Version; // 版本号
    48. //--------------------------------------------------------------------------------------------------
    49. static ScriptCompiler() // 静态构造函数
    50. {
    51. var version = Assembly.GetExecutingAssembly().GetName().Version; // 获取当前程序集的版本
    52. _Version = float.Parse($"{version.Major}.{version.Minor}", CultureInfo.InvariantCulture); // 解析版本号
    53. }
    54. //--------------------------------------------------------------------------------------------------
    55. internal static void OverrideVersion(float version) // 重写版本号
    56. {
    57. _Version = version; // 设置版本号
    58. }
    59. //--------------------------------------------------------------------------------------------------
    60. internal static bool Compile(ScriptInstance scriptInstance) // 编译脚本
    61. {
    62. var compiler = new ScriptCompiler(scriptInstance); // 创建 ScriptCompiler 实例
    63. if (!compiler._Compile()) // 调用 _Compile 方法进行编译
    64. return false; // 如果编译失败,返回 false
    65. ScriptCache.Add(scriptInstance, compiler._FileList); // 将编译结果添加到脚本缓存中
    66. return true; // 返回编译成功
    67. }
    68. //--------------------------------------------------------------------------------------------------
    69. readonly ScriptInstance _ScriptInstance; // 脚本实例
    70. readonly List<string> _FileList = new List<string>(); // 文件列表
    71. readonly bool _EnableDebugging = true; // 是否启用调试
    72. //--------------------------------------------------------------------------------------------------
    73. ScriptCompiler(ScriptInstance scriptInstance) // ScriptCompiler 构造函数
    74. {
    75. _ScriptInstance = scriptInstance; // 设置脚本实例
    76. }
    77. //--------------------------------------------------------------------------------------------------
    78. bool _Compile() // 编译
    79. {
    80. try
    81. {
    82. var codeStream = _ReadAndPreprocessFile(_ScriptInstance.Path); // 读取并预处理文件
    83. if (codeStream == null)
    84. return false;
    85. var baseDirectory = Path.GetDirectoryName(_ScriptInstance.Path); // 获取基目录
    86. var metadataResolver = ScriptMetadataResolver.Default // 元数据解析器
    87. .WithSearchPaths(_MetadataSearchPaths)
    88. .WithBaseDirectory(baseDirectory);
    89. var sourceResolver = new ScriptSourceResolver(baseDirectory, _ReadAndPreprocessFile); // 源代码解析器
    90. var options = ScriptOptions.Default // 脚本选项
    91. .WithWarningLevel(4)
    92. .WithReferences(_DefaultReferenceAppAssemblies)
    93. .WithMetadataResolver(metadataResolver)
    94. .WithSourceResolver(sourceResolver)
    95. .WithImports(_DefaultImports)
    96. .WithEmitDebugInformation(_EnableDebugging)
    97. .WithLanguageVersion(LanguageVersion.Latest);
    98. var assemblyLoader = new InteractiveAssemblyLoader(); // 装载程序集
    99. foreach (var defaultAssembly in AssemblyLoadContext.Default.Assemblies) // 加载默认程序集
    100. {
    101. assemblyLoader.RegisterDependency(defaultAssembly);
    102. }
    103. // This extra reference is needed for unit test runner which isolate this assembly
    104. assemblyLoader.RegisterDependency(Assembly.GetExecutingAssembly()); // 注册依赖程序集
    105. var script = CSharpScript.Create(codeStream, options, _ScriptInstance.ContextInstance.GetType(), assemblyLoader); // 创建脚本
    106. var results = script.Compile(); // 编译脚本
    107. codeStream.Dispose(); // 释放流资源
    108. var hasErrors = _ReportResults(results); // 检查编译结果
    109. if (!hasErrors) // 如果没有错误
    110. {
    111. return _ScriptInstance.Init(script.CreateDelegate()); // 初始化脚本实例
    112. }
    113. }
    114. catch (Exception e) // 捕获异常
    115. {
    116. Messages.Exception("Script compilation failed. Scriptfile: " + _ScriptInstance.Path, e); // 报告异常
    117. }
    118. return false; // 返回编译失败
    119. }
    120. //--------------------------------------------------------------------------------------------------
    121. Stream _ReadAndPreprocessFile(string filename) // 读取并预处理文件
    122. {
    123. if (!File.Exists(filename)) // 检查文件是否存在
    124. {
    125. Messages.Error($"Script imported file {filename} not found. Scriptfile: {_ScriptInstance.Path}"); // 报告错误
    126. return null; // 返回空流
    127. }
    128. if (!_FileList.Contains(filename)) // 检查文件列表中是否包含该文件
    129. {
    130. _FileList.Add(filename); // 添加文件到文件列表
    131. }
    132. var ms = new MemoryStream(); // 创建内存流
    133. using StreamWriter sw = new StreamWriter(ms, Encoding.Unicode, 1024, true); // 创建写入器
    134. sw.WriteLine($"#line 1 \"{Path.GetFileName(filename)}\""); // 写入 #line 指令
    135. bool inComment = false; // 是否在注释中
    136. int lineNumber = 0; // 行号
    137. using (var reader = File.OpenText(filename)) // 使用文件读取器读取文件
    138. {
    139. while (!reader.EndOfStream) // 循环读取每行
    140. {
    141. var rawLine = reader.ReadLine(); // 读取原始行
    142. if (rawLine == null)
    143. break;
    144. var line = rawLine.Trim().ToLower(); // 去除首尾空白并转换为小写
    145. lineNumber++; // 行号递增
    146. if (line.IsNullOrWhiteSpace()) // 检查是否为空行
    147. {
    148. sw.WriteLine(rawLine); // 写入空行
    149. continue;
    150. }
    151. // We are in a comment block
    152. if (inComment) // 如果在注释块中
    153. {
    154. var posStart = line.LastIndexOf("/*", StringComparison.Ordinal); // 获取注释块起始位置
    155. var posEnd = line.LastIndexOf("*/", StringComparison.Ordinal); // 获取注释块结束位置
    156. if (posEnd > posStart) // 如果结束位置大于起始位置
    157. {
    158. // Comment closed
    159. inComment = false; // 标记注释块关闭
    160. // only continue if no code follows
    161. if (!line.EndsWith("*/")) // 如果注释块后还有代码
    162. continue;
    163. }
    164. // Comment continues
    165. sw.WriteLine(rawLine); // 写入注释行
    166. continue;
    167. }
    168. // Pragma
    169. if (line.StartsWith("#")) // 如果是 #pragma 指令
    170. {
    171. if (line.StartsWith("#if ") || line.StartsWith("#elif ")) // 如果是条件编译指令
    172. {
    173. var second = line.Substring(line.IndexOf(' ') + 1).Trim(); // 获取条件表达式
    174. if (second.StartsWith("version ")) // 如果是版本判断
    175. {
    176. var value = second.Substring(8); // 获取版本号值
    177. var substitute = _ProcessVersion(value); // 处理版本号
    178. if (substitute == null) // 如果处理失败
    179. {
    180. Messages.Error($"Script error in line {lineNumber}: The version expression is invalid. Scriptfile: {_ScriptInstance.Path}."); // 报告错误
    181. ms.Close(); // 关闭流
    182. return null; // 返回空流
    183. }
    184. sw.Write(rawLine.Substring(0, rawLine.IndexOf('#'))); // 写入 #pragma 指令之前的部分
    185. sw.Write(line.Substring(0, line.IndexOf(' ') + 1)); // 写入 #pragma 指令
    186. sw.WriteLine(substitute + " // version " + value); // 写入替换后的版本号表达式
    187. continue;
    188. }
    189. }
    190. // non-directive for us, just skip
    191. sw.WriteLine(rawLine); // 写入 #pragma 指令
    192. continue;
    193. }
    194. // Single comment line
    195. if (line.StartsWith("//")) // 如果是单行注释
    196. {
    197. // non-directive comment line, just skip
    198. sw.WriteLine(rawLine); // 写入单行注释
    199. continue;
    200. }
    201. // Comment starting
    202. if (line.StartsWith("/*")) // 如果是注释块起始
    203. {
    204. var posStart = line.LastIndexOf("/*", StringComparison.Ordinal); // 获取注释块起始位置
    205. var posEnd = line.LastIndexOf("*/", StringComparison.Ordinal); // 获取注释块结束位置
    206. if (posEnd < posStart) // 如果结束位置小于起始位置
    207. {
    208. // Comment opened, but not closed
    209. inComment = true; // 标记注释块开启
    210. }
    211. else
    212. {
    213. // Comment opened and closed
    214. // only continue if no code follows
    215. if (!line.EndsWith("*/")) // 如果注释块后还有代码
    216. continue;
    217. }
    218. sw.WriteLine(rawLine); // 写入注释行
    219. continue;
    220. }
    221. sw.WriteLine(rawLine); // 写入原始行
    222. }
    223. }
    224. return ms; // 返回内存流
    225. }
    226. //--------------------------------------------------------------------------------------------------
    227. static readonly char[] _VersionOperands = {'<', '>', '=', '!', ' '}; // 版本号操作符
    228. string _ProcessVersion(string line) // 处理版本号
    229. {
    230. var splitIndex = line.LastIndexOfAny(_VersionOperands); // 查找操作符位置
    231. if (splitIndex < 0) // 如果操作符位置小于 0
    232. return null;
    233. var value = line.Substring(splitIndex + 1); // 获取版本号值
    234. if (!float.TryParse(value, NumberStyles.AllowDecimalPoint, CultureInfo.InvariantCulture, out var version)) // 解析版本号
    235. return null;
    236. bool result;
    237. var operand = line.Substring(0, splitIndex + 1).Trim(); // 获取操作符
    238. switch (operand) // 判断操作符
    239. {
    240. case "==":
    241. result = version.IsEqual(_Version, 0.001f); // 判断是否相等
    242. break;
    243. case "!=":
    244. result = !version.IsEqual(_Version, 0.001f); // 判断是否不相等
    245. break;
    246. case "<":
    247. result = _Version < version; // 判断是否小于
    248. break;
    249. case "<=":
    250. result = _Version < version || version.IsEqual(_Version, 0.001f); // 判断是否小于等于
    251. break;
    252. case ">":
    253. result = _Version > version; // 判断是否大于
    254. break;
    255. case ">=":
    256. result = _Version > version || version.IsEqual(_Version, 0.001f); // 判断是否大于等于
    257. break;
    258. default:
    259. return null;
    260. }
    261. return result ? "true" : "false"; // 返回处理结果
    262. }
    263. //--------------------------------------------------------------------------------------------------
    264. bool _ReportResults(ImmutableArray errors) // 报告编译结果
    265. {
    266. DiagnosticSeverity severity = DiagnosticSeverity.Info; // 默认的诊断级别为 Info
    267. var sb = new StringBuilder(); // 创建字符串构建器
    268. foreach (var diag in errors) // 遍历诊断信息
    269. {
    270. if (diag.Severity < DiagnosticSeverity.Warning) // 如果诊断级别低于警告
    271. continue;
    272. if (diag.Severity > severity) // 如果诊断级别高于当前级别
    273. severity = diag.Severity; // 更新诊断级别
    274. if (diag.Location != null) // 如果有位置信息
    275. {
    276. var location = diag.Location.GetMappedLineSpan(); // 获取映射的行范围
    277. if (location.IsValid && !location.Path.IsNullOrEmpty()) // 如果有效且路径不为空
    278. {
    279. sb.Append(Path.GetFileName(location.Path)); // 添加文件名
    280. sb.Append($" ({location.Span.Start.Line},{location.Span.Start.Character}): "); // 添加行号和字符位置
    281. }
    282. }
    283. sb.Append(severity == DiagnosticSeverity.Error ? "Error " : "Warning "); // 添加错误或警告信息
    284. sb.Append(diag.Id); // 添加诊断标识
    285. sb.Append(": ");
    286. sb.AppendLine(diag.GetMessage(CultureInfo.InvariantCulture)); // 添加诊断消息
    287. }
    288. if (severity == DiagnosticSeverity.Error) // 如果诊断级别为错误
    289. {
    290. Messages.Error("Script compilation failed with errors.", sb.ToString()); // 报告编译错误
    291. }
    292. else if(severity == DiagnosticSeverity.Warning) // 如果诊断级别为警告
    293. {
    294. Messages.Warning("Script compiled with warnings.", sb.ToString()); // 报告编译警告
    295. }
    296. return severity == DiagnosticSeverity.Error; // 返回是否有错误
    297. }
    298. }
    299. }

    以上代码是一个用于编译脚本的 C# 类 ScriptCompiler,它负责读取、预处理、编译脚本文件,并提供一些额外的功能,如版本控制和诊断报告。下面是代码的注释说明:

    • ScriptCompiler 类包含了用于编译脚本的各种方法和功能。
    • Compile 方法用于编译脚本实例。
    • _Compile 方法实现了脚本的实际编译过程,包括读取、预处理文件,设置编译选项,编译脚本,并处理编译结果。
    • _ReadAndPreprocessFile 方法用于读取和预处理文件,包括处理注释、#pragma 指令和版本号条件等。
    • _ProcessVersion 方法用于处理版本号条件表达式。
    • _ReportResults 方法用于报告编译结果,包括错误和警告信息。
    • 其他部分包括一些字段和常量的定义,以及静态构造函数和一些辅助方法的实现。

    这个类的主要功能是将脚本文件编译成可执行的代码,并提供错误和警告信息以供调试和修复。

    19.

    1. using Macad.Core.Topology;
    2. namespace Macad.Core
    3. {
    4. ///
    5. /// 脚本上下文类,作为所有脚本的基类,在应用程序中提供对各种组件的访问。
    6. ///
    7. public class ScriptContext
    8. {
    9. ///
    10. /// 默认的脚本上下文实例,允许无需实例化新的对象即可访问其成员。
    11. ///
    12. internal static ScriptContext Default { get; } = new ScriptContext();
    13. //--------------------------------------------------------------------------------------------------
    14. ///
    15. /// 模型对象,包含应用程序中的所有实体和对每个实体的引用。
    16. ///
    17. public Model Document => CoreContext.Current.Document;
    18. ///
    19. /// 图层集合,定义了与实体的可见性、交互性和可视化相关的共享属性。
    20. ///
    21. public LayerCollection Layers => CoreContext.Current.Layers;
    22. ///
    23. /// 工作空间,包含应用程序内部用于可视化和交互的所有功能。
    24. ///
    25. public Workspace Workspace => CoreContext.Current.Workspace;
    26. ///
    27. /// 视口,是工作空间的窗口,用于用户在图形环境中查看和操作对象。
    28. ///
    29. public Viewport Viewport => CoreContext.Current.Viewport;
    30. }
    31. }

    这段代码定义了名为 ScriptContext 的类,它作为脚本的基类,在应用程序中提供对各种组件的访问。下面是对其成员的解释:

    • Default 属性

      • 提供了 ScriptContext 的静态实例,允许在不需要实例化新的 ScriptContext 对象的情况下轻松访问其成员。
    • Document 属性

      • 表示模型,其中包含应用程序中的所有实体和对每个实体的引用。通常,CAD 模型的几何结构和结构都驻留在这里。
    • Layers 属性

      • 表示图层集合,定义了与应用程序中实体的可见性、交互性和可视化相关的共享属性。图层通常用于组织和管理在视口中显示对象的方式。
    • Workspace 属性

      • 表示工作空间,其中包含应用程序内部用于可视化和交互的所有功能。这包括与 CAD 模型相关的工具、命令和其他功能。
    • Viewport 属性

      • 表示视口,它是对工作空间的窗口。视口是用户与 CAD 模型交互的地方,在图形环境中查看和操作对象。

    这些属性为脚本提供了对应用程序环境中关键组件的访问,使其能够有效地执行操作并在 CAD 模型中操作数据。

    20.

    1. using System;
    2. using System.Collections.Generic;
    3. using System.IO;
    4. using System.Linq;
    5. using System.Reflection;
    6. using Microsoft.CodeAnalysis.Scripting;
    7. namespace Macad.Core
    8. {
    9. ///
    10. /// 表示一个脚本实例,可以加载、编译和运行脚本文件。
    11. ///
    12. public sealed class ScriptInstance
    13. {
    14. ///
    15. /// 从文件加载脚本实例。
    16. ///
    17. /// 脚本文件路径。
    18. /// 是否强制重新加载。
    19. /// 加载的脚本实例。
    20. public static ScriptInstance LoadScriptFromFile(string filename, bool forceReload = false)
    21. {
    22. return LoadScriptFromFile(filename, ScriptContext.Default, forceReload);
    23. }
    24. //--------------------------------------------------------------------------------------------------
    25. ///
    26. /// 从文件加载脚本实例。
    27. ///
    28. /// 脚本文件路径。
    29. /// 脚本上下文实例。
    30. /// 是否强制重新加载。
    31. /// 加载的脚本实例。
    32. public static ScriptInstance LoadScriptFromFile(string filename, ScriptContext contextInstance, bool forceReload=false)
    33. {
    34. if (!File.Exists(filename))
    35. {
    36. Messages.Error( "Script file does not exist: " + filename);
    37. }
    38. ScriptInstance scriptInstance;
    39. if (!forceReload)
    40. {
    41. scriptInstance = ScriptCache.Find(filename);
    42. if (scriptInstance != null)
    43. return scriptInstance;
    44. }
    45. scriptInstance = new ScriptInstance(filename, contextInstance);
    46. if(ScriptCompiler.Compile(scriptInstance))
    47. {
    48. return scriptInstance;
    49. }
    50. return null;
    51. }
    52. //--------------------------------------------------------------------------------------------------
    53. ///
    54. /// 获取当前正在运行的脚本实例。
    55. ///
    56. public static ScriptInstance Current
    57. {
    58. get { return _RunningScripts.Any() ? _RunningScripts.Peek() : null; }
    59. }
    60. static readonly Stack _RunningScripts = new Stack();
    61. //--------------------------------------------------------------------------------------------------
    62. ///
    63. /// 脚本名称。
    64. ///
    65. public string Name { get; }
    66. ///
    67. /// 脚本文件路径。
    68. ///
    69. public string Path { get; }
    70. ///
    71. /// 脚本上下文实例。
    72. ///
    73. public ScriptContext ContextInstance { get; }
    74. //--------------------------------------------------------------------------------------------------
    75. ScriptRunner<object> _RunnerDelegate;
    76. //--------------------------------------------------------------------------------------------------
    77. ///
    78. /// 初始化脚本实例。
    79. ///
    80. internal ScriptInstance(string filename, ScriptContext contextInstance)
    81. {
    82. Name = System.IO.Path.GetFileName(filename);
    83. Path = System.IO.Path.GetFullPath(filename);
    84. ContextInstance = contextInstance;
    85. _Reset();
    86. }
    87. //--------------------------------------------------------------------------------------------------
    88. ///
    89. /// 重置脚本实例。
    90. ///
    91. void _Reset()
    92. {
    93. _RunnerDelegate = null;
    94. }
    95. //--------------------------------------------------------------------------------------------------
    96. ///
    97. /// 设置脚本运行器委托。
    98. ///
    99. internal bool Init(ScriptRunner<object> runnerDelegate)
    100. {
    101. _Reset();
    102. _RunnerDelegate = runnerDelegate;
    103. return true;
    104. }
    105. //--------------------------------------------------------------------------------------------------
    106. ///
    107. /// 运行脚本。
    108. ///
    109. /// 指示脚本是否成功运行。
    110. public bool Run()
    111. {
    112. bool result = false;
    113. if (_RunnerDelegate == null)
    114. return false;
    115. _RunningScripts.Push(this);
    116. try
    117. {
    118. _RunnerDelegate(ContextInstance).Wait();
    119. result = true;
    120. }
    121. catch (Exception e)
    122. {
    123. Messages.Exception($"The executed script '{Name}' throwed an exception.", e);
    124. }
    125. finally
    126. {
    127. }
    128. _RunningScripts.Pop();
    129. // Only commit after the last script has ended.
    130. if(_RunningScripts.Count == 0)
    131. CoreContext.Current?.UndoHandler?.Commit();
    132. return result;
    133. }
    134. }
    135. }

    以上代码是用于处理脚本的加载、编译和运行的类 ScriptInstance。下面是逐行注释和说明:

    1. using 指令:引入了一系列命名空间,包括必要的系统命名空间和 Microsoft.CodeAnalysis.Scripting 用于动态编译和运行脚本的命名空间。

    2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个脚本实例类。

    3. public sealed class ScriptInstance:定义了 ScriptInstance 类,用于表示一个脚本实例。

    4. public static ScriptInstance LoadScriptFromFile(string filename, bool forceReload = false) 方法:从文件加载脚本实例的静态方法。根据提供的文件名加载脚本,并可以选择是否强制重新加载。返回加载的脚本实例。

    5. public static ScriptInstance LoadScriptFromFile(string filename, ScriptContext contextInstance, bool forceReload=false) 方法:从文件加载脚本实例的静态方法,可以指定脚本上下文实例。返回加载的脚本实例。

    6. ScriptInstance(string filename, ScriptContext contextInstance) 构造函数:初始化脚本实例的私有构造函数。用于创建脚本实例对象。

    7. public static ScriptInstance Current 属性:获取当前正在运行的脚本实例。使用栈来存储运行的脚本实例,从而支持嵌套调用。

    8. _RunningScripts 字段:用于存储当前正在运行的脚本实例的栈。

    9. public string Name { get; } 属性:脚本名称。

    10. public string Path { get; } 属性:脚本文件路径。

    11. public ScriptContext ContextInstance { get; } 属性:脚本上下文实例。

    12. _RunnerDelegate 字段:脚本运行器委托,用于执行脚本的方法。

    13. _Reset() 方法:重置脚本实例,清空运行器委托。

    14. internal bool Init(ScriptRunner runnerDelegate) 方法:初始化脚本实例,设置运行器委托。

    15. public bool Run() 方法:运行脚本的方法。使用运行器委托来执行脚本的逻辑,并处理可能发生的异常。最终返回指示脚本是否成功运行的布尔值。

    16. 以上就是 ScriptInstance 类的代码及其注释说明。

      21.

      1. using System;
      2. using System.Collections.Immutable;
      3. using System.IO;
      4. using Microsoft.CodeAnalysis;
      5. namespace Macad.Core
      6. {
      7. ///
      8. /// 表示用于解析脚本源文件的解析器。
      9. ///
      10. public sealed class ScriptSourceResolver : SourceFileResolver
      11. {
      12. Func<string, Stream> _ReadFunc;
      13. //--------------------------------------------------------------------------------------------------
      14. ///
      15. /// 构造函数,初始化脚本源文件解析器。
      16. ///
      17. /// 基本目录。
      18. /// 读取文件的方法。
      19. public ScriptSourceResolver(string baseDirectory, Func<string, Stream> readFunc)
      20. : base(ImmutableArray<string>.Empty, baseDirectory)
      21. {
      22. _ReadFunc = readFunc;
      23. }
      24. //--------------------------------------------------------------------------------------------------
      25. ///
      26. /// 打开指定路径的文件流。
      27. ///
      28. /// 已解析的文件路径。
      29. /// 文件流。
      30. public override Stream OpenRead(string resolvedPath)
      31. {
      32. return _ReadFunc(Path.GetFullPath(resolvedPath));
      33. }
      34. }
      35. }

      逐行注释和说明如下:

      1. using 指令:引入了必要的命名空间。

      2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个脚本源文件解析器类。

      3. public sealed class ScriptSourceResolver : SourceFileResolver:定义了 ScriptSourceResolver 类,用于解析脚本的源文件。

      4. Func _ReadFunc;:私有字段,用于存储读取文件的方法。

      5. 构造函数 ScriptSourceResolver(string baseDirectory, Func readFunc):初始化脚本源文件解析器的构造函数,设置基本目录和读取文件的方法。

      6. public override Stream OpenRead(string resolvedPath) 方法:重写了基类的打开读取方法,根据解析后的文件路径调用存储的读取文件方法获取文件流。

      以上是 ScriptSourceResolver 类的代码及其注释说明。

      22.

      1. using System;
      2. using System.Diagnostics;
      3. using Macad.Core.Topology;
      4. namespace Macad.Core
      5. {
      6. public class DataBlobUndoAction : UndoAction
      7. {
      8. byte[] _StoredData;
      9. //--------------------------------------------------------------------------------------------------
      10. public DataBlobUndoAction(Guid instanceGuid)
      11. {
      12. InstanceGuid = instanceGuid;
      13. }
      14. //--------------------------------------------------------------------------------------------------
      15. public bool Set(IUndoableDataBlob dataBlobOwner)
      16. {
      17. InstanceGuid = dataBlobOwner.Guid;
      18. var data = dataBlobOwner.GetUndoDataBlob();
      19. if (data != null)
      20. {
      21. _StoredData = data;
      22. //Debug.WriteLine(_StoredData);
      23. return true;
      24. }
      25. return false;
      26. }
      27. //--------------------------------------------------------------------------------------------------
      28. public override void Restore(Entity instance, UndoHandler undoHandler)
      29. {
      30. var dataBlobOwner = instance as IUndoableDataBlob;
      31. Debug.Assert(dataBlobOwner != null);
      32. dataBlobOwner.SetUndoDataBlob(_StoredData);
      33. }
      34. }
      35. }

      逐行注释和说明如下:

      1. using 指令:引入了必要的命名空间。

      2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个类的定义。

      3. public class DataBlobUndoAction : UndoAction:定义了 DataBlobUndoAction 类,表示数据块撤销操作。

      4. _StoredData:私有字段,存储撤销操作的数据块。

      5. 构造函数 DataBlobUndoAction(Guid instanceGuid):初始化具有指定实例 GUID 的 DataBlobUndoAction 类的新实例。

      6. public bool Set(IUndoableDataBlob dataBlobOwner) 方法:设置数据块的撤销操作,参数为拥有数据块的对象。

      7. public override void Restore(Entity instance, UndoHandler undoHandler) 方法:重写了基类的恢复方法,用于恢复撤销的操作。

      以上是 DataBlobUndoAction 类的代码及其注释说明。

      23.

      1. using System;
      2. namespace Macad.Core
      3. {
      4. ///
      5. /// 定义了可撤销数据块的接口。
      6. ///
      7. public interface IUndoableDataBlob
      8. {
      9. ///
      10. /// 获取数据块的 GUID。
      11. ///
      12. Guid Guid { get; }
      13. ///
      14. /// 获取数据块的撤销数据。
      15. ///
      16. /// 表示数据块的字节数组。
      17. byte[] GetUndoDataBlob();
      18. ///
      19. /// 设置数据块的撤销数据。
      20. ///
      21. /// 要设置的数据块的字节数组。
      22. void SetUndoDataBlob(byte[] dataBlob);
      23. }
      24. }

      逐行注释和说明如下:

      1. using 指令:引入了必要的命名空间。

      2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个接口的定义。

      3. public interface IUndoableDataBlob:定义了 IUndoableDataBlob 接口,表示可撤销数据块的接口。

      4. Guid Guid { get; } 属性:获取数据块的唯一标识符(GUID)。

      5. byte[] GetUndoDataBlob() 方法:获取数据块的撤销数据,返回表示数据块的字节数组。

      6. void SetUndoDataBlob(byte[] dataBlob) 方法:设置数据块的撤销数据,参数为要设置的数据块的字节数组。

      以上是 IUndoableDataBlob 接口的代码及其注释说明。

      24.

      1. using System;
      2. using Macad.Core.Topology;
      3. namespace Macad.Core
      4. {
      5. ///
      6. /// 定义了可撤销拓扑操作的接口。
      7. ///
      8. public interface IUndoableTopology
      9. {
      10. ///
      11. /// 获取拓扑操作的唯一标识符(GUID)。
      12. ///
      13. Guid Guid { get; }
      14. ///
      15. /// 根据实例的 GUID 查找实体。
      16. ///
      17. /// 要查找的实例的 GUID。
      18. /// 找到的实体,如果未找到则为 null。
      19. Entity FindInstance(Guid instanceGuid);
      20. ///
      21. /// 获取实例的父实体。
      22. ///
      23. /// 要获取父实体的实例。
      24. /// 实例的父实体。
      25. Entity GetParent(Entity instance);
      26. ///
      27. /// 从撤销操作中添加子实体。
      28. ///
      29. /// 要添加的子实体。
      30. /// 子实体的父实体。
      31. void AddChildFromUndo(Entity instance, Entity parent);
      32. ///
      33. /// 从撤销操作中移除子实体。
      34. ///
      35. /// 要移除的子实体。
      36. void RemoveChildFromUndo(Entity instance);
      37. ///
      38. /// 从撤销操作中移动子实体到新的父实体。
      39. ///
      40. /// 要移动的子实体。
      41. /// 子实体的新父实体。
      42. void MoveChildFromUndo(Entity instance, Entity newParent);
      43. }
      44. }

      逐行注释和说明如下:

      1. using 指令:引入了必要的命名空间。

      2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个接口的定义。

      3. public interface IUndoableTopology:定义了 IUndoableTopology 接口,表示可撤销拓扑操作的接口。

      4. Guid Guid { get; } 属性:获取拓扑操作的唯一标识符(GUID)。

      5. Entity FindInstance(Guid instanceGuid) 方法:根据实例的 GUID 查找实体。

      6. Entity GetParent(Entity instance) 方法:获取实例的父实体。

      7. void AddChildFromUndo(Entity instance, Entity parent) 方法:从撤销操作中添加子实体。

      8. void RemoveChildFromUndo(Entity instance) 方法:从撤销操作中移除子实体。

      9. void MoveChildFromUndo(Entity instance, Entity newParent) 方法:从撤销操作中移动子实体到新的父实体。

      以上是 IUndoableTopology 接口的代码及其注释说明。

      25.

      1. using System;
      2. using System.Collections.Generic;
      3. using System.Linq;
      4. using System.Reflection;
      5. using System.Runtime.InteropServices;
      6. using Macad.Core.Topology;
      7. namespace Macad.Core
      8. {
      9. ///
      10. /// 表示属性的撤销操作。
      11. ///
      12. public class PropertyUndoAction : UndoAction
      13. {
      14. //--------------------------------------------------------------------------------------------------
      15. ///
      16. /// 表示属性值的更改。
      17. ///
      18. class PropertyValueChange
      19. {
      20. readonly PropertyInfo _PropertyInfo; // 属性信息
      21. object _Value; // 属性值
      22. bool _IsEntityReference; // 属性是否引用了实体
      23. //--------------------------------------------------------------------------------------------------
      24. ///
      25. /// 构造函数,初始化 PropertyValueChange 的新实例。
      26. ///
      27. /// 要更改的属性信息。
      28. public PropertyValueChange(PropertyInfo propertyInfo)
      29. {
      30. _PropertyInfo = propertyInfo;
      31. _IsEntityReference = typeof(Entity).IsAssignableFrom(_PropertyInfo.DeclaringType)
      32. && typeof(Entity).IsAssignableFrom(_PropertyInfo.PropertyType);
      33. }
      34. //--------------------------------------------------------------------------------------------------
      35. ///
      36. /// 判断属性是否相等。
      37. ///
      38. /// 要比较的属性信息。
      39. /// 如果属性相等,则为 true,否则为 false。
      40. public bool IsEqual(PropertyInfo propInfo)
      41. {
      42. return _PropertyInfo.Equals(propInfo);
      43. }
      44. //--------------------------------------------------------------------------------------------------
      45. ///
      46. /// 更新属性的值。
      47. ///
      48. /// 属性所在的实例。
      49. /// 要设置的属性值。
      50. public void Update(object instance, object value = null)
      51. {
      52. if (value != null)
      53. {
      54. _Value = value;
      55. }
      56. else
      57. {
      58. if (_IsEntityReference)
      59. {
      60. // 仅保存引用
      61. var entity = _PropertyInfo.GetValue(instance) as Entity;
      62. _Value = entity?.Guid;
      63. }
      64. else
      65. {
      66. _Value = _PropertyInfo.GetValue(instance);
      67. }
      68. }
      69. }
      70. //--------------------------------------------------------------------------------------------------
      71. ///
      72. /// 还原属性的值。
      73. ///
      74. /// 属性所在的实例。
      75. public void RestoreValue(object instance)
      76. {
      77. if (_IsEntityReference)
      78. {
      79. // 通过引用还原
      80. var document = (instance as Entity)?.Document;
      81. if (document != null && _Value != null && _Value is Guid guid)
      82. {
      83. _PropertyInfo.SetValue(instance, document.FindInstance(guid));
      84. }
      85. else
      86. {
      87. _PropertyInfo.SetValue(instance, null);
      88. }
      89. }
      90. else
      91. {
      92. _PropertyInfo.SetValue(instance, _Value);
      93. }
      94. }
      95. //--------------------------------------------------------------------------------------------------
      96. }
      97. //--------------------------------------------------------------------------------------------------
      98. //--------------------------------------------------------------------------------------------------
      99. readonly List _ChangeList = new List(); // 属性值更改列表
      100. //--------------------------------------------------------------------------------------------------
      101. ///
      102. /// 初始化 PropertyUndoAction 类的新实例。
      103. ///
      104. /// 操作实例的 GUID。
      105. public PropertyUndoAction(Guid instanceGuid)
      106. {
      107. InstanceGuid = instanceGuid;
      108. }
      109. //--------------------------------------------------------------------------------------------------
      110. ///
      111. /// 设置属性的撤销操作。
      112. ///
      113. /// 要设置的属性信息。
      114. /// 属性所在的实例。
      115. /// 要设置的属性值。
      116. public void Set(PropertyInfo propertyInfo, Entity instance, object value = null)
      117. {
      118. // 注意:只保存第一个值更改,否则原始状态将会丢失。
      119. var change = _ChangeList.FirstOrDefault(pvc => pvc.IsEqual(propertyInfo));
      120. if(change != null)
      121. return;
      122. change = new PropertyValueChange(propertyInfo);
      123. change.Update(instance, value);
      124. _ChangeList.Add(change);
      125. }
      126. //--------------------------------------------------------------------------------------------------
      127. ///
      128. /// 还原属性的撤销操作。
      129. ///
      130. /// 操作实例。
      131. /// 撤销处理程序。
      132. public override void Restore(Entity instance, UndoHandler undoHandler)
      133. {
      134. _ChangeList.ForEach( change => change.RestoreValue(instance));
      135. var shape = instance as Shapes.Shape;
      136. shape?.Invalidate();
      137. }
      138. //--------------------------------------------------------------------------------------------------
      139. }
      140. }

      逐行注释和说明如下:

      1. using 指令:引入了必要的命名空间。

      2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个类的定义。

      3. public class PropertyUndoAction : UndoAction:定义了表示属性撤销操作的 PropertyUndoAction 类。

      4. class PropertyValueChange:表示属性值的更改,是 PropertyUndoAction 类的嵌套类。

      5. readonly List _ChangeList = new List();:属性值更改列表,用于保存属性值的更改。

      6. public PropertyUndoAction(Guid instanceGuid)PropertyUndoAction 类的构造函数,初始化实例的 GUID。

      7. public void Set(PropertyInfo propertyInfo, Entity instance, object value = null):设置属性的撤销操作,记录属性值的更改。

      8. public override void Restore(Entity instance, UndoHandler undoHandler):还原属性的撤销操作,将属性值还原到之前的状态,并在需要时更新形状的无效状态。

      以上是 PropertyUndoAction 类的代码及其注释说明。

      26.

      1. using System;
      2. using System.Diagnostics;
      3. using Macad.Core.Topology;
      4. using Macad.Common.Serialization;
      5. using Macad.Core.Shapes;
      6. using Macad.Common;
      7. namespace Macad.Core
      8. {
      9. ///
      10. /// 表示拓扑操作的撤销动作。
      11. ///
      12. public class TopologyUndoAction : UndoAction
      13. {
      14. string _StoredData; // 存储的数据
      15. UndoHandler.TopologyAction _TopoAction; // 拓扑操作类型
      16. Guid _ChildGuid; // 子实体的 GUID
      17. Guid? _ParentGuid; // 父实体的 GUID
      18. //--------------------------------------------------------------------------------------------------
      19. ///
      20. /// 初始化 TopologyUndoAction 类的新实例。
      21. ///
      22. /// 实例的 GUID。
      23. public TopologyUndoAction(Guid instanceGuid)
      24. {
      25. InstanceGuid = instanceGuid;
      26. }
      27. //--------------------------------------------------------------------------------------------------
      28. ///
      29. /// 设置拓扑操作的撤销动作。
      30. ///
      31. /// 子实体。
      32. /// 包含子实体的容器。
      33. /// 拓扑操作类型。
      34. /// 如果设置成功,则为 true,否则为 false。
      35. public bool Set(Entity child, IUndoableTopology container, UndoHandler.TopologyAction action)
      36. {
      37. _ChildGuid = child.Guid;
      38. InstanceGuid = container.Guid;
      39. _ParentGuid = null;
      40. var parent = container.GetParent(child);
      41. if (parent != null)
      42. _ParentGuid = parent.Guid;
      43. _TopoAction = action;
      44. _StoredData = null;
      45. switch (action)
      46. {
      47. case UndoHandler.TopologyAction.Added:
      48. // 逆操作:移除。我们只需要实例以便稍后移除。
      49. return true;
      50. case UndoHandler.TopologyAction.Removed:
      51. // 逆操作:添加。我们需要实例、父实体和其数据以便稍后添加。
      52. var data = Serializer.Serialize(child, new SerializationContext(SerializationScope.UndoRedo));
      53. if (!data.IsNullOrEmpty())
      54. {
      55. _StoredData = data;
      56. return true;
      57. }
      58. break;
      59. case UndoHandler.TopologyAction.Moved:
      60. // 逆操作:移动回。我们需要实例和父实体。
      61. return true;
      62. }
      63. return false;
      64. }
      65. //--------------------------------------------------------------------------------------------------
      66. ///
      67. /// 还原拓扑操作的撤销动作。
      68. ///
      69. /// 操作实例。
      70. /// 撤销处理程序。
      71. public override void Restore(Entity instance, UndoHandler undoHandler)
      72. {
      73. var container = undoHandler.FindEntityInstance(InstanceGuid) as IUndoableTopology;
      74. Debug.Assert(container != null, "container != null");
      75. var child = undoHandler.FindEntityInstance(_ChildGuid);
      76. var parent = _ParentGuid.HasValue ? undoHandler.FindEntityInstance(_ParentGuid.Value) : null;
      77. switch (_TopoAction)
      78. {
      79. case UndoHandler.TopologyAction.Added:
      80. Debug.Assert(child != null);
      81. // 逆操作:移除。
      82. container.RemoveChildFromUndo(child);
      83. break;
      84. case UndoHandler.TopologyAction.Removed:
      85. Debug.Assert(child == null);
      86. // 逆操作:添加。
      87. var context = new SerializationContext(SerializationScope.UndoRedo);
      88. context.SetInstance(CoreContext.Current.Document);
      89. context.SetInstance(CoreContext.Current.Document);
      90. context.SetInstance(CoreContext.Current.Workspace);
      91. child = Serializer.Deserialize(_StoredData, context);
      92. if (child != null)
      93. {
      94. container.AddChildFromUndo(child, parent);
      95. // 更新可视化状态
      96. foreach(var entity in context.GetInstanceList())
      97. entity.RaiseVisualChanged();
      98. }
      99. break;
      100. case UndoHandler.TopologyAction.Moved:
      101. Debug.Assert(child != null);
      102. // 逆操作:移动回。
      103. undoHandler.AddTopologyChange(UndoHandler.TopologyAction.Moved, container, child);
      104. container.MoveChildFromUndo(child, parent);
      105. break;
      106. }
      107. }
      108. }
      109. }

      逐行注释和说明如下:

      1. using 指令:引入了必要的命名空间。

      2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个类的定义。

      3. public class TopologyUndoAction : UndoAction:定义了表示拓扑操作的撤销动作的 TopologyUndoAction 类。

      4. string _StoredData;:存储数据,用于保存被移除的实体的数据。

      5. UndoHandler.TopologyAction _TopoAction;:拓扑操作类型,表示进行的拓扑操作。

      6. Guid _ChildGuid;:子实体的 GUID。

      7. Guid? _ParentGuid;:父实体的 GUID。

      8. public TopologyUndoAction(Guid instanceGuid)TopologyUndoAction 类的构造函数,初始化实例的 GUID。

      9. public bool Set(Entity child, IUndoableTopology container, UndoHandler.TopologyAction action):设置拓扑操作的撤销动作,记录进行的拓扑操作及相关信息。

      10. public override void Restore(Entity instance, UndoHandler undoHandler):还原拓扑操作的撤销动作,执行相应的逆操作,并在需要时更新可视化状态。

      27.

      1. using System;
      2. using Macad.Core.Topology;
      3. namespace Macad.Core
      4. {
      5. ///
      6. /// 表示撤销动作的抽象基类。
      7. ///
      8. public abstract class UndoAction
      9. {
      10. ///
      11. /// 获取或设置实例的 GUID。
      12. ///
      13. public Guid InstanceGuid { get; protected set; }
      14. ///
      15. /// 还原撤销动作。
      16. ///
      17. /// 应用撤销动作的实例。
      18. /// 撤销处理程序。
      19. public abstract void Restore(Entity instance, UndoHandler undoHandler);
      20. }
      21. }

      逐行注释和说明如下:

      1. using 指令:引入了必要的命名空间。

      2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个类的定义。

      3. public abstract class UndoAction:定义了表示撤销动作的抽象基类 UndoAction

      4. public Guid InstanceGuid { get; protected set; }:表示实例的 GUID 属性,用于标识要执行撤销动作的实例。

      5. public abstract void Restore(Entity instance, UndoHandler undoHandler);:抽象方法,表示还原撤销动作的操作,需要由派生类实现具体的还原逻辑。

      28.

      1. using System;
      2. using System.Collections.Generic;
      3. using System.Linq;
      4. using System.Reflection;
      5. using System.Runtime.CompilerServices;
      6. using Macad.Core.Topology;
      7. using Macad.Common;
      8. using Macad.Common.Serialization;
      9. namespace Macad.Core
      10. {
      11. ///
      12. /// 处理撤销和重做操作的管理器。
      13. ///
      14. public class UndoHandler : BaseObject
      15. {
      16. #region Enums
      17. ///
      18. /// 表示拓扑操作的枚举。
      19. ///
      20. public enum TopologyAction
      21. {
      22. Added,
      23. Removed,
      24. Moved
      25. }
      26. #endregion
      27. #region Properties
      28. ///
      29. /// 获取一个值,该值指示是否可以执行撤销操作。
      30. ///
      31. public bool CanUndo
      32. {
      33. get { return _UndoStack.Count > 0; }
      34. }
      35. ///
      36. /// 获取一个值,该值指示是否可以执行重做操作。
      37. ///
      38. public bool CanRedo
      39. {
      40. get { return _RedoStack.Count > 0; }
      41. }
      42. ///
      43. /// 获取用于存储撤销操作的栈。
      44. ///
      45. public LimitedStack UndoStack
      46. {
      47. get { return _UndoStack; }
      48. }
      49. ///
      50. /// 获取用于存储重做操作的栈。
      51. ///
      52. public LimitedStack RedoStack
      53. {
      54. get { return _RedoStack; }
      55. }
      56. #endregion
      57. readonly IUndoableTopology _Document;
      58. readonly LimitedStack _RedoStack;
      59. readonly LimitedStack _UndoStack;
      60. readonly List _PendingActions = new List();
      61. bool _IsRestoring;
      62. //--------------------------------------------------------------------------------------------------
      63. ///
      64. /// 初始化 类的新实例。
      65. ///
      66. /// 撤销处理器所属的文档。
      67. public UndoHandler(IUndoableTopology document)
      68. {
      69. _Document = document;
      70. _UndoStack = new LimitedStack(500);
      71. _RedoStack = new LimitedStack(500);
      72. }
      73. //--------------------------------------------------------------------------------------------------
      74. ///
      75. /// 引发属性更改事件。
      76. ///
      77. void RaisePropertyChanged()
      78. {
      79. RaisePropertyChanged("CanUndo");
      80. RaisePropertyChanged("CanRedo");
      81. }
      82. //--------------------------------------------------------------------------------------------------
      83. ///
      84. /// 提交挂起的撤销操作。
      85. ///
      86. public void Commit()
      87. {
      88. if (!_IsRestoring)
      89. {
      90. Commit(false);
      91. _RedoStack.Clear();
      92. }
      93. }
      94. //--------------------------------------------------------------------------------------------------
      95. ///
      96. /// 提交挂起的撤销操作。
      97. ///
      98. /// 指示是否提交到重做操作的栈。
      99. void Commit(bool toRedoStack)
      100. {
      101. var stack = toRedoStack ? _RedoStack : _UndoStack;
      102. if (_PendingActions.Count > 0)
      103. {
      104. // 反转动作列表以便首先撤销最后一个动作
      105. _PendingActions.Reverse();
      106. stack.Push(_PendingActions.ToArray());
      107. _PendingActions.Clear();
      108. }
      109. }
      110. //--------------------------------------------------------------------------------------------------
      111. ///
      112. /// 添加属性更改的撤销操作。
      113. ///
      114. /// 发生属性更改的实例。
      115. /// 更改的属性名称。
      116. /// 属性的克隆值。
      117. public void AddPropertyChange(Entity instance, [CallerMemberName] string propertyName = "", object clone = null)
      118. {
      119. var propInfo = instance.GetType().GetProperty(propertyName, BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
      120. if (propInfo == null)
      121. return;
      122. if (!propInfo.GetCustomAttributes(typeof(SerializeMemberAttribute), true).Any())
      123. return;
      124. var action = (PropertyUndoAction)_PendingActions.FirstOrDefault(a => a.InstanceGuid.Equals(instance.Guid) && a is PropertyUndoAction);
      125. if (action == null)
      126. {
      127. action = new PropertyUndoAction(instance.Guid);
      128. _PendingActions.Add(action);
      129. }
      130. action.Set(propInfo, instance, clone);
      131. }
      132. //--------------------------------------------------------------------------------------------------
      133. ///
      134. /// 添加数据块更改的撤销操作。
      135. ///
      136. /// 数据块实例。
      137. public void AddDataBlockChange(IUndoableDataBlob instance)
      138. {
      139. var action = (DataBlobUndoAction)_PendingActions.FirstOrDefault(a => a.InstanceGuid.Equals(instance.Guid) && a is DataBlobUndoAction);
      140. if (action != null)
      141. return;
      142. action = new DataBlobUndoAction(instance.Guid);
      143. if (action.Set(instance))
      144. {
      145. _PendingActions.Add(action);
      146. }
      147. }
      148. //--------------------------------------------------------------------------------------------------
      149. ///
      150. /// 添加拓扑更改的撤销操作。
      151. ///
      152. /// 拓扑操作类型。
      153. /// 容器实例。
      154. /// 拓扑实例。
      155. public void AddTopologyChange(TopologyAction topologyAction, IUndoableTopology container, Entity instance)
      156. {
      157. var action = new TopologyUndoAction(container.Guid);
      158. if (action.Set(instance, container, topologyAction))
      159. {
      160. _PendingActions.Add(action);
      161. }
      162. }
      163. //--------------------------------------------------------------------------------------------------
      164. ///
      165. /// 执行指定步数的撤销操作。
      166. ///
      167. /// 撤销步数。
      168. public void DoUndo(int steps)
      169. {
      170. while ((steps > 0) && (_UndoStack.Count > 0))
      171. {
      172. Restore(false);
      173. steps--;
      174. }
      175. Commit(true);
      176. RaisePropertyChanged();
      177. }
      178. //--------------------------------------------------------------------------------------------------
      179. ///
      180. /// 执行指定步数的重做操作。
      181. ///
      182. /// 重做步数。
      183. public void DoRedo(int steps)
      184. {
      185. while ((steps > 0) && (_RedoStack.Count > 0))
      186. {
      187. Restore(true);
      188. steps--;
      189. }
      190. Commit(false);
      191. RaisePropertyChanged();
      192. }
      193. //--------------------------------------------------------------------------------------------------
      194. ///
      195. /// 还原撤销操作。
      196. ///
      197. /// 指示是否从重做操作的栈中还原。
      198. void Restore(bool fromRedoStack)
      199. {
      200. var stack = fromRedoStack ? _RedoStack : _UndoStack;
      201. _IsRestoring = true;
      202. var actions = stack.Pop();
      203. foreach (var action in actions)
      204. {
      205. var instance = FindEntityInstance(action.InstanceGuid);
      206. // 如果未找到实例,则跳过,因为它必须是拓扑操作的一部分
      207. if(instance == null)
      208. continue;
      209. instance.OnBeforeUndo();
      210. action.Restore(instance, this);
      211. instance.OnAfterUndo();
      212. }
      213. _IsRestoring = false;
      214. }
      215. //--------------------------------------------------------------------------------------------------
      216. ///
      217. /// 根据实例的 GUID 查找实例。
      218. ///
      219. /// 实例的 GUID。
      220. /// 找到的实例,如果未找到则为 null。
      221. public Entity FindEntityInstance(Guid instanceGuid)
      222. {
      223. return _Document.FindInstance(instanceGuid);
      224. }
      225. }
      226. }

      逐行注释和说明如下:

      1. using 指令:引入了必要的命名空间。

      2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个类的定义。

      3. public class UndoHandler : BaseObject:定义了处理撤销和重做操作的管理器 UndoHandler,它继承自 BaseObject 类。

      4. public enum TopologyAction:定义了表示拓扑操作的枚举类型 TopologyAction,包括 Added、Removed 和 Moved。

      5. IUndoableTopology _Document:存储撤销处理器所属的文档。

      6. LimitedStack _RedoStackLimitedStack _UndoStack:分别用于存储重做操作和撤销操作的栈。

      7. List _PendingActions:存储待提交的撤销动作列表。

      8. public UndoHandler(IUndoableTopology document):构造函数,初始化撤销处理器。

      9. void RaisePropertyChanged():引发属性更改事件。

      10. public void Commit()void Commit(bool toRedoStack):提交挂起的撤销操作。

      11. public void AddPropertyChange(Entity instance, [CallerMemberName] string propertyName = "", object clone = null):添加属性更改的撤销操作。

      12. public void AddDataBlockChange(IUndoableDataBlob instance):添加数据块更改的撤销操作。

      13. public void AddTopologyChange(TopologyAction topologyAction, IUndoableTopology container, Entity instance):添加拓扑更改的撤销操作。

      14. public void DoUndo(int steps)public void DoRedo(int steps):执行指定步数的撤销和重做操作。

      15. void Restore(bool fromRedoStack):还原撤销操作。

      16. public Entity FindEntityInstance(Guid instanceGuid):根据实例的 GUID 查找实例。

      29.

      1. using System.IO;
      2. using System.Text;
      3. using Macad.Common;
      4. namespace Macad.Core
      5. {
      6. ///
      7. /// 抽象类,表示剪贴板操作。
      8. ///
      9. public abstract class Clipboard
      10. {
      11. ///
      12. /// 获取或设置当前剪贴板实例。
      13. ///
      14. public static Clipboard Current { get; protected set; }
      15. ///
      16. /// 检查剪贴板中是否包含指定格式的数据。
      17. ///
      18. /// 数据格式。
      19. /// 如果剪贴板中包含指定格式的数据,则为 true;否则为 false。
      20. public abstract bool ContainsData(in string format);
      21. ///
      22. /// 从剪贴板中获取指定格式的数据流。
      23. ///
      24. /// 数据格式。
      25. /// 数据流。
      26. public abstract MemoryStream GetDataStream(in string format);
      27. ///
      28. /// 将数据写入剪贴板。
      29. ///
      30. /// 数据格式。
      31. /// 数据流。
      32. public abstract void SetData(in string format, in MemoryStream data);
      33. //--------------------------------------------------------------------------------------------------
      34. ///
      35. /// 将字符串数据写入剪贴板。
      36. ///
      37. /// 数据格式。
      38. /// 字符串数据。
      39. public void SetData(in string format, in string data)
      40. {
      41. SetData(format, new MemoryStream(Encoding.Unicode.GetBytes(data)));
      42. }
      43. ///
      44. /// 从剪贴板中获取指定格式的数据并转换为字符串。
      45. ///
      46. /// 数据格式。
      47. /// 数据字符串。
      48. public string GetDataAsString(in string format)
      49. {
      50. var memstream = GetDataStream(format);
      51. return Encoding.Unicode.GetString(memstream.ToArray());
      52. }
      53. }
      54. }

      逐行注释和说明如下:

      1. using 指令:引入了必要的命名空间。

      2. namespace Macad.Core:定义了 Macad.Core 命名空间,包含了整个类的定义。

      3. public abstract class Clipboard:定义了抽象类 Clipboard,表示剪贴板操作。

      4. public static Clipboard Current { get; protected set; }:获取或设置当前剪贴板实例。

      5. public abstract bool ContainsData(in string format):抽象方法,检查剪贴板中是否包含指定格式的数据。

      6. public abstract MemoryStream GetDataStream(in string format):抽象方法,从剪贴板中获取指定格式的数据流。

      7. public abstract void SetData(in string format, in MemoryStream data):抽象方法,将数据写入剪贴板。

      8. public void SetData(in string format, in string data):将字符串数据写入剪贴板。

      9. public string GetDataAsString(in string format):从剪贴板中获取指定格式的数据并转换为字符串。

    17. 相关阅读:
      HEVC熵编码核心点介绍
      shell脚本任务
      PAM从入门到精通(二)
      线上问题处理案例:出乎意料的数据库连接池
      AS400 API 从零到一的整个历程
      测试猿送分题: 电商项目如何测试?聪明人这么回答
      CSS复合选择器(二)
      简单学懂链式编程
      【EMQX】 Spring Cloud 集成MQTT并异步入库(mongodb)
      4.无约束优化问题基本公式
    18. 原文地址:https://blog.csdn.net/m0_53082780/article/details/136221116