CloudCompare|点测量功能源码分析
文章目录
- 先从接口类开始分析
- 🔷 类名:`ccPointPickingGenericInterface`
- 📌 所在文件:
- 一、类继承结构:
- ✅ 父类功能:
- 二、核心用途:
- 三、核心成员函数详解:
- 🔹 构造函数
- 🔹 bool linkWith(ccGLWindowInterface\* win)
- 🔹 bool start()
- 🔹 void stop(bool state)
- 🔹 void onItemPicked(const PickedItem& pi)
- 🔹 virtual void processPickedPoint(const PickedItem& picked) = 0;
- 四、核心成员变量:
- 五、总结:类的职责定位
- ✅ 使用场景(CloudCompare 中的实际用法)
- 再分析一下该接口类继承的两个类
- 一、`ccOverlayDialog` 分析(继承自 `QDialog`)
- 📌 定义用途
- 🔧 核心功能点
- 二、`ccPickingListener` 分析(接口类)
- 📌 定义用途
- 🔧 核心功能点
- 三、结合继承场景分析
- ✅ 同时拥有:
- ✅ 可能用途:
- ✅ 示例结构:
- 四、设计总结
- 最后分析继承该接口的两个类
- ccPointPropertiesDlg
- ✅ 类 `ccPointPropertiesDlg` 的职责
- ✅ 类成员组成
- 成员变量
- 成员函数(核心)
- 继承接口的实现
- 模式切换槽函数(按钮点击触发)
- 其他功能
- ✅ `processPickedPoint` 工作流程详解
- ✅ `linkWith` 功能说明
- ✅ 总结:`ccPointPropertiesDlg` 的核心价值
- 🧩 类功能概述
- ✅ 核心作用:
- 🔄 类继承与成员结构
- 🧠 核心成员与方法说明
- 1. **构造函数与初始化**
- 2. **点拾取逻辑处理**
- 3. **实体关联**
- 4. **导出功能**
- 5. **撤销/还原逻辑**
- 6. **辅助 UI 控制**
- 7. **数据结构成员变量**
- ✅ 典型使用流程
- ccPointListPickingDlg
- 🧭 和 `ccPointPickingGenericInterface` 的区别?
- 🌟 核心功能概览
- ✅ 类的结构简析
- 构造函数
- 点列表获取
- 数据关联
- 导出功能
- 撤销与退出
- 💡 实用细节
- 标签命名
- 数据结构维护
- 🔎 可能的拓展方向建议
- 🧩 与 CloudCompare 的配合
主要涉及到的类
先从接口类开始分析
当然可以,我们一起来分析 ccPointPickingGenericInterface
这个接口类,它是 CloudCompare 中用于点选操作相关交互工具的通用基类,代码结构清晰、职责单一,适合作为各种需要鼠标选点功能工具的基类。
🔷 类名:ccPointPickingGenericInterface
📌 所在文件:
- 头文件:
ccPointPickingGenericInterface.h
- 实现文件:
ccPointPickingGenericInterface.cpp
一、类继承结构:
class ccPointPickingGenericInterface : public ccOverlayDialog, public ccPickingListener
✅ 父类功能:
ccOverlayDialog
:CloudCompare 中所有工具浮窗的基类,提供对话框与渲染窗口的绑定、开始/停止的接口。ccPickingListener
:CloudCompare 的拾取回调接口,专门用来监听鼠标选中的点等拾取信息。
二、核心用途:
该类是一个抽象基类(接口类),用于实现所有基于鼠标点选操作的工具。例如:点距离测量工具、基准点选取、投影工具等。
它为这些工具提供了统一的拾取点逻辑框架,具体点选处理逻辑由子类实现。
三、核心成员函数详解:
🔹 构造函数
explicit ccPointPickingGenericInterface(ccPickingHub* pickingHub, QWidget* parent = nullptr);
- 接收一个
ccPickingHub*
对象,用于注册监听点选事件。 ccPickingHub
是点选事件调度中心,可以同时支持多个监听器。
🔹 bool linkWith(ccGLWindowInterface* win)
bool ccPointPickingGenericInterface::linkWith(ccGLWindowInterface* win)
- 将该拾取界面绑定到一个
ccGLWindowInterface
(渲染窗口)。 - 如果之前绑定了窗口,需要断开旧窗口的信号连接。
- 注意:
ccOverlayDialog::linkWith(win)
是基类实现的绑定逻辑,必须调用。
🔹 bool start()
bool ccPointPickingGenericInterface::start()
- 启用点选监听器功能。
- 通过
m_pickingHub->addListener(this, true, true, POINT_PICKING)
注册本对象到ccPickingHub
。 - 会将窗口设置为不可关闭状态,避免误操作。
ccOverlayDialog::start()
调用后进入浮窗显示状态。
🔹 void stop(bool state)
void ccPointPickingGenericInterface::stop(bool state)
- 取消监听点选事件。
- 将窗口恢复为可关闭状态。
- 调用
ccOverlayDialog::stop(state)
通知父类退出浮窗状态。
🔹 void onItemPicked(const PickedItem& pi)
void ccPointPickingGenericInterface::onItemPicked(const PickedItem& pi)
- 实现自
ccPickingListener
,当用户通过鼠标在窗口中拾取了一个点,会调用此函数。 - 调用
processPickedPoint(pi)
,由子类进一步处理。
🔹 virtual void processPickedPoint(const PickedItem& picked) = 0;
- 纯虚函数,必须由子类实现。
- 子类实现具体的拾取点响应逻辑(例如:记录点、更新UI、计算距离等)。
四、核心成员变量:
ccPickingHub* m_pickingHub;
- 点选事件调度器,管理多个窗口/多个监听器。
- 非空指针,由构造函数传入。
五、总结:类的职责定位
功能 | 实现方式 |
---|---|
绑定渲染窗口 | linkWith() |
注册监听点拾取 | start() |
处理拾取结果 | onItemPicked() 调用 processPickedPoint() |
停止拾取并解绑 | stop() |
留给子类扩展逻辑 | processPickedPoint() (纯虚函数) |
✅ 使用场景(CloudCompare 中的实际用法)
你可以看到该类作为如下功能的基础类:
- 点对点测量工具
- 三角测量工具
- 坐标记录工具
- 捕捉标注点工具
子类继承这个接口后只需实现 processPickedPoint()
,即可实现各种响应逻辑,避免重复构建点选管理逻辑。
再分析一下该接口类继承的两个类
你目前提供的两个基类是:
ccOverlayDialog
:是一个基于QDialog
的界面类,用于作为叠加式的工具对话框;ccPickingListener
:是一个抽象接口类,用于响应 3D 视图中的点/面拾取事件。
下面对这两个类进行详细分析,并结合它们在 CloudCompare 中可能的继承用途进行总结。
一、ccOverlayDialog
分析(继承自 QDialog
)
📌 定义用途
该类是 CloudCompare 中所有工具对话框(如测量、剪裁、绘图等)的通用基类,它:
- 是一个轻量的、无边框窗口(通过
FramelessWindowHint | Tool
设置); - 能够被挂接到一个 3D 显示窗口
ccGLWindowInterface
; - 通过事件过滤器监听快捷键输入等;
- 提供
start()
/stop()
流程控制接口; - 使用信号槽机制和主窗口通信。
🔧 核心功能点
-
窗口与渲染窗口联动:通过
linkWith(ccGLWindowInterface* win)
绑定到具体的渲染视图; -
生命周期管理:
start()
和stop(bool accepted)
管理工具的运行状态; -
快捷键支持:可通过
addOverriddenShortcut(Qt::Key key)
添加快捷键; -
自动监听
Esc
退出; -
事件过滤器:过滤并响应窗口事件、快捷键事件、
Show
事件; -
信号:
processFinished(bool)
:工具流程结束时发出;shortcutTriggered(int)
:自定义快捷键被触发;shown()
:窗口展示时发出;
二、ccPickingListener
分析(接口类)
📌 定义用途
该类是 CloudCompare 中与鼠标拾取(pick)相关的功能接口,用于响应:
- 用户在视图中点击点、三角形、实体中心等事件;
- 获取拾取的 3D 点、点击位置、面片索引等。
🔧 核心功能点
-
纯虚函数:
virtual void onItemPicked(const PickedItem& pi) = 0;
子类必须实现该函数,响应用户拾取行为。
-
数据结构
PickedItem
:
提供了拾取位置、目标实体、点索引、3D 坐标、barycentric 坐标等详细信息。
三、结合继承场景分析
一个继承了 ccOverlayDialog
和 ccPickingListener
的类将:
✅ 同时拥有:
- 图形界面能力(窗口、启动/停止、快捷键等);
- 拾取事件响应能力(点击点、面、中心的处理);
✅ 可能用途:
这种多重继承设计非常适合构建 “带界面的拾取工具”,例如:
- 点到点测量工具(用户点击两个点计算距离);
- 选点标记工具(点击点以附加标签);
- 模型注释工具(点击位置添加批注);
- 三角面拾取工具(点击面片选定,做进一步分析如法向计算等)。
✅ 示例结构:
class MyPickingDialog : public ccOverlayDialog, public ccPickingListener
{Q_OBJECT
public:MyPickingDialog(QWidget* parent = nullptr);//实现拾取处理逻辑void onItemPicked(const PickedItem& pi) override;//界面初始化和开始逻辑void startPicking();private://内部状态,比如拾取的点集合、选中实体等
};
四、设计总结
基类 | 功能类型 | 特点说明 |
---|---|---|
ccOverlayDialog | UI框架 | QDialog 弹窗形式工具,能绑定视图、接收快捷键等 |
ccPickingListener | 拾取接口 | 响应用户在三维视图中点击选择点、面、中心的事件 |
🧩 多继承配合 | 工具设计模板 | 能设计“带界面的交互工具”,响应鼠标点选并处理对应逻辑 |
如你正在设计测量工具或交互工具界面,这两个类正是 CloudCompare 插件或内部功能的标准模式,可以直接扩展复用。需要帮助实现具体类或功能时可继续提供具体需求。
最后分析继承该接口的两个类
CloudCompare 中继承自 ccPointPickingGenericInterface
的两个类之一 —— ccPointPropertiesDlg
,它主要是一个用于点拾取和属性显示的对话框类。现在我们来详细分析这个类以及其在项目中的作用:
ccPointPropertiesDlg
✅ 类 ccPointPropertiesDlg
的职责
该类继承自 ccPointPickingGenericInterface
,用于管理如下几种拾取/测量模式:
模式名 | 功能说明 |
---|---|
POINT_INFO | 显示单个点的属性信息(如坐标、标量值等) |
POINT_POINT_DISTANCE | 计算两个点之间的距离 |
POINTS_ANGLE | 计算三个点所构成夹角 |
RECT_ZONE | 矩形区域选择(2D 区域) |
✅ 类成员组成
成员变量
Mode m_pickingMode; // 当前拾取模式
cc2DLabel* m_label; // 用于显示点、距离、角度的2D标签
cc2DViewportLabel* m_rect2DLabel; // 用于绘制矩形区域的2D标签
成员函数(核心)
继承接口的实现
bool start() override; // 开始拾取,默认启用点信息模式
void stop(bool state) override; // 停止拾取,清除状态
bool linkWith(ccGLWindowInterface* win) override; // 绑定窗口,注册事件
void processPickedPoint(const PickedItem&) override; // 处理拾取点
模式切换槽函数(按钮点击触发)
void activatePointPropertiesDisplay();
void activateDistanceDisplay();
void activateAngleDisplay();
void activate2DZonePicking();
其他功能
void exportCurrentLabel(); // 导出当前标签为实体(可用于保存或进一步操作)
void initializeState(); // 重置当前状态
void update2DZone(int x, int y, Qt::MouseButtons buttons); // 鼠标拖动区域时调用
void processClickedPoint(int x, int y); // 处理2D区域点击
void close2DZone(); // 鼠标释放时结束矩形选择
✅ processPickedPoint
工作流程详解
这是该类最核心的处理逻辑,它会根据当前模式执行如下动作:
- POINT_INFO: 清空旧标签,记录当前点,显示坐标等信息
- POINT_POINT_DISTANCE: 最多记录两个点,自动清空之前的点
- POINTS_ANGLE: 最多记录三个点,显示角度
- RECT_ZONE: 此模式不处理拾取点(鼠标点击位置会进入
processClickedPoint
)
并且在每次点选后,会输出点信息至控制台日志(ccLog::Print()
)。
✅ linkWith
功能说明
此函数将标签与 ccGLWindowInterface
绑定,注册信号槽响应(如鼠标移动、点击等)。它还负责在不同窗口切换时的清理/注册逻辑,确保标签显示不混乱。
✅ 总结:ccPointPropertiesDlg
的核心价值
该类提供了直观、可视化的点拾取交互工具,具备以下特性:
- 统一的界面交互(继承自
ccPointPickingGenericInterface
) - 丰富的测量模式支持(点信息、距离、角度、2D区域)
- 实时的图形反馈(标签显示)
- 可输出为实体,供后续分析/保存
它是 CloudCompare 交互式测量功能中的核心组件之一。
你贴出的 ccPointListPickingDlg
类是 CloudCompare 中 点列表拾取功能的完整交互对话框类,是一个核心 UI 类,继承自 ccPointPickingGenericInterface
,并结合 Qt Designer 的 UI 界面类(Ui::PointListPickingDlg
)。这个类的主要功能是让用户通过图形界面 依次拾取点并管理点列表、导出数据或生成新对象(如 polyline、点云等)。
🧩 类功能概述
✅ 核心作用:
功能 | 描述 |
---|---|
拾取点 | 支持交互方式拾取多个点,显示在列表中 |
导出点列表 | 支持导出为 ASCII 文件(多种格式)、点云或 polyline |
撤销拾取 | 可撤销最近点或全部点(通过 UI 按钮) |
支持取消还原 | 用户取消拾取时恢复原始状态 |
交互性强 | 拾取过程中标记点、重绘窗口、修改标注尺寸和索引等 |
🔄 类继承与成员结构
class ccPointListPickingDlg: public ccPointPickingGenericInterface, // 拾取点通用接口(虚函数 processPickedPoint), public Ui::PointListPickingDlg // Qt UI 界面(控件等)
ccPointPickingGenericInterface
:抽象接口类,提供通用的点拾取机制(定义了processPickedPoint()
虚函数)。Ui::PointListPickingDlg
:由 Qt Designer 生成的界面类,包含按钮、表格等控件。
🧠 核心成员与方法说明
1. 构造函数与初始化
ccPointListPickingDlg(ccPickingHub* pickingHub, QWidget* parent);
- 初始化 UI,注册按钮槽函数,准备拾取逻辑。
- 注册到
ccPickingHub
(CloudCompare 的中心拾取系统)。
2. 点拾取逻辑处理
void processPickedPoint(const PickedItem& picked) override;
- 重写接口函数。
- 每当用户在视图中拾取一个点时,这个函数被调用。
- 内部会创建 2D Label 或将点加入
m_toBeAdded
等待后续处理。 - 同时更新 UI 表格展示新点。
3. 实体关联
void linkWithEntity(ccHObject* entity);
- 设置当前操作对象,比如某个点云或网格。
- 后续拾取的数据和导出操作都围绕该实体进行。
4. 导出功能
void exportToNewCloud();
void exportToNewPolyline();
void exportToASCII(ExportFormat format); // 支持多种导出格式
-
exportToNewCloud()
:将拾取的点生成一个新的ccPointCloud
。 -
exportToNewPolyline()
:按拾取顺序连接成 polyline。 -
exportToASCII(format)
:XYZ
:基本坐标IXYZ
:带点索引GXYZ
:带全局索引LXYZ
:带标签或注释等
5. 撤销/还原逻辑
void removeLastEntry(); // 撤销最近一个
void cancelAndExit(); // 取消所有新建标注
void applyAndExit(); // 确认当前拾取
- 内部通过
m_toBeDeleted
,m_toBeAdded
管理新增/待删除对象,支持撤销。 - 若用户按下“取消”,不会改变原始数据结构。
6. 辅助 UI 控制
void markerSizeChanged(int);
void startIndexChanged(int);
void updateList();
- 响应用户在 UI 中调节标注大小、编号起始值等行为。
updateList()
会更新 Qt 表格显示当前所有拾取的点及其属性。
7. 数据结构成员变量
成员变量 | 含义 |
---|---|
ccHObject* m_associatedEntity | 当前操作的点云或网格 |
ccHObject* m_orderedLabelsContainer | 顺序存储生成的 cc2DLabel 对象 |
ccHObject::Container m_toBeDeleted | 记录在取消时应删除的对象 |
ccHObject::Container m_toBeAdded | 记录在取消时应恢复的新增对象 |
unsigned m_lastPreviousID | 启动前已有标注的最大 ID(用于防止 ID 冲突) |
✅ 典型使用流程
- 用户点击进入拾取模式(UI上启动
ccPointListPickingDlg
对话框)。 - 视图绑定 → 通过
linkWithEntity()
绑定点云或网格。 - 用户点击拾取点 →
processPickedPoint()
被调用,生成 2D label,记录坐标。 - 在表格中实时展示点编号和坐标。
- 可选择导出、生成新云、Polyline、ASCII 文件。
- 用户取消或确认拾取结果,内部通过
m_toBeDeleted
/m_toBeAdded
管理撤销。
ccPointListPickingDlg
🧭 和 ccPointPickingGenericInterface
的区别?
类名 | 作用 |
---|---|
ccPointPickingGenericInterface | 抽象接口类,定义拾取流程中的通用行为 |
ccPointListPickingDlg | UI 层封装类,真正实现交互功能、管理拾取逻辑、绑定实体、导出 |
CloudCompare 中不同拾取功能(如三点测角、线段测距)都可能继承 ccPointPickingGenericInterface
,但使用不同 UI 封装类。
你提供的这份 ccPointListPickingDlg
类实现是 CloudCompare 中负责“点列表拾取与导出”的 UI 类之一。它允许用户在 3D 视图中交互式选择点、查看坐标、导出为点云或折线、保存为 ASCII 文本等。以下是对这段代码关键模块的结构性分析与说明:
🌟 核心功能概览
功能 | 实现方式 |
---|---|
拾取点列表管理 | cc2DLabel 组合在 m_orderedLabelsContainer 中管理 |
拾取点的导出(ASCII/Cloud/Polyline) | exportToASCII_* ,exportToNewCloud() ,exportToNewPolyline() |
操作撤销(移除最后拾取点) | removeLastEntry() |
拾取序号设置与更新 | startIndexSpinBox 与 startIndexChanged() |
坐标系选择(局部/全局) | showGlobalCoordsCheckBox 与 updateList() |
UI 按钮与菜单构建 | 构造函数中创建 QMenu 并绑定 QAction |
持久化用户选项(文件路径等) | 使用 QSettings |
✅ 类的结构简析
构造函数
- 创建导出按钮菜单
- 连接按钮和控件信号槽
- 恢复上次的设置(起始编号、坐标系)
updateList()
:刷新当前点列表显示(表格视图)
点列表获取
unsigned ccPointListPickingDlg::getPickedPoints(std::vector<cc2DLabel*>& pickedPoints)
- 获取当前容器
m_orderedLabelsContainer
中所有可见的cc2DLabel
(注意:排除cc2DViewportLabel
)
数据关联
void ccPointListPickingDlg::linkWithEntity(ccHObject* entity)
- 绑定一个点云或模型对象,扫描其子层级寻找已存在的 “Picked points list” 容器并加载其中的 label。
- 同时开启/禁用“全局坐标”选项(如果该对象进行了 Shift)
导出功能
exportToNewCloud()
:将拾取点导出为新的ccPointCloud
,可用于保存/后续处理exportToNewPolyline()
:生成ccPolyline
,常用于测量路径等用途exportToASCII_xyz()
等:将点导出为指定格式文本(X,Y,Z、标签、局部/全局索引)
撤销与退出
removeLastEntry()
:根据唯一 ID 判断是否是旧点,从添加或删除列表中更新状态cancelAndExit()
:恢复之前的标签状态(还原不可见等)applyAndExit()
:确认拾取点后从数据库中删除旧标签,清除临时缓存
💡 实用细节
标签命名
static const char s_defaultLabelBaseName[] = "Point #";
可用于后续自动命名拾取点,例如 “Point #0”, “Point #1” 等。
数据结构维护
m_toBeDeleted
: 存储用户在当前会话中删除的旧点(在取消时恢复)m_toBeAdded
: 当前会话中新增的点(在撤销时删除)
🔎 可能的拓展方向建议
拓展项 | 建议实现 |
---|---|
支持多维数据导出 | 在 exportToASCII_* 中加入强度、颜色、法线等字段 |
导入功能 | 支持从 ASCII 导入点列表并创建 label |
支持区域选择添加标签 | 批量在选区中拾取点作为 label |
兼容多实体 | 当前 m_associatedEntity 是单一对象,未来可以扩展为多个实体支持 |
🧩 与 CloudCompare 的配合
此类一般配合:
ccPickingHub
:处理鼠标点击拾取事件(点击点)cc2DLabel
:显示每个拾取点的2D标签信息MainWindow::TheInstance()->addToDB()
:统一添加/管理对象ccGLWindowInterface
:响应标注大小调整、重绘等 UI 操作