板房系统开发详解

第七章:板房系统开发详解

7.1 板房系统概述

7.1.1 功能介绍

板房系统是FY_Layout中最复杂的功能模块,用于在施工场地布置临时板房建筑。主要功能包括:

  • 板房楼栋的创建和布置
  • 单间板房的配置
  • 楼层管理
  • 房间功能设置(宿舍、办公室、会议室等)
  • 人员配置
  • 三维模型生成

7.1.2 核心类结构

PlateHouse/
├── PlateBuilding.cs          # 单间板房类
├── PlateBuildGroup.cs        # 板房楼栋类
├── PlateBuildingFloor.cs     # 楼层类
├── PlateRoom.cs              # 房间类
├── PlateK.cs                 # 板房单元格
├── PlatePassageway.cs        # 走廊类
├── StairsCell.cs             # 楼梯单元
├── GridCell.cs               # 网格单元
├── PlateBuildingAction.cs    # 板房操作类
├── PlateBuildGroupAction.cs  # 楼栋操作类
├── PlateBuild3dAction.cs     # 三维渲染类
├── PlateSet.cs               # 板房设置窗口
├── PlateGroupSet.cs          # 楼栋设置窗口
├── PlateRoomConfigManager.cs # 房间配置管理器
└── RoomConfigControl.cs      # 房间配置控件

7.2 板房数据模型

7.2.1 PlateBuilding - 单间板房

public class PlateBuilding : DirectComponent
{
    /// <summary>
    /// 板房位置
    /// </summary>
    public Vector2 Position { get; set; }
    
    /// <summary>
    /// 板房宽度
    /// </summary>
    public double Width
    {
        get => Properties.GetValue<double>("Width");
        set => SetProps((GetPropId(nameof(Width)), value));
    }
    
    /// <summary>
    /// 板房深度(长度)
    /// </summary>
    public double Depth
    {
        get => Properties.GetValue<double>("Depth");
        set => SetProps((GetPropId(nameof(Depth)), value));
    }
    
    /// <summary>
    /// 板房高度
    /// </summary>
    public double Height
    {
        get => Properties.GetValue<double>("Height");
        set => SetProps((GetPropId(nameof(Height)), value));
    }
    
    /// <summary>
    /// 旋转角度
    /// </summary>
    public double Rotation
    {
        get => Properties.GetValue<double>("Rotation");
        set => SetProps((GetPropId(nameof(Rotation)), value));
    }
    
    /// <summary>
    /// 所属楼栋
    /// </summary>
    public PlateBuildGroup ParentGroup { get; set; }
    
    /// <summary>
    /// 所在楼层
    /// </summary>
    public int FloorIndex { get; set; }
    
    /// <summary>
    /// 房间类型
    /// </summary>
    public RoomType RoomType { get; set; }
    
    public PlateBuilding()
    {
        Type = LayoutElementType.PlateBuilding;
        Width = 6000;   // 默认6米
        Depth = 3000;   // 默认3米
        Height = 2800;  // 默认2.8米
    }
    
    /// <summary>
    /// 获取板房轮廓
    /// </summary>
    public override Curve2dGroupCollection GetShapes()
    {
        var shapes = new Curve2dGroupCollection();
        var group = new Curve2dGroup();
        
        // 计算四个角点
        var halfW = Width / 2;
        var halfD = Depth / 2;
        
        var p1 = new Vector2(-halfW, -halfD);
        var p2 = new Vector2(halfW, -halfD);
        var p3 = new Vector2(halfW, halfD);
        var p4 = new Vector2(-halfW, halfD);
        
        // 应用旋转
        var rotMatrix = new Matrix3().MakeRotation(Rotation);
        p1.ApplyMatrix3(rotMatrix);
        p2.ApplyMatrix3(rotMatrix);
        p3.ApplyMatrix3(rotMatrix);
        p4.ApplyMatrix3(rotMatrix);
        
        // 平移到位置
        p1.Add(Position);
        p2.Add(Position);
        p3.Add(Position);
        p4.Add(Position);
        
        // 创建轮廓
        group.Curve2ds.Add(new Line2d(p1, p2));
        group.Curve2ds.Add(new Line2d(p2, p3));
        group.Curve2ds.Add(new Line2d(p3, p4));
        group.Curve2ds.Add(new Line2d(p4, p1));
        
        shapes.Add(group);
        return shapes;
    }
}

