znlgis 博客

GIS开发与技术分享 — GDAL · GeoServer · PostGIS · QGIS · OpenLayers · Cesium · FreeCAD · NPOI

第07章:空间、开洞与地形

第05章和第06章介绍了墙、梁、柱、楼板、桁架等结构构件。本章将视角从”构件”切换到”容器”与”场地”——空间(Space)定义了房间与区域,开洞(Opening)在构件上创建门窗等通道,地形(Topography)描述场地的高低起伏。此外还会介绍早期设计阶段的体量(Mass)、建筑轴网系统(GridLine)和天花板(Ceiling)元素。

7.1 Space:空间元素

Space 是 Elements 中用于表达可占用区域(occupiable space)的元素类型。它对应 BIM 中的”房间”或”区域”概念——不一定是实体构件,而是建筑中的三维空间范围。

7.1.1 核心属性

public class Space : GeometricElement
{
    public Profile Profile { get; set; }  // 空间的平面轮廓
    public double Height { get; set; }     // 空间的高度
}

Space 由两个关键属性定义:

  • Profile:空间的平面轮廓(Polygon),定义房间在 XY 平面上的边界
  • Height:空间的高度,沿 +Z 方向从底面拉伸

7.1.2 创建空间

using Elements;
using Elements.Geometry;

var model = new Model();

// 用多边形定义房间轮廓
var roomBoundary = new Polygon(new[]
{
    new Vector3(0, 0, 0),
    new Vector3(6, 0, 0),
    new Vector3(6, 4, 0),
    new Vector3(0, 4, 0),
});

var profile = new Profile(roomBoundary);

var livingRoom = new Space(
    profile,
    2.8,                // 层高 2.8 米
    BuiltInMaterials.XAxis,  // 可选材质
    name: "客厅"
);

model.AddElement(livingRoom);

构造函数签名:

public Space(
    Profile profile,
    double height,
    Material material = null,
    Transform transform = null,
    Representation representation = null,
    bool isElementDefinition = false,
    Guid id = default,
    string name = null
);

height 必须大于 0,否则构造函数会抛出 ArgumentOutOfRangeException

7.1.3 计算面积和体积

Space 提供了直观的面积和体积计算方法:

var meetingRoom = new Space(
    new Profile(Polygon.Rectangle(10, 8)),
    3.0,
    name: "会议室"
);

double area = meetingRoom.Area();     // 80 m² (10 × 8)
double volume = meetingRoom.Volume(); // 240 m³ (80 × 3.0)

Area() 委托给 Profile.Area()Volume() 则是面积乘以高度。两者都在几何计算之前就可使用,因为它们仅依赖 Profile 的数学属性,不依赖 CSG 实体生成。

7.1.4 使用 Transform 放置空间

Space 可以通过 Transform 放置在建筑的任意位置和方向:

// 在二楼创建一个空间(Z=3.0 标高)
var upperRoom = new Space(
    new Profile(Polygon.Rectangle(5, 4)),
    2.8,
    transform: new Transform(2, 1, 3.0),  // 从 (2,1,3) 开始
    name: "二楼书房"
);

ProfileTransformed() 方法可以获取 Transform 变换后的轮廓:

Profile transformedProfile = upperRoom.ProfileTransformed();
// 返回原始轮廓应用 Transform 后的新轮廓

7.1.5 几何表示

Space.UpdateRepresentations() 将 Profile 沿 +Z 方向拉伸 Height 距离,生成一个 Extrude 实体操作:

public override void UpdateRepresentations()
{
    this.Representation.SolidOperations.Clear();
    this.Representation.SolidOperations.Add(
        new Extrude(this.Profile, this.Height, Vector3.ZAxis, false)
    );
}

默认材质为 BuiltInMaterials.Mass(半透明材质),区别于墙体等不透明构件,便于在视觉上识别为空间区域。

7.1.6 从实体构造空间

