// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkCutMaterial.h" #include "vtkCell.h" #include "vtkCellData.h" #include "vtkCutter.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPlane.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkThreshold.h" #include "vtkUnstructuredGrid.h" VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkCutMaterial); // Instantiate object with no input and no defined output. vtkCutMaterial::vtkCutMaterial() { this->MaterialArrayName = nullptr; this->SetMaterialArrayName("material"); this->Material = 0; this->ArrayName = nullptr; this->UpVector[0] = 0.0; this->UpVector[1] = 0.0; this->UpVector[2] = 1.0; this->MaximumPoint[0] = 0.0; this->MaximumPoint[1] = 0.0; this->MaximumPoint[2] = 0.0; this->CenterPoint[0] = 0.0; this->CenterPoint[1] = 0.0; this->CenterPoint[2] = 0.0; this->Normal[0] = 0.0; this->Normal[1] = 1.0; this->Normal[2] = 0.0; this->PlaneFunction = vtkPlane::New(); } vtkCutMaterial::~vtkCutMaterial() { this->PlaneFunction->Delete(); this->PlaneFunction = nullptr; this->SetMaterialArrayName(nullptr); this->SetArrayName(nullptr); } int vtkCutMaterial::RequestData(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // get the info objects vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); vtkInformation* outInfo = outputVector->GetInformationObject(0); // get the input and output vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkThreshold* thresh; vtkCutter* cutter; // Check to see if we have the required field arrays. if (this->MaterialArrayName == nullptr || this->ArrayName == nullptr) { vtkErrorMacro("Material and Array names must be set."); return 0; } if (input->GetCellData()->GetArray(this->MaterialArrayName) == nullptr) { vtkErrorMacro("Could not find cell array " << this->MaterialArrayName); return 0; } if (input->GetCellData()->GetArray(this->ArrayName) == nullptr) { vtkErrorMacro("Could not find cell array " << this->ArrayName); return 0; } // It would be nice to get rid of this in the future. thresh = vtkThreshold::New(); thresh->SetInputData(input); thresh->SetInputArrayToProcess( 0, 0, 0, vtkDataObject::FIELD_ASSOCIATION_CELLS, this->MaterialArrayName); thresh->SetThresholdFunction(vtkThreshold::THRESHOLD_BETWEEN); thresh->SetLowerThreshold(this->Material - 0.5); thresh->SetUpperThreshold(this->Material + 0.5); thresh->Update(); const double* bds = thresh->GetOutput()->GetBounds(); this->CenterPoint[0] = 0.5 * (bds[0] + bds[1]); this->CenterPoint[1] = 0.5 * (bds[2] + bds[3]); this->CenterPoint[2] = 0.5 * (bds[4] + bds[5]); this->ComputeMaximumPoint(thresh->GetOutput()); this->ComputeNormal(); this->PlaneFunction->SetOrigin(this->CenterPoint); this->PlaneFunction->SetNormal(this->Normal); cutter = vtkCutter::New(); cutter->SetInputConnection(thresh->GetOutputPort()); cutter->SetCutFunction(this->PlaneFunction); cutter->SetValue(0, 0.0); cutter->Update(); output->CopyStructure(cutter->GetOutput()); output->GetPointData()->PassData(cutter->GetOutput()->GetPointData()); output->GetCellData()->PassData(cutter->GetOutput()->GetCellData()); cutter->Delete(); thresh->Delete(); return 1; } void vtkCutMaterial::ComputeNormal() { double tmp[3]; double mag; if (this->UpVector[0] == 0.0 && this->UpVector[1] == 0.0 && this->UpVector[2] == 0.0) { vtkErrorMacro("Zero magnitude UpVector."); this->UpVector[2] = 1.0; } tmp[0] = this->MaximumPoint[0] - this->CenterPoint[0]; tmp[1] = this->MaximumPoint[1] - this->CenterPoint[1]; tmp[2] = this->MaximumPoint[2] - this->CenterPoint[2]; vtkMath::Cross(tmp, this->UpVector, this->Normal); mag = vtkMath::Normalize(this->Normal); // Rare singularity while (mag == 0.0) { tmp[0] = vtkMath::Random(); tmp[1] = vtkMath::Random(); tmp[2] = vtkMath::Random(); vtkMath::Cross(tmp, this->UpVector, this->Normal); mag = vtkMath::Normalize(this->Normal); } } void vtkCutMaterial::ComputeMaximumPoint(vtkDataSet* input) { vtkDataArray* data; vtkIdType idx, bestIdx, num; double comp, best; vtkCell* cell; // Find the maximum value. data = input->GetCellData()->GetArray(this->ArrayName); if (data == nullptr) { vtkErrorMacro("What happened to the array " << this->ArrayName); return; } num = data->GetNumberOfTuples(); if (num <= 0) { vtkErrorMacro("No values in array " << this->ArrayName); return; } best = data->GetComponent(0, 0); bestIdx = 0; for (idx = 1; idx < num; ++idx) { comp = data->GetComponent(idx, 0); if (comp > best) { best = comp; bestIdx = idx; } } // Get the cell with the larges value. cell = input->GetCell(bestIdx); const double* bds = cell->GetBounds(); this->MaximumPoint[0] = (bds[0] + bds[1]) * 0.5; this->MaximumPoint[1] = (bds[2] + bds[3]) * 0.5; this->MaximumPoint[2] = (bds[4] + bds[5]) * 0.5; } int vtkCutMaterial::FillInputPortInformation(int, vtkInformation* info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); return 1; } void vtkCutMaterial::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "ArrayName: "; if (this->ArrayName) { os << this->ArrayName << endl; } else { os << "(None)" << endl; } os << indent << "MaterialArrayName: " << this->MaterialArrayName << endl; os << indent << "Material: " << this->Material << endl; os << indent << "UpVector: " << this->UpVector[0] << ", " << this->UpVector[1] << ", " << this->UpVector[2] << endl; os << indent << "MaximumPoint: " << this->MaximumPoint[0] << ", " << this->MaximumPoint[1] << ", " << this->MaximumPoint[2] << endl; os << indent << "CenterPoint: " << this->CenterPoint[0] << ", " << this->CenterPoint[1] << ", " << this->CenterPoint[2] << endl; os << indent << "Normal: " << this->Normal[0] << ", " << this->Normal[1] << ", " << this->Normal[2] << endl; } VTK_ABI_NAMESPACE_END