public enum RoomType
{
    Dormitory,      // 宿舍
    Office,         // 办公室
    MeetingRoom,    // 会议室
    Canteen,        // 食堂
    Bathroom,       // 卫生间
    Storage,        // 仓库
    Guard,          // 门卫室
    Other           // 其他
}

7.2.2 PlateBuildGroup - 板房楼栋

public class PlateBuildGroup : DirectComponent
{
    /// <summary>
    /// 楼栋位置
    /// </summary>
    public Vector2 Position { get; set; }
    
    /// <summary>
    /// 旋转角度
    /// </summary>
    public double Rotation { get; set; }
    
    /// <summary>
    /// 楼层数
    /// </summary>
    public int FloorCount
    {
        get => Properties.GetValue<int>("FloorCount");
        set => SetProps((GetPropId(nameof(FloorCount)), value));
    }
    
    /// <summary>
    /// 每层房间数(X方向)
    /// </summary>
    public int RoomsPerFloorX
    {
        get => Properties.GetValue<int>("RoomsPerFloorX");
        set => SetProps((GetPropId(nameof(RoomsPerFloorX)), value));
    }
    
    /// <summary>
    /// 每层房间数(Y方向)
    /// </summary>
    public int RoomsPerFloorY
    {
        get => Properties.GetValue<int>("RoomsPerFloorY");
        set => SetProps((GetPropId(nameof(RoomsPerFloorY)), value));
    }
    
    /// <summary>
    /// 单间宽度
    /// </summary>
    public double RoomWidth
    {
        get => Properties.GetValue<double>("RoomWidth");
        set => SetProps((GetPropId(nameof(RoomWidth)), value));
    }
    
    /// <summary>
    /// 单间深度
    /// </summary>
    public double RoomDepth
    {
        get => Properties.GetValue<double>("RoomDepth");
        set => SetProps((GetPropId(nameof(RoomDepth)), value));
    }
    
    /// <summary>
    /// 层高
    /// </summary>
    public double FloorHeight
    {
        get => Properties.GetValue<double>("FloorHeight");
        set => SetProps((GetPropId(nameof(FloorHeight)), value));
    }
    
    /// <summary>
    /// 走廊宽度
    /// </summary>
    public double CorridorWidth
    {
        get => Properties.GetValue<double>("CorridorWidth");
        set => SetProps((GetPropId(nameof(CorridorWidth)), value));
    }
    
    /// <summary>
    /// 楼层列表
    /// </summary>
    public List<PlateBuildingFloor> Floors { get; set; } = new List<PlateBuildingFloor>();
    
    /// <summary>
    /// 楼栋名称
    /// </summary>
    public string BuildingName { get; set; }
    
    public PlateBuildGroup()
    {
        Type = LayoutElementType.PlateBuildGroup;
        FloorCount = 2;
        RoomsPerFloorX = 5;
        RoomsPerFloorY = 2;
        RoomWidth = 6000;
        RoomDepth = 3000;
        FloorHeight = 2800;
        CorridorWidth = 1500;
    }
    
    /// <summary>
    /// 生成楼层和房间
    /// </summary>
    public void GenerateFloors()
    {
        Floors.Clear();
        
        for (int f = 0; f < FloorCount; f++)
        {
            var floor = new PlateBuildingFloor
            {
                FloorIndex = f,
                Elevation = f * FloorHeight,
                Rooms = new List<PlateRoom>()
            };
            
            // 生成房间
            for (int x = 0; x < RoomsPerFloorX; x++)
            {
                for (int y = 0; y < RoomsPerFloorY; y++)
                {
                    var room = new PlateRoom
                    {
                        GridX = x,
                        GridY = y,
                        Width = RoomWidth,
                        Depth = RoomDepth,
                        RoomType = RoomType.Dormitory
                    };
                    floor.Rooms.Add(room);
                }
            }
            
            Floors.Add(floor);
        }
    }
    
    /// <summary>
    /// 计算楼栋总尺寸
    /// </summary>
    public (double width, double depth, double height) GetTotalSize()
    {
        double width = RoomsPerFloorX * RoomWidth;
        double depth = RoomsPerFloorY * RoomDepth + CorridorWidth;
        double height = FloorCount * FloorHeight;
        return (width, depth, height);
    }
}

7.2.3 PlateBuildingFloor - 楼层

