znlgis 博客

GIS开发与技术分享

第十四章:设备与模板排布系统

14.1 设备系统概述

14.1.1 场布设备的概念

在建筑工程场地布置中,施工设备的合理布置是确保施工安全和效率的关键因素。FY_Layout提供了完整的设备元素系统(LayoutEquipment),用于管理和布置各类施工设备,如塔吊、升降机、搅拌站等。

14.1.2 设备元素类型定义

在LayoutElementType.cs中,设备元素的类型定义如下:

public static ElementType LayoutEquipment = new ElementType
{
    Guid = Guid.ParseExact("{552E316C-ADB2-43A7-AC77-9E0069ACEDC8}", "B").ToLcGuid(),
    Name = "LayoutEquipment",
    DispalyName = "场布设备",
    ClassType = typeof(QdLayoutEquipment)
};

14.1.3 设备系统的核心特点

  • 参数化设计:设备的尺寸、旋转角度、安装位置等均可参数化调整
  • 类型丰富:支持各类常见施工设备的定义和布置
  • 三维可视化:设备在三维视图中有对应的立体展示
  • 碰撞检测:可与其他场布元素进行空间冲突检查

14.2 QdLayoutEquipment类详解

14.2.1 类结构

public class QdLayoutEquipment : DirectComponent
{
    // 设备类型名称
    public string EquipmentName
    {
        get { return Properties.GetValue<string>("EquipmentName"); }
        set { SetProps((GetPropId(nameof(EquipmentName)), value)); }
    }

    // 底部高程
    public double Bottom
    {
        get { return Properties.GetValue<double>("Bottom"); }
        set { SetProps((GetPropId(nameof(Bottom)), value)); }
    }

    // 材质信息
    public MaterialInfo Material
    {
        get { return Properties.GetValue<MaterialInfo>("Material"); }
        set { SetProps((GetPropId(nameof(Material)), value)); }
    }

    // 设备轮廓
    public Polyline2d Outline
    {
        get { return this.BaseCurve as Polyline2d; }
        set { this.BaseCurve = value; }
    }

    // 旋转角度
    public double Rotation
    {
        get { return Properties.GetValue<double>("Rotation"); }
        set { SetProps((GetPropId(nameof(Rotation)), value)); }
    }

    public QdLayoutEquipment(LcComponentDefinition def) : base(def)
    {
        Type = LayoutElementType.LayoutEquipment;
    }

    public override Box2 GetBoundingBox()
    {
        return new Box2().ExpandByPoints(
            GetShapes()[0].Curve2ds
                .SelectMany(n => n.GetPoints()).ToArray());
    }

    public override LcElement Clone()
    {
        var clone = new QdLayoutEquipment(this.Definition);
        clone.Copy(this);
        return clone;
    }

    public override void Copy(LcElement src)
    {
        base.Copy(src);
        var equip = (QdLayoutEquipment)src;
    }
}

14.2.2 设备属性体系

设备元素支持以下核心属性:

属性名 类型 说明 默认值
EquipmentName string 设备名称 ””
Bottom double 底部高程(mm) 0
Material MaterialInfo 设备材质 Metal1
Rotation double 旋转角度(弧度) 0
Outline Polyline2d 设备轮廓 空多段线

14.3 模板排布系统

14.3.1 TemplateArrange功能概述

TemplateArrange是FY_Layout中的模板排布模块,位于QdLayout/TemplateArrange/目录下。该模块实现了基于用地红线的自动排布功能,可以根据预定义的模板,在指定的区域内自动排列场布元素。

14.3.2 核心类:TemComAttriAction

public class TemComAttriAction : DirectComponentAction
{
    public TemComAttriAction() { }

    public TemComAttriAction(IDocumentEditor docEditor) : base(docEditor)
    {
        commandCtrl.WriteInfo("命令:模板排布");
    }

    // 执行模板排布
    public async void ExecCreate(string[] args = null)
    {
        // 1. 选择用地红线
        var elementInputer = new ElementSetInputer(this.docEditor);
        var result = await elementInputer.Execute("请选择用地红线:");
        if (elementInputer.isCancelled || result == null)
        {
            this.Cancel();
            return;
        }

        // 2. 获取红线区域
        if (result.ValueX != null)
        {
            var eles = result.ValueX as List<LcElement>;
            // 解析红线元素,获取排布区域
            ProcessRedLines(eles);
        }
    }