Space 也支持从已有的 Solid 几何体反向构造(常见于 IFC 导入场景):

var solidFromImport = /* 来自 IFC 的 Solid */;
var importedSpace = new Space(solidFromImport, name: "导入房间");

此构造函数将 Solid 包装为 ConstructedSolid,适用于无法还原为 Profile+Height 的复杂空间形状。


7.2 Opening:开洞元素

Opening 用于在墙体、楼板、天花板等实体构件上创建贯通的开洞——如门洞、窗洞、管道井开口等。

7.2.1 核心属性

public class Opening : GeometricElement
{
    public Polygon Perimeter { get; set; }   // 开洞的轮廓多边形
    public double DepthFront { get; set; }    // 沿 +Z 轴方向的深度
    public double DepthBack { get; set; }     // 沿 -Z 轴方向的深度
    public Vector3 Normal { get; set; }       // 开洞的法线方向
}
属性 说明
Perimeter 开洞的平面多边形轮廓,定义洞口形状(可以是矩形、圆形近似等)
DepthFront 洞口在法线正方向(+Z/法线方向)的深度,默认 1.0
DepthBack 洞口在法线负方向(-Z/法线反方向)的深度,默认 1.0
Normal 洞口的法线方向。对于墙体上的开洞,Normal 应与墙面的法线一致

7.2.2 创建开洞

// 创建一个矩形的门洞
var doorPerimeter = Polygon.Rectangle(0.9, 2.1); // 宽 0.9m,高 2.1m

var doorOpening = new Opening(
    doorPerimeter,
    Vector3.ZAxis,       // 法线方向
    depthFront: 0.15,    // 前方深度(墙体厚度方向)
    depthBack: 0.15,     // 后方深度
    transform: new Transform(1.5, 0, 0), // 放置在墙的 (1.5, 0, 0) 处
    name: "主入口"
);

构造函数提供了重载:如果不指定 normal,默认使用 Vector3.ZAxis

// 简化的构造函数(normal 默认为 ZAxis)
public Opening(
    Polygon perimeter,
    double depthFront = 1.0,
    double depthBack = 1.0,
    Transform transform = null,
    ...
);

7.2.3 开洞的几何表示

Opening.UpdateRepresentations() 创建一个 IsVoid = true 的 Extrude 操作:

public override void UpdateRepresentations()
{
    this.Representation.SolidOperations.Clear();
    var depth = this.DepthFront + this.DepthBack;
    var depthBackTransform = new Transform(-DepthBack * Normal);
    var op = new Extrude(
        this.Perimeter.TransformedPolygon(depthBackTransform),
        depth,
        Normal,
        true   // ★ IsVoid = true:这是一个挖空操作
    );
    this.Representation.SolidOperations.Add(op);
}

IsVoid = true 是关键——它告诉 CSG 引擎:此 Extrude 不是添加到实体上,而是从目标实体中减去

7.2.4 开洞与墙体/楼板的关系

