1.toolkits
using System.Linq;
using Macad.Common;
using Macad.Core.Drawing;
using Macad.Core.Geom;
using Macad.Core.Shapes;
using Macad.Core.Topology;
using Macad.Occt;
namespace Macad.Core.Toolkits
{
// 将 BRep 形状转换为可编辑的草图工具类
public class ConvertToEditableSketch : IDrawingRenderer, IRendererCapabilities
{
// 将 BRep 形状转换为可编辑的草图
public static Sketch Convert(TopoDS_Shape brepShape)
{
var converter = new ConvertToEditableSketch();
converter.Add(brepShape);
return converter._Sketch;
}
//--------------------------------------------------------------------------------------------------
// 折叠形状堆栈,将非草图形状转换为草图
public static bool CollapseShapeStack(Body[] bodies, bool saveUndo = true)
{
var result = true;
// 获取原始形状中的草图
Shape[] originalShapes = bodies.Select(body => body.Shape)
.Where(shape => shape.ShapeType == ShapeType.Sketch)
.ToArray();
if (originalShapes.Length == 0)
return false; // 没有需要处理的草图形状
// 获取原始形状的 BRep 表示
TopoDS_Shape[] originalBreps = originalShapes.Select(shape => shape.GetBRep())
.ToArray();
for (var i = 0; i < bodies.Length; i++)
{
var originalShape = originalShapes[i];
if (originalShape is Sketch)
{
continue;
}
if (originalBreps[i] == null)
{
result = false;
continue;
}
// 将非草图形状转换为草图
Sketch newSketch = Convert(originalBreps[i]);
Body body = bodies[i];
body.CollapseShapeStack(newSketch, saveUndo);
// 修正转换
if (EdgeAlgo.GetPlaneOfEdges(originalBreps[i], out Geom_Plane plane))
{
var worldPosition = plane.Position().Transformed(body.GetTransformation());
Trsf trsf = new Trsf(new Ax3(Pnt.Origin, worldPosition.Direction, worldPosition.XDirection), Ax3.XOY);
body.Position = worldPosition.Location;
body.Rotation = trsf.GetRotation();
}
}
return result;
}
//--------------------------------------------------------------------------------------------------
readonly Sketch _Sketch;
readonly SketchBuilder _Builder;
bool _InPath;
bool _PathIsOpen;
//--------------------------------------------------------------------------------------------------
// 构造函数,初始化草图和草图构建器
ConvertToEditableSketch()
{
_Sketch = new Sketch();
_Builder = new SketchBuilder(_Sketch);
}
//--------------------------------------------------------------------------------------------------
// 向草图中添加 BRep 形状
void Add(TopoDS_Shape brepShape)
{
BrepRenderHelper.RenderShape(this, brepShape);
}
//--------------------------------------------------------------------------------------------------
#region IRendererCapabilities
// 曲线的最大贝塞尔曲线阶数
int IRendererCapabilities.BezierCurveMaxDegree => 3;
// 椭圆弧是否作为曲线渲染
bool IRendererCapabilities.EllipticalArcAsCurve => true;
#endregion
#region IDrawingRenderer
// 获取渲染器的功能
IRendererCapabilities IDrawingRenderer.Capabilities => this;
// 绘制直线
void IDrawingRenderer.Line(Pnt2d start, Pnt2d end)
{
if (_InPath)
{
_StartPath(start.X, start.Y);
_Builder.LineTo(end.X, end.Y);
}
else
{
_Builder.Line(start.X, start.Y, end.X, end.Y);
}
}
// 绘制圆
void IDrawingRenderer.Circle(Pnt2d center, double radius, double startAngle, double endAngle)
{
// 实现绘制圆的方法
}
// 绘制椭圆
void IDrawingRenderer.Ellipse(Pnt2d center, double majorRadius, double minorRadius, double rotation, double startAngle, double endAngle)
{
// 实现绘制椭圆的方法
}
// 绘制贝塞尔曲线
void IDrawingRenderer.BezierCurve(Pnt2d[] knots)
{
// 实现绘制贝塞尔曲线的方法
}
// 开始绘制路径段
void IDrawingRenderer.BeginPathSegment()
{
_InPath = true;
}
// 结束绘制路径段
void IDrawingRenderer.EndPathSegment()
{
// 实现结束绘制路径段的方法
}
// 绘制文本
void IDrawingRenderer.Text(string text, Pnt2d position, double rotation)
{
// 实现绘制文本的方法
}
// 设置样式
void IDrawingRenderer.SetStyle(StrokeStyle stroke, FillStyle fill, FontStyle font)
{
// 实现设置样式的方法
}
#endregion
}
}
这段代码实现了将 BRep 形状转换为可编辑的草图的功能,并提供了一些绘制方法和样式设置方法,用于在草图中绘制基本图形元素。同时,它还实现了一个方法,用于将非草图形状堆栈转换为草图形状堆栈。
2.
using System.Linq;
using Macad.Core.Shapes;
using Macad.Core.Topology;
using Macad.Occt;
namespace Macad.Core.Toolkits
{
// 将形状堆栈中的所有非固体形状转换为固体形状的工具类
public static class ConvertToSolid
{
// 折叠形状堆栈,将非固体形状转换为固体形状
public static bool CollapseShapeStack(Body[] bodies, bool saveUndo = true)
{
var result = true;
// 获取原始形状中的固体形状
Shape[] originalShapes = bodies.Select(body => body.Shape)
.Where(shape => shape.ShapeType == ShapeType.Solid)
.ToArray();
if (originalShapes.Length == 0)
return false; // 没有需要处理的固体形状
// 获取原始形状的 BRep 表示
TopoDS_Shape[] originalBreps = originalShapes.Select(shape => shape.GetBRep())
.ToArray();
for (var i = 0; i < bodies.Length; i++)
{
var originalShape = originalShapes[i];
if (originalShape is Solid)
{
continue;
}
if (originalBreps[i] == null)
{
result = false;
continue;
}
// 将非固体形状转换为固体形状
Solid solid = Solid.Create(originalBreps[i]);
bodies[i].CollapseShapeStack(solid, saveUndo);
}
return result;
}
//--------------------------------------------------------------------------------------------------
}
}
段代码定义了一个名为 ConvertToSolid
的静态类,其中包含一个静态方法 CollapseShapeStack
。该方法用于将形状堆栈中的所有非固体形状转换为固体形状。具体作用如下:
CollapseShapeStack
方法接受一个 Body
数组和一个布尔类型参数 saveUndo
,用于指示是否保存撤消信息。originalShapes
数组中。Solid.Create
方法,该方法接受一个 TopoDS_Shape
参数并返回对应的 Solid
对象。Body
上,并根据需要保存撤消信息。3.
using System;
using System.Linq;
using Macad.Core.Components;
using Macad.Core;
using Macad.Core.Geom;
using Macad.Core.Shapes;
using Macad.Core.Topology;
using Macad.Common;
using Macad.Common.Serialization;
using Macad.Core.Drawing;
using Macad.Occt;
namespace Macad.Core.Toolkits
{
// 蚀刻蒙版组件,用于生成蚀刻蒙版的工具类
[SerializeType]
public sealed class EtchingMaskComponent : Component, IShapeDependent
{
#region Properties
// 层数
[SerializeMember]
public int LayerCount
{
get { return _LayerCount; }
set
{
var clampedValue = value.Clamp(1, 2); // 限制层数在1到2之间
if (_LayerCount != clampedValue)
{
SaveUndo();
_LayerCount = clampedValue;
Invalidate();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 形状 GUID
[SerializeMember]
public Guid ShapeGuid
{
get { return _ShapeGuid; }
set
{
if (_ShapeGuid != value)
{
SaveUndo();
_ShapeGuid = value;
Invalidate();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 参考面子形状
[SerializeMember]
public SubshapeReference ReferenceFace
{
get { return _ReferenceFace; }
set
{
if (_ReferenceFace != value)
{
SaveUndo();
_ReferenceFace = value;
Invalidate();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 是否有效
public bool IsValid
{
get
{
if (_Layers != null && _Layers.Length > 0)
return true;
if (!_HasErrors)
return Make(); // 尝试生成蚀刻蒙版数据
return false;
}
}
//--------------------------------------------------------------------------------------------------
// 图层数组
public SliceByPlanes.Slice[] Layers
{
get
{
if (!IsValid && !_HasErrors)
Make(); // 如果数据无效,则尝试生成蚀刻蒙版数据
return _Layers;
}
}
//--------------------------------------------------------------------------------------------------
// 重构的 BRep
public TopoDS_Shape ReconstructedBRep
{
get
{
if (!IsValid && !_HasErrors)
Make(); // 如果数据无效,则尝试生成蚀刻蒙版数据
return _ReconstructedBRep;
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Members and infrastructure
int _LayerCount; // 层数
SubshapeReference _ReferenceFace; // 参考面子形状
Guid _ShapeGuid; // 形状 GUID
bool _HasErrors; // 是否有错误
SliceByPlanes.Slice[] _Layers; // 图层数组
TopoDS_Shape _ReconstructedBRep; // 重构的 BRep
//--------------------------------------------------------------------------------------------------
// 构造函数
public EtchingMaskComponent()
{
_LayerCount = 2; // 默认层数为2
}
//--------------------------------------------------------------------------------------------------
// 使蚀刻蒙版组件失效
public void Invalidate()
{
_Layers = null;
_ReconstructedBRep = null;
_HasErrors = false;
RaisePropertyChanged(nameof(Layers));
RaisePropertyChanged(nameof(ReconstructedBRep));
}
//--------------------------------------------------------------------------------------------------
// 当所有者发生变化时执行操作
protected override void OwnerChanged(IDecorable oldOwner, IDecorable newOwner)
{
base.OwnerChanged(oldOwner, newOwner);
if(oldOwner is Body oldBody)
{
oldBody.RemoveDependent(this);
}
if(newOwner is Body newBody)
{
newBody.AddDependent(this);
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Statics
// 检查是否可以找到参考面子形状
public static bool CanFindReferenceFace(TopoDS_Shape shape)
{
try
{
// 查找最大的面
var (_, plane1, _, plane2) = FaceAlgo.FindFaceByAreaSize(shape, (area1, area2) => area1 > area2);
return plane1 != null && plane2 != null;
}
catch (Exception)
{
return false;
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Make
// 生成蚀刻蒙版数据
class MakeContext
{
internal TopoDS_Shape SourceShape; // 源形状
internal TopoDS_Face ReferenceFace; // 参考面
internal SliceByPlanes Slicer; // 切片器
}
//--------------------------------------------------------------------------------------------------
// 获取形状
public Shape GetShape()
{
var body = Owner as Body;
if (body == null)
return null;
// 查找形状
Shape shape;
if (ShapeGuid != Guid.Empty)
shape = (body.Model?.FindInstance(ShapeGuid) as Shape);
else
shape = body.Shape;
return shape;
}
//--------------------------------------------------------------------------------------------------
// 尝试生成蚀刻蒙版数据
public bool Make()
{
var body = Owner as Body;
if (body == null)
{
Messages.Error("Etching Mask processor was started with an invalid component (owner is not a body).");
_HasErrors = true;
return false;
}
CoreContext.Current.MessageHandler.ClearEntityMessages(this);
using (new ProcessingScope(this, "Generating Etching Mask Drawing"))
{
Invalidate();
if (!(_InitMake(out var context) && _Slice(context)))
{
_HasErrors = true;
return false;
}
// 重构
_ReconstructedBRep = context.Slicer.Reconstruct();
}
RaisePropertyChanged(nameof(Layers));
RaisePropertyChanged(nameof(ReconstructedBRep));
return true;
}
//--------------------------------------------------------------------------------------------------
// 初始化生成过程
bool _InitMake(out MakeContext context)
{
var body = Owner as Body;
context = new MakeContext();
var shape = GetShape();
if (shape == null)
{
Messages.Error("The source shape cannot be found. Please reselect the shape or use top shape.");
return false;
}
context.SourceShape = shape?.GetBRep();
if (context.SourceShape == null)
{
Messages.Error("The shape does not generate valid data.");
return false;
}
// 获取参考面
if(ReferenceFace == null)
{
// 查找最大的面
var (face1, plane1, face2, plane2) = FaceAlgo.FindFaceByAreaSize(context.SourceShape, (area1, area2) => area1 > area2);
if (plane1 == null || plane2 == null)
{
Messages.Error("Reference face cannot be automatically detected.");
return false;
}
// 找到距离 XoY-平面更近的面
context.ReferenceFace = plane1.Value.Distance(Pln.XOY) > plane2.Value.Distance(Pln.XOY) ? face2 : face1;
}
else
{
context.ReferenceFace = shape.FindSubshape(ReferenceFace, null)?.FirstOrDefault()?.ToFace();
if (context.ReferenceFace == null)
{
Messages.Error("Manual reference face cannot be found and needs to be reselected.");
return false;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
// 切片
bool _Slice(MakeContext context)
{
context.Slicer = new SliceByPlanes(context.SourceShape, context.ReferenceFace, LayerCount);
if(!context.Slicer.CreateSlices(false))
{
return false;
}
_Layers = new SliceByPlanes.Slice[context.Slicer.Slices.Length];
for (int index = 0; index < context.Slicer.Slices.Length; index++)
{
Layers[index] = context.Slicer.Slices[index];
}
return true;
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Export
// 导出蚀刻蒙版数据
public bool Export(string fileName, IExchanger exchanger)
{
if (!IsValid)
{
Messages.Error("The etching mask data could not be generated.");
return false;
}
var exporter = exchanger as IDrawingExporter;
if (exporter == null)
return false;
Drawing.Drawing drawing = new()
{
Name = "Masks"
};
for (var layer = 0; layer < _Layers.Length; layer++)
{
BRepDrawing drawingLayer = new()
{
Name = $"Layer{layer}",
Source = new TopoDSBrepSource(_Layers[layer].BRep),
Stroke = new StrokeStyle(Color.Black, 0.1f, LineStyle.Solid),
Fill = new FillStyle(Color.Black)
};
drawing.Add(drawingLayer);
}
return exporter.DoExport(fileName, drawing);
}
//--------------------------------------------------------------------------------------------------
#endregion
#region IShapeDependent implementation
// 当形状失效时执行操作
public void OnShapeInvalidated(IShapeOperand operand)
{
Invalidate();
}
//--------------------------------------------------------------------------------------------------
public void OnTransformInvalidated(Body body)
{
}
//--------------------------------------------------------------------------------------------------
#endregion
}
}
这段代码定义了一个名为 EtchingMaskComponent
的类,用于生成蚀刻蒙版数据。其主要作用如下:
IShapeDependent
接口,用于在形状失效时执行相应操作。4.
using System;
using System.Linq;
using Macad.Core.Components;
using Macad.Core;
using Macad.Core.Geom;
using Macad.Core.Shapes;
using Macad.Core.Topology;
using Macad.Common;
using Macad.Common.Serialization;
using Macad.Core.Drawing;
using Macad.Occt;
namespace Macad.Core.Toolkits
{
// 切片轮廓组件,用于生成切片轮廓的工具类
[SerializeType]
public class SliceContourComponent : Component, IShapeDependent
{
#region Properties
// 层数
[SerializeMember]
public int LayerCount
{
get { return _LayerCount; }
set
{
var clampedValue = value.Clamp(1, 99); // 限制层数在1到99之间
if (_LayerCount != clampedValue)
{
SaveUndo();
_LayerCount = clampedValue;
Invalidate();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 形状 GUID
[SerializeMember]
public Guid ShapeGuid
{
get { return _ShapeGuid; }
set
{
if (_ShapeGuid != value)
{
SaveUndo();
_ShapeGuid = value;
Invalidate();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 参考面子形状
[SerializeMember]
public SubshapeReference ReferenceFace
{
get { return _ReferenceFace; }
set
{
if (_ReferenceFace != value)
{
SaveUndo();
_ReferenceFace = value;
Invalidate();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 自定义层间距
[SerializeMember]
public double[] CustomLayerInterval
{
get { return _CustomLayerInterval; }
set
{
if (_CustomLayerInterval != value)
{
SaveUndo();
_CustomLayerInterval = value;
Invalidate();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 是否有效
public bool IsValid
{
get
{
if (_Layers != null && _Layers.Length > 0)
return true;
if (!_HasErrors)
return Make(); // 尝试生成切片轮廓数据
return false;
}
}
//--------------------------------------------------------------------------------------------------
// 切片轮廓数组
public SliceByPlanes.Slice[] Layers
{
get
{
if (!IsValid && !_HasErrors)
Make(); // 如果数据无效,则尝试生成切片轮廓数据
return _Layers;
}
}
//--------------------------------------------------------------------------------------------------
// 重构的 BRep
public TopoDS_Shape ReconstructedBRep
{
get
{
if (!IsValid && !_HasErrors)
Make(); // 如果数据无效,则尝试生成切片轮廓数据
return _ReconstructedBRep;
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Members and infrastructure
internal static bool DebugOutput; // 调试输出标志
int _LayerCount; // 层数
SubshapeReference _ReferenceFace; // 参考面子形状
Guid _ShapeGuid; // 形状 GUID
bool _HasErrors; // 是否有错误
double[] _CustomLayerInterval; // 自定义层间距
SliceByPlanes.Slice[] _Layers; // 切片轮廓数组
TopoDS_Shape _ReconstructedBRep; // 重构的 BRep
//--------------------------------------------------------------------------------------------------
// 构造函数
public SliceContourComponent()
{
_LayerCount = 1; // 默认层数为1
}
//--------------------------------------------------------------------------------------------------
// 使切片轮廓组件失效
public void Invalidate()
{
_Layers = null;
_ReconstructedBRep = null;
_HasErrors = false;
RaisePropertyChanged(nameof(Layers));
RaisePropertyChanged(nameof(ReconstructedBRep));
}
//--------------------------------------------------------------------------------------------------
// 当所有者发生变化时执行操作
protected override void OwnerChanged(IDecorable oldOwner, IDecorable newOwner)
{
base.OwnerChanged(oldOwner, newOwner);
if(oldOwner is Body oldBody)
{
oldBody.RemoveDependent(this);
}
if(newOwner is Body newBody)
{
newBody.AddDependent(this);
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Statics
// 检查是否可以找到参考面子形状
public static bool CanFindReferenceFace(TopoDS_Shape shape)
{
try
{
// 查找最大的面
var (_, plane1, _, plane2) = FaceAlgo.FindFaceByAreaSize(shape, (area1, area2) => area1 > area2);
return plane1 != null && plane2 != null;
}
catch (Exception)
{
return false;
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Make
// 生成切片轮廓数据
class MakeContext
{
internal TopoDS_Shape SourceShape; // 源形状
internal TopoDS_Face ReferenceFace; // 参考面
internal SliceByPlanes Slicer; // 切片器
}
//--------------------------------------------------------------------------------------------------
// 获取形状
public Shape GetShape()
{
var body = Owner as Body;
if (body == null)
return null;
// 查找形状
Shape shape;
if (ShapeGuid != Guid.Empty)
shape = (body.Model?.FindInstance(ShapeGuid) as Shape);
else
shape = body.Shape;
return shape;
}
//--------------------------------------------------------------------------------------------------
// 尝试生成切片轮廓数据
public bool Make()
{
var body = Owner as Body;
if (body == null)
{
Messages.Error("Slice Contour processor was started with an invalid component (owner is not a body).");
_HasErrors = true;
return false;
}
CoreContext.Current.MessageHandler.ClearEntityMessages(this);
using (new ProcessingScope(this, "Generating Slice Contour Drawing"))
{
Invalidate();
if (!(_InitMake(out var context) && _Slice(context)))
{
_HasErrors = true;
return false;
}
// 重构
_ReconstructedBRep = context.Slicer.Reconstruct();
}
RaisePropertyChanged(nameof(Layers));
RaisePropertyChanged(nameof(ReconstructedBRep));
return true;
}
//--------------------------------------------------------------------------------------------------
// 初始化生成过程
bool _InitMake(out MakeContext context)
{
var body = Owner as Body;
context = new MakeContext();
var shape = GetShape();
if (shape == null)
{
Messages.Error("The source shape cannot be found. Please reselect the shape or use top shape.");
return false;
}
context.SourceShape = shape?.GetBRep();
if (context.SourceShape == null)
{
Messages.Error("The shape does not generate valid data.");
return false;
}
// 获取参考面
if(ReferenceFace == null)
{
// 查找最大的面
var (face1, plane1, face2, plane2) = FaceAlgo.FindFaceByAreaSize(context.SourceShape, (area1, area2) => area1 > area2);
if (plane1 == null || plane2 == null)
{
Messages.Error("Reference face cannot be automatically detected.");
return false;
}
// 查找距离 XoY-平面更近的面
context.ReferenceFace = plane1.Value.Distance(Pln.XOY) > plane2.Value.Distance(Pln.XOY) ? face2 : face1;
}
else
{
context.ReferenceFace = shape.FindSubshape(ReferenceFace, null)?.FirstOrDefault()?.ToFace();
if (context.ReferenceFace == null)
{
Messages.Error("Manual reference face cannot be found and needs to be reselected.");
return false;
}
}
return true;
}
//--------------------------------------------------------------------------------------------------
// 切片操作
bool _Slice(MakeContext context)
{
context.Slicer = new SliceByPlanes(context.SourceShape, context.ReferenceFace, _LayerCount, _CustomLayerInterval);
if(!context.Slicer.CreateSlices(DebugOutput))
{
return false;
}
_Layers = new SliceByPlanes.Slice[context.Slicer.Slices.Length];
for (int index = 0; index < context.Slicer.Slices.Length; index++)
{
Layers[index] = context.Slicer.Slices[index];
}
return true;
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Export
// 导出切片轮廓数据
public bool Export(string fileName, IExchanger exchanger)
{
if (!IsValid)
{
Messages.Error("The slice contour data could not be generated.");
return false;
}
var exporter = exchanger as IDrawingExporter;
if (exporter == null)
return false;
Drawing.Drawing drawing = new()
{
Name = "Contours"
};
for (var layer = 0; layer < _Layers.Length; layer++)
{
BRepDrawing drawingLayer = new()
{
Name = $"Layer{layer}",
Source = new TopoDSBrepSource(_Layers[layer].BRep),
Stroke = new StrokeStyle(Color.Black, 0.1f, LineStyle.Solid)
};
drawing.Add(drawingLayer);
}
return exporter.DoExport(fileName, drawing);
}
//--------------------------------------------------------------------------------------------------
#endregion
#region IShapeDependent implementation
// 当形状失效时执行操作
public void OnShapeInvalidated(IShapeOperand operand)
{
Invalidate();
}
//--------------------------------------------------------------------------------------------------
public void OnTransformInvalidated(Body body)
{
}
//--------------------------------------------------------------------------------------------------
#endregion
}
}
这段代码定义了一个名为 SliceContourComponent
的类,它是用于生成切片轮廓的工具类。以下是代码段的详细说明:
命名空间和引用:
类定义:
SliceContourComponent
类继承自 Component
类,并实现了 IShapeDependent
接口。属性:
LayerCount
:切片轮廓的层数,限制在1到99之间。ShapeGuid
:形状的 GUID,用于指定操作的形状。ReferenceFace
:参考面子形状,用于确定切片方向。CustomLayerInterval
:自定义层间距,可选属性。IsValid
:判断切片轮廓是否有效。Layers
:获取切片轮廓数组。ReconstructedBRep
:获取重构的 BRep。成员和基础设施:
静态方法:
CanFindReferenceFace
:用于检查是否可以找到参考面子形状的静态方法。生成切片轮廓:
Make
方法和一些辅助方法,用于初始化生成过程、执行切片操作以及处理可能的错误情况。导出:
Export
方法,用于将切片轮廓数据导出到文件中。形状依赖接口:
IShapeDependent
接口,用于处理形状失效时的操作。5.topology
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using Macad.Core.Components;
using Macad.Core.Shapes;
using Macad.Common;
using Macad.Common.Serialization;
using Macad.Occt;
namespace Macad.Core.Topology
{
// Body 类:表示三维实体的容器
public class Body : InteractiveEntity, IUndoableDataBlob, IDecorable, ITransformable
{
#region Properties
// 位置
[SerializeMember]
public Pnt Position
{
get
{
return _Position;
}
set
{
if (!_Position.IsEqual(value, Double.Epsilon))
{
SaveUndo();
_Position = value;
_InvalidateTransformation();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 旋转
[SerializeMember]
public Quaternion Rotation
{
get
{
return _Rotation;
}
set
{
if (!_Rotation.IsEqual(value))
{
SaveUndo();
_Rotation = value;
_InvalidateTransformation();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 根形状
[SerializeMember]
public Shape RootShape
{
get { return _RootShape; }
private set
{
if (_RootShape != value)
{
SaveTopologyUndo();
_RootShape = value;
Invalidate();
RaisePropertyChanged();
RaisePropertyChanged("Shape");
RaiseVisualChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 当前形状
[SerializeMember]
public Shape Shape
{
get { return _CurrentShape ?? _RootShape; }
set
{
if (_CurrentShape != value)
{
if (_RootShape == null)
{
// 初始化根形状,将当前形状设置为顶层
_RootShape = value;
_CurrentShape = null;
}
else
{
// 检查当前形状是否属于形状树根
SaveUndo();
Debug.Assert(_RootShape.Body == value.Body);
_CurrentShape = (_RootShape == value) ? null : value;
}
Invalidate();
RaisePropertyChanged();
UpdateErrorState();
RaiseVisualChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 组件列表
[SerializeMember(SortKey = 900)]
public List Components
{
get { return _Components; }
set
{
if (_Components != value)
{
SaveUndo();
_Components = value;
Invalidate();
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 模型
public Model Model
{
get { return Document as Model; }
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Members
Shape _CurrentShape;
Shape _RootShape;
Pnt _Position = Pnt.Origin;
Quaternion _Rotation = Quaternion.Identity;
List _Components;
Ax3? _CachedCoordinateSystem;
Trsf? _CachedTransformation;
#endregion
#region ITransformable
// 获取变换矩阵
public Trsf GetTransformation()
{
_CachedTransformation ??= new Trsf(Rotation, Position.ToVec());
return _CachedTransformation.Value;
}
//--------------------------------------------------------------------------------------------------
// 获取坐标系
public Ax3 GetCoordinateSystem()
{
_CachedCoordinateSystem ??= Rotation.ToAx3(Position);
return _CachedCoordinateSystem.Value;
}
//--------------------------------------------------------------------------------------------------
// 使变换无效
void _InvalidateTransformation()
{
_CachedCoordinateSystem = null;
_CachedTransformation = null;
if (IsDeserializing)
return;
Shape?.InvalidateTransformation();
foreach (var reference in _Dependents)
{
if (reference.TryGetTarget(out var dependent))
{
dependent.OnTransformInvalidated(this);
}
}
}
//--------------------------------------------------------------------------------------------------
// 获取连接的变换对象
public IEnumerable GetLinkedTransformables()
{
List bodies = new List();
(Shape as IShapeOperand)?.GetLinkedBodies(bodies);
return bodies;
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Shape
// 添加形状
public bool AddShape(Shape shape, bool saveUndo = true)
{
if (saveUndo)
SaveTopologyUndo();
var modifier = shape as ModifierBase;
if (shape.Body != null && shape.Body != this)
{
var oldBody = shape.Body;
if (!shape.Body.RemoveShape(shape, saveUndo))
return false;
// 切换 IShapeOperand 从 Shape 到 Body
Debug.Assert(modifier != null);
modifier.Predecessor = new BodyShapeOperand(oldBody);
}
shape.Body = this;
// 情况 1:首个形状
if (_RootShape == null)
{
RootShape = shape;
return true;
}
// 如果已经有顶层形状,则只允许修改器
Debug.Assert(modifier != null);
Debug.Assert(modifier != _RootShape);
// 情况 2:插入
if (_CurrentShape != null && _CurrentShape != _RootShape)
{
// 将每个依赖项的操作符更改为新的修改器
foreach (var dependent in _CurrentShape.GetDependents().ToList())
{
var dependentModifier = dependent as ModifierBase;
if(dependentModifier == null)
continue;
for (var opIndex = 0; opIndex < dependentModifier.Operands.Count; opIndex++)
{
if (dependentModifier.Operands[opIndex] == _CurrentShape)
dependentModifier.ReplaceOperand(opIndex, modifier);
}
}
// 在当前形状之上设置新的修改器
modifier.Predecessor = _CurrentShape;
Shape = modifier;
return true;
}
// 情况 3:前置
modifier.Predecessor = _RootShape;
RootShape = modifier;
return true;
}
//--------------------------------------------------------------------------------------------------
// 移除形状
public bool RemoveShape(Shape shape, bool saveUndo = true)
{
if (saveUndo)
SaveTopologyUndo();
// 只能移除修改器
var modifier = shape as ModifierBase;
Debug.Assert(modifier != null);
var replaceWithShape = modifier.Predecessor as Shape;
if (replaceWithShape == null)
return false;
foreach (var dependent in modifier.GetDependents().ToList())
{
var dependentModifier = dependent as ModifierBase;
if (dependentModifier == null)
continue;
for (var opIndex = 0; opIndex < dependentModifier.Operands.Count; opIndex++)
{
if (dependentModifier.Operands[opIndex] == modifier)
dependentModifier.ReplaceOperand(opIndex, replaceWithShape);
}
}
if (_CurrentShape == modifier)
_CurrentShape = replaceWithShape;
if (_RootShape == modifier)
RootShape = replaceWithShape;
shape.Body = null;
Invalidate();
RaisePropertyChanged("Shape");
RaiseVisualChanged();
return true;
}
//--------------------------------------------------------------------------------------------------
// 使形状无效
public override void Invalidate()
{
if (!IsDeserializing)
{
Shape?.Invalidate();
InvalidateDependents();
}
_InvalidateTransformation();
}
//--------------------------------------------------------------------------------------------------
// 获取引用的实体列表
public List GetReferencedBodies()
{
List bodies = new List();
(Shape as IShapeOperand)?.GetReferencedBodies(bodies);
return bodies;
}
//--------------------------------------------------------------------------------------------------
// 更新错误状态
public void UpdateErrorState()
{
HasErrors = Shape?.HasErrors ?? false;
}
//--------------------------------------------------------------------------------------------------
// 折叠形状堆栈
public void CollapseShapeStack(Shape newRootShape, bool saveUndo = true)
{
if (saveUndo)
SaveTopologyUndo();
Shape shape = RootShape;
while (shape != null)
{
foreach (var dependent in shape.GetDependents().ToList())
{
var dependentModifier = dependent as ModifierBase;
if (dependentModifier == null)
continue;
for (var opIndex = 0; opIndex < dependentModifier.Operands.Count; opIndex++)
{
if (dependentModifier.Operands[opIndex] == shape)
dependentModifier.ReplaceOperand(opIndex, shape);
}
}
shape.Body = null;
shape = (shape as ModifierBase)?.Predecessor as Shape;
}
newRootShape.Body = this;
RootShape = newRootShape;
_CurrentShape = null;
Invalidate();
RaisePropertyChanged("RootShape");
RaisePropertyChanged("Shape");
RaiseVisualChanged();
}
//--------------------------------------------------------------------------------------------------
// 形状是否有效
public bool IsShapeEffective(Shape shape)
{
if(shape.IsSkipped)
return false;
var current = Shape;
while (current != null)
{
if (shape == current)
return true;
var pred = current.Predecessor;
switch (pred)
{
case BodyShapeOperand bodyOp:
current = bodyOp.Shape;
break;
case Shape shapeOp:
current = shapeOp;
break;
default:
return false;
}
}
return false;
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Initialization / Serialization
// 创建 Body
public static Body Create(Shape shape)
{
var body = new Body
{
Name = CoreContext.Current.Document?.AddNextNameSuffix(shape.Name) ?? shape.Name,
Layer = CoreContext.Current.Layers?.ActiveLayer,
Document = CoreContext.Current.Document
};
body.AddShape(shape, false);
return body;
}
//--------------------------------------------------------------------------------------------------
// 构造函数
public Body()
{
Components = new List();
}
//--------------------------------------------------------------------------------------------------
// 开始反序列化
public override void OnBeginDeserializing(SerializationContext context)
{
base.OnBeginDeserializing(context);
context.SetInstance(this);
}
//--------------------------------------------------------------------------------------------------
// 反序列化完成
public override void OnDeserialized(SerializationContext context)
{
base.OnDeserialized(context);
Components.ForEach(c => c.Owner = this);
}
//--------------------------------------------------------------------------------------------------
// 移除 Body
public override void Remove()
{
_RootShape?.Remove();
_RootShape = null;
Components.Clear();
base.Remove();
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Property and Undo handling
//--------------------------------------------------------------------------------------------------
// 保存拓扑撤销
public void SaveTopologyUndo()
{
if ((!IsDeserializing) && (Model != null))
{
SaveUndo(nameof(Shape));
CoreContext.Current?.UndoHandler?.AddDataBlockChange(this);
}
}
//--------------------------------------------------------------------------------------------------
// 触发属性更改
protected override void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
base.RaisePropertyChanged(propertyName);
if (!IsDeserializing)
{
if (CoreContext.Current.Workspace != null)
CoreContext.Current.Workspace.MarkAsUnsaved();
}
}
//--------------------------------------------------------------------------------------------------
// 触发形状拓扑更改
public void RaiseShapeTopologyChanged()
{
RaisePropertyChanged(nameof(Shape));
}
//--------------------------------------------------------------------------------------------------
#endregion
#region IUndoableDataBlob
//--------------------------------------------------------------------------------------------------
// 获取撤销数据
public byte[] GetUndoDataBlob()
{
if (_RootShape == null)
return null;
var data = Serializer.Serialize(_RootShape, new SerializationContext(SerializationScope.UndoRedo));
return data.IsNullOrEmpty() ? null : data.ToUtf8Bytes();
}
//--------------------------------------------------------------------------------------------------
// 设置撤销数据
public void SetUndoDataBlob(byte[] dataBlob)
{
CoreContext.Current.UndoHandler.AddDataBlockChange(this);
_RootShape?.Remove();
_RootShape = null;
_CurrentShape = null;
if ((dataBlob == null)||(dataBlob.Length == 0))
return;
var context = new SerializationContext(SerializationScope.UndoRedo);
context.SetInstance(Model);
context.SetInstance(Model);
context.SetInstance(this);
context.SetInstance(CoreContext.Current.Workspace);
RootShape = Serializer.Deserialize(dataBlob.FromUtf8Bytes(), context);
Invalidate();
RaisePropertyChanged("RootShape");
RaisePropertyChanged("Shape");
RaiseVisualChanged();
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Components
// 获取所属模型
public Model GetOwnerModel()
{
return Model;
}
//--------------------------------------------------------------------------------------------------
// 获取组件列表
public IEnumerable GetComponents(bool inherited)
{
return Components;
}
//--------------------------------------------------------------------------------------------------
// 查找特定类型的组件
public T FindComponent(bool inherited = false) where T : Component
{
return (T)Components.Find(c => c is T);
}
//--------------------------------------------------------------------------------------------------
// 添加组件
public void AddComponent(Component component)
{
Debug.Assert(component != null);
Components.Add(component);
component.Owner = this;
Model?.RegisterInstance(component);
RaisePropertyChanged(nameof(Components));
}
//--------------------------------------------------------------------------------------------------
// 移除组件
public void RemoveComponent(Component component)
{
Model?.UnregisterInstance(component);
component.Owner = null;
Components.Remove(component);
RaisePropertyChanged(nameof(Components));
}
//--------------------------------------------------------------------------------------------------
#endregion
#region InteractiveEntity
// 获取 BRep
public TopoDS_Shape GetBRep()
{
return Shape?.GetBRep();
}
//--------------------------------------------------------------------------------------------------
// 获取变换后的 BRep
public override TopoDS_Shape GetTransformedBRep()
{
return Shape?.GetTransformedBRep();
}
//--------------------------------------------------------------------------------------------------
// 获取可视样式组件
public override VisualStyle GetVisualStyleComponent()
{
return FindComponent(true);
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Dependents
//--------------------------------------------------------------------------------------------------
readonly List> _Dependents = new List>();
//--------------------------------------------------------------------------------------------------
// 添加依赖项
public void AddDependent(IShapeDependent dependent)
{
_Dependents.Add(new WeakReference(dependent));
RaisePropertyChanged("Dependents");
}
//--------------------------------------------------------------------------------------------------
// 移除依赖项
public void RemoveDependent(IShapeDependent dependent)
{
var index = _Dependents.FindIndex(wr => wr.TryGetTarget(out var target) && ReferenceEquals(target, dependent));
if (index >= 0)
{
_Dependents.RemoveAt(index);
}
}
//--------------------------------------------------------------------------------------------------
// 使依赖项无效
public void InvalidateDependents()
{
foreach (var reference in _Dependents)
{
if (reference.TryGetTarget(out var dependent))
{
dependent.OnShapeInvalidated(null);
}
}
}
//--------------------------------------------------------------------------------------------------
// 获取依赖项
public IEnumerable GetDependents()
{
foreach (var reference in _Dependents)
{
if (reference.TryGetTarget(out var dependent))
{
yield return dependent;
}
}
}
//--------------------------------------------------------------------------------------------------
#endregion
}
}
这段代码定义了一个 Body
类,用于表示三维实体的容器。它包含了形状树、位置、旋转、组件等属性,并提供了相关的方法用于管理形状、组件、撤销等功能。同时,它也实现了 ITransformable
接口,支持变换操作。
6.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using Macad.Core.Shapes;
using Macad.Common.Serialization;
using Macad.Occt;
namespace Macad.Core.Topology
{
// 序列化类型和调试显示
[SerializeType]
[DebuggerDisplay("Body: {Body.Name}, Shape: {Shape?.Name ?? \"\"}")]
public sealed class BodyShapeOperand : IShapeOperand, IEquatable
{
// 序列化的Body对象,使用Body的setter用于序列化
[SerializeMember(ReaderFunc = nameof(DeserializeBody))]
public Body Body { get; private set; }
//--------------------------------------------------------------------------------------------------
// 序列化的形状的唯一标识符
[SerializeMember]
public Guid ShapeId { get; private set; }
//--------------------------------------------------------------------------------------------------
// 获取与Body关联的形状
public Shape Shape
{
get
{
// 如果Body为空,则返回空
if (Body == null)
return null;
// 如果ShapeId为空,则返回Body的形状
if (ShapeId.Equals(Guid.Empty))
return Body.Shape;
// 否则根据ShapeId查找模型中的形状
var shape = Body.Model?.FindInstance(ShapeId) as Shape;
// 如果找不到形状或者形状的Body不是当前Body,则返回Body的形状
if (shape == null || shape.Body != Body)
return Body.Shape;
return shape;
}
}
//--------------------------------------------------------------------------------------------------
// 构造函数
public BodyShapeOperand(Body body, Shape shape = null)
{
// 设置Body和ShapeId
Body = body;
ShapeId = shape?.Guid ?? Guid.Empty;
}
//--------------------------------------------------------------------------------------------------
// 用于序列化的构造函数
BodyShapeOperand()
{
// 用于序列化
}
//--------------------------------------------------------------------------------------------------
// 反序列化Body对象
bool DeserializeBody(Reader reader, SerializationContext context)
{
// 获取当前文档和序列化的范围
IDocument document = context.GetInstance();
bool reuseModelBodies = false;
CloneOptions cloneOptions = default;
switch (context.Scope)
{
// 如果是撤销重做范围,则重用模型的Body
case SerializationScope.UndoRedo:
reuseModelBodies = true;
break;
// 如果是复制粘贴范围,则尝试克隆选项
case SerializationScope.CopyPaste:
context.TryGetInstance(out cloneOptions);
reuseModelBodies = true; // 之后再询问
break;
}
// 如果允许重用模型的Body,并且有文档
if (reuseModelBodies && document != null)
{
// 尝试在当前模型中找到引用的Body形状
var anticipated = ClassSerializer.AnticipateType(reader, context);
if (anticipated.Type != null && typeof(Body).IsAssignableFrom(anticipated.Type))
{
// 尝试在文档中找到Body
var body = document.FindInstance(anticipated.Guid) as Body;
if (body != null)
{
// 如果没有克隆选项,则直接使用现有的Body对象
if (!(cloneOptions?.CloneReferencedBodies ?? false))
{
// Operand已经存在于模型中,直接使用该Body
Body = body;
reader.SkipListOrMapValue();
return true;
}
}
}
}
// 获取旧的Body对象
Body oldBody = context.GetInstance();
// 读取新的Body对象
Body = reader.ReadType(null, context);
// 设置旧的Body对象
context.SetInstance(oldBody);
return true;
}
//--------------------------------------------------------------------------------------------------
// 判断两个BodyShapeOperand对象是否相等
public bool Equals(BodyShapeOperand other)
{
return Equals(Body, other.Body) && ShapeId.Equals(other.ShapeId);
}
//--------------------------------------------------------------------------------------------------
// 计算哈希码
[SuppressMessage("ReSharper", "NonReadonlyMemberInGetHashCode")]
public override int GetHashCode()
{
unchecked
{
return ((Body != null ? Body.GetHashCode() : 0) * 397) ^ ShapeId.GetHashCode();
}
}
//--------------------------------------------------------------------------------------------------
// 缓存坐标系转换结果
Tuple _CachedLocation = new Tuple(Ax3.XOY, Ax3.XOY, new TopLoc_Location());
// 获取缓存的坐标系转换结果
TopLoc_Location _GetCachedLocation(Ax3 targetFrame)
{
// 如果Body为空,则返回空
if (Body == null)
return null;
// 获取Body的坐标系
var bodyFrame = Body.GetCoordinateSystem();
// 如果与缓存的坐标系一致,则直接返回缓存的坐标系转换结果
if (_CachedLocation.Item1 == bodyFrame
&& _CachedLocation.Item2 == targetFrame)
{
return _CachedLocation.Item3;
}
// 计算坐标系转换结果
var location = new TopLoc_Location(new Trsf(Body.GetCoordinateSystem(), targetFrame));
_CachedLocation = new Tuple(bodyFrame, targetFrame, location);
return location;
}
//--------------------------------------------------------------------------------------------------
// 折叠形状到指定的坐标系下
Shape IShapeOperand.Collapse(Ax3 targetFrame)
{
// 如果Body为空,则返回空
if (Body == null)
return null;
// 获取形状的BRep,并将其移动到目标坐标系下
var collapsedBRep = ((IShapeOperand)this).GetBRep(targetFrame);
if (collapsedBRep == null)
return null;
// 创建折叠后的形状
return Solid.Create(collapsedBRep);
}
//--------------------------------------------------------------------------------------------------
// 获取形状的类型
ShapeType IShapeOperand.GetShapeType()
{
return Shape?.ShapeType ?? ShapeType.Unknown;
}
//--------------------------------------------------------------------------------------------------
// 添加依赖
void IShapeOperand.AddDependent(IShapeDependent dependent)
{
Body?.AddDependent(dependent);
}
//--------------------------------------------------------------------------------------------------
// 移除依赖
void IShapeOperand.RemoveDependent(IShapeDependent dependent)
{
Body?.RemoveDependent(dependent);
}
//--------------------------------------------------------------------------------------------------
// 移除形状操作数
public void Remove()
{
// 意图为空
}
//--------------------------------------------------------------------------------------------------
// 获取形状的BRep
TopoDS_Shape IShapeOperand.GetBRep(Ax3 targetFrame)
{
// 如果Body为空,则返回空
if (Body == null)
return null;
// 获取形状的BRep,并将其移动到目标坐标系下
return Shape?.GetBRep()?.Moved(_GetCachedLocation(targetFrame));
}
//--------------------------------------------------------------------------------------------------
// 将形状绑定到平面
bool IShapeOperand.BindToPlane(Ax3 targetFrame, Entity boundTo, Pln? plane)
{
// 如果Body为空,则返回false
if (Body == null)
return false;
var shape = Shape;
// 如果形状为空,则返回false
if (shape == null)
return false;
// 根据平面是否为空执行形状绑定到平面操作
if (plane.HasValue)
return shape.BindToPlane(Body.GetCoordinateSystem(), boundTo, plane.Value.Transformed(new Trsf(Body.GetCoordinateSystem(), targetFrame)));
else
return shape.BindToPlane(Body.GetCoordinateSystem(), boundTo, null);
}
//--------------------------------------------------------------------------------------------------
// 获取子形状的引用
SubshapeReference IShapeOperand.GetSubshapeReference(TopoDS_Shape ocSubshape, Ax3? sourceFrame)
{
// 如果Body为空,则返回空
if (Body == null)
return null;
var shape = Shape;
// 如果形状为空,则返回空
if (shape == null)
return null;
// 根据sourceFrame是否为空获取子形状的引用
if (sourceFrame.HasValue)
{
var transformedBrep = shape.GetBRep()?.Moved(_GetCachedLocation(sourceFrame.Value));
if(transformedBrep != null)
return shape.GetSubshapeReference(transformedBrep, ocSubshape);
}
else
{
return shape.GetSubshapeReference(ocSubshape);
}
return null;
}
//--------------------------------------------------------------------------------------------------
// 查找子形状
List IShapeOperand.FindSubshape(SubshapeReference reference, Ax3? targetFrame)
{
// 如果Body为空,则返回空
if (Body == null)
return null;
var shape = Shape;
// 如果形状为空,则返回空
if (shape == null)
return null;
var shapeList = shape.FindSubshape(reference, Body.GetCoordinateSystem());
// 如果targetFrame不为空,则将结果移动到目标坐标系下
if (shapeList != null && targetFrame.HasValue)
{
var location = _GetCachedLocation(targetFrame.Value);
for (var i = 0; i < shapeList.Count; i++)
{
shapeList[i] = shapeList[i].Moved(location);
}
}
return shapeList;
}
//--------------------------------------------------------------------------------------------------
// 获取引用的Body列表
void IShapeOperand.GetReferencedBodies(List bodyList)
{
// 如果Body为空,则返回
if (Body == null)
return;
var shape = Shape;
// 如果形状为空,则返回
if (shape == null)
return;
// 如果列表中已包含当前Body,则返回
if (bodyList.Contains(Body))
return;
// 将当前Body添加到列表中
bodyList.Add(Body);
// 递归获取引用的Body列表
shape.GetReferencedBodies(bodyList);
}
//--------------------------------------------------------------------------------------------------
// 获取链接的Body列表
void IShapeOperand.GetLinkedBodies(List bodyList)
{
// 调用获取引用的Body列表方法
(this as IShapeOperand).GetReferencedBodies(bodyList);
}
//--------------------------------------------------------------------------------------------------
}
}
这段代码定义了 BodyShapeOperand
类,它是表示形状操作数的一种类型。主要功能包括:
属性和构造函数:
Body
:表示所属的 Body
实例。ShapeId
:表示形状的唯一标识符。Body
和相应的 Shape
。序列化和反序列化:
DeserializeBody
,在反序列化时根据需要重用现有的 Body
实例。SerializeMember
和 SerializeType
特性指定了序列化规则。功能方法:
Collapse
:将形状折叠到指定坐标系下,并返回折叠后的形状。GetShapeType
:获取形状的类型。AddDependent
和 RemoveDependent
:管理形状操作数的依赖关系。GetBRep
:获取形状的 BRep 表示,并将其移动到指定的坐标系下。BindToPlane
:将形状绑定到指定平面。GetSubshapeReference
和 FindSubshape
:用于处理子形状的引用和查找。GetReferencedBodies
和 GetLinkedBodies
:获取形状操作数引用的所有 Body
实例。其他方法:
Equals
和 GetHashCode
:重写了相等性比较方法。_GetCachedLocation
:缓存了坐标系转换的结果,以提高性能。总体而言,BodyShapeOperand
类提供了对形状操作数的封装和管理功能,用于表示形状操作时所涉及的 Body
和形状信息。
7.
namespace Macad.Core.Topology
{
// 克隆选项类
public class CloneOptions
{
// 是否克隆引用的Body,默认为false
public virtual bool CloneReferencedBodies
{
get { return _CloneReferencedBodies; }
protected set { _CloneReferencedBodies = value; }
}
//--------------------------------------------------------------------------------------------------
// 是否克隆引用的Body的标志位
bool _CloneReferencedBodies;
//--------------------------------------------------------------------------------------------------
// 构造函数,初始化克隆选项
public CloneOptions(bool cloneReferencedBodies)
{
_CloneReferencedBodies = cloneReferencedBodies;
}
//--------------------------------------------------------------------------------------------------
}
}
整段代码定义了一个名为 CloneOptions
的类,用于指定在执行对象克隆操作时的选项。该类包含一个布尔属性 CloneReferencedBodies
,用于指示是否克隆引用的 Body
对象。构造函数用于初始化克隆选项。
8.
using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using Macad.Core.Shapes;
using Macad.Common;
using Macad.Common.Serialization;
namespace Macad.Core.Topology
{
// 表示一个模型的类,继承自Document
[SerializeType]
public class Model : Document
{
// 工作空间列表
[SerializeMember]
public List Workspaces { get; private set; }
//--------------------------------------------------------------------------------------------------
// 图层集合
[SerializeMember]
public LayerCollection Layers { get; private set; }
//--------------------------------------------------------------------------------------------------
// 文件扩展名和版本信息
public const string FileExtension = "model";
public const int FileVersionMajor = 3;
public const int FileVersionMinor = 1;
//--------------------------------------------------------------------------------------------------
// 构造函数
public Model()
{
Layers = new LayerCollection(this); // 创建图层集合
Workspaces = new List {new (this)}; // 创建工作空间列表
CoreContext.Current.MessageHandler.ClearAllEntityMessages(); // 清除所有实体消息
}
//--------------------------------------------------------------------------------------------------
#region File IO
// 反序列化开始时调用
public override void OnBeginDeserializing(SerializationContext context)
{
context.SetInstance(this);
base.OnBeginDeserializing(context);
}
//--------------------------------------------------------------------------------------------------
// 保存数据到文件系统
protected override bool SaveData(FileSystem fileSystem)
{
_SaveShapeCaches(fileSystem); // 保存形状缓存
return base.SaveData(fileSystem);
}
//--------------------------------------------------------------------------------------------------
// 从文件系统加载数据
protected override bool LoadData(FileSystem fileSystem)
{
_LoadShapeCaches(fileSystem); // 加载形状缓存
return base.LoadData(fileSystem);
}
//--------------------------------------------------------------------------------------------------
// 保存形状缓存
void _SaveShapeCaches(FileSystem fileSystem)
{
foreach (var reference in Instances.Values)
{
if (reference.TryGetTarget(out var entity))
{
var shape = entity as Shape;
if ((shape == null) || !shape.IsVisible || shape.HasErrors)
continue;
shape.SaveShapeCache(fileSystem); // 保存形状缓存
}
}
}
//--------------------------------------------------------------------------------------------------
// 加载形状缓存
void _LoadShapeCaches(FileSystem fileSystem)
{
foreach (var reference in Instances.Values)
{
if (reference.TryGetTarget(out var entity))
{
var shape = entity as Shape;
if ((shape == null) || (!shape.IsVisible))
continue;
shape.LoadShapeCache(fileSystem); // 加载形状缓存
}
}
}
//--------------------------------------------------------------------------------------------------
// 从文件创建模型实例
public static Model CreateFromFile(string filePath, SerializationContext context)
{
return CreateFromFile(filePath, context, _VerifyVersion);
}
//--------------------------------------------------------------------------------------------------
// 验证文件版本
static bool _VerifyVersion(Version version)
{
if (version.Major > FileVersionMajor)
{
return false;
}
return true;
}
//--------------------------------------------------------------------------------------------------
// 将模型保存到文件
public override bool SaveToFile(string filePath)
{
var context = new SerializationContext(SerializationScope.Storage)
{
Version = new Version(FileVersionMajor, FileVersionMinor)
};
return base.SaveToFile(filePath, context);
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Content handling
// 安全删除实体
public void SafeDelete(IEnumerable entitiesToDelete)
{
var interactiveEntities = entitiesToDelete as List ?? entitiesToDelete.ToList();
var bodies = interactiveEntities.OfType().ToArray();
foreach (var body in bodies)
{
foreach (var dependent in body.GetDependents().ToArray()) // 遍历依赖项
{
if (dependent is ModifierBase modifierBase
&& modifierBase.Body != null
&& !bodies.Contains(modifierBase.Body))
{
foreach (var operand in modifierBase.Operands.ToArray())
{
if (operand is BodyShapeOperand bodyShapeOperand
&& body == bodyShapeOperand.Body)
{
// 创建Solid对象
var solid = operand.Collapse(modifierBase.GetCoordinateSystem());
solid.Body = modifierBase.Body;
modifierBase.Body.SaveTopologyUndo();
modifierBase.ReplaceOperand(operand, solid);
}
}
}
}
}
foreach (var entity in interactiveEntities)
{
Remove(entity);
entity.Remove();
}
}
//--------------------------------------------------------------------------------------------------
#endregion
}
}
整段代码定义了一个名为 Model
的类,用于表示模型,并包含了文件的读写操作,内容处理等功能。其中包括文件读写方法、保存和加载形状缓存、创建模型实例、验证文件版本、安全删除实体等功能。
9.
using Macad.Common;
using Macad.Common.Serialization;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using Macad.Core.Components;
namespace Macad.Core.Topology
{
// 定义一个接口,表示文档
public interface IDocument
{
void RegisterInstance(Entity entity); // 注册实例
void UnregisterInstance(Entity entity); // 注销实例
Entity FindInstance(Guid instanceGuid); // 查找实例
}
//--------------------------------------------------------------------------------------------------
// 抽象类Document,继承自EntityContainer,实现了IDocument和IUndoableTopology接口
[SerializeType]
public abstract class Document : EntityContainer, IDocument, IUndoableTopology
where T : Entity
{
#region Properties
// 名称后缀字典
[SerializeMember]
Dictionary LastNameSuffices { get; set; } = new Dictionary();
//--------------------------------------------------------------------------------------------------
// 名称属性,根据文件路径获取
public override string Name
{
get { return _FilePath!=null ? PathUtils.GetFilenameWithoutExtensionAndPoint(_FilePath, false) : "Unnamed"; }
}
//--------------------------------------------------------------------------------------------------
// 文件路径属性
public string FilePath
{
get { return _FilePath; }
set
{
_FilePath = value;
RaisePropertyChanged();
}
}
// 是否有未保存的更改
public bool HasUnsavedChanges { get; protected set; }
//--------------------------------------------------------------------------------------------------
// 标记为未保存
public void MarkAsUnsaved()
{
if (IsDeserializing)
return;
HasUnsavedChanges = true;
}
//--------------------------------------------------------------------------------------------------
// 重置未保存的更改
public void ResetUnsavedChanges()
{
HasUnsavedChanges = false;
}
//--------------------------------------------------------------------------------------------------
// 撤销处理程序
public UndoHandler UndoHandler
{
get
{
if (_UndoHandler == null)
_UndoHandler = new UndoHandler(this);
return _UndoHandler;
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Member
UndoHandler _UndoHandler;
string _FilePath;
//--------------------------------------------------------------------------------------------------
#endregion
#region IUndoableTopology
// 查找实例
public Entity FindInstance(Guid instanceGuid)
{
if (instanceGuid.Equals(Guid))
return this;
if (Instances.TryGetValue(instanceGuid, out var reference)
&& reference.TryGetTarget(out var entity))
return entity;
return null;
}
//--------------------------------------------------------------------------------------------------
// 获取父实体
Entity IUndoableTopology.GetParent(Entity instance)
{
// 暂不支持层次结构
return null;
}
//--------------------------------------------------------------------------------------------------
// 从撤销中添加子实体
void IUndoableTopology.AddChildFromUndo(Entity instance, Entity parent)
{
var typedInstance = instance as T;
Debug.Assert(typedInstance != null);
Add(typedInstance);
}
//--------------------------------------------------------------------------------------------------
// 从撤销中移除子实体
void IUndoableTopology.RemoveChildFromUndo(Entity instance)
{
var typedInstance = instance as T;
Debug.Assert(typedInstance != null);
Remove(typedInstance);
typedInstance.Remove();
}
//--------------------------------------------------------------------------------------------------
// 从撤销中移动子实体
void IUndoableTopology.MoveChildFromUndo(Entity instance, Entity newParent)
{
throw new NotImplementedException();
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Childs
// 添加子实体
public override void Add(T entity, bool update = true)
{
CoreContext.Current?.UndoHandler?.AddTopologyChange(UndoHandler.TopologyAction.Added, this, entity);
base.Add(entity, update);
}
//--------------------------------------------------------------------------------------------------
// 移除子实体
public override void Remove(T entity, bool update = true)
{
CoreContext.Current?.UndoHandler?.AddTopologyChange(UndoHandler.TopologyAction.Removed, this, entity);
base.Remove(entity, update);
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Instances
// 实例字典
public readonly Dictionary> Instances = new Dictionary>();
//--------------------------------------------------------------------------------------------------
// 注册实例
public void RegisterInstance(Entity entity)
{
if (entity.Guid == Guid.Empty)
return;
Instances[entity.Guid] = new WeakReference(entity);
if (entity is IDecorable decorable)
{
foreach (var component in decorable.GetComponents(false))
{
Instances[component.Guid] = new WeakReference(component);
}
}
}
//--------------------------------------------------------------------------------------------------
// 注销实例
public void UnregisterInstance(Entity entity)
{
if (Instances.Remove(entity.Guid))
{
if (entity is IDecorable)
{
foreach (var component in ((IDecorable) entity).GetComponents(false))
{
Instances.Remove(component.Guid);
}
}
CoreContext.Current?.MessageHandler?.ClearEntityMessages(entity);
}
}
//--------------------------------------------------------------------------------------------------
// 添加下一个名称后缀
public string AddNextNameSuffix(string baseName)
{
if (!LastNameSuffices.TryGetValue(baseName, out int suffix))
{
suffix = 0;
}
suffix++;
LastNameSuffices[baseName] = suffix;
return baseName + "_" + suffix;
}
//--------------------------------------------------------------------------------------------------
// 查找特定类型的实例
public IEnumerable FindInstances()
{
foreach (var reference in Instances.Values)
{
if (reference.TryGetTarget(out var target))
{
if(target is TEntity typedEntity)
yield return typedEntity;
}
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region File I/O
// 文档文件系统处理程序
public delegate void DocumentFileSystemHandler(Document sender, FileSystem fileSystem);
public static event DocumentFileSystemHandler AdditionalDataLoading;
public static event DocumentFileSystemHandler AdditionalDataSaving;
//--------------------------------------------------------------------------------------------------
// 保存文档
public bool Save()
{
if (!FilePath.IsNullOrEmpty())
{
return SaveToFile(FilePath);
}
return false;
}
//--------------------------------------------------------------------------------------------------
// 保存到文件
public abstract bool SaveToFile(string filePath);
//--------------------------------------------------------------------------------------------------
// 带上下文的保存到文件
protected bool SaveToFile(string filePath, SerializationContext context)
{
// 保存
try
{
using FileSystem fileSystem = new(filePath);
if (!fileSystem.Serialize(GetType().Name, this, context))
return false;
SaveData(fileSystem);
fileSystem.Commit();
HasUnsavedChanges = false;
FilePath = filePath;
return true;
}
catch (Exception e)
{
Messages.Error(e.Message);
return false;
}
}
//--------------------------------------------------------------------------------------------------
// 从文件创建实例
protected static TD CreateFromFile(string filePath, SerializationContext context, Func verifyVersion)
where TD : Document
{
try
{
using FileSystem fileSystem = new(filePath);
var newDoc = fileSystem.Deserialize(typeof(TD).Name, context, verifyVersion);
if (newDoc != null)
{
newDoc.FilePath = filePath;
newDoc.HasUnsavedChanges = false;
newDoc.LoadData(fileSystem);
if (context.HasErrors)
{
Messages.Error($"The document {Path.GetFileName(filePath)} loaded with errors.", string.Join("\n", context.Errors), newDoc);
}
}
return newDoc;
}
catch (Exception e)
{
Messages.Error(e.Message);
return null;
}
}
//--------------------------------------------------------------------------------------------------
// 保存数据
protected virtual bool SaveData(FileSystem fileSystem)
{
AdditionalDataSaving?.Invoke(this, fileSystem);
return true;
}
//--------------------------------------------------------------------------------------------------
// 加载数据
protected virtual bool LoadData(FileSystem fileSystem)
{
AdditionalDataLoading?.Invoke(this, fileSystem);
return true;
}
//--------------------------------------------------------------------------------------------------
// 反序列化开始时调用
public override void OnBeginDeserializing(SerializationContext context)
{
context.SetInstance(this);
base.OnBeginDeserializing(context);
}
//--------------------------------------------------------------------------------------------------
#endregion
}
}
整段代码定义了一个抽象类 Document
,用于表示文档,并实现了文档的保存、加载、添加子实体、注册实例等功能。该类还实现了 IDocument
和 IUndoableTopology
接口,用于文档操作和撤销操作。
10.
using System;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using Macad.Common;
using Macad.Common.Serialization;
namespace Macad.Core.Topology
{
// 表示顶级实体的抽象基类
[SerializeType]
public abstract class Entity : BaseObject
{
// 实体的全局唯一标识符
[SerializeMember]
[SerializeReferenceId]
public Guid Guid
{
get { return _Guid; }
set
{
_Document?.UnregisterInstance(this); // 在更改之前注销旧实例
_Guid = value;
_Document?.RegisterInstance(this); // 在更改之后注册新实例
}
}
//--------------------------------------------------------------------------------------------------
// 实体的类型名称
public string TypeName
{
get { return GetType().Name; }
}
//--------------------------------------------------------------------------------------------------
// 实体的名称属性,虚方法,可以在派生类中重写
[SuppressMessage("ReSharper", "ValueParameterNotUsed")]
public virtual string Name
{
get { return "Unknown"; } // 默认名称为"Unknown"
set { }
}
//--------------------------------------------------------------------------------------------------
// 实体是否有错误的标志
public virtual bool HasErrors
{
get { return _HasErrors; }
set
{
if (_HasErrors != value)
{
_HasErrors = value;
RaisePropertyChanged(); // 触发属性更改事件
RaiseErrorStateChanged(); // 触发错误状态更改事件
}
}
}
//--------------------------------------------------------------------------------------------------
// 构造函数,为实体分配全局唯一标识符
protected Entity()
{
_Guid = Guid.NewGuid();
}
//--------------------------------------------------------------------------------------------------
#region Topology
// 实体所属的文档
internal IDocument Document
{
get { return _Document; }
set
{
_Document?.UnregisterInstance(this); // 在更改之前注销旧实例
_Document = value;
_Document?.RegisterInstance(this); // 在更改之后注册新实例
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Members
IDocument _Document; // 实体所属的文档
Guid _Guid; // 实体的全局唯一标识符
bool _HasErrors; // 实体是否有错误的标志
//--------------------------------------------------------------------------------------------------
#endregion
#region Events
// 实体移除事件
public delegate void EntityChangedEventHandler(Entity entity);
//--------------------------------------------------------------------------------------------------
public static event EntityChangedEventHandler EntityRemoved;
void RaiseEntityRemoved()
{
EntityRemoved?.Invoke(this); // 触发实体移除事件
}
//--------------------------------------------------------------------------------------------------
public static event EntityChangedEventHandler ErrorStateChanged;
void RaiseErrorStateChanged()
{
ErrorStateChanged?.Invoke(this); // 触发错误状态更改事件
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Serialization
// 获取实体的参考标识符
public override Guid? GetReferenceId()
{
return Guid;
}
//--------------------------------------------------------------------------------------------------
// 反序列化完成时调用的方法
public override void OnDeserialized(SerializationContext context)
{
Document = context.GetInstance(); // 设置实体所属的文档
base.OnDeserialized(context);
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Undo
// 保存属性更改的撤销操作
protected virtual void SaveUndo([CallerMemberName] string propertyName = "", object value = null)
{
if (!IsDeserializing && _Document != null)
{
CoreContext.Current?.UndoHandler?.AddPropertyChange(this, propertyName, value); // 将属性更改添加到撤销处理程序中
}
}
//--------------------------------------------------------------------------------------------------
#endregion
// 移除实体
public virtual void Remove()
{
RaiseEntityRemoved(); // 触发实体移除事件
Document = null; // 解除实体与文档的关联
}
//--------------------------------------------------------------------------------------------------
// 返回实体的名称
public override string ToString()
{
return Name;
}
}
}
整段代码定义了一个名为 Entity
的抽象基类,表示顶级实体,它具有全局唯一标识符、名称、错误状态等属性,并提供了与文档、撤销操作相关的方法。
11.
using System.Collections.Generic;
using System.Collections.Specialized;
using Macad.Common.Serialization;
namespace Macad.Core.Topology
{
// 表示实体容器的泛型类
[SerializeType]
public class EntityContainer : Entity, IEnumerable, INotifyCollectionChanged
where T : Entity
{
//--------------------------------------------------------------------------------------------------
// 构造函数,初始化 EntityList
public EntityContainer()
{
EntityList = new List();
}
//--------------------------------------------------------------------------------------------------
#region EntityList
// 实体列表
[SerializeMember(SortKey = 1000)]
List EntityList { get; set; }
//--------------------------------------------------------------------------------------------------
// 实体数量
public int EntityCount
{
get { return EntityList.Count; }
}
//--------------------------------------------------------------------------------------------------
// 添加实体到容器
public virtual void Add(T entity, bool update = true)
{
EntityList.Add(entity);
if (update)
{
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, entity, EntityList.Count-1));
}
}
//--------------------------------------------------------------------------------------------------
// 从容器中移除实体
public virtual void Remove(T entity, bool update = true)
{
var index = EntityList.IndexOf(entity);
if (index < 0)
return;
EntityList.RemoveAt(index);
entity.Remove(); // 调用实体的 Remove 方法
if (update)
{
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, entity, index));
}
}
//--------------------------------------------------------------------------------------------------
// 获取指定索引处的实体
public virtual T Get(int index)
{
return EntityList[index];
}
//--------------------------------------------------------------------------------------------------
// 移除容器中的所有实体
public override void Remove()
{
EntityList.ForEach(e => e.Remove()); // 调用每个实体的 Remove 方法
EntityList.Clear(); // 清空实体列表
base.Remove(); // 调用基类的 Remove 方法
}
#endregion
#region IEnumerable
// 实现 IEnumerable 接口的方法,用于循环访问实体列表
public IEnumerator GetEnumerator()
{
return EntityList.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return EntityList.GetEnumerator();
}
//--------------------------------------------------------------------------------------------------
#endregion
#region INotifyCollectionChanged
// 集合更改事件
public event NotifyCollectionChangedEventHandler CollectionChanged;
//--------------------------------------------------------------------------------------------------
#endregion
}
}
该代码定义了一个泛型类 EntityContainer
,表示实体容器,它包含一个实体列表 EntityList
,可以添加、移除、获取实体,并且支持 IEnumerable
和 INotifyCollectionChanged
接口。
12.
using System;
using Macad.Common.Serialization;
using Macad.Core.Components;
using Macad.Occt;
namespace Macad.Core.Topology
{
// 交互式实体的抽象基类
[SerializeType]
public abstract class InteractiveEntity : Entity
{
#region Properties
// 实体名称
[SerializeMember(SortKey = -900)]
public override string Name
{
get { return _Name; }
set
{
if (_Name != value)
{
SaveUndo(); // 保存撤销信息
_Name = value;
RaisePropertyChanged(); // 触发属性更改事件
}
}
}
//--------------------------------------------------------------------------------------------------
// 是否可见
[SerializeMember]
public bool IsVisible
{
get { return _IsVisible; }
set
{
if (_IsVisible != value)
{
SaveUndo(); // 保存撤销信息
_IsVisible = value;
RaisePropertyChanged(); // 触发属性更改事件
if (!IsDeserializing && CoreContext.Current != null && CoreContext.Current.Workspace != null)
{
RaiseVisualChanged(); // 触发可视化更改事件
}
}
}
}
//--------------------------------------------------------------------------------------------------
// 图层ID
[SerializeMember]
public Guid LayerId
{
get { return _LayerId; }
set
{
if (_LayerId != value)
{
SaveUndo(); // 保存撤销信息
_LayerId = value;
Invalidate(); // 使实体无效
RaisePropertyChanged(); // 触发属性更改事件
RaisePropertyChanged("Layer"); // 触发属性更改事件
RaiseVisualChanged(); // 触发可视化更改事件
}
}
}
// 图层
public Layer Layer
{
get { return CoreContext.Current?.Layers?.Find(_LayerId); }
set
{
var layers = CoreContext.Current?.Layers;
LayerId = (value == layers?.Default || value == null) ? Guid.Empty : value.Guid;
}
}
//--------------------------------------------------------------------------------------------------
#endregion
#region Initialization / Serialization
// 成员变量
Guid _LayerId;
string _Name;
bool _IsVisible;
//--------------------------------------------------------------------------------------------------
// 构造函数
protected InteractiveEntity()
{
_Name = "Unnamed"; // 默认名称
_IsVisible = true; // 默认可见
}
//--------------------------------------------------------------------------------------------------
// 开始反序列化时调用
public override void OnBeginDeserializing(SerializationContext context)
{
base.OnBeginDeserializing(context);
context.GetInstanceList().Add(this); // 添加到实例列表
context.SetInstance(this);
}
//--------------------------------------------------------------------------------------------------
// 移除实体时调用
public override void Remove()
{
base.Remove();
}
//--------------------------------------------------------------------------------------------------
// 获取转换后的 BRep 几何体
public virtual TopoDS_Shape GetTransformedBRep()
{
return null;
}
//--------------------------------------------------------------------------------------------------
#endregion
// 使实体无效
public virtual void Invalidate()
{
// Nothing to do here
}
//--------------------------------------------------------------------------------------------------
// 交互式实体更改事件处理程序
public delegate void InteractiveChangedEventHandler(InteractiveEntity entity);
public static event InteractiveChangedEventHandler VisualChanged;
// 触发可视化更改事件
public void RaiseVisualChanged()
{
if (!IsDeserializing)
VisualChanged?.Invoke(this);
}
//--------------------------------------------------------------------------------------------------
// 获取可视化样式组件
public virtual VisualStyle GetVisualStyleComponent()
{
return null;
}
//--------------------------------------------------------------------------------------------------
}
}
该代码定义了一个抽象基类 InteractiveEntity
,表示交互式实体,包含了名称、可见性、图层等属性,并提供了初始化、序列化、移除、获取转换后的几何体等功能。同时还定义了交互式实体更改事件和获取可视化样式组件的方法。
13.
using System.Collections.Generic;
using System.ComponentModel;
using Macad.Core.Shapes;
using Macad.Occt;
namespace Macad.Core.Topology
{
// 可变换接口
public interface ITransformable
{
// 位置
Pnt Position { get; set; }
// 旋转
Quaternion Rotation { get; set; }
// 几何体形状
Shape Shape
{
get { return null; }
}
//--------------------------------------------------------------------------------------------------
// 属性更改事件
event PropertyChangedEventHandler PropertyChanged;
// 获取坐标系
public Ax3 GetCoordinateSystem();
// 获取关联的可变换对象集合
IEnumerable GetLinkedTransformables()
{
yield break;
}
//--------------------------------------------------------------------------------------------------
}
}
该代码定义了一个接口 ITransformable
,表示可变换对象,包含了位置、旋转、几何体形状等属性,并提供了获取坐标系、获取关联的可变换对象集合等功能。
14.
using System.Diagnostics;
using System.Runtime.CompilerServices;
using Macad.Common;
using Macad.Common.Serialization;
using Macad.Occt;
namespace Macad.Core.Topology
{
// 图层类
[SerializeType]
[DebuggerDisplay("Layer: {Name,nq}")]
public class Layer : Entity
{
// 图层名称
[SerializeMember(SortKey = -900)]
public override string Name
{
get { return _Name; }
set
{
if (_Name != value)
{
SaveUndo();
_Name = value;
RaisePropertyChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 是否可见
[SerializeMember]
public bool IsVisible
{
get { return _IsVisible; }
set
{
if (_IsVisible != value)
{
SaveUndo();
_IsVisible = value;
RaisePropertyChanged();
RaiseInteractivityChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 是否锁定
[SerializeMember]
public bool IsLocked
{
get { return _IsLocked; }
set
{
if (_IsLocked != value)
{
SaveUndo();
_IsLocked = value;
RaisePropertyChanged();
RaiseInteractivityChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 展示模式
[SerializeMember]
public PresentationMode PresentationMode
{
get { return _PresentationMode; }
set
{
if (_PresentationMode != value)
{
SaveUndo();
_PresentationMode = value;
RaisePropertyChanged();
RaisePresentationChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 颜色
[SerializeMember]
public Color Color
{
get { return _Color; }
set
{
if (_Color != value)
{
SaveUndo();
_Color = value;
RaisePropertyChanged();
RaisePresentationChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 透明度
[SerializeMember]
public float Transparency
{
get { return _Transparency; }
set
{
if (_Transparency != value)
{
SaveUndo();
_Transparency = value;
RaisePropertyChanged();
RaisePresentationChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 线型
[SerializeMember]
public LineStyle LineStyle
{
get { return _LineStyle; }
set
{
if (_LineStyle != value)
{
SaveUndo();
_LineStyle = value;
RaisePropertyChanged();
RaisePresentationChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 线宽
[SerializeMember]
public LineThickness LineThickness
{
get { return _LineThickness; }
set
{
if (_LineThickness != value)
{
SaveUndo();
_LineThickness = value;
RaisePropertyChanged();
RaisePresentationChanged();
}
}
}
//--------------------------------------------------------------------------------------------------
// 集合
public LayerCollection Collection
{
get { return _Collection; }
set
{
_Collection = value;
Document = _Collection?.Model;
}
}
//--------------------------------------------------------------------------------------------------
// 是否激活
public bool IsActive
{
get { return this == CoreContext.Current?.Layers?.ActiveLayer; }
}
// 激活图层更改时调用
internal void OnActiveLayerChanged()
{
RaisePropertyChanged("IsActive");
}
//--------------------------------------------------------------------------------------------------
// 图层属性更改事件
#region Events
public delegate void LayerChangedEventHandler(Layer layer);
public static event LayerChangedEventHandler PresentationChanged;
public static event LayerChangedEventHandler InteractivityChanged;
// 触发展示属性更改事件
public void RaisePresentationChanged()
{
PresentationChanged?.Invoke(this);
}
// 触发交互性更改事件
public void RaiseInteractivityChanged()
{
InteractivityChanged?.Invoke(this);
}
#endregion
//--------------------------------------------------------------------------------------------------
#region Members
string _Name;
bool _IsLocked;
bool _IsVisible;
PresentationMode _PresentationMode;
Color _Color;
float _Transparency;
LineStyle _LineStyle;
LineThickness _LineThickness;
LayerCollection _Collection;
//--------------------------------------------------------------------------------------------------
#endregion
// 构造函数
public Layer()
{
_IsVisible = true;
_IsLocked = false;
_PresentationMode = PresentationMode.SolidWithBoundary;
_Color = new Color("#c0c0c0");
_Transparency = 0;
_LineStyle = LineStyle.Solid;
_LineThickness = LineThickness.Normal;
}
//--------------------------------------------------------------------------------------------------
#region Property and Undo handling
// 属性更改时引发事件
protected override void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
base.RaisePropertyChanged(propertyName);
if (!IsDeserializing)
{
if ((CoreContext.Current != null) && (CoreContext.Current.Workspace != null))
CoreContext.Current.Workspace.MarkAsUnsaved();
}
}
//--------------------------------------------------------------------------------------------------
#endregion
//--------------------------------------------------------------------------------------------------
#region Serialization
// 反序列化开始时
public override void OnBeginDeserializing(SerializationContext context)
{
Collection = context.GetInstance();
base.OnBeginDeserializing(context);
}
#endregion
}
}
该代码定义了一个 Layer
类,表示图层。图层包含名称、可见性、锁定状态、展示模式、颜色、透明度、线型、线宽等属性。同时,它还具有处理属性更改和撤销的方法,以及处理事件的功能。
15.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Linq;
using Macad.Common.Serialization;
namespace Macad.Core.Topology
{
// 图层集合类
[SerializeType]
public sealed class LayerCollection : Entity, IEnumerable, INotifyCollectionChanged, IUndoableTopology
{
// 图层列表
[SerializeMember]
List Layers { get; } = new();
//--------------------------------------------------------------------------------------------------
// 获取指定索引处的图层
public Layer this[int i]
{
get { return Layers[i]; }
}
//--------------------------------------------------------------------------------------------------
// 默认图层
public Layer Default
{
get { return Layers.Count > 0 ? Layers[0] : null; }
}
//--------------------------------------------------------------------------------------------------
// 所属模型
public Model Model
{
get { return _Model; }
set
{
_Model = value;
Document = _Model;
}
}
//--------------------------------------------------------------------------------------------------
// 活动图层
[SerializeMember]
public Layer ActiveLayer
{
get { return _ActiveLayer ?? Default; }
set
{
if (_ActiveLayer != value)
{
var formerLayer = ActiveLayer;
_ActiveLayer = value;
RaisePropertyChanged();
formerLayer?.OnActiveLayerChanged();
ActiveLayer.OnActiveLayerChanged();
if (_IsolateActiveLayer)
{
formerLayer?.RaiseInteractivityChanged();
ActiveLayer.RaiseInteractivityChanged();
}
}
}
}
//--------------------------------------------------------------------------------------------------
// 是否孤立活动图层
[SerializeMember]
public bool IsolateActiveLayer
{
get { return _IsolateActiveLayer; }
set
{
if (_IsolateActiveLayer != value)
{
_IsolateActiveLayer = value;
RaisePropertyChanged();
foreach (var changedLayer in Layers.Where(layer => layer != _ActiveLayer && !layer.IsLocked && layer.IsVisible))
{
changedLayer.RaiseInteractivityChanged();
}
}
}
}
bool _IsolateActiveLayer;
Layer _ActiveLayer;
Model _Model;
//--------------------------------------------------------------------------------------------------
// 构造函数
LayerCollection()
{
// 仅用于反序列化
}
//--------------------------------------------------------------------------------------------------
// 构造函数
internal LayerCollection(Model model)
{
Model = model;
// 默认图层
Layers.Add(new Layer()
{
Name = "0 (Default)",
Collection = this
});
}
//--------------------------------------------------------------------------------------------------
// 查找指定 GUID 的图层
public Layer Find(Guid? guid)
{
if (guid == null)
return Layers[0];
return Layers.FirstOrDefault(l => l.Guid == guid) ?? Layers[0];
}
//--------------------------------------------------------------------------------------------------
// 添加图层
public void Add(Layer layer)
{
if (Layers.Any(l => l.Guid == layer.Guid))
return;
CoreContext.Current?.UndoHandler?.AddTopologyChange(UndoHandler.TopologyAction.Added, this, layer);
layer.Collection = this;
Layers.Add(layer);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, layer, Layers.IndexOf(layer)));
}
//--------------------------------------------------------------------------------------------------
// 移除图层
public void Remove(Layer layer)
{
if(ReferenceEquals(layer, Default))
throw new ArgumentException("The default layer can not be removed.");
var index = Layers.IndexOf(layer);
if (index >= 0)
{
CoreContext.Current?.UndoHandler?.AddTopologyChange(UndoHandler.TopologyAction.Removed, this, layer);
Layers.RemoveAt(index);
layer.Collection = null;
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, layer, index));
}
if (_ActiveLayer == layer)
ActiveLayer = null;
// 实体被推回到默认图层,更新它们
foreach (var changedBody in CoreContext.Current?.Document?.Where(body => body.LayerId.Equals(layer.Guid)))
{
changedBody.LayerId = Guid.Empty;
}
}
//--------------------------------------------------------------------------------------------------
// 移动图层
public bool Move(Layer layer, int newIndex)
{
int oldIndex = Layers.IndexOf(layer);
if (layer == null)
return false;
if (oldIndex == newIndex)
return false;
if (oldIndex < newIndex)
newIndex--;
Layers.Remove(layer);
Layers.Insert(newIndex, layer);
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, layer, oldIndex));
CollectionChanged?.Invoke(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, layer, newIndex));
return true;
}
//--------------------------------------------------------------------------------------------------
#region IEnumerable
// 获取枚举器
public IEnumerator GetEnumerator()
{
return Layers.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return Layers.GetEnumerator();
}
//--------------------------------------------------------------------------------------------------
#endregion
#region INotifyCollectionChanged
// 集合更改事件
public event NotifyCollectionChangedEventHandler CollectionChanged;
//--------------------------------------------------------------------------------------------------
#endregion
#region Serialization
// 反序列化开始时
public override void OnBeginDeserializing(SerializationContext context)
{
Model = context.GetInstance();
base.OnBeginDeserializing(context);
context.SetInstance(this);
}
//--------------------------------------------------------------------------------------------------
// 激活时
public void OnActivated()
{
RaisePropertyChanged(nameof(ActiveLayer));
}
//--------------------------------------------------------------------------------------------------
#endregion
#region IUndoableTopology
// 查找实例
Entity IUndoableTopology.FindInstance(Guid instanceGuid)
{
return Find(instanceGuid);
}
//--------------------------------------------------------------------------------------------------
// 获取父级
Entity IUndoableTopology.GetParent(Entity instance)
{
return Layers.Contains(instance) ? this : null;
}
//--------------------------------------------------------------------------------------------------
// 从撤销添加子级
void IUndoableTopology.AddChildFromUndo(Entity instance, Entity parent)
{
var typedInstance = instance as Layer;
Debug.Assert(typedInstance != null);
Add(typedInstance);
}
//--------------------------------------------------------------------------------------------------
// 从撤销移除子级
void IUndoableTopology.RemoveChildFromUndo(Entity instance)
{
var typedInstance = instance as Layer;
Debug.Assert(typedInstance != null);
Remove(typedInstance);
typedInstance.Remove();
}
//--------------------------------------------------------------------------------------------------
// 从撤销移动子级
void IUndoableTopology.MoveChildFromUndo(Entity instance, Entity newParent)
{
throw new NotImplementedException();
}
//--------------------------------------------------------------------------------------------------
#endregion
}
}
该代码定义了一个 LayerCollection
类,表示图层的集合。该集合包含了多个图层,并提供了添加、移除、移动图层等操作。此外,还实现了反序列化、集合更改事件和撤销相关的功能。
16.
using Macad.Occt;
namespace Macad.Core.Topology
{
///
/// 提供了对实现了 接口的实体进行平移和旋转操作的工具方法。
///
public static class TransformUtils
{
///
/// 将实体沿指定的向量进行平移。
///
/// 要平移的实体。
/// 平移的向量。
public static void Translate(ITransformable entity, Vec vec)
{
// 获取实体当前位置,并根据指定的向量进行平移
entity.Position = entity.Position.Translated(vec);
}
//--------------------------------------------------------------------------------------------------
///
/// 将实体围绕指定轴进行旋转。
///
/// 要旋转的实体。
/// 旋转轴。
/// 旋转角度(弧度)。
public static void Rotate(ITransformable entity, Ax1 rotationAxis, double angle)
{
// 创建旋转变换
var rotTrsf = new Trsf(rotationAxis, angle);
// 创建综合变换,包括旋转和平移
var trsf = rotTrsf.Multiplied(new Trsf(entity.Rotation, entity.Position.ToVec()));
// 获取综合变换中的平移部分,赋值给实体的位置属性
entity.Position = trsf.TranslationPart().ToPnt();
// 获取综合变换中的旋转部分,赋值给实体的旋转属性
entity.Rotation = trsf.GetRotation();
}
}
}
这段代码定义了一个静态类 TransformUtils
,其中包含了两个静态方法:
-
Translate(ITransformable entity, Vec vec)
:将实现了 ITransformable
接口的实体沿指定的向量进行平移。该方法首先获取实体的当前位置,然后调用 Translated
方法对位置进行平移,最后将结果赋值给实体的位置属性。
-
Rotate(ITransformable entity, Ax1 rotationAxis, double angle)
:将实现了 ITransformable
接口的实体围绕指定轴进行旋转。该方法首先创建一个旋转变换 rotTrsf
,然后根据该变换以及实体的当前位置和旋转角度创建一个综合变换 trsf
。接着从综合变换中获取平移部分,并将其赋值给实体的位置属性,同时获取旋转部分并将其赋值给实体的旋转属性。
这些方法提供了对实现了 ITransformable
接口的实体进行平移和旋转操作的便捷方式。
17.
using System.Text;
using Macad.Common.Serialization;
namespace Macad.Core
{
///
/// 提供了 Macad.Core 模块的初始化功能。
///
public static class CoreModule
{
static bool _IsInitialized;
//--------------------------------------------------------------------------------------------------
///
/// 初始化 Macad.Core 模块。
///
public static void Initialize()
{
// 如果已经初始化过,则直接返回
if (_IsInitialized)
return;
// 注册编码提供程序,用于支持特定编码
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// 初始化 Occt 序列化器
OcctSerializers.Init();
// 注册命名空间别名,以便在序列化过程中使用
Serializer.RegisterNamespaceAlias("Core", "Macad.Core");
Serializer.RegisterNamespaceAlias("Topology", "Macad.Core.Topology");
Serializer.RegisterNamespaceAlias("Shapes", "Macad.Core.Shapes");
Serializer.RegisterNamespaceAlias("Auxiliary", "Macad.Core.Auxiliary");
Serializer.RegisterNamespaceAlias("Components", "Macad.Core.Components");
Serializer.RegisterNamespaceAlias("Toolkits", "Macad.Core.Toolkits");
Serializer.RegisterNamespaceAlias("Occt", "Macad.Occt");
// 标记已经初始化
_IsInitialized = true;
}
//--------------------------------------------------------------------------------------------------
}
}
通过调用 CoreModule.Initialize()
方法,可以初始化 Macad.Core 模块,注册所需的命名空间别名以及其他必要的设置。
你可能感兴趣的:(学习)