    // 处理红线元素
    private void ProcessRedLines(List<LcElement> elements)
    {
        // 提取红线轮廓
        // 计算可排布区域
        // 执行自动排布算法
    }
}

14.3.3 命令注册

模板排布的命令在LayoutCmds.cs中注册:

[CommandMethod(Name = "SelRedLinesForArrange", ShortCuts = "SRFA")]
public CommandResult SelRedLinesForArrange(
    IDocumentEditor docEditor, string[] args)
{
    TemComAttriAction tcaRt = new TemComAttriAction(docEditor);
    tcaRt.ExecCreate(args);
    return CommandResult.Succ();
}

14.4 绘制与调整系统(DrawOrAdjust)

14.4.1 DrawOrAdjustAction概述

FY_Layout提供了DrawOrAdjustAction类,用于在场布设计中进行元素的绘制或位置调整操作:

[CommandMethod(Name = "DrawOrAdjust", ShortCuts = "DRAD")]
public CommandResult DrawOrAdjust(
    IDocumentEditor docEditor, string[] args)
{
    DrawOrAdjustAction drad = new DrawOrAdjustAction(docEditor);
    drad.ExecCreate(args);
    return CommandResult.Succ();
}

14.4.2 DrawOrAdjustAction类

public class DrawOrAdjustAction : DirectComponentAction
{
    public DrawOrAdjustAction() { }

    public DrawOrAdjustAction(IDocumentEditor docEditor) : base(docEditor)
    {
        commandCtrl.WriteInfo("命令:绘制或调整");
    }

    public async void ExecCreate(string[] args = null)
    {
        // 1. 提示用户选择操作模式
        // 2. 如果选择绘制,进入绘制流程
        // 3. 如果选择调整,进入调整流程
        //    - 选择已有元素
        //    - 修改位置/尺寸/属性
        //    - 更新显示
    }
}

14.5 开门边线系统(OpenLine)

14.5.1 QdOpenLine元素

开门边线(OpenLine)用于标记围墙或围挡的出入口位置:

public static ElementType OpenLine = new ElementType
{
    Guid = Guid.ParseExact("{6FE950F0-9E13-FA8A-E216-AAE0D40BECBC}", "B").ToLcGuid(),
    Name = "OpenLine",
    DispalyName = "开门边线",
    ClassType = typeof(QdOpenLine)
};

14.5.2 OpenLineAction操作类

public class OpenLineAction : DirectComponentAction
{
    public OpenLineAction() { }

    public OpenLineAction(IDocumentEditor docEditor) : base(docEditor)
    {
        commandCtrl.WriteInfo("命令:OpenOuterLine");
    }

    // 创建开门边线
    public async void ExecCreateOpenLine(string[] args = null)
    {
        // 1. 获取用户指定的起点和终点
        // 2. 在围墙或围挡上创建开口标记
        // 3. 设置开口宽度和方向
    }
}

14.5.3 命令注册

[CommandMethod(Name = "OpenOuterLine", ShortCuts = "OPL")]
public CommandResult OpenOuterLine(
    IDocumentEditor docEditor, string[] args)
{
    var tcaRt = new OpenLineAction(docEditor);
    tcaRt.ExecCreateOpenLine(args);
    return CommandResult.Succ();
}

14.6 设备布置实战流程

14.6.1 典型的设备布置工作流

  1. 确定场地范围:使用Site命令绘制场地边界
  2. 绘制用地红线:使用PropertyLine命令标注用地范围
  3. 布置主体设施:使用PlanBuild命令绘制拟建建筑
  4. 布置施工道路:使用Road/Berm命令规划道路网络
  5. 布置施工设备:在合适位置放置设备元素
  6. 自动排布优化:使用SelRedLinesForArrange命令进行自动排布
  7. 调整和优化:使用DrawOrAdjust命令微调元素位置

14.6.2 设备间距规范

在施工场地布置中,设备的间距需要满足安全规范:

设备类型 最小间距(m) 安全距离(m) 说明
塔吊 2.0 5.0 吊臂旋转半径外
升降机 1.5 3.0 围护结构外
搅拌站 3.0 5.0 操作空间需求
配电箱 1.0 2.0 安全操作距离

14.6.3 设备与其他元素的关系

设备元素与场布中其他元素的关系:

