|
|
|
|
@ -10,17 +10,51 @@
|
|
|
|
|
#include <vtkCoordinate.h>
|
|
|
|
|
#include <vtkLookupTable.h>
|
|
|
|
|
#include <vtkMath.h>
|
|
|
|
|
#include <vtkObjectFactory.h>
|
|
|
|
|
#include <vtkPoints.h>
|
|
|
|
|
#include <vtkPolyData.h>
|
|
|
|
|
#include <vtkPolyDataMapper2D.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。
|
|
|
|
|
@ -40,6 +74,7 @@ const int SCALAR_BAR_SWATCH_HEIGHT_PIXELS = 12;
|
|
|
|
|
const int SCALAR_BAR_SWATCH_GAP_PIXELS = 4;
|
|
|
|
|
const int SCALAR_BAR_TEXT_GAP_PIXELS = 6;
|
|
|
|
|
const int SCALAR_BAR_LABEL_GAP_PIXELS = 8;
|
|
|
|
|
const int SCALAR_BAR_TITLE_CONTENT_GAP_PIXELS = 4;
|
|
|
|
|
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;
|
|
|
|
|
@ -87,7 +122,7 @@ vtkSmartPointer<vtkActor2D> createRangeSwatchActor(vtkPoints* pPoints)
|
|
|
|
|
return pActor;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 独立文本共用字号和颜色;常量值可选择与普通刻度一致的强调样式。
|
|
|
|
|
// 独立文本共用字号和颜色;单值端点可选择与普通刻度一致的强调样式。
|
|
|
|
|
void configureOverlayTextActor(vtkTextActor* pActor,
|
|
|
|
|
bool bUseTickStyle)
|
|
|
|
|
{
|
|
|
|
|
@ -134,6 +169,34 @@ void configureTitleActor(vtkTextActor* pActor)
|
|
|
|
|
pActor->SetVisibility(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 优先读取 VTK 按当前 DPI 计算的真实文字高度,尚未挂载时使用稳定回退值。
|
|
|
|
|
double getOverlayTextHeightPixels(vtkTextActor* pActor,
|
|
|
|
|
vtkRenderer* pRenderer,
|
|
|
|
|
double dFallbackHeight)
|
|
|
|
|
{
|
|
|
|
|
if(pActor == nullptr || pRenderer == nullptr) {
|
|
|
|
|
return dFallbackHeight;
|
|
|
|
|
}
|
|
|
|
|
double dSize[2] = { 0.0, 0.0 };
|
|
|
|
|
pActor->GetSize(pRenderer, dSize);
|
|
|
|
|
return vtkMath::IsFinite(dSize[1]) && dSize[1] > 0.0
|
|
|
|
|
? dSize[1] : dFallbackHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 横向避让仅在极小视口空间不足时使用,正常布局仍保持色块位于色带上方。
|
|
|
|
|
double getOverlayTextWidthPixels(vtkTextActor* pActor,
|
|
|
|
|
vtkRenderer* pRenderer,
|
|
|
|
|
double dFallbackWidth)
|
|
|
|
|
{
|
|
|
|
|
if(pActor == nullptr || pRenderer == nullptr) {
|
|
|
|
|
return dFallbackWidth;
|
|
|
|
|
}
|
|
|
|
|
double dSize[2] = { 0.0, 0.0 };
|
|
|
|
|
pActor->GetSize(pRenderer, dSize);
|
|
|
|
|
return vtkMath::IsFinite(dSize[0]) && dSize[0] > 0.0
|
|
|
|
|
? dSize[0] : dFallbackWidth;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 更新矩形四角并显式标记 Points 已修改,Mapper 会在下一次 Render 使用新位置。
|
|
|
|
|
void updateRectangle(vtkPoints* pPoints,
|
|
|
|
|
double dX, double dY,
|
|
|
|
|
@ -152,9 +215,10 @@ nmVTKScalarBarLayer::nmVTKScalarBarLayer(const QString& sLayerId)
|
|
|
|
|
: nmVTKRenderLayer(sLayerId),
|
|
|
|
|
m_pLookupTable(nullptr),
|
|
|
|
|
m_pRootAssembly(vtkSmartPointer<vtkPropAssembly>::New()),
|
|
|
|
|
m_pActor(vtkSmartPointer<vtkScalarBarActor>::New()),
|
|
|
|
|
m_pActor(vtkSmartPointer<vtkNmScalarBarActor>::New()),
|
|
|
|
|
m_pTitleActor(vtkSmartPointer<vtkTextActor>::New()),
|
|
|
|
|
m_pConstantValueActor(vtkSmartPointer<vtkTextActor>::New()),
|
|
|
|
|
m_pConstantMinimumValueActor(vtkSmartPointer<vtkTextActor>::New()),
|
|
|
|
|
m_pConstantMaximumValueActor(vtkSmartPointer<vtkTextActor>::New()),
|
|
|
|
|
m_pBelowRangeSwatchPoints(vtkSmartPointer<vtkPoints>::New()),
|
|
|
|
|
m_pBelowRangeSwatchActor(nullptr),
|
|
|
|
|
m_pBelowRangeTextActor(vtkSmartPointer<vtkTextActor>::New()),
|
|
|
|
|
@ -204,7 +268,8 @@ nmVTKScalarBarLayer::nmVTKScalarBarLayer(const QString& sLayerId)
|
|
|
|
|
m_pAboveRangeSwatchActor =
|
|
|
|
|
createRangeSwatchActor(m_pAboveRangeSwatchPoints);
|
|
|
|
|
configureTitleActor(m_pTitleActor);
|
|
|
|
|
configureOverlayTextActor(m_pConstantValueActor, true);
|
|
|
|
|
configureOverlayTextActor(m_pConstantMinimumValueActor, true);
|
|
|
|
|
configureOverlayTextActor(m_pConstantMaximumValueActor, true);
|
|
|
|
|
configureOverlayTextActor(m_pBelowRangeTextActor, false);
|
|
|
|
|
configureOverlayTextActor(m_pAboveRangeTextActor, false);
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
@ -212,7 +277,8 @@ nmVTKScalarBarLayer::nmVTKScalarBarLayer(const QString& sLayerId)
|
|
|
|
|
// 根 Assembly 只在构造时注册,运行期仅更新子 Actor 状态。
|
|
|
|
|
m_pRootAssembly->AddPart(m_pActor);
|
|
|
|
|
m_pRootAssembly->AddPart(m_pTitleActor);
|
|
|
|
|
m_pRootAssembly->AddPart(m_pConstantValueActor);
|
|
|
|
|
m_pRootAssembly->AddPart(m_pConstantMinimumValueActor);
|
|
|
|
|
m_pRootAssembly->AddPart(m_pConstantMaximumValueActor);
|
|
|
|
|
m_pRootAssembly->AddPart(m_pBelowRangeSwatchActor);
|
|
|
|
|
m_pRootAssembly->AddPart(m_pBelowRangeTextActor);
|
|
|
|
|
m_pRootAssembly->AddPart(m_pAboveRangeSwatchActor);
|
|
|
|
|
@ -232,7 +298,8 @@ nmVTKScalarBarLayer::~nmVTKScalarBarLayer()
|
|
|
|
|
m_pBelowRangeTextActor = nullptr;
|
|
|
|
|
m_pBelowRangeSwatchActor = nullptr;
|
|
|
|
|
m_pBelowRangeSwatchPoints = nullptr;
|
|
|
|
|
m_pConstantValueActor = nullptr;
|
|
|
|
|
m_pConstantMaximumValueActor = nullptr;
|
|
|
|
|
m_pConstantMinimumValueActor = nullptr;
|
|
|
|
|
m_pTitleActor = nullptr;
|
|
|
|
|
m_pActor = nullptr;
|
|
|
|
|
m_pRootAssembly = nullptr;
|
|
|
|
|
@ -248,6 +315,7 @@ void nmVTKScalarBarLayer::setLookupTable(vtkLookupTable* pLookupTable)
|
|
|
|
|
m_pLookupTable = pLookupTable;
|
|
|
|
|
m_pActor->SetLookupTable(pLookupTable);
|
|
|
|
|
updateRangeSwatchColors();
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
vtkLookupTable* nmVTKScalarBarLayer::getLookupTable() const
|
|
|
|
|
@ -267,6 +335,8 @@ void nmVTKScalarBarLayer::setTitle(const QString& sTitle)
|
|
|
|
|
const QByteArray aTitle = sTitle.toUtf8();
|
|
|
|
|
m_pTitleActor->SetInput(aTitle.constData());
|
|
|
|
|
m_pTitleActor->SetVisibility(sTitle.isEmpty() ? 0 : 1);
|
|
|
|
|
// 标题宽度参与极小视口下 Above max 的横向避让。
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString nmVTKScalarBarLayer::getTitle() const
|
|
|
|
|
@ -283,6 +353,8 @@ bool nmVTKScalarBarLayer::setLabelFormat(const QString& sFormat)
|
|
|
|
|
m_sLabelFormat = sFormat;
|
|
|
|
|
const QByteArray aFormat = sFormat.toLatin1();
|
|
|
|
|
m_pActor->SetLabelFormat(aFormat.constData());
|
|
|
|
|
// 格式变化可能改变刻度宽度及 VTK 内部实际色带矩形。
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -298,6 +370,8 @@ bool nmVTKScalarBarLayer::setNumberOfLabels(int nLabelCount)
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
m_pActor->SetNumberOfLabels(nLabelCount);
|
|
|
|
|
// 标签数量会影响 VTK 内部色带矩形,独立 Overlay 必须同步其最新位置。
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -387,6 +461,7 @@ void nmVTKScalarBarLayer::setBelowRangeSwatch(
|
|
|
|
|
m_pBelowRangeSwatchActor->SetVisibility(bVisible ? 1 : 0);
|
|
|
|
|
m_pBelowRangeTextActor->SetVisibility(
|
|
|
|
|
bVisible && !m_sBelowRangeText.isEmpty() ? 1 : 0);
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmVTKScalarBarLayer::setAboveRangeSwatch(
|
|
|
|
|
@ -403,6 +478,7 @@ void nmVTKScalarBarLayer::setAboveRangeSwatch(
|
|
|
|
|
m_pAboveRangeSwatchActor->SetVisibility(bVisible ? 1 : 0);
|
|
|
|
|
m_pAboveRangeTextActor->SetVisibility(
|
|
|
|
|
bVisible && !m_sAboveRangeText.isEmpty() ? 1 : 0);
|
|
|
|
|
updateOverlayLayout();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void nmVTKScalarBarLayer::setConstantValueLabel(
|
|
|
|
|
@ -416,9 +492,13 @@ void nmVTKScalarBarLayer::setConstantValueLabel(
|
|
|
|
|
|
|
|
|
|
m_sConstantValueText = bVisible ? sText : QString();
|
|
|
|
|
const QByteArray aText = m_sConstantValueText.toUtf8();
|
|
|
|
|
m_pConstantValueActor->SetInput(aText.constData());
|
|
|
|
|
m_pConstantValueActor->SetVisibility(
|
|
|
|
|
bVisible && !m_sConstantValueText.isEmpty() ? 1 : 0);
|
|
|
|
|
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)
|
|
|
|
|
@ -460,33 +540,49 @@ void nmVTKScalarBarLayer::updateOverlayLayout()
|
|
|
|
|
? 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 常量值与普通刻度共用色带右侧的固定像素起点。
|
|
|
|
|
const double dLabelX = m_dPositionX + dColorWidth +
|
|
|
|
|
SCALAR_BAR_LABEL_GAP_PIXELS * dPixelX;
|
|
|
|
|
const double dLabelY = m_dPositionY + m_dHeight * 0.5;
|
|
|
|
|
m_pConstantValueActor->GetPositionCoordinate()->SetValue(
|
|
|
|
|
dLabelX, dLabelY, 0.0);
|
|
|
|
|
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 dDesiredTitleY =
|
|
|
|
|
m_dPositionY + m_dHeight +
|
|
|
|
|
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(
|
|
|
|
|
m_dPositionX,
|
|
|
|
|
dTitleY,
|
|
|
|
|
0.0);
|
|
|
|
|
// 单值属性在色带上下端重复显示真实值,位置与普通端点刻度一致。
|
|
|
|
|
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 dSwatchWidth = bHasViewport
|
|
|
|
|
@ -498,21 +594,101 @@ void nmVTKScalarBarLayer::updateOverlayLayout()
|
|
|
|
|
? SCALAR_BAR_SWATCH_GAP_PIXELS * dPixelY : 0.012;
|
|
|
|
|
const double dTextGap = bHasViewport
|
|
|
|
|
? SCALAR_BAR_TEXT_GAP_PIXELS * dPixelX : 0.008;
|
|
|
|
|
const bool bConstantLabelsVisible =
|
|
|
|
|
m_pConstantMinimumValueActor->GetVisibility() != 0 &&
|
|
|
|
|
!m_sConstantValueText.isEmpty();
|
|
|
|
|
const double dConstantTextHeight = getOverlayTextHeightPixels(
|
|
|
|
|
m_pConstantMinimumValueActor, pRenderer,
|
|
|
|
|
SCALAR_BAR_LABEL_FONT_SIZE);
|
|
|
|
|
const bool bBelowRangeVisible =
|
|
|
|
|
m_pBelowRangeSwatchActor->GetVisibility() != 0;
|
|
|
|
|
const bool bAboveRangeVisible =
|
|
|
|
|
m_pAboveRangeSwatchActor->GetVisibility() != 0;
|
|
|
|
|
const double dBelowTextHeight = getOverlayTextHeightPixels(
|
|
|
|
|
m_pBelowRangeTextActor, pRenderer,
|
|
|
|
|
SCALAR_BAR_LABEL_FONT_SIZE);
|
|
|
|
|
const double dAboveTextHeight = getOverlayTextHeightPixels(
|
|
|
|
|
m_pAboveRangeTextActor, pRenderer,
|
|
|
|
|
SCALAR_BAR_LABEL_FONT_SIZE);
|
|
|
|
|
const double dBelowClearance =
|
|
|
|
|
bConstantLabelsVisible && bBelowRangeVisible
|
|
|
|
|
? qMax(0.0,
|
|
|
|
|
(dConstantTextHeight + dBelowTextHeight -
|
|
|
|
|
SCALAR_BAR_SWATCH_HEIGHT_PIXELS) * 0.5 * dPixelY)
|
|
|
|
|
: 0.0;
|
|
|
|
|
const double dAboveClearance =
|
|
|
|
|
bConstantLabelsVisible && bAboveRangeVisible
|
|
|
|
|
? qMax(0.0,
|
|
|
|
|
(dConstantTextHeight + dAboveTextHeight -
|
|
|
|
|
SCALAR_BAR_SWATCH_HEIGHT_PIXELS) * 0.5 * dPixelY)
|
|
|
|
|
: 0.0;
|
|
|
|
|
// 单值端点与越界说明可以同时启用。将越界注记整体向外错开,
|
|
|
|
|
// 保证其文字区域不会覆盖位于实际色带端点的单值标签。
|
|
|
|
|
const double dBelowY =
|
|
|
|
|
m_dPositionY - dSwatchGap - dSwatchHeight;
|
|
|
|
|
const double dAboveY =
|
|
|
|
|
m_dPositionY + m_dHeight + dSwatchGap;
|
|
|
|
|
dColorY - dSwatchGap - dSwatchHeight -
|
|
|
|
|
dBelowClearance;
|
|
|
|
|
double dAboveX = dColorX;
|
|
|
|
|
double dAboveY =
|
|
|
|
|
dColorY + dColorHeight + dSwatchGap +
|
|
|
|
|
dAboveClearance;
|
|
|
|
|
|
|
|
|
|
// 标题默认保持原有偏移;Above max 向外避让后若更高,则标题继续上移。
|
|
|
|
|
const double dAboveTextHalfHeight =
|
|
|
|
|
m_pAboveRangeTextActor->GetVisibility() != 0
|
|
|
|
|
? dAboveTextHeight * 0.5 * dPixelY : 0.0;
|
|
|
|
|
const double dAboveContentHalfHeight = qMax(
|
|
|
|
|
dSwatchHeight * 0.5, dAboveTextHalfHeight);
|
|
|
|
|
const double dAboveContentTop =
|
|
|
|
|
dAboveY + dSwatchHeight * 0.5 +
|
|
|
|
|
dAboveContentHalfHeight;
|
|
|
|
|
const double dBaseTitleY =
|
|
|
|
|
dColorY + dColorHeight +
|
|
|
|
|
SCALAR_BAR_TITLE_OFFSET_Y_PIXELS * dPixelY;
|
|
|
|
|
const double dDesiredTitleY = bAboveRangeVisible
|
|
|
|
|
? qMax(dBaseTitleY,
|
|
|
|
|
dAboveContentTop +
|
|
|
|
|
SCALAR_BAR_TITLE_CONTENT_GAP_PIXELS * dPixelY)
|
|
|
|
|
: dBaseTitleY;
|
|
|
|
|
const double dMaximumTitleY = bHasViewport
|
|
|
|
|
? qMax(0.0, 1.0 -
|
|
|
|
|
SCALAR_BAR_TITLE_SAFE_HEIGHT_PIXELS * dPixelY)
|
|
|
|
|
: dDesiredTitleY;
|
|
|
|
|
const double dTitleY = qMin(dDesiredTitleY, dMaximumTitleY);
|
|
|
|
|
|
|
|
|
|
if(bAboveRangeVisible &&
|
|
|
|
|
dTitleY < dAboveContentTop +
|
|
|
|
|
SCALAR_BAR_TITLE_CONTENT_GAP_PIXELS * dPixelY) {
|
|
|
|
|
// 极小视口无法同时向上容纳标题和 Above max。此时保持标题不越界,
|
|
|
|
|
// 并把越界注记放到标题、单值标签两者的右侧,消除水平交叠。
|
|
|
|
|
const double dConstantTextWidth = bConstantLabelsVisible
|
|
|
|
|
? getOverlayTextWidthPixels(
|
|
|
|
|
m_pConstantMaximumValueActor, pRenderer,
|
|
|
|
|
m_sConstantValueText.length() *
|
|
|
|
|
SCALAR_BAR_LABEL_FONT_SIZE * 0.6)
|
|
|
|
|
: 0.0;
|
|
|
|
|
const double dTitleWidth = getOverlayTextWidthPixels(
|
|
|
|
|
m_pTitleActor, pRenderer,
|
|
|
|
|
m_sTitle.length() *
|
|
|
|
|
SCALAR_BAR_TITLE_FONT_SIZE * 0.6);
|
|
|
|
|
dAboveX = qMax(
|
|
|
|
|
dLabelX + dConstantTextWidth * dPixelX + dTextGap,
|
|
|
|
|
dColorX + dTitleWidth * dPixelX + dTextGap);
|
|
|
|
|
dAboveY = dColorY + dColorHeight - dSwatchHeight * 0.5;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_pTitleActor->GetPositionCoordinate()->SetValue(
|
|
|
|
|
dColorX, dTitleY, 0.0);
|
|
|
|
|
updateRectangle(m_pBelowRangeSwatchPoints,
|
|
|
|
|
m_dPositionX, dBelowY,
|
|
|
|
|
dColorX, dBelowY,
|
|
|
|
|
dSwatchWidth, dSwatchHeight);
|
|
|
|
|
updateRectangle(m_pAboveRangeSwatchPoints,
|
|
|
|
|
m_dPositionX, dAboveY,
|
|
|
|
|
dAboveX, dAboveY,
|
|
|
|
|
dSwatchWidth, dSwatchHeight);
|
|
|
|
|
m_pBelowRangeTextActor->GetPositionCoordinate()->SetValue(
|
|
|
|
|
m_dPositionX + dSwatchWidth + dTextGap,
|
|
|
|
|
dColorX + dSwatchWidth + dTextGap,
|
|
|
|
|
dBelowY + dSwatchHeight * 0.5, 0.0);
|
|
|
|
|
m_pAboveRangeTextActor->GetPositionCoordinate()->SetValue(
|
|
|
|
|
m_dPositionX + dSwatchWidth + dTextGap,
|
|
|
|
|
dAboveX + dSwatchWidth + dTextGap,
|
|
|
|
|
dAboveY + dSwatchHeight * 0.5, 0.0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|