截面测量架构设计

一、架构设计原则

  1. 数据与视图分离:测量数据模型独立于渲染逻辑
  2. 命令模式:所有交互操作封装为命令,支持撤销/重做
  3. 策略模式:不同测量算法作为可替换策略
  4. 观察者模式:视图间数据同步
  5. 工厂模式:几何元素和测量对象的创建

二、核心架构图

@startuml SectionMeasureArchitecture

skinparam packageStyle rectangle
skinparam shadowing false

package "表现层 Presentation" #LightBlue {
    class View3DWidget {
        - vtkRenderer* renderer3D
        - vtkRenderWindow* renderWindow
        --
        + updateSlicePlane()
        + highlightSliceRegion()
    }

    class View2DSliceWidget {
        - vtkImageViewer2* imageViewer
        - SliceLineInteractor* lineInteractor
        --
        + onLinePositionChanged()
        + updateBoundingBox()
    }

    class View2DMeasureWidget {
        - vtkRenderer* renderer2D
        - InteractionStateMachine* stateMachine
        - GeometryRenderer* geometryRenderer
        --
        + handleMouseEvent()
        + renderGeometries()
        + renderMeasurements()
    }
}

package "控制层 Controller" #LightGreen {
    class SectionMeasureController {
        - SectionDataModel* dataModel
        - CommandManager* commandManager
        --
        + executeCommand(Command*)
        + undo()
        + redo()
        + synchronizeViews()
    }

    class InteractionStateMachine {
        - State currentState
        - GeometryFactory* factory
        --
        + handleEvent(MouseEvent)
        + transitionTo(State)
        + createGeometry()
    }

    class CommandManager {
        - stack<Command*> undoStack
        - stack<Command*> redoStack
        --
        + execute(Command*)
        + undo()
        + redo()
    }
}

package "业务逻辑层 Business Logic" #LightYellow {

    package "几何元素 Geometry" {
        abstract class GeometryElement {
            # string id
            # GeometryType type
            # vector<Point2D> controlPoints
            --
            + {abstract} validate()
            + {abstract} serialize()
            + {abstract} deserialize()
        }

        class Point2D {
            - double x
            - double y
        }

        class Line2D {
            - Point2D startPoint
            - Point2D endPoint
            - double width
            --
            + extractRegion()
        }

        class Circle2D {
            - Point2D center
            - double radius
            - double ringWidth
            --
            + extractRegion()
        }

        class TextAnnotation {
            - string text
            - Point2D position
        }
    }

    package "测量对象 Measurement" {
        abstract class MeasurementElement {
            # string id
            # MeasurementType type
            # GeometryElement* source
            # GeometryElement* target
            # MeasurementStrategy* strategy
            --
            + {abstract} calculate()
            + {abstract} serialize()
        }

        class PointToPointMeasure
        class PointToLineMeasure
        class LineToLineMeasure
        class CircleToLineMeasure
        class PointToCircleMeasure
        class CircleToCircleMeasure
        class AngleMeasure
        class RadiusMeasure
    }

    package "测量策略 Strategy" {
        interface MeasurementStrategy {
            + {abstract} calculate()
        }

        class VerticalDistanceStrategy
        class HorizontalDistanceStrategy
        class NearestDistanceStrategy
        class CenterDistanceStrategy
        class FarthestDistanceStrategy
    }

    package "工厂 Factory" {
        class GeometryFactory {
            + createPoint2D()
            + createLine2D()
            + createCircle2D()
            + createTextAnnotation()
        }

        class MeasurementFactory {
            + createMeasurement(type, source, target, strategy)
        }
    }
}

package "数据层 Data" #LightCoral {
    class SectionDataModel {
        - vector<GeometryElement*> geometries
        - vector<MeasurementElement*> measurements
        - SlicePlaneData slicePlane
        - BoundingBox boundingBox
        --
        + addGeometry(GeometryElement*)
        + removeGeometry(id)
        + addMeasurement(MeasurementElement*)
        + removeMeasurement(id)
        + serialize()
        + deserialize()
    }

    class ObjectTreeAdapter {
        + syncToObjectTree()
        + syncFromObjectTree()
    }

    class DataSerializer {
        + serializeToJson()
        + deserializeFromJson()
        + serializeToXml()
        + deserializeFromXml()
    }
}

package "渲染层 Rendering" #LightGray {
    class GeometryRenderer {
        - map<GeometryType, RenderStrategy*> renderStrategies
        --
        + render(GeometryElement*)
        + highlight(GeometryElement*)
        + updateVisibility(id, visible)
    }

    class MeasurementRenderer {
        - map<MeasurementType, RenderStrategy*> renderStrategies
        --
        + render(MeasurementElement*)
        + updateAnnotation(id, value)
    }

    interface RenderStrategy {
        + {abstract} render(vtkRenderer*, Element*)
    }
}

