本文主要是介绍macad.interaction解析workspace,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
1.
using Macad.Occt; // 引入Macad.Occt命名空间,提供对OpenCascade CAD内核的访问namespace Macad.Interaction
{public sealed class AndSelectionFilter : ISelectionFilter // 定义名为AndSelectionFilter的类,实现了ISelectionFilter接口{readonly ISelectionFilter[] _Filters; // 声明一个只读字段_Filters,类型为ISelectionFilter数组//--------------------------------------------------------------------------------------------------public AndSelectionFilter(params ISelectionFilter[] filters) // 构造函数,接受可变数量的ISelectionFilter参数{_Filters = filters; // 将传入的参数赋值给_Filters字段}//--------------------------------------------------------------------------------------------------SelectMgr_Filter ISelectionFilter.GetNativeFilter() // 实现接口方法GetNativeFilter,返回SelectMgr_Filter对象{var andFilter = new SelectMgr_AndFilter(); // 创建SelectMgr_AndFilter对象foreach (var filter in _Filters) // 遍历_Filters数组中的每个过滤器{andFilter.Add(filter.GetNativeFilter()); // 将每个过滤器的原生过滤器添加到andFilter中}return andFilter; // 返回andFilter对象}//--------------------------------------------------------------------------------------------------}
}
总结:这段代码定义了一个名为 AndSelectionFilter
的类,用于创建多个选择过滤器的逻辑与(AND)组合。通过传入不同的选择过滤器,可以根据多个条件进行对象的选择。
2.
using System; // 引入System命名空间,提供基本的系统功能
using Macad.Occt; // 引入Macad.Occt命名空间,提供对OpenCascade CAD内核的访问namespace Macad.Interaction
{public sealed class EdgeSelectionFilter : ISelectionFilter // 定义名为EdgeSelectionFilter的类,实现了ISelectionFilter接口{public enum EdgeType // 定义名为EdgeType的枚举,表示边的类型{Any, // 任意类型的边Line, // 直线Circle, // 圆}//--------------------------------------------------------------------------------------------------readonly EdgeType _EdgeType = EdgeType.Any; // 声明只读字段_EdgeType,类型为EdgeType,默认值为Any//--------------------------------------------------------------------------------------------------public EdgeSelectionFilter(EdgeType edgeType) // 构造函数,接受EdgeType参数{_EdgeType = edgeType; // 将传入的参数赋值给_EdgeType字段}//--------------------------------------------------------------------------------------------------SelectMgr_Filter ISelectionFilter.GetNativeFilter() // 实现接口方法GetNativeFilter,返回SelectMgr_Filter对象{return new StdSelect_EdgeFilter(_GetNativeTypeOfEdge(_EdgeType)); // 返回一个基于_EdgeType的原生边过滤器}//--------------------------------------------------------------------------------------------------StdSelect_TypeOfEdge _GetNativeTypeOfEdge(EdgeSelectionFilter.EdgeType type) // 定义一个私有方法,将EdgeType转换为StdSelect_TypeOfEdge{switch (type) // 根据传入的EdgeType类型进行判断{case EdgeType.Any: // 如果是Any类型的边return StdSelect_TypeOfEdge.AnyEdge; // 返回AnyEdge类型case EdgeType.Line: // 如果是Line类型的边return StdSelect_TypeOfEdge.Line; // 返回Line类型case EdgeType.Circle: // 如果是Circle类型的边return StdSelect_TypeOfEdge.Circle; // 返回Circle类型default: // 如果传入的类型不是上述三种之一throw new ArgumentOutOfRangeException(nameof(type), type, null); // 抛出参数越界异常}}}
}
总结:这段代码定义了一个名为 EdgeSelectionFilter
的类,用于创建用于选择边的选择过滤器。该类包含一个枚举 EdgeType
,用于表示边的不同类型,包括任意类型、直线和圆。通过传入不同的 EdgeType
,可以创建对应类型的边选择过滤器。
3.
using System; // 引入System命名空间,提供基本的系统功能
using Macad.Occt; // 引入Macad.Occt命名空间,提供对OpenCascade CAD内核的访问namespace Macad.Interaction
{public sealed class FaceSelectionFilter : ISelectionFilter // 定义名为FaceSelectionFilter的类,实现了ISelectionFilter接口{public enum FaceType // 定义名为FaceType的枚举,表示面的类型{Any, // 任意类型的面Plane, // 平面Cylinder, // 圆柱面Sphere, // 球面Torus, // 圆环面Revolution, // 旋转面Cone // 圆锥面}//--------------------------------------------------------------------------------------------------readonly FaceType _FaceType = FaceType.Any; // 声明只读字段_FaceType,类型为FaceType,默认值为Any//--------------------------------------------------------------------------------------------------public FaceSelectionFilter(FaceType faceType) // 构造函数,接受FaceType参数{_FaceType = faceType; // 将传入的参数赋值给_FaceType字段}//--------------------------------------------------------------------------------------------------SelectMgr_Filter ISelectionFilter.GetNativeFilter() // 实现接口方法GetNativeFilter,返回SelectMgr_Filter对象{return new StdSelect_FaceFilter(_GetNativeTypeOfFace(_FaceType)); // 返回一个基于_FaceType的原生面过滤器}//--------------------------------------------------------------------------------------------------StdSelect_TypeOfFace _GetNativeTypeOfFace(FaceType type) // 定义一个私有方法,将FaceType转换为StdSelect_TypeOfFace{switch (type) // 根据传入的FaceType类型进行判断{case FaceType.Any: // 如果是Any类型的面return StdSelect_TypeOfFace.AnyFace; // 返回AnyFace类型case FaceType.Plane: // 如果是Plane类型的面return StdSelect_TypeOfFace.Plane; // 返回Plane类型case FaceType.Cylinder: // 如果是Cylinder类型的面return StdSelect_TypeOfFace.Cylinder; // 返回Cylinder类型case FaceType.Sphere: // 如果是Sphere类型的面return StdSelect_TypeOfFace.Sphere; // 返回Sphere类型case FaceType.Torus: // 如果是Torus类型的面return StdSelect_TypeOfFace.Torus; // 返回Torus类型case FaceType.Revolution: // 如果是Revolution类型的面return StdSelect_TypeOfFace.Revol; // 返回Revol类型case FaceType.Cone: // 如果是Cone类型的面return StdSelect_TypeOfFace.Cone; // 返回Cone类型default: // 如果传入的类型不是上述七种之一throw new ArgumentOutOfRangeException(nameof(type), type, null); // 抛出参数越界异常}}}
}
总结:这段代码定义了一个名为 FaceSelectionFilter
的类,用于创建用于选择面的选择过滤器。该类包含一个枚举 FaceType
,用于表示面的不同类型,包括任意类型、平面、圆柱面、球面、圆环面、旋转面和圆锥面。通过传入不同的 FaceType
,可以创建对应类型的面选择过滤器。
4.
using System.Collections.Generic; // 引入System.Collections.Generic命名空间,提供泛型集合类的支持
using System.Linq; // 引入System.Linq命名空间,提供LINQ查询功能
using Macad.Common; // 引入Macad.Common命名空间
using Macad.Interaction.Visual; // 引入Macad.Interaction.Visual命名空间
using Macad.Occt; // 引入Macad.Occt命名空间
using Macad.Occt.Extensions; // 引入Macad.Occt.Extensions命名空间namespace Macad.Interaction
{public class InstanceSelectionFilter : ISelectionFilter // 定义名为InstanceSelectionFilter的类,实现了ISelectionFilter接口{readonly AIS_InteractiveObject[] _Instances; // 声明只读字段_Instances,类型为AIS_InteractiveObject数组,用于存储实例对象//--------------------------------------------------------------------------------------------------public InstanceSelectionFilter(IEnumerable<AIS_InteractiveObject> instances) // 构造函数,接受AIS_InteractiveObject类型的集合作为参数{_Instances = instances.ToArray(); // 将传入的实例对象集合转换为数组并赋值给_Instances字段}//--------------------------------------------------------------------------------------------------public InstanceSelectionFilter(IEnumerable<VisualObject> instances) // 构造函数,接受VisualObject类型的集合作为参数{_Instances = instances.Select(obj => obj.AisObject).ToArray(); // 将传入的VisualObject集合的AisObject属性提取出来转换为数组并赋值给_Instances字段}//--------------------------------------------------------------------------------------------------SelectMgr_Filter ISelectionFilter.GetNativeFilter() // 实现接口方法GetNativeFilter,返回SelectMgr_Filter对象{AISX_InstanceFilter filter = new(); // 创建AISX_InstanceFilter对象_Instances.ForEach(filter.Add); // 将_Instances数组中的每个元素添加到过滤器中return filter; // 返回过滤器}}
}
总结:这段代码定义了一个名为 InstanceSelectionFilter
的类,用于创建用于选择实例的选择过滤器。该类实现了 ISelectionFilter
接口。它包含两个构造函数,一个接受 IEnumerable<AIS_InteractiveObject>
类型的实例集合,另一个接受 IEnumerable<VisualObject>
类型的实例集合。通过这两个构造函数,可以传入不同类型的实例对象集合来创建对应的选择过滤器。然后,通过实现 GetNativeFilter
方法,返回一个 SelectMgr_Filter
对象,其中包含了要选择的实例对象。
5.
using Macad.Occt; // 引入Macad.Occt命名空间namespace Macad.Interaction
{public interface ISelectionFilter // 定义名为ISelectionFilter的接口{SelectMgr_Filter GetNativeFilter(); // 声明一个返回SelectMgr_Filter类型的GetNativeFilter方法}
}
总结:这段代码定义了一个名为 ISelectionFilter
的接口,其中包含一个方法 GetNativeFilter
,用于获取原生的选择过滤器。该接口用于定义选择过滤器的标准,以便在交互操作中使用不同的过滤器实现。
6.
using Macad.Occt; // 引入Macad.Occt命名空间namespace Macad.Interaction
{public sealed class OrSelectionFilter : ISelectionFilter // 定义名为OrSelectionFilter的类,实现ISelectionFilter接口{readonly ISelectionFilter[] _Filters; // 声明一个名为_Filters的只读ISelectionFilter数组字段//--------------------------------------------------------------------------------------------------public OrSelectionFilter(params ISelectionFilter[] filters) // 构造函数,接受一个可变长度的ISelectionFilter数组作为参数{_Filters = filters; // 将参数赋值给_Filters字段}//--------------------------------------------------------------------------------------------------SelectMgr_Filter ISelectionFilter.GetNativeFilter() // 实现接口中的GetNativeFilter方法{var andFilter = new SelectMgr_OrFilter(); // 创建SelectMgr_OrFilter实例foreach (var filter in _Filters) // 遍历_Filters数组中的每个选择过滤器{andFilter.Add(filter.GetNativeFilter()); // 将每个选择过滤器的原生过滤器添加到orFilter中}return andFilter; // 返回组合后的orFilter}}
}
总结:这段代码定义了一个名为 OrSelectionFilter
的类,实现了 ISelectionFilter
接口。该类用于创建一个“或”组合的选择过滤器,即如果任何一个子过滤器返回 true,则整体条件为 true。
7.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Remoting;
using Macad.Interaction.Visual;
using Macad.Core;
using Macad.Core.Shapes;
using Macad.Core.Topology;
using Macad.Occt;namespace Macad.Interaction
{public sealed class SelectionContext : IDisposable{[Flags]public enum Options{None = 0,IncludeAll = 1 << 0,NewSelectedList = 1 << 1,}//--------------------------------------------------------------------------------------------------public List<InteractiveEntity> SelectedEntities { get; } // 存储选中的实体的列表readonly WorkspaceController _WorkspaceController; // 工作空间控制器readonly HashSet<VisualObject> _InOrExcludedShapes = new(); // 存储要包含或排除的可视对象的哈希集合readonly Options _Options; // 选择上下文的选项bool _IsActive = false; // 选择上下文是否处于活动状态SubshapeTypes _SubshapeTypes; // 子形状的类型ISelectionFilter _SelectionFilter; // 选择过滤器//--------------------------------------------------------------------------------------------------// 构造函数,接受工作空间控制器和选项作为参数public SelectionContext(WorkspaceController workspaceController, Options options){_WorkspaceController = workspaceController;_Options = options;if (_Options.HasFlag(Options.NewSelectedList)) // 如果选项中包含NewSelectedList,则创建一个新的选中实体列表{SelectedEntities = new List<InteractiveEntity>();}}//--------------------------------------------------------------------------------------------------public void Dispose(){if (_IsActive) // 如果选择上下文处于活动状态{VisualObject.AisObjectChanged -= _VisualObject_AisObjectChanged; // 取消注册VisualObject.AisObjectChanged事件的处理程序_IsActive = false; // 将活动状态标志设置为false}}//--------------------------------------------------------------------------------------------------// 设置子形状选择的类型public void SetSubshapeSelection(SubshapeTypes enabledTypes){if (_SubshapeTypes == enabledTypes)return;_SubshapeTypes = enabledTypes; // 设置子形状的类型_RaiseParametersChanged(); // 触发参数已更改事件}//--------------------------------------------------------------------------------------------------// 设置选择过滤器public void SetSelectionFilter(ISelectionFilter filter){_SelectionFilter = filter; // 设置选择过滤器_UpdateFilter(); // 更新过滤器}//--------------------------------------------------------------------------------------------------#region In-/Exclusion// 包含特定实体public void Include(InteractiveEntity entity){var visShape = _WorkspaceController.VisualObjects.Get(entity, true); // 获取与实体关联的可视对象if(visShape != null)Include(visShape); // 调用重载的Include方法}//--------------------------------------------------------------------------------------------------// 包含特定可视对象public void Include(VisualObject visObject){if (_Options.HasFlag(Options.IncludeAll)) // 如果选项中包含IncludeAll,则将要排除的可视对象从_InOrExcludedShapes集合中移除{if (_InOrExcludedShapes.Contains(visObject)){_InOrExcludedShapes.Remove(visObject);_RaiseParametersChanged(); // 触发参数已更改事件}return;}if (_InOrExcludedShapes.Contains(visObject)) // 如果_InOrExcludedShapes集合中已包含可视对象,则直接返回return;_InOrExcludedShapes.Add(visObject); // 否则将可视对象添加到_InOrExcludedShapes集合中_RaiseParametersChanged(); // 触发参数已更改事件}//--------------------------------------------------------------------------------------------------// 排除特定实体public void Exclude(InteractiveEntity entity){var visObject = _WorkspaceController.VisualObjects.Get(entity, true); // 获取与实体关联的可视对象if (visObject != null)Exclude(visObject); // 调用重载的Exclude方法}//--------------------------------------------------------------------------------------------------// 排除特定可视对象public void Exclude(VisualObject visObject){if (!_Options.HasFlag(Options.IncludeAll)) // 如果选项中不包含IncludeAll,则将要排除的可视对象添加到_InOrExcludedShapes集合中{if (_InOrExcludedShapes.Contains(visObject)){_InOrExcludedShapes.Remove(visObject);_RaiseParametersChanged(); // 触发参数已更改事件}return;}if (_InOrExcludedShapes.Contains(visObject)) // 如果_InOrExcludedShapes集合中已包含可视对象,则直接返回return;_InOrExcludedShapes.Add(visObject); // 否则将可视对象添加到_InOrExcludedShapes集合中_RaiseParametersChanged(); // 触发参数已更改事件}//--------------------------------------------------------------------------------------------------#endregion#region AIS Context Control// 激活选择上下文public void Activate(){Debug.Assert(!_IsActive); // 确保选择上下文当前处于非活动状态VisualObject.AisObjectChanged += _VisualObject_AisObjectChanged; // 注册VisualObject.AisObjectChanged事件的处理程序_UpdateFilter(); // 更新过滤器_IsActive = true; // 将活动状态标志设置为true}//--------------------------------------------------------------------------------------------------// 停用选择上下文public void DeActivate(){if (!_IsActive) // 如果选择上下文不处于活动状态,则直接返回return;VisualObject.AisObjectChanged -= _VisualObject_AisObjectChanged; // 取消注册VisualObject.AisObjectChanged事件的处理程序var aisContext = _WorkspaceController?.Workspace?.AisContext; // 获取AIS上下文aisContext?.RemoveFilters(); // 移除所有过滤器_IsActive = false; // 将活动状态标志设置为false}//--------------------------------------------------------------------------------------------------// 更新AIS上下文public void UpdateAis(){// 更新形状var visShapes = _WorkspaceController.VisualObjects.GetAll(); // 获取所有可视对象foreach (var visualShape in visShapes){_UpdateShape(visualShape); // 更新形状}}//--------------------------------------------------------------------------------------------------// 更新特定可视对象的形状public void UpdateShape(VisualObject visualObject){_UpdateShape(visualObject); // 更新形状}//--------------------------------------------------------------------------------------------------// 更新形状void _UpdateShape(VisualObject visualObject){var aisContext = _WorkspaceController?.Workspace?.AisContext; // 获取AIS上下文var aisObject = visualObject?.AisObject; // 获取可视对象关联的对象if (aisContext == null || aisObject == null) // 如果AIS上下文或关联的对象为空,则直接返回return;bool includeByDefault = _Options.HasFlag(Options.IncludeAll); // 按默认情况是否包含bool isInOrExcluded = _InOrExcludedShapes.Contains(visualObject); // 是否在包含或排除列表中bool activate = includeByDefault ? !isInOrExcluded : isInOrExcluded; // 是否应该激活if (visualObject.IsSelectable) // 如果可视对象是可选择的{// 获取已激活的模式var colActivatedModes = new TColStd_ListOfInteger(); // 创建一个整型列表aisContext.ActivatedModes(aisObject, colActivatedModes); // 获取已激活的模式var activatedModes = colActivatedModes.ToList(); // 将列表转换为列表// 枚举所有请求的模式var modesToBeActivated = new bool[5]; // 创建一个包含5个布尔值的数组var snapHandler = _WorkspaceController.SnapHandler; // 获取工作空间的SnapHandlermodesToBeActivated[0] = activate && _SubshapeTypes == SubshapeTypes.None; // 如果应激活且子形状类型为None,则激活modesToBeActivated[SubshapeType.Vertex.ToAisSelectionMode()] = activate && _SubshapeTypes.HasFlag(SubshapeTypes.Vertex) // 如果应激活且子形状类型为Vertex,则激活|| snapHandler.NeedActiveSubshapes(SubshapeType.Vertex); // 或者如果SnapHandler需要激活子形状,则激活modesToBeActivated[SubshapeType.Edge.ToAisSelectionMode()] = activate && _SubshapeTypes.HasFlag(SubshapeTypes.Edge) // 如果应激活且子形状类型为Edge,则激活|| snapHandler.NeedActiveSubshapes(SubshapeType.Edge); // 或者如果SnapHandler需要激活子形状,则激活modesToBeActivated[SubshapeType.Wire.ToAisSelectionMode()] = activate && _SubshapeTypes.HasFlag(SubshapeTypes.Wire) // 如果应激活且子形状类型为Wire,则激活|| snapHandler.NeedActiveSubshapes(SubshapeType.Wire); // 或者如果SnapHandler需要激活子形状,则激活modesToBeActivated[SubshapeType.Face.ToAisSelectionMode()] = activate && _SubshapeTypes.HasFlag(SubshapeTypes.Face) // 如果应激活且子形状类型为Face,则激活|| snapHandler.NeedActiveSubshapes(SubshapeType.Face); // 或者如果SnapHandler需要激活子形状,则激活// 停用未请求的所有模式foreach (var mode in activatedModes){if(!modesToBeActivated[mode])aisContext.SetSelectionModeActive(aisObject, mode, false, AIS_SelectionModesConcurrency.Multiple); // 设置选择模式为不活跃}// 激活所有请求的模式for (int mode = 0; mode < 5; mode++){if(modesToBeActivated[mode])aisContext.SetSelectionModeActive(aisObject, mode, true, AIS_SelectionModesConcurrency.Multiple); // 设置选择模式为活跃}}else{aisContext.Deactivate(aisObject); // 如果不可选择,则停用可视对象}}//--------------------------------------------------------------------------------------------------// 当可视对象的AIS对象发生变化时调用void _VisualObject_AisObjectChanged(VisualObject visualObject){if (visualObject.AisObject != null){UpdateShape(visualObject); // 更新形状}}//--------------------------------------------------------------------------------------------------#endregion#region Eventspublic delegate void ParametersChangedEventHandler(SelectionContext selectionContext); // 参数更改事件处理程序委托//--------------------------------------------------------------------------------------------------public event ParametersChangedEventHandler ParametersChanged; // 参数更改事件//--------------------------------------------------------------------------------------------------void _RaiseParametersChanged(){ParametersChanged?.Invoke(this); // 触发参数更改事件}#endregion}
}
总结:这段代码定义了一个名为 SelectionContext
的类,用于管理交互式对象的选择上下文。它包含了选择的实体列表、工作空间控制器、选项、子形状类型、选择过滤器等信息。该类提供了一系列方法用于激活、停用选择上下文,设置子形状选择类型,设置选择过滤器,包含或排除特定实体或可视对象,并更新AIS上下文中的形状。
8.
namespace Macad.Interaction
{public static class SelectionFilterExtensions{// 将多个选择过滤器组合成逻辑或操作的选择过滤器public static ISelectionFilter Or(this ISelectionFilter filter, params ISelectionFilter[] others){ISelectionFilter[] filters = new ISelectionFilter[others.Length + 1]; // 创建一个长度为其他选择过滤器数量加1的数组filters[0] = filter; // 将当前选择过滤器作为数组的第一个元素others.CopyTo(filters, 1); // 将其他选择过滤器复制到数组中return new OrSelectionFilter(filters); // 返回一个逻辑或操作的选择过滤器} //--------------------------------------------------------------------------------------------------// 将多个选择过滤器组合成逻辑与操作的选择过滤器public static ISelectionFilter And(this ISelectionFilter filter, params ISelectionFilter[] others){ISelectionFilter[] filters = new ISelectionFilter[others.Length + 1]; // 创建一个长度为其他选择过滤器数量加1的数组filters[0] = filter; // 将当前选择过滤器作为数组的第一个元素others.CopyTo(filters, 1); // 将其他选择过滤器复制到数组中return new AndSelectionFilter(filters); // 返回一个逻辑与操作的选择过滤器}//--------------------------------------------------------------------------------------------------}
}
总结:SelectionFilterExtensions
类定义了两个扩展方法 Or
和 And
,用于将多个选择过滤器组合成逻辑或操作和逻辑与操作的选择过滤器。这些方法通过创建 OrSelectionFilter
和 AndSelectionFilter
类的实例来实现组合操作。
9.
namespace Macad.Interaction
{public sealed class SelectionManager : IDisposable{// 选择模式枚举public enum SelectionMode{Exclusive, // 排他模式Add, // 添加模式Toggle // 切换模式}//--------------------------------------------------------------------------------------------------// 已选择的实体列表public List<InteractiveEntity> SelectedEntities{get{for (var i = _SelectionContexts.Count - 1; i >= 0; i--){var sel = _SelectionContexts[i].SelectedEntities;if (sel != null)return sel;}return _BaseContext.SelectedEntities;}}//--------------------------------------------------------------------------------------------------// 静态空列表static readonly List<InteractiveEntity> _EmptyList = new(0);readonly WorkspaceController _WorkspaceController;//--------------------------------------------------------------------------------------------------// 构造函数public SelectionManager(WorkspaceController workspaceController){_WorkspaceController = workspaceController;_BaseContext = new SelectionContext(workspaceController, SelectionContext.Options.IncludeAll | SelectionContext.Options.NewSelectedList);_BaseContext.Activate();Entity.EntityRemoved += _Entity_EntityRemoved;}//--------------------------------------------------------------------------------------------------// 销毁方法public void Dispose(){Entity.EntityRemoved -= _Entity_EntityRemoved;_BaseContext.Dispose();SelectedEntities.Clear();}//--------------------------------------------------------------------------------------------------#region Selection//--------------------------------------------------------------------------------------------------// 清除选择public void ClearSelection(){ChangeEntitySelection(_EmptyList, SelectedEntities);}//--------------------------------------------------------------------------------------------------// 选择实体public void SelectEntity(InteractiveEntity entity, SelectionMode mode = SelectionMode.Exclusive){SelectEntities(new []{entity}, mode);}//--------------------------------------------------------------------------------------------------// 选择多个实体public void SelectEntities(IEnumerable<InteractiveEntity> entities, SelectionMode mode = SelectionMode.Exclusive){List<InteractiveEntity> toSelect = null;List<InteractiveEntity> toDeselect = null;entities ??= _EmptyList;switch (mode){case SelectionMode.Exclusive:toSelect = entities.Except(SelectedEntities).ToList();toDeselect = SelectedEntities.Except(entities).ToList();break;case SelectionMode.Add:toSelect = entities.Except(SelectedEntities).ToList();toDeselect = _EmptyList;break;case SelectionMode.Toggle:toSelect = entities.Except(SelectedEntities).ToList();toDeselect = SelectedEntities.Intersect(entities).ToList();break;}ChangeEntitySelection(toSelect, toDeselect);}//--------------------------------------------------------------------------------------------------// 取消选择实体public void DeselectEntity(InteractiveEntity entity){DeselectEntities(new []{entity});}//--------------------------------------------------------------------------------------------------// 取消选择多个实体public void DeselectEntities(IEnumerable<InteractiveEntity> entities){if (entities == null)return;List<InteractiveEntity> toDeselect = entities.Intersect(SelectedEntities).ToList();if (toDeselect.Count == 0)return;ChangeEntitySelection(_EmptyList, toDeselect);}//--------------------------------------------------------------------------------------------------// 更改实体选择[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]public void ChangeEntitySelection(IEnumerable<InteractiveEntity> entitiesToSelect, IEnumerable<InteractiveEntity> entitiesToUnSelect){if (_RaiseSelectionChanging(entitiesToSelect, entitiesToUnSelect))return;entitiesToUnSelect.ForEach(_RemoveEntityFromSelectionList);entitiesToSelect.ForEach(_AddEntityToSelectionList);_SyncToAisSelection();_RaiseSelectionChanged();}//--------------------------------------------------------------------------------------------------// 将实体添加到选择列表void _AddEntityToSelectionList(InteractiveEntity entity){if (entity == null || SelectedEntities.Contains(entity))return;SelectedEntities.Add(entity);}//--------------------------------------------------------------------------------------------------// 从选择列表中移除实体void _RemoveEntityFromSelectionList(InteractiveEntity entity){if (entity == null)return;SelectedEntities.Remove(entity);}//--------------------------------------------------------------------------------------------------// 从 AIS 选择中同步到选择列表void _SyncFromAisSelection(){var aisContext = _WorkspaceController.Workspace.AisContext;var aisSelected = new List<InteractiveEntity>();aisContext.InitSelected();while (aisContext.MoreSelected()){var selected = _WorkspaceController.VisualObjects.GetEntity(aisContext.SelectedInteractive());if (selected != null)aisSelected.Add(selected);aisContext.NextSelected();}var toSelect = aisSelected.Except(SelectedEntities).ToArray();var toDeselect = SelectedEntities.Except(aisSelected).ToArray();if (_RaiseSelectionChanging(toSelect, toDeselect))return;foreach (var entity in toDeselect){_RemoveEntityFromSelectionList(entity);}foreach (var entity in toSelect){_AddEntityToSelectionList(entity);}_RaiseSelectionChanged();}//--------------------------------------------------------------------------------------------------// 从选择列表同步到 AIS 选择[SuppressMessage("ReSharper", "PossibleMultipleEnumeration")]void _SyncToAisSelection(){var aisContext = _WorkspaceController.Workspace.AisContext;_WorkspaceController.VisualObjects.UpdateInvalidatedEntities();aisContext.ClearSelected(false);var aisObjToSelect = SelectedEntities.Select(entity => _WorkspaceController.VisualObjects.Get(entity)?.AisObject).Where(vo => vo != null);foreach (var selected in aisObjToSelect){aisContext.AddOrRemoveSelected(selected, false);}aisContext.UpdateSelected(false);aisContext.ClearDetected(false);}//--------------------------------------------------------------------------------------------------// 选择变更取消事件参数类public class SelectionChangingCancelEventArgs : CancelEventArgs{public IEnumerable<InteractiveEntity> EntitiesToUnSelect { get; }public IEnumerable<InteractiveEntity> EntitiesToSelect { get; }public SelectionChangingCancelEventArgs(IEnumerable<InteractiveEntity> entitiesToSelect, IEnumerable<InteractiveEntity> entitiesToUnSelect){EntitiesToSelect = entitiesToSelect ?? new List<InteractiveEntity>();EntitiesToUnSelect = entitiesToUnSelect ?? new List<InteractiveEntity>();}}//--------------------------------------------------------------------------------------------------// 选择变更事件委托public delegate void SelectionChangingEventHandler(SelectionManager selectionManager, SelectionChangingCancelEventArgs eventArgs);//--------------------------------------------------------------------------------------------------// 选择变更事件public event SelectionChangingEventHandler SelectionChanging;//--------------------------------------------------------------------------------------------------// 触发选择变更事件bool _RaiseSelectionChanging(IEnumerable<InteractiveEntity> entitiesToSelect, IEnumerable<InteractiveEntity> entitiesToUnSelect){if (SelectionChanging != null){var eventArgs = new SelectionChangingCancelEventArgs(entitiesToSelect, entitiesToUnSelect);SelectionChanging.Invoke(this, eventArgs);return eventArgs.Cancel;}return false;}//--------------------------------------------------------------------------------------------------// 选择变更完成事件委托public delegate void SelectionChangedEventHandler(SelectionManager selectionManager);//--------------------------------------------------------------------------------------------------// 选择变更完成事件public event SelectionChangedEventHandler SelectionChanged;//--------------------------------------------------------------------------------------------------// 触发选择变更完成事件void _RaiseSelectionChanged(){SelectionChanged?.Invoke(this);}//--------------------------------------------------------------------------------------------------// 实体被移除事件处理方法void _Entity_EntityRemoved(Entity entity){if (!(entity is InteractiveEntity interactiveEntity))return;// Deselect_RemoveEntityFromSelectionList(interactiveEntity);_RaiseSelectionChanged();}//--------------------------------------------------------------------------------------------------#endregion#region SelectionContextreadonly SelectionContext _BaseContext;readonly List<SelectionContext> _SelectionContexts = new List<SelectionContext>();// 当前上下文属性public SelectionContext CurrentContext { get { return _SelectionContexts.LastOrDefault(); } }bool _ContextUpdatePending = false;//--------------------------------------------------------------------------------------------------// 打开新的选择上下文public SelectionContext OpenContext(SelectionContext.Options options = SelectionContext.Options.None){(CurrentContext ?? _BaseContext).DeActivate();var context = new SelectionContext(_WorkspaceController, options);context.ParametersChanged += _Context_ParametersChanged;_SelectionContexts.Add(context);context.Activate();_SyncToAisSelection();Invalidate();return context;}//--------------------------------------------------------------------------------------------------// 关闭选择上下文public void CloseContext(SelectionContext context){if (_SelectionContexts.Contains(context)){bool wasCurrent = context == CurrentContext;context.DeActivate();context.ParametersChanged -= _Context_ParametersChanged;_SelectionContexts.Remove(context);if (wasCurrent){(CurrentContext ?? _BaseContext).Activate();_SyncToAisSelection();}}Invalidate();}//--------------------------------------------------------------------------------------------------// 上下文参数变更事件处理方法void _Context_ParametersChanged(SelectionContext selectionContext){Invalidate();}//--------------------------------------------------------------------------------------------------// 无效化方法public void Invalidate(){_ContextUpdatePending = true;}//--------------------------------------------------------------------------------------------------// 更新方法public void Update(){if (!_ContextUpdatePending)return;var ctx = CurrentContext ?? _BaseContext;ctx.UpdateAis();_ContextUpdatePending = false;}//--------------------------------------------------------------------------------------------------#endregion}
}
总结:SelectionManager
类实现了选择管理器,用于管理交互式实体的选择操作。它包括选择模式、选择列表的操作、选择上下文的管理以及与AIS上下文的同步等功能。通过事件 SelectionChanging
和 SelectionChanged
实现了选择变更前后的通知。同时,通过 SelectionContext
类管理了多个选择上下文,支持在不同的选择模式下进行选择操作。
10.
using Macad.Occt;namespace Macad.Interaction
{// 选择标识结构体public struct SelectionSignature{// 交互式对象类型public AIS_KindOfInteractive Kind { get; }// 签名public int Signature { get; }//--------------------------------------------------------------------------------------------------// 构造函数public SelectionSignature(AIS_KindOfInteractive kind, int signature){Kind = kind;Signature = signature;}}
}
总结:SelectionSignature
结构体用于表示选择的标识,其中包括交互式对象的类型和签名信息。
11.
using Macad.Occt;namespace Macad.Interaction
{// 签名选择过滤器类public class SignatureSelectionFilter : ISelectionFilter{// 选择标识readonly SelectionSignature _Signature;//--------------------------------------------------------------------------------------------------// 构造函数,通过传入交互式对象类型和签名来创建过滤器public SignatureSelectionFilter(AIS_KindOfInteractive kind, int signature){_Signature = new(kind, signature);}//--------------------------------------------------------------------------------------------------// 构造函数,通过传入选择标识对象来创建过滤器public SignatureSelectionFilter(SelectionSignature signature){_Signature = signature;}//--------------------------------------------------------------------------------------------------// 获取本地过滤器SelectMgr_Filter ISelectionFilter.GetNativeFilter(){return new AIS_SignatureFilter(_Signature.Kind, _Signature.Signature);}}
}
总结:SignatureSelectionFilter
类是一个实现了 ISelectionFilter
接口的选择过滤器,用于根据选择标识来过滤选择的交互式对象。
12.
using Macad.Core;
using Macad.Occt;namespace Macad.Interaction
{// 子形状类型选择过滤器类public sealed class SubshapeTypeSelectionFilter : ISelectionFilter{// 子形状类型readonly SubshapeType _SubshapeType;//--------------------------------------------------------------------------------------------------// 构造函数,通过传入子形状类型来创建过滤器public SubshapeTypeSelectionFilter(SubshapeType subshapeType){_SubshapeType = subshapeType;}//--------------------------------------------------------------------------------------------------// 获取本地过滤器SelectMgr_Filter ISelectionFilter.GetNativeFilter(){return new StdSelect_ShapeTypeFilter(_SubshapeType.ToTopAbs());}//--------------------------------------------------------------------------------------------------}
}
总结:SubshapeTypeSelectionFilter
类是一个实现了 ISelectionFilter
接口的选择过滤器,用于根据子形状类型来过滤选择的形状对象。
13.
using Macad.Occt;namespace Macad.Interaction
{// 顶点选择过滤器类public sealed class VertexSelectionFilter : ISelectionFilter{// 顶点类型枚举public enum VertexType{All // 所有类型的顶点}//--------------------------------------------------------------------------------------------------// 顶点类型,默认为所有类型的顶点readonly VertexType _VertexType = VertexType.All;//--------------------------------------------------------------------------------------------------// 构造函数,通过传入顶点类型来创建过滤器public VertexSelectionFilter(VertexType vertexType){_VertexType = vertexType;}//--------------------------------------------------------------------------------------------------// 获取本地过滤器SelectMgr_Filter ISelectionFilter.GetNativeFilter(){return new StdSelect_ShapeTypeFilter(TopAbs_ShapeEnum.VERTEX);}//--------------------------------------------------------------------------------------------------}
}
总结:VertexSelectionFilter
类是一个实现了 ISelectionFilter
接口的选择过滤器,用于过滤选择的顶点对象。目前仅支持过滤所有类型的顶点。
14.
using System.ComponentModel;
using Macad.Interaction.Editors.Shapes;
using Macad.Common;
using Macad.Common.Serialization;namespace Macad.Interaction
{// 编辑器状态类,继承自 BaseObject[SerializeType]public class EditorState : BaseObject{#region Active Tools// 当前激活的工具名称public string ActiveTool{get { return _ActiveTool; }set{RaisePropertyChanged();}}string _ActiveTool;//--------------------------------------------------------------------------------------------------// 更新当前激活的工具void _UpdateActiveTool(Tool tool){_ActiveTool = tool?.Id ?? "";RaisePropertyChanged(nameof(ActiveTool));_UpdateSketchEditTool(tool as SketchEditorTool);}//--------------------------------------------------------------------------------------------------#endregion#region Sketch//--------------------------------------------------------------------------------------------------// 是否显示草图组public bool SketchGroupVisible{get { return _SketchGroupVisible; }private set{_SketchGroupVisible = value;RaisePropertyChanged();}}bool _SketchGroupVisible;//--------------------------------------------------------------------------------------------------// 当前激活的草图工具名称public string ActiveSketchTool{get { return _ActiveSketchTool; }private set{_ActiveSketchTool = value;RaisePropertyChanged();}}string _ActiveSketchTool;//--------------------------------------------------------------------------------------------------// 是否启用草图裁剪平面public bool SketchClipPlaneEnabled{get { return _CurrentSketchEditorTool?.ClipPlaneEnabled ?? false; }}//--------------------------------------------------------------------------------------------------SketchEditorTool _CurrentSketchEditorTool;// 更新草图编辑工具void _UpdateSketchEditTool(SketchEditorTool sketchEditorTool){if (_CurrentSketchEditorTool != null){_CurrentSketchEditorTool.PropertyChanged -= SketchEditorToolPropertyChanged;_CurrentSketchEditorTool = null;ActiveSketchTool = "";SketchGroupVisible = false;}if (sketchEditorTool != null){SketchGroupVisible = true;_CurrentSketchEditorTool = sketchEditorTool;_CurrentSketchEditorTool.PropertyChanged += SketchEditorToolPropertyChanged;RaisePropertyChanged(nameof(SketchClipPlaneEnabled));}}//--------------------------------------------------------------------------------------------------// 草图编辑工具属性变更处理程序void SketchEditorToolPropertyChanged(object sender, PropertyChangedEventArgs e){if (_CurrentSketchEditorTool != sender) return;if (e.PropertyName == nameof(SketchEditorTool.CurrentTool)){if (_CurrentSketchEditorTool.CurrentTool is SketchSegmentLineCreator){ActiveSketchTool = _CurrentSketchEditorTool.ContinuesSegmentCreation ? "SketchSegmentPolyLineCreator" : "SketchSegmentLineCreator";}else{ActiveSketchTool = _CurrentSketchEditorTool.CurrentTool?.GetType().Name ?? "";}}else if (e.PropertyName == nameof(SketchEditorTool.ClipPlaneEnabled)){RaisePropertyChanged(nameof(SketchClipPlaneEnabled));}}//--------------------------------------------------------------------------------------------------#endregion#region Transform// 变换的枢轴点[SerializeMember]public TransformTool.PivotPoint TransformPivot{get { return _TransformPivot; }set{_TransformPivot = value;RaisePropertyChanged();}}TransformTool.PivotPoint _TransformPivot;//--------------------------------------------------------------------------------------------------// 变换的选项[SerializeMember]public TransformTool.Options TransformOptions{get { return _TransformOptions; }set{_TransformOptions = value;RaisePropertyChanged();}}TransformTool.Options _TransformOptions;//--------------------------------------------------------------------------------------------------#endregion#region Selection// 橡皮筋选择模式[SerializeMember]public ViewportController.RubberbandSelectionMode RubberbandSelectionMode{get { return _RubberbandSelectionMode; }set{_RubberbandSelectionMode = value; RaisePropertyChanged();}}ViewportController.RubberbandSelectionMode _RubberbandSelectionMode;//--------------------------------------------------------------------------------------------------// 是否包含接触到的对象public bool RubberbandIncludeTouched{get { return _RubberbandIncludeTouched; }set{_RubberbandIncludeTouched = value;RaisePropertyChanged();}}bool _RubberbandIncludeTouched;//--------------------------------------------------------------------------------------------------#endregion#region WorkspaceWorkspaceController _WorkspaceController;//--------------------------------------------------------------------------------------------------// 工作区控制器属性变更处理程序void _WorkspaceController_PropertyChanged(object sender, PropertyChangedEventArgs e){if (e.PropertyName == nameof(WorkspaceController.CurrentTool)){_UpdateActiveTool((sender as WorkspaceController)?.CurrentTool);}}//--------------------------------------------------------------------------------------------------#endregion#region Snapping// 是否启用网格捕捉[SerializeMember]public bool SnapToGridSelected{get { return _SnapToGridSelected; }set{if (_SnapToGridSelected != value){_SnapToGridSelected = value;RaisePropertyChanged();}}}bool _SnapToGridSelected;//--------------------------------------------------------------------------------------------------// 是否启用顶点捕捉[SerializeMember]public bool SnapToVertexSelected{get { return _SnapToVertexSelected; }set{if (_SnapToVertexSelected != value){_SnapToVertexSelected = value;RaisePropertyChanged();_WorkspaceController?.Selection?.Invalidate();}}}bool _SnapToVertexSelected;//--------------------------------------------------------------------------------------------------// 是否启用边捕捉[SerializeMember]public bool SnapToEdgeSelected{get { return _SnapToEdgeSelected; }set{if (_SnapToEdgeSelected != value){_SnapToEdgeSelected = value;RaisePropertyChanged();_WorkspaceController?.Selection?.Invalidate();}}}bool _SnapToEdgeSelected;//--------------------------------------------------------------------------------------------------// 是否启用捕捉[SerializeMember]public bool SnappingEnabled{get { return _SnappingEnabled; }set{if (_SnappingEnabled != value){_SnappingEnabled = value;RaisePropertyChanged();_WorkspaceController?.Selection?.Invalidate();}}}bool _SnappingEnabled;//--------------------------------------------------------------------------------------------------// 捕捉像素容差[SerializeMember]public double SnappingPixelTolerance{get { return _SnappingPixelTolerance; }set{_WorkspaceController?.Workspace?.AisContext?.SetPixelTolerance((int)value);if (_SnappingPixelTolerance != value){_SnappingPixelTolerance = value;RaisePropertyChanged();}}}double _SnappingPixelTolerance = 2.0;//--------------------------------------------------------------------------------------------------#endregion#region c'tor and property handling// 构造函数public EditorState(){InteractiveContext.Current.PropertyChanged += _InteractiveContext_PropertyChanged;_WorkspaceController = InteractiveContext.Current.WorkspaceController;if (_WorkspaceController != null){_WorkspaceController.PropertyChanged += _WorkspaceController_PropertyChanged;}}//--------------------------------------------------------------------------------------------------// 交互上下文属性变更处理程序void _InteractiveContext_PropertyChanged(object sender, PropertyChangedEventArgs e){if (e.PropertyName == "WorkspaceController"){if (_WorkspaceController != null){_WorkspaceController.PropertyChanged -= _WorkspaceController_PropertyChanged;}_WorkspaceController = InteractiveContext.Current.WorkspaceController;if (_WorkspaceController != null){_WorkspaceController.PropertyChanged += _WorkspaceController_PropertyChanged;}_WorkspaceController_PropertyChanged(_WorkspaceController, new PropertyChangedEventArgs(nameof(WorkspaceController.CurrentTool)));}}//--------------------------------------------------------------------------------------------------#endregion}
}
总结:EditorState
类是一个包含了编辑器状态的类,用于跟踪编辑器的各种状态,包括当前激活的工具、草图相关状态、变换选项、选择模式、捕捉设置等。
15.
using Macad.Core.Topology;namespace Macad.Interaction
{// 交互克隆选项类,继承自 CloneOptionsinternal class InteractiveCloneOptions : CloneOptions{// 克隆引用体public override bool CloneReferencedBodies { get {// 如果尚未询问过是否克隆引用体,则询问用户if(!_AskedForCloneReferencedBodies)CloneReferencedBodies = AskForCloneReferencedBodies();return base.CloneReferencedBodies;}}//--------------------------------------------------------------------------------------------------// 是否被取消public bool IsCanceled { get; private set; }//--------------------------------------------------------------------------------------------------// 是否已询问过是否克隆引用体bool _AskedForCloneReferencedBodies;//--------------------------------------------------------------------------------------------------// 构造函数,初始化基类为禁止克隆引用体public InteractiveCloneOptions() : base(false){}//--------------------------------------------------------------------------------------------------// 询问是否克隆引用体bool AskForCloneReferencedBodies(){_AskedForCloneReferencedBodies = true;// 弹出询问对话框var dlgResult = Dialogs.Dialogs.AskBodyCloneBehaviour();if (!dlgResult.HasValue){// 如果用户取消,则标记为取消IsCanceled = true;return false;}return dlgResult.Value;}//--------------------------------------------------------------------------------------------------}
}
总结:
InteractiveCloneOptions
类继承自CloneOptions
,用于提供交互式克隆操作的选项。CloneReferencedBodies
属性重写了基类的属性,以延迟询问用户是否克隆引用体。_AskedForCloneReferencedBodies
字段用于跟踪是否已经询问过用户。AskForCloneReferencedBodies
方法用于实际询问用户是否克隆引用体,并根据用户的选择进行处理。
16.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Macad.Common;
using Macad.Core;
using Macad.Interaction.Panels;namespace Macad.Interaction
{// 交互式上下文类,继承自 CoreContextpublic abstract class InteractiveContext : CoreContext{// 文档控制器public ModelController DocumentController{get { return _DocumentController; }protected set{_DocumentController = value;RaisePropertyChanged();}}//--------------------------------------------------------------------------------------------------// 工作区控制器public override Workspace Workspace{get{return base.Workspace;}protected set{WorkspaceController = value == null ? null : new WorkspaceController(value);base.Workspace = value;RaisePropertyChanged(nameof(WorkspaceController));}}//--------------------------------------------------------------------------------------------------// 工作区控制器public WorkspaceController WorkspaceController{get { return _WorkspaceController; }private set{if (_WorkspaceController == value)return;_WorkspaceController?.Dispose();_WorkspaceController = value;}}//--------------------------------------------------------------------------------------------------// 视图控制器public override Viewport Viewport{get{return base.Viewport;}protected set{base.Viewport = value;if (value == null){ViewportController = null;WorkspaceController.ActiveViewport = null;}else{WorkspaceController.ActiveViewport = base.Viewport;ViewportController = WorkspaceController.GetViewController(base.Viewport);}}}//--------------------------------------------------------------------------------------------------// 视图控制器public ViewportController ViewportController{get{return _ViewportController;}private set{_ViewportController = value;RaisePropertyChanged();}}//--------------------------------------------------------------------------------------------------// 属性面板管理器public IPropertyPanelManager PropertyPanelManager { get; set; }//--------------------------------------------------------------------------------------------------// 最近使用的颜色列表public IList<Color> RecentUsedColors{get{if (_RecentUsedColors == null)_RecentUsedColors = LoadLocalSettings<List<Color>>("RecentUsedColors") ?? new List<Color>();return _RecentUsedColors;}}//--------------------------------------------------------------------------------------------------// 编辑器状态public EditorState EditorState{get{if(_EditorState == null)_EditorState = LoadLocalSettings<EditorState>("EditorState") ?? new EditorState();return _EditorState;}}//--------------------------------------------------------------------------------------------------// 快捷键处理器public ShortcutHandler ShortcutHandler { get; }//--------------------------------------------------------------------------------------------------ViewportController _ViewportController;ModelController _DocumentController;List<Color> _RecentUsedColors;EditorState _EditorState;WorkspaceController _WorkspaceController;//--------------------------------------------------------------------------------------------------// 构造函数protected InteractiveContext(){InteractionModule.Initialize();Current = this;DocumentController = new ModelController();ShortcutHandler = new ShortcutHandler();}//--------------------------------------------------------------------------------------------------// 释放资源protected override void Dispose(bool disposing){WorkspaceController?.Dispose();WorkspaceController = null;ViewportController = null;base.Dispose(disposing);}//--------------------------------------------------------------------------------------------------#region Statics// 当前交互式上下文public new static InteractiveContext Current { get; private set; }//--------------------------------------------------------------------------------------------------#endregion// 保存设置public override void SaveSettings(){base.SaveSettings();if(_RecentUsedColors != null)SaveLocalSettings("RecentUsedColors", _RecentUsedColors);if(EditorState != null)SaveLocalSettings("EditorState", EditorState);}//--------------------------------------------------------------------------------------------------#region ScriptMru// 最近使用的脚本列表public ObservableCollection<string> RecentUsedScripts{get{if (_RecentUsedScripts == null)_RecentUsedScripts = LoadLocalSettings<ObservableCollection<string>>("RecentUsedScripts") ?? new ObservableCollection<string>();return _RecentUsedScripts;}}const int _MaxScriptMruCount = 1;ObservableCollection<string> _RecentUsedScripts;//--------------------------------------------------------------------------------------------------// 添加到最近使用的脚本列表internal void AddToScriptMruList(string filePath){var recentList = RecentUsedScripts;var index = recentList.IndexOfFirst(s => s.CompareIgnoreCase(filePath) == 0);if (index >= 0){// 移动到列表顶部recentList.Move(index, 0);recentList[0] = filePath;return;}if(recentList.Count >= _MaxScriptMruCount)recentList.RemoveAt(recentList.Count-1);recentList.Insert(0, filePath);SaveLocalSettings("RecentUsedScripts", recentList);}//--------------------------------------------------------------------------------------------------#endregion}
}
总结:
InteractiveContext
类是交互式上下文的抽象基类,继承自CoreContext
。- 它管理了文档控制器、工作区控制器、视图控制器、属性面板管理器等核心对象。
RecentUsedColors
属性存储了最近使用的颜色列表。EditorState
属性存储了编辑器的状态信息。RecentUsedScripts
属性存储了最近使用的脚本文件列表。AddToScriptMruList
方法用于将文件路径添加到最近使用的脚本列表中。
17.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Shell;
using Macad.Interaction.Dialogs;
using Microsoft.Win32;
using Macad.Common;
using Macad.Core;
using Macad.Common.Serialization;
using Macad.Core.Topology;
using Macad.Presentation;namespace Macad.Interaction
{// 模型控制器类,继承自 BaseObjectpublic class ModelController : BaseObject{#region Member variables// 最近使用的文件列表public ObservableCollection<string> MruList { get; }#endregion#region Initialization// 构造函数public ModelController(){// 加载最近使用的文件列表MruList = InteractiveContext.Current.LoadLocalSettings<ObservableCollection<string>>("MRU")?? new ObservableCollection<string>();while (MruList.Count >= _MaxMruCount){MruList.RemoveAt(MruList.Count-1);}// 订阅模型附加数据保存事件Model.AdditionalDataSaving += _Model_AdditionalDataSaving;}//--------------------------------------------------------------------------------------------------#endregion#region Model// 创建新模型public Model NewModel(){Model newModel = new();InteractiveContext.Current.Document = newModel;newModel.ResetUnsavedChanges();return newModel;}//--------------------------------------------------------------------------------------------------// 创建新模型并保存到指定路径public Model CreateModelAs(string baseDirectory = null){var dlg = new SaveFileDialog(){Title = "Create Model...",CheckPathExists = true,Filter = "Macad3D Models|*." + Model.FileExtension,DefaultExt = Model.FileExtension,};if (!(baseDirectory is null)){dlg.InitialDirectory = baseDirectory;}var result = dlg.ShowDialog(Application.Current.MainWindow);if (!(result ?? false))return null;var relativeFilePath = dlg.FileName;var model = NewModel();if (model.SaveToFile(relativeFilePath)){return model;}else{ErrorDialogs.CannotSaveFile(dlg.FileName);}return null;}//--------------------------------------------------------------------------------------------------// 打开模型public bool OpenModel(string filePath){try{var stopwatch = new Stopwatch();stopwatch.Start();var context = new SerializationContext(SerializationScope.Storage);var model = Model.CreateFromFile(filePath, context);if (model == null){switch (context.Result){case SerializationResult.VersionMismatch:ErrorDialogs.FileVersionIsNewer(filePath);break;default:ErrorDialogs.CannotLoadFile(filePath);break;}return false;}if (context.HasErrors){ErrorDialogs.FileLoadedWithErrors(filePath);}InteractiveContext.Current.Document = model;model.ResetUnsavedChanges();AddToMruList(filePath);stopwatch.Stop();Messages.Info(string.Format("Model " + model.Name + " loaded in {0}:{1} seconds.", stopwatch.Elapsed.Seconds, stopwatch.Elapsed.Milliseconds));return true;}catch (Exception e){Messages.Exception($"Exception while loading model {filePath}.", e);ErrorDialogs.CannotLoadFile(filePath);return false;}}//--------------------------------------------------------------------------------------------------// 保存模型public bool SaveModel(){var model = InteractiveContext.Current.Document;if (model.FilePath.IsNullOrEmpty()){return SaveModelAs();}else{if (model.Save()){AddToMruList(model.FilePath);return true;}ErrorDialogs.CannotSaveFile(model.FilePath);}return false;}//--------------------------------------------------------------------------------------------------// 另存为模型public bool SaveModelAs(){var dlg = new SaveFileDialog(){Title = "Saving Model...",InitialDirectory = Path.GetDirectoryName(InteractiveContext.Current.Document.FilePath),FileName = Path.GetFileName(InteractiveContext.Current.Document.FilePath),CheckPathExists = true,Filter = "Macad3D Models|*." + Model.FileExtension,DefaultExt = Model.FileExtension};var result = dlg.ShowDialog(Application.Current.MainWindow);if (result ?? false){var filePath = dlg.FileName;if (PathUtils.GetExtensionWithoutPoint(filePath).ToLower() != Model.FileExtension){filePath += "." + Model.FileExtension;}var model = InteractiveContext.Current.Document;if (model.SaveToFile(filePath)){AddToMruList(model.FilePath);return true;}else{ErrorDialogs.CannotSaveFile(dlg.FileName);}}return false;}//--------------------------------------------------------------------------------------------------// 从指定目录打开模型public bool OpenModelFrom(string initialDirectory){var dlg = new OpenFileDialog(){Title = "Open Model...",CheckFileExists = true,Filter = "Macad3D Models|*." + Model.FileExtension,DefaultExt = Model.FileExtension,InitialDirectory = initialDirectory ?? String.Empty};var result = dlg.ShowDialog(Application.Current.MainWindow);if (!((bool) result)){return false;}return OpenModel(dlg.FileName);}//--------------------------------------------------------------------------------------------------// 询问是否保存模型的更改public bool AskForSavingModelChanges(){if (InteractiveContext.Current.Document == null)return true;if (InteractiveContext.Current.Document.HasUnsavedChanges){switch (Dialogs.Dialogs.AskForSavingModelChanges()){case TaskDialogResults.Cancel:return false;case TaskDialogResults.Yes:if (!SaveModel()){return false;}break;case TaskDialogResults.No:break;}}return true;}//--------------------------------------------------------------------------------------------------#endregion#region Generic File I/O// 打开文件public void OpenFile(string filePath, bool mergeToCurrent){var extension = PathUtils.GetExtensionWithoutPoint(filePath);if (extension != null && extension.Equals(Model.FileExtension)){// Load modelif (AskForSavingModelChanges()){OpenModel(filePath);}return;}// Try importervar importer = ExchangeRegistry.FindExchanger<IBodyImporter>(extension);if (importer == null)return;if (!mergeToCurrent){if (!AskForSavingModelChanges()){return;}}// Call for Settingsif (!ExchangerSettings.Execute<IBodyImporter>(importer))return;// Do itusing (new ProcessingScope(null, "Importing file...")){if (!mergeToCurrent){NewModel();}if (importer.DoImport(filePath, out var newBodies)){foreach (var newBody in newBodies){CoreContext.Current?.Document?.Add(newBody);}InteractiveContext.Current.ViewportController.ZoomFitAll();AddToMruList(filePath);}CoreContext.Current.UndoHandler.Commit();}}//--------------------------------------------------------------------------------------------------// 添加到最近使用的文件列表public void AddToMruList(string filePath){var index = MruList.IndexOfFirst(s => s.CompareIgnoreCase(filePath) == 0);if (index >= 0){// Move to top of listMruList.Move(index, 0);MruList[0] = filePath;}else{if(MruList.Count >= _MaxMruCount)MruList.RemoveAt(MruList.Count-1);MruList.Insert(0, filePath);}InteractiveContext.Current.SaveLocalSettings("MRU", MruList);try{JumpList.AddToRecentCategory(filePath);}catch{// ignored}}//--------------------------------------------------------------------------------------------------// 从最近使用的文件列表中移除public void RemoveFromMruList(string filePath){var index = MruList.IndexOfFirst(s => s.CompareIgnoreCase(filePath) == 0);if (index >= 0){MruList.RemoveAt(index);}InteractiveContext.Current.SaveLocalSettings("MRU", MruList);}//--------------------------------------------------------------------------------------------------// 保存模型附加数据void _Model_AdditionalDataSaving(Document<InteractiveEntity> sender, FileSystem fileSystem){if (InteractiveContext.Current?.Document != sender)return; // This model is not activevar bitmap = InteractiveContext.Current?.ViewportController.RenderToBitmap(500, 500);if (bitmap == null)return;using (var ms = new MemoryStream()){bitmap.Save(ms, ImageFormat.Png);fileSystem.Write("thumbnail.png", ms.GetBuffer());}}//--------------------------------------------------------------------------------------------------#endregion#region Delete, Duplicate, Clipboardconst string ClipboardContentFormat = "Macad.ModelContent.1";[SerializeType]public class ClipboardHeader{[SerializeMember]public Guid ModelGuid { get; set; }}//--------------------------------------------------------------------------------------------------// 是否可以删除internal bool CanDelete(List<InteractiveEntity> entities){return entities.Any() && entities.All(e => CoreContext.Current.Document.Contains(e));}//--------------------------------------------------------------------------------------------------// 删除实体internal void Delete(List<InteractiveEntity> entities){if (!CanDelete(entities))return;// Delete all bodies. Use array copy, since the list will change.var entitiesToDelete = entities.ToArray();InteractiveContext.Current.WorkspaceController.Selection.ChangeEntitySelection(new InteractiveEntity[0], entitiesToDelete);InteractiveContext.Current.Document.SafeDelete(entitiesToDelete);}//--------------------------------------------------------------------------------------------------// 是否可以复制internal bool CanDuplicate(List<InteractiveEntity> entities){return entities.Any() && entities.All(e => CoreContext.Current.Document.Contains(e));}//--------------------------------------------------------------------------------------------------// 复制实体internal IEnumerable<InteractiveEntity> Duplicate(List<InteractiveEntity> entities, CloneOptions options = null){if (!CanDuplicate(entities))return null;var context = new SerializationContext(SerializationScope.CopyPaste);context.SetInstance(InteractiveContext.Current.Document);context.SetInstance<IDocument>(InteractiveContext.Current.Document);var serialized = Serializer.Serialize(entities, context);context = new SerializationContext(SerializationScope.CopyPaste);context.SetInstance(InteractiveContext.Current.Document);context.SetInstance<IDocument>(InteractiveContext.Current.Document);context.SetInstance(ReadOptions.RecreateGuids);var cloneOptions = options ?? new InteractiveCloneOptions();context.SetInstance<CloneOptions>(cloneOptions);var cloned = Serializer.Deserialize<InteractiveEntity[]>(serialized, context);if ((cloneOptions as InteractiveCloneOptions)?.IsCanceled ?? false)return null;foreach (var entity in context.GetInstanceList<InteractiveEntity>()){InteractiveContext.Current.Document.Add(entity);entity.RaiseVisualChanged();}InteractiveContext.Current.WorkspaceController.Selection.SelectEntities(cloned);return cloned;}//--------------------------------------------------------------------------------------------------// 是否可以复制到剪贴板internal bool CanCopyToClipboard(List<InteractiveEntity> entities){return entities.Any() && entities.All(e => e is InteractiveEntity && CoreContext.Current.Document.Contains(e));}//--------------------------------------------------------------------------------------------------// 复制到剪贴板internal void CopyToClipboard(List<InteractiveEntity> entities){if (!CanCopyToClipboard(entities))return;var context = new SerializationContext(SerializationScope.CopyPaste);context.SetInstance(InteractiveContext.Current.Document);context.SetInstance<IDocument>(InteractiveContext.Current.Document);var document = new ClipboardHeader(){ModelGuid = CoreContext.Current.Document.Guid};var writer = new Writer();if (!Serializer.Serialize(writer, document, context)|| !Serializer.Serialize(writer, entities, context))return;Core.Clipboard.Current?.SetData(ClipboardContentFormat, writer.ToString());}//--------------------------------------------------------------------------------------------------// 是否可以从剪贴板粘贴internal bool CanPasteFromClipboard(){return Core.Clipboard.Current?.ContainsData(ClipboardContentFormat) ?? false;}//--------------------------------------------------------------------------------------------------// 从剪贴板粘贴internal IEnumerable<InteractiveEntity> PasteFromClipboard(){var serialized = Core.Clipboard.Current?.GetDataAsString(ClipboardContentFormat);if (serialized == null)return null;var context = new SerializationContext(SerializationScope.CopyPaste);context.SetInstance(InteractiveContext.Current.Document);context.SetInstance<IDocument>(InteractiveContext.Current.Document);var reader = new Reader(serialized, ReadOptions.RecreateGuids);var document = Serializer.Deserialize<ClipboardHeader>(reader, context);if (document == null)return null;// Same Model -> Ask for cloning// Foreign Model -> Clone alwayscontext.SetInstance<CloneOptions>(document.ModelGuid == CoreContext.Current.Document.Guid ? new InteractiveCloneOptions() : new CloneOptions(true));var cloned = Serializer.Deserialize<InteractiveEntity[]>(reader, context);foreach (var entity in context.GetInstanceList<InteractiveEntity>()){InteractiveContext.Current.Document.Add(entity);entity.RaiseVisualChanged();}InteractiveContext.Current.WorkspaceController?.Selection?.SelectEntities(cloned);return cloned;}//--------------------------------------------------------------------------------------------------#endregion}
}
该代码定义了一个模型控制器类,用于管理模型的创建、打开、保存、导入、复制、粘贴、删除等操作。每个方法都进行了详细的注释,说明了其功能和用法。
18.
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Input;
using Macad.Core;
using Macad.Core.Topology;
using Macad.Occt;namespace Macad.Interaction
{/// <summary>/// 鼠标事件处理器接口。/// </summary>public interface IMouseEventHandler{/// <summary>/// 处理鼠标移动事件。/// </summary>/// <param name="data">鼠标事件数据。</param>/// <returns>如果事件已处理,则为 true;否则为 false。</returns>bool OnMouseMove(MouseEventData data);/// <summary>/// 处理鼠标按下事件。/// </summary>/// <param name="data">鼠标事件数据。</param>/// <returns>如果事件已处理,则为 true;否则为 false。</returns>bool OnMouseDown(MouseEventData data);/// <summary>/// 处理鼠标释放事件。/// </summary>/// <param name="data">鼠标事件数据。</param>/// <returns>如果事件已处理,则为 true;否则为 false。</returns>bool OnMouseUp(MouseEventData data);}//--------------------------------------------------------------------------------------------------/// <summary>/// 包含鼠标事件信息的类。/// </summary>public class MouseEventData{/// <summary>/// 与鼠标事件关联的视口。/// </summary>public Viewport Viewport { get; private set; }/// <summary>/// 鼠标事件发生的屏幕点。/// </summary>public Point ScreenPoint { get; private set; }/// <summary>/// 鼠标事件发生的原始三维空间点。/// </summary>public Pnt RawPoint { get; private set; }/// <summary>/// 鼠标事件发生的平面点。/// </summary>public Pnt PointOnPlane { get; private set; }/// <summary>/// 鼠标事件期间按下的修饰键。/// </summary>public ModifierKeys ModifierKeys { get; set; }/// <summary>/// 在鼠标事件期间检测到的 AIS 交互对象列表。/// </summary>public List<AIS_InteractiveObject> DetectedAisInteractives { get; } = new();/// <summary>/// 在鼠标事件期间检测到的交互实体列表。/// </summary>public List<InteractiveEntity> DetectedEntities { get; } = new();/// <summary>/// 在鼠标事件期间检测到的形状列表。/// </summary>public List<TopoDS_Shape> DetectedShapes { get; } = new();/// <summary>/// 指示是否强制重新检测鼠标事件期间的实体。/// </summary>public bool ForceReDetection { get; set; }//--------------------------------------------------------------------------------------------------/// <summary>/// 与鼠标事件关联的拾取轴。/// </summary>public Ax1 PickAxis{get{return Viewport.ViewAxis((int)ScreenPoint.X, (int)ScreenPoint.Y);}}//--------------------------------------------------------------------------------------------------/// <summary>/// 初始化 <see cref="MouseEventData"/> 类的新实例。/// </summary>public MouseEventData(){ScreenPoint = default;RawPoint = default;PointOnPlane = default;ForceReDetection = false;}//--------------------------------------------------------------------------------------------------/// <summary>/// 清除鼠标事件数据。/// </summary>public void Clear(){Viewport = default;ScreenPoint = default;RawPoint = default;PointOnPlane = default;ForceReDetection = false;DetectedAisInteractives.Clear();DetectedEntities.Clear();DetectedShapes.Clear();}//--------------------------------------------------------------------------------------------------/// <summary>/// 设置鼠标事件数据。/// </summary>public void Set(in Viewport viewport, in Point screenPoint, in Pnt rawPoint, in Pnt pointOnPlane, in InteractiveEntity detectedEntity,in AIS_InteractiveObject detectedInteractive, in TopoDS_Shape detectedShape, in ModifierKeys modifierKeys){Viewport = viewport;ScreenPoint = screenPoint;RawPoint = rawPoint;PointOnPlane = pointOnPlane;ModifierKeys = modifierKeys;DetectedAisInteractives.Clear();if (detectedInteractive != null)DetectedAisInteractives.Add(detectedInteractive);DetectedEntities.Clear();if (detectedEntity != null)DetectedEntities.Add(detectedEntity);DetectedShapes.Clear();if (detectedShape != null)DetectedShapes.Add(detectedShape);}}
}
上面的代码定义了一个接口 IMouseEventHandler
和一个类 MouseEventData
,用于处理鼠标事件和存储鼠标事件的相关数据。这些类提供了对鼠标移动、按下和释放事件的处理,并提供了有关鼠标事件的详细信息,例如鼠标位置、点击的实体等。
18.
using System.Collections.Generic;
using System.Windows.Input;
using Macad.Presentation;namespace Macad.Interaction
{/// <summary>/// 表示快捷键的作用范围。/// </summary>public enum ShortcutScope{Application,Workspace}//--------------------------------------------------------------------------------------------------/// <summary>/// 快捷键处理程序。/// </summary>public class ShortcutHandler{/// <summary>/// 表示一个快捷键。/// </summary>public class Shortcut{/// <summary>/// 获取或设置快捷键的键。/// </summary>public Key Key { get; }/// <summary>/// 获取或设置快捷键的修饰键。/// </summary>public ModifierKeys ModifierKeys { get; }/// <summary>/// 获取或设置与快捷键关联的命令。/// </summary>public ICommand Command { get; }/// <summary>/// 获取或设置传递给命令的参数。/// </summary>public object Parameter { get; }/// <summary>/// 使用指定的键、修饰键、命令和参数初始化 <see cref="Shortcut"/> 类的新实例。/// </summary>public Shortcut(Key key, ICommand command, object parameter = null): this(key, ModifierKeys.None, command, parameter){}//--------------------------------------------------------------------------------------------------/// <summary>/// 使用指定的键、修饰键、命令和参数初始化 <see cref="Shortcut"/> 类的新实例。/// </summary>public Shortcut(Key key, ModifierKeys modifierKeys, ICommand command, object parameter = null){Key = key;ModifierKeys = modifierKeys;Command = command;Parameter = parameter;if (command is IActionCommand actionCommand){actionCommand.Shortcut = GetKeyString();}}//--------------------------------------------------------------------------------------------------/// <summary>/// 获取表示快捷键的字符串。/// </summary>public string GetKeyString(){if (ModifierKeys != ModifierKeys.None){return $"{ModifierKeys.ToString()} + {Key.ToString()}";}else{return Key.ToString();}}}//--------------------------------------------------------------------------------------------------readonly Dictionary<ShortcutScope, List<Shortcut>> _ShortcutScopes = new();//--------------------------------------------------------------------------------------------------/// <summary>/// 初始化 <see cref="ShortcutHandler"/> 类的新实例。/// </summary>public ShortcutHandler(){// TODO: 从外部配置文件中读取_ShortcutScopes.Add(ShortcutScope.Application, new List<Shortcut>{new(Key.Y, ModifierKeys.Control, WorkspaceCommands.DoRedo),new(Key.Z, ModifierKeys.Control, WorkspaceCommands.DoUndo),new(Key.C, ModifierKeys.Control, WorkspaceCommands.CopyToClipboard),new(Key.X, ModifierKeys.Control, WorkspaceCommands.CutToClipboard),new(Key.V, ModifierKeys.Control, WorkspaceCommands.PasteFromClipboard),});_ShortcutScopes.Add(ShortcutScope.Workspace, new List<Shortcut>{new(Key.G, WorkspaceCommands.ToggleGrid),new(Key.S, WorkspaceCommands.ToggleSnappingEnabled),new(Key.F, WorkspaceCommands.ZoomFitSelected),new(Key.F, ModifierKeys.Control, WorkspaceCommands.ZoomFitAll),new(Key.T, WorkspaceCommands.Transform),new(Key.W, WorkspaceCommands.AlignWorkingPlane),new(Key.Delete, WorkspaceCommands.DeleteEntity),new(Key.D, ModifierKeys.Control, WorkspaceCommands.DuplicateEntity),new(Key.R, ModifierKeys.Control, ModelCommands.CreateReference),new(Key.I, WorkspaceCommands.ToggleIsolateSelection),new(Key.E, WorkspaceCommands.StartEditing),new(Key.Escape, WorkspaceCommands.Escape),});// 注册}//--------------------------------------------------------------------------------------------------/// <summary>/// 添加快捷键。/// </summary>public void AddShortcut(ShortcutScope scope, Shortcut shortcut){if (!_ShortcutScopes.TryGetValue(scope, out var shortcutList)){shortcutList = new List<Shortcut>();_ShortcutScopes.Add(scope, shortcutList);}shortcutList.Add(shortcut);}//--------------------------------------------------------------------------------------------------/// <summary>/// 检查是否按下指定的快捷键,并执行相关命令。/// </summary>public bool KeyPressed(ShortcutScope scope, Key key, ModifierKeys modifierKeys){if (!_ShortcutScopes.ContainsKey(scope))return false;var shortcut = _ShortcutScopes[scope].Find(s => s.Key == key && s.ModifierKeys == modifierKeys);if (shortcut?.Command == null || !shortcut.Command.CanExecute(shortcut.Parameter))return false;shortcut.Command.Execute(shortcut.Parameter);return true;}//--------------------------------------------------------------------------------------------------/// <summary>/// 获取与指定命令关联的快捷键。/// </summary>public string GetKeyString(ICommand command){foreach (var shortcutScope in _ShortcutScopes){foreach (var shortcut in shortcutScope.Value){if (shortcut.Command.Equals(command))return shortcut.GetKeyString();}}return null;}}
}
上面的代码定义了一个 ShortcutHandler
类,用于处理快捷键及其相关操作。该类中包含了一个内部类 Shortcut
,用于表示快捷键的信息,包括键、修饰键、关联的命令和参数。ShortcutHandler
类提供了添加快捷键、检查是否按下指定的快捷键并执行相关命令、以及获取与指定命令关联的快捷键等功能。
19.
using System;
using Macad.Common;
using Macad.Core;
using Macad.Occt;namespace Macad.Interaction
{/// <summary>/// 表示吸附模式。/// </summary>[Flags]public enum SnapMode{None = 0,Grid = 1 << 0,Vertex = 1 << 1,Edge = 1 << 2,Face = 1 << 3}//--------------------------------------------------------------------------------------------------/// <summary>/// 表示吸附信息。/// </summary>public class SnapInfo{/// <summary>/// 获取或设置吸附模式。/// </summary>public SnapMode SnapMode { get; set; }/// <summary>/// 获取或设置吸附点。/// </summary>public Pnt Point { get; set; }}//--------------------------------------------------------------------------------------------------/// <summary>/// 表示二维吸附信息。/// </summary>public class SnapInfo2D{/// <summary>/// 获取或设置吸附模式。/// </summary>public SnapMode SnapMode { get; set; }/// <summary>/// 获取或设置吸附点。/// </summary>public Pnt2d Point { get; set; }/// <summary>/// 获取或设置距离。/// </summary>public double Distance { get; set; }}//--------------------------------------------------------------------------------------------------/// <summary>/// 表示吸附处理程序。/// </summary>public sealed class SnapHandler : BaseObject, IDisposable{/// <summary>/// 获取或设置支持的吸附模式。/// </summary>public SnapMode SupportedSnapModes{get { return _SupportedSnapModes; }private set{_SupportedSnapModes = value; InteractiveContext.Current?.WorkspaceController?.Selection?.Invalidate();}}//--------------------------------------------------------------------------------------------------SnapMode _SupportedSnapModes = SnapMode.None;WorkspaceController _WorkspaceController;//--------------------------------------------------------------------------------------------------/// <summary>/// 初始化 <see cref="SnapHandler"/> 类的新实例。/// </summary>public SnapHandler(WorkspaceController workspaceController){_WorkspaceController = workspaceController;Tool.ToolActionChanged += _Tool_ToolActionChanged;}//--------------------------------------------------------------------------------------------------/// <summary>/// 释放资源。/// </summary>public void Dispose(){Tool.ToolActionChanged -= _Tool_ToolActionChanged;_WorkspaceController = null;}//--------------------------------------------------------------------------------------------------void _Tool_ToolActionChanged(Tool sender, ToolAction action){SupportedSnapModes = action?.SupportedSnapModes ?? SnapMode.None;}//--------------------------------------------------------------------------------------------------/// <summary>/// 吸附。/// </summary>public SnapInfo Snap(MouseEventData mouseEvent){if (!InteractiveContext.Current.EditorState.SnappingEnabled){return null;}SnapInfo info = null;if (mouseEvent.DetectedShapes.Count == 1){var detectedShape = mouseEvent.DetectedShapes[0];if (SupportedSnapModes.HasFlag(SnapMode.Vertex) && InteractiveContext.Current.EditorState.SnapToVertexSelected && (detectedShape.ShapeType() == TopAbs_ShapeEnum.VERTEX)){// On Vertexvar vertex = TopoDS.Vertex(detectedShape);info = new SnapInfo(){Point = BRep_Tool.Pnt(vertex),SnapMode = SnapMode.Vertex};}else if (SupportedSnapModes.HasFlag(SnapMode.Edge)&& InteractiveContext.Current.EditorState.SnapToEdgeSelected&& (detectedShape.ShapeType() == TopAbs_ShapeEnum.EDGE)){// On Edgevar edge = TopoDS.Edge(detectedShape);double umin = 0, umax = 0;var curve = BRep_Tool.Curve(edge, ref umin, ref umax);if (curve != null){var extrema = new GeomAPI_ExtremaCurveCurve(curve,new Geom_Line(_WorkspaceController.ActiveViewport.ViewAxis(Convert.ToInt32(mouseEvent.ScreenPoint.X), Convert.ToInt32(mouseEvent.ScreenPoint.Y))));if (extrema.NbExtrema() >= 1){Pnt p1 = new Pnt();Pnt p2 = new Pnt();if (extrema.TotalNearestPoints(ref p1, ref p2)){info = new SnapInfo(){Point = p1,SnapMode = SnapMode.Edge};}}}}}else if (mouseEvent.DetectedAisInteractives.Count == 1){if (SupportedSnapModes.HasFlag(SnapMode.Vertex) && InteractiveContext.Current.EditorState.SnapToVertexSelected && (mouseEvent.DetectedAisInteractives[0] is AIS_Point aisPoint)){// On Vertexinfo = new SnapInfo(){Point = aisPoint.Component().Pnt(),SnapMode = SnapMode.Vertex};}}else if (SupportedSnapModes.HasFlag(SnapMode.Grid)&& InteractiveContext.Current.EditorState.SnapToGridSelected&& _WorkspaceController.Workspace.GridEnabled){if (_WorkspaceController.Workspace.ProjectToGrid(_WorkspaceController.ActiveViewport,Convert.ToInt32(mouseEvent.ScreenPoint.X),Convert.ToInt32(mouseEvent.ScreenPoint.Y),out Pnt gridPnt)){// On Gridinfo = new SnapInfo(){Point = gridPnt,SnapMode = SnapMode.Grid};}}if (info != null){_WorkspaceController.CursorPosition = info.Point;}return info;}//--------------------------------------------------------------------------------------------------/// <summary>/// 在平面上进行吸附。/// </summary>public Pnt2d? SnapOnPlane(SnapInfo snapInfo, Pln? localPlane = null){if (snapInfo != null){var plane = localPlane ?? _WorkspaceController.Workspace.WorkingPlane;switch (snapInfo.SnapMode){case SnapMode.Grid:case SnapMode.Vertex:case SnapMode.Edge:return ProjLib.Project(plane, snapInfo.Point);}}return null;}//--------------------------------------------------------------------------------------------------/// <summary>/// 是否需要激活子形状。/// </summary>public bool NeedActiveSubshapes(SubshapeType subshapeType){switch (subshapeType){case SubshapeType.Vertex:return InteractiveContext.Current.EditorState.SnappingEnabled&& InteractiveContext.Current.EditorState.SnapToVertexSelected&& SupportedSnapModes.HasFlag(SnapMode.Vertex);case SubshapeType.Edge:return InteractiveContext.Current.EditorState.SnappingEnabled&& InteractiveContext.Current.EditorState.SnapToEdgeSelected&& SupportedSnapModes.HasFlag(SnapMode.Edge);}return false;}}
}
上面的代码定义了一个 SnapHandler
类,用于处理吸附操作。该类中包含了表示吸附模式的枚举 SnapMode
,以及表示吸附信息的类 SnapInfo
和 SnapInfo2D
。SnapHandler
类提供了吸附操作的实现,包括吸附计算、在平面上进行吸附、以及判断是否需要激活子形状等功能。
20.
using System; // 引入 System 命名空间
using System.Diagnostics; // 引入 System.Diagnostics 命名空间
using System.Runtime.InteropServices; // 引入 System.Runtime.InteropServices 命名空间
using System.Windows; // 引入 System.Windows 命名空间
using System.Windows.Input; // 引入 System.Windows.Input 命名空间
using System.Windows.Interop; // 引入 System.Windows.Interop 命名空间
using Macad.Common; // 引入 Macad.Common 命名空间
using Macad.Common.Interop; // 引入 Macad.Common.Interop 命名空间
using Macad.Core; // 引入 Macad.Core 命名空间namespace Macad.Interaction // 定义 Macad.Interaction 命名空间
{/// <summary>/// 空间导航器参数集。/// </summary>public sealed class SpaceNavigatorParameterSet : OverridableParameterSet // 定义 SpaceNavigatorParameterSet 类,继承自 OverridableParameterSet{/// <summary>/// 获取或设置移动灵敏度。/// </summary>public double 移动灵敏度 { get => GetValue<double>(); set => SetValue(value); } // 定义移动灵敏度属性/// <summary>/// 获取或设置旋转灵敏度。/// </summary>public double 旋转灵敏度 { get => GetValue<double>(); set => SetValue(value); } // 定义旋转灵敏度属性/// <summary>/// 获取或设置缩放灵敏度。/// </summary>public double 缩放灵敏度 { get => GetValue<double>(); set => SetValue(value); } // 定义缩放灵敏度属性/// <summary>/// 获取或设置滚动死区。/// </summary>public double 滚动死区 { get => GetValue<double>(); set => SetValue(value); } // 定义滚动死区属性//--------------------------------------------------------------------------------------------------/// <summary>/// 初始化 <see cref="SpaceNavigatorParameterSet"/> 类的新实例。/// </summary>public SpaceNavigatorParameterSet() // 定义构造函数{SetDefaultValue(nameof(移动灵敏度), 1.0); // 设置默认值SetDefaultValue(nameof(旋转灵敏度), 1.0); // 设置默认值SetDefaultValue(nameof(缩放灵敏度), 1.0); // 设置默认值SetDefaultValue(nameof(滚动死区), 1.25); // 设置默认值}}//--------------------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------------------/// <summary>/// 空间导航器。/// </summary>public class SpaceNavigator // 定义 SpaceNavigator 类{static double _MoveDataDivisorScale = 16.0; // 定义移动数据除数比例static double _RotateDataDivisorScale = 400.0; // 定义旋转数据除数比例static double _ZoomDataDivisorScale = 20480.0; // 定义缩放数据除数比例//--------------------------------------------------------------------------------------------------bool _Initialized = false; // 定义初始化状态变量uint _WindowMessageCode; // 定义窗口消息代码变量IntPtr _DeviceHandle; // 定义设备句柄变量static double _MoveDataDivisor = _MoveDataDivisorScale; // 定义移动数据除数变量static double _RotateDataDivisor = _RotateDataDivisorScale; // 定义旋转数据除数变量static double _ZoomDataDivisor = _ZoomDataDivisorScale; // 定义缩放数据除数变量static double _RollDeadZone = 1.25; // 定义滚动死区变量//--------------------------------------------------------------------------------------------------/// <summary>/// 初始化空间导航器。/// </summary>public bool Init(Window targetWindow) // 定义初始化方法{try // 尝试执行以下代码块{var result = Driver.SiInitialize(); // 调用驱动程序初始化方法if (result != Driver.SpwRetVal.SPW_NO_ERROR) // 如果初始化结果不是无错误{var message = Marshal.PtrToStringAnsi(Driver.SpwErrorString(result)); // 获取错误消息Messages.Info($"[SpaceNavigator] Driver not initialized: {message}"); // 输出消息return false; // 返回初始化失败}_WindowMessageCode = Win32Api.RegisterWindowMessage("SpaceWareMessage00"); // 注册窗口消息IntPtr windowHandle = new WindowInteropHelper(targetWindow).Handle; // 获取窗口句柄Driver.SiOpenData openData = new(); // 创建 SiOpenData 实例Driver.SiOpenWinInit(ref openData, windowHandle); // 初始化打开数据_DeviceHandle = Driver.SiOpen("Macad3D", -1 /* and device */, IntPtr.Zero, 1 /* Event */, ref openData); // 打开设备if (_DeviceHandle == IntPtr.Zero) // 如果设备句柄为空{Messages.Warning("[SpaceNavigator] Device could not be opened."); // 输出警告消息return false; // 返回初始化失败}var hwndSource = HwndSource.FromHwnd(windowHandle); // 获取窗口源if (hwndSource == null) // 如果窗口源为空{Console.WriteLine("[SpaceNavigator] Window hook not successful."); // 输出消息return false; // 返回初始化失败}hwndSource.AddHook(_WndProc); // 添加窗口过程钩子_Initialized = true; // 设置初始化状态为真_UpdateParameters(); // 更新参数return true; // 返回初始化成功}catch (DllNotFoundException) // 捕获找不到 DLL 异常{Console.WriteLine("[SpaceNavigator] Device driver dll not found (siapp.dll)."); // 输出消息return false; // 返回初始化失败}catch (Exception) // 捕获所有其他异常{return false; // 返回初始化失败}}//--------------------------------------------------------------------------------------------------static void _UpdateParameters() // 定义更新参数方法{Debug.Assert(InteractiveContext.Current != null); // 断言当前交互上下文不为空// 初始化参数var paramSet = InteractiveContext.Current.Parameters.Get<SpaceNavigatorParameterSet>(); // 获取参数集_MoveDataDivisor = _MoveDataDivisorScale * paramSet.MoveSensitivity; // 更新移动数据除数_RotateDataDivisor = _RotateDataDivisorScale * paramSet.RotationSensitivity; // 更新旋转数据除数_ZoomDataDivisor = _ZoomDataDivisorScale * paramSet.ZoomSensitivity; // 更新缩放数据除数_RollDeadZone = paramSet.RollDeadZone; // 更新滚动死区}//--------------------------------------------------------------------------------------------------IntPtr _WndProc(IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam, ref bool handled) // 定义窗口过程方法{if ((uint) msg == _WindowMessageCode) // 如果消息代码与注册的窗口消息代码相等{var viewportController = InteractiveContext.Current.ViewportController; // 获取视口控制器if (viewportController != null) // 如果视口控制器不为空{Driver.SiGetEventData eventData = new(); // 创建 SiGetEventData 实例Driver.SiSpwEvent evt = new(); // 创建 SiSpwEvent 实例Driver.SiGetEventWinInit(ref eventData, _WindowMessageCode, wparam, lparam); // 初始化事件数据if (Driver.SiGetEvent(_DeviceHandle, 0, ref eventData, ref evt) == Driver.SpwRetVal.SI_IS_EVENT // 如果获取事件成功且事件类型为运动事件&& evt.Type == Driver.SiEventType.SI_MOTION_EVENT){double panX = -evt.Tx / (_MoveDataDivisor * viewportController.Viewport.Scale); // 计算平移 Xdouble panY = -evt.Ty / (_MoveDataDivisor * viewportController.Viewport.Scale); // 计算平移 YviewportController.Pan(panX, panY); // 执行平移操作double zoom = evt.Tz / _ZoomDataDivisor; // 计算缩放viewportController.Zoom(zoom); // 执行缩放操作double rotX = evt.Rx / _RotateDataDivisor; // 计算旋转 Xdouble rotY = evt.Ry / _RotateDataDivisor; // 计算旋转 Ydouble rotZ = -evt.Rz / _RotateDataDivisor; // 计算旋转 Z// 添加滚动死区到旋转if (Math.Abs(rotZ) < _RollDeadZone) // 如果旋转 Z 的绝对值小于滚动死区{rotZ = 0.0; // 设置旋转 Z 为 0}else // 否则{rotZ -= rotZ > 0 ? _RollDeadZone : -_RollDeadZone; // 对旋转 Z 进行滚动死区处理}viewportController.Rotate(rotY, rotX, rotZ); // 执行旋转操作viewportController.MouseMove(Keyboard.Modifiers); // 执行鼠标移动操作}}handled = true; // 标记消息已处理}return IntPtr.Zero; // 返回零指针}//--------------------------------------------------------------------------------------------------public void DeInit() // 定义反初始化方法{if (_Initialized) // 如果已初始化{Driver.SiTerminate(); // 终止驱动程序_Initialized = false; // 设置初始化状态为假}}//--------------------------------------------------------------------------------------------------static SpaceNavigator() // 静态构造函数{SpaceNavigatorParameterSet.ParameterChanged += (set, key) => _UpdateParameters(); // 注册参数变更事件处理程序}//--------------------------------------------------------------------------------------------------//--------------------------------------------------------------------------------------------------static class Driver // 定义驱动程序类{internal enum SpwRetVal // 定义返回值枚举{SPW_NO_ERROR = 0, // 无错误SI_IS_EVENT = 5 // 是事件}internal enum SiEventType // 定义事件类型枚举{SI_MOTION_EVENT = 2 // 运动事件}[StructLayout(LayoutKind.Sequential, Size = 284)] // 结构布局internal struct SiOpenData // 定义 SiOpenData 结构体{}[StructLayout(LayoutKind.Sequential, Size = 20)] // 结构布局internal struct SiGetEventData // 定义 SiGetEventData 结构体{}[StructLayout(LayoutKind.Sequential, Size = 5124)] // 结构布局internal struct SiSpwEvent // 定义 SiSpwEvent 结构体{internal SiEventType Type; // 事件类型internal uint BtnLast; // 上次按钮internal uint BtnCurrent; // 当前按钮internal uint BtnPressed; // 按下按钮internal uint BtnReleased; // 释放按钮internal int Tx; // X 位移internal int Ty; // Y 位移internal int Tz; // Z 位移internal int Rx; // X 旋转internal int Ry; // Y 旋转internal int Rz; // Z 旋转internal int Period; // 周期}[DllImport("siappdll")] // 引入外部 DLLinternal static extern SpwRetVal SiInitialize(); // 定义驱动程序初始化方法[DllImport("siappdll")] // 引入外部 DLLinternal static extern void SiTerminate(); // 定义驱动程序终止方法[DllImport("siappdll")] // 引入外部 DLLinternal static extern IntPtr SpwErrorString(SpwRetVal code); // 定义错误字符串获取方法[DllImport("siappdll")] // 引入外部 DLLinternal static extern void SiOpenWinInit(ref SiOpenData openData, IntPtr windowHandle); // 定义窗口初始化方法[DllImport("siappdll", CharSet = CharSet.Ansi)] // 引入外部 DLLinternal static extern IntPtr SiOpen(string appName, int deviceId, IntPtr typeMask, int mode, ref SiOpenData openData); // 定义打开方法[DllImport("siappdll")] // 引入外部 DLLinternal static extern IntPtr SiGetEventWinInit(ref SiGetEventData eventData, uint msg, IntPtr wparam, IntPtr lparam); // 定义事件初始化方法[DllImport("siappdll")] // 引入外部 DLLinternal static extern SpwRetVal SiGetEvent(IntPtr deviceHandle, int flags, ref SiGetEventData eventData, ref SiSpwEvent spwEvent); // 定义获取事件方法}}
}
在这段代码中,我们定义了一个名为SpaceNavigator
的类,它用于处理空间导航器的输入。同时,还定义了一个名为SpaceNavigatorParameterSet
的类,用于存储空间导航器的参数。整段代码中包含了初始化、更新参数、处理窗口消息等功能。
21.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows;
using System.Windows.Input;
using Macad.Common;
using Macad.Common.Interop;
using Macad.Core;
using Macad.Occt;
using Macad.Occt.Helper;
using Macad.Resources;
using Point = System.Windows.Point;namespace Macad.Interaction
{public sealed class ViewportController : BaseObject, IDisposable{const int RubberbandFreehandSelectionThresholdSquared = 100;#region Enumspublic enum RubberbandSelectionMode{Rectangle,Freehand}#endregion#region Propertiespublic WorkspaceController WorkspaceController { get; private set; }//--------------------------------------------------------------------------------------------------public Viewport Viewport { get; private set; }//--------------------------------------------------------------------------------------------------public bool LockedToPlane{get { return _LockedToPlane; }set{if (_LockedToPlane != value){if (value){SetPredefinedView(PredefinedViews.WorkingPlane);}_LockedToPlane = value;_SetViewCube(!value);_SetTrihedron(!value && _ShowTrihedron);RaisePropertyChanged();}}}//--------------------------------------------------------------------------------------------------public bool IsInRubberbandSelection{get { return _AisRubberBand != null; }}//--------------------------------------------------------------------------------------------------#endregion#region Member variablesstatic WNT_WClass _OcWindowClass;const double _OrbitProjectionConstraint = Maths.HalfPI - 0.000000000001;WNT_Window _OcWindow;bool _ZoomFitAllOnInit;MouseMoveMode _CurrentMouseMoveMode;Point _StartedMousePosition;Point _LastMousePosition;Pnt? _GravityPoint;bool _LockedToPlane;bool _ShowTrihedron;AIS_RubberBand _AisRubberBand;RubberbandSelectionMode _RubberbandMode;bool _RubberbandIncludeTouched;readonly List<ValueTuple<int, int>> _RubberbandPoints = new();Macad.Occt.Ext.AIS_ViewCubeEx _AisViewCube;//--------------------------------------------------------------------------------------------------#endregion#region Initializationpublic ViewportController(Viewport viewport, WorkspaceController workspaceController){Debug.Assert(viewport != null);Viewport = viewport;WorkspaceController = workspaceController;Init();}//--------------------------------------------------------------------------------------------------~ViewportController(){Dispose(false);}public void Dispose(){Dispose(true);}void Dispose(bool disposing){ViewportParameterSet.ParameterChanged -= _ViewportParameterSet_ParameterChanged;_AisViewCube?.Dispose();_AisViewCube = null;_AisRubberBand?.Dispose();_AisRubberBand = null;Viewport.Dispose();if (_OcWindow != null && !_OcWindow.IsDisposed()){if (_OcWindow.IsMapped())_OcWindow.Unmap();_OcWindow.Dispose();_OcWindow = null;}}//--------------------------------------------------------------------------------------------------void Init(){ViewportParameterSet.ParameterChanged += _ViewportParameterSet_ParameterChanged;var parameterSet = InteractiveContext.Current.Parameters.Get<ViewportParameterSet>();Viewport.Init(parameterSet.EnableAntialiasing);}//--------------------------------------------------------------------------------------------------public IntPtr InitWindow(IntPtr parentHWnd, Int32Rect initialRect){Debug.Assert(Viewport.V3dView != null);uint style;if (_OcWindowClass == null){style = Win32Api.CS_OWNDC;_OcWindowClass = new WNT_WClass(new TCollection_AsciiString("WorkspaceView"), IntPtr.Zero, style, 0);}if (initialRect.IsEmpty){initialRect = new Int32Rect(0, 0, 64, 64);}style = Win32Api.WS_VISIBLE | (parentHWnd == IntPtr.Zero ? Win32Api.WS_POPUP : Win32Api.WS_CHILD);_OcWindow = new WNT_Window("WorkspaceView", _OcWindowClass, style, initialRect.X, initialRect.Y, initialRect.Width, initialRect.Height, Quantity_NameOfColor.GRAY50, parentHWnd);_OcWindow.Map();Viewport.V3dView.SetWindow(_OcWindow);//Viewport.InitV3dView();if (_ZoomFitAllOnInit){_ZoomFitAllOnInit = false;ZoomFitAll();}Viewport.V3dView.Update();Viewport.V3dView.MustBeResized();Viewport.V3dView.SetImmediateUpdate(false);_UpdateParameter();var handle = _OcWindow.HWindow();return handle;}//--------------------------------------------------------------------------------------------------void _ViewportParameterSet_ParameterChanged(OverridableParameterSet set, string key){_UpdateParameter();}//--------------------------------------------------------------------------------------------------void _UpdateParameter(){var parameterSet = InteractiveContext.Current.Parameters.Get<ViewportParameterSet>();_SetViewCube(parameterSet.ShowViewCube, parameterSet.ViewCubeSize, parameterSet.ViewCubeAnimationDuration);_SetTrihedron(parameterSet.ShowTrihedron);_ShowTrihedron = parameterSet.ShowTrihedron;}//--------------------------------------------------------------------------------------------------#endregion#region Viewport navigationpublic enum PredefinedViews{Top,Bottom,Left,Right,Front,Back,WorkingPlane}//--------------------------------------------------------------------------------------------------public void SetPredefinedView(PredefinedViews predefinedView){if (predefinedView == PredefinedViews.WorkingPlane){var plane = WorkspaceController.Workspace.WorkingPlane;var dir = plane.Axis.Direction;Viewport.V3dView.SetProj(dir.X, dir.Y, dir.Z);var up = plane.YAxis.Direction;Viewport.V3dView.SetUp(up.X, up.Y, up.Z);return;}V3d_TypeOfOrientation orientation;switch (predefinedView){case PredefinedViews.Top:orientation = V3d_TypeOfOrientation.Zup_Top;break;case PredefinedViews.Bottom:orientation = V3d_TypeOfOrientation.Zup_Bottom;break;case PredefinedViews.Left:orientation = V3d_TypeOfOrientation.Zup_Left;break;case PredefinedViews.Right:orientation = V3d_TypeOfOrientation.Zup_Right;break;case PredefinedViews.Front:orientation = V3d_TypeOfOrientation.Zup_Front;break;case PredefinedViews.Back:orientation = V3d_TypeOfOrientation.Zup_Back;break;default:return;}var viewCubeOwner = new AIS_ViewCubeOwner(_AisViewCube, orientation);_AisViewCube.HandleClick(viewCubeOwner);viewCubeOwner.Dispose();WorkspaceController.Invalidate();}//--------------------------------------------------------------------------------------------------public enum MouseMoveMode{None,Panning,Rotating,Twisting,Zooming}//--------------------------------------------------------------------------------------------------public void MouseMove(Point pos, ModifierKeys modifierKeys = ModifierKeys.None, MouseMoveMode mode = MouseMoveMode.None){if (IsInRubberbandSelection){_LastMousePosition = pos;_UpdateRubberbandSelection();WorkspaceController.Invalidate(true);return;}if (_CurrentMouseMoveMode != mode){if (mode == MouseMoveMode.None){_ResetMouseMoveMode();}else{_StartedMousePosition = pos;_SetMouseMoveMode(mode);}}switch (_CurrentMouseMoveMode){case MouseMoveMode.Panning:Viewport.V3dView.Pan((int) (pos.X - _LastMousePosition.X), -(int) (pos.Y - _LastMousePosition.Y), 1.0, true);Viewport.OnViewMoved();break;case MouseMoveMode.Twisting:Rotate(0, 0, (pos.Y - _LastMousePosition.Y) / 12.0);break;case MouseMoveMode.Rotating:// TurntableRotate((_LastMousePosition.X - pos.X) / 6.0, (_LastMousePosition.Y - pos.Y) / 6.0, 0);break;case MouseMoveMode.Zooming:Viewport.V3dView.ZoomAtPoint((int) _LastMousePosition.X, (int) pos.Y, (int) pos.X, (int) _LastMousePosition.Y);Viewport.OnViewMoved();break;}WorkspaceController.MouseMove(this, pos, modifierKeys);WorkspaceController.Invalidate();_LastMousePosition = pos;}//--------------------------------------------------------------------------------------------------public void MouseMove(ModifierKeys modifierKeys = ModifierKeys.None){if (_AisRubberBand != null)return;WorkspaceController.MouseMove(this, _LastMousePosition, modifierKeys);}//--------------------------------------------------------------------------------------------------public void MouseDown(ModifierKeys modifierKeys = ModifierKeys.None){WorkspaceController.MouseDown(this, modifierKeys);}//--------------------------------------------------------------------------------------------------public void MouseUp(ModifierKeys modifierKeys = ModifierKeys.None){if (IsInRubberbandSelection){_StopRubberbandSelection();}WorkspaceController.MouseUp(this, modifierKeys);}//--------------------------------------------------------------------------------------------------void _SetMouseMoveMode(MouseMoveMode mode){switch (mode){case MouseMoveMode.Panning:_CurrentMouseMoveMode = MouseMoveMode.Panning;break;case MouseMoveMode.Rotating:_CurrentMouseMoveMode = MouseMoveMode.Rotating;_GravityPoint ??= Viewport.V3dView.GravityPoint();break;case MouseMoveMode.Twisting:_CurrentMouseMoveMode = MouseMoveMode.Twisting;break;case MouseMoveMode.Zooming:Viewport.V3dView.StartZoomAtPoint((int) (_StartedMousePosition.X), (int) (_StartedMousePosition.Y));_CurrentMouseMoveMode = MouseMoveMode.Zooming;break;}}//--------------------------------------------------------------------------------------------------void _ResetMouseMoveMode(){_GravityPoint = null;_CurrentMouseMoveMode = MouseMoveMode.None;}//--------------------------------------------------------------------------------------------------public void Rotate(double yawDeg, double pitchDeg, double rollDeg){if (!_LockedToPlane){if (Math.Abs(yawDeg) > 0.001 || Math.Abs(pitchDeg) > 0.001){if (Viewport.Twist == 180){Viewport.Twist = 0;}var pitch = pitchDeg.ToRad();var yaw = yawDeg.ToRad();// Constraint polar regions, do not go 'overhead'var upDir = Viewport.GetUpDirection();var viewDir = Viewport.GetViewDirection();var angleLeft = _OrbitProjectionConstraint - Ax2.XOY.Angle(new Ax2(Pnt.Origin, upDir));if (viewDir.Z < 0 && pitch < -angleLeft){pitch = -angleLeft;}else if (viewDir.Z > 0 && pitch > angleLeft){pitch = angleLeft;}var gravityPoint = _GravityPoint ?? Viewport.V3dView.GravityPoint();Trsf trsf1 = new Trsf(new Ax1(gravityPoint, Viewport.GetRightDirection()), pitch);Viewport.V3dView.Camera().Transform(trsf1);Trsf trsf2 = new Trsf(new Ax1(gravityPoint, Dir.DZ), yaw);Viewport.V3dView.Camera().Transform(trsf2);}if (Math.Abs(rollDeg) > 0.001){Viewport.V3dView.Turn(V3d_TypeOfAxe.Z, rollDeg.ToRad(), true);}}WorkspaceController.Invalidate();Viewport.OnViewMoved();}//--------------------------------------------------------------------------------------------------public void Pan(double dX, double dY){Viewport.V3dView.Panning(dX, dY, 1.0, true);WorkspaceController.Invalidate();Viewport.OnViewMoved();}//--------------------------------------------------------------------------------------------------public void Zoom(Point pos, double value){double delta = value * 20.0;if (_CurrentMouseMoveMode != MouseMoveMode.Zooming){Viewport.V3dView.StartZoomAtPoint((int) pos.X, (int) (pos.Y - delta));}Viewport.V3dView.ZoomAtPoint((int) pos.X, (int) (pos.Y - delta), (int) pos.X, (int) (pos.Y + delta));WorkspaceController.Invalidate();Viewport.OnViewMoved();}//--------------------------------------------------------------------------------------------------public void Zoom(double value){if (value > 0){Viewport.V3dView.SetZoom(1.0 + value, true);}else if (value < 0){Viewport.V3dView.SetZoom(1.0 / (1.0-value), true);}WorkspaceController.Invalidate();Viewport.OnViewMoved();}//--------------------------------------------------------------------------------------------------public void ZoomFitAll(){if (_OcWindow == null){// We need a window, defer call_ZoomFitAllOnInit = true;return;}WorkspaceController.VisualObjects.UpdateInvalidatedEntities();Viewport.V3dView.FitAll(0.1, false);Viewport.V3dView.ZFitAll(1.0);WorkspaceController.Invalidate();Viewport.OnViewMoved();}//--------------------------------------------------------------------------------------------------public void ZoomFitSelected(){WorkspaceController.VisualObjects.UpdateInvalidatedEntities();WorkspaceController.Workspace.AisContext.FitSelected(Viewport.V3dView, 0.1, false);WorkspaceController.Invalidate();Viewport.OnViewMoved();}//--------------------------------------------------------------------------------------------------#endregion#region Usability Toolsvoid _SetViewCube(bool isVisible){var aisContext = WorkspaceController.Workspace.AisContext;if (_AisViewCube == null)return;if (isVisible && !aisContext.IsDisplayed(_AisViewCube)){aisContext.Display(_AisViewCube, false);WorkspaceController.Invalidate(true);}else if (!isVisible && aisContext.IsDisplayed(_AisViewCube)){aisContext.Remove(_AisViewCube, false);WorkspaceController.Invalidate(true);}}//--------------------------------------------------------------------------------------------------void _SetViewCube(bool isVisible, uint size, double duration){var aisContext = WorkspaceController.Workspace.AisContext;if (_AisViewCube != null){_SetViewCube(isVisible);return;}if (!isVisible)return;var bitmap = ResourceUtils.ReadBitmapFromResource(@"Visual\ViewCubeSides.png");if (bitmap == null){Messages.Error($"Could not load view cube texture from resource.");return;}var pixmap = PixMapHelper.ConvertFromBitmap(bitmap);if (pixmap == null){Messages.Error($"Could not load view cube texture into pixmap.");return;}_AisViewCube = new Macad.Occt.Ext.AIS_ViewCubeEx();_AisViewCube.SetSize(size * Viewport.DpiScale);_AisViewCube.SetBoxFacetExtension(size * Viewport.DpiScale * 0.15);_AisViewCube.SetViewAnimation(Viewport.AisAnimationCamera);_AisViewCube.SetFixedAnimationLoop(false);_AisViewCube.SetDrawAxes(false);_AisViewCube.SetDuration(duration);_AisViewCube.SetResetCamera(true);_AisViewCube.SetFitSelected(true);_AisViewCube.SetTexture(pixmap);_AisViewCube.SetTransformPersistence(new Graphic3d_TransformPers(Graphic3d_TransModeFlags.TriedronPers,Aspect_TypeOfTriedronPosition.RIGHT_UPPER, new Graphic3d_Vec2i(100, 100)));var color = new Quantity_Color();Quantity_Color.ColorFromHex("d9dfe5", color);_AisViewCube.BoxSideStyle().SetColor(color);Quantity_Color.ColorFromHex("93a4b6", color);_AisViewCube.BoxEdgeStyle().SetColor(color);Quantity_Color.ColorFromHex("a6b4c3", color);_AisViewCube.BoxCornerStyle().SetColor(color);var material = new Graphic3d_MaterialAspect(Graphic3d_NameOfMaterial.DEFAULT);material.SetAmbientColor(Quantity_NameOfColor.GRAY80.ToColor());material.SetDiffuseColor(Quantity_NameOfColor.GRAY20.ToColor());material.SetEmissiveColor(Quantity_NameOfColor.BLACK.ToColor());material.SetSpecularColor(Quantity_NameOfColor.BLACK.ToColor());_AisViewCube.SetMaterial(material);_AisViewCube.DynamicHilightAttributes().ShadingAspect().SetColor(Colors.Highlight);_AisViewCube.DynamicHilightAttributes().ShadingAspect().SetMaterial(material);if (isVisible){aisContext.Display(_AisViewCube, false);foreach (var viewport in WorkspaceController.Workspace.Viewports){aisContext.SetViewAffinity(_AisViewCube, viewport.V3dView, ReferenceEquals(viewport, Viewport));}}WorkspaceController.Invalidate(true);}//--------------------------------------------------------------------------------------------------void _SetTrihedron(bool visible){if (visible){Viewport?.V3dView?.TriedronDisplay(Aspect_TypeOfTriedronPosition.LEFT_LOWER, Quantity_NameOfColor.ALICEBLUE.ToColor(), 0.1, V3d_TypeOfVisualization.ZBUFFER);}else{Viewport?.V3dView?.TriedronErase();}}//--------------------------------------------------------------------------------------------------#endregion#region Rubberband Selectionint[] _CalcRectangleSelectionPoints(bool bottomUp){int height = 0, width = 0;_OcWindow.Size(ref width, ref height);int left = Math.Max(0, Math.Min((int) _StartedMousePosition.X, (int) _LastMousePosition.X));int right = Math.Min(width, Math.Max((int) _StartedMousePosition.X, (int) _LastMousePosition.X));int top = Math.Max(0, Math.Min((int) _StartedMousePosition.Y, (int) _LastMousePosition.Y));int bottom = Math.Min(height, Math.Max((int) _StartedMousePosition.Y, (int) _LastMousePosition.Y));if (bottomUp){top = height - top;bottom = height - bottom;}return new[] {left, bottom, right, top};}//--------------------------------------------------------------------------------------------------void _UpdateRubberbandSelection(){switch (_RubberbandMode){case RubberbandSelectionMode.Rectangle:var points = _CalcRectangleSelectionPoints(true);_AisRubberBand.SetRectangle(points[0], points[1], points[2], points[3]);break;case RubberbandSelectionMode.Freehand:int height = 0, width = 0;_OcWindow.Size(ref width, ref height);int currentPointX = (int) _LastMousePosition.X.Clamp(0, width);int currentPointY = (int) _LastMousePosition.Y.Clamp(0, height);var (lastPointX, lastPointY) = _RubberbandPoints[_RubberbandPoints.Count - 2];var distX = currentPointX - lastPointX;var distY = currentPointY - lastPointY;if (distX * distX + distY * distY > RubberbandFreehandSelectionThresholdSquared){_RubberbandPoints.Add((currentPointX, currentPointY));}else{_RubberbandPoints[_RubberbandPoints.Count - 1] = (currentPointX, currentPointY);}AisHelper.SetRubberbandPoints(_OcWindow, _AisRubberBand, _RubberbandPoints);break;}WorkspaceController.Workspace.AisContext.Redisplay(_AisRubberBand, false);}//--------------------------------------------------------------------------------------------------public void StartRubberbandSelection(RubberbandSelectionMode mode, bool includeTouched, Point? position=null){if (_AisRubberBand != null) return;_StartedMousePosition = position ?? _LastMousePosition;_RubberbandIncludeTouched = includeTouched;var aisContext = WorkspaceController.Workspace.AisContext;_AisRubberBand = new AIS_RubberBand(new Quantity_Color(Quantity_NameOfColor.BLUE1), Aspect_TypeOfLine.DASH, new Quantity_Color(Quantity_NameOfColor.BLUE1),0.9, 2, true);_RubberbandMode = mode;_RubberbandPoints.Clear();if (_RubberbandMode != RubberbandSelectionMode.Rectangle){var startPoint = ((int) _StartedMousePosition.X, (int) _StartedMousePosition.Y);_RubberbandPoints.Add(startPoint);_RubberbandPoints.Add(startPoint);}_UpdateRubberbandSelection();aisContext.Display(_AisRubberBand, false);foreach (var viewport in WorkspaceController.Workspace.Viewports){aisContext.SetViewAffinity(_AisRubberBand, viewport.V3dView, ReferenceEquals(viewport, Viewport));}WorkspaceController.Invalidate(true);}//--------------------------------------------------------------------------------------------------void _StopRubberbandSelection(){if (_AisRubberBand != null){WorkspaceController.Workspace.AisContext.Remove(_AisRubberBand, false);_AisRubberBand = null;switch (_RubberbandMode){case RubberbandSelectionMode.Rectangle:WorkspaceController.SelectByRectangle(_CalcRectangleSelectionPoints(false), _RubberbandIncludeTouched, this);break;case RubberbandSelectionMode.Freehand:// Close polyline_RubberbandPoints.Add(_RubberbandPoints[0]);WorkspaceController.SelectByPolyline(_RubberbandPoints, _RubberbandIncludeTouched, this);break;}_RubberbandPoints.Clear();WorkspaceController.Invalidate(true);}}//--------------------------------------------------------------------------------------------------#endregion#region Imagepublic Bitmap RenderToBitmap(uint width, uint height){if (Viewport?.V3dView == null || width == 0 || height == 0)return null;try{_SetTrihedron(false);_SetViewCube(false);var pixmap = new Image_AlienPixMap();pixmap.InitZero(Image_Format.RGB, width, height);Viewport?.V3dView?.ToPixMap(pixmap, (int)width, (int)height);_SetTrihedron(_ShowTrihedron);_SetViewCube(true);return PixMapHelper.ConvertToBitmap(pixmap);}catch (Exception ){_SetTrihedron(_ShowTrihedron);_SetTrihedron(true);return null;}}//--------------------------------------------------------------------------------------------------#endregion}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Windows;
using System.Windows.Input;
using Macad.Common;
using Macad.Common.Interop;
using Macad.Core;
using Macad.Occt;
using Macad.Occt.Helper;
using Macad.Resources;
using Point = System.Windows.Point;namespace Macad.Interaction
{// 视口控制器负责管理图形应用程序中的视口交互public sealed class ViewportController : BaseObject, IDisposable{// 橡皮筋自由形状选择的阈值(用于判断两个点之间是否应该绘制直线)const int RubberbandFreehandSelectionThresholdSquared = 100;// 橡皮筋选择的模式:矩形或自由形状public enum RubberbandSelectionMode{Rectangle,Freehand}// 工作区控制器实例,用于处理视口所在的工作区public WorkspaceController WorkspaceController { get; private set; }// 视口实例,代表了用户界面中的一个图形窗口public Viewport Viewport { get; private set; }// 视口是否锁定到平面public bool LockedToPlane{get { return _LockedToPlane; }set{if (_LockedToPlane != value){// 如果值发生变化,更新视图if (value){SetPredefinedView(PredefinedViews.WorkingPlane); }_LockedToPlane = value;_SetViewCube(!value);_SetTrihedron(!value && _ShowTrihedron);RaisePropertyChanged(); // 通知属性变化}}}// 视口是否处于橡皮筋选择状态public bool IsInRubberbandSelection{get { return _AisRubberBand != null; }}// 构造函数,初始化视口控制器public ViewportController(Viewport viewport, WorkspaceController workspaceController){Debug.Assert(viewport != null);Viewport = viewport;WorkspaceController = workspaceController;Init(); // 执行初始化}// 析构函数,用于释放资源~ViewportController(){Dispose(false);}// 释放资源public void Dispose(){Dispose(true);}// 初始化方法,用于设置初始状态void Init(){// 订阅参数变化事件ViewportParameterSet.ParameterChanged += _ViewportParameterSet_ParameterChanged;// 获取参数集合并初始化视口var parameterSet = InteractiveContext.Current.Parameters.Get<ViewportParameterSet>();Viewport.Init(parameterSet.EnableAntialiasing);}// 窗口初始化方法,用于创建视口窗口public IntPtr InitWindow(IntPtr parentHWnd, Int32Rect initialRect){Debug.Assert(Viewport.V3dView != null);uint style;// 如果窗口类还未创建,则创建窗口类if (_OcWindowClass == null){style = Win32Api.CS_OWNDC;_OcWindowClass = new WNT_WClass(new TCollection_AsciiString("WorkspaceView"), IntPtr.Zero, style, 0);}// 如果初始矩形为空,则设置默认矩形尺寸if (initialRect.IsEmpty){initialRect = new Int32Rect(0, 0, 64, 64);}// 设置窗口样式style = Win32Api.WS_VISIBLE | (parentHWnd == IntPtr.Zero ? Win32Api.WS_POPUP : Win32Api.WS_CHILD);// 创建窗口实例并映射到父窗口上_OcWindow = new WNT_Window("WorkspaceView", _OcWindowClass, style, initialRect.X, initialRect.Y, initialRect.Width, initialRect.Height, Quantity_NameOfColor.GRAY50, parentHWnd);_OcWindow.Map();// 将视口与窗口关联起来Viewport.V3dView.SetWindow(_OcWindow);//Viewport.InitV3dView();if (_ZoomFitAllOnInit){_ZoomFitAllOnInit = false;ZoomFitAll();}Viewport.V3dView.Update();Viewport.V3dView.MustBeResized();Viewport.V3dView.SetImmediateUpdate(false);_UpdateParameter(); // 更新参数var handle = _OcWindow.HWindow();return handle;}// 处理视口参数变化的事件void _ViewportParameterSet_ParameterChanged(OverridableParameterSet set, string key){_UpdateParameter(); // 更新参数}// 更新参数void _UpdateParameter(){var parameterSet = InteractiveContext.Current.Parameters.Get<ViewportParameterSet>();_SetViewCube(parameterSet.ShowViewCube, parameterSet.ViewCubeSize, parameterSet.ViewCubeAnimationDuration); // 设置视图立方体_SetTrihedron(parameterSet.ShowTrihedron); // 设置三轴指示器_ShowTrihedron = parameterSet.ShowTrihedron; // 记录是否显示三轴指示器}// 更多代码...}
}
这段C#代码定义了一个名为ViewportController
的类,它负责控制图形应用程序中的视口。让我们逐步解释这个类的关键部分:
-
命名空间和依赖项:该类导入了多个命名空间,包括系统库如
System
、System.Drawing
和System.Windows
,以及来自 Macad 应用程序的自定义命名空间。 -
ViewportController 类:这个类管理与视口的交互,包括导航、选择和渲染。
-
属性:它具有诸如
WorkspaceController
、Viewport
、LockedToPlane
和IsInRubberbandSelection
等属性,用于管理视口的状态和行为。 -
初始化:该类提供了初始化(
Init
)和窗口创建(InitWindow
)的方法,在这些方法中设置了视口以进行渲染。 -
视口导航:
Rotate
、Pan
、Zoom
、ZoomFitAll
和SetPredefinedView
等方法控制视口的导航。 -
橡皮筋选择:它包括用于橡皮筋选择的功能,允许用户通过绘制矩形或自由形状来选择对象。
-
三轴和视图立方体:
_SetTrihedron
和_SetViewCube
等方法管理视口内定位指示器的显示。 -
图像渲染:该类提供了将视口内容渲染到位图图像的功能,使用
RenderToBitmap
方法。
总的来说,这个类封装了图形应用程序中视口交互的逻辑,提供了导航、选择和渲染的方法。
22.
using Macad.Common;namespace Macad.Interaction
{// 视口参数集合,继承自可重写的参数集合public sealed class ViewportParameterSet : OverridableParameterSet{// 用于调整草图选择的灵敏度public int SketchSelectionSensitivity { get => GetValue<int>(); set => SetValue(value); }// 是否显示视图立方体public bool ShowViewCube { get => GetValue<bool>(); set => SetValue(value); }// 视图立方体的尺寸public uint ViewCubeSize { get => GetValue<uint>(); set => SetValue(value); }// 视图立方体动画的持续时间public double ViewCubeAnimationDuration { get => GetValue<double>(); set => SetValue(value); }// 是否显示三轴指示器public bool ShowTrihedron { get => GetValue<bool>(); set => SetValue(value); }// 是否启用抗锯齿public bool EnableAntialiasing { get => GetValue<bool>(); set => SetValue(value); }// 构造函数,初始化参数并设置默认值public ViewportParameterSet(){SetDefaultValue(nameof(SketchSelectionSensitivity), 1); // 默认草图选择灵敏度为1SetDefaultValue(nameof(ShowViewCube), true); // 默认显示视图立方体SetDefaultValue(nameof(ViewCubeSize), (uint)50); // 默认视图立方体尺寸为50SetDefaultValue(nameof(ViewCubeAnimationDuration), 0.3); // 默认视图立方体动画持续时间为0.3SetDefaultValue(nameof(ShowTrihedron), true); // 默认显示三轴指示器SetDefaultValue(nameof(EnableAntialiasing), true); // 默认启用抗锯齿}}
}
这段代码定义了一个名为 ViewportParameterSet
的类,用于管理视口的参数设置。其中包括草图选择的灵敏度、是否显示视图立方体、视图立方体的尺寸和动画持续时间、是否显示三轴指示器以及是否启用抗锯齿等参数。
23.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Threading;
using Macad.Interaction.Visual;
using Macad.Common;
using Macad.Core;
using Macad.Core.Topology;
using Macad.Occt;
using Macad.Occt.Extensions;
using Macad.Occt.Helper;namespace Macad.Interaction
{// 工作区控制器,实现了 IContextMenuItemProvider 接口和 IDisposable 接口public sealed class WorkspaceController : BaseObject, IContextMenuItemProvider, IDisposable{// 属性// 工作区public Workspace Workspace { get; }// 活动视口public Viewport ActiveViewport { get; set; }// 活动视口控制器public ViewportController ActiveViewControlller { get { return GetViewController(ActiveViewport); } }// 吸附处理器public SnapHandler SnapHandler { get; }// HUD 管理器public IHudManager HudManager { get; set; }// 工作平面锁定public bool LockWorkingPlane { get; set; }// 选择管理器public SelectionManager Selection { get; }// 是否正在进行选择操作public bool IsSelecting { get; private set; }// 可视对象管理器public VisualObjectManager VisualObjects { get; init; }//--------------------------------------------------------------------------------------------------// 成员变量readonly List<ViewportController> _ViewControllers = new(); // 视口控制器列表readonly DispatcherTimer _RedrawTimer; // 重绘定时器AISX_Grid _Grid; // 网格对象XY _LastGridSize = new(200.0, 200.0); // 上一次的网格尺寸bool _GridNeedsUpdate; // 网格是否需要更新标志位//--------------------------------------------------------------------------------------------------// 构造函数// 初始化工作区控制器public WorkspaceController(Workspace workspace){Debug.Assert(workspace != null);Workspace = workspace; // 初始化工作区workspace.GridChanged += _Workspace_GridChanged; // 监听网格改变事件Viewport.ViewportChanged += _Viewport_ViewportChanged; // 监听视口改变事件VisualObjects = new VisualObjectManager(this); // 初始化可视对象管理器Selection = new SelectionManager(this); // 初始化选择管理器Selection.SelectionChanging += _Selection_SelectionChanging; // 监听选择改变事件Selection.SelectionChanged += _Selection_SelectionChanged; // 监听选择改变事件SnapHandler = new SnapHandler(this); // 初始化吸附处理器VisualParameterSet.ParameterChanged += _VisualParameterSet_ParameterChanged; // 监听可视参数改变事件_RedrawTimer = new DispatcherTimer(DispatcherPriority.Render) // 初始化重绘定时器{Interval = TimeSpan.FromSeconds(1.0 / 60.0) // 设置重绘时间间隔为 1/60 秒};_RedrawTimer.Tick += _RedrawTimer_Tick; // 监听重绘事件_RedrawTimer.Start(); // 启动重绘定时器InitWorkspace(); // 初始化工作区}// 析构函数~WorkspaceController(){Dispose(false);}// 释放资源public void Dispose(){Dispose(true);}// 释放资源void Dispose(bool disposing){if (disposing){if (_CurrentTool != null)CancelTool(_CurrentTool, true);StopEditor();}_CurrentTool = null;_CurrentEditor = null;_Grid = null;_RedrawTimer.Stop();_RedrawTimer.Tick -= _RedrawTimer_Tick;VisualParameterSet.ParameterChanged -= _VisualParameterSet_ParameterChanged;Selection.SelectionChanged -= _Selection_SelectionChanged;Selection.SelectionChanging -= _Selection_SelectionChanging;Selection.Dispose();VisualObjects.Dispose();SnapHandler.Dispose();Viewport.ViewportChanged -= _Viewport_ViewportChanged;foreach (var viewCtrl in _ViewControllers){viewCtrl.Dispose();}_ViewControllers.Clear();_LastDetectedInteractive?.Dispose();Workspace.GridChanged -= _Workspace_GridChanged;Workspace.Dispose();GC.SuppressFinalize(this);}//--------------------------------------------------------------------------------------------------// 工作区网格改变事件处理函数void _Workspace_GridChanged(Workspace sender){if (Workspace == sender){_RecalculateGridSize();_GridNeedsUpdate = true;_UpdateGrid();Invalidate();}}//--------------------------------------------------------------------------------------------------// 视口改变事件处理函数void _Viewport_ViewportChanged(Viewport sender){if (_ViewControllers.Any(vc => vc.Viewport == sender)){_RecalculateGridSize();Invalidate();}}//--------------------------------------------------------------------------------------------------// 可视参数改变事件处理函数void _VisualParameterSet_ParameterChanged(OverridableParameterSet set, string key){_UpdateParameter();}//--------------------------------------------------------------------------------------------------// 初始化工作区void InitWorkspace(){Workspace.InitV3dViewer();Workspace.InitAisContext();_InitVisualSettings();foreach (var view in Workspace.Viewports){var viewCtrl = new ViewportController(view, this);_ViewControllers.Add(viewCtrl);}_Grid = new AISX_Grid();AisHelper.DisableGlobalClipPlanes(_Grid);Workspace.AisContext?.Display(_Grid, 0, -1, false);VisualObjects.InitEntities();_UpdateGrid();}//--------------------------------------------------------------------------------------------------// 初始化可视设置void _InitVisualSettings(){var aisContext = Workspace.AisContext;_UpdateParameter();// Higlight Selectedvar selectionDrawer = new Prs3d_Drawer();selectionDrawer.SetupOwnDefaults();selectionDrawer.SetColor(Colors.Selection);selectionDrawer.SetDisplayMode(0);selectionDrawer.SetZLayer(0); // Graphic3d_ZLayerId_DefaultselectionDrawer.SetTypeOfDeflection(Aspect_TypeOfDeflection.RELATIVE);selectionDrawer.SetDeviationAngle(aisContext.DeviationAngle());selectionDrawer.SetDeviationCoefficient(aisContext.DeviationCoefficient());aisContext.SetSelectionStyle(selectionDrawer);aisContext.SetHighlightStyle(Prs3d_TypeOfHighlight.Selected, selectionDrawer);aisContext.SetHighlightStyle(Prs3d_TypeOfHighlight.LocalSelected, selectionDrawer);aisContext.SetHighlightStyle(Prs3d_TypeOfHighlight.SubIntensity, selectionDrawer);// Higlight Dynamicvar hilightDrawer = new Prs3d_Drawer();hilightDrawer.SetupOwnDefaults();hilightDrawer.SetColor(Colors.Highlight);hilightDrawer.SetDisplayMode(0);hilightDrawer.SetZLayer(-2); // Graphic3d_ZLayerId_TophilightDrawer.SetTypeOfDeflection(Aspect_TypeOfDeflection.RELATIVE);hilightDrawer.SetDeviationAngle(aisContext.DeviationAngle());hilightDrawer.SetDeviationCoefficient(aisContext.DeviationCoefficient());aisContext.SetHighlightStyle(Prs3d_TypeOfHighlight.Dynamic, hilightDrawer);// Higlight Localvar hilightLocalDrawer = new Prs3d_Drawer();hilightLocalDrawer.SetupOwnDefaults();hilightLocalDrawer.SetColor(Colors.Highlight);hilightLocalDrawer.SetDisplayMode(1);hilightLocalDrawer.SetZLayer(-2); // Graphic3d_ZLayerId_TophilightLocalDrawer.SetTypeOfDeflection(Aspect_TypeOfDeflection.RELATIVE);hilightLocalDrawer.SetDeviationAngle(aisContext.DeviationAngle());hilightLocalDrawer.SetDeviationCoefficient(aisContext.DeviationCoefficient());var shadingAspect = new Prs3d_ShadingAspect();shadingAspect.SetColor(Colors.Highlight);shadingAspect.SetTransparency(0);var aspectFill = new Graphic3d_AspectFillArea3d(shadingAspect.Aspect());aspectFill.SetPolygonOffsets((int)Aspect_PolygonOffsetMode.Fill, 0.99f, 0.0f);shadingAspect.SetAspect(aspectFill);hilightLocalDrawer.SetShadingAspect(shadingAspect);var lineAspect = new Prs3d_LineAspect(Colors.Highlight, Aspect_TypeOfLine.SOLID, 3.0);hilightLocalDrawer.SetLineAspect(lineAspect);hilightLocalDrawer.SetSeenLineAspect(lineAspect);hilightLocalDrawer.SetWireAspect(lineAspect);hilightLocalDrawer.SetFaceBoundaryAspect(lineAspect);hilightLocalDrawer.SetFreeBoundaryAspect(lineAspect);hilightLocalDrawer.SetUnFreeBoundaryAspect(lineAspect);hilightLocalDrawer.SetPointAspect(Marker.CreateBitmapPointAspect(Marker.BallImage, Colors.Highlight));aisContext.SetHighlightStyle(Prs3d_TypeOfHighlight.LocalDynamic, hilightLocalDrawer);}//--------------------------------------------------------------------------------------------------// 更新参数void _UpdateParameter(){if (Workspace.AisContext == null)return;var aisContext = Workspace.AisContext;var parameterSet = InteractiveContext.Current.Parameters.Get<VisualParameterSet>();aisContext.SetDeviationCoefficient(parameterSet.DeviationCoefficient);aisContext.SetDeviationAngle(parameterSet.DeviationAngle.ToRad());}//--------------------------------------------------------------------------------------------------// 获取指定索引的视口控制器public ViewportController GetViewController(int viewIndex){Debug.Assert(viewIndex >= 0);Debug.Assert(viewIndex < _ViewControllers.Count);return _ViewControllers[viewIndex];}//--------------------------------------------------------------------------------------------------// 获取指定视口的视口控制器public ViewportController GetViewController(Viewport viewport){if(viewport == null){return null;}return _ViewControllers.Find(vc => vc.Viewport == viewport);}//--------------------------------------------------------------------------------------------------#endregion
#region 工具public Tool CurrentTool
{get { return _CurrentTool; }set {// 什么也不做,此setter必须是public以启用正确的绑定}
}
Tool _CurrentTool;//--------------------------------------------------------------------------------------------------public bool StartTool(Tool tool)
{try{if (CurrentTool != null && !CancelTool(CurrentTool, true))return false;if (tool != null){tool.WorkspaceController = this;_CurrentTool = tool;CurrentEditor?.StopTools();if (!tool.Start()){return false;}RaisePropertyChanged(nameof(CurrentTool));Invalidate(true);return true;}return false;}catch (Exception e){Debug.WriteLine(e);return false;}
}//--------------------------------------------------------------------------------------------------public bool CancelTool(Tool tool, bool force)
{var isCancelled = true;Debug.Assert(tool != null);if (CurrentTool != tool)return false;if (CurrentTool != null){if (!CurrentTool.Cancel(force)){Debug.WriteLine("CancelTool -> CurrentTool.Cancel() denied.");isCancelled = false;}}if (isCancelled){_CurrentTool = null;RaisePropertyChanged(nameof(CurrentTool));}Invalidate();UpdateSelection();return isCancelled;
}//--------------------------------------------------------------------------------------------------public void RemoveTool(Tool tool)
{Debug.Assert(tool != null);if (CurrentTool != tool)return;_CurrentTool = null;RaisePropertyChanged(nameof(CurrentTool));Invalidate();UpdateSelection();if (CurrentTool == null){_CurrentEditor?.StartTools();}
}//--------------------------------------------------------------------------------------------------public bool PrepareUndo()
{if (CurrentTool != null){return CurrentTool.PrepareUndo();}return true;
}//--------------------------------------------------------------------------------------------------#endregion#region 选择变化void _Selection_SelectionChanging(SelectionManager selectionManager, SelectionManager.SelectionChangingCancelEventArgs eventArgs)
{if (EnumerateControls().Any(child => child.OnEntitySelectionChanging(eventArgs.EntitiesToSelect, eventArgs.EntitiesToUnSelect))){eventArgs.Cancel = true;}
}//--------------------------------------------------------------------------------------------------void _Selection_SelectionChanged(SelectionManager selectionManager)
{if (VisualObjects.EntityIsolationEnabled){if (VisualObjects.GetIsolatedEntities().SymmetricExcept(selectionManager.SelectedEntities).Any()){VisualObjects.SetIsolatedEntities(null);}}UpdateEditor();
}//--------------------------------------------------------------------------------------------------#endregion#region 重绘和无效化//static int _InvalidateCount = 0;
//static int _RedrawCount = 0;public void Invalidate(bool immediateOnly = false, bool forceRedraw = false)
{//_InvalidateCount++;//Debug.WriteLine("Invalidated: {0} Redrawn: {1}", _InvalidateCount, _RedrawCount);Workspace.NeedsImmediateRedraw = true;if (!immediateOnly)Workspace.NeedsRedraw = true;if(forceRedraw)_Redraw();
}//--------------------------------------------------------------------------------------------------void _Redraw()
{_UpdateGrid();if (Workspace.V3dViewer == null)return;Workspace.Viewports.ForEach(v =>{if (!v.AisAnimationCamera.IsStopped()){v.AisAnimationCamera.UpdateTimer();Workspace.NeedsRedraw = true;}});if (Workspace.NeedsRedraw){VisualObjects.UpdateInvalidatedEntities();Workspace.Viewports.ForEach(v =>{if(v.RenderMode == Viewport.RenderModes.HLR)v.V3dView?.Update();});Workspace.V3dViewer.Redraw();Workspace.V3dViewer.RedrawImmediate();Workspace.NeedsRedraw = false;}else if (Workspace.NeedsImmediateRedraw){Workspace.V3dViewer.RedrawImmediate();Workspace.NeedsImmediateRedraw = false;}
}//--------------------------------------------------------------------------------------------------void _RedrawTimer_Tick(object sender, EventArgs e)
{_Redraw();
}//--------------------------------------------------------------------------------------------------#endregion#region 网格//--------------------------------------------------------------------------------------------------void _RecalculateGridSize()
{Pnt[] corners = new Pnt[4];double u = 0;double v = 0;double sizeX = 50.0 * Workspace.GridStep;double sizeY = 50.0 * Workspace.GridStep;Pln plane = Workspace.WorkingContext.WorkingPlane;foreach (var viewportController in _ViewControllers){var viewport = viewportController.Viewport;if (viewport == null)continue;var screenSize = viewport.ScreenSize;viewport.ScreenToPoint(plane, 0, 0, out corners[0]);viewport.ScreenToPoint(plane, 0, screenSize.Height, out corners[1]);viewport.ScreenToPoint(plane, screenSize.Width, screenSize.Height, out corners[2]);viewport.ScreenToPoint(plane, screenSize.Width, 0, out corners[3]);foreach (var corner in corners){ElSLib.Parameters(plane, corner, ref u, ref v);sizeX = Math.Max(sizeX, u.Abs());sizeY = Math.Max(sizeY, v.Abs());}}// 取最大值,增加10,并且限制在一个(不现实的)最大值内XY newGridSize = new XY(Math.Min(sizeX + 10.0, Workspace.GridStep * 1000.0),Math.Min(sizeY + 10.0, Workspace.GridStep * 1000.0));XY diff = _LastGridSize - newGridSize;if (diff.X is < 0 or > 50.0 || diff.Y is < 0 or > 50.0){_LastGridSize = newGridSize;_GridNeedsUpdate = true;}
}//--------------------------------------------------------------------------------------------------void _UpdateGrid()
{if (!_GridNeedsUpdate) return;if (_Grid is null)return;WorkingContext wc = Workspace.WorkingContext;if (Workspace.GridEnabled){Ax3 position = wc.WorkingPlane.Position;if (wc.GridRotation != 0){position.Rotate(wc.WorkingPlane.Axis, wc.GridRotation.ToRad());}_Grid.SetPosition(position);_Grid.SetExtents(_LastGridSize.X, _LastGridSize.Y);_Grid.SetDivisions(wc.GridStep, wc.GridDivisions);if (wc.GridType == Workspace.GridTypes.Rectangular){Workspace.AisContext?.SetDisplayMode(_Grid, 1, false);}else{Workspace.AisContext?.SetDisplayMode(_Grid, 2, false);}}else{Workspace.AisContext?.SetDisplayMode(_Grid, 0, false);}_GridNeedsUpdate = false;
}//--------------------------------------------------------------------------------------------------#endregion#region 删除、复制、剪切板public bool CanDelete()
{if(CurrentTool != null)return CurrentTool.CanDelete();elsereturn InteractiveContext.Current.DocumentController.CanDelete(Selection.SelectedEntities);
}//--------------------------------------------------------------------------------------------------public void Delete()
{if(CurrentTool != null)CurrentTool.Delete();elseInteractiveContext.Current.DocumentController.Delete(Selection.SelectedEntities);
}//--------------------------------------------------------------------------------------------------public bool CanDuplicate()
{if(CurrentTool != null)return CurrentTool.CanDuplicate();elsereturn InteractiveContext.Current.DocumentController.CanDuplicate(Selection.SelectedEntities);
}//--------------------------------------------------------------------------------------------------public void Duplicate()
{if(CurrentTool != null)CurrentTool.Duplicate();elseInteractiveContext.Current.DocumentController.Duplicate(Selection.SelectedEntities);
}//--------------------------------------------------------------------------------------------------public bool CanCopyToClipboard()
{if(CurrentTool != null)return CurrentTool.CanCopyToClipboard();elsereturn InteractiveContext.Current.DocumentController.CanCopyToClipboard(Selection.SelectedEntities);
}//--------------------------------------------------------------------------------------------------public void CopyToClipboard()
{if(CurrentTool != null)CurrentTool.CopyToClipboard();elseInteractiveContext.Current.DocumentController.CopyToClipboard(Selection.SelectedEntities);
}//--------------------------------------------------------------------------------------------------public bool CanPasteFromClipboard()
{if(CurrentTool != null)return CurrentTool.CanPasteFromClipboard();elsereturn InteractiveContext.Current.DocumentController.CanPasteFromClipboard();
}//--------------------------------------------------------------------------------------------------public IEnumerable<InteractiveEntity> PasteFromClipboard()
{if(CurrentTool != null)return CurrentTool.PasteFromClipboard();elsereturn InteractiveContext.Current.DocumentController.PasteFromClipboard();
}//--------------------------------------------------------------------------------------------------#endregion#region IActionCommandProviderpublic void EnrichContextMenu(ContextMenuItems itemList)
{if (CurrentTool != null) return;itemList.AddCommandIfExecutable(WorkspaceCommands.StartEditing, null);if (Selection.SelectedEntities.Count > 0){itemList.AddCommand(WorkspaceCommands.Transform);}
}//--------------------------------------------------------------------------------------------------#endregion
24.
using Macad.Common.Serialization; // 导入Macad.Common.Serialization命名空间,用于序列化namespace Macad.Interaction
{[AutoRegisterHost] // 标记该类为自动注册的宿主类public static partial class InteractionModule // 定义名为InteractionModule的静态类{static bool _IsInitialized; // 声明一个静态布尔变量_IsInitialized,默认为false,用于跟踪模块是否已经初始化//--------------------------------------------------------------------------------------------------public static void Initialize() // 定义一个公共静态方法Initialize,用于初始化交互模块{if (_IsInitialized) // 如果模块已经初始化过,则直接返回,避免重复初始化return;Serializer.RegisterNamespaceAlias("Editors", "Macad.Interaction.Editors"); // 注册命名空间别名,用于序列化器_DoAutoRegister(); // 调用私有静态方法_DoAutoRegister,用于自动注册相关组件_IsInitialized = true; // 将模块的初始化状态标记为已完成}//--------------------------------------------------------------------------------------------------}
}
这段代码定义了一个静态类InteractionModule
,其中包含了一个静态方法Initialize()
用于初始化交互模块。在初始化过程中,会注册命名空间别名以及自动注册相关组件。同时,使用了AutoRegisterHost
特性标记该类为自动注册的宿主类。
这篇关于macad.interaction解析workspace的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!