设备布置关系图:
┌──────────────────────────────────────┐
│ 场地 (Site)                          │
│  ┌────────────────────────────────┐  │
│  │ 用地红线 (PropertyLine)        │  │
│  │  ┌──────┐    ┌──────┐         │  │
│  │  │拟建建筑│    │ 基坑  │         │  │
│  │  │PlanBld│    │FndPit│         │  │
│  │  └──────┘    └──────┘         │  │
│  │       ↕ 道路 (Road)            │  │
│  │  ┌──────┐    ┌──────┐         │  │
│  │  │ 塔吊  │    │板房区 │         │  │
│  │  │Equip │    │Plate │         │  │
│  │  └──────┘    └──────┘         │  │
│  │  ── 围墙 (Fence) ──           │  │
│  └────────────────────────────────┘  │
└──────────────────────────────────────┘

14.7 属性面板与参数编辑

14.7.1 设备属性面板

设备元素的属性通过PropertyObserver暴露到属性面板:

public override List<PropertyObserver> GetPropertyObservers()
{
    return new List<PropertyObserver>()
    {
        new PropertyObserver()
        {
            Name = "EquipmentName",
            DisplayName = "设备名称",
            CategoryName = "Basic",
            CategoryDisplayName = "基本信息",
            PropType = PropertyType.String,
            Getter = (ele) => (ele as QdLayoutEquipment)
                .Properties.GetValue<string>("EquipmentName"),
            Setter = (ele, value) =>
            {
                var equip = ele as QdLayoutEquipment;
                equip.OnPropertyChangedBefore("EquipmentName",
                    equip.EquipmentName, value);
                equip.Properties.SetValue("EquipmentName",
                    value.ToString());
                equip.OnPropertyChangedAfter("EquipmentName",
                    equip.EquipmentName, value);
            }
        },
        new PropertyObserver()
        {
            Name = "Bottom",
            DisplayName = "底高",
            CategoryName = "Geometry",
            CategoryDisplayName = "几何信息",
            PropType = PropertyType.Double,
            Getter = (ele) => (ele as QdLayoutEquipment)
                .Properties.GetValue<double>("Bottom"),
            Setter = (ele, value) =>
            {
                var equip = ele as QdLayoutEquipment;
                if (!double.TryParse(value.ToString(), out var bottom))
                    return;
                equip.OnPropertyChangedBefore("Bottom",
                    equip.Bottom, bottom);
                equip.Properties.SetValue("Bottom", bottom);
                equip.ResetCache();
                equip.OnPropertyChangedAfter("Bottom",
                    equip.Bottom, bottom);
            }
        },
        new PropertyObserver()
        {
            Name = "Rotation",
            DisplayName = "旋转角度",
            CategoryName = "Geometry",
            CategoryDisplayName = "几何信息",
            PropType = PropertyType.Double,
            Getter = (ele) => (ele as QdLayoutEquipment)
                .Properties.GetValue<double>("Rotation"),
            Setter = (ele, value) =>
            {
                var equip = ele as QdLayoutEquipment;
                if (!double.TryParse(value.ToString(), out var rotation))
                    return;
                equip.OnPropertyChangedBefore("Rotation",
                    equip.Rotation, rotation);
                equip.Properties.SetValue("Rotation", rotation);
                equip.ResetCache();
                equip.OnPropertyChangedAfter("Rotation",
                    equip.Rotation, rotation);
            }
        }
    };
}

14.7.2 属性变更通知机制

FY_Layout的属性变更采用Before/After通知模式:

// 变更前通知 - 用于记录历史状态(撤销/重做)
equip.OnPropertyChangedBefore("PropertyName", oldValue, newValue);

// 执行属性变更
equip.Properties.SetValue("PropertyName", newValue);

// 重置缓存 - 更新几何数据和包围盒
equip.ResetCache();

// 变更后通知 - 用于触发视图更新
equip.OnPropertyChangedAfter("PropertyName", oldValue, newValue);

14.8 UI工具栏中的设备按钮

14.8.1 LayoutPlugin中的设备按钮注册

在LayoutPlugin.cs中,设备和模板相关按钮被注册到场布工具栏:

public static TabItem LayoutItem = new TabItem
{
    Name = "LayoutMajor",
    Text = "场布",
    ShortCut = "",
    Children = new TabButtonGroup[]
    {
        // ... 其他按钮组 ...
        new TabButtonGroup
        {
            Name = "设备",
            Children = new TabButton[]
            {
                new TabButton
                {
                    Name = "场布设备",
                    CommandName = "LayoutEquipment",
                    Image = Resources.equipment_icon,
                    ToolTip = "放置施工设备"
                }
            }
        },
        new TabButtonGroup
        {
            Name = "排布",
            Children = new TabButton[]
            {
                new TabButton
                {
                    Name = "模板排布",
                    CommandName = "SelRedLinesForArrange",
                    Image = Resources.arrange_icon,
                    ToolTip = "基于红线自动排布"
                },
                new TabButton
                {
                    Name = "绘制调整",
                    CommandName = "DrawOrAdjust",
                    Image = Resources.adjust_icon,
                    ToolTip = "绘制或调整元素位置"
                }
            }
        }
    }
};

