You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/Src/nmNum/nmSubWxs/nmWxPropertyInterpolationPr...

621 lines
26 KiB
C++

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#include "nmWxPropertyInterpolationPreviewDlg.h"
#include <QApplication>
#include <QCoreApplication>
#include <QDesktopWidget>
#include <QHBoxLayout>
#include <QPushButton>
#include <QSizePolicy>
#include <QVBoxLayout>
#include <QVTKWidget.h>
#include <vtkActor.h>
#include <vtkActor2D.h>
#include <vtkBandedPolyDataContourFilter.h>
#include <vtkCamera.h>
#include <vtkCellArray.h>
#include <vtkDataArray.h>
#include <vtkDelaunay2D.h>
#include <vtkDoubleArray.h>
#include <vtkExtractPolyDataGeometry.h>
#include <vtkImplicitSelectionLoop.h>
#include <vtkInteractorStyleImage.h>
#include <vtkLabeledDataMapper.h>
#include <vtkLookupTable.h>
#include <vtkPointData.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkScalarBarActor.h>
#include <vtkSmartPointer.h>
#include <vtkStringArray.h>
#include <vtkTextActor.h>
#include <vtkTextProperty.h>
#include <vtkVertexGlyphFilter.h>
namespace
{
QString previewText(const char* sourceText)
{
return QCoreApplication::translate("nmWxPropertyInterpolationPreviewDlg", sourceText);
}
vtkSmartPointer<vtkLookupTable> createPreviewLookupTable(double minimum,
double maximum)
{
vtkSmartPointer<vtkLookupTable> lookupTable =
vtkSmartPointer<vtkLookupTable>::New();
lookupTable->SetNumberOfTableValues(256);
lookupTable->SetRange(minimum, maximum);
lookupTable->SetHueRange(0.60, 0.02);
lookupTable->SetSaturationRange(0.50, 0.50);
lookupTable->SetValueRange(0.96, 0.96);
lookupTable->Build();
return lookupTable;
}
void showPreviewFailure(vtkRenderer* renderer,
vtkRenderWindow* renderWindow,
const QString& message)
{
if(renderer == NULL || renderWindow == NULL) {
return;
}
vtkSmartPointer<vtkTextActor> messageActor =
vtkSmartPointer<vtkTextActor>::New();
const QString displayMessage = message.isEmpty() ?
previewText("Preview Failed") : message;
messageActor->SetInput(displayMessage.toUtf8().constData());
messageActor->SetDisplayPosition(24, 24);
messageActor->GetTextProperty()->SetColor(0.75, 0.15, 0.12);
messageActor->GetTextProperty()->SetFontSize(16);
renderer->AddActor2D(messageActor);
renderWindow->Render();
}
}
nmWxPropertyInterpolationPreviewDlg::nmWxPropertyInterpolationPreviewDlg(
const QString& dataSetName,
const QString& scalarTitle,
const QRectF& bounds,
int columnCount,
int rowCount,
const QVector<double>& interpolationValues,
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
const QVector<QPointF>& outlinePoints,
const QVector<QPointF>& wellPoints,
const QStringList& wellNames,
bool showMeasurementPoints,
bool showMeasurementLabels,
QWidget* parent)
: iDlgBase(parent),
m_pVtkWidget(NULL)
{
setWindowModality(Qt::NonModal);
setModal(false);
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->setContentsMargins(8, 8, 8, 8);
mainLayout->setSpacing(8);
m_pVtkWidget = new QVTKWidget(this);
m_pVtkWidget->setSizePolicy(QSizePolicy::Expanding,
QSizePolicy::Expanding);
mainLayout->addWidget(m_pVtkWidget, 1);
QHBoxLayout* buttonLayout = new QHBoxLayout;
buttonLayout->addStretch();
QPushButton* closeButton = new QPushButton(previewText("Close"), this);
buttonLayout->addWidget(closeButton);
mainLayout->addLayout(buttonLayout);
connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
updatePreview(dataSetName, scalarTitle, bounds, columnCount, rowCount,
interpolationValues, measurementPoints,
measurementValues, outlinePoints, wellPoints, wellNames,
showMeasurementPoints, showMeasurementLabels);
}
QSize nmWxPropertyInterpolationPreviewDlg::sizeHint() const
{
QDesktopWidget* desktop = QApplication::desktop();
if(desktop == NULL) {
return iDlgBase::sizeHint();
}
// 预览窗口随当前屏幕可用区域调整,避免固定像素尺寸在不同分辨率下失衡.
const QRect availableRect = desktop->availableGeometry(this);
return QSize(availableRect.width() * 1 / 2,
availableRect.height() * 4 / 5);
}
void nmWxPropertyInterpolationPreviewDlg::updatePreview(
const QString& dataSetName,
const QString& scalarTitle,
const QRectF& bounds,
int columnCount,
int rowCount,
const QVector<double>& interpolationValues,
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
const QVector<QPointF>& outlinePoints,
const QVector<QPointF>& wellPoints,
const QStringList& wellNames,
bool showMeasurementPoints,
bool showMeasurementLabels)
{
setWindowTitle(previewText("Interpolation Preview") + " - " + dataSetName);
initializeRenderer(scalarTitle, bounds, columnCount, rowCount,
interpolationValues, measurementPoints,
measurementValues, outlinePoints, wellPoints, wellNames,
showMeasurementPoints, showMeasurementLabels);
}
void nmWxPropertyInterpolationPreviewDlg::showMessage(
const QString& dataSetName,
const QString& message)
{
if(m_pVtkWidget == NULL) {
return;
}
QString windowTitle = previewText("Interpolation Preview");
if(!dataSetName.isEmpty()) {
windowTitle += " - " + dataSetName;
}
setWindowTitle(windowTitle);
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetMultiSamples(0);
renderWindow->AddRenderer(renderer);
m_pVtkWidget->SetRenderWindow(renderWindow);
showPreviewFailure(renderer, renderWindow, message);
}
void nmWxPropertyInterpolationPreviewDlg::initializeRenderer(
const QString& scalarTitle,
const QRectF& bounds,
int columnCount,
int rowCount,
const QVector<double>& interpolationValues,
const QVector<QPointF>& measurementPoints,
const QVector<double>& measurementValues,
const QVector<QPointF>& outlinePoints,
const QVector<QPointF>& wellPoints,
const QStringList& wellNames,
bool showMeasurementPoints,
bool showMeasurementLabels)
{
if(m_pVtkWidget == NULL) {
return;
}
// 显式创建渲染窗口避免使用尚未初始化的QVTKWidget默认窗口.
vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetMultiSamples(0);
renderWindow->AddRenderer(renderer);
m_pVtkWidget->SetRenderWindow(renderWindow);
if(columnCount < 2 || rowCount < 2 ||
bounds.width() <= 0.0 || bounds.height() <= 0.0 ||
interpolationValues.size() != columnCount * rowCount) {
showPreviewFailure(renderer, renderWindow, previewText("Preview Failed"));
return;
}
// 规则采样点使用Kriging结果测点作为额外顶点直接使用已知值.
vtkSmartPointer<vtkPoints> surfacePoints =
vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkDoubleArray> scalarArray =
vtkSmartPointer<vtkDoubleArray>::New();
scalarArray->SetName("InterpolatedValue");
scalarArray->SetNumberOfComponents(1);
const double spacingX = bounds.width() / (columnCount - 1);
const double spacingY = bounds.height() / (rowCount - 1);
for(int row = 0; row < rowCount; ++row) {
const double y = bounds.top() + spacingY * row;
for(int column = 0; column < columnCount; ++column) {
const int valueIndex = row * columnCount + column;
const double x = bounds.left() + spacingX * column;
surfacePoints->InsertNextPoint(x, y, 0.0);
scalarArray->InsertNextValue(interpolationValues[valueIndex]);
}
}
if(measurementPoints.size() == measurementValues.size()) {
const double coordinateTolerance = qMax(
qMax(bounds.width(), bounds.height()) * 1.0e-10,
1.0e-12);
const int regularPointCount = surfacePoints->GetNumberOfPoints();
for(int i = 0; i < measurementPoints.size(); ++i) {
vtkIdType matchingPointId = -1;
for(int pointIndex = 0; pointIndex < regularPointCount; ++pointIndex) {
double regularPoint[3] = { 0.0, 0.0, 0.0 };
surfacePoints->GetPoint(pointIndex, regularPoint);
if(qAbs(regularPoint[0] - measurementPoints[i].x()) <= coordinateTolerance &&
qAbs(regularPoint[1] - measurementPoints[i].y()) <= coordinateTolerance) {
matchingPointId = pointIndex;
break;
}
}
if(matchingPointId >= 0) {
scalarArray->SetValue(matchingPointId, measurementValues[i]);
}
else {
surfacePoints->InsertNextPoint(measurementPoints[i].x(),
measurementPoints[i].y(), 0.0);
scalarArray->InsertNextValue(measurementValues[i]);
}
}
}
vtkSmartPointer<vtkPolyData> surfaceData =
vtkSmartPointer<vtkPolyData>::New();
surfaceData->SetPoints(surfacePoints);
surfaceData->GetPointData()->SetScalars(scalarArray);
vtkSmartPointer<vtkDelaunay2D> triangulationFilter =
vtkSmartPointer<vtkDelaunay2D>::New();
triangulationFilter->SetInputData(surfaceData);
triangulationFilter->SetProjectionPlaneMode(VTK_DELAUNAY_XY_PLANE);
triangulationFilter->SetTolerance(0.0);
triangulationFilter->BoundingTriangulationOff();
triangulationFilter->Update();
// 默认使用完整三角网格;仅在裁剪结果有效且保留标量时切换.
vtkPolyData* visibleSurface = triangulationFilter->GetOutput();
vtkSmartPointer<vtkExtractPolyDataGeometry> extractFilter;
vtkSmartPointer<vtkImplicitSelectionLoop> selectionLoop;
vtkSmartPointer<vtkPoints> selectionPoints;
if(outlinePoints.size() >= 3) {
selectionPoints = vtkSmartPointer<vtkPoints>::New();
for(int i = 0; i < outlinePoints.size(); ++i) {
selectionPoints->InsertNextPoint(outlinePoints[i].x(),
outlinePoints[i].y(), 0.0);
}
selectionLoop = vtkSmartPointer<vtkImplicitSelectionLoop>::New();
selectionLoop->SetLoop(selectionPoints);
selectionLoop->AutomaticNormalGenerationOff();
selectionLoop->SetNormal(0.0, 0.0, 1.0);
extractFilter = vtkSmartPointer<vtkExtractPolyDataGeometry>::New();
extractFilter->SetInputConnection(triangulationFilter->GetOutputPort());
extractFilter->SetImplicitFunction(selectionLoop);
extractFilter->ExtractInsideOn();
extractFilter->ExtractBoundaryCellsOn();
extractFilter->Update();
vtkPolyData* extractedSurface = extractFilter->GetOutput();
if(extractedSurface != NULL &&
extractedSurface->GetNumberOfPoints() > 0 &&
extractedSurface->GetPointData() != NULL &&
extractedSurface->GetPointData()->GetScalars() != NULL) {
visibleSurface = extractedSurface;
}
}
if(visibleSurface == NULL || visibleSurface->GetNumberOfPoints() == 0 ||
visibleSurface->GetPointData() == NULL ||
visibleSurface->GetPointData()->GetScalars() == NULL) {
showPreviewFailure(renderer, renderWindow, previewText("Preview Failed"));
return;
}
vtkDataArray* interpolatedScalars =
visibleSurface->GetPointData()->GetScalars();
visibleSurface->GetPointData()->SetScalars(interpolatedScalars);
// 颜色条使用测点值范围,避免规则采样未命中测点时最大、最小值向内收缩.
double displayMinimum = 0.0;
double displayMaximum = 0.0;
if(!measurementValues.isEmpty()) {
displayMinimum = measurementValues[0];
displayMaximum = measurementValues[0];
for(int i = 1; i < measurementValues.size(); ++i) {
displayMinimum = qMin(displayMinimum, measurementValues[i]);
displayMaximum = qMax(displayMaximum, measurementValues[i]);
}
}
else {
double displayRange[2] = { 0.0, 0.0 };
visibleSurface->GetPointData()->GetScalars()->GetRange(displayRange);
displayMinimum = displayRange[0];
displayMaximum = displayRange[1];
}
if(qAbs(displayMaximum - displayMinimum) < 1.0e-12) {
const double padding = qMax(qAbs(displayMinimum) * 0.01, 1.0e-6);
displayMinimum -= padding;
displayMaximum += padding;
}
vtkSmartPointer<vtkLookupTable> lookupTable =
createPreviewLookupTable(displayMinimum, displayMaximum);
// 将连续点标量划分为8级色带Mapper按CellData进行分级着色.
const int colorBandCount = 8;
vtkSmartPointer<vtkBandedPolyDataContourFilter> bandFilter =
vtkSmartPointer<vtkBandedPolyDataContourFilter>::New();
bandFilter->SetInputData(visibleSurface);
bandFilter->GenerateValues(colorBandCount + 1,
displayMinimum, displayMaximum);
bandFilter->SetScalarModeToValue();
bandFilter->GenerateContourEdgesOff();
vtkSmartPointer<vtkPolyDataMapper> surfaceMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
surfaceMapper->SetInputConnection(bandFilter->GetOutputPort());
surfaceMapper->SetScalarModeToUseCellData();
surfaceMapper->SetLookupTable(lookupTable);
surfaceMapper->SetScalarRange(displayMinimum, displayMaximum);
surfaceMapper->ScalarVisibilityOn();
vtkSmartPointer<vtkActor> surfaceActor = vtkSmartPointer<vtkActor>::New();
surfaceActor->SetMapper(surfaceMapper);
surfaceActor->GetProperty()->EdgeVisibilityOff();
renderer->AddActor(surfaceActor);
// 叠加储层边界并通过轻微Z偏移避免与色带表面重合.
if(outlinePoints.size() >= 3) {
vtkSmartPointer<vtkPoints> outlineVtkPoints =
vtkSmartPointer<vtkPoints>::New();
for(int i = 0; i < outlinePoints.size(); ++i) {
outlineVtkPoints->InsertNextPoint(outlinePoints[i].x(),
outlinePoints[i].y(), 0.01);
}
vtkSmartPointer<vtkCellArray> outlineLines =
vtkSmartPointer<vtkCellArray>::New();
outlineLines->InsertNextCell(outlinePoints.size() + 1);
for(int i = 0; i < outlinePoints.size(); ++i) {
outlineLines->InsertCellPoint(i);
}
outlineLines->InsertCellPoint(0);
vtkSmartPointer<vtkPolyData> outlineData =
vtkSmartPointer<vtkPolyData>::New();
outlineData->SetPoints(outlineVtkPoints);
outlineData->SetLines(outlineLines);
vtkSmartPointer<vtkPolyDataMapper> outlineMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
outlineMapper->SetInputData(outlineData);
outlineMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> outlineActor = vtkSmartPointer<vtkActor>::New();
outlineActor->SetMapper(outlineMapper);
outlineActor->GetProperty()->SetColor(0.55, 0.38, 0.22);
outlineActor->GetProperty()->SetLineWidth(1.2);
renderer->AddActor(outlineActor);
}
// 测点和数值标签复用同一组坐标和值,叠加显示在插值面上.
if((showMeasurementPoints || showMeasurementLabels) &&
!measurementPoints.isEmpty() &&
measurementPoints.size() == measurementValues.size()) {
vtkSmartPointer<vtkPoints> measurementVtkPoints =
vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkDoubleArray> measurementScalars =
vtkSmartPointer<vtkDoubleArray>::New();
measurementScalars->SetName("MeasurementValue");
measurementScalars->SetNumberOfComponents(1);
for(int i = 0; i < measurementPoints.size(); ++i) {
measurementVtkPoints->InsertNextPoint(measurementPoints[i].x(),
measurementPoints[i].y(), 0.02);
measurementScalars->InsertNextValue(measurementValues[i]);
}
vtkSmartPointer<vtkPolyData> measurementData =
vtkSmartPointer<vtkPolyData>::New();
measurementData->SetPoints(measurementVtkPoints);
measurementData->GetPointData()->SetScalars(measurementScalars);
if(showMeasurementPoints) {
vtkSmartPointer<vtkVertexGlyphFilter> glyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
glyphFilter->SetInputData(measurementData);
// 深色外层形成清晰描边,避免测点颜色与附近插值色带融为一体.
vtkSmartPointer<vtkPolyDataMapper> borderMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
borderMapper->SetInputConnection(glyphFilter->GetOutputPort());
borderMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> borderActor =
vtkSmartPointer<vtkActor>::New();
borderActor->SetMapper(borderMapper);
borderActor->GetProperty()->SetColor(0.10, 0.10, 0.10);
borderActor->GetProperty()->SetPointSize(9.0);
renderer->AddActor(borderActor);
vtkSmartPointer<vtkPolyDataMapper> measurementMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
measurementMapper->SetInputConnection(glyphFilter->GetOutputPort());
measurementMapper->SetLookupTable(lookupTable);
measurementMapper->SetScalarRange(displayMinimum, displayMaximum);
measurementMapper->SetScalarModeToUsePointData();
vtkSmartPointer<vtkActor> measurementActor =
vtkSmartPointer<vtkActor>::New();
measurementActor->SetMapper(measurementMapper);
measurementActor->GetProperty()->SetPointSize(5.0);
measurementActor->SetPosition(0.0, 0.0, 0.001);
renderer->AddActor(measurementActor);
}
if(showMeasurementLabels) {
// 标签使用独立坐标上移,测点方框仍保持在原始测量位置.
const double labelOffset =
qMax(bounds.width(), bounds.height()) * 0.018;
vtkSmartPointer<vtkPoints> measurementLabelPoints =
vtkSmartPointer<vtkPoints>::New();
for(int i = 0; i < measurementPoints.size(); ++i) {
measurementLabelPoints->InsertNextPoint(
measurementPoints[i].x(),
measurementPoints[i].y() + labelOffset, 0.03);
}
vtkSmartPointer<vtkPolyData> measurementLabelData =
vtkSmartPointer<vtkPolyData>::New();
measurementLabelData->SetPoints(measurementLabelPoints);
measurementLabelData->GetPointData()->SetScalars(
measurementScalars);
vtkSmartPointer<vtkLabeledDataMapper> labelMapper =
vtkSmartPointer<vtkLabeledDataMapper>::New();
labelMapper->SetInputData(measurementLabelData);
labelMapper->SetLabelModeToLabelScalars();
labelMapper->SetLabelFormat("%.6g");
labelMapper->GetLabelTextProperty()->SetColor(0.12, 0.12, 0.12);
labelMapper->GetLabelTextProperty()->SetFontSize(12);
labelMapper->GetLabelTextProperty()->BoldOff();
labelMapper->GetLabelTextProperty()->ItalicOff();
labelMapper->GetLabelTextProperty()->ShadowOff();
labelMapper->GetLabelTextProperty()->SetJustificationToCentered();
labelMapper->GetLabelTextProperty()->SetVerticalJustificationToBottom();
vtkSmartPointer<vtkActor2D> labelActor =
vtkSmartPointer<vtkActor2D>::New();
labelActor->SetMapper(labelMapper);
renderer->AddActor2D(labelActor);
}
}
// Map中显示的井使用独立红色标记和名称叠加不参与插值表面计算.
if(!wellPoints.isEmpty() && wellPoints.size() == wellNames.size()) {
vtkSmartPointer<vtkPoints> wellVtkPoints =
vtkSmartPointer<vtkPoints>::New();
vtkSmartPointer<vtkStringArray> wellNameArray =
vtkSmartPointer<vtkStringArray>::New();
wellNameArray->SetName("WellName");
for(int i = 0; i < wellPoints.size(); ++i) {
wellVtkPoints->InsertNextPoint(wellPoints[i].x(),
wellPoints[i].y(), 0.04);
wellNameArray->InsertNextValue(wellNames[i].toUtf8().constData());
}
vtkSmartPointer<vtkPolyData> wellData =
vtkSmartPointer<vtkPolyData>::New();
wellData->SetPoints(wellVtkPoints);
wellData->GetPointData()->AddArray(wellNameArray);
vtkSmartPointer<vtkVertexGlyphFilter> wellGlyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
wellGlyphFilter->SetInputData(wellData);
vtkSmartPointer<vtkPolyDataMapper> wellBorderMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
wellBorderMapper->SetInputConnection(wellGlyphFilter->GetOutputPort());
wellBorderMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> wellBorderActor =
vtkSmartPointer<vtkActor>::New();
wellBorderActor->SetMapper(wellBorderMapper);
wellBorderActor->GetProperty()->SetColor(0.12, 0.12, 0.12);
wellBorderActor->GetProperty()->SetPointSize(9.0);
renderer->AddActor(wellBorderActor);
vtkSmartPointer<vtkPolyDataMapper> wellMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
wellMapper->SetInputConnection(wellGlyphFilter->GetOutputPort());
wellMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> wellActor = vtkSmartPointer<vtkActor>::New();
wellActor->SetMapper(wellMapper);
wellActor->GetProperty()->SetColor(0.90, 0.12, 0.10);
wellActor->GetProperty()->SetPointSize(5.0);
wellActor->SetPosition(0.0, 0.0, 0.001);
renderer->AddActor(wellActor);
// 井名同样使用独立坐标,避免文字覆盖井位标记.
const double wellLabelOffset =
qMax(bounds.width(), bounds.height()) * 0.022;
vtkSmartPointer<vtkPoints> wellLabelPoints =
vtkSmartPointer<vtkPoints>::New();
for(int i = 0; i < wellPoints.size(); ++i) {
wellLabelPoints->InsertNextPoint(
wellPoints[i].x(),
wellPoints[i].y() + wellLabelOffset, 0.05);
}
vtkSmartPointer<vtkPolyData> wellLabelData =
vtkSmartPointer<vtkPolyData>::New();
wellLabelData->SetPoints(wellLabelPoints);
wellLabelData->GetPointData()->AddArray(wellNameArray);
vtkSmartPointer<vtkLabeledDataMapper> wellLabelMapper =
vtkSmartPointer<vtkLabeledDataMapper>::New();
wellLabelMapper->SetInputData(wellLabelData);
wellLabelMapper->SetLabelModeToLabelFieldData();
wellLabelMapper->SetFieldDataName("WellName");
wellLabelMapper->SetLabelFormat("%s");
wellLabelMapper->GetLabelTextProperty()->SetColor(0.10, 0.10, 0.10);
wellLabelMapper->GetLabelTextProperty()->SetFontSize(13);
wellLabelMapper->GetLabelTextProperty()->BoldOff();
wellLabelMapper->GetLabelTextProperty()->ItalicOff();
wellLabelMapper->GetLabelTextProperty()->ShadowOff();
wellLabelMapper->GetLabelTextProperty()->SetJustificationToCentered();
wellLabelMapper->GetLabelTextProperty()->SetVerticalJustificationToBottom();
vtkSmartPointer<vtkActor2D> wellLabelActor =
vtkSmartPointer<vtkActor2D>::New();
wellLabelActor->SetMapper(wellLabelMapper);
renderer->AddActor2D(wellLabelActor);
}
vtkSmartPointer<vtkScalarBarActor> scalarBar =
vtkSmartPointer<vtkScalarBarActor>::New();
scalarBar->SetLookupTable(lookupTable);
scalarBar->SetTitle(scalarTitle.toUtf8().constData());
scalarBar->SetNumberOfLabels(6);
scalarBar->SetPosition(0.88, 0.12);
scalarBar->SetWidth(0.08);
scalarBar->SetHeight(0.76);
scalarBar->UnconstrainedFontSizeOn();
scalarBar->GetLabelTextProperty()->SetColor(0.15, 0.15, 0.15);
scalarBar->GetLabelTextProperty()->SetFontSize(11);
scalarBar->GetLabelTextProperty()->BoldOff();
scalarBar->GetLabelTextProperty()->ItalicOff();
scalarBar->GetLabelTextProperty()->ShadowOff();
scalarBar->GetTitleTextProperty()->SetColor(0.15, 0.15, 0.15);
scalarBar->GetTitleTextProperty()->SetFontSize(13);
scalarBar->GetTitleTextProperty()->BoldOff();
scalarBar->GetTitleTextProperty()->ItalicOff();
scalarBar->GetTitleTextProperty()->ShadowOff();
renderer->AddActor2D(scalarBar);
// 使用正交相机按模型边界居中显示,保持平面比例并避免透视变形.
vtkCamera* camera = renderer->GetActiveCamera();
const double centerX = bounds.left() + bounds.width() * 0.5;
const double centerY = bounds.top() + bounds.height() * 0.5;
camera->SetPosition(centerX, centerY, 1.0);
camera->SetFocalPoint(centerX, centerY, 0.0);
camera->SetViewUp(0.0, 1.0, 0.0);
camera->ParallelProjectionOn();
double cameraBounds[6] = {
bounds.left(), bounds.right(), bounds.top(), bounds.bottom(), -0.1, 0.1
};
renderer->ResetCamera(cameraBounds);
camera->SetParallelScale(qMax(bounds.height(), bounds.width()) * 0.52);
vtkSmartPointer<vtkInteractorStyleImage> interactorStyle =
vtkSmartPointer<vtkInteractorStyleImage>::New();
renderWindow->GetInteractor()->SetInteractorStyle(interactorStyle);
renderWindow->Render();
}