public class PlateBuildingFloor
{
    /// <summary>
    /// 楼层索引(从0开始)
    /// </summary>
    public int FloorIndex { get; set; }
    
    /// <summary>
    /// 楼层标高
    /// </summary>
    public double Elevation { get; set; }
    
    /// <summary>
    /// 房间列表
    /// </summary>
    public List<PlateRoom> Rooms { get; set; } = new List<PlateRoom>();
    
    /// <summary>
    /// 楼梯列表
    /// </summary>
    public List<StairsCell> Stairs { get; set; } = new List<StairsCell>();
    
    /// <summary>
    /// 走廊
    /// </summary>
    public PlatePassageway Corridor { get; set; }
    
    /// <summary>
    /// 获取楼层名称
    /// </summary>
    public string FloorName => FloorIndex == 0 ? "首层" : $"{FloorIndex + 1}层";
    
    /// <summary>
    /// 获取指定位置的房间
    /// </summary>
    public PlateRoom GetRoom(int gridX, int gridY)
    {
        return Rooms.FirstOrDefault(r => r.GridX == gridX && r.GridY == gridY);
    }
}

7.2.4 PlateRoom - 房间

public class PlateRoom
{
    /// <summary>
    /// 网格X坐标
    /// </summary>
    public int GridX { get; set; }
    
    /// <summary>
    /// 网格Y坐标
    /// </summary>
    public int GridY { get; set; }
    
    /// <summary>
    /// 房间宽度
    /// </summary>
    public double Width { get; set; }
    
    /// <summary>
    /// 房间深度
    /// </summary>
    public double Depth { get; set; }
    
    /// <summary>
    /// 房间类型
    /// </summary>
    public RoomType RoomType { get; set; }
    
    /// <summary>
    /// 房间名称
    /// </summary>
    public string RoomName { get; set; }
    
    /// <summary>
    /// 容纳人数
    /// </summary>
    public int Capacity { get; set; }
    
    /// <summary>
    /// 已分配人数
    /// </summary>
    public int AssignedCount { get; set; }
    
    /// <summary>
    /// 门的位置
    /// </summary>
    public DoorPosition DoorPosition { get; set; }
    
    /// <summary>
    /// 窗的位置列表
    /// </summary>
    public List<WindowPosition> Windows { get; set; } = new List<WindowPosition>();
    
    public PlateRoom()
    {
        Width = 6000;
        Depth = 3000;
        RoomType = RoomType.Dormitory;
        Capacity = 4;
    }
    
    /// <summary>
    /// 获取房间面积
    /// </summary>
    public double GetArea()
    {
        return Width * Depth / 1000000; // 转换为平方米
    }
}

public class DoorPosition
{
    public Side Side { get; set; }      // 门所在的边
    public double Offset { get; set; }   // 沿边的偏移
    public double Width { get; set; }    // 门宽
    public double Height { get; set; }   // 门高
}

public class WindowPosition
{
    public Side Side { get; set; }
    public double Offset { get; set; }
    public double Width { get; set; }
    public double Height { get; set; }
    public double Sill { get; set; }     // 窗台高度
}

public enum Side
{
    Front, Back, Left, Right
}

7.3 板房操作类

7.3.1 PlateBuildingAction

public class PlateBuildingAction : DirectComponentAction
{
    public PlateBuildingAction() { }
    
    public PlateBuildingAction(IDocumentEditor docEditor) : base(docEditor)
    {
        commandCtrl.WriteInfo("命令:PlateBuilding");
    }
    
    /// <summary>
    /// 执行创建
    /// </summary>
    public async void ExecCreate(string[] args = null)
    {
        var pointInputer = new PointInputer(docEditor);
        
        // 获取放置位置
        commandCtrl.WriteInfo("指定板房放置位置:");
        var result = await pointInputer.Execute();
        
        if (result.Status != InputStatus.OK)
        {
            commandCtrl.WriteInfo("操作已取消");
            return;
        }
        
        // 显示设置对话框
        var settingForm = new PlateSet();
        if (settingForm.ShowDialog() == DialogResult.OK)
        {
            CreatePlateBuilding(result.Point, settingForm.Settings);
        }
    }
    
