第八章:实体建模系统
8.1 实体建模概述
8.1.1 什么是实体建模
实体建模(Solid Modeling)是三维CAD系统的核心能力,通过对二维轮廓进行拉伸、旋转、放样等操作来创建三维实体对象。LightCAD的实体建模系统位于LightCAD.Core/Elements/Solid/目录下,提供了完整的参数化实体建模功能。
8.1.2 支持的建模操作
| 操作类型 | 类名 | 说明 |
|---|---|---|
| 拉伸 | LcExtrude3d | 沿方向拉伸轮廓 |
| 旋转 | LcRevolve3d | 绕轴旋转轮廓 |
| 放样 | LcLoft3d | 在多个截面之间过渡 |
| 融合 | LcBlend3d | 在实体边缘创建圆角或倒角 |
| 扫掠融合 | LcSweptBlend3d | 沿路径扫掠的融合体 |
| 推拉 | LcPushPull3d | 直接推拉面 |
| 网格 | LcMesh3d | 网格体表示 |
| 布尔运算 | LcCombination | 并集/交集/差集 |
8.2 实体基类(LcSolid3d)
8.2.1 数据结构
LcSolid3d是所有实体建模操作的基类,文件大小达26KB,是Core模块中最复杂的类之一:
public abstract class LcSolid3d : LcEntity, IUpdateObject
{
/// <summary>
/// 实体的变换矩阵
/// </summary>
public Matrix4d Transform { get; set; } = Matrix4d.Identity;
/// <summary>
/// 材质
/// </summary>
public MaterialInfo Material { get; set; }
/// <summary>
/// 三维包围盒
/// </summary>
public BoundingBox3d Bounds3d { get; protected set; }
/// <summary>
/// 体积
/// </summary>
public abstract double Volume { get; }
/// <summary>
/// 表面积
/// </summary>
public abstract double SurfaceArea { get; }
/// <summary>
/// 质心
/// </summary>
public abstract Point3d Centroid { get; }
/// <summary>
/// 生成三角网格(用于渲染)
/// </summary>
public abstract MeshData GenerateMesh(int quality = 1);
/// <summary>
/// 获取实体的面集合
/// </summary>
public abstract List<SolidFace> GetFaces();
/// <summary>
/// 获取实体的边集合
/// </summary>
public abstract List<SolidEdge> GetEdges();
/// <summary>
/// 获取实体的顶点集合
/// </summary>
public abstract List<Point3d> GetVertices();
/// <summary>
/// 参数是否有效
/// </summary>
public abstract bool IsValid { get; }
/// <summary>
/// 重新生成几何(参数改变后调用)
/// </summary>
public abstract void Regenerate();
}
/// <summary>
/// 网格数据(用于渲染)
/// </summary>
public class MeshData
{
public List<Point3d> Vertices { get; set; } = new();
public List<Vector3d> Normals { get; set; } = new();
public List<int> Indices { get; set; } = new();
public List<Point2d> UVCoordinates { get; set; } = new();
}
/// <summary>
/// 实体面
/// </summary>
public class SolidFace
{
public List<Point3d> Vertices { get; set; }
public Vector3d Normal { get; set; }
public FaceType Type { get; set; }
}
public enum FaceType
{
Planar, // 平面
Cylindrical, // 圆柱面
Conical, // 圆锥面
Spherical, // 球面
Toroidal, // 环面
FreeForm // 自由曲面
}
8.3 拉伸体(LcExtrude3d)
8.3.1 数据结构
拉伸是最基本的实体建模操作,将二维轮廓沿指定方向拉伸为三维实体:
public class LcExtrude3d : LcSolid3d
{
/// <summary>
/// 拉伸轮廓
/// </summary>
public LcProfile3d Profile { get; set; }
/// <summary>
/// 拉伸方向
/// </summary>
public Vector3d Direction { get; set; } = Vector3d.ZAxis;
/// <summary>
/// 拉伸距离
/// </summary>
public double Distance { get; set; }
/// <summary>
/// 拔模角度(拉伸时的锥度)
/// </summary>
public double DraftAngle { get; set; } = 0;
/// <summary>
/// 是否双向拉伸
/// </summary>
public bool IsBidirectional { get; set; } = false;
/// <summary>
/// 反向拉伸距离(双向拉伸时使用)
/// </summary>
public double ReverseDistance { get; set; }
/// <summary>
/// 拉伸终止类型
/// </summary>
public ExtrudeEndType EndType { get; set; } = ExtrudeEndType.Distance;
public override string TypeName => "Extrude3d";
public override double Volume
{
get
{
if (Math.Abs(DraftAngle) < 1e-10)
{
// 无拔模角,体积 = 面积 × 距离
return Profile.Area * Distance;
}
else
{
// 有拔模角,需要数值积分
return CalculateVolume();
}
}
}
public override MeshData GenerateMesh(int quality = 1)
{
var mesh = new MeshData();
var profilePoints = Profile.OuterLoop.Tessellate();
int segments = profilePoints.Count;
// 生成底面和顶面
GenerateCapMesh(mesh, profilePoints, 0, false); // 底面
GenerateCapMesh(mesh, profilePoints, Distance, true); // 顶面
// 生成侧面
GenerateSideMesh(mesh, profilePoints);
return mesh;
}
private void GenerateCapMesh(MeshData mesh, List<Point2d> profile,
double height, bool isTop)
{
var baseIndex = mesh.Vertices.Count;
var normal = isTop ? Direction : Direction * -1;
foreach (var p in profile)
{
var worldPoint = Profile.WorkPlane.LocalToWorld(p);
mesh.Vertices.Add(new Point3d(
worldPoint.X + Direction.X * height,
worldPoint.Y + Direction.Y * height,
worldPoint.Z + Direction.Z * height
));
mesh.Normals.Add(normal);
}
// 三角化(扇形三角化)
for (int i = 1; i < profile.Count - 1; i++)
{
if (isTop)
{
mesh.Indices.Add(baseIndex);
mesh.Indices.Add(baseIndex + i + 1);
mesh.Indices.Add(baseIndex + i);
}
else
{
mesh.Indices.Add(baseIndex);
mesh.Indices.Add(baseIndex + i);
mesh.Indices.Add(baseIndex + i + 1);
}
}
}
private void GenerateSideMesh(MeshData mesh, List<Point2d> profile)
{
var baseIndex = mesh.Vertices.Count;
for (int i = 0; i < profile.Count; i++)
{
int next = (i + 1) % profile.Count;
// 底部顶点
var bottomPoint = Profile.WorkPlane.LocalToWorld(profile[i]);
// 顶部顶点
var topPoint = new Point3d(
bottomPoint.X + Direction.X * Distance,
bottomPoint.Y + Direction.Y * Distance,
bottomPoint.Z + Direction.Z * Distance
);
// 计算法向量
var edge = Profile.WorkPlane.LocalToWorld(profile[next]);
var edgeDir = new Vector3d(
edge.X - bottomPoint.X,
edge.Y - bottomPoint.Y,
edge.Z - bottomPoint.Z).Normalize();
var sideNormal = edgeDir.Cross(Direction).Normalize();
mesh.Vertices.Add(bottomPoint);
mesh.Normals.Add(sideNormal);
mesh.Vertices.Add(topPoint);
mesh.Normals.Add(sideNormal);
}
// 侧面三角形索引
for (int i = 0; i < profile.Count; i++)
{
int next = (i + 1) % profile.Count;
int bi = baseIndex + i * 2;
int ni = baseIndex + next * 2;
mesh.Indices.Add(bi);
mesh.Indices.Add(bi + 1);
mesh.Indices.Add(ni);
mesh.Indices.Add(ni);
mesh.Indices.Add(bi + 1);
mesh.Indices.Add(ni + 1);
}
}
}
public enum ExtrudeEndType
{
Distance, // 指定距离
ToFace, // 延伸到面
ThroughAll, // 贯穿全部
ToNextFace // 延伸到下一个面
}
8.3.2 使用示例
// 创建一个矩形轮廓并拉伸
var profile = new LcProfile3d
{
WorkPlane = new LcWorkPlane3d
{
Origin = Point3d.Origin,
Normal = Vector3d.ZAxis
},
OuterLoop = CreateRectangle(0, 0, 100, 50)
};
var extrude = new LcExtrude3d
{
Profile = profile,
Direction = Vector3d.ZAxis,
Distance = 30,
DraftAngle = 0
};
// 带拔模角的拉伸(创建锥台)
var tapered = new LcExtrude3d
{
Profile = profile,
Direction = Vector3d.ZAxis,
Distance = 50,
DraftAngle = AngleUtils.DegToRad(5) // 5度拔模角
};
// 双向拉伸
var bidirectional = new LcExtrude3d
{
Profile = profile,
Direction = Vector3d.ZAxis,
Distance = 20,
IsBidirectional = true,
ReverseDistance = 10
};
8.4 旋转体(LcRevolve3d)
8.4.1 数据结构
public class LcRevolve3d : LcSolid3d
{
/// <summary>
/// 旋转轮廓
/// </summary>
public LcProfile3d Profile { get; set; }
/// <summary>
/// 旋转轴上的一点
/// </summary>
public Point3d AxisPoint { get; set; }
/// <summary>
/// 旋转轴方向
/// </summary>
public Vector3d AxisDirection { get; set; } = Vector3d.YAxis;
/// <summary>
/// 旋转角度(弧度)
/// </summary>
public double Angle { get; set; } = 2 * Math.PI;
/// <summary>
/// 是否为完整旋转(360度)
/// </summary>
public bool IsFullRevolution => Math.Abs(Angle - 2 * Math.PI) < 1e-10;
public override string TypeName => "Revolve3d";
public override MeshData GenerateMesh(int quality = 1)
{
var mesh = new MeshData();
var profilePoints = Profile.OuterLoop.Tessellate();
int radialSegments = Math.Max(16, 32 * quality);
// 对每个轮廓点,绕轴旋转生成顶点环
for (int i = 0; i <= radialSegments; i++)
{
var t = (double)i / radialSegments;
var currentAngle = Angle * t;
var rotationMatrix = RotateAroundAxis(
AxisPoint, AxisDirection, currentAngle);
foreach (var p in profilePoints)
{
var worldPoint = Profile.WorkPlane.LocalToWorld(p);
var rotated = rotationMatrix.Transform(worldPoint);
mesh.Vertices.Add(rotated);
// 计算法向量
var normal = CalculateNormal(worldPoint, rotated, AxisPoint);
mesh.Normals.Add(normal);
}
}
// 生成三角形索引
int profileCount = profilePoints.Count;
for (int i = 0; i < radialSegments; i++)
{
for (int j = 0; j < profileCount - 1; j++)
{
int current = i * profileCount + j;
int next = (i + 1) * profileCount + j;
mesh.Indices.Add(current);
mesh.Indices.Add(next);
mesh.Indices.Add(current + 1);
mesh.Indices.Add(current + 1);
mesh.Indices.Add(next);
mesh.Indices.Add(next + 1);
}
}
return mesh;
}
}
8.4.2 使用示例
// 创建一个花瓶形状(旋转体)
var vaseProfile = new LcPolyline();
vaseProfile.AddVertex(new Point2d(20, 0)); // 底部
vaseProfile.AddVertex(new Point2d(25, 10));
vaseProfile.AddVertex(new Point2d(15, 30)); // 收窄
vaseProfile.AddVertex(new Point2d(20, 50));
vaseProfile.AddVertex(new Point2d(30, 80)); // 口沿
vaseProfile.AddVertex(new Point2d(28, 85));
vaseProfile.AddVertex(new Point2d(0, 85)); // 内壁
vaseProfile.IsClosed = true;
var profile = new LcProfile3d
{
WorkPlane = new LcWorkPlane3d { Origin = Point3d.Origin },
OuterLoop = vaseProfile
};
var vase = new LcRevolve3d
{
Profile = profile,
AxisPoint = Point3d.Origin,
AxisDirection = Vector3d.YAxis,
Angle = 2 * Math.PI // 完整旋转
};
8.5 放样体(LcLoft3d)
8.5.1 数据结构
放样操作在两个或多个截面轮廓之间创建平滑过渡的实体。LcLoft3d是建模系统中最复杂的操作之一(源代码文件达40KB):
public class LcLoft3d : LcSolid3d
{
/// <summary>
/// 截面轮廓集合(至少2个)
/// </summary>
public List<LcProfile3d> Profiles { get; set; } = new();
/// <summary>
/// 引导线(可选,用于控制过渡形状)
/// </summary>
public List<LcCurve3d> GuideCurves { get; set; } = new();
/// <summary>
/// 路径曲线(可选,截面沿路径放样)
/// </summary>
public LcCurve3d PathCurve { get; set; }
/// <summary>
/// 起始条件
/// </summary>
public LoftEndCondition StartCondition { get; set; } = LoftEndCondition.Free;
/// <summary>
/// 终止条件
/// </summary>
public LoftEndCondition EndCondition { get; set; } = LoftEndCondition.Free;
/// <summary>
/// 过渡类型
/// </summary>
public LoftTransitionType Transition { get; set; } = LoftTransitionType.Smooth;
public override string TypeName => "Loft3d";
public override MeshData GenerateMesh(int quality = 1)
{
var mesh = new MeshData();
int steps = Math.Max(16, 32 * quality);
// 对每个步骤,在截面之间插值
for (int step = 0; step <= steps; step++)
{
var t = (double)step / steps;
var interpolatedProfile = InterpolateProfiles(t);
foreach (var point in interpolatedProfile)
{
mesh.Vertices.Add(point);
}
}
// 生成三角形索引(连接相邻步骤的顶点)
// ...
return mesh;
}
/// <summary>
/// 在截面之间进行插值
/// </summary>
private List<Point3d> InterpolateProfiles(double t)
{
if (Profiles.Count < 2)
throw new InvalidOperationException("至少需要2个截面");
// 确定当前t值对应的两个截面
var sectionT = t * (Profiles.Count - 1);
int index = Math.Min((int)sectionT, Profiles.Count - 2);
var localT = sectionT - index;
var profile1 = Profiles[index].GetWorldPoints();
var profile2 = Profiles[index + 1].GetWorldPoints();
// 确保两个轮廓的顶点数一致
AlignVertexCounts(ref profile1, ref profile2);
// 线性插值(可替换为样条插值以获得更平滑的效果)
var result = new List<Point3d>();
for (int i = 0; i < profile1.Count; i++)
{
result.Add(new Point3d(
profile1[i].X * (1 - localT) + profile2[i].X * localT,
profile1[i].Y * (1 - localT) + profile2[i].Y * localT,
profile1[i].Z * (1 - localT) + profile2[i].Z * localT
));
}
return result;
}
}
public enum LoftEndCondition
{
Free, // 自由
Tangent, // 与相邻面相切
Perpendicular, // 垂直于截面
Smooth // 平滑过渡
}
public enum LoftTransitionType
{
Linear, // 线性过渡
Smooth, // 平滑过渡
RuleSurface // 直纹面
}
8.6 融合体(LcBlend3d)
8.6.1 数据结构
融合操作用于在实体的边缘创建圆角或倒角:
public class LcBlend3d : LcSolid3d
{
/// <summary>
/// 要进行融合的目标实体
/// </summary>
public LcSolid3d TargetSolid { get; set; }
/// <summary>
/// 要融合的边
/// </summary>
public List<SolidEdge> SelectedEdges { get; set; } = new();
/// <summary>
/// 融合类型
/// </summary>
public BlendType Type { get; set; } = BlendType.Fillet;
/// <summary>
/// 圆角半径
/// </summary>
public double Radius { get; set; }
/// <summary>
/// 倒角距离1
/// </summary>
public double ChamferDistance1 { get; set; }
/// <summary>
/// 倒角距离2
/// </summary>
public double ChamferDistance2 { get; set; }
/// <summary>
/// 是否为变截面融合
/// </summary>
public bool IsVariable { get; set; } = false;
public override string TypeName => "Blend3d";
}
public enum BlendType
{
Fillet, // 圆角
Chamfer // 倒角
}
8.7 推拉体(LcPushPull3d)
8.7.1 数据结构
推拉操作允许直接拉伸或收缩实体的面:
public class LcPushPull3d : LcSolid3d
{
/// <summary>
/// 目标实体
/// </summary>
public LcSolid3d TargetSolid { get; set; }
/// <summary>
/// 选中的面
/// </summary>
public SolidFace SelectedFace { get; set; }
/// <summary>
/// 推拉距离(正值向外,负值向内)
/// </summary>
public double Distance { get; set; }
/// <summary>
/// 拔模角度
/// </summary>
public double DraftAngle { get; set; }
public override string TypeName => "PushPull3d";
}
8.8 网格体(LcMesh3d)
8.8.1 数据结构
LcMesh3d直接以三角网格的形式表示三维实体:
public class LcMesh3d : LcSolid3d
{
/// <summary>
/// 顶点列表
/// </summary>
public List<Point3d> Vertices { get; set; } = new();
/// <summary>
/// 法向量列表
/// </summary>
public List<Vector3d> Normals { get; set; } = new();
/// <summary>
/// 三角形面索引(每3个为一组)
/// </summary>
public List<int> FaceIndices { get; set; } = new();
/// <summary>
/// UV纹理坐标
/// </summary>
public List<Point2d> UVs { get; set; } = new();
/// <summary>
/// 三角形数量
/// </summary>
public int TriangleCount => FaceIndices.Count / 3;
/// <summary>
/// 顶点数量
/// </summary>
public int VertexCount => Vertices.Count;
public override string TypeName => "Mesh3d";
public override double Volume
{
get
{
// 使用Divergence Theorem计算网格体积
double volume = 0;
for (int i = 0; i < FaceIndices.Count; i += 3)
{
var v0 = Vertices[FaceIndices[i]];
var v1 = Vertices[FaceIndices[i + 1]];
var v2 = Vertices[FaceIndices[i + 2]];
volume += SignedTriangleVolume(v0, v1, v2);
}
return Math.Abs(volume);
}
}
private static double SignedTriangleVolume(Point3d a, Point3d b, Point3d c)
{
return (a.X * (b.Y * c.Z - b.Z * c.Y) +
a.Y * (b.Z * c.X - b.X * c.Z) +
a.Z * (b.X * c.Y - b.Y * c.X)) / 6.0;
}
public override MeshData GenerateMesh(int quality = 1)
{
return new MeshData
{
Vertices = new List<Point3d>(Vertices),
Normals = new List<Vector3d>(Normals),
Indices = new List<int>(FaceIndices),
UVCoordinates = new List<Point2d>(UVs)
};
}
/// <summary>
/// 计算平滑法向量
/// </summary>
public void RecalculateNormals()
{
Normals = new List<Vector3d>(new Vector3d[Vertices.Count]);
for (int i = 0; i < FaceIndices.Count; i += 3)
{
var i0 = FaceIndices[i];
var i1 = FaceIndices[i + 1];
var i2 = FaceIndices[i + 2];
var v0 = Vertices[i0];
var v1 = Vertices[i1];
var v2 = Vertices[i2];
var edge1 = new Vector3d(v1.X - v0.X, v1.Y - v0.Y, v1.Z - v0.Z);
var edge2 = new Vector3d(v2.X - v0.X, v2.Y - v0.Y, v2.Z - v0.Z);
var faceNormal = edge1.Cross(edge2);
Normals[i0] = Normals[i0] + faceNormal;
Normals[i1] = Normals[i1] + faceNormal;
Normals[i2] = Normals[i2] + faceNormal;
}
for (int i = 0; i < Normals.Count; i++)
{
Normals[i] = Normals[i].Normalize();
}
}
}
8.9 布尔运算(LcCombination)
8.9.1 数据结构
布尔运算是实体建模中最强大的工具,可以通过并集、交集和差集来组合实体:
public class LcCombination : LcSolid3d
{
/// <summary>
/// 第一个操作实体
/// </summary>
public LcSolid3d SolidA { get; set; }
/// <summary>
/// 第二个操作实体
/// </summary>
public LcSolid3d SolidB { get; set; }
/// <summary>
/// 布尔运算类型
/// </summary>
public BooleanOperationType Operation { get; set; }
public override string TypeName => "Combination";
public override MeshData GenerateMesh(int quality = 1)
{
var meshA = SolidA.GenerateMesh(quality);
var meshB = SolidB.GenerateMesh(quality);
return Operation switch
{
BooleanOperationType.Union =>
BooleanMesh.Union(meshA, meshB),
BooleanOperationType.Intersect =>
BooleanMesh.Intersect(meshA, meshB),
BooleanOperationType.Subtract =>
BooleanMesh.Subtract(meshA, meshB),
_ => meshA
};
}
}
public enum BooleanOperationType
{
Union, // 并集:A ∪ B
Intersect, // 交集:A ∩ B
Subtract // 差集:A - B
}
8.9.2 使用示例
// 创建一个带孔的方块(差集运算)
var box = CreateBox(100, 100, 50);
var cylinder = CreateCylinder(
new Point3d(50, 50, 0), 15, 50);
var boxWithHole = new LcCombination
{
SolidA = box,
SolidB = cylinder,
Operation = BooleanOperationType.Subtract
};
// 创建两个圆柱的交集
var cyl1 = CreateCylinder(Point3d.Origin, 30, 100);
var cyl2 = CreateCylinder(
new Point3d(50, 0, 0), 30, 100);
var intersection = new LcCombination
{
SolidA = cyl1,
SolidB = cyl2,
Operation = BooleanOperationType.Intersect
};
8.10 组件操作(Component.Actions)
8.10.1 操作系统概述
LightCAD.Component.Actions模块提供了实际的建模操作实现,每个操作对应用户界面中的一个命令:
LightCAD.Component.Actions/
├── ComponentActionLoader.cs # 操作加载器
├── CubeAction.cs # 立方体操作
├── CuboidAction.cs # 长方体操作(7KB)
├── ExtrudeAction.cs # 拉伸操作(15KB)
└── LoftAction.cs # 放样操作(40KB)
8.10.2 CuboidAction示例
public class CuboidAction : IComponentAction
{
public string Name => "Cuboid";
public string DisplayName => "长方体";
public string Category => "基本实体";
/// <summary>
/// 执行创建长方体的操作
/// </summary>
public LcSolid3d Execute(ActionContext context)
{
// 获取用户输入的参数
var origin = context.GetPoint("指定基点");
var width = context.GetDistance("指定宽度");
var height = context.GetDistance("指定高度");
var depth = context.GetDistance("指定深度");
// 创建矩形轮廓
var profile = new LcProfile3d
{
WorkPlane = new LcWorkPlane3d { Origin = origin },
OuterLoop = CreateRectangle(0, 0, width, height)
};
// 拉伸创建长方体
return new LcExtrude3d
{
Profile = profile,
Direction = Vector3d.ZAxis,
Distance = depth
};
}
}
8.10.3 ExtrudeAction示例
public class ExtrudeAction : IComponentAction
{
public string Name => "Extrude";
public string DisplayName => "拉伸";
public LcSolid3d Execute(ActionContext context)
{
// 选择要拉伸的轮廓
var profile = context.SelectProfile("选择拉伸轮廓");
// 获取拉伸参数
var distance = context.GetDistance("指定拉伸距离");
var direction = context.GetDirection("指定拉伸方向",
profile.WorkPlane.Normal); // 默认法线方向
var draftAngle = context.GetAngle("拔模角度(可选)", 0);
return new LcExtrude3d
{
Profile = profile,
Direction = direction,
Distance = distance,
DraftAngle = draftAngle
};
}
}
8.11 参数化建模
8.11.1 参数化特性
LightCAD的实体建模系统是参数化的,这意味着:
- 参数可修改:创建实体后可以随时修改参数
- 自动更新:修改参数后实体自动重新生成
- 历史记录:保留完整的建模操作历史
// 修改参数示例
var extrude = new LcExtrude3d { ... };
// 修改拉伸距离
extrude.Distance = 50;
extrude.Regenerate(); // 重新生成几何
// 修改轮廓
extrude.Profile.OuterLoop.Vertices[2] =
new PolylineVertex(new Point2d(150, 50));
extrude.Regenerate();
8.11.2 特征树
LightCAD支持特征树(Feature Tree)来管理建模历史:
public class FeatureTree
{
public List<Feature> Features { get; } = new();
public void AddFeature(Feature feature)
{
Features.Add(feature);
Rebuild();
}
public void RemoveFeature(int index)
{
Features.RemoveAt(index);
Rebuild();
}
/// <summary>
/// 重建所有特征
/// </summary>
public void Rebuild()
{
LcSolid3d currentSolid = null;
foreach (var feature in Features)
{
currentSolid = feature.Apply(currentSolid);
}
}
}
public abstract class Feature
{
public string Name { get; set; }
public bool IsEnabled { get; set; } = true;
public abstract LcSolid3d Apply(LcSolid3d input);
}
8.12 本章小结
本章全面介绍了LightCAD的实体建模系统。从基础的拉伸和旋转,到复杂的放样和布尔运算,LightCAD提供了完整的参数化实体建模能力。所有实体类型都继承自LcSolid3d基类,支持网格生成、体积计算和几何变换。组件操作模块(Component.Actions)将建模操作封装为可交互的命令,方便用户通过界面进行操作。参数化特性使得实体可以在创建后随时修改参数并自动更新。
上一章:第七章:三维图元系统