comac_desk_app/PostProcessing/WidgetCutter.cpp

728 lines
24 KiB
C++
Raw Normal View History

2024-11-21 11:50:43 +08:00
#include "WidgetCutter.h"
#include <vtkCellData.h>
#include <vtkPointData.h>
#include <vtkDataSet.h>
#include <vtkOutlineFilter.h>
#include <vtkScalarBarRepresentation.h>
#include <vtkPolyDataWriter.h>
#include <vtkCutter.h>
#include <vtkActor.h>
#include <vtkPlane.h>
#include <vtkPlanes.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkLookupTable.h>
#include <vtkScalarBarWidget.h>
#include <vtkScalarBarActor.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkDoubleArray.h>
namespace pst
{
WidgetCutter::WidgetCutter()
: m_inputData(vtkSmartPointer<vtkPolyData>::New())
, m_inputDataOriginal(vtkSmartPointer<vtkPolyData>::New())
, m_planeWidget(vtkSmartPointer<vtkPlaneWidget>::New())
, m_plane(vtkSmartPointer<vtkPlane>::New())
, m_boxWidget(vtkSmartPointer<vtkBoxWidget>::New())
, m_planes(vtkSmartPointer<vtkPlanes>::New())
, m_cutter(vtkSmartPointer<vtkCutter>::New())
, m_selectedDataMapper(vtkSmartPointer<vtkPolyDataMapper>::New())
, m_cutterDataActor(vtkSmartPointer<vtkActor>::New())
, m_cutterWidgetCall(vtkSmartPointer<vtkWidgetCall>::New())
, m_lookupTable(vtkSmartPointer<vtkLookupTable>::New())
, m_scalarBarWidget(vtkSmartPointer<vtkScalarBarWidget>::New())
, m_scalarBarActor(vtkSmartPointer<vtkScalarBarActor>::New())
, m_dataOutlineActor(vtkSmartPointer<vtkActor>::New())
, m_interactor(vtkSmartPointer<vtkRenderWindowInteractor>::New())
, m_cutterDataToSave(vtkSmartPointer<vtkPolyData>::New())
, m_currentWidgetType(WidgetType::PLANE)
, m_currentAddedPointArrayIndex{ -1 }
, m_currentAddedCellArrayIndex{ -1 }
, m_isScalarAttributeSet{ false }
, m_currentArrayRange{ 0,11 }
{
InitLookupTable();
InitPipeLine();
}
void WidgetCutter::SetInteractor(vtkRenderWindowInteractor* iren)
{
m_planeWidget->SetInteractor(iren);
m_boxWidget->SetInteractor(iren);
m_scalarBarWidget->SetInteractor(iren);
m_interactor = iren;
}
void WidgetCutter::SetInputData(vtkDataSet* dataSet)
{
m_inputData = dataSet;
m_inputDataOriginal->DeepCopy(dataSet);
}
std::vector<WidgetCutter::ArrayInformation>
WidgetCutter::GetPointsArrayIndexAndNames()
{
return GetPointsArrayIndexAndNames(m_inputDataOriginal);
}
std::vector<WidgetCutter::ArrayInformation>
WidgetCutter::GetCellsArrayIndexAndNames()
{
return GetCellsArrayIndexAndNames(m_inputDataOriginal);
}
bool WidgetCutter::SetActiveScalarAttribute(int index,
const StructureType type, const int compIndex)
{
auto polyData = vtkPointSet::SafeDownCast(m_inputData);
//移除上次额外添加的数组
polyData->GetPointData()->RemoveArray(m_currentAddedPointArrayIndex);
polyData->GetCellData()->RemoveArray(m_currentAddedCellArrayIndex);
switch (type)
{
case StructureType::POINTS:
{
if (index >= m_inputData->GetPointData()->GetNumberOfArrays() || index < -1)
{
std::cout << "Error! Index illegal!" << std::endl;
return false;
}
auto activeScalarArray = m_inputData->GetPointData()->GetArray(index);
const auto nComponents = activeScalarArray->GetNumberOfComponents();
auto time1 = clock();
//单组分array,忽略组分提取,直接设置
if (nComponents == 1)
{
m_inputData->GetPointData()->SetActiveAttribute(
index, vtkDataSetAttributes::AttributeTypes::SCALARS);
m_lookupTable->SetTableRange(activeScalarArray->GetRange());
m_currentArrayRange[0] = activeScalarArray->GetRange()[0];
m_currentArrayRange[1] = activeScalarArray->GetRange()[1];
}
else
{
if (compIndex < -1 || compIndex >= nComponents)
{
std::cout << "Error! Extracting component index is " << compIndex
<< ", current array component is " << nComponents << std::endl;
return false;
}
vtkNew<vtkDoubleArray> magArray;
bool isSuccess = GetSingleComponent(activeScalarArray, compIndex, magArray);
if (!isSuccess)
{
std::cout << "Extract component failed!" << std::endl;
return false;
}
m_currentAddedPointArrayIndex = polyData->GetPointData()->AddArray(magArray);
m_inputData->GetPointData()->SetActiveAttribute(
m_currentAddedPointArrayIndex, vtkDataSetAttributes::AttributeTypes::SCALARS);
m_lookupTable->SetTableRange(magArray->GetRange());
m_currentArrayRange[0] = magArray->GetRange()[0];
m_currentArrayRange[1] = magArray->GetRange()[1];
}
auto time2 = clock();
std::cout << "Add scalar time = " << time2 - time1 << std::endl;
m_selectedDataMapper->SetScalarModeToUsePointData();
break;
}
case StructureType::CELLS:
{
if (index >= m_inputData->GetCellData()->GetNumberOfArrays() || index < 0)
{
std::cout << "Error! Index illegal!" << std::endl;
return false;
}
auto activeScalarArray = m_inputData->GetCellData()->GetArray(index);
const auto nComponents = activeScalarArray->GetNumberOfComponents();
auto time1 = clock();
//单组分array,忽略组分提取,直接设置
if (nComponents == 1)
{
m_inputData->GetCellData()->SetActiveAttribute(
index, vtkDataSetAttributes::AttributeTypes::SCALARS);
m_lookupTable->SetTableRange(activeScalarArray->GetRange());
m_currentArrayRange[0] = activeScalarArray->GetRange()[0];
m_currentArrayRange[1] = activeScalarArray->GetRange()[1];
}
else
{
if (compIndex < -1 || compIndex >= nComponents)
{
std::cout << "Error! Extracting component index is " << compIndex
<< ", current array component is " << nComponents << std::endl;
return false;
}
vtkNew<vtkDoubleArray> magArray;
bool isSuccess = GetSingleComponent(activeScalarArray, compIndex, magArray);
if (!isSuccess)
{
std::cout << "Extract component failed!" << std::endl;
return false;
}
m_currentAddedCellArrayIndex = polyData->GetCellData()->AddArray(magArray);
std::cout << "indexxxxx = " << m_currentAddedCellArrayIndex << std::endl;
m_inputData->GetCellData()->SetActiveAttribute(
m_currentAddedCellArrayIndex, vtkDataSetAttributes::AttributeTypes::SCALARS);
m_lookupTable->SetTableRange(magArray->GetRange());
m_currentArrayRange[0] = magArray->GetRange()[0];
m_currentArrayRange[1] = magArray->GetRange()[1];
}
auto time2 = clock();
std::cout << "Add scalar time = " << time2 - time1 << std::endl;
m_selectedDataMapper->SetScalarModeToUseCellData();
// m_currentUsingScalarType = StructureType::CELLS;
break;
}
default:
std::cout << "Wrong structure type" << std::endl;
return false;
break;
}
m_isScalarAttributeSet = true;
return true;
}
void WidgetCutter::SetWidgetType(WidgetType type)
{
m_currentWidgetType = type;
}
void WidgetCutter::SetPlaneNormalDirection(PlaneNormalDirection direction)
{
//PlaceWidget必须先于SetNormal调用但似乎该函数并无效果。
// m_planeWidget->PlaceWidget(m_inputData->GetBounds());
switch (direction)
{
case PlaneNormalDirection::X:
{
m_planeWidget->SetNormal(1, 0, 0);
m_plane->SetNormal(1, 0, 0);
break;
}
case PlaneNormalDirection::Y:
{
m_planeWidget->SetNormal(0, 1, 0);
m_plane->SetNormal(0, 1, 0);
break;
}
case PlaneNormalDirection::Z:
{
m_planeWidget->SetNormal(0, 0, 1);
m_plane->SetNormal(0, 0, 1);
break;
}
default:
{
break;
}
}
}
void WidgetCutter::SetRepresentationType(PlaneRepresentation type)
{
switch (type)
{
// case PlaneRepresentation::OUTLINE:
// {
//// m_planeWidget->SetRepresentationToOutline();
// m_cutterDataActor->GetProperty()->SetRepresentationToPoints();
// break;
// }
case PlaneRepresentation::WIREFRAME:
{
// m_planeWidget->SetRepresentationToWireframe();
m_cutterDataActor->GetProperty()->SetRepresentationToWireframe();
break;
}
case PlaneRepresentation::SURFACE:
{
// m_planeWidget->SetRepresentationToSurface();
m_cutterDataActor->GetProperty()->SetRepresentationToSurface();
break;
}
case PlaneRepresentation::POINTS:
{
m_cutterDataActor->GetProperty()->SetRepresentationToPoints();
break;
}
default:
{
break;
}
}
}
void WidgetCutter::SetCenter(double x[3])
{
m_planeWidget->SetCenter(x);
m_plane->SetOrigin(x);
}
void WidgetCutter::TurnAllWidgetOff()
{
if (m_planeWidget->GetInteractor())
{
m_planeWidget->Off();
}
if (m_boxWidget->GetInteractor())
{
m_boxWidget->Off();
}
}
void WidgetCutter::TurnWidgetOn()
{
switch (m_currentWidgetType)
{
case WidgetType::BOX:
m_boxWidget->On();
break;
case WidgetType::PLANE:
m_planeWidget->On();
break;
default:
break;
}
}
void WidgetCutter::Update()
{
m_boxWidget->SetInputData(m_inputData);
m_boxWidget->PlaceWidget(m_inputData->GetBounds());
m_planes->SetBounds(m_inputData->GetBounds());
//默认开启plane
m_planeWidget->SetInputData(m_inputData);
m_planeWidget->PlaceWidget(m_inputData->GetBounds());
m_planeWidget->On();
m_cutterWidgetCall->SetCallbackWidgetType(vtkWidgetCall::CallbackWidgetType::PLANE);
m_cutter->SetCutFunction(m_plane);
m_cutter->SetInputData(m_inputData);
m_cutter->Update();
m_selectedDataMapper->Update();
m_scalarBarWidget->SetScalarBarActor(m_scalarBarActor);
// m_scalarBarWidget->SetResizable(true);
vtkScalarBarRepresentation* rep =
vtkScalarBarRepresentation::SafeDownCast(m_scalarBarWidget->GetRepresentation());
rep->SetPosition2(0.05, 0.7);
rep->SetPosition(0.01, 0.1);
m_scalarBarWidget->On();
GenerateDataOutlineBox();
}
void WidgetCutter::refreshWidget()
{
switch (m_currentWidgetType)
{
//将widget的interactor置空SetInteractor(NULL)
//是为了能让每个widget都能响应键盘事件否则其只响应最早设置interactor的widget
case WidgetType::BOX:
{
m_planeWidget->Off();
m_planeWidget->SetInteractor(nullptr);
m_boxWidget->SetInteractor(m_interactor);
m_boxWidget->On();
//置空再设置是为了让interactor优先响应m_boxWidget键盘事件
m_scalarBarWidget->SetInteractor(nullptr);
m_scalarBarWidget->SetInteractor(m_interactor);
m_scalarBarWidget->On();
m_cutter->SetCutFunction(m_planes);
m_cutterWidgetCall->SetCallbackWidgetType(vtkWidgetCall::CallbackWidgetType::BOX);
m_cutterWidgetCall->Execute(m_boxWidget, 0, nullptr);
break;
}
case WidgetType::PLANE:
{
m_boxWidget->Off();
m_boxWidget->SetInteractor(nullptr);
m_planeWidget->SetInteractor(m_interactor);
m_planeWidget->On();
//置空再设置是为了让interactor优先响应m_planeWidget键盘事件
m_scalarBarWidget->SetInteractor(nullptr);
m_scalarBarWidget->SetInteractor(m_interactor);
m_scalarBarWidget->On();
m_cutter->SetCutFunction(m_plane);
m_cutterWidgetCall->SetCallbackWidgetType(vtkWidgetCall::CallbackWidgetType::PLANE);
m_cutterWidgetCall->Execute(m_planeWidget, 0, nullptr);
break;
}
default:
break;
}
}
vtkProperty* WidgetCutter::GetWidgetPlaneProperty()
{
return m_planeWidget->GetPlaneProperty();
}
vtkProperty* WidgetCutter::GetWidgetHandelProperty()
{
return m_planeWidget->GetHandleProperty();
}
vtkPlaneWidget* WidgetCutter::GetPlaneWidget()
{
return m_planeWidget;
}
vtkBoxWidget* WidgetCutter::GetBoxWidget()
{
return m_boxWidget;
}
vtkCutter* WidgetCutter::GetCutter()
{
return m_cutter;
}
vtkPolyDataMapper* WidgetCutter::GetMapper()
{
return m_selectedDataMapper;
}
vtkActor* WidgetCutter::GetCutterActor()
{
return m_cutterDataActor;
}
bool WidgetCutter::SetScalarBarRangeToAuto()
{
if (!m_isScalarAttributeSet)
{
std::cout << "Error, scalars attribute must be set !" << std::endl;
return false;
}
m_lookupTable->SetTableRange(m_currentArrayRange[0], m_currentArrayRange[1]);
return true;
}
void WidgetCutter::SetScalarBarRange(const double min, const double max)
{
m_lookupTable->SetTableRange(min, max);
}
void WidgetCutter::SetScalarBarTitle(const std::string& title)
{
m_scalarBarActor->SetTitle(title.c_str());
}
void WidgetCutter::SetScalarBarNumberOfLabel(const int num)
{
m_scalarBarActor->SetNumberOfLabels(num);
}
void WidgetCutter::SetScalarBarDisplayPosition(const int x, const int y)
{
m_scalarBarActor->SetDisplayPosition(x, y);
}
vtkScalarBarActor* WidgetCutter::GetScalarBar()
{
return m_scalarBarActor;
}
void WidgetCutter::SetDataOutlineActorColor(const double r, const double g, const double b)
{
m_dataOutlineActor->GetProperty()->SetColor(r, g, b);
}
vtkActor* WidgetCutter::GetDataOutlineActor()
{
return m_dataOutlineActor;
}
void WidgetCutter::WriteTheCutterData(const std::string& fileName)
{
vtkNew<vtkPolyDataWriter> writer;
writer->SetInputData(m_cutterDataToSave);
writer->SetFileName(fileName.c_str());
try
{
writer->Update();
}
catch (const std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
void WidgetCutter::ResetCurrentWidgetPositon()
{
switch (m_currentWidgetType)
{
case WidgetType::BOX:
m_boxWidget->PlaceWidget(m_inputData->GetBounds());
break;
case WidgetType::PLANE:
m_planeWidget->SetCenter(m_inputData->GetCenter());
m_planeWidget->PlaceWidget(m_inputData->GetBounds());
break;
default:
break;
}
}
vtkLookupTable* WidgetCutter::GetLookupTable()
{
return m_lookupTable;
}
void WidgetCutter::SetLookupTable(vtkLookupTable* lookupTable)
{
m_lookupTable = lookupTable;
}
void WidgetCutter::InitPipeLine()
{
m_planeWidget->SetResolution(10);
m_planeWidget->SetHandleSize(0.001);
m_planeWidget->SetPlaceFactor(0.1);
m_planeWidget->GetPlaneProperty()->SetColor(.9, .4, .4);
m_planeWidget->GetPlaneProperty()->SetPointSize(2);
m_planeWidget->GetHandleProperty()->SetColor(0, .4, .7);
m_planeWidget->GetHandleProperty()->SetLineWidth(1.5);
m_planeWidget->SetRepresentationToOutline();
m_planeWidget->SetPlaceFactor(1);
m_boxWidget->SetPlaceFactor(1);
m_boxWidget->SetHandleSize(0.003);
m_boxWidget->SetPlaceFactor(1);
m_cutterWidgetCall->m_planes = m_planes;
m_scalarBarActor->SetTitle("Cutter");
m_scalarBarActor->SetLookupTable(m_lookupTable);
// m_scalarBarActor->SetDisplayPosition(10,10);
m_scalarBarActor->SetPosition(0.01, 0.1);
m_scalarBarActor->SetPosition2(0.05, 0.7);
m_cutterWidgetCall->m_singlePlane = m_plane;
m_planeWidget->AddObserver(vtkCommand::InteractionEvent, m_cutterWidgetCall);
m_boxWidget->AddObserver(vtkCommand::InteractionEvent, m_cutterWidgetCall);
m_selectedDataMapper->SetInterpolateScalarsBeforeMapping(true);
m_selectedDataMapper->SetColorModeToMapScalars();
m_selectedDataMapper->ScalarVisibilityOn();
m_selectedDataMapper->SetUseLookupTableScalarRange(1);
m_selectedDataMapper->SetInputConnection(m_cutter->GetOutputPort());
m_selectedDataMapper->SetLookupTable(m_lookupTable);
m_cutterDataActor->SetMapper(m_selectedDataMapper);
}
void WidgetCutter::InitLookupTable()
{
//色调范围从蓝色到红色
m_lookupTable->SetNumberOfColors(600);
m_lookupTable->SetHueRange(0.67, 0.0);
m_lookupTable->Build();
}
void WidgetCutter::GenerateDataOutlineBox()
{
vtkNew<vtkOutlineFilter> outline;
outline->SetInputData(m_inputData);
vtkNew<vtkPolyDataMapper> outlineMapper;
outlineMapper->SetInputConnection(outline->GetOutputPort());
outlineMapper->Update();
m_dataOutlineActor->SetMapper(outlineMapper);
}
bool
WidgetCutter::GetSingleComponent(vtkDataArray* array,
const int componentIndex, vtkDoubleArray* returnArray)
{
auto nComponents = array->GetNumberOfComponents();
std::cout << " nComponents = " << nComponents << std::endl;
//检查下标合法性,-1代表取magnitude
if (componentIndex < -1 || componentIndex >= nComponents)
{
return false;
}
//取单个组分的属性的0组分即返回自己
if (componentIndex == 0 && nComponents == 1)
{
returnArray->DeepCopy(vtkDoubleArray::SafeDownCast(array));
return true;
}
const auto nTuples = array->GetNumberOfTuples();
std::cout << " nTuples = " << nTuples << std::endl;
vtkNew<vtkDoubleArray> singleArray;
singleArray->SetNumberOfComponents(1);
singleArray->SetNumberOfTuples(nTuples);
//取magnitude
if (componentIndex == -1)
{
std::cout << "magnitude " << std::endl;
singleArray->SetName("Magnitude");
for (vtkIdType i = 0; i < nTuples; ++i)
{
double mag = 0;
for (int j = 0; j < nComponents; ++j)
{
double tmp = array->GetComponent(i, j);
mag += tmp * tmp;
}
mag = sqrt(mag);
singleArray->InsertTuple1(i, mag);
}
}
else //取现有的单个组件
{
std::cout << "extract comp = " << componentIndex << std::endl;
if (componentIndex == 0)
{
singleArray->SetName("X");
}
else if (componentIndex == 1)
{
singleArray->SetName("Y");
}
else if (componentIndex == 2)
{
singleArray->SetName("Z");
}
else
{
singleArray->SetName(std::to_string(componentIndex).c_str());
}
for (vtkIdType j = 0; j < nTuples; ++j)
{
singleArray->InsertTuple1(j, array->GetComponent(j, componentIndex));
}
}
returnArray->DeepCopy(singleArray);
return true;
}
void
WidgetCutter::SelectFieldsToSaveForCutter(bool useOrigianl,
const std::vector<ArrayInformation>& selectedPointsFiledId,
const std::vector<ArrayInformation>& selectedCellsFiledId)
{
m_cutterDataToSave->DeepCopy(m_cutter->GetOutput());
if (useOrigianl)
{
auto pointsInfoOriginal = GetPointsArrayIndexAndNames(m_inputDataOriginal);
auto cellsInfoOriginal = GetCellsArrayIndexAndNames(m_inputDataOriginal);
SelectArrayFromCutterData(pointsInfoOriginal, cellsInfoOriginal);
}
else
{
SelectArrayFromCutterData(selectedPointsFiledId, selectedCellsFiledId);
}
}
std::vector<WidgetCutter::ArrayInformation>
WidgetCutter::GetPointsArrayIndexAndNames(vtkDataSet* data)
{
std::vector<WidgetCutter::ArrayInformation> arrayInfoVector;
WidgetCutter::ArrayInformation tempInfo;
for (int i = 0; i < data->GetPointData()->GetNumberOfArrays(); ++i)
{
tempInfo.arrayIndex = i;
tempInfo.arrayName = data->GetPointData()->GetArrayName(i);
tempInfo.arrayComponent = data->GetPointData()->GetArray(i)->GetNumberOfComponents();
arrayInfoVector.push_back(tempInfo);
}
return arrayInfoVector;
}
std::vector<WidgetCutter::ArrayInformation>
WidgetCutter::GetCellsArrayIndexAndNames(vtkDataSet* data)
{
std::vector<WidgetCutter::ArrayInformation> arrayInfoVector;
WidgetCutter::ArrayInformation tempInfo;
for (int i = 0; i < data->GetCellData()->GetNumberOfArrays(); ++i)
{
tempInfo.arrayIndex = i;
tempInfo.arrayName = data->GetCellData()->GetArrayName(i);
tempInfo.arrayComponent = data->GetCellData()->GetArray(i)->GetNumberOfComponents();
arrayInfoVector.push_back(tempInfo);
}
return arrayInfoVector;
}
void WidgetCutter::SelectArrayFromCutterData(
const std::vector<ArrayInformation>& selectedPointsFiled,
const std::vector<ArrayInformation>& selectedCellsFiled)
{
auto pointsInfoCutter = GetPointsArrayIndexAndNames(m_cutterDataToSave);
auto cellsInfoCutter = GetCellsArrayIndexAndNames(m_cutterDataToSave);
for (int i = 0; i < pointsInfoCutter.size(); ++i)
{
for (int j = 0; j < selectedPointsFiled.size(); ++j)
{
//在其中,需要保留
if (pointsInfoCutter[i].arrayIndex == selectedPointsFiled[j].arrayIndex)
{
break;
}
//没找到,不在其中,移除多余列
if (j == selectedPointsFiled.size() - 1)
{
m_cutterDataToSave->GetPointData()->RemoveArray(pointsInfoCutter[i].arrayIndex);
}
}
}
for (int i = 0; i < cellsInfoCutter.size(); ++i)
{
for (int j = 0; j < selectedCellsFiled.size(); ++j)
{
//在其中,需要保留
if (cellsInfoCutter[i].arrayIndex == selectedCellsFiled[j].arrayIndex)
{
break;
}
if (j == selectedCellsFiled.size() - 1)
{
m_cutterDataToSave->GetCellData()->RemoveArray(cellsInfoCutter[i].arrayIndex);
}
}
}
}
}