|
|
#include "nmVTKRotationCenterMarkerLayer.h"
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
#include <QThread>
|
|
|
|
|
|
#include <vtkActor.h>
|
|
|
#include <vtkCallbackCommand.h>
|
|
|
#include <vtkCamera.h>
|
|
|
#include <vtkCellArray.h>
|
|
|
#include <vtkCellData.h>
|
|
|
#include <vtkCommand.h>
|
|
|
#include <vtkMath.h>
|
|
|
#include <vtkPoints.h>
|
|
|
#include <vtkPolyData.h>
|
|
|
#include <vtkPolyDataMapper.h>
|
|
|
#include <vtkProperty.h>
|
|
|
#include <vtkRenderer.h>
|
|
|
#include <vtkUnsignedCharArray.h>
|
|
|
#include <vtkWeakPointer.h>
|
|
|
|
|
|
#include <cmath>
|
|
|
#include <limits>
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
const double ROTATION_CENTER_HALF_LENGTH_PIXELS = 18.0;
|
|
|
const double ROTATION_CENTER_DEPTH_OFFSET_PIXELS = 1.5;
|
|
|
const double ROTATION_CENTER_HOMOGENEOUS_EPSILON =
|
|
|
std::numeric_limits<double>::epsilon();
|
|
|
|
|
|
bool isRotationCenterMarkerGuiThread()
|
|
|
{
|
|
|
QCoreApplication* pApplication = QCoreApplication::instance();
|
|
|
return pApplication == nullptr ||
|
|
|
pApplication->thread() == QThread::currentThread();
|
|
|
}
|
|
|
|
|
|
bool isFinitePoint3(const double dPoint[3])
|
|
|
{
|
|
|
return dPoint != nullptr &&
|
|
|
vtkMath::IsFinite(dPoint[0]) &&
|
|
|
vtkMath::IsFinite(dPoint[1]) &&
|
|
|
vtkMath::IsFinite(dPoint[2]);
|
|
|
}
|
|
|
|
|
|
bool worldToDisplay(vtkRenderer* pRenderer,
|
|
|
const double dWorld[3],
|
|
|
double dDisplay[3])
|
|
|
{
|
|
|
if(pRenderer == nullptr || dWorld == nullptr || dDisplay == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
pRenderer->SetWorldPoint(dWorld[0], dWorld[1], dWorld[2], 1.0);
|
|
|
pRenderer->WorldToDisplay();
|
|
|
const double* pDisplay = pRenderer->GetDisplayPoint();
|
|
|
if(!isFinitePoint3(pDisplay)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
dDisplay[0] = pDisplay[0];
|
|
|
dDisplay[1] = pDisplay[1];
|
|
|
dDisplay[2] = pDisplay[2];
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool displayToWorld(vtkRenderer* pRenderer,
|
|
|
const double dDisplay[3],
|
|
|
double dWorld[3])
|
|
|
{
|
|
|
if(pRenderer == nullptr || dDisplay == nullptr || dWorld == nullptr ||
|
|
|
!isFinitePoint3(dDisplay)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
pRenderer->SetDisplayPoint(
|
|
|
dDisplay[0], dDisplay[1], dDisplay[2]);
|
|
|
pRenderer->DisplayToWorld();
|
|
|
const double* pHomogeneousWorld = pRenderer->GetWorldPoint();
|
|
|
if(pHomogeneousWorld == nullptr ||
|
|
|
!vtkMath::IsFinite(pHomogeneousWorld[0]) ||
|
|
|
!vtkMath::IsFinite(pHomogeneousWorld[1]) ||
|
|
|
!vtkMath::IsFinite(pHomogeneousWorld[2]) ||
|
|
|
!vtkMath::IsFinite(pHomogeneousWorld[3]) ||
|
|
|
std::fabs(pHomogeneousWorld[3]) <=
|
|
|
ROTATION_CENTER_HOMOGENEOUS_EPSILON) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
const double dInverseW = 1.0 / pHomogeneousWorld[3];
|
|
|
dWorld[0] = pHomogeneousWorld[0] * dInverseW;
|
|
|
dWorld[1] = pHomogeneousWorld[1] * dInverseW;
|
|
|
dWorld[2] = pHomogeneousWorld[2] * dInverseW;
|
|
|
return isFinitePoint3(dWorld);
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
class nmVTKRotationCenterMarkerLayerPrivate
|
|
|
{
|
|
|
public:
|
|
|
nmVTKRotationCenterMarkerLayerPrivate()
|
|
|
: m_pPoints(vtkSmartPointer<vtkPoints>::New()),
|
|
|
m_pLines(vtkSmartPointer<vtkCellArray>::New()),
|
|
|
m_pColors(vtkSmartPointer<vtkUnsignedCharArray>::New()),
|
|
|
m_pPolyData(vtkSmartPointer<vtkPolyData>::New()),
|
|
|
m_pMapper(vtkSmartPointer<vtkPolyDataMapper>::New()),
|
|
|
m_pActor(vtkSmartPointer<vtkActor>::New()),
|
|
|
m_pRendererCallback(vtkSmartPointer<vtkCallbackCommand>::New()),
|
|
|
m_pCameraCallback(vtkSmartPointer<vtkCallbackCommand>::New()),
|
|
|
m_pRenderer(nullptr),
|
|
|
m_pCamera(nullptr),
|
|
|
m_nRendererObserverTag(0),
|
|
|
m_nCameraObserverTag(0),
|
|
|
m_bHasWorldCenter(false)
|
|
|
{
|
|
|
// 必须通过 vtkActor::New() 的对象工厂路径获得实际 OpenGL Actor。
|
|
|
initializeGeometry();
|
|
|
|
|
|
m_dWorldCenter[0] = 0.0;
|
|
|
m_dWorldCenter[1] = 0.0;
|
|
|
m_dWorldCenter[2] = 0.0;
|
|
|
|
|
|
m_pRendererCallback->SetClientData(this);
|
|
|
m_pRendererCallback->SetCallback(
|
|
|
nmVTKRotationCenterMarkerLayerPrivate::rendererStarted);
|
|
|
m_pCameraCallback->SetClientData(this);
|
|
|
m_pCameraCallback->SetCallback(
|
|
|
nmVTKRotationCenterMarkerLayerPrivate::cameraModified);
|
|
|
}
|
|
|
|
|
|
~nmVTKRotationCenterMarkerLayerPrivate()
|
|
|
{
|
|
|
// 先移除 Renderer 和 Camera Observer,再阻断裸回调目标。
|
|
|
unbindRenderer();
|
|
|
m_pRendererCallback->SetClientData(nullptr);
|
|
|
m_pRendererCallback->SetCallback(nullptr);
|
|
|
m_pCameraCallback->SetClientData(nullptr);
|
|
|
m_pCameraCallback->SetCallback(nullptr);
|
|
|
}
|
|
|
|
|
|
vtkActor* getActor() const
|
|
|
{
|
|
|
return m_pActor;
|
|
|
}
|
|
|
|
|
|
bool bindRenderer(vtkRenderer* pRenderer)
|
|
|
{
|
|
|
if(pRenderer == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
if(m_pRenderer.GetPointer() != pRenderer) {
|
|
|
unbindRenderer();
|
|
|
m_pRenderer = pRenderer;
|
|
|
}
|
|
|
|
|
|
if(!ensureRendererObserver(pRenderer) ||
|
|
|
!ensureCameraObserver(pRenderer->GetActiveCamera())) {
|
|
|
unbindRenderer();
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void unbindRenderer()
|
|
|
{
|
|
|
removeCameraObserver();
|
|
|
removeRendererObserver();
|
|
|
m_pRenderer = nullptr;
|
|
|
}
|
|
|
|
|
|
bool synchronize()
|
|
|
{
|
|
|
return synchronizeForRenderer(m_pRenderer.GetPointer());
|
|
|
}
|
|
|
|
|
|
bool synchronizeForRenderer(vtkRenderer* pRenderer)
|
|
|
{
|
|
|
if(pRenderer == nullptr || m_pRenderer.GetPointer() != pRenderer ||
|
|
|
!m_bHasWorldCenter) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
vtkCamera* pCamera = pRenderer->GetActiveCamera();
|
|
|
if(pCamera == nullptr || !ensureCameraObserver(pCamera)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
int* pViewportSize = pRenderer->GetSize();
|
|
|
if(pViewportSize == nullptr || pViewportSize[0] <= 0 ||
|
|
|
pViewportSize[1] <= 0) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
const double dLogicalCenter[3] = {
|
|
|
m_dWorldCenter[0], m_dWorldCenter[1], m_dWorldCenter[2]
|
|
|
};
|
|
|
double dCameraPosition[3];
|
|
|
pCamera->GetPosition(dCameraPosition);
|
|
|
if(!isFinitePoint3(dLogicalCenter) ||
|
|
|
!isFinitePoint3(dCameraPosition)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
double dCenterDisplay[3];
|
|
|
if(!worldToDisplay(pRenderer, dLogicalCenter, dCenterDisplay)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
double dOffsetDisplay[3] = {
|
|
|
dCenterDisplay[0],
|
|
|
dCenterDisplay[1] + ROTATION_CENTER_HALF_LENGTH_PIXELS,
|
|
|
dCenterDisplay[2]
|
|
|
};
|
|
|
double dCenterAtDepth[3];
|
|
|
double dOffsetAtDepth[3];
|
|
|
if(!displayToWorld(pRenderer, dCenterDisplay, dCenterAtDepth) ||
|
|
|
!displayToWorld(pRenderer, dOffsetDisplay, dOffsetAtDepth)) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
const double dScaleX = dOffsetAtDepth[0] - dCenterAtDepth[0];
|
|
|
const double dScaleY = dOffsetAtDepth[1] - dCenterAtDepth[1];
|
|
|
const double dScaleZ = dOffsetAtDepth[2] - dCenterAtDepth[2];
|
|
|
const double dHalfLength = std::sqrt(
|
|
|
dScaleX * dScaleX +
|
|
|
dScaleY * dScaleY +
|
|
|
dScaleZ * dScaleZ);
|
|
|
if(!vtkMath::IsFinite(dHalfLength) || dHalfLength <= 0.0) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
double dTowardCamera[3];
|
|
|
if(pCamera->GetParallelProjection() != 0) {
|
|
|
const double* pDirectionOfProjection =
|
|
|
pCamera->GetDirectionOfProjection();
|
|
|
if(!isFinitePoint3(pDirectionOfProjection)) {
|
|
|
return false;
|
|
|
}
|
|
|
dTowardCamera[0] = -pDirectionOfProjection[0];
|
|
|
dTowardCamera[1] = -pDirectionOfProjection[1];
|
|
|
dTowardCamera[2] = -pDirectionOfProjection[2];
|
|
|
} else {
|
|
|
dTowardCamera[0] = dCameraPosition[0] - dLogicalCenter[0];
|
|
|
dTowardCamera[1] = dCameraPosition[1] - dLogicalCenter[1];
|
|
|
dTowardCamera[2] = dCameraPosition[2] - dLogicalCenter[2];
|
|
|
}
|
|
|
if(vtkMath::Normalize(dTowardCamera) <= 0.0) {
|
|
|
return false;
|
|
|
}
|
|
|
|
|
|
const double dWorldPerPixel =
|
|
|
dHalfLength / ROTATION_CENTER_HALF_LENGTH_PIXELS;
|
|
|
const double dDepthOffset =
|
|
|
dWorldPerPixel * ROTATION_CENTER_DEPTH_OFFSET_PIXELS;
|
|
|
const double dDisplayCenter[3] = {
|
|
|
dLogicalCenter[0] + dTowardCamera[0] * dDepthOffset,
|
|
|
dLogicalCenter[1] + dTowardCamera[1] * dDepthOffset,
|
|
|
dLogicalCenter[2] + dTowardCamera[2] * dDepthOffset
|
|
|
};
|
|
|
|
|
|
const double dAxisPoints[6][3] = {
|
|
|
{ dDisplayCenter[0] - dHalfLength,
|
|
|
dDisplayCenter[1], dDisplayCenter[2] },
|
|
|
{ dDisplayCenter[0] + dHalfLength,
|
|
|
dDisplayCenter[1], dDisplayCenter[2] },
|
|
|
{ dDisplayCenter[0],
|
|
|
dDisplayCenter[1] - dHalfLength, dDisplayCenter[2] },
|
|
|
{ dDisplayCenter[0],
|
|
|
dDisplayCenter[1] + dHalfLength, dDisplayCenter[2] },
|
|
|
{ dDisplayCenter[0], dDisplayCenter[1],
|
|
|
dDisplayCenter[2] - dHalfLength },
|
|
|
{ dDisplayCenter[0], dDisplayCenter[1],
|
|
|
dDisplayCenter[2] + dHalfLength }
|
|
|
};
|
|
|
for(vtkIdType nPoint = 0; nPoint < 6; ++nPoint) {
|
|
|
if(!isFinitePoint3(dAxisPoints[nPoint])) {
|
|
|
return false;
|
|
|
}
|
|
|
}
|
|
|
for(vtkIdType nPoint = 0; nPoint < 6; ++nPoint) {
|
|
|
m_pPoints->SetPoint(nPoint, dAxisPoints[nPoint]);
|
|
|
}
|
|
|
m_pPoints->Modified();
|
|
|
m_pPolyData->Modified();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool setWorldCenter(double dX, double dY, double dZ)
|
|
|
{
|
|
|
const double dCenter[3] = { dX, dY, dZ };
|
|
|
if(!isFinitePoint3(dCenter)) {
|
|
|
return false;
|
|
|
}
|
|
|
m_dWorldCenter[0] = dX;
|
|
|
m_dWorldCenter[1] = dY;
|
|
|
m_dWorldCenter[2] = dZ;
|
|
|
m_bHasWorldCenter = true;
|
|
|
synchronize();
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
bool hasWorldCenter() const
|
|
|
{
|
|
|
return m_bHasWorldCenter;
|
|
|
}
|
|
|
|
|
|
private:
|
|
|
static void rendererStarted(vtkObject* pCaller,
|
|
|
unsigned long,
|
|
|
void* pClientData,
|
|
|
void*)
|
|
|
{
|
|
|
nmVTKRotationCenterMarkerLayerPrivate* pThis =
|
|
|
static_cast<nmVTKRotationCenterMarkerLayerPrivate*>(
|
|
|
pClientData);
|
|
|
if(pThis != nullptr) {
|
|
|
// StartEvent 位于 Prop 遍历之前,可使用最终视口尺寸覆盖 Resize 路径。
|
|
|
pThis->synchronizeForRenderer(
|
|
|
vtkRenderer::SafeDownCast(pCaller));
|
|
|
}
|
|
|
}
|
|
|
|
|
|
static void cameraModified(vtkObject*,
|
|
|
unsigned long,
|
|
|
void* pClientData,
|
|
|
void*)
|
|
|
{
|
|
|
nmVTKRotationCenterMarkerLayerPrivate* pThis =
|
|
|
static_cast<nmVTKRotationCenterMarkerLayerPrivate*>(
|
|
|
pClientData);
|
|
|
if(pThis != nullptr) {
|
|
|
// 相机回调只同步几何,最终 Render 仍由交互器或容器统一提交。
|
|
|
pThis->synchronize();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void initializeGeometry()
|
|
|
{
|
|
|
m_pPoints->SetDataTypeToDouble();
|
|
|
m_pPoints->SetNumberOfPoints(6);
|
|
|
for(vtkIdType nPoint = 0; nPoint < 6; ++nPoint) {
|
|
|
m_pPoints->SetPoint(nPoint, 0.0, 0.0, 0.0);
|
|
|
}
|
|
|
|
|
|
for(vtkIdType nAxis = 0; nAxis < 3; ++nAxis) {
|
|
|
vtkIdType nPointIds[2] = {
|
|
|
nAxis * 2, nAxis * 2 + 1
|
|
|
};
|
|
|
m_pLines->InsertNextCell(2, nPointIds);
|
|
|
}
|
|
|
|
|
|
m_pColors->SetName("RotationCenterAxisColors");
|
|
|
m_pColors->SetNumberOfComponents(3);
|
|
|
m_pColors->InsertNextTuple3(255.0, 0.0, 0.0);
|
|
|
m_pColors->InsertNextTuple3(254.0, 255.0, 0.0);
|
|
|
m_pColors->InsertNextTuple3(0.0, 255.0, 0.0);
|
|
|
|
|
|
m_pPolyData->SetPoints(m_pPoints);
|
|
|
m_pPolyData->SetLines(m_pLines);
|
|
|
m_pPolyData->GetCellData()->SetScalars(m_pColors);
|
|
|
|
|
|
m_pMapper->SetInputData(m_pPolyData);
|
|
|
m_pMapper->ScalarVisibilityOn();
|
|
|
m_pMapper->SetScalarModeToUseCellData();
|
|
|
m_pMapper->SetColorModeToDirectScalars();
|
|
|
|
|
|
m_pActor->SetMapper(m_pMapper);
|
|
|
m_pActor->GetProperty()->SetLineWidth(2.0f);
|
|
|
m_pActor->GetProperty()->SetOpacity(1.0);
|
|
|
m_pActor->GetProperty()->LightingOff();
|
|
|
m_pActor->PickableOff();
|
|
|
m_pActor->UseBoundsOff();
|
|
|
}
|
|
|
|
|
|
bool ensureRendererObserver(vtkRenderer* pRenderer)
|
|
|
{
|
|
|
if(pRenderer == nullptr || m_pRendererCallback == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
if(m_pRenderer.GetPointer() == pRenderer &&
|
|
|
m_nRendererObserverTag != 0) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
removeRendererObserver();
|
|
|
m_nRendererObserverTag = pRenderer->AddObserver(
|
|
|
vtkCommand::StartEvent, m_pRendererCallback);
|
|
|
return m_nRendererObserverTag != 0;
|
|
|
}
|
|
|
|
|
|
void removeRendererObserver()
|
|
|
{
|
|
|
vtkRenderer* pRenderer = m_pRenderer.GetPointer();
|
|
|
if(pRenderer != nullptr && m_nRendererObserverTag != 0) {
|
|
|
pRenderer->RemoveObserver(m_nRendererObserverTag);
|
|
|
}
|
|
|
m_nRendererObserverTag = 0;
|
|
|
}
|
|
|
|
|
|
bool ensureCameraObserver(vtkCamera* pCamera)
|
|
|
{
|
|
|
if(pCamera == nullptr || m_pCameraCallback == nullptr) {
|
|
|
return false;
|
|
|
}
|
|
|
if(m_pCamera.GetPointer() == pCamera &&
|
|
|
m_nCameraObserverTag != 0) {
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
removeCameraObserver();
|
|
|
m_pCamera = pCamera;
|
|
|
m_nCameraObserverTag = pCamera->AddObserver(
|
|
|
vtkCommand::ModifiedEvent, m_pCameraCallback);
|
|
|
if(m_nCameraObserverTag == 0) {
|
|
|
m_pCamera = nullptr;
|
|
|
return false;
|
|
|
}
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
void removeCameraObserver()
|
|
|
{
|
|
|
vtkCamera* pCamera = m_pCamera.GetPointer();
|
|
|
if(pCamera != nullptr && m_nCameraObserverTag != 0) {
|
|
|
pCamera->RemoveObserver(m_nCameraObserverTag);
|
|
|
}
|
|
|
m_nCameraObserverTag = 0;
|
|
|
m_pCamera = nullptr;
|
|
|
}
|
|
|
|
|
|
vtkSmartPointer<vtkPoints> m_pPoints;
|
|
|
vtkSmartPointer<vtkCellArray> m_pLines;
|
|
|
vtkSmartPointer<vtkUnsignedCharArray> m_pColors;
|
|
|
vtkSmartPointer<vtkPolyData> m_pPolyData;
|
|
|
vtkSmartPointer<vtkPolyDataMapper> m_pMapper;
|
|
|
vtkSmartPointer<vtkActor> m_pActor;
|
|
|
vtkSmartPointer<vtkCallbackCommand> m_pRendererCallback;
|
|
|
vtkSmartPointer<vtkCallbackCommand> m_pCameraCallback;
|
|
|
vtkWeakPointer<vtkRenderer> m_pRenderer; ///< 非所有权引用。
|
|
|
vtkWeakPointer<vtkCamera> m_pCamera; ///< 非所有权引用。
|
|
|
unsigned long m_nRendererObserverTag; ///< 为零表示尚未注册观察者。
|
|
|
unsigned long m_nCameraObserverTag; ///< 为零表示尚未注册观察者。
|
|
|
double m_dWorldCenter[3]; ///< 独立于相机焦点的逻辑中心。
|
|
|
bool m_bHasWorldCenter;
|
|
|
};
|
|
|
|
|
|
nmVTKRotationCenterMarkerLayer::nmVTKRotationCenterMarkerLayer(
|
|
|
const QString& sLayerId)
|
|
|
: nmVTKRenderLayer(sLayerId),
|
|
|
m_pPrivate(new nmVTKRotationCenterMarkerLayerPrivate)
|
|
|
{
|
|
|
Q_ASSERT(isRotationCenterMarkerGuiThread());
|
|
|
setRenderProp(m_pPrivate->getActor());
|
|
|
setVisible(false);
|
|
|
}
|
|
|
|
|
|
nmVTKRotationCenterMarkerLayer::~nmVTKRotationCenterMarkerLayer()
|
|
|
{
|
|
|
Q_ASSERT(isRotationCenterMarkerGuiThread());
|
|
|
if(m_pPrivate != nullptr) {
|
|
|
// Renderer/Camera Observer 必须在 Renderer 和回调目标释放前解除。
|
|
|
m_pPrivate->unbindRenderer();
|
|
|
detach();
|
|
|
delete m_pPrivate;
|
|
|
m_pPrivate = nullptr;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool nmVTKRotationCenterMarkerLayer::bindRenderer(vtkRenderer* pRenderer)
|
|
|
{
|
|
|
Q_ASSERT(isRotationCenterMarkerGuiThread());
|
|
|
if(!isRotationCenterMarkerGuiThread() || m_pPrivate == nullptr ||
|
|
|
pRenderer == nullptr || getAttachedRenderer() != pRenderer) {
|
|
|
return false;
|
|
|
}
|
|
|
return m_pPrivate->bindRenderer(pRenderer);
|
|
|
}
|
|
|
|
|
|
void nmVTKRotationCenterMarkerLayer::unbindRenderer()
|
|
|
{
|
|
|
Q_ASSERT(isRotationCenterMarkerGuiThread());
|
|
|
if(isRotationCenterMarkerGuiThread() && m_pPrivate != nullptr) {
|
|
|
m_pPrivate->unbindRenderer();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool nmVTKRotationCenterMarkerLayer::synchronize()
|
|
|
{
|
|
|
Q_ASSERT(isRotationCenterMarkerGuiThread());
|
|
|
return isRotationCenterMarkerGuiThread() && m_pPrivate != nullptr &&
|
|
|
m_pPrivate->synchronize();
|
|
|
}
|
|
|
|
|
|
bool nmVTKRotationCenterMarkerLayer::setWorldCenter(
|
|
|
double dX,
|
|
|
double dY,
|
|
|
double dZ)
|
|
|
{
|
|
|
Q_ASSERT(isRotationCenterMarkerGuiThread());
|
|
|
return isRotationCenterMarkerGuiThread() && m_pPrivate != nullptr &&
|
|
|
m_pPrivate->setWorldCenter(dX, dY, dZ);
|
|
|
}
|
|
|
|
|
|
bool nmVTKRotationCenterMarkerLayer::hasWorldCenter() const
|
|
|
{
|
|
|
return m_pPrivate != nullptr && m_pPrivate->hasWorldCenter();
|
|
|
}
|
|
|
|
|
|
void nmVTKRotationCenterMarkerLayer::setMarkerVisible(bool bVisible)
|
|
|
{
|
|
|
Q_ASSERT(isRotationCenterMarkerGuiThread());
|
|
|
if(!isRotationCenterMarkerGuiThread()) {
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
const bool bCanShow = bVisible && m_pPrivate != nullptr &&
|
|
|
m_pPrivate->hasWorldCenter();
|
|
|
setVisible(bCanShow);
|
|
|
if(bCanShow) {
|
|
|
// 首次显示先准备几何;视口尚未建立时由绘制前同步再次补齐。
|
|
|
m_pPrivate->synchronize();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
bool nmVTKRotationCenterMarkerLayer::isMarkerVisible() const
|
|
|
{
|
|
|
return isVisible();
|
|
|
}
|