package "命令模式 Command" #Lavender {
    abstract class Command {
        # SectionDataModel* dataModel
        --
        + {abstract} execute()
        + {abstract} undo()
    }

    class CreateGeometryCommand
    class DeleteGeometryCommand
    class CreateMeasurementCommand
    class DeleteMeasurementCommand
}

package "数据提取层 Extraction" #LightCyan {
    class RegionExtractor {
        + extractPointCloud(region)
        + extractCADMesh(region)
    }

    class PointCloudExtractor
    class CADMeshExtractor
}

' 继承关系
GeometryElement <|-- Point2D
GeometryElement <|-- Line2D
GeometryElement <|-- Circle2D
GeometryElement <|-- TextAnnotation

MeasurementElement <|-- PointToPointMeasure
MeasurementElement <|-- PointToLineMeasure
MeasurementElement <|-- LineToLineMeasure
MeasurementElement <|-- CircleToLineMeasure
MeasurementElement <|-- PointToCircleMeasure
MeasurementElement <|-- CircleToCircleMeasure
MeasurementElement <|-- AngleMeasure
MeasurementElement <|-- RadiusMeasure

MeasurementStrategy <|.. VerticalDistanceStrategy
MeasurementStrategy <|.. HorizontalDistanceStrategy
MeasurementStrategy <|.. NearestDistanceStrategy
MeasurementStrategy <|.. CenterDistanceStrategy
MeasurementStrategy <|.. FarthestDistanceStrategy

Command <|-- CreateGeometryCommand
Command <|-- DeleteGeometryCommand
Command <|-- CreateMeasurementCommand
Command <|-- DeleteMeasurementCommand

' 组合/依赖关系
View3DWidget --> SectionMeasureController
View2DSliceWidget --> SectionMeasureController
View2DMeasureWidget --> SectionMeasureController
View2DMeasureWidget --> InteractionStateMachine

SectionMeasureController --> SectionDataModel
SectionMeasureController --> CommandManager
SectionMeasureController --> GeometryRenderer
SectionMeasureController --> MeasurementRenderer

InteractionStateMachine --> GeometryFactory
CommandManager --> Command

MeasurementElement --> MeasurementStrategy
MeasurementElement --> GeometryElement

SectionDataModel --> GeometryElement
SectionDataModel --> MeasurementElement
SectionDataModel --> ObjectTreeAdapter
SectionDataModel --> DataSerializer

GeometryRenderer --> RenderStrategy
MeasurementRenderer --> RenderStrategy

Line2D --> RegionExtractor
Circle2D --> RegionExtractor
RegionExtractor --> PointCloudExtractor
RegionExtractor --> CADMeshExtractor

@enduml

三、交互状态机设计

@startuml
[*] --> Idle

Idle --> CreatingLine : 选择创建线工具
Idle --> CreatingCircle : 选择创建圆工具
Idle --> CreatingPoint : 选择创建点工具
Idle --> CreatingMeasurement : 选择测量工具

state CreatingLine {
    [*] --> WaitingFirstPoint
    WaitingFirstPoint --> Dragging : 双击
    Dragging --> WaitingSecondPoint : 拖动
    WaitingSecondPoint --> Extracting : 双击
    Extracting --> Completed : 提取完成
}

state CreatingCircle {
    [*] --> WaitingFirstPoint
    WaitingFirstPoint --> WaitingSecondPoint : 双击
    WaitingSecondPoint --> DraggingRing : 双击
    DraggingRing --> Extracting : 双击
    Extracting --> Completed : 提取完成
}

state CreatingPoint {
    [*] --> WaitingClick
    WaitingClick --> Completed : 双击
}

state CreatingMeasurement {
    [*] --> SelectingSource
    SelectingSource --> SelectingTarget : 选择源几何
    SelectingTarget --> SelectingStrategy : 选择目标几何
    SelectingStrategy --> Calculating : 选择算法
    Calculating --> Completed : 计算完成
}

CreatingLine --> Idle : 完成/取消
CreatingCircle --> Idle : 完成/取消
CreatingPoint --> Idle : 完成/取消
CreatingMeasurement --> Idle : 完成/取消

@enduml

四、数据流设计

@startuml
participant "View2DSlice" as V2DS
participant "Controller" as CTRL
participant "DataModel" as DM
participant "View3D" as V3D
participant "View2DMeasure" as V2DM