14.9 扩展开发:自定义设备类型

14.9.1 创建塔吊设备示例

// 1. 定义塔吊元素类
public class QdTowerCrane : QdLayoutEquipment
{
    // 吊臂长度
    public double ArmLength
    {
        get { return Properties.GetValue<double>("ArmLength"); }
        set { SetProps((GetPropId(nameof(ArmLength)), value)); }
    }

    // 吊臂高度
    public double ArmHeight
    {
        get { return Properties.GetValue<double>("ArmHeight"); }
        set { SetProps((GetPropId(nameof(ArmHeight)), value)); }
    }

    // 额定起重量
    public double MaxLoad
    {
        get { return Properties.GetValue<double>("MaxLoad"); }
        set { SetProps((GetPropId(nameof(MaxLoad)), value)); }
    }

    public QdTowerCrane(LcComponentDefinition def) : base(def)
    {
        EquipmentName = "塔吊";
        ArmLength = 50000; // 50m
        ArmHeight = 80000; // 80m
        MaxLoad = 8000;    // 8t
    }
}

// 2. 实现塔吊操作类
public class TowerCraneAction : DirectComponentAction
{
    public TowerCraneAction() { }
    public TowerCraneAction(IDocumentEditor docEditor) : base(docEditor)
    {
        commandCtrl.WriteInfo("命令:放置塔吊");
    }

    public async void ExecCreate(string[] args = null)
    {
        // 1. 获取放置点
        var pointInputer = new PointInputer(docEditor);
        var result = await pointInputer.Execute("指定塔吊中心位置:");
        if (pointInputer.isCancelled || result == null)
        {
            this.Cancel();
            return;
        }

        // 2. 创建塔吊元素
        var center = result.Value;
        CreateTowerCrane(center);
    }

    private void CreateTowerCrane(Vector2 center)
    {
        var doc = docRt.Document;
        var def = docRt.GetUseComDef(
            $"{NamespaceKey}.施工设备", "塔吊", null);
        var crane = new QdTowerCrane(def);
        crane.Initilize(doc);

        // 创建塔吊基座轮廓(正方形)
        var baseSize = 3000; // 3m基座
        var outline = new Polyline2d();
        outline.Curve2ds.Add(new Line2d(
            new Vector2(center.X - baseSize/2, center.Y - baseSize/2),
            new Vector2(center.X + baseSize/2, center.Y - baseSize/2)));
        outline.Curve2ds.Add(new Line2d(
            new Vector2(center.X + baseSize/2, center.Y - baseSize/2),
            new Vector2(center.X + baseSize/2, center.Y + baseSize/2)));
        outline.Curve2ds.Add(new Line2d(
            new Vector2(center.X + baseSize/2, center.Y + baseSize/2),
            new Vector2(center.X - baseSize/2, center.Y + baseSize/2)));
        outline.Curve2ds.Add(new Line2d(
            new Vector2(center.X - baseSize/2, center.Y + baseSize/2),
            new Vector2(center.X - baseSize/2, center.Y - baseSize/2)));

        crane.Outline = outline;
        crane.ResetBoundingBox();
        crane.Layer = GetLayer().Name;
        crane.Material = MaterialManager.GetMaterial(
            MaterialManager.Metal1Uuid);
        vportRt.ActiveElementSet.InsertElement(crane);
        docRt.Action.ClearSelects();
    }

    private LcLayer GetLayer()
    {
        var layer = docRt.Document.Layers
            .FirstOrDefault(n => n.Name == "Layout_Equipment");
        if (layer == null)
        {
            layer = docRt.Document.CreateObject<LcLayer>();
            layer.Name = "Layout_Equipment";
            layer.Color = 0xFF6600;
            layer.SetLineType(new LcLineType("ByLayer"));
            layer.Transparency = 0;
            docRt.Document.Layers.Add(layer);
        }
        return layer;
    }
}