开洞本身不直接嵌入到墙体中。正确的做法是:将 Opening 添加到目标元素的 Openings 列表中。Elements 中实现了 IHasOpenings 接口的元素包括:

  • Wall(以及 StandardWall
  • Floor
  • SolidCeiling
// IHasOpenings 接口
public interface IHasOpenings
{
    List<Opening> Openings { get; }
}

工作流程:

// 1. 创建墙
var wall = new Wall(
    new Line(new Vector3(0, 0, 0), new Vector3(6, 0, 0)),
    new Profile(Polygon.Rectangle(0.2, 3.0)),
    3.0,
    name: "外墙-A"
);

// 2. 创建开洞
var windowOpening = new Opening(
    Polygon.Rectangle(1.2, 1.5),   // 1.2m × 1.5m 的窗洞
    depthFront: 0.11,
    depthBack: 0.11,
    transform: new Transform(2, -0.11, 0.9), // 离地 0.9m,墙厚方向居中
    name: "窗户-1"
);

// 3. 将开洞添加到墙的 Openings 列表
wall.Openings.Add(windowOpening);

// 4. 添加到模型(墙和开洞都需要添加)
model.AddElement(wall);
// 墙的 UpdateRepresentations 会读取 Openings 列表,
// 生成组合的 CSG 实体——先拉伸墙体,再减去所有开洞

重要:Opening 本身也是 Element,需要添加到 Model 中(model.AddElement(opening)),否则在序列化和更新的某些环节可能丢失。

7.2.5 在楼板上创建开洞

楼板上的开洞遵循相同的模式:

var floor = new Floor(
    Polygon.Rectangle(8, 6),
    0.2,   // 楼板厚 0.2m
    name: "二楼楼板"
);

// 楼梯井开洞
var stairOpening = new Opening(
    Polygon.Rectangle(2.0, 3.0),
    depthFront: 0.2,
    depthBack: 0.0,
    transform: new Transform(3, 1.5, 0),
    name: "楼梯井"
);

floor.Openings.Add(stairOpening);
model.AddElements(new Element[] { floor, stairOpening });

7.2.6 多边形开洞(非矩形)

Perimeter 是通用的 Polygon 类型,因此可以创建任意形状的开洞:

// 圆形窗洞(用正多边形近似)
var circlePolygon = new Circle(Vector3.Origin, 0.5).ToPolygon(32);
var roundOpening = new Opening(
    circlePolygon,
    depthFront: 0.15,
    depthBack: 0.15,
    transform: new Transform(3, -0.15, 1.5),
    name: "圆窗"
);

wall.Openings.Add(roundOpening);

7.3 Topography:地形元素

Topography 继承自 MeshElement,通过高程点阵(elevation grid)定义三维地形曲面。它自动生成顶面三角网、侧面和底面,形成一个闭合的体量网格。

7.3.1 构造地形

最常见的构造方式:提供原点、宽度和一个扁平的高程数组

using Elements;
using Elements.Geometry;

var model = new Model();

// 定义一个 10×10 的高程点阵(100 个点)
var width = 90.0;  // 场地宽度 90 米
var rowWidth = 10; // 每行 10 个点
var elevations = new double[rowWidth * rowWidth];

var random = new Random(42);
for (var y = 0; y < rowWidth; y++)
{
    for (var x = 0; x < rowWidth; x++)
    {
        var i = x + y * rowWidth;
        // 模拟中间高、四周低的地形
        var distFromCenter = Math.Sqrt(
            Math.Pow(x - rowWidth / 2.0, 2) +
            Math.Pow(y - rowWidth / 2.0, 2)
        );
        elevations[i] = Math.Max(0, 5.0 - distFromCenter * 0.8)
                        + random.NextDouble() * 1.5;
    }
}

var topography = new Topography(
    Vector3.Origin,   // 原点
    width,            // 总宽度
    elevations,       // 高程数组
    name: "场地地形"
);

model.AddElement(topography);

构造函数参数说明:

参数 说明
origin 地形原点(左下角)
width 地形在 X 和 Y 方向的总尺寸(正方形场地)
elevations 扁平数组,长度必须是完全平方数(如 100 = 10×10)
material 材质,默认为 BuiltInMaterials.Topography

内部通过 Math.Sqrt(elevations.Length) 计算 RowWidthCellWidth = width / (RowWidth - 1)

7.3.2 地形几何

Topography 生成的网格包括:

  1. 顶面:根据高程数组三角化的曲面
  2. 四个侧面:从边缘向下延伸到最低高程以下
  3. 底面:最低高程以下 10 米(默认)处的平面

通过 DepthBelowMinimumElevation 属性控制底部深度:

topography.DepthBelowMinimumElevation = 20.0; // 底部延伸到最低点以下 20 米

也可以设置绝对最低高程:

topography.AbsoluteMinimumElevation = -5.0; // 底部在 Z=-5 处
// 设置后 DepthBelowMinimumElevation 将被忽略

7.3.3 地形修剪(Trim)

Trim 方法用指定的轮廓边界裁剪地形:

// 用多边形边界裁剪地形
var boundary = new Profile(Polygon.LShape(60, 60, 30, 20));
topography.Trim(boundary);

Trimmed 方法返回裁剪后的新地形副本(不修改原对象):

var trimmedTopo = topography.Trimmed(boundary);

7.3.4 挖填方计算(CutAndFill)

CutAndFill 是地形中最实用的功能之一——计算将场地平整到指定高程所需的挖方和填方量:

var perimeters = new List<Polygon>
{
    Polygon.Rectangle(10, 40, 20, 5) // 需要平整的区域
};

var (cutVolume, fillVolume) = topography.CutAndFill(
    perimeters,
    3.0,              // 目标高程
    out var cutMeshes,  // 挖方网格
    out var fillMeshes, // 填方网格
    batterAngle: 45.0   // 放坡角度
);

Console.WriteLine($"挖方量: {cutVolume:F2} m³");
Console.WriteLine($"填方量: {fillVolume:F2} m³");

7.3.5 隧道开挖(Tunnel)

// 沿一条 Bézier 曲线开挖隧道
var tunnelPath = new Bezier(
    new List<Vector3>
    {
        new Vector3(0, 30, 2),
        new Vector3(30, 30, 1),
        new Vector3(60, 30, 3),
        new Vector3(90, 30, 2),
    }
);

topography.Tunnel(tunnelPath, diameter: 5.0);

7.3.6 从自定义网格创建地形

// 从外部数据生成 Mesh
var externalMesh = LoadMeshFromFile("terrain.obj");
var customTopo = new Topography(
    externalMesh,
    BuiltInMaterials.Earth,
    new Transform(),
    id: Guid.NewGuid(),
    name: "导入地形"
);

7.4 Mass:体量元素

Mass 是早期设计阶段使用的抽象体量——一个有轮廓和高度的拉伸体,不携带墙、柱等构件的具体语义。

7.4.1 核心属性

public class Mass : GeometricElement
{
    public Profile Profile { get; set; }  // 体量轮廓
    public double Height { get; set; }     // 体量高度
}

Mass 的结构与 Space 非常相似,但语义不同——Mass 代表建筑的总形体量,Space 代表内部的可占用区域。

7.4.2 创建体量

// 创建一个 L 形体量(早期方案推敲)
var lShapedProfile = new Profile(
    Polygon.LShape(30, 20, 12, 14)
);

var buildingMass = new Mass(
    lShapedProfile,
    15.0,   // 15 米高(约 5 层)
    material: new Material("方案体量", new Color(0.7, 0.7, 0.85, 0.4)),
    name: "方案A-主体"
);

Console.WriteLine($"体量容积: {buildingMass.Volume():F1} m³");

model.AddElement(buildingMass);

7.4.3 多个体量的组合

在实际方案推敲中,常需要多个体量来表示塔楼、裙房、附属建筑等:

// 塔楼(正方形,20 层 × 3.5m = 70m)
var tower = new Mass(
    new Profile(Polygon.Rectangle(20, 20)),
    70.0,
    transform: new Transform(5, 5, 0),
    name: "塔楼"
);

// 裙房(矩形,4 层 × 4.5m = 18m)
var podium = new Mass(
    new Profile(Polygon.Rectangle(40, 15)),
    18.0,
    transform: new Transform(-5, -5, 0),
    name: "裙房"
);

model.AddElements(new Element[] { tower, podium });

7.4.4 体量与空间的区别

维度 Mass Space
语义 建筑体量(building massing) 可占用空间(room/zone)
设计阶段 早期概念/方案阶段 详细设计/施工图阶段
默认材质 BuiltInMaterials.Mass(半透明) BuiltInMaterials.Mass
典型用途 体量研究、容积率计算、日照遮挡分析 房间面积统计、空间规划、IFC 导出

7.5 GridLine:轴网元素

GridLine 是建筑和结构设计中的轴网线——表示柱网、承重墙轴线的定位参考线系统。在平面图和立面图中,轴网线通过圆圈标注轴号(如 A, B, C… 或 1, 2, 3…)。

7.5.1 核心属性

public class GridLine : GeometricElement
{
    public BoundedCurve Curve { get; set; }     // 轴网线的几何(Line 或 Polyline)
    public double Radius { get; set; } = 1;     // 轴号圆圈的半径
    public double ExtensionBeginning { get; set; } = 1; // 起始端延伸长度
    public double ExtensionEnd { get; set; } = 1;       // 终止端延伸长度
}

7.5.2 创建轴网

using Elements;
using Elements.Geometry;

var model = new Model();

// 创建纵向轴网(1 号轴、2 号轴、3 号轴...)
for (int i = 0; i <= 6; i++)
{
    var x = i * 8.0; // 柱距 8 米
    var gridLine = new GridLine
    {
        Curve = new Line(
            new Vector3(x, -1, 0),
            new Vector3(x, 33, 0)  // 总长 34m(两端各延伸 1m)
        ),
        Radius = 0.6,
        ExtensionBeginning = 1.5,
        ExtensionEnd = 1.5,
        Name = (i + 1).ToString()   // 轴号 "1", "2", "3"...
    };
    model.AddElement(gridLine);
}

// 创建横向轴网(A 轴、B 轴、C 轴...)
var letters = new[] { "A", "B", "C", "D" };
for (int i = 0; i < letters.Length; i++)
{
    var y = i * 9.0; // 跨度 9 米
    var gridLine = new GridLine
    {
        Curve = new Line(
            new Vector3(-1, y, 0),
            new Vector3(49, y, 0)
        ),
        Radius = 0.6,
        ExtensionBeginning = 1.5,
        ExtensionEnd = 1.5,
        Name = letters[i]
    };
    model.AddElement(gridLine);
}

7.5.3 轴网的视觉呈现

GridLine 的几何渲染由 TryToGraphicsBuffers 方法控制,它生成一个包含三部分的线条:

  1. 圆圈(轴号标注)
  2. 延伸段(从圆圈到轴线起点)
  3. 轴线主体
  4. 延伸段(从轴线终点到另一端)

AddTextToCollection 方法为轴号文字提供放置信息:

var texts = new List<(Vector3 location, Vector3 facingDirection,
                     Vector3 lineDirection, string text, Color? color)>();

foreach (var gridLine in model.AllElementsOfType<GridLine>())
{
    gridLine.AddTextToCollection(texts);
}

// texts 中包含每个轴网的文字位置和方向,
// 可用于在 glTF 或其他导出中放置 ModelText

7.6 Ceiling:天花板元素

Elements 将天花板设计为从楼板(Floor)向上偏移形成的独立元素体系。它具有四种类型:

BaseCeiling(抽象基类)
├── SolidCeiling     实体天花板(带厚度和开洞)
├── OpenCeiling       无几何天花板(仅定义边界和标高)
└── TiledCeiling      格栅/拼块天花板(通过 Grid2d 排布)

7.6.1 BaseCeiling:天花板基类

public abstract class BaseCeiling : GeometricElement
{
    public double Elevation { get; protected set; }   // 标高(天花板下表面高度)
    public Polygon Perimeter { get; protected set; }   // 轮廓(必须位于 XY 平面)
}

BaseCeiling 的构造函数要求 Perimeter 位于 XY 平面(会内部验证 Normal().IsParallelTo(Vector3.ZAxis))。构造时自动将 Transform 沿 Z 方向平移到 Elevation 标高。

7.6.2 SolidCeiling:实体天花板

最常用的天花板类型——一个从 Perimeter 向上拉伸 Thickness 的实体:

// 3m 标高处、0.15m 厚的实体天花板
var solidCeiling = new SolidCeiling(
    Polygon.Rectangle(6, 5),   // 6m × 5m 的房间
    0.15,                       // 厚度 0.15m
    3.0,                        // 标高 3.0m
    material: BuiltInMaterials.Concrete,
    name: "石膏板吊顶"
);

model.AddElement(solidCeiling);

SolidCeiling 实现了 IHasOpenings,可以在天花板上创建开洞(如灯槽、检修口):

// 在天花板上开一个灯槽
var lightOpening = new Opening(
    Polygon.Rectangle(0.6, 1.2),
    depthFront: 0.15,
    depthBack: 0.0,
    transform: new Transform(2, 2, 0),
    name: "灯槽"
);

solidCeiling.Openings.Add(lightOpening);
model.AddElement(lightOpening);
// SolidCeiling.GetProfile() 会从 Perimeter 中减去所有 Openings

便捷方法 AddOpening 可直接添加:

solidCeiling.AddOpening(Polygon.Rectangle(0.6, 0.6));

7.6.3 OpenCeiling:无几何天花板

OpenCeiling 不生成任何几何体——它仅记录一个边界和标高,用于表示”此处有天花板空间但不渲染实体”。例如,开放式吊顶区域、待定区域等。

var openCeiling = new OpenCeiling(
    Polygon.Rectangle(8, 6),
    3.5,    // 标高 3.5m
    name: "开放吊顶区域"
);

model.AddElement(openCeiling);
// Representation.SolidOperations 为空——无可见几何

7.6.4 TiledCeiling:拼块天花板

TiledCeiling 是最复杂的天花板类型,通过内部 Grid2d 将天花板区域划分为规则排列的格子:

var tiledCeiling = new TiledCeiling(
    Polygon.Rectangle(12, 9),   // 12m × 9m 的房间
    3.0,                          // 标高 3.0m
    tileWidth: 0.6,               // 每块 0.6m 宽
    tileLength: 1.2,              // 每块 1.2m 长
    spaceBetween: 0.01,           // 块间缝隙 1cm
    gridOrientation: null,        // null = 自动对齐边界
    name: "矿棉板吊顶"
);

model.AddElement(tiledCeiling);

内部工作原理:

TiledCeiling.UpdateRepresentations()
  → GetTiles() 通过 Grid2d 生成格子列表
  → 每个格子的边界被多边形修剪(Polygon.Intersection)
  → 每个修剪后的格子创建为一个 Lamina(薄片)
  → 所有 Lamina 添加到 Representation.SolidOperations

TiledCeiling 提供以下查询方法:

var tiles = tiledCeiling.GetTiles();          // 所有拼块多边形列表
var grid = tiledCeiling.GetGrid();            // 底层 Grid2d
int uCount = tiledCeiling.GetCountOfUCells();  // U 方向的格子数
int vCount = tiledCeiling.GetCountOfVCells();  // V 方向的格子数
var tileCells = tiledCeiling.GetTileCells();  // 作为 Grid2d 列表的格子单元

gridOrientation 参数允许旋转格子排布方向:

// 旋转 45 度的拼块天花板
var rotatedCeiling = new TiledCeiling(
    Polygon.Rectangle(12, 9),
    3.0,
    0.6, 1.2, 0.01,
    gridOrientation: new Transform(Vector3.Origin, new Vector3(1, 1, 0), Vector3.ZAxis),
    name: "斜拼吊顶"
);

7.7 综合示例

下面的示例创建一个完整的楼层平面——包含四面墙、一个楼板、空间定义、天花板,以及墙上的一扇门洞:

using Elements;
using Elements.Geometry;
using Elements.Geometry.Solids;

var model = new Model();

// ===== 1. 楼板 =====
var floorBoundary = Polygon.Rectangle(8, 6);
var floor = new Floor(floorBoundary, 0.2, name: "首层楼板");

// ===== 2. 墙体 =====
var wallProfile = new Profile(Polygon.Rectangle(0.2, 3.0));

var walls = new[]
{
    new Wall(new Line(new Vector3(0, 0, 0), new Vector3(8, 0, 0)), wallProfile, 3.0) { Name = "南墙" },
    new Wall(new Line(new Vector3(8, 0, 0), new Vector3(8, 6, 0)), wallProfile, 3.0) { Name = "东墙" },
    new Wall(new Line(new Vector3(8, 6, 0), new Vector3(0, 6, 0)), wallProfile, 3.0) { Name = "北墙" },
    new Wall(new Line(new Vector3(0, 6, 0), new Vector3(0, 0, 0)), wallProfile, 3.0) { Name = "西墙" },
};

// ===== 3. 在南墙上创建门洞 =====
var doorOpening = new Opening(
    Polygon.Rectangle(1.0, 2.2),    // 1.0m 宽 × 2.2m 高
    depthFront: 0.15,
    depthBack: 0.15,
    transform: new Transform(3.5, -0.15, 0), // 离地 0,居中偏右
    name: "入口门"
);
walls[0].Openings.Add(doorOpening);

// ===== 4. 空间定义 =====
var roomSpace = new Space(
    new Profile(new Polygon(new[]
    {
        new Vector3(0.2, 0.2, 0),
        new Vector3(7.8, 0.2, 0),
        new Vector3(7.8, 5.8, 0),
        new Vector3(0.2, 5.8, 0),
    })),
    2.8,  // 净高 2.8m
    name: "主房间"
);

// ===== 5. 天花板 =====
var ceiling = new SolidCeiling(
    Polygon.Rectangle(7.6, 5.6),
    0.12,   // 12cm 厚
    2.8,    // 标高 2.8m(与空间顶齐平)
    transform: new Transform(0.2, 0.2, 0),
    name: "石膏板吊顶"
);

// 在天花板上开一个灯槽
ceiling.AddOpening(
    Polygon.Rectangle(0.6, 1.2).TransformedPolygon(new Transform(3.5, 2.5, 0))
);

// ===== 6. 添加所有元素到模型 =====
model.AddElements(new Element[]
{
    floor,
    walls[0], walls[1], walls[2], walls[3],
    doorOpening,
    roomSpace,
    ceiling,
});

// ===== 7. 统计信息 =====
Console.WriteLine($"房间面积: {roomSpace.Area():F1} m²");
Console.WriteLine($"房间容积: {roomSpace.Volume():F1} m³");
Console.WriteLine($"模型元素数: {model.Elements.Count}");

// ===== 8. 导出 =====
model.ToGlTF("floor_plan.glb");

运行上述代码后,floor_plan.glb 中包含:

  • 一个 L 形的实体楼板
  • 四面 3 米高的墙,南墙带门洞
  • 一个半透明的空间体积(标识房间范围)
  • 一个实体天花板(标高 2.8m,带灯槽开口)

7.8 小结

本章覆盖了六种与空间和场地相关的元素类型:

  • Space:用 Profile + Height 定义可占用区域,提供 Area()Volume() 方法
  • Opening:创建墙体/楼板/天花板上的贯通开洞,通过 IHasOpenings 接口与宿主元素关联,IsVoid=true 的 Extrude 实现挖空
  • Topography:基于高程点阵的三角网地形,支持 Trim、CutAndFill、Tunnel 等场地工程操作
  • Mass:早期体量推敲工具,与 Space 结构相似但语义不同
  • GridLine:建筑轴网系统,支持直线和折线轴线,带圆圈标注和延伸段
  • Ceiling:四种天花板类型——SolidCeiling(实体)、OpenCeiling(仅边界)、TiledCeiling(Grid2d 拼块),均从 Floor 标高向上偏移

下一章将深入 Elements 几何内核的核心机制——CSG 布尔运算与实体操作。


← 上一章 目录 下一章 →