// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkImageToStructuredPoints.h" #include "vtkCellData.h" #include "vtkDataArray.h" #include "vtkFieldData.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkStructuredPoints.h" #include VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkImageToStructuredPoints); //------------------------------------------------------------------------------ vtkImageToStructuredPoints::vtkImageToStructuredPoints() { this->SetNumberOfInputPorts(2); this->Translate[0] = this->Translate[1] = this->Translate[2] = 0; } //------------------------------------------------------------------------------ vtkImageToStructuredPoints::~vtkImageToStructuredPoints() = default; //------------------------------------------------------------------------------ void vtkImageToStructuredPoints::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); } //------------------------------------------------------------------------------ vtkStructuredPoints* vtkImageToStructuredPoints::GetStructuredPointsOutput() { return vtkStructuredPoints::SafeDownCast(this->GetOutputDataObject(0)); } //------------------------------------------------------------------------------ void vtkImageToStructuredPoints::SetVectorInputData(vtkImageData* input) { this->SetInputData(1, input); } //------------------------------------------------------------------------------ vtkImageData* vtkImageToStructuredPoints::GetVectorInput() { if (this->GetNumberOfInputConnections(1) < 1) { return nullptr; } return vtkImageData::SafeDownCast(this->GetExecutive()->GetInputData(1, 0)); } //------------------------------------------------------------------------------ int vtkImageToStructuredPoints::RequestData( vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); vtkInformation* vectorInfo = inputVector[1]->GetInformationObject(0); vtkInformation* outInfo = outputVector->GetInformationObject(0); int uExtent[6]; int* wExtent; int idxX, idxY, idxZ; int maxX = 0; int maxY = 0; int maxZ = 0; vtkIdType inIncX, inIncY, inIncZ; int rowLength; unsigned char *inPtr1, *inPtr, *outPtr; vtkStructuredPoints* output = vtkStructuredPoints::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkImageData* data = vtkImageData::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkImageData* vData = nullptr; if (vectorInfo) { vData = vtkImageData::SafeDownCast(vectorInfo->Get(vtkDataObject::DATA_OBJECT())); } outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), uExtent); output->SetExtent(uExtent); uExtent[0] += this->Translate[0]; uExtent[1] += this->Translate[0]; uExtent[2] += this->Translate[1]; uExtent[3] += this->Translate[1]; uExtent[4] += this->Translate[2]; uExtent[5] += this->Translate[2]; // if the data extent matches the update extent then just pass the data // otherwise we must reformat and copy the data if (data) { wExtent = data->GetExtent(); if (wExtent[0] == uExtent[0] && wExtent[1] == uExtent[1] && wExtent[2] == uExtent[2] && wExtent[3] == uExtent[3] && wExtent[4] == uExtent[4] && wExtent[5] == uExtent[5]) { if (data->GetPointData()) { output->GetPointData()->PassData(data->GetPointData()); } if (data->GetCellData()) { output->GetCellData()->PassData(data->GetCellData()); } if (data->GetFieldData()) { output->GetFieldData()->ShallowCopy(data->GetFieldData()); } } else { inPtr = static_cast(data->GetScalarPointerForExtent(uExtent)); outPtr = static_cast(output->GetScalarPointer()); // Make sure there are data. if (!inPtr || !outPtr) { output->Initialize(); return 1; } // Get increments to march through data data->GetIncrements(inIncX, inIncY, inIncZ); // find the region to loop over rowLength = (uExtent[1] - uExtent[0] + 1) * inIncX * data->GetScalarSize(); maxX = uExtent[1] - uExtent[0]; maxY = uExtent[3] - uExtent[2]; maxZ = uExtent[5] - uExtent[4]; inIncY *= data->GetScalarSize(); inIncZ *= data->GetScalarSize(); // Loop through output pixels for (idxZ = 0; idxZ <= maxZ; idxZ++) { inPtr1 = inPtr + idxZ * inIncZ; for (idxY = 0; idxY <= maxY; idxY++) { memcpy(outPtr, inPtr1, rowLength); inPtr1 += inIncY; outPtr += rowLength; } } } } if (vData) { // if the data extent matches the update extent then just pass the data // otherwise we must reformat and copy the data wExtent = vData->GetExtent(); if (wExtent[0] == uExtent[0] && wExtent[1] == uExtent[1] && wExtent[2] == uExtent[2] && wExtent[3] == uExtent[3] && wExtent[4] == uExtent[4] && wExtent[5] == uExtent[5]) { output->GetPointData()->SetVectors(vData->GetPointData()->GetScalars()); } else { vtkDataArray* fv = vtkDataArray::CreateDataArray(vData->GetScalarType()); float* inPtr2 = static_cast(vData->GetScalarPointerForExtent(uExtent)); // Make sure there are data. if (!inPtr2) { output->Initialize(); return 1; } fv->SetNumberOfComponents(3); fv->SetNumberOfTuples((maxZ + 1) * (maxY + 1) * (maxX + 1)); vData->GetContinuousIncrements(uExtent, inIncX, inIncY, inIncZ); int numComp = vData->GetNumberOfScalarComponents(); int idx = 0; // Loop through output pixels for (idxZ = 0; idxZ <= maxZ; idxZ++) { for (idxY = 0; idxY <= maxY; idxY++) { for (idxX = 0; idxX <= maxX; idxX++) { fv->SetTuple(idx, inPtr2); inPtr2 += numComp; idx++; } inPtr2 += inIncY; } inPtr2 += inIncZ; } output->GetPointData()->SetVectors(fv); fv->Delete(); } } return 1; } //------------------------------------------------------------------------------ // Copy WholeExtent, Spacing and Origin. int vtkImageToStructuredPoints::RequestInformation(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // get the info objects vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); vtkInformation* vInfo = inputVector[1]->GetInformationObject(0); int whole[6], *tmp; double *spacing, origin[3]; vtkInformation* inScalarInfo = vtkDataObject::GetActiveFieldInformation( inInfo, vtkDataObject::FIELD_ASSOCIATION_POINTS, vtkDataSetAttributes::SCALARS); if (!inScalarInfo) { vtkErrorMacro("Missing scalar field on input information!"); return 0; } vtkDataObject::SetPointDataActiveScalarInfo(outInfo, inScalarInfo->Get(vtkDataObject::FIELD_ARRAY_TYPE()), inScalarInfo->Get(vtkDataObject::FIELD_NUMBER_OF_COMPONENTS())); inInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), whole); spacing = inInfo->Get(vtkDataObject::SPACING()); inInfo->Get(vtkDataObject::ORIGIN(), origin); // intersections for whole extent if (vInfo) { tmp = vInfo->Get(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT()); whole[0] = std::max(tmp[0], whole[0]); whole[2] = std::max(tmp[2], whole[2]); whole[4] = std::max(tmp[4], whole[4]); whole[1] = std::min(tmp[1], whole[1]); whole[3] = std::min(tmp[3], whole[3]); whole[5] = std::min(tmp[5], whole[5]); } // slide min extent to 0,0,0 (I Hate this !!!!) this->Translate[0] = whole[0]; this->Translate[1] = whole[2]; this->Translate[2] = whole[4]; origin[0] += spacing[0] * whole[0]; origin[1] += spacing[1] * whole[2]; origin[2] += spacing[2] * whole[4]; whole[1] -= whole[0]; whole[3] -= whole[2]; whole[5] -= whole[4]; whole[0] = whole[2] = whole[4] = 0; outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), whole, 6); // Now should Origin and Spacing really be part of information? // How about xyx arrays in RectilinearGrid of Points in StructuredGrid? outInfo->Set(vtkDataObject::ORIGIN(), origin, 3); outInfo->Set(vtkDataObject::SPACING(), spacing, 3); return 1; } //------------------------------------------------------------------------------ int vtkImageToStructuredPoints::RequestUpdateExtent( vtkInformation*, vtkInformationVector** inputVector, vtkInformationVector* outputVector) { vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); vtkInformation* vInfo = inputVector[1]->GetInformationObject(0); vtkInformation* outInfo = outputVector->GetInformationObject(0); int ext[6]; outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), ext); ext[0] += this->Translate[0]; ext[1] += this->Translate[0]; ext[2] += this->Translate[1]; ext[3] += this->Translate[1]; ext[4] += this->Translate[2]; ext[5] += this->Translate[2]; inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), ext, 6); if (vInfo) { vInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_EXTENT(), ext, 6); } return 1; } //------------------------------------------------------------------------------ int vtkImageToStructuredPoints::FillOutputPortInformation(int port, vtkInformation* info) { if (!this->Superclass::FillOutputPortInformation(port, info)) { return 0; } info->Set(vtkDataObject::DATA_TYPE_NAME(), "vtkStructuredPoints"); return 1; } //------------------------------------------------------------------------------ int vtkImageToStructuredPoints::FillInputPortInformation(int port, vtkInformation* info) { if (!this->Superclass::FillInputPortInformation(port, info)) { return 0; } if (port == 1) { info->Set(vtkAlgorithm::INPUT_IS_OPTIONAL(), 1); } return 1; } VTK_ABI_NAMESPACE_END