    private void CreatePlateBuilding(Vector2 position, PlateBuildingSettings settings)
    {
        var doc = docRt.Document;
        
        var plate = new PlateBuilding
        {
            Position = position,
            Width = settings.Width,
            Depth = settings.Depth,
            Height = settings.Height,
            RoomType = settings.RoomType
        };
        
        plate.Initilize(doc);
        plate.ResetBoundingBox();
        plate.Layer = GetLayer().Name;
        
        vportRt.ActiveElementSet.InsertElement(plate);
        docRt.Action.ClearSelects();
    }
    
    /// <summary>
    /// 绘制板房
    /// </summary>
    public override void Draw(LcCanvas2d canvas, LcElement element, Matrix3 matrix)
    {
        var plate = element as PlateBuilding;
        var pen = GetDrawPen(plate);
        
        // 绘制轮廓
        foreach (var curve in plate.GetShapes()[0].Curve2ds)
        {
            canvas.DrawCurve(pen, curve, matrix);
        }
        
        // 绘制房间类型标注
        var textPaint = new LcTextPaint
        {
            Color = pen.Color,
            FontName = "仿宋",
            Size = 500,
            Position = plate.Position
        };
        canvas.DrawText(textPaint, GetRoomTypeText(plate.RoomType), matrix, out _);
    }
    
    private string GetRoomTypeText(RoomType type)
    {
        return type switch
        {
            RoomType.Dormitory => "宿舍",
            RoomType.Office => "办公室",
            RoomType.MeetingRoom => "会议室",
            RoomType.Canteen => "食堂",
            RoomType.Bathroom => "卫生间",
            RoomType.Storage => "仓库",
            RoomType.Guard => "门卫",
            _ => "其他"
        };
    }
}

7.3.2 PlateBuildGroupAction

public class PlateBuildGroupAction : DirectComponentAction
{
    public PlateBuildGroupAction() { }
    
    public PlateBuildGroupAction(IDocumentEditor docEditor) : base(docEditor)
    {
        commandCtrl.WriteInfo("命令:PlateBuildGroup");
    }
    
    /// <summary>
    /// 创建板房楼栋
    /// </summary>
    public async void ExecCreate(string[] args = null)
    {
        var pointInputer = new PointInputer(docEditor);
        
        // 获取放置位置
        commandCtrl.WriteInfo("指定楼栋放置位置:");
        var result = await pointInputer.Execute();
        
        if (result.Status != InputStatus.OK)
        {
            Cancel();
            return;
        }
        
        // 显示楼栋设置对话框
        var settingForm = new PlateGroupSet();
        if (settingForm.ShowDialog() == DialogResult.OK)
        {
            CreateBuildGroup(result.Point, settingForm.Settings);
        }
    }
    
    private void CreateBuildGroup(Vector2 position, PlateBuildGroupSettings settings)
    {
        var doc = docRt.Document;
        
        var group = new PlateBuildGroup
        {
            Position = position,
            BuildingName = settings.BuildingName,
            FloorCount = settings.FloorCount,
            RoomsPerFloorX = settings.RoomsPerFloorX,
            RoomsPerFloorY = settings.RoomsPerFloorY,
            RoomWidth = settings.RoomWidth,
            RoomDepth = settings.RoomDepth,
            FloorHeight = settings.FloorHeight,
            CorridorWidth = settings.CorridorWidth
        };
        
        group.GenerateFloors();
        group.Initilize(doc);
        group.ResetBoundingBox();
        group.Layer = GetLayer().Name;
        
        vportRt.ActiveElementSet.InsertElement(group);
        docRt.Action.ClearSelects();
        
        commandCtrl.WriteInfo($"已创建楼栋:{settings.BuildingName},共{settings.FloorCount}层,{settings.RoomsPerFloorX * settings.RoomsPerFloorY * settings.FloorCount}个房间");
    }
    
    /// <summary>
    /// 设置楼栋属性
    /// </summary>
    public void SetGroup(string[] args = null)
    {
        var selectedElements = docRt.GetSelectedElements();
        var groups = selectedElements.OfType<PlateBuildGroup>().ToList();
        
        if (groups.Count == 0)
        {
            commandCtrl.WriteError("请先选择板房楼栋");
            return;
        }
        
        var settingForm = new PlateGroupSet(groups[0]);
        if (settingForm.ShowDialog() == DialogResult.OK)
        {
            foreach (var group in groups)
            {
                UpdateGroupSettings(group, settingForm.Settings);
            }
        }
    }
    