V2DS -> CTRL : onLinePositionChanged(newPosition)
activate CTRL
CTRL -> DM : updateSlicePlane(newPosition)
activate DM
DM -> DM : recalculateBoundingBox()
DM --> CTRL : slicePlaneUpdated event
deactivate DM

CTRL -> V3D : updateSlicePlane(planeData)
activate V3D
V3D -> V3D : renderSlicePlane()
V3D --> CTRL : rendered
deactivate V3D

CTRL -> V2DM : updateBoundingBox(boxData)
activate V2DM
V2DM -> V2DM : renderBoundingBox()
V2DM --> CTRL : rendered
deactivate V2DM

deactivate CTRL
@enduml

五、核心模块说明

5.1 表现层(Presentation Layer)

  • View3DWidget:3D视口,显示切割平面和高亮区域
  • View2DSliceWidget:2D切割线拖动视口,实时更新边界框
  • View2DMeasureWidget:2D测量编辑视口,核心交互窗口

5.2 控制层(Controller Layer)

  • SectionMeasureController:总控制器,协调三个视图的同步
  • InteractionStateMachine:状态机,管理复杂的交互流程
  • CommandManager:命令管理器,支持撤销/重做

5.3 业务逻辑层(Business Logic Layer)

  • Geometry包:几何元素定义(点、线、圆、文本)
  • Measurement包:测量对象定义(各种距离、角度测量)
  • Strategy包:测量算法策略(垂直、水平、最近距离等)
  • Factory包:对象创建工厂

5.4 数据层(Data Layer)

  • SectionDataModel:核心数据模型,存储所有几何和测量数据
  • ObjectTreeAdapter:与对象树的适配器
  • DataSerializer:序列化/反序列化支持

5.5 渲染层(Rendering Layer)

  • GeometryRenderer:几何元素渲染器
  • MeasurementRenderer:测量结果渲染器
  • RenderStrategy:渲染策略接口

5.6 命令模式(Command Pattern)

  • 所有修改操作封装为命令
  • 支持撤销/重做
  • 便于操作历史记录

5.7 数据提取层(Extraction Layer)

  • RegionExtractor:区域数据提取器
  • PointCloudExtractor:点云提取
  • CADMeshExtractor:CAD网格提取

六、扩展性设计

6.1 新增几何类型

  1. 继承GeometryElement
  2. GeometryFactory中添加创建方法
  3. 实现对应的RenderStrategy
  4. 在状态机中添加新状态

6.2 新增测量类型

  1. 继承MeasurementElement
  2. 实现对应的MeasurementStrategy
  3. MeasurementFactory中注册
  4. 实现对应的RenderStrategy

6.3 新增测量算法

  1. 实现MeasurementStrategy接口
  2. 在测量对象中注册策略

七、关键技术点

7.1 数据与渲染分离

  • 数据模型独立于VTK渲染
  • 渲染器只负责可视化,不持有业务数据
  • 支持多种渲染后端切换

7.2 序列化设计

SectionData {
    version: "1.0"
    slicePlane: {...}
    geometries: [
        {id, type, data, ...},
        ...
    ]
    measurements: [
        {id, type, source, target, strategy, result, ...},
        ...
    ]
}

截面测量架构设计说明

一、设计思路过程

1. 问题分析

  • 三视图联动:3D视图、2D切割视图、2D测量视图需要数据同步
  • 复杂交互:多步骤的几何创建流程(线、圆的创建需要3-6个步骤)
  • 多样测量:10+种测量类型,每种有不同算法(3种距离算法)
  • 数据持久化:需要序列化到对象树,支持恢复

2. 设计策略

按照”分离关注点”原则,将系统拆分为5层:

  1. 表现层:负责UI显示和用户输入
  2. 控制层:协调视图同步和业务流程
  3. 业务逻辑层:封装几何和测量的核心逻辑
  4. 数据层:管理数据存储和序列化
  5. 渲染层:独立的VTK渲染逻辑

3. 关键设计模式选择

  • 命令模式:解决撤销/重做问题
  • 状态机模式:解决复杂交互流程问题
  • 策略模式:解决多算法切换问题
  • 工厂模式:解决对象创建统一管理
  • 观察者模式:解决视图间同步问题

二、架构核心说明

【表现层】三个独立视图

View3DWidget          → 显示3D切割状态
View2DSliceWidget     → 拖动切割线,触发数据更新
View2DMeasureWidget   → 核心交互窗口,创建几何和测量

职责:只负责显示和收集用户输入,不包含业务逻辑


【控制层】协调中枢

