// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkPlot3D.h" #include "vtkChartXYZ.h" #include "vtkDataArray.h" #include "vtkIdTypeArray.h" #include "vtkLookupTable.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPen.h" #include "vtkPoints.h" #include "vtkStringArray.h" #include "vtkTable.h" VTK_ABI_NAMESPACE_BEGIN //------------------------------------------------------------------------------ vtkPlot3D::vtkPlot3D() { this->Points->SetDataTypeToFloat(); this->Pen = vtkSmartPointer::New(); this->Pen->SetWidth(2.0); this->SelectionPen = vtkSmartPointer::New(); this->SelectionPen->SetColor(255, 50, 0, 150); this->SelectionPen->SetWidth(4.0); this->NumberOfComponents = 0; this->Chart = nullptr; } //------------------------------------------------------------------------------ vtkPlot3D::~vtkPlot3D() = default; //------------------------------------------------------------------------------ void vtkPlot3D::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ void vtkPlot3D::SetPen(vtkPen* pen) { if (this->Pen != pen) { this->Pen = pen; this->Modified(); } } //------------------------------------------------------------------------------ vtkPen* vtkPlot3D::GetSelectionPen() { return this->SelectionPen; } //------------------------------------------------------------------------------ void vtkPlot3D::SetSelectionPen(vtkPen* pen) { if (this->SelectionPen != pen) { this->SelectionPen = pen; this->Modified(); } } //------------------------------------------------------------------------------ vtkPen* vtkPlot3D::GetPen() { return this->Pen; } //------------------------------------------------------------------------------ void vtkPlot3D::SetInputData(vtkTable* input) { assert(input->GetNumberOfColumns() >= 3); // assume the 4th column is color info if available if (input->GetNumberOfColumns() > 3) { this->SetInputData(input, input->GetColumnName(0), input->GetColumnName(1), input->GetColumnName(2), input->GetColumnName(3)); } else { this->SetInputData( input, input->GetColumnName(0), input->GetColumnName(1), input->GetColumnName(2)); } } //------------------------------------------------------------------------------ void vtkPlot3D::SetInputData( vtkTable* input, vtkIdType xColumn, vtkIdType yColumn, vtkIdType zColumn) { this->SetInputData(input, input->GetColumnName(xColumn), input->GetColumnName(yColumn), input->GetColumnName(zColumn)); } //------------------------------------------------------------------------------ void vtkPlot3D::SetInputData( vtkTable* input, const vtkStdString& xName, const vtkStdString& yName, const vtkStdString& zName) { // Copy the points into our data structure for rendering - pack x, y, z... vtkDataArray* xArr = vtkArrayDownCast(input->GetColumnByName(xName.c_str())); vtkDataArray* yArr = vtkArrayDownCast(input->GetColumnByName(yName.c_str())); vtkDataArray* zArr = vtkArrayDownCast(input->GetColumnByName(zName.c_str())); // Ensure that we have valid data arrays, and that they are of the same length. assert(xArr); assert(yArr); assert(zArr); assert(xArr->GetNumberOfTuples() == yArr->GetNumberOfTuples() && xArr->GetNumberOfTuples() == zArr->GetNumberOfTuples()); size_t n = xArr->GetNumberOfTuples(); this->Points->SetNumberOfPoints(n); this->Points->GetData()->CopyComponent(0, xArr, 0); this->Points->GetData()->CopyComponent(1, yArr, 0); this->Points->GetData()->CopyComponent(2, zArr, 0); this->PointsBuildTime.Modified(); // This removes the colors from our points. // They will be (re-)added by SetColors if necessary. this->NumberOfComponents = 0; this->XAxisLabel = xName; this->YAxisLabel = yName; this->ZAxisLabel = zName; this->ComputeDataBounds(); } //------------------------------------------------------------------------------ void vtkPlot3D::SetInputData(vtkTable* input, const vtkStdString& xName, const vtkStdString& yName, const vtkStdString& zName, const vtkStdString& colorName) { this->SetInputData(input, xName, yName, zName); vtkDataArray* colorArr = vtkArrayDownCast(input->GetColumnByName(colorName.c_str())); this->SetColors(colorArr); } //------------------------------------------------------------------------------ void vtkPlot3D::SetColors(vtkDataArray* colorArr) { assert(colorArr); const vtkIdType numPoints = this->Points->GetNumberOfPoints(); assert(colorArr->GetNumberOfTuples() == numPoints); this->NumberOfComponents = 3; // generate a color lookup table vtkNew lookupTable; double min = VTK_DOUBLE_MAX; double max = VTK_DOUBLE_MIN; for (vtkIdType i = 0; i < numPoints; ++i) { double value = colorArr->GetComponent(i, 0); max = std::max(value, max); min = std::min(value, min); } lookupTable->SetNumberOfTableValues(256); lookupTable->SetRange(min, max); lookupTable->Build(); this->Colors->Reset(); // important! The number of components lets graphics code know if alpha channel is present or // not. (rgba vs rgb) this->Colors->SetNumberOfComponents(this->NumberOfComponents); this->Colors->SetNumberOfTuples(numPoints); for (vtkIdType i = 0; i < numPoints; ++i) { double value = colorArr->GetComponent(i, 0); this->Colors->SetTypedTuple(i, lookupTable->MapValue(value)); } this->Modified(); } //------------------------------------------------------------------------------ void vtkPlot3D::ComputeDataBounds() { double bounds[6] = {}; vtkMath::UninitializeBounds(bounds); this->Points->GetBounds(bounds); const double& xMin = bounds[0]; const double& xMax = bounds[1]; const double& yMin = bounds[2]; const double& yMax = bounds[3]; const double& zMin = bounds[4]; const double& zMax = bounds[5]; this->DataBounds.clear(); this->DataBounds.resize(8); float* data = this->DataBounds[0].GetData(); // point 1: xMin, yMin, zMin data[0] = xMin; data[1] = yMin; data[2] = zMin; // point 2: xMin, yMin, zMax data[3] = xMin; data[4] = yMin; data[5] = zMax; // point 3: xMin, yMax, zMin data[6] = xMin; data[7] = yMax; data[8] = zMin; // point 4: xMin, yMax, zMax data[9] = xMin; data[10] = yMax; data[11] = zMax; // point 5: xMax, yMin, zMin data[12] = xMax; data[13] = yMin; data[14] = zMin; // point 6: xMax, yMin, zMax data[15] = xMax; data[16] = yMin; data[17] = zMax; // point 7: xMax, yMax, zMin data[18] = xMax; data[19] = yMax; data[20] = zMin; // point 8: xMax, yMax, zMax data[21] = xMax; data[22] = yMax; data[23] = zMax; } //------------------------------------------------------------------------------ void vtkPlot3D::SetChart(vtkChartXYZ* chart) { this->Chart = chart; } //------------------------------------------------------------------------------ std::string vtkPlot3D::GetXAxisLabel() { return this->XAxisLabel; } //------------------------------------------------------------------------------ std::string vtkPlot3D::GetYAxisLabel() { return this->YAxisLabel; } //------------------------------------------------------------------------------ std::string vtkPlot3D::GetZAxisLabel() { return this->ZAxisLabel; } //------------------------------------------------------------------------------ void vtkPlot3D::SetSelection(vtkIdTypeArray* id) { if (id == this->Selection) { return; } this->Selection = id; this->Modified(); } //------------------------------------------------------------------------------ vtkIdTypeArray* vtkPlot3D::GetSelection() { return this->Selection; } //------------------------------------------------------------------------------ std::vector vtkPlot3D::GetPoints() { std::vector points; const vtkIdType numPoints = this->Points->GetNumberOfPoints(); for (vtkIdType i = 0; i < numPoints; ++i) { double p[3] = {}; this->Points->GetPoint(i, p); points.emplace_back(p[0], p[1], p[2]); } return points; } VTK_ABI_NAMESPACE_END