    private void UpdateGroupSettings(PlateBuildGroup group, PlateBuildGroupSettings settings)
    {
        group.BuildingName = settings.BuildingName;
        group.FloorCount = settings.FloorCount;
        group.RoomsPerFloorX = settings.RoomsPerFloorX;
        group.RoomsPerFloorY = settings.RoomsPerFloorY;
        group.RoomWidth = settings.RoomWidth;
        group.RoomDepth = settings.RoomDepth;
        group.FloorHeight = settings.FloorHeight;
        group.CorridorWidth = settings.CorridorWidth;
        
        group.GenerateFloors();
        group.ResetCache();
    }
    
    /// <summary>
    /// 绘制楼栋
    /// </summary>
    public override void Draw(LcCanvas2d canvas, LcElement element, Matrix3 matrix)
    {
        var group = element as PlateBuildGroup;
        var pen = GetDrawPen(group);
        
        // 计算楼栋边界
        var (width, depth, _) = group.GetTotalSize();
        var halfW = width / 2;
        var halfD = depth / 2;
        
        // 绘制外边框
        var p1 = group.Position + new Vector2(-halfW, -halfD);
        var p2 = group.Position + new Vector2(halfW, -halfD);
        var p3 = group.Position + new Vector2(halfW, halfD);
        var p4 = group.Position + new Vector2(-halfW, halfD);
        
        canvas.DrawLine(pen, p1.ApplyMatrix3(matrix), p2.ApplyMatrix3(matrix));
        canvas.DrawLine(pen, p2.ApplyMatrix3(matrix), p3.ApplyMatrix3(matrix));
        canvas.DrawLine(pen, p3.ApplyMatrix3(matrix), p4.ApplyMatrix3(matrix));
        canvas.DrawLine(pen, p4.ApplyMatrix3(matrix), p1.ApplyMatrix3(matrix));
        
        // 绘制内部网格(房间分隔)
        DrawRoomGrid(canvas, group, matrix, pen);
        
        // 绘制楼栋名称
        var textPaint = new LcTextPaint
        {
            Color = pen.Color,
            FontName = "仿宋",
            Size = 1000,
            Position = group.Position
        };
        canvas.DrawText(textPaint, group.BuildingName ?? "板房楼栋", matrix, out _);
    }
    
    private void DrawRoomGrid(LcCanvas2d canvas, PlateBuildGroup group, Matrix3 matrix, LcPaint pen)
    {
        var (width, depth, _) = group.GetTotalSize();
        var startX = group.Position.X - width / 2;
        var startY = group.Position.Y - depth / 2;
        
        // 绘制垂直线(X方向分隔)
        for (int x = 1; x < group.RoomsPerFloorX; x++)
        {
            var lineX = startX + x * group.RoomWidth;
            var p1 = new Vector2(lineX, startY);
            var p2 = new Vector2(lineX, startY + depth);
            canvas.DrawLine(pen, p1.ApplyMatrix3(matrix), p2.ApplyMatrix3(matrix));
        }
        
        // 绘制水平线(Y方向分隔)
        for (int y = 1; y <= group.RoomsPerFloorY; y++)
        {
            var lineY = startY + y * group.RoomDepth;
            if (y == group.RoomsPerFloorY)
            {
                // 走廊分隔线
                lineY = startY + group.RoomsPerFloorY * group.RoomDepth;
            }
            var p1 = new Vector2(startX, lineY);
            var p2 = new Vector2(startX + width, lineY);
            canvas.DrawLine(pen, p1.ApplyMatrix3(matrix), p2.ApplyMatrix3(matrix));
        }
    }
}

7.4 房间配置管理

7.4.1 PlateRoomConfigManager

public static class PlateRoomConfigManager
{
    private static Dictionary<RoomType, RoomConfig> Configs = new Dictionary<RoomType, RoomConfig>();
    
