|
|
|
|
|
#include "nmVTKScalarBarLayer.h"
|
|
|
|
|
|
|
|
|
|
|
|
#include <QByteArray>
|
|
|
|
|
|
#include <QCoreApplication>
|
|
|
|
|
|
#include <QThread>
|
|
|
|
|
|
#include <QtGlobal>
|
|
|
|
|
|
|
|
|
|
|
|
#include <vtkCoordinate.h>
|
|
|
|
|
|
#include <vtkLookupTable.h>
|
|
|
|
|
|
#include <vtkMath.h>
|
|
|
|
|
|
#include <vtkObjectFactory.h>
|
|
|
|
|
|
#include <vtkPropAssembly.h>
|
|
|
|
|
|
#include <vtkProperty2D.h>
|
|
|
|
|
|
#include <vtkRenderer.h>
|
|
|
|
|
|
#include <vtkScalarBarActor.h>
|
|
|
|
|
|
#include <vtkTextActor.h>
|
|
|
|
|
|
#include <vtkTextProperty.h>
|
|
|
|
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
|
* @brief 只公开 VTK 色标的按需布局入口,供独立 Overlay 在 Render 前读取新几何。
|
|
|
|
|
|
*/
|
|
|
|
|
|
class vtkNmScalarBarActor : public vtkScalarBarActor
|
|
|
|
|
|
{
|
|
|
|
|
|
public:
|
|
|
|
|
|
static vtkNmScalarBarActor* New();
|
|
|
|
|
|
vtkTypeMacro(vtkNmScalarBarActor, vtkScalarBarActor);
|
|
|
|
|
|
|
|
|
|
|
|
/** @brief 立即同步内部色带、刻度和文字布局,不触发 Renderer 绘制。 */
|
|
|
|
|
|
int refreshLayout(vtkViewport* pViewport)
|
|
|
|
|
|
{
|
|
|
|
|
|
return pViewport != nullptr
|
|
|
|
|
|
? RebuildLayoutIfNeeded(pViewport) : 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
|
vtkNmScalarBarActor()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
virtual ~vtkNmScalarBarActor()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
vtkNmScalarBarActor(const vtkNmScalarBarActor&);
|
|
|
|
|
|
void operator=(const vtkNmScalarBarActor&);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
vtkStandardNewMacro(vtkNmScalarBarActor);
|
|
|
|
|
|
|
|
|
|
|
|
const int SCALAR_BAR_LEFT_MARGIN_PIXELS = 20;
|
|
|
|
|
|
const int SCALAR_BAR_TOTAL_WIDTH_PIXELS = 108;
|
|
|
|
|
|
// VTK 内部留白会压缩色带,目标宽度设为 34px 后可见宽度约为 30px。
|
|
|
|
|
|
const int SCALAR_BAR_COLOR_WIDTH_PIXELS = 34;
|
|
|
|
|
|
const int SCALAR_BAR_VISIBLE_COLOR_WIDTH_PIXELS = 30;
|
|
|
|
|
|
const int SCALAR_BAR_TITLE_FONT_SIZE = 18;
|
|
|
|
|
|
const int SCALAR_BAR_TITLE_SAFE_HEIGHT_PIXELS = 24;
|
|
|
|
|
|
const int SCALAR_BAR_LABEL_FONT_SIZE = 15;
|
|
|
|
|
|
const int SCALAR_BAR_SMALL_VIEWPORT_HEIGHT = 450;
|
|
|
|
|
|
const int SCALAR_BAR_MEDIUM_VIEWPORT_HEIGHT = 650;
|
|
|
|
|
|
const int SCALAR_BAR_LABEL_SPACING_PIXELS = 80;
|
|
|
|
|
|
const int SCALAR_BAR_MIN_LABEL_COUNT = 6;
|
|
|
|
|
|
const int SCALAR_BAR_MAX_LABEL_COUNT = 9;
|
|
|
|
|
|
const int SCALAR_BAR_TITLE_OFFSET_Y_PIXELS = 28;
|
|
|
|
|
|
const int SCALAR_BAR_LABEL_GAP_PIXELS = 8;
|
|
|
|
|
|
const double SCALAR_BAR_NORMAL_BOTTOM_RATIO = 0.22;
|
|
|
|
|
|
const double SCALAR_BAR_NORMAL_HEIGHT_RATIO = 0.67;
|
|
|
|
|
|
const double SCALAR_BAR_SMALL_BOTTOM_RATIO = 0.22;
|
|
|
|
|
|
const double SCALAR_BAR_SMALL_HEIGHT_RATIO = 0.62;
|
|
|
|
|
|
|
|
|
|
|
|
// ScalarBarActor 和 LookupTable 均只能在 Qt GUI 线程中修改。
|
|
|
|
|
|
bool isScalarBarGuiThread()
|
|
|
|
|
|
{
|
|
|
|
|
|
QCoreApplication* pApplication = QCoreApplication::instance();
|
|
|
|
|
|
return pApplication == nullptr ||
|
|
|
|
|
|
pApplication->thread() == QThread::currentThread();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 单值端点标签沿用普通刻度的字号、粗斜体和阴影样式。
|
|
|
|
|
|
void configureConstantValueActor(vtkTextActor* pActor)
|
|
|
|
|
|
{
|
|
|
|
|
|
pActor->SetInput("");
|
|
|
|
|
|
pActor->SetTextScaleModeToNone();
|
|
|
|
|
|
pActor->GetTextProperty()->SetFontFamilyToArial();
|
|
|
|
|
|
pActor->GetTextProperty()->SetFontSize(SCALAR_BAR_LABEL_FONT_SIZE);
|
|
|
|
|
|
pActor->GetTextProperty()->SetColor(1.0, 1.0, 1.0);
|
|
|
|
|
|
pActor->GetTextProperty()->BoldOn();
|
|
|
|
|
|
pActor->GetTextProperty()->ItalicOn();
|
|
|
|
|
|
pActor->GetTextProperty()->ShadowOn();
|
|
|
|
|
|
pActor->GetTextProperty()->SetShadowOffset(1, -1);
|
|
|
|
|
|
pActor->GetTextProperty()->SetJustificationToLeft();
|
|
|
|
|
|
pActor->GetTextProperty()->SetVerticalJustificationToCentered();
|
|
|
|
|
|
pActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport();
|
|
|
|
|
|
pActor->GetProperty()->SetDisplayLocationToForeground();
|
|
|
|
|
|
pActor->PickableOff();
|
|
|
|
|
|
pActor->SetVisibility(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 独立标题不受 vtkScalarBarActor 内部居中布局影响,始终保持左对齐。
|
|
|
|
|
|
void configureTitleActor(vtkTextActor* pActor)
|
|
|
|
|
|
{
|
|
|
|
|
|
pActor->SetInput("");
|
|
|
|
|
|
pActor->SetTextScaleModeToNone();
|
|
|
|
|
|
pActor->GetTextProperty()->SetFontFamilyToArial();
|
|
|
|
|
|
pActor->GetTextProperty()->SetFontSize(SCALAR_BAR_TITLE_FONT_SIZE);
|
|
|
|
|
|
pActor->GetTextProperty()->SetColor(1.0, 1.0, 1.0);
|
|
|
|
|
|
pActor->GetTextProperty()->BoldOff();
|
|
|
|
|
|
pActor->GetTextProperty()->ItalicOff();
|
|
|
|
|
|
pActor->GetTextProperty()->ShadowOn();
|
|
|
|
|
|
pActor->GetTextProperty()->SetShadowOffset(1, -1);
|
|
|
|
|
|
pActor->GetTextProperty()->SetJustificationToLeft();
|
|
|
|
|
|
pActor->GetTextProperty()->SetVerticalJustificationToBottom();
|
|
|
|
|
|
pActor->GetPositionCoordinate()->SetCoordinateSystemToNormalizedViewport();
|
|
|
|
|
|
pActor->GetProperty()->SetDisplayLocationToForeground();
|
|
|
|
|
|
pActor->PickableOff();
|
|
|
|
|
|
pActor->SetVisibility(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nmVTKScalarBarLayer::nmVTKScalarBarLayer(const QString& sLayerId)
|
|
|
|
|
|
: nmVTKRenderLayer(sLayerId),
|
|
|
|
|
|
m_pLookupTable(nullptr),
|
|
|
|
|
|
m_pRootAssembly(vtkSmartPointer<vtkPropAssembly>::New()),
|
|
|
|
|
|
m_pActor(vtkSmartPointer<vtkNmScalarBarActor>::New()),
|
|
|
|
|
|
m_pTitleActor(vtkSmartPointer<vtkTextActor>::New()),
|
|
|
|
|
|
m_pConstantMinimumValueActor(vtkSmartPointer<vtkTextActor>::New()),
|
|
|
|
|
|
m_pConstantMaximumValueActor(vtkSmartPointer<vtkTextActor>::New()),
|
|
|
|
|
|
m_sLabelFormat(QString::fromLatin1("%.6g")),
|
|
|
|
|
|
m_dPositionX(0.0),
|
|
|
|
|
|
m_dPositionY(0.0),
|
|
|
|
|
|
m_dWidth(0.1),
|
|
|
|
|
|
m_dHeight(0.8),
|
|
|
|
|
|
m_nViewportWidth(0),
|
|
|
|
|
|
m_nViewportHeight(0)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
// vtkScalarBarActor 是二维 Prop,仍通过图层基类统一完成挂载和显隐。
|
|
|
|
|
|
m_pActor->SetNumberOfLabels(5);
|
|
|
|
|
|
m_pActor->SetLabelFormat("%.6g");
|
|
|
|
|
|
m_pActor->SetTitle("");
|
|
|
|
|
|
m_pActor->SetOrientationToVertical();
|
|
|
|
|
|
m_pActor->SetTextPositionToSucceedScalarBar();
|
|
|
|
|
|
m_pActor->SetTextPad(3);
|
|
|
|
|
|
m_pActor->UnconstrainedFontSizeOn();
|
|
|
|
|
|
m_pActor->GetLabelTextProperty()->SetFontFamilyToArial();
|
|
|
|
|
|
m_pActor->GetLabelTextProperty()->SetFontSize(
|
|
|
|
|
|
SCALAR_BAR_LABEL_FONT_SIZE);
|
|
|
|
|
|
m_pActor->GetLabelTextProperty()->SetColor(1.0, 1.0, 1.0);
|
|
|
|
|
|
m_pActor->GetLabelTextProperty()->BoldOn();
|
|
|
|
|
|
m_pActor->GetLabelTextProperty()->ItalicOn();
|
|
|
|
|
|
m_pActor->GetLabelTextProperty()->ShadowOn();
|
|
|
|
|
|
m_pActor->GetLabelTextProperty()->SetShadowOffset(1, -1);
|
|
|
|
|
|
m_pActor->SetMaximumWidthInPixels(SCALAR_BAR_TOTAL_WIDTH_PIXELS);
|
|
|
|
|
|
m_pActor->SetBarRatio(
|
|
|
|
|
|
static_cast<double>(SCALAR_BAR_COLOR_WIDTH_PIXELS) /
|
|
|
|
|
|
static_cast<double>(SCALAR_BAR_TOTAL_WIDTH_PIXELS));
|
|
|
|
|
|
m_pActor->GetProperty()->SetDisplayLocationToForeground();
|
|
|
|
|
|
m_pActor->PickableOff();
|
|
|
|
|
|
m_pActor->DrawAnnotationsOff();
|
|
|
|
|
|
m_pActor->DrawBelowRangeSwatchOff();
|
|
|
|
|
|
m_pActor->DrawAboveRangeSwatchOff();
|
|
|
|
|
|
|
|
|
|
|
|
configureTitleActor(m_pTitleActor);
|
|
|
|
|
|
configureConstantValueActor(m_pConstantMinimumValueActor);
|
|
|
|
|
|
configureConstantValueActor(m_pConstantMaximumValueActor);
|
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
|
|
|
|
|
|
|
// 根 Assembly 只在构造时注册,运行期仅更新子 Actor 状态。
|
|
|
|
|
|
m_pRootAssembly->AddPart(m_pActor);
|
|
|
|
|
|
m_pRootAssembly->AddPart(m_pTitleActor);
|
|
|
|
|
|
m_pRootAssembly->AddPart(m_pConstantMinimumValueActor);
|
|
|
|
|
|
m_pRootAssembly->AddPart(m_pConstantMaximumValueActor);
|
|
|
|
|
|
setRenderProp(m_pRootAssembly);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nmVTKScalarBarLayer::~nmVTKScalarBarLayer()
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
// 先移除二维 Prop,再释放对外部 LookupTable 的共享引用。
|
|
|
|
|
|
detach();
|
|
|
|
|
|
m_pLookupTable = nullptr;
|
|
|
|
|
|
m_pConstantMaximumValueActor = nullptr;
|
|
|
|
|
|
m_pConstantMinimumValueActor = nullptr;
|
|
|
|
|
|
m_pTitleActor = nullptr;
|
|
|
|
|
|
m_pActor = nullptr;
|
|
|
|
|
|
m_pRootAssembly = nullptr;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmVTKScalarBarLayer::setLookupTable(vtkLookupTable* pLookupTable)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
if(!isScalarBarGuiThread()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 智能指针共享 LookupTable,保证外部释放原指针后色标仍可安全显示。
|
|
|
|
|
|
m_pLookupTable = pLookupTable;
|
|
|
|
|
|
m_pActor->SetLookupTable(pLookupTable);
|
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vtkLookupTable* nmVTKScalarBarLayer::getLookupTable() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_pLookupTable;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmVTKScalarBarLayer::setTitle(const QString& sTitle)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
if(!isScalarBarGuiThread()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
m_sTitle = sTitle;
|
|
|
|
|
|
// 内置标题永久留空,避免其按整个 ScalarBarActor 宽度自动居中。
|
|
|
|
|
|
m_pActor->SetTitle("");
|
|
|
|
|
|
const QByteArray aTitle = sTitle.toUtf8();
|
|
|
|
|
|
m_pTitleActor->SetInput(aTitle.constData());
|
|
|
|
|
|
m_pTitleActor->SetVisibility(sTitle.isEmpty() ? 0 : 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString nmVTKScalarBarLayer::getTitle() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_sTitle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmVTKScalarBarLayer::setLabelFormat(const QString& sFormat)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
if(!isScalarBarGuiThread() || sFormat.isEmpty()) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
m_sLabelFormat = sFormat;
|
|
|
|
|
|
const QByteArray aFormat = sFormat.toLatin1();
|
|
|
|
|
|
m_pActor->SetLabelFormat(aFormat.constData());
|
|
|
|
|
|
// 格式变化可能改变刻度宽度及 VTK 内部实际色带矩形。
|
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QString nmVTKScalarBarLayer::getLabelFormat() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_sLabelFormat;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmVTKScalarBarLayer::setNumberOfLabels(int nLabelCount)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
if(!isScalarBarGuiThread() || nLabelCount < 0 || nLabelCount > 64) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
m_pActor->SetNumberOfLabels(nLabelCount);
|
|
|
|
|
|
// 标签数量会影响 VTK 内部色带矩形,独立 Overlay 必须同步其最新位置。
|
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int nmVTKScalarBarLayer::getNumberOfLabels() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_pActor != nullptr ? m_pActor->GetNumberOfLabels() : 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmVTKScalarBarLayer::setViewportSize(int nWidth, int nHeight)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
if(!isScalarBarGuiThread() || nWidth <= 0 || nHeight <= 0) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_nViewportWidth = nWidth;
|
|
|
|
|
|
m_nViewportHeight = nHeight;
|
|
|
|
|
|
const bool bSmallViewport =
|
|
|
|
|
|
nHeight < SCALAR_BAR_SMALL_VIEWPORT_HEIGHT;
|
|
|
|
|
|
const double dBottomRatio = bSmallViewport
|
|
|
|
|
|
? SCALAR_BAR_SMALL_BOTTOM_RATIO
|
|
|
|
|
|
: SCALAR_BAR_NORMAL_BOTTOM_RATIO;
|
|
|
|
|
|
const double dHeightRatio = bSmallViewport
|
|
|
|
|
|
? SCALAR_BAR_SMALL_HEIGHT_RATIO
|
|
|
|
|
|
: SCALAR_BAR_NORMAL_HEIGHT_RATIO;
|
|
|
|
|
|
|
|
|
|
|
|
// 小于目标宽度的极端视口会安全收窄;正常窗口保持固定像素宽度。
|
|
|
|
|
|
const int nLeftMargin = qMin(
|
|
|
|
|
|
SCALAR_BAR_LEFT_MARGIN_PIXELS, qMax(0, nWidth - 1));
|
|
|
|
|
|
const int nLayoutWidth = qMin(
|
|
|
|
|
|
SCALAR_BAR_TOTAL_WIDTH_PIXELS,
|
|
|
|
|
|
qMax(1, nWidth - nLeftMargin));
|
|
|
|
|
|
const int nLayoutHeight = qMax(1, qRound(nHeight * dHeightRatio));
|
|
|
|
|
|
m_dPositionX = static_cast<double>(nLeftMargin) / nWidth;
|
|
|
|
|
|
m_dPositionY = dBottomRatio;
|
|
|
|
|
|
m_dWidth = static_cast<double>(nLayoutWidth) / nWidth;
|
|
|
|
|
|
m_dHeight = static_cast<double>(nLayoutHeight) / nHeight;
|
|
|
|
|
|
|
|
|
|
|
|
m_pActor->SetPosition(m_dPositionX, m_dPositionY);
|
|
|
|
|
|
m_pActor->SetWidth(m_dWidth);
|
|
|
|
|
|
m_pActor->SetHeight(m_dHeight);
|
|
|
|
|
|
m_pActor->SetMaximumWidthInPixels(nLayoutWidth);
|
|
|
|
|
|
m_pActor->SetMaximumHeightInPixels(nLayoutHeight);
|
|
|
|
|
|
double dBarRatio =
|
|
|
|
|
|
static_cast<double>(SCALAR_BAR_COLOR_WIDTH_PIXELS) /
|
|
|
|
|
|
static_cast<double>(nLayoutWidth);
|
|
|
|
|
|
if(dBarRatio >= 1.0) {
|
|
|
|
|
|
dBarRatio = 0.95;
|
|
|
|
|
|
}
|
|
|
|
|
|
m_pActor->SetBarRatio(dBarRatio);
|
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int nmVTKScalarBarLayer::getResponsiveLabelCount() const
|
|
|
|
|
|
{
|
|
|
|
|
|
if(m_nViewportHeight <= 0) {
|
|
|
|
|
|
return 5;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(m_nViewportHeight < SCALAR_BAR_SMALL_VIEWPORT_HEIGHT) {
|
|
|
|
|
|
return 4;
|
|
|
|
|
|
}
|
|
|
|
|
|
if(m_nViewportHeight <= SCALAR_BAR_MEDIUM_VIEWPORT_HEIGHT) {
|
|
|
|
|
|
return 6;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const int nBarHeight = qMax(
|
|
|
|
|
|
1, qRound(m_dHeight * m_nViewportHeight));
|
|
|
|
|
|
return qBound(
|
|
|
|
|
|
SCALAR_BAR_MIN_LABEL_COUNT,
|
|
|
|
|
|
qRound(static_cast<double>(nBarHeight) /
|
|
|
|
|
|
SCALAR_BAR_LABEL_SPACING_PIXELS),
|
|
|
|
|
|
SCALAR_BAR_MAX_LABEL_COUNT);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmVTKScalarBarLayer::setConstantValueLabel(
|
|
|
|
|
|
bool bVisible,
|
|
|
|
|
|
const QString& sText)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
if(!isScalarBarGuiThread()) {
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
m_sConstantValueText = bVisible ? sText : QString();
|
|
|
|
|
|
const QByteArray aText = m_sConstantValueText.toUtf8();
|
|
|
|
|
|
m_pConstantMinimumValueActor->SetInput(aText.constData());
|
|
|
|
|
|
m_pConstantMaximumValueActor->SetInput(aText.constData());
|
|
|
|
|
|
const int nVisibility =
|
|
|
|
|
|
bVisible && !m_sConstantValueText.isEmpty() ? 1 : 0;
|
|
|
|
|
|
m_pConstantMinimumValueActor->SetVisibility(nVisibility);
|
|
|
|
|
|
m_pConstantMaximumValueActor->SetVisibility(nVisibility);
|
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmVTKScalarBarLayer::setPosition(double dX, double dY)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
if(!isScalarBarGuiThread() || !vtkMath::IsFinite(dX) ||
|
|
|
|
|
|
!vtkMath::IsFinite(dY)) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
// vtkScalarBarActor 默认使用归一化视口坐标,位置值由上层布局策略决定。
|
|
|
|
|
|
m_dPositionX = dX;
|
|
|
|
|
|
m_dPositionY = dY;
|
|
|
|
|
|
m_pActor->SetPosition(dX, dY);
|
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool nmVTKScalarBarLayer::setSize(double dWidth, double dHeight)
|
|
|
|
|
|
{
|
|
|
|
|
|
Q_ASSERT(isScalarBarGuiThread());
|
|
|
|
|
|
if(!isScalarBarGuiThread() || !vtkMath::IsFinite(dWidth) ||
|
|
|
|
|
|
!vtkMath::IsFinite(dHeight) || dWidth <= 0.0 || dHeight <= 0.0) {
|
|
|
|
|
|
return false;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 这里只拒绝非正尺寸,不替业务层限制色标是否超出视口。
|
|
|
|
|
|
m_dWidth = dWidth;
|
|
|
|
|
|
m_dHeight = dHeight;
|
|
|
|
|
|
m_pActor->SetWidth(dWidth);
|
|
|
|
|
|
m_pActor->SetHeight(dHeight);
|
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
|
return true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void nmVTKScalarBarLayer::updateOverlayLayout()
|
|
|
|
|
|
{
|
|
|
|
|
|
const bool bHasViewport =
|
|
|
|
|
|
m_nViewportWidth > 0 && m_nViewportHeight > 0;
|
|
|
|
|
|
const double dPixelX = bHasViewport
|
|
|
|
|
|
? 1.0 / m_nViewportWidth : 0.01;
|
|
|
|
|
|
const double dPixelY = bHasViewport
|
|
|
|
|
|
? 1.0 / m_nViewportHeight : 0.01;
|
|
|
|
|
|
double dColorX = m_dPositionX;
|
|
|
|
|
|
double dColorY = m_dPositionY;
|
|
|
|
|
|
double dColorWidth = bHasViewport
|
|
|
|
|
|
? SCALAR_BAR_VISIBLE_COLOR_WIDTH_PIXELS * dPixelX
|
|
|
|
|
|
: m_dWidth * 0.33;
|
|
|
|
|
|
double dColorHeight = m_dHeight;
|
|
|
|
|
|
if(dColorWidth > m_dWidth) {
|
|
|
|
|
|
dColorWidth = m_dWidth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vtkRenderer* pRenderer = getAttachedRenderer();
|
|
|
|
|
|
vtkNmScalarBarActor* pLayoutActor =
|
|
|
|
|
|
vtkNmScalarBarActor::SafeDownCast(m_pActor);
|
|
|
|
|
|
if(bHasViewport && pRenderer != nullptr &&
|
|
|
|
|
|
m_pLookupTable != nullptr && pLayoutActor != nullptr &&
|
|
|
|
|
|
pLayoutActor->refreshLayout(pRenderer)) {
|
|
|
|
|
|
// vtkScalarBarActor 的 Position/Size 是包含刻度留白的外框;端点和
|
|
|
|
|
|
// 其他装饰必须先刷新布局,再读取最终计算出的实际彩色色带矩形。
|
|
|
|
|
|
int nColorBarRect[4] = { 0, 0, 0, 0 };
|
|
|
|
|
|
m_pActor->GetScalarBarRect(nColorBarRect, pRenderer);
|
|
|
|
|
|
double dLeft = nColorBarRect[0];
|
|
|
|
|
|
double dBottom = nColorBarRect[1];
|
|
|
|
|
|
double dRight = nColorBarRect[0] + nColorBarRect[2];
|
|
|
|
|
|
double dTop = nColorBarRect[1] + nColorBarRect[3];
|
|
|
|
|
|
pRenderer->ViewportToNormalizedViewport(dLeft, dBottom);
|
|
|
|
|
|
pRenderer->ViewportToNormalizedViewport(dRight, dTop);
|
|
|
|
|
|
if(vtkMath::IsFinite(dLeft) && vtkMath::IsFinite(dBottom) &&
|
|
|
|
|
|
vtkMath::IsFinite(dRight) && vtkMath::IsFinite(dTop) &&
|
|
|
|
|
|
dRight > dLeft && dTop > dBottom) {
|
|
|
|
|
|
dColorX = dLeft;
|
|
|
|
|
|
dColorY = dBottom;
|
|
|
|
|
|
dColorWidth = dRight - dLeft;
|
|
|
|
|
|
dColorHeight = dTop - dBottom;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 单值属性在色带上下端重复显示真实值,位置与普通端点刻度一致。
|
|
|
|
|
|
const double dLabelX = dColorX + dColorWidth +
|
|
|
|
|
|
SCALAR_BAR_LABEL_GAP_PIXELS * dPixelX;
|
|
|
|
|
|
m_pConstantMinimumValueActor->GetPositionCoordinate()->SetValue(
|
|
|
|
|
|
dLabelX, dColorY, 0.0);
|
|
|
|
|
|
m_pConstantMaximumValueActor->GetPositionCoordinate()->SetValue(
|
|
|
|
|
|
dLabelX, dColorY + dColorHeight, 0.0);
|
|
|
|
|
|
|
|
|
|
|
|
// 标题固定放在实际色带左上方;极小视口下向下钳制避免裁切。
|
|
|
|
|
|
const double dDesiredTitleY =
|
|
|
|
|
|
dColorY + dColorHeight +
|
|
|
|
|
|
SCALAR_BAR_TITLE_OFFSET_Y_PIXELS * dPixelY;
|
|
|
|
|
|
const double dMaximumTitleY = bHasViewport
|
|
|
|
|
|
? qMax(0.0, 1.0 -
|
|
|
|
|
|
SCALAR_BAR_TITLE_SAFE_HEIGHT_PIXELS * dPixelY)
|
|
|
|
|
|
: dDesiredTitleY;
|
|
|
|
|
|
const double dTitleY = qMin(dDesiredTitleY, dMaximumTitleY);
|
|
|
|
|
|
m_pTitleActor->GetPositionCoordinate()->SetValue(
|
|
|
|
|
|
dColorX, dTitleY, 0.0);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
vtkScalarBarActor* nmVTKScalarBarLayer::getActor() const
|
|
|
|
|
|
{
|
|
|
|
|
|
return m_pActor;
|
|
|
|
|
|
}
|