话说if (null == x)

本文探讨了Java项目中if语句的一种特殊写法,并解释了其源自C/C++的原因。文章分析了这两种语言中if语句的不同处理方式,强调了Java语言特性如何避免了C/C++中常见的错误。
最近看到Java项目的代码中看到这样的语句,
Java代码  收藏代码
  1. if (null == model)  
  2. {  
  3.      ...  
  4. }  

     我问开发这段代码的同事问什么这么写,同事说是编程规范规定的。

 

     但是在Java项目中,不需要这样写,也不应该这样写。

 

     if 的判断语句倒着写,这种写法是从C\C++语言开始的,(获取其它语言更早就有了 :-) )

     在C\C++语言中,数字等于0表示false, 不等于0表示true, 下面的两个if判断代码都是合法的,但是含义却南辕北辙

Cpp代码  收藏代码
  1. // 1 赋值 + 判断  
  2. int count = -1;  
  3. if (count = read())  
  4. {  
  5.      ...  
  6. }  
  7.   
  8. // 2 判断  
  9. int expectedCount = 20;  
  10. if (expectedCount == read())  
  11. {  
  12.      ...  
  13. }  

  人总是会犯错误的,一个不小心,第二段代码就成了

Cpp代码  收藏代码
  1. int expectedCount = 20;  
  2. if (expectedCount = read()) // == 变成了 =  
  3. {  
  4.      ...  
  5. }  

  为了防止这种低级错误,于是就有了编程规范。

Cpp代码  收藏代码
  1. int expectedCount = 20;  
  2. if (read() = expectedCount) // 直接编译错误,就避免了错误的产生  
  3. {  
  4.      ...  
  5. }  

  所以在C、C++项目中有这样的编程规范是正确的。

 

但是在Java项目中,

Java 语言中布尔变量就只有true和false, 数字不能表示布尔.下面的代码编译器是直接报错的,所以就避免了低级错误的发生.

Java代码  收藏代码
  1. int expectedCount = 20;  
  2. if (expectedCount = read()) // 编译器直接报错  
  3. {  
  4.      ...  
  5. }  

 所以在Java项目中,不需要 倒着写; 这样还会降低可读性,所以不应该 倒着写;