    public static void Init()
    {
        // 初始化默认配置
        Configs[RoomType.Dormitory] = new RoomConfig
        {
            Type = RoomType.Dormitory,
            Name = "宿舍",
            DefaultCapacity = 4,
            MinArea = 12,
            RequiredFurniture = new[] { "床", "衣柜", "桌子" }
        };
        
        Configs[RoomType.Office] = new RoomConfig
        {
            Type = RoomType.Office,
            Name = "办公室",
            DefaultCapacity = 2,
            MinArea = 15,
            RequiredFurniture = new[] { "办公桌", "椅子", "文件柜" }
        };
        
        Configs[RoomType.MeetingRoom] = new RoomConfig
        {
            Type = RoomType.MeetingRoom,
            Name = "会议室",
            DefaultCapacity = 10,
            MinArea = 30,
            RequiredFurniture = new[] { "会议桌", "椅子", "投影仪" }
        };
        
        Configs[RoomType.Canteen] = new RoomConfig
        {
            Type = RoomType.Canteen,
            Name = "食堂",
            DefaultCapacity = 50,
            MinArea = 100,
            RequiredFurniture = new[] { "餐桌", "椅子", "厨具" }
        };
        
        Configs[RoomType.Bathroom] = new RoomConfig
        {
            Type = RoomType.Bathroom,
            Name = "卫生间",
            DefaultCapacity = 5,
            MinArea = 10,
            RequiredFurniture = new[] { "便器", "洗手台", "镜子" }
        };
        
        // 加载自定义配置
        LoadCustomConfigs();
    }
    
    public static RoomConfig GetConfig(RoomType type)
    {
        return Configs.TryGetValue(type, out var config) ? config : null;
    }
    
    public static void SetConfig(RoomType type, RoomConfig config)
    {
        Configs[type] = config;
        SaveCustomConfigs();
    }
    
    private static void LoadCustomConfigs()
    {
        var path = GetConfigFilePath();
        if (File.Exists(path))
        {
            var json = File.ReadAllText(path);
            var customConfigs = JsonConvert.DeserializeObject<Dictionary<RoomType, RoomConfig>>(json);
            foreach (var kvp in customConfigs)
            {
                Configs[kvp.Key] = kvp.Value;
            }
        }
    }
    
    private static void SaveCustomConfigs()
    {
        var path = GetConfigFilePath();
        var json = JsonConvert.SerializeObject(Configs, Formatting.Indented);
        File.WriteAllText(path, json);
    }
    
    private static string GetConfigFilePath()
    {
        return Path.Combine(
            Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData),
            "LightCAD", "QdLayout", "room_configs.json"
        );
    }
}

public class RoomConfig
{
    public RoomType Type { get; set; }
    public string Name { get; set; }
    public int DefaultCapacity { get; set; }
    public double MinArea { get; set; }
    public string[] RequiredFurniture { get; set; }
}

7.5 三维模型生成

7.5.1 PlateBuild3dAction

public class PlateBuild3dAction : IElement3dAction
{
    /// <summary>
    /// 生成板房楼栋的三维模型
    /// </summary>
    public Object3D Get3dObject(LcElement element, DocumentRuntime docRt)
    {
        var group = element as PlateBuildGroup;
        var root = new Object3D();
        
        // 获取楼栋尺寸
        var (width, depth, height) = group.GetTotalSize();
        
        // 生成每层
        for (int f = 0; f < group.FloorCount; f++)
        {
            var floorObj = CreateFloor3D(group, f);
            floorObj.Position.Y = f * group.FloorHeight;
            root.Add(floorObj);
        }
        
        // 生成屋顶
        var roofObj = CreateRoof3D(group);
        roofObj.Position.Y = height;
        root.Add(roofObj);
        
        // 生成楼梯
        if (group.FloorCount > 1)
        {
            var stairsObj = CreateStairs3D(group);
            root.Add(stairsObj);
        }
        
        // 设置位置和旋转
        root.Position.X = group.Position.X;
        root.Position.Z = group.Position.Y;
        root.Rotation.Y = group.Rotation;
        
        return root;
    }
    
    private Object3D CreateFloor3D(PlateBuildGroup group, int floorIndex)
    {
        var floor = new Object3D();
        var (width, depth, _) = group.GetTotalSize();
        
        // 创建楼板
        var slabGeometry = new BoxGeometry(width, 100, depth);
        var slabMaterial = new MeshLambertMaterial
        {
            Color = new ThreeJs4Net.Color(0xCCCCCC)
        };
        var slab = new Mesh(slabGeometry, slabMaterial);
        floor.Add(slab);
        
        // 创建房间
        var startX = -width / 2 + group.RoomWidth / 2;
        var startZ = -depth / 2 + group.RoomDepth / 2;
        
        for (int x = 0; x < group.RoomsPerFloorX; x++)
        {
            for (int y = 0; y < group.RoomsPerFloorY; y++)
            {
                var room = CreateRoom3D(group, floorIndex, x, y);
                room.Position.X = startX + x * group.RoomWidth;
                room.Position.Z = startZ + y * group.RoomDepth;
                floor.Add(room);
            }
        }
        
        // 创建走廊
        var corridorObj = CreateCorridor3D(group);
        corridorObj.Position.Z = -depth / 2 + group.RoomsPerFloorY * group.RoomDepth + group.CorridorWidth / 2;
        floor.Add(corridorObj);
        
        return floor;
    }
    