// 3. 实现塔吊三维显示
public class TowerCrane3dAction : IElement3dAction
{
    public Object3D Get3dObject(LcElement element, DocumentRuntime docRt)
    {
        var crane = element as QdTowerCrane;
        var group = new Group();

        // 塔身(圆柱体)
        var bodyGeometry = new CylinderGeometry(
            500, 500, crane.ArmHeight, 8);
        var bodyMaterial = new MeshPhongMaterial
        {
            Color = new Color(0xFF6600)
        };
        var body = new Mesh(bodyGeometry, bodyMaterial);
        body.Position.Set(0, 0, crane.ArmHeight / 2);
        group.Add(body);

        // 吊臂(长方体)
        var armGeometry = new BoxGeometry(
            crane.ArmLength, 500, 500);
        var armMaterial = new MeshPhongMaterial
        {
            Color = new Color(0xFFCC00)
        };
        var arm = new Mesh(armGeometry, armMaterial);
        arm.Position.Set(0, 0, crane.ArmHeight);
        group.Add(arm);

        return group;
    }
}

14.10 完整命令汇总

14.10.1 设备与模板系统命令表

命令名 快捷键 功能说明 Action类
OpenOuterLine OPL 开门边线 OpenLineAction
SelRedLinesForArrange SRFA 模板排布 TemComAttriAction
DrawOrAdjust DRAD 绘制或调整 DrawOrAdjustAction

14.10.2 LayoutPlugin.cs中的完整按钮组注册

// LayoutPlugin.cs - 完整的TabItem按钮组结构
public static TabItem LayoutItem = new TabItem
{
    Name = "LayoutMajor",
    Text = "场布",
    ShortCut = "",
    Children = new TabButtonGroup[]
    {
        // 第一组:基础元素
        new TabButtonGroup { Name = "基础", Children = new TabButton[] {
            GetTabButton("场地", "Site"),
            GetTabButton("用地红线", "PropertyLine"),
            GetTabButton("拟建建筑", "PlanBuild"),
        }},
        // 第二组:绿化设施
        new TabButtonGroup { Name = "绿化", Children = new TabButton[] {
            GetTabButton("草坪", "Lawn"),
        }},
        // 第三组:道路工程
        new TabButtonGroup { Name = "道路", Children = new TabButton[] {
            GetTabButton("道路", "Road"),
            GetTabButton("出土道路", "Berm"),
            GetTabButton("路面硬化", "Harden"),
            GetTabButton("硬化地面", "Ground"),
        }},
        // 第四组:坑槽工程
        new TabButtonGroup { Name = "坑槽", Children = new TabButton[] {
            GetTabButton("基坑", "FoundationPit"),
            GetTabButton("土方回填", "Earthwork"),
        }},
        // 第五组:围护设施
        new TabButtonGroup { Name = "围护", Children = new TabButton[] {
            GetTabButton("围墙", "Fence"),
            GetTabButton("防护栏杆", "Barrier"),
            GetTabButton("开门边线", "OpenOuterLine"),
        }},
        // 第六组:临建设施
        new TabButtonGroup { Name = "临建", Children = new TabButton[] {
            GetTabButton("板房", "PlateBuilding"),
            GetTabButton("板房楼栋", "PlateUBuild"),
            GetTabButton("楼栋设置", "SetBuildGroup"),
        }},
        // 第七组:排布工具
        new TabButtonGroup { Name = "排布", Children = new TabButton[] {
            GetTabButton("模板排布", "SelRedLinesForArrange"),
            GetTabButton("绘制调整", "DrawOrAdjust"),
        }},
    }
};

14.11 本章小结

本章详细介绍了FY_Layout中的设备与模板排布系统:

  1. 设备元素(LayoutEquipment):提供参数化的施工设备放置功能,支持各类设备类型的定义和管理
  2. 模板排布(TemplateArrange):基于用地红线的自动排布功能,实现场布元素的智能布局
  3. 绘制调整(DrawOrAdjust):灵活的元素绘制和位置调整功能
  4. 开门边线(OpenLine):围墙出入口的标记功能
  5. 属性面板:通过PropertyObserver机制实现属性的可视化编辑
  6. 扩展开发:通过继承现有类型,可以方便地创建自定义设备类型(如塔吊、升降机等)

设备和模板系统是场布设计从手动布局向智能化布局发展的关键组件,掌握这些功能的开发模式,对于构建专业化的场布设计工具具有重要价值。


上一章:道路与交叉口系统详解 下一章:文件格式与数据交换