对界面做了优化
This commit is contained in:
parent
517889ff90
commit
176a833bb2
2
.gitignore
vendored
2
.gitignore
vendored
@ -16,6 +16,8 @@ Makefile*
|
|||||||
moc_*.cpp
|
moc_*.cpp
|
||||||
moc_*.h
|
moc_*.h
|
||||||
qrc_*.cpp
|
qrc_*.cpp
|
||||||
|
*_resource.rc
|
||||||
|
*_resource.res
|
||||||
ui_*.h
|
ui_*.h
|
||||||
*.autosave
|
*.autosave
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,13 @@ QT += core
|
|||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
CONFIG += staticlib
|
CONFIG += staticlib
|
||||||
|
|
||||||
|
win32:CONFIG(debug, debug|release) {
|
||||||
|
DESTDIR = $$PWD/debug
|
||||||
|
}
|
||||||
|
win32:CONFIG(release, debug|release) {
|
||||||
|
DESTDIR = $$PWD/release
|
||||||
|
}
|
||||||
|
|
||||||
win32-msvc {
|
win32-msvc {
|
||||||
QMAKE_CXXFLAGS += /utf-8
|
QMAKE_CXXFLAGS += /utf-8
|
||||||
}
|
}
|
||||||
|
|||||||
@ -212,24 +212,55 @@ int LaserDataLoader::LoadLaserScanData(const std::string& fileName,
|
|||||||
bool bFindLineNum = true;
|
bool bFindLineNum = true;
|
||||||
int nLaserPointIdx = 0;
|
int nLaserPointIdx = 0;
|
||||||
|
|
||||||
|
auto failTextLoad = [&](int code, const std::string& message) -> int {
|
||||||
|
m_lastError = message;
|
||||||
|
LOG_ERROR("%s\n", message.c_str());
|
||||||
|
if (!bFindLineNum) {
|
||||||
|
laserLines.push_back(std::make_pair(eDataType, sLaserData));
|
||||||
|
bFindLineNum = true;
|
||||||
|
}
|
||||||
|
FreeLaserScanData(laserLines);
|
||||||
|
lineNum = 0;
|
||||||
|
return ERR_CODE(code);
|
||||||
|
};
|
||||||
|
|
||||||
|
auto commitCurrentLine = [&]() -> int {
|
||||||
|
if (bFindLineNum) return SUCCESS;
|
||||||
|
// if (nLaserPointIdx != sLaserData.nPointCount) {
|
||||||
|
// std::ostringstream message;
|
||||||
|
// message << "Incomplete laser line: expected " << sLaserData.nPointCount
|
||||||
|
// << " points, got " << nLaserPointIdx;
|
||||||
|
// return failTextLoad(FILE_ERR_FORMAT, message.str());
|
||||||
|
// }
|
||||||
|
laserLines.push_back(std::make_pair(eDataType, sLaserData));
|
||||||
|
bFindLineNum = true;
|
||||||
|
return SUCCESS;
|
||||||
|
};
|
||||||
|
|
||||||
while (std::getline(inputFile, line)) {
|
while (std::getline(inputFile, line)) {
|
||||||
// 去除行末的 \r 字符(处理 Windows 格式的 CR LF 换行符)
|
// 去除行末的 \r 字符(处理 Windows 格式的 CR LF 换行符)
|
||||||
TrimCarriageReturn(line);
|
TrimCarriageReturn(line);
|
||||||
|
|
||||||
if (line.find("LineNum:") == 0) {
|
if (line.find("LineNum:") == 0) {
|
||||||
sscanf(line.c_str(), "LineNum:%d", &lineNum);
|
if (1 != sscanf(line.c_str(), "LineNum:%d", &lineNum) || lineNum <= 0) {
|
||||||
|
return failTextLoad(FILE_ERR_FORMAT, "Invalid LineNum header: " + line);
|
||||||
|
}
|
||||||
} else if (line.find("DataType:") == 0) {
|
} else if (line.find("DataType:") == 0) {
|
||||||
|
|
||||||
} else if (line.find("Line_") == 0) {
|
} else if (line.find("Line_") == 0) {
|
||||||
|
|
||||||
if(false == bFindLineNum) {
|
if(false == bFindLineNum) {
|
||||||
laserLines.push_back(std::make_pair(eDataType, sLaserData));
|
result = commitCurrentLine();
|
||||||
|
if (SUCCESS != result) return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int lineIndex;
|
int lineIndex = 0;
|
||||||
unsigned int timeStamp;
|
unsigned int timeStamp = 0;
|
||||||
int ptNum = 0;
|
int ptNum = 0;
|
||||||
sscanf(line.c_str(), "Line_%d_%u_%d", &lineIndex, &timeStamp, &ptNum);
|
if (3 != sscanf(line.c_str(), "Line_%d_%u_%d", &lineIndex, &timeStamp, &ptNum) ||
|
||||||
|
ptNum < 0) {
|
||||||
|
return failTextLoad(FILE_ERR_FORMAT, "Invalid laser line header: " + line);
|
||||||
|
}
|
||||||
|
|
||||||
sLaserData.llFrameIdx = lineIndex;
|
sLaserData.llFrameIdx = lineIndex;
|
||||||
sLaserData.llTimeStamp = timeStamp;
|
sLaserData.llTimeStamp = timeStamp;
|
||||||
@ -256,7 +287,10 @@ int LaserDataLoader::LoadLaserScanData(const std::string& fileName,
|
|||||||
polyNum = std::atoi(line.c_str() + lastUnderscore + 1);
|
polyNum = std::atoi(line.c_str() + lastUnderscore + 1);
|
||||||
}
|
}
|
||||||
for (int skip = 0; skip < polyNum; ) {
|
for (int skip = 0; skip < polyNum; ) {
|
||||||
if (!std::getline(inputFile, line)) break;
|
if (!std::getline(inputFile, line)) {
|
||||||
|
return failTextLoad(inputFile.bad() ? FILE_ERR_READ : FILE_ERR_FORMAT,
|
||||||
|
"Incomplete Poly block in laser file: " + fileName);
|
||||||
|
}
|
||||||
TrimCarriageReturn(line);
|
TrimCarriageReturn(line);
|
||||||
if (!line.empty()) {
|
if (!line.empty()) {
|
||||||
++skip;
|
++skip;
|
||||||
@ -283,21 +317,38 @@ int LaserDataLoader::LoadLaserScanData(const std::string& fileName,
|
|||||||
if (eDataType == keResultDataType_PointXYZRGBA) {
|
if (eDataType == keResultDataType_PointXYZRGBA) {
|
||||||
SVzNLPointXYZRGBA* pRGBAPoints = static_cast<SVzNLPointXYZRGBA*>(sLaserData.p3DPoint);
|
SVzNLPointXYZRGBA* pRGBAPoints = static_cast<SVzNLPointXYZRGBA*>(sLaserData.p3DPoint);
|
||||||
SVzNL2DLRPoint* p2DPoints = static_cast<SVzNL2DLRPoint*>(sLaserData.p2DPoint);
|
SVzNL2DLRPoint* p2DPoints = static_cast<SVzNL2DLRPoint*>(sLaserData.p2DPoint);
|
||||||
_ParseLaserScanPoint(line, pRGBAPoints[nLaserPointIdx], p2DPoints[nLaserPointIdx]);
|
result = _ParseLaserScanPoint(line, pRGBAPoints[nLaserPointIdx], p2DPoints[nLaserPointIdx]);
|
||||||
|
if (SUCCESS != result) {
|
||||||
|
return failTextLoad(FILE_ERR_FORMAT, "Invalid RGBD point: " + line);
|
||||||
|
}
|
||||||
nLaserPointIdx++;
|
nLaserPointIdx++;
|
||||||
} else {
|
} else {
|
||||||
SVzNL3DPosition* p3DPoints = static_cast<SVzNL3DPosition*>(sLaserData.p3DPoint);
|
SVzNL3DPosition* p3DPoints = static_cast<SVzNL3DPosition*>(sLaserData.p3DPoint);
|
||||||
SVzNL2DPosition* p2DPoints = static_cast<SVzNL2DPosition*>(sLaserData.p2DPoint);
|
SVzNL2DPosition* p2DPoints = static_cast<SVzNL2DPosition*>(sLaserData.p2DPoint);
|
||||||
_ParseLaserScanPoint(line, p3DPoints[nLaserPointIdx], p2DPoints[nLaserPointIdx]);
|
result = _ParseLaserScanPoint(line, p3DPoints[nLaserPointIdx], p2DPoints[nLaserPointIdx]);
|
||||||
|
if (SUCCESS != result) {
|
||||||
|
return failTextLoad(FILE_ERR_FORMAT, "Invalid XYZ point: " + line);
|
||||||
|
}
|
||||||
p3DPoints[nLaserPointIdx].nPointIdx = nLaserPointIdx;
|
p3DPoints[nLaserPointIdx].nPointIdx = nLaserPointIdx;
|
||||||
nLaserPointIdx++;
|
nLaserPointIdx++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inputFile.bad()) {
|
||||||
|
return failTextLoad(FILE_ERR_READ, "Failed while reading laser file: " + fileName);
|
||||||
|
}
|
||||||
|
|
||||||
// 添加最后一条扫描线数据
|
// 添加最后一条扫描线数据
|
||||||
if (!bFindLineNum) {
|
if (!bFindLineNum) {
|
||||||
laserLines.push_back(std::make_pair(eDataType, sLaserData));
|
result = commitCurrentLine();
|
||||||
|
if (SUCCESS != result) return result;
|
||||||
|
}
|
||||||
|
if (lineNum <= 0 || laserLines.size() != static_cast<size_t>(lineNum)) {
|
||||||
|
std::ostringstream message;
|
||||||
|
message << "Laser line count mismatch: expected " << lineNum
|
||||||
|
<< ", got " << laserLines.size();
|
||||||
|
return failTextLoad(FILE_ERR_FORMAT, message.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
inputFile.close();
|
inputFile.close();
|
||||||
@ -484,6 +535,19 @@ int LaserDataLoader::SaveLaserScanData(const std::string& fileName,
|
|||||||
LOG_ERROR("Invalid parameters for saving unified laser data\n");
|
LOG_ERROR("Invalid parameters for saving unified laser data\n");
|
||||||
return ERR_CODE(DEV_ARG_INVAILD);
|
return ERR_CODE(DEV_ARG_INVAILD);
|
||||||
}
|
}
|
||||||
|
const EVzResultDataType fileDataType = laserLines.front().first;
|
||||||
|
if (fileDataType != keResultDataType_Position &&
|
||||||
|
fileDataType != keResultDataType_PointXYZI &&
|
||||||
|
fileDataType != keResultDataType_PointXYZRGBA) {
|
||||||
|
m_lastError = "Unsupported laser data type for saving";
|
||||||
|
return ERR_CODE(DEV_ARG_INVAILD);
|
||||||
|
}
|
||||||
|
if (lineNum != static_cast<int>(laserLines.size()) ||
|
||||||
|
std::any_of(laserLines.begin(), laserLines.end(),
|
||||||
|
[fileDataType](const auto& line) { return line.first != fileDataType; })) {
|
||||||
|
m_lastError = "Line count mismatch or mixed laser data types";
|
||||||
|
return ERR_CODE(DEV_ARG_INVAILD);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
std::ofstream sw(fileName);
|
std::ofstream sw(fileName);
|
||||||
@ -495,7 +559,7 @@ int LaserDataLoader::SaveLaserScanData(const std::string& fileName,
|
|||||||
|
|
||||||
// 写入文件头
|
// 写入文件头
|
||||||
sw << "LineNum:" << lineNum << '\n';
|
sw << "LineNum:" << lineNum << '\n';
|
||||||
sw << "DataType: 0" << '\n';
|
sw << "DataType:" << static_cast<int>(fileDataType) << '\n';
|
||||||
sw << "ScanSpeed:" << scanSpeed << '\n';
|
sw << "ScanSpeed:" << scanSpeed << '\n';
|
||||||
sw << "PointAdjust: 1" << '\n';
|
sw << "PointAdjust: 1" << '\n';
|
||||||
sw << "MaxTimeStamp:" << maxTimeStamp << "_" << clockPerSecond << '\n';
|
sw << "MaxTimeStamp:" << maxTimeStamp << "_" << clockPerSecond << '\n';
|
||||||
@ -523,10 +587,13 @@ int LaserDataLoader::SaveLaserScanData(const std::string& fileName,
|
|||||||
float x = static_cast<float>(points[i].pt3D.x);
|
float x = static_cast<float>(points[i].pt3D.x);
|
||||||
float y = static_cast<float>(points[i].pt3D.y);
|
float y = static_cast<float>(points[i].pt3D.y);
|
||||||
float z = static_cast<float>(points[i].pt3D.z);
|
float z = static_cast<float>(points[i].pt3D.z);
|
||||||
|
const int leftX = points2D ? points2D[i].ptLeft2D.x : 0;
|
||||||
|
const int leftY = points2D ? points2D[i].ptLeft2D.y : 0;
|
||||||
|
const int rightX = points2D ? points2D[i].ptRight2D.x : 0;
|
||||||
|
const int rightY = points2D ? points2D[i].ptRight2D.y : 0;
|
||||||
AppendFormattedLine(buffer, "{ %.6f,%.6f,%.6f }-{ %d,%d }-{ %d,%d }\n",
|
AppendFormattedLine(buffer, "{ %.6f,%.6f,%.6f }-{ %d,%d }-{ %d,%d }\n",
|
||||||
x, y, z,
|
x, y, z,
|
||||||
points2D[i].ptLeft2D.x, points2D[i].ptLeft2D.y,
|
leftX, leftY, rightX, rightY);
|
||||||
points2D[i].ptRight2D.x, points2D[i].ptRight2D.y);
|
|
||||||
}
|
}
|
||||||
sw.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
|
sw.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
|
||||||
}
|
}
|
||||||
@ -566,18 +633,27 @@ int LaserDataLoader::SaveLaserScanData(const std::string& fileName,
|
|||||||
int r = (points[i].nRGB >> 16) & 0xFF;
|
int r = (points[i].nRGB >> 16) & 0xFF;
|
||||||
int g = (points[i].nRGB >> 8) & 0xFF;
|
int g = (points[i].nRGB >> 8) & 0xFF;
|
||||||
int b = points[i].nRGB & 0xFF;
|
int b = points[i].nRGB & 0xFF;
|
||||||
|
const int leftX = points2D ? points2D[i].sLeft.x : 0;
|
||||||
|
const int leftY = points2D ? points2D[i].sLeft.y : 0;
|
||||||
|
const int rightX = points2D ? points2D[i].sRight.x : 0;
|
||||||
|
const int rightY = points2D ? points2D[i].sRight.y : 0;
|
||||||
|
|
||||||
AppendFormattedLine(buffer, "{%.6f,%.6f,%.6f,%.6f,%.6f,%.6f}-{ %d,%d }-{ %d,%d }\n",
|
AppendFormattedLine(buffer, "{%.6f,%.6f,%.6f,%.6f,%.6f,%.6f}-{ %d,%d }-{ %d,%d }\n",
|
||||||
x, y, z,
|
x, y, z,
|
||||||
b * 1.0f / 255, g * 1.0f / 255, r * 1.0f / 255,
|
b * 1.0f / 255, g * 1.0f / 255, r * 1.0f / 255,
|
||||||
points2D[i].sLeft.x, points2D[i].sLeft.y,
|
leftX, leftY, rightX, rightY);
|
||||||
points2D[i].sRight.x, points2D[i].sRight.y);
|
|
||||||
}
|
}
|
||||||
sw.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
|
sw.write(buffer.data(), static_cast<std::streamsize>(buffer.size()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sw.flush();
|
||||||
|
if (!sw.good()) {
|
||||||
|
m_lastError = "Failed while writing file: " + fileName;
|
||||||
|
LOG_ERROR("Failed while writing file: %s\n", fileName.c_str());
|
||||||
|
return ERR_CODE(FILE_ERR_WRITE);
|
||||||
|
}
|
||||||
sw.close();
|
sw.close();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
|
||||||
@ -657,6 +733,12 @@ int LaserDataLoader::DebugSaveLaser(std::string fileName, std::vector<std::vecto
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sw.flush();
|
||||||
|
if (!sw.good()) {
|
||||||
|
m_lastError = "Failed while writing file: " + fileName;
|
||||||
|
LOG_ERROR("Failed while writing file: %s\n", fileName.c_str());
|
||||||
|
return ERR_CODE(FILE_ERR_WRITE);
|
||||||
|
}
|
||||||
sw.close();
|
sw.close();
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
|
|
||||||
@ -711,8 +793,12 @@ int LaserDataLoader::LoadPolySegments(const std::string& fileName,
|
|||||||
|
|
||||||
// 读取 num 个点坐标
|
// 读取 num 个点坐标
|
||||||
std::vector<SVzNLPointXYZRGBA> points;
|
std::vector<SVzNLPointXYZRGBA> points;
|
||||||
|
bool incompleteBlock = false;
|
||||||
for (int i = 0; i < num; ) {
|
for (int i = 0; i < num; ) {
|
||||||
if (!std::getline(inputFile, line)) break;
|
if (!std::getline(inputFile, line)) {
|
||||||
|
incompleteBlock = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
TrimCarriageReturn(line);
|
TrimCarriageReturn(line);
|
||||||
if (line.empty()) {
|
if (line.empty()) {
|
||||||
continue; // 跳过空行,不计数
|
continue; // 跳过空行,不计数
|
||||||
@ -795,9 +881,20 @@ int LaserDataLoader::LoadPolySegments(const std::string& fileName,
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (points.size() >= 2) {
|
if (incompleteBlock || points.size() != static_cast<size_t>(num)) {
|
||||||
|
m_lastError = "Incomplete or invalid Poly block in file: " + fileName;
|
||||||
|
LOG_ERROR("%s\n", m_lastError.c_str());
|
||||||
|
polyLines.clear();
|
||||||
|
return ERR_CODE(inputFile.bad() ? FILE_ERR_READ : FILE_ERR_FORMAT);
|
||||||
|
}
|
||||||
polyLines.push_back(std::move(points));
|
polyLines.push_back(std::move(points));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inputFile.bad()) {
|
||||||
|
m_lastError = "Failed while reading Poly file: " + fileName;
|
||||||
|
LOG_ERROR("%s\n", m_lastError.c_str());
|
||||||
|
polyLines.clear();
|
||||||
|
return ERR_CODE(FILE_ERR_READ);
|
||||||
}
|
}
|
||||||
|
|
||||||
inputFile.close();
|
inputFile.close();
|
||||||
@ -1043,10 +1140,13 @@ void LaserDataLoader::FreeConvertedData(std::vector<SVzNLXYZRGBDLaserLine>& rgbd
|
|||||||
|
|
||||||
int LaserDataLoader::_ParseLaserScanPoint(const std::string& data, SVzNL3DPosition& sData, SVzNL2DPosition& s2DData)
|
int LaserDataLoader::_ParseLaserScanPoint(const std::string& data, SVzNL3DPosition& sData, SVzNL2DPosition& s2DData)
|
||||||
{
|
{
|
||||||
float X, Y, Z;
|
float X = 0.0f, Y = 0.0f, Z = 0.0f;
|
||||||
float leftX, leftY;
|
float leftX = 0.0f, leftY = 0.0f;
|
||||||
float rightX, rightY;
|
float rightX = 0.0f, rightY = 0.0f;
|
||||||
sscanf(data.c_str(), "{%f,%f,%f}-{%f,%f}-{%f,%f}", &X, &Y, &Z, &leftX, &leftY, &rightX, &rightY);
|
if (7 != sscanf(data.c_str(), " { %f , %f , %f } - { %f , %f } - { %f , %f }",
|
||||||
|
&X, &Y, &Z, &leftX, &leftY, &rightX, &rightY)) {
|
||||||
|
return ERR_CODE(FILE_ERR_FORMAT);
|
||||||
|
}
|
||||||
sData.pt3D.x = X;
|
sData.pt3D.x = X;
|
||||||
sData.pt3D.y = Y;
|
sData.pt3D.y = Y;
|
||||||
sData.pt3D.z = Z;
|
sData.pt3D.z = Z;
|
||||||
@ -1059,9 +1159,9 @@ int LaserDataLoader::_ParseLaserScanPoint(const std::string& data, SVzNL3DPositi
|
|||||||
|
|
||||||
int LaserDataLoader::_ParseLaserScanPoint(const std::string& data, SVzNLPointXYZRGBA& sData, SVzNL2DLRPoint& s2DData)
|
int LaserDataLoader::_ParseLaserScanPoint(const std::string& data, SVzNLPointXYZRGBA& sData, SVzNL2DLRPoint& s2DData)
|
||||||
{
|
{
|
||||||
float X, Y, Z;
|
float X = 0.0f, Y = 0.0f, Z = 0.0f;
|
||||||
float leftX, leftY;
|
float leftX = 0.0f, leftY = 0.0f;
|
||||||
float rightX, rightY;
|
float rightX = 0.0f, rightY = 0.0f;
|
||||||
|
|
||||||
// 尝试新格式: {x,y,z}-{lx,ly}-{rx,ry}-{R,G,B,A}
|
// 尝试新格式: {x,y,z}-{lx,ly}-{rx,ry}-{R,G,B,A}
|
||||||
int R, G, B, A;
|
int R, G, B, A;
|
||||||
@ -1088,10 +1188,12 @@ int LaserDataLoader::_ParseLaserScanPoint(const std::string& data, SVzNLPointXYZ
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 旧格式: {x,y,z,r,g,b}-{lx,ly}-{rx,ry} r,g,b 为 0~1 浮点值
|
// 旧格式: {x,y,z,r,g,b}-{lx,ly}-{rx,ry} r,g,b 为 0~1 浮点值
|
||||||
float r, g, b;
|
float r = 0.0f, g = 0.0f, b = 0.0f;
|
||||||
sscanf(data.c_str(),
|
if (10 != sscanf(data.c_str(),
|
||||||
" { %f , %f , %f , %f , %f , %f } - { %f , %f } - { %f , %f }",
|
" { %f , %f , %f , %f , %f , %f } - { %f , %f } - { %f , %f }",
|
||||||
&X, &Y, &Z, &r, &g, &b, &leftX, &leftY, &rightX, &rightY);
|
&X, &Y, &Z, &r, &g, &b, &leftX, &leftY, &rightX, &rightY)) {
|
||||||
|
return ERR_CODE(FILE_ERR_FORMAT);
|
||||||
|
}
|
||||||
sData.x = X;
|
sData.x = X;
|
||||||
sData.y = Y;
|
sData.y = Y;
|
||||||
sData.z = Z;
|
sData.z = Z;
|
||||||
|
|||||||
@ -15,9 +15,9 @@ TEMPLATE = app
|
|||||||
|
|
||||||
# 椤圭洰鐩綍
|
# 椤圭洰鐩綍
|
||||||
INCLUDEPATH += $$PWD/Inc
|
INCLUDEPATH += $$PWD/Inc
|
||||||
|
INCLUDEPATH += $$PWD/../../Device/SDK/VzNLSDK/Inc
|
||||||
INCLUDEPATH += $$PWD/../CloudView3D/Inc
|
INCLUDEPATH += $$PWD/../CloudView3D/Inc
|
||||||
INCLUDEPATH += $$PWD/../CloudUtils/Inc
|
INCLUDEPATH += $$PWD/../CloudUtils/Inc
|
||||||
INCLUDEPATH += $$PWD/../../Device/SDK/VzNLSDK/Inc
|
|
||||||
INCLUDEPATH += $$PWD/../VrUtils/Inc
|
INCLUDEPATH += $$PWD/../VrUtils/Inc
|
||||||
INCLUDEPATH += $$PWD/../VrCommon/Inc
|
INCLUDEPATH += $$PWD/../VrCommon/Inc
|
||||||
|
|
||||||
@ -35,23 +35,28 @@ SOURCES += \
|
|||||||
|
|
||||||
# 璧勬簮鏂囦欢
|
# 璧勬簮鏂囦欢
|
||||||
RESOURCES += resource/resource.qrc
|
RESOURCES += resource/resource.qrc
|
||||||
RESOURCES += $$PWD/../../AppUtils/UICommon/common_resources.qrc
|
COMMON_RESOURCES = $$PWD/../../AppUtils/UICommon/common_resources.qrc
|
||||||
|
exists($$COMMON_RESOURCES) {
|
||||||
|
RESOURCES += $$COMMON_RESOURCES
|
||||||
|
} else {
|
||||||
|
message("CloudView: optional common_resources.qrc not found; using text view buttons")
|
||||||
|
}
|
||||||
|
|
||||||
# Windows 搴旂敤鍥炬爣
|
# Windows 搴旂敤鍥炬爣
|
||||||
RC_ICONS = resource/logo.ico
|
RC_ICONS = resource/logo.ico
|
||||||
|
|
||||||
# Windows骞冲彴搴撻摼鎺?
|
# Windows骞冲彴搴撻摼鎺?
|
||||||
win32:CONFIG(release, debug|release): {
|
win32:CONFIG(release, debug|release): {
|
||||||
LIBS += -L../CloudView3D/release -lCloudView3D
|
LIBS += -L$$PWD/../CloudView3D/release -lCloudView3D
|
||||||
LIBS += -L../CloudUtils/release -lCloudUtils
|
LIBS += -L$$PWD/../CloudUtils/release -lCloudUtils
|
||||||
LIBS += -L../VrUtils/release -lVrUtils
|
LIBS += -L$$PWD/../VrUtils/release -lVrUtils
|
||||||
LIBS += -L../VrCommon/release -lVrCommon
|
LIBS += -L$$PWD/../VrCommon/release -lVrCommon
|
||||||
}
|
}
|
||||||
else:win32:CONFIG(debug, debug|release): {
|
else:win32:CONFIG(debug, debug|release): {
|
||||||
LIBS += -L../CloudView3D/debug -lCloudView3D
|
LIBS += -L$$PWD/../CloudView3D/debug -lCloudView3D
|
||||||
LIBS += -L../CloudUtils/debug -lCloudUtils
|
LIBS += -L$$PWD/../CloudUtils/debug -lCloudUtils
|
||||||
LIBS += -L../VrUtils/debug -lVrUtils
|
LIBS += -L$$PWD/../VrUtils/debug -lVrUtils
|
||||||
LIBS += -L../VrCommon/debug -lVrCommon
|
LIBS += -L$$PWD/../VrCommon/debug -lVrCommon
|
||||||
}
|
}
|
||||||
|
|
||||||
# Windows绯荤粺搴?
|
# Windows绯荤粺搴?
|
||||||
|
|||||||
@ -1359,6 +1359,7 @@ QWidget* CloudViewMainWindow::createViewToolbar()
|
|||||||
// 视图预设:图标、提示、旋转角度
|
// 视图预设:图标、提示、旋转角度
|
||||||
struct ViewPreset {
|
struct ViewPreset {
|
||||||
const char* iconPath;
|
const char* iconPath;
|
||||||
|
const char* fallbackText;
|
||||||
const char* tooltip;
|
const char* tooltip;
|
||||||
float rotX;
|
float rotX;
|
||||||
float rotY;
|
float rotY;
|
||||||
@ -1367,13 +1368,13 @@ QWidget* CloudViewMainWindow::createViewToolbar()
|
|||||||
|
|
||||||
// 坐标系定义:X向右,Y向下,Z朝后
|
// 坐标系定义:X向右,Y向下,Z朝后
|
||||||
ViewPreset presets[] = {
|
ViewPreset presets[] = {
|
||||||
{":/common/resource/view_front.png", "正视 (XY面)", 180.0f, 0.0f, 0.0f},
|
{":/common/resource/view_front.png", "前", "正视 (XY面)", 180.0f, 0.0f, 0.0f},
|
||||||
{":/common/resource/view_back.png", "后视", 180.0f, 180.0f, 0.0f},
|
{":/common/resource/view_back.png", "后", "后视", 180.0f, 180.0f, 0.0f},
|
||||||
{":/common/resource/view_left.png", "左视 (YZ面)", 180.0f, 90.0f, 0.0f},
|
{":/common/resource/view_left.png", "左", "左视 (YZ面)", 180.0f, 90.0f, 0.0f},
|
||||||
{":/common/resource/view_right.png", "右视", 180.0f, -90.0f, 0.0f},
|
{":/common/resource/view_right.png", "右", "右视", 180.0f, -90.0f, 0.0f},
|
||||||
{":/common/resource/view_top.png", "俯视 (XZ面)", 90.0f, 0.0f, 0.0f},
|
{":/common/resource/view_top.png", "上", "俯视 (XZ面)", 90.0f, 0.0f, 0.0f},
|
||||||
{":/common/resource/view_bottom.png", "仰视", -90.0f, 0.0f, 0.0f},
|
{":/common/resource/view_bottom.png", "下", "仰视", -90.0f, 0.0f, 0.0f},
|
||||||
{":/common/resource/view_robot.png", "机械臂", -90.0f, 90.0f, 0.0f},
|
{":/common/resource/view_robot.png", "机", "机械臂", -90.0f, 90.0f, 0.0f},
|
||||||
};
|
};
|
||||||
|
|
||||||
int btnSize = 32;
|
int btnSize = 32;
|
||||||
@ -1381,8 +1382,13 @@ QWidget* CloudViewMainWindow::createViewToolbar()
|
|||||||
|
|
||||||
for (const auto& preset : presets) {
|
for (const auto& preset : presets) {
|
||||||
QToolButton* btn = new QToolButton(widget);
|
QToolButton* btn = new QToolButton(widget);
|
||||||
btn->setIcon(QIcon(preset.iconPath));
|
const QIcon icon(preset.iconPath);
|
||||||
|
if (icon.isNull()) {
|
||||||
|
btn->setText(QString::fromUtf8(preset.fallbackText));
|
||||||
|
} else {
|
||||||
|
btn->setIcon(icon);
|
||||||
btn->setIconSize(QSize(iconSize, iconSize));
|
btn->setIconSize(QSize(iconSize, iconSize));
|
||||||
|
}
|
||||||
btn->setFixedSize(btnSize, btnSize);
|
btn->setFixedSize(btnSize, btnSize);
|
||||||
btn->setToolTip(preset.tooltip);
|
btn->setToolTip(preset.tooltip);
|
||||||
btn->setAutoRaise(true);
|
btn->setAutoRaise(true);
|
||||||
@ -2379,6 +2385,7 @@ void CloudViewMainWindow::showBasicShape(const QString& shapeName,
|
|||||||
if (!points.isEmpty()) {
|
if (!points.isEmpty()) {
|
||||||
m_glWidget->appendBasicShapePoints(points);
|
m_glWidget->appendBasicShapePoints(points);
|
||||||
}
|
}
|
||||||
|
m_glWidget->fitToContent();
|
||||||
statusBar()->showMessage(QString("已添加 %1").arg(shapeName));
|
statusBar()->showMessage(QString("已添加 %1").arg(shapeName));
|
||||||
LOG_INFO("[CloudView] Add basic shape: %s, segments=%d, points=%d\n",
|
LOG_INFO("[CloudView] Add basic shape: %s, segments=%d, points=%d\n",
|
||||||
shapeName.toStdString().c_str(), segments.size(), points.size());
|
shapeName.toStdString().c_str(), segments.size(), points.size());
|
||||||
@ -2392,6 +2399,7 @@ void CloudViewMainWindow::showBasicSurface(const QString& shapeName, const QVect
|
|||||||
|
|
||||||
m_glWidget->appendBasicShapeSurfaces(surfaces);
|
m_glWidget->appendBasicShapeSurfaces(surfaces);
|
||||||
m_glWidget->appendBasicShapeSegments(outlines);
|
m_glWidget->appendBasicShapeSegments(outlines);
|
||||||
|
m_glWidget->fitToContent();
|
||||||
statusBar()->showMessage(QString("已添加 %1").arg(shapeName));
|
statusBar()->showMessage(QString("已添加 %1").arg(shapeName));
|
||||||
LOG_INFO("[CloudView] Add basic surface: %s, surfaces=%d, outlines=%d\n",
|
LOG_INFO("[CloudView] Add basic surface: %s, surfaces=%d, outlines=%d\n",
|
||||||
shapeName.toStdString().c_str(), surfaces.size(), outlines.size());
|
shapeName.toStdString().c_str(), surfaces.size(), outlines.size());
|
||||||
|
|||||||
@ -65,6 +65,14 @@ int main(int argc, char* argv[])
|
|||||||
parser.addOption(triangleOption);
|
parser.addOption(triangleOption);
|
||||||
parser.addOption(sequenceOption);
|
parser.addOption(sequenceOption);
|
||||||
parser.addPositionalArgument("files", "Point cloud or segment files to load.");
|
parser.addPositionalArgument("files", "Point cloud or segment files to load.");
|
||||||
|
if (app.arguments().contains(QStringLiteral("--help")) ||
|
||||||
|
app.arguments().contains(QStringLiteral("-h"))) {
|
||||||
|
parser.showHelp(0);
|
||||||
|
}
|
||||||
|
if (app.arguments().contains(QStringLiteral("--version")) ||
|
||||||
|
app.arguments().contains(QStringLiteral("-v"))) {
|
||||||
|
parser.showVersion();
|
||||||
|
}
|
||||||
parser.process(app);
|
parser.process(app);
|
||||||
|
|
||||||
CloudViewMainWindow::StartupFiles startupFiles;
|
CloudViewMainWindow::StartupFiles startupFiles;
|
||||||
|
|||||||
@ -4,6 +4,13 @@ CONFIG += c++17 staticlib
|
|||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
TARGET = CloudView3D
|
TARGET = CloudView3D
|
||||||
|
|
||||||
|
win32:CONFIG(debug, debug|release) {
|
||||||
|
DESTDIR = $$PWD/debug
|
||||||
|
}
|
||||||
|
win32:CONFIG(release, debug|release) {
|
||||||
|
DESTDIR = $$PWD/release
|
||||||
|
}
|
||||||
|
|
||||||
win32-msvc {
|
win32-msvc {
|
||||||
QMAKE_CXXFLAGS += /utf-8
|
QMAKE_CXXFLAGS += /utf-8
|
||||||
QMAKE_CXXFLAGS += /bigobj
|
QMAKE_CXXFLAGS += /bigobj
|
||||||
@ -11,8 +18,8 @@ win32-msvc {
|
|||||||
|
|
||||||
INCLUDEPATH += $$PWD/Inc
|
INCLUDEPATH += $$PWD/Inc
|
||||||
INCLUDEPATH += $$PWD/../VrUtils/Inc
|
INCLUDEPATH += $$PWD/../VrUtils/Inc
|
||||||
INCLUDEPATH += $$PWD/../VrCommon/Inc
|
|
||||||
INCLUDEPATH += $$PWD/../../Device/SDK/VzNLSDK/Inc
|
INCLUDEPATH += $$PWD/../../Device/SDK/VzNLSDK/Inc
|
||||||
|
INCLUDEPATH += $$PWD/../VrCommon/Inc
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
Inc/CloudView3D.h \
|
Inc/CloudView3D.h \
|
||||||
|
|||||||
@ -170,6 +170,7 @@ public:
|
|||||||
|
|
||||||
void addPointCloud(const PointCloudXYZ& cloud, const QString& name = "");
|
void addPointCloud(const PointCloudXYZ& cloud, const QString& name = "");
|
||||||
void addPointCloud(const PointCloudXYZRGB& cloud, const QString& name = "");
|
void addPointCloud(const PointCloudXYZRGB& cloud, const QString& name = "");
|
||||||
|
void appendPointCloud(const PointCloudXYZRGB& cloud, const QString& name = "");
|
||||||
void clearPointClouds();
|
void clearPointClouds();
|
||||||
void setPointCloudColor(PointCloudColor color);
|
void setPointCloudColor(PointCloudColor color);
|
||||||
void setPointSize(float size);
|
void setPointSize(float size);
|
||||||
@ -455,6 +456,8 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
void computeBoundingBox();
|
void computeBoundingBox();
|
||||||
|
void updateProjection(const QMatrix4x4& modelView);
|
||||||
|
float minimumCameraDistance() const;
|
||||||
void setCurrentColor(PointCloudColor color);
|
void setCurrentColor(PointCloudColor color);
|
||||||
void setColorByIndex(int colorIndex); // 根据索引设置颜色
|
void setColorByIndex(int colorIndex); // 根据索引设置颜色
|
||||||
SelectedPointInfo pickPoint(int screenX, int screenY);
|
SelectedPointInfo pickPoint(int screenX, int screenY);
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QtMath>
|
#include <QtMath>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
#include <algorithm>
|
||||||
#include <cfloat>
|
#include <cfloat>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include "VrLog.h"
|
#include "VrLog.h"
|
||||||
@ -116,12 +117,6 @@ void PointCloudGLWidget::initializeGL()
|
|||||||
void PointCloudGLWidget::resizeGL(int w, int h)
|
void PointCloudGLWidget::resizeGL(int w, int h)
|
||||||
{
|
{
|
||||||
glViewport(0, 0, w, h);
|
glViewport(0, 0, w, h);
|
||||||
|
|
||||||
m_projection.setToIdentity();
|
|
||||||
float aspect = static_cast<float>(w) / static_cast<float>(h > 0 ? h : 1);
|
|
||||||
// 放大裁剪范围以容纳激光雷达点云(最大可能跨越数十万 mm)
|
|
||||||
// near 取 1.0 保留 depth buffer 精度,far 放到 1e7 避免远点被裁掉
|
|
||||||
m_projection.perspective(45.0f, aspect, 1.0f, 1.0e7f);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointCloudGLWidget::paintGL()
|
void PointCloudGLWidget::paintGL()
|
||||||
@ -146,11 +141,13 @@ void PointCloudGLWidget::paintGL()
|
|||||||
euler.x(), euler.y(), euler.z());
|
euler.x(), euler.y(), euler.z());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QMatrix4x4 modelView = m_view * m_model;
|
||||||
|
|
||||||
glMatrixMode(GL_PROJECTION);
|
glMatrixMode(GL_PROJECTION);
|
||||||
|
updateProjection(modelView);
|
||||||
glLoadMatrixf(m_projection.constData());
|
glLoadMatrixf(m_projection.constData());
|
||||||
|
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
QMatrix4x4 modelView = m_view * m_model;
|
|
||||||
glLoadMatrixf(modelView.constData());
|
glLoadMatrixf(modelView.constData());
|
||||||
|
|
||||||
// 确保颜色数组禁用
|
// 确保颜色数组禁用
|
||||||
@ -440,6 +437,101 @@ void PointCloudGLWidget::addPointCloud(const PointCloudXYZRGB& cloud, const QStr
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PointCloudGLWidget::appendPointCloud(const PointCloudXYZRGB& cloud,
|
||||||
|
const QString& name)
|
||||||
|
{
|
||||||
|
if (cloud.empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (m_pointClouds.empty() || !m_pointClouds.back().hasColor) {
|
||||||
|
addPointCloud(cloud, name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PointCloudData& data = m_pointClouds.back();
|
||||||
|
if (!name.isEmpty()) {
|
||||||
|
data.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool incomingHasLineInfo = !cloud.lineIndices.empty();
|
||||||
|
data.hasLineInfo = data.hasLineInfo || incomingHasLineInfo;
|
||||||
|
const size_t originalIndexOffset = data.vertices.size() / 3;
|
||||||
|
const float epsilon = 1e-6f;
|
||||||
|
int previousLineIndex = -1;
|
||||||
|
int pointInLineIndex = 0;
|
||||||
|
|
||||||
|
for (size_t index = 0; index < cloud.points.size(); ++index) {
|
||||||
|
const Point3DRGB& point = cloud.points[index];
|
||||||
|
int lineIndex = -1;
|
||||||
|
if (incomingHasLineInfo && index < cloud.lineIndices.size()) {
|
||||||
|
lineIndex = cloud.lineIndices[index];
|
||||||
|
}
|
||||||
|
if (lineIndex != previousLineIndex) {
|
||||||
|
pointInLineIndex = 0;
|
||||||
|
previousLineIndex = lineIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!std::isfinite(point.x) || !std::isfinite(point.y) ||
|
||||||
|
!std::isfinite(point.z) ||
|
||||||
|
(std::fabs(point.x) < epsilon &&
|
||||||
|
std::fabs(point.y) < epsilon &&
|
||||||
|
std::fabs(point.z) < epsilon)) {
|
||||||
|
++pointInLineIndex;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t pointIndex = data.vertices.size() / 3;
|
||||||
|
data.vertices.push_back(point.x);
|
||||||
|
data.vertices.push_back(point.y);
|
||||||
|
data.vertices.push_back(point.z);
|
||||||
|
data.colors.push_back(point.r / 255.0f);
|
||||||
|
data.colors.push_back(point.g / 255.0f);
|
||||||
|
data.colors.push_back(point.b / 255.0f);
|
||||||
|
data.originalIndices.push_back(
|
||||||
|
static_cast<int>(originalIndexOffset + index));
|
||||||
|
data.pointInLineIndices.push_back(pointInLineIndex);
|
||||||
|
|
||||||
|
if (lineIndex >= 0) {
|
||||||
|
data.lineIndices.push_back(lineIndex);
|
||||||
|
data.totalLines = qMax(data.totalLines, lineIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (point.pointSize > 1.0f) {
|
||||||
|
auto sizeGroup = std::find_if(
|
||||||
|
data.customPointSizeGroups.begin(),
|
||||||
|
data.customPointSizeGroups.end(),
|
||||||
|
[&point](const PointCloudData::PointSizeGroup& group) {
|
||||||
|
return group.pointSize == point.pointSize;
|
||||||
|
});
|
||||||
|
if (sizeGroup == data.customPointSizeGroups.end()) {
|
||||||
|
PointCloudData::PointSizeGroup group;
|
||||||
|
group.pointSize = point.pointSize;
|
||||||
|
data.customPointSizeGroups.push_back(std::move(group));
|
||||||
|
sizeGroup = data.customPointSizeGroups.end() - 1;
|
||||||
|
}
|
||||||
|
sizeGroup->indices.push_back(pointIndex);
|
||||||
|
data.hasCustomPointSizes = true;
|
||||||
|
}
|
||||||
|
++pointInLineIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.totalLines > 0) {
|
||||||
|
data.pointsPerLine =
|
||||||
|
static_cast<int>(data.vertices.size() / 3) / data.totalLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
makeCurrent();
|
||||||
|
uploadToVBO(data);
|
||||||
|
doneCurrent();
|
||||||
|
|
||||||
|
computeBoundingBox();
|
||||||
|
const QVector3D size = m_maxBound - m_minBound;
|
||||||
|
const float maximumSize = qMax(qMax(size.x(), size.y()), size.z());
|
||||||
|
m_distance = qMax(m_distance,
|
||||||
|
qBound(10.0f, maximumSize * 2.5f, 1.0e7f));
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
void PointCloudGLWidget::clearPointClouds()
|
void PointCloudGLWidget::clearPointClouds()
|
||||||
{
|
{
|
||||||
// 释放所有 VBO
|
// 释放所有 VBO
|
||||||
@ -506,17 +598,81 @@ void PointCloudGLWidget::fitToContent()
|
|||||||
resetView();
|
resetView();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PointCloudGLWidget::updateProjection(const QMatrix4x4& modelView)
|
||||||
|
{
|
||||||
|
const QVector3D corners[] = {
|
||||||
|
{m_minBound.x(), m_minBound.y(), m_minBound.z()},
|
||||||
|
{m_minBound.x(), m_minBound.y(), m_maxBound.z()},
|
||||||
|
{m_minBound.x(), m_maxBound.y(), m_minBound.z()},
|
||||||
|
{m_minBound.x(), m_maxBound.y(), m_maxBound.z()},
|
||||||
|
{m_maxBound.x(), m_minBound.y(), m_minBound.z()},
|
||||||
|
{m_maxBound.x(), m_minBound.y(), m_maxBound.z()},
|
||||||
|
{m_maxBound.x(), m_maxBound.y(), m_minBound.z()},
|
||||||
|
{m_maxBound.x(), m_maxBound.y(), m_maxBound.z()}
|
||||||
|
};
|
||||||
|
|
||||||
|
float minimumDepth = FLT_MAX;
|
||||||
|
float maximumDepth = -FLT_MAX;
|
||||||
|
for (const QVector3D& corner : corners) {
|
||||||
|
const float depth = -modelView.map(corner).z();
|
||||||
|
minimumDepth = qMin(minimumDepth, depth);
|
||||||
|
maximumDepth = qMax(maximumDepth, depth);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float kMinimumNearPlane = 0.01f;
|
||||||
|
float nearPlane = kMinimumNearPlane;
|
||||||
|
float farPlane = 1.0f;
|
||||||
|
if (maximumDepth > kMinimumNearPlane) {
|
||||||
|
// 点云贴近或跨过相机时保持很小的近裁剪距离,避免前侧点被裁掉。
|
||||||
|
if (minimumDepth > kMinimumNearPlane) {
|
||||||
|
nearPlane = qMax(kMinimumNearPlane, minimumDepth * 0.5f);
|
||||||
|
}
|
||||||
|
// 远裁剪面仅覆盖当前内容,并限制 near/far 比值以保证深度缓冲精度。
|
||||||
|
farPlane = qMax(nearPlane + 1.0f, maximumDepth * 1.5f);
|
||||||
|
nearPlane = qMax(nearPlane, farPlane / 100000.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float aspect = static_cast<float>(width()) /
|
||||||
|
static_cast<float>(height() > 0 ? height() : 1);
|
||||||
|
m_projection.setToIdentity();
|
||||||
|
m_projection.perspective(45.0f, aspect, nearPlane, farPlane);
|
||||||
|
}
|
||||||
|
|
||||||
|
float PointCloudGLWidget::minimumCameraDistance() const
|
||||||
|
{
|
||||||
|
const QVector3D corners[] = {
|
||||||
|
{m_minBound.x(), m_minBound.y(), m_minBound.z()},
|
||||||
|
{m_minBound.x(), m_minBound.y(), m_maxBound.z()},
|
||||||
|
{m_minBound.x(), m_maxBound.y(), m_minBound.z()},
|
||||||
|
{m_minBound.x(), m_maxBound.y(), m_maxBound.z()},
|
||||||
|
{m_maxBound.x(), m_minBound.y(), m_minBound.z()},
|
||||||
|
{m_maxBound.x(), m_minBound.y(), m_maxBound.z()},
|
||||||
|
{m_maxBound.x(), m_maxBound.y(), m_minBound.z()},
|
||||||
|
{m_maxBound.x(), m_maxBound.y(), m_maxBound.z()}
|
||||||
|
};
|
||||||
|
|
||||||
|
float frontExtent = 0.0f;
|
||||||
|
for (const QVector3D& corner : corners) {
|
||||||
|
const QVector3D relativePosition = corner - m_center;
|
||||||
|
frontExtent = qMax(frontExtent,
|
||||||
|
m_rotation.rotatedVector(relativePosition).z());
|
||||||
|
}
|
||||||
|
|
||||||
|
const float margin = qMax(0.1f, (m_maxBound - m_minBound).length() * 0.002f);
|
||||||
|
return qBound(0.1f, frontExtent + margin, 1.0e7f);
|
||||||
|
}
|
||||||
|
|
||||||
void PointCloudGLWidget::zoomIn()
|
void PointCloudGLWidget::zoomIn()
|
||||||
{
|
{
|
||||||
m_distance *= 0.9f;
|
m_distance *= 0.9f;
|
||||||
m_distance = qBound(0.1f, m_distance, 1.0e7f);
|
m_distance = qBound(minimumCameraDistance(), m_distance, 1.0e7f);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PointCloudGLWidget::zoomOut()
|
void PointCloudGLWidget::zoomOut()
|
||||||
{
|
{
|
||||||
m_distance *= 1.1f;
|
m_distance *= 1.1f;
|
||||||
m_distance = qBound(0.1f, m_distance, 1.0e7f);
|
m_distance = qBound(minimumCameraDistance(), m_distance, 1.0e7f);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -529,6 +685,7 @@ void PointCloudGLWidget::setViewAngles(float rotX, float rotY, float rotZ)
|
|||||||
|
|
||||||
// 从欧拉角转换为四元数(ZYX顺序)
|
// 从欧拉角转换为四元数(ZYX顺序)
|
||||||
m_rotation = QQuaternion::fromEulerAngles(rotX, rotY, rotZ);
|
m_rotation = QQuaternion::fromEulerAngles(rotX, rotY, rotZ);
|
||||||
|
m_distance = qMax(m_distance, minimumCameraDistance());
|
||||||
|
|
||||||
LOG_INFO("[CloudView] setViewAngles: rotX=%.1f, rotY=%.1f, rotZ=%.1f\n", rotX, rotY, rotZ);
|
LOG_INFO("[CloudView] setViewAngles: rotX=%.1f, rotY=%.1f, rotZ=%.1f\n", rotX, rotY, rotZ);
|
||||||
|
|
||||||
@ -1441,6 +1598,7 @@ void PointCloudGLWidget::mouseMoveEvent(QMouseEvent* event)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 发送角度变化信号
|
// 发送角度变化信号
|
||||||
|
m_distance = qMax(m_distance, minimumCameraDistance());
|
||||||
emit viewAnglesChanged(m_rotationX, m_rotationY, m_rotationZ);
|
emit viewAnglesChanged(m_rotationX, m_rotationY, m_rotationZ);
|
||||||
update();
|
update();
|
||||||
} else if (m_middleButtonPressed) {
|
} else if (m_middleButtonPressed) {
|
||||||
@ -1454,6 +1612,7 @@ void PointCloudGLWidget::mouseMoveEvent(QMouseEvent* event)
|
|||||||
QQuaternion deltaRotation = QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), angle);
|
QQuaternion deltaRotation = QQuaternion::fromAxisAndAngle(QVector3D(0, 0, 1), angle);
|
||||||
m_rotation = deltaRotation * m_rotation;
|
m_rotation = deltaRotation * m_rotation;
|
||||||
m_rotationZ += angle;
|
m_rotationZ += angle;
|
||||||
|
m_distance = qMax(m_distance, minimumCameraDistance());
|
||||||
emit viewAnglesChanged(m_rotationX, m_rotationY, m_rotationZ);
|
emit viewAnglesChanged(m_rotationX, m_rotationY, m_rotationZ);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
@ -1474,7 +1633,7 @@ void PointCloudGLWidget::wheelEvent(QWheelEvent* event)
|
|||||||
{
|
{
|
||||||
float delta = event->angleDelta().y() / 120.0f;
|
float delta = event->angleDelta().y() / 120.0f;
|
||||||
m_distance *= (1.0f - delta * 0.1f);
|
m_distance *= (1.0f - delta * 0.1f);
|
||||||
m_distance = qBound(0.1f, m_distance, 1.0e7f);
|
m_distance = qBound(minimumCameraDistance(), m_distance, 1.0e7f);
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,13 @@ TEMPLATE = lib
|
|||||||
CONFIG += staticlib
|
CONFIG += staticlib
|
||||||
CONFIG += c++17
|
CONFIG += c++17
|
||||||
|
|
||||||
|
win32:CONFIG(debug, debug|release) {
|
||||||
|
DESTDIR = $$PWD/debug
|
||||||
|
}
|
||||||
|
win32:CONFIG(release, debug|release) {
|
||||||
|
DESTDIR = $$PWD/release
|
||||||
|
}
|
||||||
|
|
||||||
# You can make your code fail to compile if it uses deprecated APIs.
|
# You can make your code fail to compile if it uses deprecated APIs.
|
||||||
# In order to do so, uncomment the following line.
|
# In order to do so, uncomment the following line.
|
||||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||||
|
|||||||
@ -8,6 +8,13 @@ DEFINES += LOG4CPP_HAVE_SSTREAM=1
|
|||||||
DEFINES += VR_UTILS_EXPORTS
|
DEFINES += VR_UTILS_EXPORTS
|
||||||
CONFIG += c++11
|
CONFIG += c++11
|
||||||
|
|
||||||
|
win32:CONFIG(debug, debug|release) {
|
||||||
|
DESTDIR = $$PWD/debug
|
||||||
|
}
|
||||||
|
win32:CONFIG(release, debug|release) {
|
||||||
|
DESTDIR = $$PWD/release
|
||||||
|
}
|
||||||
|
|
||||||
# Unix平台特定配置
|
# Unix平台特定配置
|
||||||
unix:!macx {
|
unix:!macx {
|
||||||
DEFINES += LOG4CPP_HAVE_UNISTD_H
|
DEFINES += LOG4CPP_HAVE_UNISTD_H
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user