    private Object3D CreateRoom3D(PlateBuildGroup group, int floorIndex, int gridX, int gridY)
    {
        var room = new Object3D();
        var floor = group.Floors[floorIndex];
        var roomData = floor.GetRoom(gridX, gridY);
        
        // 墙体高度
        var wallHeight = group.FloorHeight - 100;  // 减去楼板厚度
        var wallThickness = 100;
        
        // 创建四面墙
        // 前墙
        var frontWall = CreateWall(group.RoomWidth, wallHeight, wallThickness);
        frontWall.Position.Z = group.RoomDepth / 2;
        room.Add(frontWall);
        
        // 后墙
        var backWall = CreateWall(group.RoomWidth, wallHeight, wallThickness);
        backWall.Position.Z = -group.RoomDepth / 2;
        room.Add(backWall);
        
        // 左墙
        var leftWall = CreateWall(wallThickness, wallHeight, group.RoomDepth);
        leftWall.Position.X = -group.RoomWidth / 2;
        room.Add(leftWall);
        
        // 右墙
        var rightWall = CreateWall(wallThickness, wallHeight, group.RoomDepth);
        rightWall.Position.X = group.RoomWidth / 2;
        room.Add(rightWall);
        
        // 添加门洞
        if (roomData?.DoorPosition != null)
        {
            // 在相应的墙上创建门洞
            // 简化实现:使用布尔运算或多个几何体组合
        }
        
        return room;
    }
    
    private Mesh CreateWall(double width, double height, double depth)
    {
        var geometry = new BoxGeometry(width, height, depth);
        var material = new MeshLambertMaterial
        {
            Color = new ThreeJs4Net.Color(0xFFFFFF)
        };
        var mesh = new Mesh(geometry, material);
        mesh.Position.Y = height / 2;
        return mesh;
    }
    
    private Object3D CreateCorridor3D(PlateBuildGroup group)
    {
        var corridor = new Object3D();
        var (width, _, _) = group.GetTotalSize();
        
        // 走廊地面
        var floorGeometry = new BoxGeometry(width, 50, group.CorridorWidth);
        var floorMaterial = new MeshLambertMaterial
        {
            Color = new ThreeJs4Net.Color(0x808080)
        };
        var floorMesh = new Mesh(floorGeometry, floorMaterial);
        corridor.Add(floorMesh);
        
        // 走廊护栏
        var railHeight = 1000;
        var railGeometry = new BoxGeometry(width, railHeight, 50);
        var railMaterial = new MeshLambertMaterial
        {
            Color = new ThreeJs4Net.Color(0x404040)
        };
        var railMesh = new Mesh(railGeometry, railMaterial);
        railMesh.Position.Y = railHeight / 2;
        railMesh.Position.Z = group.CorridorWidth / 2;
        corridor.Add(railMesh);
        
        return corridor;
    }
    
    private Object3D CreateRoof3D(PlateBuildGroup group)
    {
        var roof = new Object3D();
        var (width, depth, _) = group.GetTotalSize();
        
        var roofGeometry = new BoxGeometry(width + 200, 100, depth + 200);
        var roofMaterial = new MeshLambertMaterial
        {
            Color = new ThreeJs4Net.Color(0x404040)
        };
        var roofMesh = new Mesh(roofGeometry, roofMaterial);
        roof.Add(roofMesh);
        
        return roof;
    }
    
    private Object3D CreateStairs3D(PlateBuildGroup group)
    {
        var stairs = new Object3D();
        
        // 简化的楼梯实现
        var stairWidth = 1200;
        var stairDepth = 2400;
        
        for (int f = 0; f < group.FloorCount - 1; f++)
        {
            var stairRun = CreateStairRun(stairWidth, group.FloorHeight, stairDepth);
            stairRun.Position.Y = f * group.FloorHeight;
            stairs.Add(stairRun);
        }
        
        return stairs;
    }
    
