|
|
|
|
@ -4,6 +4,8 @@
|
|
|
|
|
#include "nmVTKImageExporter.h"
|
|
|
|
|
#include "nmVTKInteractionManager.h"
|
|
|
|
|
#include "nmVTKOrientationMarkerController.h"
|
|
|
|
|
#include "nmVTKRotationCenterMarkerLayer.h"
|
|
|
|
|
#include "nmVTKRotationCenterPicker.h"
|
|
|
|
|
#include "nmVTKScene.h"
|
|
|
|
|
#include "nmVTKViewCommandController.h"
|
|
|
|
|
|
|
|
|
|
@ -16,6 +18,7 @@
|
|
|
|
|
#include <QMouseEvent>
|
|
|
|
|
#include <QStackedWidget>
|
|
|
|
|
#include <QThread>
|
|
|
|
|
#include <QTimer>
|
|
|
|
|
#include <QVBoxLayout>
|
|
|
|
|
#include <QVTKWidget.h>
|
|
|
|
|
|
|
|
|
|
@ -28,6 +31,13 @@ VTK_MODULE_INIT(vtkInteractionStyle)
|
|
|
|
|
#include <vtkRenderWindow.h>
|
|
|
|
|
#include <vtkRenderWindowInteractor.h>
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
const char* const ROTATION_CENTER_MARKER_LAYER_ID =
|
|
|
|
|
"nm.render.rotation_center_marker";
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmWxVTKRenderContainerWidget::nmWxVTKRenderContainerWidget(QWidget* pParent)
|
|
|
|
|
: QWidget(pParent),
|
|
|
|
|
m_pMainLayout(nullptr),
|
|
|
|
|
@ -37,11 +47,14 @@ nmWxVTKRenderContainerWidget::nmWxVTKRenderContainerWidget(QWidget* pParent)
|
|
|
|
|
m_pVtkWidget(nullptr),
|
|
|
|
|
m_pRenderer(nullptr),
|
|
|
|
|
m_pScene(nullptr),
|
|
|
|
|
m_pSystemScene(nullptr),
|
|
|
|
|
m_pCameraController(nullptr),
|
|
|
|
|
m_pInteractionManager(nullptr),
|
|
|
|
|
m_pImageExporter(nullptr),
|
|
|
|
|
m_pViewCommandController(nullptr),
|
|
|
|
|
m_pOrientationMarkerController(nullptr)
|
|
|
|
|
m_pOrientationMarkerController(nullptr),
|
|
|
|
|
m_pRotationCenterPicker(nullptr),
|
|
|
|
|
m_pRotationCenterMarkerLayer(nullptr)
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
|
|
|
|
|
@ -79,9 +92,26 @@ nmWxVTKRenderContainerWidget::nmWxVTKRenderContainerWidget(QWidget* pParent)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. 管理对象、图片服务和命令对象均只服务当前容器实例。
|
|
|
|
|
// 业务图层和容器内部装饰分别管理;公开业务清场不会删除系统 Marker。
|
|
|
|
|
m_pScene = new nmVTKScene(m_pRenderer);
|
|
|
|
|
m_pSystemScene = new nmVTKScene(m_pRenderer);
|
|
|
|
|
m_pCameraController = new nmVTKCameraController(m_pRenderer);
|
|
|
|
|
m_pInteractionManager = new nmVTKInteractionManager();
|
|
|
|
|
m_pInteractionManager = new nmVTKInteractionManager(
|
|
|
|
|
m_pCameraController);
|
|
|
|
|
nmVTKRotationCenterMarkerLayer* pRotationCenterMarkerLayer =
|
|
|
|
|
new nmVTKRotationCenterMarkerLayer(
|
|
|
|
|
ROTATION_CENTER_MARKER_LAYER_ID);
|
|
|
|
|
if(m_pSystemScene != nullptr &&
|
|
|
|
|
m_pSystemScene->addLayer(pRotationCenterMarkerLayer)) {
|
|
|
|
|
if(pRotationCenterMarkerLayer->bindRenderer(m_pRenderer)) {
|
|
|
|
|
m_pRotationCenterMarkerLayer = pRotationCenterMarkerLayer;
|
|
|
|
|
} else {
|
|
|
|
|
m_pSystemScene->removeLayer(ROTATION_CENTER_MARKER_LAYER_ID);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
delete pRotationCenterMarkerLayer;
|
|
|
|
|
}
|
|
|
|
|
m_pRotationCenterPicker = new nmVTKRotationCenterPicker();
|
|
|
|
|
m_pImageExporter = new nmVTKImageExporter();
|
|
|
|
|
m_pImageExporter->setRenderWindow(pRenderWindow);
|
|
|
|
|
m_pViewCommandController =
|
|
|
|
|
@ -103,8 +133,13 @@ nmWxVTKRenderContainerWidget::nmWxVTKRenderContainerWidget(QWidget* pParent)
|
|
|
|
|
connect(m_pViewCommandController,
|
|
|
|
|
SIGNAL(contextMenuAboutToShow(QMenu*)),
|
|
|
|
|
this, SIGNAL(contextMenuAboutToShow(QMenu*)));
|
|
|
|
|
connect(this, SIGNAL(rotationCenterPickingChanged(bool)),
|
|
|
|
|
m_pViewCommandController,
|
|
|
|
|
SLOT(setRotationCenterPicking(bool)));
|
|
|
|
|
const bool bInteractionReady =
|
|
|
|
|
m_pInteractionManager->bindInteractor(pInteractor);
|
|
|
|
|
m_pInteractionManager->bindInteractor(
|
|
|
|
|
pInteractor, m_pRenderer);
|
|
|
|
|
updateRotationCenterCommandAvailability();
|
|
|
|
|
|
|
|
|
|
// 方向轴是独立辅助 Renderer;绑定失败只隐藏方向轴,不影响主视图初始化。
|
|
|
|
|
m_pOrientationMarkerController =
|
|
|
|
|
@ -138,42 +173,60 @@ nmWxVTKRenderContainerWidget::~nmWxVTKRenderContainerWidget()
|
|
|
|
|
m_pViewCommandController = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 3. MarkerWidget 持有 Interactor 和辅助 Renderer 引用,必须优先解绑。
|
|
|
|
|
// 3. 拾取器先恢复光标;场景标记必须在 Camera 和 Renderer 前解除观察关系。
|
|
|
|
|
if(m_pRotationCenterPicker != nullptr) {
|
|
|
|
|
m_pRotationCenterPicker->reset();
|
|
|
|
|
delete m_pRotationCenterPicker;
|
|
|
|
|
m_pRotationCenterPicker = nullptr;
|
|
|
|
|
}
|
|
|
|
|
nmVTKRotationCenterMarkerLayer* pRotationCenterMarkerLayer =
|
|
|
|
|
getRotationCenterMarkerLayer();
|
|
|
|
|
if(pRotationCenterMarkerLayer != nullptr) {
|
|
|
|
|
pRotationCenterMarkerLayer->unbindRenderer();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. MarkerWidget 持有 Interactor 和辅助 Renderer 引用,必须优先解绑。
|
|
|
|
|
if(m_pOrientationMarkerController != nullptr) {
|
|
|
|
|
m_pOrientationMarkerController->unbindInteractor();
|
|
|
|
|
delete m_pOrientationMarkerController;
|
|
|
|
|
m_pOrientationMarkerController = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 4. 图片服务不拥有 RenderWindow,先解除引用再销毁服务。
|
|
|
|
|
// 5. 图片服务不拥有 RenderWindow,先解除引用再销毁服务。
|
|
|
|
|
if(m_pImageExporter != nullptr) {
|
|
|
|
|
m_pImageExporter->setRenderWindow(nullptr);
|
|
|
|
|
delete m_pImageExporter;
|
|
|
|
|
m_pImageExporter = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 5. Interactor 必须先释放对默认 Style 的 VTK 引用。
|
|
|
|
|
// 6. Interactor 必须先释放对默认 Style 的 VTK 引用。
|
|
|
|
|
if(m_pInteractionManager != nullptr) {
|
|
|
|
|
m_pInteractionManager->unbindInteractor();
|
|
|
|
|
delete m_pInteractionManager;
|
|
|
|
|
m_pInteractionManager = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6. Scene 在 Renderer 移除前清空所有 Layer 和 Prop。
|
|
|
|
|
// 7. 两个 Scene 均在 Camera 和 Renderer 前清空;系统装饰先解除所有权。
|
|
|
|
|
if(m_pSystemScene != nullptr) {
|
|
|
|
|
m_pRotationCenterMarkerLayer = nullptr;
|
|
|
|
|
m_pSystemScene->clear();
|
|
|
|
|
delete m_pSystemScene;
|
|
|
|
|
m_pSystemScene = nullptr;
|
|
|
|
|
}
|
|
|
|
|
if(m_pScene != nullptr) {
|
|
|
|
|
m_pScene->clear();
|
|
|
|
|
delete m_pScene;
|
|
|
|
|
m_pScene = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 7. 相机控制器仅解除 Renderer 非所有权引用。
|
|
|
|
|
// 8. 相机控制器仅解除 Renderer 非所有权引用。
|
|
|
|
|
if(m_pCameraController != nullptr) {
|
|
|
|
|
m_pCameraController->setRenderer(nullptr);
|
|
|
|
|
delete m_pCameraController;
|
|
|
|
|
m_pCameraController = nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 8. 最后从 RenderWindow 移除并释放当前实例 Renderer。
|
|
|
|
|
// 9. 最后从 RenderWindow 移除并释放当前实例 Renderer。
|
|
|
|
|
vtkRenderWindow* pRenderWindow = getRenderWindow();
|
|
|
|
|
if(pRenderWindow != nullptr && m_pRenderer != nullptr) {
|
|
|
|
|
pRenderWindow->RemoveRenderer(m_pRenderer);
|
|
|
|
|
@ -224,32 +277,84 @@ nmWxVTKRenderContainerWidget::getOrientationMarkerController() const
|
|
|
|
|
void nmWxVTKRenderContainerWidget::setViewCommandCapabilities(
|
|
|
|
|
nmVTKViewCommandController::ViewCommands eCommands)
|
|
|
|
|
{
|
|
|
|
|
if(!eCommands.testFlag(
|
|
|
|
|
nmVTKViewCommandController::ViewCommand_SetRotationCenter)) {
|
|
|
|
|
// 能力移除前先结束模式,QAction 仅在随后同步隐藏和禁用。
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
}
|
|
|
|
|
if(m_pViewCommandController != nullptr) {
|
|
|
|
|
m_pViewCommandController->setCapabilities(eCommands);
|
|
|
|
|
}
|
|
|
|
|
updateRotationCenterMarkerVisibility();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::setRotationCenterPickTarget(
|
|
|
|
|
vtkProp* pTarget)
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
if(!isGuiThread() || m_pRotationCenterPicker == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(pTarget == nullptr ||
|
|
|
|
|
m_pRotationCenterPicker->getPickTarget() != pTarget) {
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
m_pRotationCenterPicker->setPickTarget(pTarget);
|
|
|
|
|
}
|
|
|
|
|
if(pTarget == nullptr) {
|
|
|
|
|
hideRotationCenterMarker();
|
|
|
|
|
}
|
|
|
|
|
updateRotationCenterCommandAvailability();
|
|
|
|
|
updateRotationCenterMarkerVisibility();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmWxVTKRenderContainerWidget::isRotationCenterPicking() const
|
|
|
|
|
{
|
|
|
|
|
return m_pRotationCenterPicker != nullptr &&
|
|
|
|
|
m_pRotationCenterPicker->isActive();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::hideRotationCenterMarker()
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
nmVTKRotationCenterMarkerLayer* pMarkerLayer =
|
|
|
|
|
getRotationCenterMarkerLayer();
|
|
|
|
|
if(isGuiThread() && pMarkerLayer != nullptr) {
|
|
|
|
|
pMarkerLayer->setMarkerVisible(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmWxVTKRenderContainerWidget::installInteractionStyle(
|
|
|
|
|
vtkInteractorStyle* pStyle)
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
return isGuiThread() && m_pInteractionManager != nullptr &&
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
const bool bSucceeded = isGuiThread() &&
|
|
|
|
|
m_pInteractionManager != nullptr &&
|
|
|
|
|
m_pInteractionManager->installInteractionStyle(pStyle);
|
|
|
|
|
updateRotationCenterCommandAvailability();
|
|
|
|
|
return bSucceeded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmWxVTKRenderContainerWidget::restoreDefaultInteraction()
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
return isGuiThread() && m_pInteractionManager != nullptr &&
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
const bool bSucceeded = isGuiThread() &&
|
|
|
|
|
m_pInteractionManager != nullptr &&
|
|
|
|
|
m_pInteractionManager->restoreDefaultInteraction();
|
|
|
|
|
updateRotationCenterCommandAvailability();
|
|
|
|
|
return bSucceeded;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::clearInteractionStyle()
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(isGuiThread() && m_pInteractionManager != nullptr) {
|
|
|
|
|
m_pInteractionManager->clearInteractionStyle();
|
|
|
|
|
}
|
|
|
|
|
updateRotationCenterCommandAvailability();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::renderView()
|
|
|
|
|
@ -258,6 +363,7 @@ void nmWxVTKRenderContainerWidget::renderView()
|
|
|
|
|
vtkRenderWindow* pRenderWindow = getRenderWindow();
|
|
|
|
|
// Scene、Layer 和相机均不隐式渲染,批量更新最终汇聚到此入口。
|
|
|
|
|
if(isGuiThread() && pRenderWindow != nullptr) {
|
|
|
|
|
synchronizeRotationCenterMarker();
|
|
|
|
|
pRenderWindow->Render();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -265,11 +371,29 @@ void nmWxVTKRenderContainerWidget::renderView()
|
|
|
|
|
bool nmWxVTKRenderContainerWidget::fitTopViewWithoutRender()
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
// 相机控制器本身不触发 Render,便于业务图层完成整批更新后只渲染一次。
|
|
|
|
|
return isGuiThread() && m_pCameraController != nullptr &&
|
|
|
|
|
m_pCameraController->setTopView();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmWxVTKRenderContainerWidget::resetRotationCenterWithoutRender()
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(!isGuiThread() || m_pCameraController == nullptr ||
|
|
|
|
|
!m_pCameraController->resetRotationCenter()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
double dCenter[3];
|
|
|
|
|
if(!m_pCameraController->getRotationCenter(dCenter)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return applyRotationCenter(
|
|
|
|
|
dCenter[0], dCenter[1], dCenter[2], true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::showReadyState()
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
@ -281,6 +405,7 @@ void nmWxVTKRenderContainerWidget::showReadyState()
|
|
|
|
|
if(m_pViewCommandController != nullptr) {
|
|
|
|
|
m_pViewCommandController->setViewAvailable(true);
|
|
|
|
|
}
|
|
|
|
|
updateRotationCenterMarkerVisibility();
|
|
|
|
|
if(m_pOrientationMarkerController != nullptr) {
|
|
|
|
|
m_pOrientationMarkerController->setViewAvailable(true);
|
|
|
|
|
}
|
|
|
|
|
@ -305,6 +430,7 @@ void nmWxVTKRenderContainerWidget::showRenderingState(
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::zoomIn()
|
|
|
|
|
{
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(m_pCameraController != nullptr && m_pCameraController->zoomIn()) {
|
|
|
|
|
renderView();
|
|
|
|
|
}
|
|
|
|
|
@ -312,6 +438,7 @@ void nmWxVTKRenderContainerWidget::zoomIn()
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::zoomOut()
|
|
|
|
|
{
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(m_pCameraController != nullptr && m_pCameraController->zoomOut()) {
|
|
|
|
|
renderView();
|
|
|
|
|
}
|
|
|
|
|
@ -319,6 +446,7 @@ void nmWxVTKRenderContainerWidget::zoomOut()
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::fitView()
|
|
|
|
|
{
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(m_pCameraController != nullptr && m_pCameraController->fitView()) {
|
|
|
|
|
renderView();
|
|
|
|
|
}
|
|
|
|
|
@ -326,6 +454,7 @@ void nmWxVTKRenderContainerWidget::fitView()
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::resetCamera()
|
|
|
|
|
{
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
// 控制器用返回值表示相机是否确实改变,成功时只提交一次渲染。
|
|
|
|
|
if(m_pCameraController != nullptr && m_pCameraController->resetCamera()) {
|
|
|
|
|
renderView();
|
|
|
|
|
@ -334,6 +463,7 @@ void nmWxVTKRenderContainerWidget::resetCamera()
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::setTopView()
|
|
|
|
|
{
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(m_pCameraController != nullptr && m_pCameraController->setTopView()) {
|
|
|
|
|
renderView();
|
|
|
|
|
}
|
|
|
|
|
@ -341,6 +471,7 @@ void nmWxVTKRenderContainerWidget::setTopView()
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::setFrontView()
|
|
|
|
|
{
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(m_pCameraController != nullptr && m_pCameraController->setFrontView()) {
|
|
|
|
|
renderView();
|
|
|
|
|
}
|
|
|
|
|
@ -348,6 +479,7 @@ void nmWxVTKRenderContainerWidget::setFrontView()
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::setRightView()
|
|
|
|
|
{
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(m_pCameraController != nullptr && m_pCameraController->setRightView()) {
|
|
|
|
|
renderView();
|
|
|
|
|
}
|
|
|
|
|
@ -355,6 +487,7 @@ void nmWxVTKRenderContainerWidget::setRightView()
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::setIsometricView()
|
|
|
|
|
{
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(m_pCameraController != nullptr &&
|
|
|
|
|
m_pCameraController->setIsometricView()) {
|
|
|
|
|
renderView();
|
|
|
|
|
@ -366,26 +499,201 @@ void nmWxVTKRenderContainerWidget::setRotationCenter(
|
|
|
|
|
double dY,
|
|
|
|
|
double dZ)
|
|
|
|
|
{
|
|
|
|
|
if(m_pCameraController != nullptr &&
|
|
|
|
|
m_pCameraController->setRotationCenter(dX, dY, dZ)) {
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
if(applyRotationCenter(dX, dY, dZ, true)) {
|
|
|
|
|
renderView();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::resetRotationCenter()
|
|
|
|
|
{
|
|
|
|
|
if(m_pCameraController != nullptr &&
|
|
|
|
|
m_pCameraController->resetRotationCenter()) {
|
|
|
|
|
if(resetRotationCenterWithoutRender()) {
|
|
|
|
|
renderView();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmWxVTKRenderContainerWidget::applyRotationCenter(
|
|
|
|
|
double dX,
|
|
|
|
|
double dY,
|
|
|
|
|
double dZ,
|
|
|
|
|
bool bShowMarker)
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
if(!isGuiThread() || m_pCameraController == nullptr ||
|
|
|
|
|
!m_pCameraController->setRotationCenter(dX, dY, dZ)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// CameraController 是独立枢轴的唯一逻辑状态源;Marker 只保存显示副本。
|
|
|
|
|
nmVTKRotationCenterMarkerLayer* pMarkerLayer =
|
|
|
|
|
getRotationCenterMarkerLayer();
|
|
|
|
|
if(pMarkerLayer != nullptr) {
|
|
|
|
|
if(!pMarkerLayer->setWorldCenter(dX, dY, dZ)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if(bShowMarker) {
|
|
|
|
|
pMarkerLayer->setMarkerVisible(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
synchronizeRotationCenterMarker();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::cancelRotationCenterPicking()
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
if(!isGuiThread()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(m_pRotationCenterPicker != nullptr) {
|
|
|
|
|
// reset 同时清除待消费 Release,并按进入模式前状态恢复光标。
|
|
|
|
|
m_pRotationCenterPicker->reset();
|
|
|
|
|
}
|
|
|
|
|
emit rotationCenterPickingChanged(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmWxVTKRenderContainerWidget::handleRotationCenterPickEvent(
|
|
|
|
|
QEvent* pEvent)
|
|
|
|
|
{
|
|
|
|
|
if(m_pRotationCenterPicker == nullptr || pEvent == nullptr) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const nmVTKRotationCenterPicker::PickEventResult oResult =
|
|
|
|
|
m_pRotationCenterPicker->handleEvent(pEvent);
|
|
|
|
|
if(oResult.eOutcome ==
|
|
|
|
|
nmVTKRotationCenterPicker::PickOutcome_Hit) {
|
|
|
|
|
double dPosition[3];
|
|
|
|
|
if(m_pRotationCenterPicker->getPickedPosition(dPosition) &&
|
|
|
|
|
applyRotationCenter(dPosition[0], dPosition[1],
|
|
|
|
|
dPosition[2], true)) {
|
|
|
|
|
// 独立旋转中心和 Marker 已作为一批提交,只渲染一次。
|
|
|
|
|
renderView();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(oResult.eOutcome !=
|
|
|
|
|
nmVTKRotationCenterPicker::PickOutcome_None) {
|
|
|
|
|
emit rotationCenterPickingChanged(false);
|
|
|
|
|
}
|
|
|
|
|
return oResult.bConsumed;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::synchronizeRotationCenterMarker()
|
|
|
|
|
{
|
|
|
|
|
nmVTKRotationCenterMarkerLayer* pMarkerLayer =
|
|
|
|
|
getRotationCenterMarkerLayer();
|
|
|
|
|
if(pMarkerLayer != nullptr && pMarkerLayer->isMarkerVisible()) {
|
|
|
|
|
// synchronize 只更新世界几何,绝不从图层内部触发 Render。
|
|
|
|
|
pMarkerLayer->synchronize();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::updateRotationCenterMarkerVisibility()
|
|
|
|
|
{
|
|
|
|
|
nmVTKRotationCenterMarkerLayer* pMarkerLayer =
|
|
|
|
|
getRotationCenterMarkerLayer();
|
|
|
|
|
if(pMarkerLayer == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool bVisible = m_pViewCommandController != nullptr &&
|
|
|
|
|
m_pViewCommandController->isViewAvailable() &&
|
|
|
|
|
m_pViewCommandController->getCapabilities().testFlag(
|
|
|
|
|
nmVTKViewCommandController::ViewCommand_SetRotationCenter) &&
|
|
|
|
|
m_pRotationCenterPicker != nullptr &&
|
|
|
|
|
m_pRotationCenterPicker->hasPickTarget() &&
|
|
|
|
|
pMarkerLayer->hasWorldCenter();
|
|
|
|
|
pMarkerLayer->setMarkerVisible(bVisible);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::updateRotationCenterCommandAvailability()
|
|
|
|
|
{
|
|
|
|
|
if(m_pViewCommandController == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool bAvailable = m_pRotationCenterPicker != nullptr &&
|
|
|
|
|
m_pRotationCenterPicker->hasPickTarget() &&
|
|
|
|
|
getRotationCenterMarkerLayer() != nullptr &&
|
|
|
|
|
m_pInteractionManager != nullptr &&
|
|
|
|
|
m_pInteractionManager->isDefaultInteractionActive();
|
|
|
|
|
m_pViewCommandController->setRotationCenterPickingAvailable(
|
|
|
|
|
bAvailable);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nmVTKRotationCenterMarkerLayer*
|
|
|
|
|
nmWxVTKRenderContainerWidget::getRotationCenterMarkerLayer() const
|
|
|
|
|
{
|
|
|
|
|
if(m_pSystemScene == nullptr || m_pRotationCenterMarkerLayer == nullptr ||
|
|
|
|
|
m_pSystemScene->getLayer(ROTATION_CENTER_MARKER_LAYER_ID) !=
|
|
|
|
|
m_pRotationCenterMarkerLayer) {
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
return m_pRotationCenterMarkerLayer;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::setRotationCenterPickingEnabled(
|
|
|
|
|
bool bEnabled)
|
|
|
|
|
{
|
|
|
|
|
Q_ASSERT(isGuiThread());
|
|
|
|
|
if(!isGuiThread()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!bEnabled) {
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool bCommandAvailable = m_pViewCommandController != nullptr &&
|
|
|
|
|
m_pViewCommandController->isViewAvailable() &&
|
|
|
|
|
m_pViewCommandController->getCapabilities().testFlag(
|
|
|
|
|
nmVTKViewCommandController::ViewCommand_SetRotationCenter);
|
|
|
|
|
const bool bCanStart = bCommandAvailable &&
|
|
|
|
|
m_pRotationCenterPicker != nullptr &&
|
|
|
|
|
m_pRotationCenterPicker->getPickTarget() != nullptr &&
|
|
|
|
|
getRotationCenterMarkerLayer() != nullptr &&
|
|
|
|
|
m_pInteractionManager != nullptr &&
|
|
|
|
|
m_pInteractionManager->isDefaultInteractionActive();
|
|
|
|
|
if(!bCanStart ||
|
|
|
|
|
!m_pRotationCenterPicker->start(m_pVtkWidget, m_pRenderer)) {
|
|
|
|
|
if(m_pRotationCenterPicker != nullptr) {
|
|
|
|
|
m_pRotationCenterPicker->reset();
|
|
|
|
|
}
|
|
|
|
|
updateRotationCenterCommandAvailability();
|
|
|
|
|
emit rotationCenterPickingChanged(false);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
emit rotationCenterPickingChanged(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool nmWxVTKRenderContainerWidget::eventFilter(
|
|
|
|
|
QObject* pObject,
|
|
|
|
|
QEvent* pEvent)
|
|
|
|
|
{
|
|
|
|
|
if(pObject == m_pVtkWidget && pEvent != nullptr &&
|
|
|
|
|
pEvent->type() == QEvent::MouseButtonPress) {
|
|
|
|
|
if(pObject != m_pVtkWidget || pEvent == nullptr) {
|
|
|
|
|
return QWidget::eventFilter(pObject, pEvent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 一次性拾取优先于 VTK 相机交互和右键菜单,并继续吞掉对应 Release。
|
|
|
|
|
if(m_pRotationCenterPicker != nullptr &&
|
|
|
|
|
(m_pRotationCenterPicker->isActive() ||
|
|
|
|
|
m_pRotationCenterPicker->hasPendingRelease()) &&
|
|
|
|
|
handleRotationCenterPickEvent(pEvent)) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(pEvent->type() == QEvent::FocusOut) {
|
|
|
|
|
// 延后到本轮焦点切换结束,避免点击工具按钮启动模式时被旧 FocusOut 取消。
|
|
|
|
|
QTimer::singleShot(
|
|
|
|
|
0, this,
|
|
|
|
|
SLOT(cancelRotationCenterPickingAfterFocusOut()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(pEvent->type() == QEvent::MouseButtonPress) {
|
|
|
|
|
QMouseEvent* pMouseEvent = static_cast<QMouseEvent*>(pEvent);
|
|
|
|
|
if(pMouseEvent->button() == Qt::RightButton) {
|
|
|
|
|
// 菜单引用命令控制器长期持有的 QAction,不在每次右键时重复创建。
|
|
|
|
|
@ -404,11 +712,22 @@ bool nmWxVTKRenderContainerWidget::eventFilter(
|
|
|
|
|
return QWidget::eventFilter(pObject, pEvent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::cancelRotationCenterPickingAfterFocusOut()
|
|
|
|
|
{
|
|
|
|
|
if(m_pVtkWidget != nullptr && !m_pVtkWidget->hasFocus() &&
|
|
|
|
|
m_pRotationCenterPicker != nullptr &&
|
|
|
|
|
(m_pRotationCenterPicker->isActive() ||
|
|
|
|
|
m_pRotationCenterPicker->hasPendingRelease())) {
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::saveImage()
|
|
|
|
|
{
|
|
|
|
|
if(m_pImageExporter == nullptr) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
synchronizeRotationCenterMarker();
|
|
|
|
|
// 实际编码格式由 QImage 按调用方选择的扩展名决定。
|
|
|
|
|
const QString sFileName = QFileDialog::getSaveFileName(
|
|
|
|
|
this,
|
|
|
|
|
@ -424,6 +743,7 @@ void nmWxVTKRenderContainerWidget::saveImage()
|
|
|
|
|
|
|
|
|
|
void nmWxVTKRenderContainerWidget::copyImage()
|
|
|
|
|
{
|
|
|
|
|
synchronizeRotationCenterMarker();
|
|
|
|
|
if(m_pImageExporter != nullptr &&
|
|
|
|
|
!m_pImageExporter->copyImageToClipboard()) {
|
|
|
|
|
QMessageBox::warning(this,
|
|
|
|
|
@ -435,6 +755,7 @@ void nmWxVTKRenderContainerWidget::copyImage()
|
|
|
|
|
void nmWxVTKRenderContainerWidget::printImage()
|
|
|
|
|
{
|
|
|
|
|
if(m_pImageExporter != nullptr) {
|
|
|
|
|
synchronizeRotationCenterMarker();
|
|
|
|
|
m_pImageExporter->printImage(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -442,6 +763,7 @@ void nmWxVTKRenderContainerWidget::printImage()
|
|
|
|
|
void nmWxVTKRenderContainerWidget::printPreview()
|
|
|
|
|
{
|
|
|
|
|
if(m_pImageExporter != nullptr) {
|
|
|
|
|
synchronizeRotationCenterMarker();
|
|
|
|
|
m_pImageExporter->printPreview(this);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -464,6 +786,9 @@ void nmWxVTKRenderContainerWidget::showMessageState(
|
|
|
|
|
}
|
|
|
|
|
m_pStateLabel->setText(sMessage);
|
|
|
|
|
m_pStateStack->setCurrentWidget(m_pStatePage);
|
|
|
|
|
// 非就绪状态先结束临时工具并清除手工标记,再禁用和取消 QAction。
|
|
|
|
|
cancelRotationCenterPicking();
|
|
|
|
|
hideRotationCenterMarker();
|
|
|
|
|
if(m_pViewCommandController != nullptr) {
|
|
|
|
|
m_pViewCommandController->setViewAvailable(false);
|
|
|
|
|
}
|
|
|
|
|
|