From eb0cbdfc54e0d0b86630dcba26a4cf2b5e766fe3 Mon Sep 17 00:00:00 2001 From: yiyi Date: Mon, 23 Feb 2026 00:43:55 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=82=B9=E7=9A=84=E5=A4=A7?= =?UTF-8?q?=E5=B0=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CloudUtils/Src/LaserDataLoader.cpp | 18 ++++--- CloudView/Inc/PointCloudConverter.h | 7 +-- CloudView/Inc/PointCloudGLWidget.h | 20 ++++++-- CloudView/Src/CloudViewMainWindow.cpp | 7 ++- CloudView/Src/PointCloudConverter.cpp | 7 ++- CloudView/Src/PointCloudGLWidget.cpp | 72 ++++++++++++++++++++++++--- CloudView/main.cpp | 2 +- 7 files changed, 106 insertions(+), 27 deletions(-) diff --git a/CloudUtils/Src/LaserDataLoader.cpp b/CloudUtils/Src/LaserDataLoader.cpp index 3687837..7ad74f7 100644 --- a/CloudUtils/Src/LaserDataLoader.cpp +++ b/CloudUtils/Src/LaserDataLoader.cpp @@ -363,8 +363,11 @@ int LaserDataLoader::LoadPolySegments(const std::string& fileName, pt.y = fy; pt.z = fz; if (cnt >= 7) { - // 解析到了颜色 R,G,B,A(0-255) - int nRGB = B; nRGB <<= 8; nRGB += G; nRGB <<= 8; nRGB += R; + // 解析到了颜色 R,G,B,A(0-255),Alpha 存储在高 8 位 + unsigned int nRGB = static_cast(A) << 24; + nRGB |= static_cast(B) << 16; + nRGB |= static_cast(G) << 8; + nRGB |= static_cast(R); pt.nRGB = nRGB; } parsed = true; @@ -650,12 +653,11 @@ int LaserDataLoader::_ParseLaserScanPoint(const std::string& data, SVzNLPointXYZ sData.y = Y; sData.z = Z; - // R,G,B 是 0-255 整数值 - int nRGB = B; - nRGB <<= 8; - nRGB += G; - nRGB <<= 8; - nRGB += R; + // R,G,B,A 是 0-255 整数值,Alpha 存储在高 8 位 + unsigned int nRGB = static_cast(A) << 24; + nRGB |= static_cast(B) << 16; + nRGB |= static_cast(G) << 8; + nRGB |= static_cast(R); sData.nRGB = nRGB; s2DData.sLeft.x = leftX; diff --git a/CloudView/Inc/PointCloudConverter.h b/CloudView/Inc/PointCloudConverter.h index 766a290..04b609e 100644 --- a/CloudView/Inc/PointCloudConverter.h +++ b/CloudView/Inc/PointCloudConverter.h @@ -22,9 +22,10 @@ struct Point3DRGB { float x, y, z; uint8_t r, g, b; - Point3DRGB() : x(0), y(0), z(0), r(255), g(255), b(255) {} - Point3DRGB(float _x, float _y, float _z, uint8_t _r = 255, uint8_t _g = 255, uint8_t _b = 255) - : x(_x), y(_y), z(_z), r(_r), g(_g), b(_b) {} + float pointSize; // 自定义点大小,0 表示使用全局默认值(来自 RGBA 中 A > 1 的值) + Point3DRGB() : x(0), y(0), z(0), r(255), g(255), b(255), pointSize(0) {} + Point3DRGB(float _x, float _y, float _z, uint8_t _r = 255, uint8_t _g = 255, uint8_t _b = 255, float _ps = 0) + : x(_x), y(_y), z(_z), r(_r), g(_g), b(_b), pointSize(_ps) {} }; /** diff --git a/CloudView/Inc/PointCloudGLWidget.h b/CloudView/Inc/PointCloudGLWidget.h index f4bac71..639ae60 100644 --- a/CloudView/Inc/PointCloudGLWidget.h +++ b/CloudView/Inc/PointCloudGLWidget.h @@ -87,10 +87,11 @@ struct LineSegment float x1, y1, z1; // 起点 float x2, y2, z2; // 终点 float r, g, b; // 颜色 (0-1) + float lineWidth; // 线宽,0 表示使用默认值(来自 RGBA 中 A > 1 的值) - LineSegment() : x1(0), y1(0), z1(0), x2(0), y2(0), z2(0), r(1), g(1), b(1) {} - LineSegment(float _x1, float _y1, float _z1, float _x2, float _y2, float _z2, float _r = 1.0f, float _g = 1.0f, float _b = 1.0f) - : x1(_x1), y1(_y1), z1(_z1), x2(_x2), y2(_y2), z2(_z2), r(_r), g(_g), b(_b) {} + LineSegment() : x1(0), y1(0), z1(0), x2(0), y2(0), z2(0), r(1), g(1), b(1), lineWidth(0) {} + LineSegment(float _x1, float _y1, float _z1, float _x2, float _y2, float _z2, float _r = 1.0f, float _g = 1.0f, float _b = 1.0f, float _lw = 0) + : x1(_x1), y1(_y1), z1(_z1), x2(_x2), y2(_y2), z2(_z2), r(_r), g(_g), b(_b), lineWidth(_lw) {} }; /** @@ -272,6 +273,14 @@ private: int totalLines; // 总线数 int pointsPerLine; // 每线点数(网格化点云) + // 自定义点大小分组(RGBA 中 A > 1 的点按大小分组) + struct PointSizeGroup { + float pointSize; // 点大小 + std::vector indices; // 该大小的点在顶点数组中的索引(顶点索引 = indices[i] * 3) + }; + std::vector customPointSizeGroups; + bool hasCustomPointSizes; + // VBO 缓冲区 QOpenGLBuffer vertexBuffer; // 顶点 VBO QOpenGLBuffer colorBuffer; // 颜色 VBO @@ -280,6 +289,7 @@ private: PointCloudData() : hasColor(false), hasLineInfo(false), colorIndex(0) , totalLines(0), pointsPerLine(0) + , hasCustomPointSizes(false) , vertexBuffer(QOpenGLBuffer::VertexBuffer) , colorBuffer(QOpenGLBuffer::VertexBuffer) , vboCreated(false) @@ -297,6 +307,8 @@ private: , colorIndex(other.colorIndex) , totalLines(other.totalLines) , pointsPerLine(other.pointsPerLine) + , customPointSizeGroups(std::move(other.customPointSizeGroups)) + , hasCustomPointSizes(other.hasCustomPointSizes) , vertexBuffer(QOpenGLBuffer::VertexBuffer) , colorBuffer(QOpenGLBuffer::VertexBuffer) , vboCreated(false) @@ -324,6 +336,8 @@ private: colorIndex = other.colorIndex; totalLines = other.totalLines; pointsPerLine = other.pointsPerLine; + customPointSizeGroups = std::move(other.customPointSizeGroups); + hasCustomPointSizes = other.hasCustomPointSizes; // VBO 需要重建 other.vboCreated = false; } diff --git a/CloudView/Src/CloudViewMainWindow.cpp b/CloudView/Src/CloudViewMainWindow.cpp index 862f693..f12b57b 100644 --- a/CloudView/Src/CloudViewMainWindow.cpp +++ b/CloudView/Src/CloudViewMainWindow.cpp @@ -708,14 +708,17 @@ bool CloudViewMainWindow::loadSegmentFile(const QString& fileName) for (size_t i = 0; i + 1 < polyLine.size(); ++i) { const auto& p1 = polyLine[i]; const auto& p2 = polyLine[i + 1]; - // 取起点颜色作为线段颜色,nRGB 为 BGR 打包格式 + // 取起点颜色作为线段颜色,nRGB 为 (A<<24)|BGR 打包格式 float r = ((p1.nRGB >> 0) & 0xFF) / 255.0f; float g = ((p1.nRGB >> 8) & 0xFF) / 255.0f; float b = ((p1.nRGB >> 16) & 0xFF) / 255.0f; + uint8_t a = static_cast((p1.nRGB >> 24) & 0xFF); + // A > 1 时作为线宽使用 + float lineWidth = (a > 1) ? static_cast(a) : 0.0f; segments.append(LineSegment( p1.x, p1.y, p1.z, p2.x, p2.y, p2.z, - r, g, b)); + r, g, b, lineWidth)); } } diff --git a/CloudView/Src/PointCloudConverter.cpp b/CloudView/Src/PointCloudConverter.cpp index 76434b2..9811a61 100644 --- a/CloudView/Src/PointCloudConverter.cpp +++ b/CloudView/Src/PointCloudConverter.cpp @@ -137,12 +137,15 @@ int PointCloudConverter::loadFromTxt(const std::string& fileName, PointCloudXYZR for (const auto& line : rgbdData) { for (int i = 0; i < line.nPointCnt; ++i) { const SVzNLPointXYZRGBA& pt = line.p3DPoint[i]; - // 解包颜色:nRGB 格式为 (B << 16) | (G << 8) | R + // 解包颜色:nRGB 格式为 (A << 24) | (B << 16) | (G << 8) | R uint8_t r = static_cast(pt.nRGB & 0xFF); uint8_t g = static_cast((pt.nRGB >> 8) & 0xFF); uint8_t b = static_cast((pt.nRGB >> 16) & 0xFF); + uint8_t a = static_cast((pt.nRGB >> 24) & 0xFF); + // A > 1 时作为点大小使用 + float pointSize = (a > 1) ? static_cast(a) : 0.0f; - Point3DRGB point(pt.x, pt.y, pt.z, r, g, b); + Point3DRGB point(pt.x, pt.y, pt.z, r, g, b, pointSize); cloud.push_back(point, lineIndex); totalCount++; } diff --git a/CloudView/Src/PointCloudGLWidget.cpp b/CloudView/Src/PointCloudGLWidget.cpp index 6f3c680..d74258d 100644 --- a/CloudView/Src/PointCloudGLWidget.cpp +++ b/CloudView/Src/PointCloudGLWidget.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "VrLog.h" // OpenGL/GLU 头文件 @@ -196,6 +197,27 @@ void PointCloudGLWidget::paintGL() glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); + + // 绘制自定义大小的点(RGBA 中 A > 1 的点) + if (cloudData.hasCustomPointSizes) { + glDepthFunc(GL_LEQUAL); // 允许在相同深度覆盖绘制 + for (const auto& group : cloudData.customPointSizeGroups) { + glPointSize(group.pointSize); + glBegin(GL_POINTS); + for (size_t idx : group.indices) { + size_t vi = idx * 3; + if (vi + 2 < cloudData.vertices.size()) { + if (cloudData.hasColor && vi + 2 < cloudData.colors.size()) { + glColor3f(cloudData.colors[vi], cloudData.colors[vi + 1], cloudData.colors[vi + 2]); + } + glVertex3f(cloudData.vertices[vi], cloudData.vertices[vi + 1], cloudData.vertices[vi + 2]); + } + } + glEnd(); + } + glDepthFunc(GL_LESS); // 恢复默认深度测试 + glPointSize(m_pointSize); // 恢复默认点大小 + } } drawSelectedPoints(); @@ -296,12 +318,19 @@ void PointCloudGLWidget::addPointCloud(const PointCloudXYZRGB& cloud, const QStr data.colors.reserve(cloud.size() * 3); data.totalLines = 0; data.pointsPerLine = 0; + data.hasCustomPointSizes = false; + + // 用于按点大小分组的临时 map + std::map> sizeGroupMap; for (size_t i = 0; i < cloud.points.size(); ++i) { const auto& pt = cloud.points[i]; if (!std::isfinite(pt.x) || !std::isfinite(pt.y) || !std::isfinite(pt.z)) { continue; } + + size_t pointIndex = data.vertices.size() / 3; + data.vertices.push_back(pt.x); data.vertices.push_back(pt.y); data.vertices.push_back(pt.z); @@ -321,6 +350,23 @@ void PointCloudGLWidget::addPointCloud(const PointCloudXYZRGB& cloud, const QStr data.totalLines = lineIdx + 1; } } + + // 收集自定义点大小(A > 1) + if (pt.pointSize > 1.0f) { + sizeGroupMap[pt.pointSize].push_back(pointIndex); + } + } + + // 构建自定义点大小分组 + if (!sizeGroupMap.empty()) { + data.hasCustomPointSizes = true; + for (auto& pair : sizeGroupMap) { + PointCloudData::PointSizeGroup group; + group.pointSize = pair.first; + group.indices = std::move(pair.second); + data.customPointSizeGroups.push_back(std::move(group)); + } + LOG_INFO("[CloudView] Found %zu custom point size groups\n", data.customPointSizeGroups.size()); } // 计算每线点数 @@ -1187,16 +1233,26 @@ void PointCloudGLWidget::drawLineSegments() return; } - glLineWidth(2.0f); - glBegin(GL_LINES); - - for (const auto& seg : m_lineSegments) { - glColor3f(seg.r, seg.g, seg.b); - glVertex3f(seg.x1, seg.y1, seg.z1); - glVertex3f(seg.x2, seg.y2, seg.z2); + // 按线宽分组绘制 + // 收集所有不同的线宽值(0 表示默认 2.0f) + std::map> widthGroups; + for (int i = 0; i < m_lineSegments.size(); ++i) { + float w = m_lineSegments[i].lineWidth > 0 ? m_lineSegments[i].lineWidth : 2.0f; + widthGroups[w].append(i); + } + + for (const auto& group : widthGroups) { + glLineWidth(group.first); + glBegin(GL_LINES); + for (int idx : group.second) { + const auto& seg = m_lineSegments[idx]; + glColor3f(seg.r, seg.g, seg.b); + glVertex3f(seg.x1, seg.y1, seg.z1); + glVertex3f(seg.x2, seg.y2, seg.z2); + } + glEnd(); } - glEnd(); glLineWidth(1.0f); } diff --git a/CloudView/main.cpp b/CloudView/main.cpp index 7a5a652..1ba138c 100644 --- a/CloudView/main.cpp +++ b/CloudView/main.cpp @@ -3,7 +3,7 @@ #include #include "CloudViewMainWindow.h" -#define APP_VERSION "1.1.1" +#define APP_VERSION "1.1.2" int main(int argc, char* argv[]) {