    private Object3D CreateStairRun(double width, double height, double depth)
    {
        var stairRun = new Object3D();
        
        int stepCount = 16;
        var stepHeight = height / stepCount;
        var stepDepth = depth / stepCount;
        
        for (int i = 0; i < stepCount; i++)
        {
            var stepGeometry = new BoxGeometry(width, stepHeight, stepDepth);
            var stepMaterial = new MeshLambertMaterial
            {
                Color = new ThreeJs4Net.Color(0x808080)
            };
            var stepMesh = new Mesh(stepGeometry, stepMaterial);
            stepMesh.Position.Y = i * stepHeight + stepHeight / 2;
            stepMesh.Position.Z = i * stepDepth + stepDepth / 2;
            stairRun.Add(stepMesh);
        }
        
        return stairRun;
    }
}

7.6 设置界面

7.6.1 PlateGroupSet窗口

设置楼栋参数的WinForms对话框:

public partial class PlateGroupSet : Form
{
    public PlateBuildGroupSettings Settings { get; private set; }
    
    public PlateGroupSet()
    {
        InitializeComponent();
        Settings = new PlateBuildGroupSettings();
        LoadDefaults();
    }
    
    public PlateGroupSet(PlateBuildGroup existingGroup) : this()
    {
        // 从现有楼栋加载设置
        txtBuildingName.Text = existingGroup.BuildingName;
        numFloorCount.Value = existingGroup.FloorCount;
        numRoomsX.Value = existingGroup.RoomsPerFloorX;
        numRoomsY.Value = existingGroup.RoomsPerFloorY;
        numRoomWidth.Value = (decimal)(existingGroup.RoomWidth / 1000);
        numRoomDepth.Value = (decimal)(existingGroup.RoomDepth / 1000);
        numFloorHeight.Value = (decimal)(existingGroup.FloorHeight / 1000);
        numCorridorWidth.Value = (decimal)(existingGroup.CorridorWidth / 1000);
    }
    
    private void LoadDefaults()
    {
        txtBuildingName.Text = "板房楼栋";
        numFloorCount.Value = 2;
        numRoomsX.Value = 5;
        numRoomsY.Value = 2;
        numRoomWidth.Value = 6;
        numRoomDepth.Value = 3;
        numFloorHeight.Value = 2.8m;
        numCorridorWidth.Value = 1.5m;
    }
    
    private void btnOK_Click(object sender, EventArgs e)
    {
        Settings = new PlateBuildGroupSettings
        {
            BuildingName = txtBuildingName.Text,
            FloorCount = (int)numFloorCount.Value,
            RoomsPerFloorX = (int)numRoomsX.Value,
            RoomsPerFloorY = (int)numRoomsY.Value,
            RoomWidth = (double)numRoomWidth.Value * 1000,
            RoomDepth = (double)numRoomDepth.Value * 1000,
            FloorHeight = (double)numFloorHeight.Value * 1000,
            CorridorWidth = (double)numCorridorWidth.Value * 1000
        };
        
        DialogResult = DialogResult.OK;
        Close();
    }
}

public class PlateBuildGroupSettings
{
    public string BuildingName { get; set; }
    public int FloorCount { get; set; }
    public int RoomsPerFloorX { get; set; }
    public int RoomsPerFloorY { get; set; }
    public double RoomWidth { get; set; }
    public double RoomDepth { get; set; }
    public double FloorHeight { get; set; }
    public double CorridorWidth { get; set; }
}

7.7 本章小结

本章详细介绍了FY_Layout中板房系统的开发:

  1. 数据模型:PlateBuilding、PlateBuildGroup、PlateBuildingFloor、PlateRoom的设计
  2. 操作类:PlateBuildingAction和PlateBuildGroupAction的实现
  3. 房间配置:PlateRoomConfigManager的配置管理
  4. 三维模型:PlateBuild3dAction的三维生成逻辑
  5. 设置界面:PlateGroupSet对话框的实现

板房系统是FY_Layout中最复杂的模块,涉及多层数据结构、参数化设计和三维模型生成。掌握这个模块的开发方法,对于开发其他复杂的BIM组件有很大帮助。

下一章我们将学习二维绘图与交互操作的详细内容。


posted @ 2026-01-31 16:02  我才是银古  阅读(2)  评论(0)    收藏  举报