#include "mainwindow.h" #include <vtkVertexGlyphFilter.h> #include <vtkProperty.h> #include <vtkMatrix4x4.h> #include <vtkMath.h> #include <vtkInteractorStyleTrackballCamera.h> #include <QVBoxLayout> #include <QHBoxLayout> #include <QImage> #include <QPixmap> #include <QMessageBox> #include <QFileDialog> #include <QKeyEvent> #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/console/print.h> #include <cmath> #include <QApplication> #include <QDebug> #ifdef _WIN32 #include <windows.h> #endif // ImageLabel实现 ImageLabel::ImageLabel(Mw* mainWin, QWidget* parent) : QLabel(parent), m_mainWin(mainWin) { setAlignment(Qt::AlignCenter); setStyleSheet("border:1px solid #444; background:#222; color:#fff;"); setScaledContents(false); setMinimumSize(200, 150); setFocusPolicy(Qt::ClickFocus); } void ImageLabel::setMatImage(const cv::Mat& mat) { if (mat.empty()) { setText("无图像数据"); return; } cv::Mat rgbMat; if (mat.channels() == 3) cv::cvtColor(mat, rgbMat, cv::COLOR_BGR2RGB); else if (mat.channels() == 1) cv::cvtColor(mat, rgbMat, cv::COLOR_GRAY2RGB); else { setText("不支持的图像格式"); return; } QImage qImg(rgbMat.data, rgbMat.cols, rgbMat.rows, static_cast<int>(rgbMat.step), QImage::Format_RGB888); originalPixmap = QPixmap::fromImage(qImg); loadImage(); } void ImageLabel::keyPressEvent(QKeyEvent* event) { emit keyPressed(this, event); QLabel::keyPressEvent(event); } void ImageLabel::resizeEvent(QResizeEvent* event) { QLabel::resizeEvent(event); loadImage(); } void ImageLabel::loadImage() { if (!originalPixmap.isNull()) { QPixmap scaledPix = originalPixmap.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation); setPixmap(scaledPix); setText(""); } } // 主窗口实现 Mw::Mw(QWidget *parent) : QMainWindow(parent) { #ifdef _WIN32 SetConsoleOutputCP(CP_UTF8); #endif setWindowTitle("点云投影查看器"); resize(1200, 800); m_originalCloud.reset(new pcl::PointCloud<pcl::PointXYZ>()); setupUI(); loadDefaultImages(); loadPointCloud(); } Mw::~Mw() { if (pointCloudRenderer) pointCloudRenderer->Delete(); if (cloudActor) cloudActor->Delete(); if (obbActor) obbActor->Delete(); if (axesActor) axesActor->Delete(); if (boxWidget) boxWidget->Delete(); } pcl::PointCloud<pcl::PointXYZ>::ConstPtr Mw::getOriginalCloud() const { return m_originalCloud; } // 调用投影接口(使用PointCloudProjection.h中的结构体和函数) void Mw::callDllProjection(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr& cloud, const std::vector<float>& obbValues) { if (obbValues.size() != 9) { showError("OBB参数数量错误(需9个值)", "错误"); return; } if (!cloud || cloud->empty()) { showError("点云为空或无效", "错误"); return; } float dx = obbValues[6], dy = obbValues[7], dz = obbValues[8]; if (sqrt(dx*dx + dy*dy + dz*dz) < 1e-3f) { showError("OBB范围过小,无法生成投影", "错误"); return; } if (!isOBBContainsPoints(cloud, obbValues) || hasInvalidValues(obbValues)) { showError("OBB参数无效或未包含点云", "错误"); return; } // 使用PointCloudProjection.h中的ProjResult和ObbData ProjResult results[3]; std::vector<ObbData> obbDataList(1); ObbData& obbData = obbDataList[0]; // 填充OBB数据(对应PointCloudProjection.h中的ObbData结构) obbData.pos_x = obbValues[0]; obbData.pos_y = obbValues[1]; obbData.pos_z = obbValues[2]; obbData.rot_x = obbValues[3]; obbData.rot_y = obbValues[4]; obbData.rot_z = obbValues[5]; obbData.scale_x = obbValues[6]; obbData.scale_y = obbValues[7]; obbData.scale_z = obbValues[8]; obbData.obj_type = "custom"; // 调用PointCloudProjection.h中声明的get_proj_results(带use_all_points参数) int ret = get_proj_results(cloud, obbDataList, results, false); if (ret == 0) { // 显示投影图像(使用ProjResult中的img) imgLabel1->setMatImage(results[0].img); imgLabel2->setMatImage(results[1].img); imgLabel3->setMatImage(results[2].img); // 调用PointCloudProjection.h中声明的free_proj_results释放内存 free_proj_results(results); } else { showError(QString("投影失败(错误码: %1)").arg(ret), "动态库调用失败"); } } void Mw::showError(const QString& message, const QString& title) { QMessageBox::critical(this, title, message); std::cerr << "[错误] " << title.toStdString() << ": " << message.toStdString() << std::endl; } void Mw::adjustOBB(float dx, float dy, float dz, float rx, float ry, float rz, float scaleRatio) { if (!boxWidget) return; vtkBoxRepresentation* rep = vtkBoxRepresentation::SafeDownCast(boxWidget->GetRepresentation()); if (!rep) return; // 获取当前变换 vtkNew<vtkTransform> currentTransform; rep->GetTransform(currentTransform); // === 提取原始状态 === double pos[3]; currentTransform->GetPosition(pos); double orient[3]; // in degrees currentTransform->GetOrientation(orient); double scale[3]; currentTransform->GetScale(scale); // 构建新变换:严格按照 T * R * S 顺序(推荐使用 pre-multiply 避免混乱) vtkNew<vtkTransform> newTransform; newTransform->PostMultiply(); // 确保按调用顺序执行 // 1. 应用缩放(仅当需要) if (std::abs(scaleRatio - 1.0f) > 1e-6) { newTransform->Scale(scale[0] * scaleRatio, scale[1] * scaleRatio, scale[2] * scaleRatio); } else { newTransform->Scale(scale[0], scale[1], scale[2]); // 保持原缩放 } // 2. 应用旋转 newTransform->RotateX(orient[0] + rx); newTransform->RotateY(orient[1] + ry); newTransform->RotateZ(orient[2] + rz); // 3. 应用平移(局部→世界) vtkMatrix4x4* mat = newTransform->GetMatrix(); Eigen::Matrix3f rot; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) rot(i,j) = static_cast<float>(mat->GetElement(i,j)); Eigen::Vector3f local(dx, dy, dz); Eigen::Vector3f world = rot * local; newTransform->Translate(pos[0] + world.x(), pos[1] + world.y(), pos[2] + world.z()); // === 更新 === rep->SetTransform(newTransform); obbActor->SetUserTransform(newTransform); vtkWidget->GetRenderWindow()->Render(); } void Mw::updateOBBProjection() { if (!boxWidget || !m_originalCloud || m_originalCloud->empty()) return; vtkTransform* currentTransform = vtkTransform::New(); vtkBoxRepresentation::SafeDownCast(boxWidget->GetRepresentation())->GetTransform(currentTransform); vtkBoxCallback callback; callback.SetMainWindow(this); std::vector<float> obbValues = callback.createOBBValuesFromTransform(currentTransform); callDllProjection(m_originalCloud, obbValues); currentTransform->Delete(); } void Mw::keyPressEvent(QKeyEvent* event) { event->ignore(); } void Mw::onImageLabelKeyPressed(ImageLabel* label, QKeyEvent* event) { int index = -1; if (label == imgLabel1) index = 0; // X+ 视角 else if (label == imgLabel2) index = 1; // Y+ 视角 else if (label == imgLabel3) index = 2; // Z+ 视角 const float TRANSLATE_STEP = 0.5f; const float ROTATE_STEP = 1.0f; const float SCALE_RATIO = 1.1f; switch(event->key()) { // WASD 移动 case Qt::Key_W: if (index == 0) adjustOBB(0, TRANSLATE_STEP, 0, 0, 0, 0, 1.0f); else if (index == 1) adjustOBB(0, 0, TRANSLATE_STEP, 0, 0, 0, 1.0f); else if (index == 2) adjustOBB(0, TRANSLATE_STEP, 0, 0, 0, 0, 1.0f); break; case Qt::Key_S: if (index == 0) adjustOBB(0, -TRANSLATE_STEP, 0, 0, 0, 0, 1.0f); else if (index == 1) adjustOBB(0, 0, -TRANSLATE_STEP, 0, 0, 0, 1.0f); else if (index == 2) adjustOBB(0, -TRANSLATE_STEP, 0, 0, 0, 0, 1.0f); break; case Qt::Key_A: if (index == 0) adjustOBB(0, 0, -TRANSLATE_STEP, 0, 0, 0, 1.0f); else if (index == 1) adjustOBB(-TRANSLATE_STEP, 0, 0, 0, 0, 0, 1.0f); else if (index == 2) adjustOBB(-TRANSLATE_STEP, 0, 0, 0, 0, 0, 1.0f); break; case Qt::Key_D: if (index == 0) adjustOBB(0, 0, TRANSLATE_STEP, 0, 0, 0, 1.0f); else if (index == 1) adjustOBB(TRANSLATE_STEP, 0, 0, 0, 0, 0, 1.0f); else if (index == 2) adjustOBB(TRANSLATE_STEP, 0, 0, 0, 0, 0, 1.0f); break; // QE 旋转 case Qt::Key_Q: if (index == 0) adjustOBB(0, 0, 0, ROTATE_STEP, 0, 0, 1.0f); else if (index == 1) adjustOBB(0, 0, 0, 0, ROTATE_STEP, 0, 1.0f); else if (index == 2) adjustOBB(0, 0, 0, 0, 0, ROTATE_STEP, 1.0f); break; case Qt::Key_E: if (index == 0) adjustOBB(0, 0, 0, -ROTATE_STEP, 0, 0, 1.0f); else if (index == 1) adjustOBB(0, 0, 0, 0, -ROTATE_STEP, 0, 1.0f); else if (index == 2) adjustOBB(0, 0, 0, 0, 0, -ROTATE_STEP, 1.0f); break; // 缩放 case Qt::Key_Equal: adjustOBB(0, 0, 0, 0, 0, 0, SCALE_RATIO); break; case Qt::Key_Minus: adjustOBB(0, 0, 0, 0, 0, 0, 1.0f/SCALE_RATIO); break; default: event->ignore(); return; } updateOBBProjection(); event->accept(); } bool Mw::isOBBContainsPoints(const pcl::PointCloud<pcl::PointXYZ>::ConstPtr& cloud, const std::vector<float>& obbValues) { float cx = obbValues[0], cy = obbValues[1], cz = obbValues[2]; float rx = obbValues[3], ry = obbValues[4], rz = obbValues[5]; float hx = obbValues[6]/2, hy = obbValues[7]/2, hz = obbValues[8]/2; Eigen::Matrix3f rot; rot = Eigen::AngleAxisf(rx, Eigen::Vector3f::UnitX()).toRotationMatrix() * Eigen::AngleAxisf(ry, Eigen::Vector3f::UnitY()).toRotationMatrix() * Eigen::AngleAxisf(rz, Eigen::Vector3f::UnitZ()).toRotationMatrix(); Eigen::Matrix3f invRot = rot.inverse(); size_t checkCount = std::min(cloud->size(), (size_t)10000); for (size_t i = 0; i < checkCount; ++i) { const auto& pt = cloud->points[i]; if (std::isnan(pt.x) || std::isnan(pt.y) || std::isnan(pt.z)) continue; Eigen::Vector3f p(pt.x - cx, pt.y - cy, pt.z - cz); Eigen::Vector3f pLocal = invRot * p; if (fabs(pLocal.x()) <= hx + 1e-4f && fabs(pLocal.y()) <= hy + 1e-4f && fabs(pLocal.z()) <= hz + 1e-4f) { return true; } } return false; } bool Mw::hasInvalidValues(const std::vector<float>& values) { for (float v : values) if (std::isnan(v) || std::isinf(v)) return true; return false; } void Mw::setupUI() { QWidget* centralWidget = new QWidget(this); QVBoxLayout* mainLayout = new QVBoxLayout(centralWidget); setCentralWidget(centralWidget); // VTK显示区域 vtkWidget = new QVTKWidget(this); vtkWidget->setMinimumHeight(400); mainLayout->addWidget(vtkWidget); // 渲染器与相机设置 pointCloudRenderer = vtkRenderer::New(); pointCloudRenderer->SetBackground(0.1, 0.1, 0.1); vtkWidget->GetRenderWindow()->AddRenderer(pointCloudRenderer); vtkCamera* camera = pointCloudRenderer->GetActiveCamera(); camera->ParallelProjectionOn(); camera->SetPosition(30, 30, 30); camera->SetFocalPoint(0, 0, 0); camera->SetViewUp(0, 1, 0); camera->SetParallelScale(15); pointCloudRenderer->ResetCameraClippingRange(); // 坐标轴 axesActor = vtkAxesActor::New(); axesActor->SetTotalLength(3, 3, 3); pointCloudRenderer->AddActor(axesActor); // 图像显示区域 QHBoxLayout* imagesLayout = new QHBoxLayout(); imagesLayout->setStretch(0, 1); imagesLayout->setStretch(1, 1); imagesLayout->setStretch(2, 1); mainLayout->addLayout(imagesLayout); imgLabel1 = new ImageLabel(this, this); imgLabel2 = new ImageLabel(this, this); imgLabel3 = new ImageLabel(this, this); connect(imgLabel1, &ImageLabel::keyPressed, this, &Mw::onImageLabelKeyPressed); connect(imgLabel2, &ImageLabel::keyPressed, this, &Mw::onImageLabelKeyPressed); connect(imgLabel3, &ImageLabel::keyPressed, this, &Mw::onImageLabelKeyPressed); imagesLayout->addWidget(imgLabel1); imagesLayout->addWidget(imgLabel2); imagesLayout->addWidget(imgLabel3); imgLabel1->setText("X+ 视角"); imgLabel2->setText("Y+ 视角"); imgLabel3->setText("Z+ 视角"); } void Mw::loadDefaultImages() { cv::Mat defaultImg(640, 1280, CV_8UC3, cv::Scalar(50, 50, 50)); cv::putText(defaultImg, "OBB", cv::Point(400, 320), cv::FONT_HERSHEY_SIMPLEX, 1.2, cv::Scalar(200, 200, 200), 2); imgLabel1->setMatImage(defaultImg); imgLabel2->setMatImage(defaultImg); imgLabel3->setMatImage(defaultImg); } bool Mw::loadPointCloud() { QString pcdPath = QFileDialog::getOpenFileName( this, "选择点云文件", "", "PCD Files (*.pcd)" ); if (pcdPath.isEmpty()) { showError("未选择点云文件", "提示"); return false; } pcl::console::setVerbosityLevel(pcl::console::L_ERROR); if (pcl::io::loadPCDFile<pcl::PointXYZ>(pcdPath.toStdString(), *m_originalCloud) == -1) { showError("点云加载失败", "错误"); return false; } if (m_originalCloud->empty()) { showError("点云为空", "错误"); return false; } // 点云转VTK格式 vtkSmartPointer<vtkPoints> cloudPoints = vtkSmartPointer<vtkPoints>::New(); for (const auto& pt : m_originalCloud->points) if (!std::isnan(pt.x) && !std::isnan(pt.y) && !std::isnan(pt.z)) cloudPoints->InsertNextPoint(pt.x, pt.y, pt.z); vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New(); polyData->SetPoints(cloudPoints); vtkSmartPointer<vtkVertexGlyphFilter> glyphFilter = vtkSmartPointer<vtkVertexGlyphFilter>::New(); glyphFilter->SetInputData(polyData); glyphFilter->Update(); vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New(); mapper->SetInputConnection(glyphFilter->GetOutputPort()); cloudActor = vtkActor::New(); cloudActor->SetMapper(mapper); cloudActor->GetProperty()->SetPointSize(1); cloudActor->GetProperty()->SetColor(1.0, 1.0, 1.0); pointCloudRenderer->AddActor(cloudActor); pointCloudRenderer->ResetCamera(); initBoxWidget(); vtkWidget->GetRenderWindow()->Render(); return true; } // 单面色立方体生成(用于OBB可视化,单个面红色标识方向) vtkSmartPointer<vtkPolyData> Mw::createSingleColoredCube() { // 立方体顶点坐标 double cubeVerts[8][3] = { {-0.5, -0.5, -0.5}, {0.5, -0.5, -0.5}, {0.5, 0.5, -0.5}, {-0.5, 0.5, -0.5}, // 前面(Z-)- 染色面 {-0.5, -0.5, 0.5}, {0.5, -0.5, 0.5}, {0.5, 0.5, 0.5}, {-0.5, 0.5, 0.5} // 其他面 }; // 面索引 vtkIdType faces[6][4] = { {0, 1, 2, 3}, // 前面(Z-) {4, 5, 6, 7}, // 后面(Z+) {0, 1, 5, 4}, // 下面(Y-) {2, 3, 7, 6}, // 上面(Y+) {0, 3, 7, 4}, // 左面(X-) {1, 2, 6, 5} // 右面(X+) }; // 颜色(仅前面有颜色,其他面透明) unsigned char colors[6][4] = { {0, 0, 0, 0}, // 其他面:全透明 {0, 255, 0, 200}, {0, 0, 0, 0}, {0, 0, 0, 0}, {255, 0, 0, 200}, // 前面:红色半透明(RGBA) {0, 0, 0, 0} }; // 创建点集 vtkSmartPointer<vtkPoints> cubePoints = vtkSmartPointer<vtkPoints>::New(); for (auto& p : cubeVerts) cubePoints->InsertNextPoint(p); // 创建面集 vtkSmartPointer<vtkCellArray> cubeFaces = vtkSmartPointer<vtkCellArray>::New(); for (auto& f : faces) cubeFaces->InsertNextCell(4, f); // 颜色数组(VTK 8.1兼容写法) vtkSmartPointer<vtkUnsignedCharArray> faceColors = vtkSmartPointer<vtkUnsignedCharArray>::New(); faceColors->SetNumberOfComponents(4); faceColors->SetName("FaceColors"); for (int i = 0; i < 6; ++i) { faceColors->InsertNextValue(colors[i][0]); // R faceColors->InsertNextValue(colors[i][1]); // G faceColors->InsertNextValue(colors[i][2]); // B faceColors->InsertNextValue(colors[i][3]); // A } // 组装PolyData vtkSmartPointer<vtkPolyData> cube = vtkSmartPointer<vtkPolyData>::New(); cube->SetPoints(cubePoints); cube->SetPolys(cubeFaces); cube->GetCellData()->SetScalars(faceColors); return cube; } void Mw::initBoxWidget() { // 加载单面色立方体作为OBB可视化载体 vtkSmartPointer<vtkPolyData> singleColoredCube = createSingleColoredCube(); vtkSmartPointer<vtkPolyDataMapper> cubeMapper = vtkSmartPointer<vtkPolyDataMapper>::New(); cubeMapper->SetInputData(singleColoredCube); cubeMapper->SetScalarModeToUseCellData(); // 使用面颜色数据 obbActor = vtkActor::New(); obbActor->SetMapper(cubeMapper); obbActor->GetProperty()->SetEdgeColor(0, 1, 0); // 线框绿色 obbActor->GetProperty()->SetLineWidth(2); obbActor->GetProperty()->SetRepresentationToSurface(); // 表面渲染 obbActor->GetProperty()->SetOpacity(0.8); // 半透明,避免遮挡点云 pointCloudRenderer->AddActor(obbActor); // OBB交互控件 boxWidget = vtkBoxWidget2::New(); boxWidget->SetInteractor(vtkWidget->GetRenderWindow()->GetInteractor()); double bounds[6]; singleColoredCube->GetBounds(bounds); vtkBoxRepresentation* boxRep = vtkBoxRepresentation::New(); boxRep->SetPlaceFactor(1.0); boxRep->PlaceWidget(bounds); boxWidget->SetRepresentation(boxRep); boxRep->Delete(); // 设置交互框样式 boxRep = vtkBoxRepresentation::SafeDownCast(boxWidget->GetRepresentation()); boxRep->GetOutlineProperty()->SetColor(1, 1, 0); // 交互框黄色 boxRep->GetOutlineProperty()->SetLineWidth(2); // 绑定交互回调 vtkBoxCallback* callback = vtkBoxCallback::New(); callback->SetMainWindow(this); callback->SetActor(obbActor); boxWidget->AddObserver(vtkCommand::InteractionEvent, callback); boxWidget->AddObserver(vtkCommand::EndInteractionEvent, callback); callback->Delete(); // 相机交互样式 vtkSmartPointer<vtkInteractorStyleTrackballCamera> style = vtkSmartPointer<vtkInteractorStyleTrackballCamera>::New(); vtkWidget->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style); boxWidget->On(); // 启用交互 } // vtkBoxCallback实现(OBB交互回调) void vtkBoxCallback::Execute(vtkObject* caller, unsigned long eventId, void*) { if (!m_actor || !m_mainWin) return; // 获取交互控件和变换矩阵 vtkBoxWidget2* boxWidget = vtkBoxWidget2::SafeDownCast(caller); vtkTransform* transform = vtkTransform::New(); vtkBoxRepresentation::SafeDownCast(boxWidget->GetRepresentation())->GetTransform(transform); // 更新OBB演员的变换 m_actor->SetUserTransform(transform); // 交互结束后触发投影 if (eventId == vtkCommand::EndInteractionEvent) { auto cloud = m_mainWin->getOriginalCloud(); if (cloud && !cloud->empty()) { // std::vector<float> obbValues = createOBBValuesFromTransform(transform); std::vector<float> obbValues = getOBBFromBoxWidget(boxWidget); m_mainWin->callDllProjection(cloud, obbValues); boxWidget->GetInteractor()->GetRenderWindow()->Render(); } } transform->Delete(); } // 从VTK变换生成OBB参数(适配PointCloudProjection.h的ObbData) std::vector<float> vtkBoxCallback::createOBBValuesFromTransform(vtkTransform* transform) { std::vector<float> obbValues(9, 0.0f); const float INIT_CUBE_SIZE = 1.0f; // 你原始设定的初始立方体基准尺寸 const float MIN_SCALE = 1e-3f; // 你原始设定的最小缩放阈值 const float MAX_SCALE_FACTOR = 1000.0f; // 你原始设定的最大缩放阈值 // 1. 提取OBB中心点坐标(逻辑完全一致) double center[3]; transform->GetPosition(center); obbValues[0] = static_cast<float>(center[0]); // pos_x obbValues[1] = static_cast<float>(center[1]); // pos_y obbValues[2] = static_cast<float>(center[2]); // pos_z // 2. 提取旋转角(roll, pitch, yaw,弧度)(逻辑完全一致) vtkMatrix4x4* mat = transform->GetMatrix(); double rotMat[9] = { mat->GetElement(0,0), mat->GetElement(0,1), mat->GetElement(0,2), mat->GetElement(1,0), mat->GetElement(1,1), mat->GetElement(1,2), mat->GetElement(2,0), mat->GetElement(2,1), mat->GetElement(2,2) }; double roll = 0.0, pitch = 0.0, yaw = 0.0; const double eps = 1e-8; if (rotMat[6] < 1.0 - eps) { if (rotMat[6] > -1.0 + eps) { pitch = asin(-rotMat[6]); roll = atan2(rotMat[7], rotMat[8]); yaw = atan2(rotMat[2], rotMat[0]); } else { pitch = -vtkMath::Pi() / 2.0; roll = -atan2(-rotMat[1], rotMat[4]); } } else { pitch = vtkMath::Pi() / 2.0; roll = atan2(-rotMat[1], rotMat[4]); } obbValues[3] = static_cast<float>(roll); // rot_x(你原始映射:roll对应rot_x) obbValues[4] = static_cast<float>(pitch); // rot_y(你原始映射:pitch对应rot_y) obbValues[5] = static_cast<float>(yaw); // rot_z(你原始映射:yaw对应rot_z) // 3. 提取缩放尺寸(你原始的核心逻辑:缩放值 × 初始立方体尺寸) double scale[3]; transform->GetScale(scale); // 你原始的缩放值处理逻辑:取绝对值、限制最大范围 auto processScale = [&](double rawScale) { return std::min(std::fabs(static_cast<float>(rawScale)), MAX_SCALE_FACTOR); }; // 你原始的尺寸计算:处理后的缩放值 × 初始立方体尺寸,再限制最小范围 obbValues[6] = std::max(processScale(scale[0]) * INIT_CUBE_SIZE, MIN_SCALE); // scale_x obbValues[7] = std::max(processScale(scale[1]) * INIT_CUBE_SIZE, MIN_SCALE); // scale_y obbValues[8] = std::max(processScale(scale[2]) * INIT_CUBE_SIZE, MIN_SCALE); // scale_z return obbValues; } std::vector<float> vtkBoxCallback::getOBBFromBoxWidget(vtkBoxWidget2* boxWidget) { std::vector<float> obb(9, 0.0f); // center[3] + rpy_rad[3] + half_extents[3] vtkBoxRepresentation* rep = vtkBoxRepresentation::SafeDownCast(boxWidget->GetRepresentation()); if (!rep) { qDebug() << "Failed to get representation."; return obb; } // --- Step 1: 获取变换(用于中心和旋转) vtkNew<vtkTransform> transform; rep->GetTransform(transform); // 这个函数在 VTK 8.1 存在 // 提取位置(即 OBB 中心) double pos[3]; transform->GetPosition(pos); obb[0] = static_cast<float>(pos[0]); obb[1] = static_cast<float>(pos[1]); obb[2] = static_cast<float>(pos[2]); // 提取欧拉角(注意:单位是 degree) double rpy_deg[3]; transform->GetOrientation(rpy_deg); // ZYX 顺序:Yaw Pitch Roll(角度制) obb[3] = static_cast<float>(rpy_deg[0] * M_PI / 180.0); // roll (x) obb[4] = static_cast<float>(rpy_deg[1] * M_PI / 180.0); // pitch (y) obb[5] = static_cast<float>(rpy_deg[2] * M_PI / 180.0); // yaw (z) // --- Step 2: 获取包围盒尺寸(使用 GetBounds 返回值) double* rawBounds = rep->GetBounds(); // ✅ 返回 double*,不要传参! bool valid = true; for (int i = 0; i < 6; ++i) { if (!std::isfinite(rawBounds[i])) { valid = false; break; } } if (valid && rawBounds[0] <= rawBounds[1]) { float sizeX = static_cast<float>((rawBounds[1] - rawBounds[0]) * 0.5f); float sizeY = static_cast<float>((rawBounds[3] - rawBounds[2]) * 0.5f); float sizeZ = static_cast<float>((rawBounds[5] - rawBounds[4]) * 0.5f); obb[6] = std::max(sizeX, 1e-3f); obb[7] = std::max(sizeY, 1e-3f); obb[8] = std::max(sizeZ, 1e-3f); } else { // 如果 bounds 无效,使用默认半长 obb[6] = obb[7] = obb[8] = 0.5f; } return obb; } int main(int argc, char *argv[]) { QApplication a(argc, argv); Mw w; w.show(); return a.exec(); } 你写好那个函数就还好,不要画蛇添足
10-26
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值