SectionMeasureController
├── 接收视图事件
├── 调用CommandManager执行命令
├── 同步三个视图的数据
└── 触发渲染更新

InteractionStateMachine
├── 管理创建几何的多步骤流程
├── 状态转换:空闲→等待第一点→拖动→等待第二点→提取→完成
└── 调用GeometryFactory创建对象

CommandManager
├── 执行命令并记录历史
├── 支持undo/redo
└── 所有数据修改都封装为命令

【业务逻辑层】核心领域模型

1. 几何元素(Geometry)

GeometryElement(抽象基类)
├── Point2D          → 2D点
├── Line2D           → 线(带宽度,支持区域提取)
├── Circle2D         → 圆环(支持区域提取)
└── TextAnnotation   → 文本标注

特点

  • 每个几何对象独立存在
  • 提供序列化/反序列化接口
  • Line2D和Circle2D支持区域提取(点云/CAD网格)

2. 测量对象(Measurement)

MeasurementElement(抽象基类)
├── PointToPointMeasure      → 点到点(3种算法)
├── PointToLineMeasure       → 点到线
├── LineToLineMeasure        → 线到线
├── CircleToLineMeasure      → 圆到线
├── PointToCircleMeasure     → 点到圆(3种算法)
├── CircleToCircleMeasure    → 圆到圆(3种算法)
├── AngleMeasure             → 角度
└── RadiusMeasure            → 半径

特点

  • 持有源几何和目标几何的引用
  • 使用策略模式注入测量算法
  • calculate()方法返回测量结果

3. 测量策略(Strategy)

MeasurementStrategy(接口)
├── VerticalDistanceStrategy    → 垂直距离
├── HorizontalDistanceStrategy  → 水平距离
├── NearestDistanceStrategy     → 最近距离
├── CenterDistanceStrategy      → 圆心距离
└── FarthestDistanceStrategy    → 最远距离

优势:算法可替换,易扩展新算法


【数据层】数据管理中心

SectionDataModel
├── 存储所有几何元素(vector<GeometryElement*>)
├── 存储所有测量对象(vector<MeasurementElement*>)
├── 存储切割平面数据(SlicePlaneData)
├── 存储边界框数据(BoundingBox)
└── 提供序列化/反序列化接口

ObjectTreeAdapter
└── 双向同步对象树数据

DataSerializer
└── 支持JSON/XML等格式序列化

核心:数据与渲染完全分离,数据模型不依赖VTK


【渲染层】可视化引擎

GeometryRenderer
├── 根据几何类型选择渲染策略
├── 渲染点、线、圆、文本
└── 支持高亮显示

MeasurementRenderer
├── 渲染测量结果(数值、标注线)
└── 动态更新测量值显示

特点

  • 使用策略模式,每种几何/测量有独立渲染策略
  • 只负责可视化,不修改数据

三、关键流程示例

流程1:创建线的完整过程

1. 用户点击"创建线"按钮
   → View2DMeasureWidget发送事件
   → InteractionStateMachine切换到"WaitingFirstPoint"状态

2. 用户双击第一点
   → 状态机切换到"Dragging"状态
   → 实时显示预览线

3. 用户拖动鼠标
   → 动态更新线的宽度区域

4. 用户双击第二点
   → 状态机切换到"Extracting"状态
   → 调用RegionExtractor提取点云/CAD网格

5. 提取完成
   → GeometryFactory创建Line2D对象
   → 封装为CreateGeometryCommand
   → CommandManager执行命令
   → SectionDataModel添加几何对象
   → GeometryRenderer渲染线和高亮区域
   → ObjectTreeAdapter同步到对象树

流程2:视图联动

1. 用户在View2DSliceWidget拖动切割线
   → 触发onLinePositionChanged()事件

2. SectionMeasureController接收事件
   → 封装为ModifySlicePlaneCommand
   → 更新SectionDataModel中的slicePlane数据
   → 重新计算boundingBox

3. Controller同步三个视图
   → View3DWidget更新3D切割平面显示
   → View2DSliceWidget更新边界框显示
   → View2DMeasureWidget重新渲染截面内容

五、技术要点总结

层次 核心职责 关键技术
表现层 UI显示和输入 Qt Widget + VTK Renderer
控制层 流程协调 命令模式 + 状态机
业务逻辑层 领域模型 策略模式 + 工厂模式
数据层 数据管理 适配器模式 + 序列化
渲染层 可视化 策略模式 + VTK

设计原则:单一职责、开闭原则、依赖倒置、接口隔离

作者:admin  创建时间:2025-12-11 10:39
最后编辑:admin  更新时间:2025-12-11 10:47