// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include #include "vtkGenericGlyph3DFilter.h" #include "vtkGenericAttribute.h" #include "vtkGenericAttributeCollection.h" #include "vtkGenericDataSet.h" #include "vtkGenericPointIterator.h" #include "vtkCell.h" #include "vtkDoubleArray.h" #include "vtkIdList.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkStreamingDemandDrivenPipeline.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkTransform.h" #include "vtkTrivialProducer.h" #include "vtkUnsignedCharArray.h" VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkGenericGlyph3DFilter); // Construct object with scaling on, scaling mode is by scalar value, // scale factor = 1.0, the range is (0,1), orient geometry is on, and // orientation is by vector. Clamping and indexing are turned off. No // initial sources are defined. vtkGenericGlyph3DFilter::vtkGenericGlyph3DFilter() { this->Scaling = 1; this->ColorMode = VTK_COLOR_BY_SCALE; this->ScaleMode = VTK_SCALE_BY_SCALAR; this->ScaleFactor = 1.0; this->Range[0] = 0.0; this->Range[1] = 1.0; this->Orient = 1; this->VectorMode = VTK_USE_VECTOR; this->Clamping = 0; this->IndexMode = VTK_INDEXING_OFF; // this->NumberOfRequiredInputs = 1; this->GeneratePointIds = 0; this->PointIdsName = nullptr; this->SetPointIdsName("InputPointIds"); this->InputScalarsSelection = nullptr; this->InputVectorsSelection = nullptr; this->InputNormalsSelection = nullptr; this->SetNumberOfInputPorts(2); } //------------------------------------------------------------------------------ vtkGenericGlyph3DFilter::~vtkGenericGlyph3DFilter() { delete[] this->PointIdsName; this->SetInputScalarsSelection(nullptr); this->SetInputVectorsSelection(nullptr); this->SetInputNormalsSelection(nullptr); } //------------------------------------------------------------------------------ int vtkGenericGlyph3DFilter::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 vtkGenericDataSet* input = vtkGenericDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkPointData* pd = nullptr; // vtkDataArray *inScalars; // vtkDataArray *inVectors; // vtkDataArray *inNormals; vtkDataArray* sourceNormals = nullptr; vtkGenericAttribute* inScalars = nullptr; vtkGenericAttribute* inVectors = nullptr; vtkGenericAttribute* inNormals = nullptr; // vtkGenericAttribute *sourceNormals=0; unsigned char* inGhostLevels = nullptr; vtkIdType numPts, numSourcePts, numSourceCells, inPtId, i; int index; vtkPoints* sourcePts = nullptr; vtkPoints* newPts; vtkDataArray* newScalars = nullptr; vtkDataArray* newVectors = nullptr; vtkDataArray* newNormals = nullptr; double x[3], v[3], vNew[3], s = 0.0, vMag = 0.0, value; vtkTransform* trans; vtkCell* cell; vtkIdList* cellPts; int npts; vtkIdList* pts; vtkIdType ptIncr, cellId; int haveVectors, haveNormals; double scalex, scaley, scalez, den; vtkPointData* outputPD = output->GetPointData(); // vtkGenericDataSet *input = this->GetInput(); int numberOfSources = this->GetNumberOfInputConnections(1); vtkPolyData* defaultSource = nullptr; vtkIdTypeArray* pointIds = nullptr; vtkGenericAttributeCollection* attributes = nullptr; int attrib = -1; vtkDebugMacro(<< "Generating glyphs"); if (!input) { vtkErrorMacro(<< "No input"); return 1; } attributes = input->GetAttributes(); if ((attributes == nullptr) || (attributes->IsEmpty())) { vtkDebugMacro("No attributes, nothing to do."); return 1; } if (this->InputScalarsSelection != nullptr) { attrib = attributes->FindAttribute(this->InputScalarsSelection); if (attrib != -1) { inScalars = attributes->GetAttribute(attrib); if (inScalars->GetNumberOfComponents() != 1) { inScalars = nullptr; vtkDebugMacro("The attribute is not a scalar."); } } else { vtkDebugMacro("No scalar attribute."); } } if (this->InputVectorsSelection != nullptr) { vtkDebugMacro("this->InputVectorsSelection!=0"); attrib = attributes->FindAttribute(this->InputVectorsSelection); vtkDebugMacro("inVectors just set"); if (attrib != -1) { inVectors = attributes->GetAttribute(attrib); if (inVectors->GetNumberOfComponents() != 3) { inVectors = nullptr; vtkDebugMacro("The attribute is not a vector."); } else { vtkDebugMacro("The attribute is a vector."); } } else { vtkDebugMacro("No vector attribute."); } } else { vtkDebugMacro("No input vector selection."); } if (this->InputNormalsSelection != nullptr) { attrib = attributes->FindAttribute(this->InputNormalsSelection); if (attrib != -1) { inNormals = attributes->GetAttribute(attrib); if (inNormals->GetNumberOfComponents() != 3) { inNormals = nullptr; vtkDebugMacro("The attribute is not a normal vector."); } } else { vtkDebugMacro("No normal attribute."); } } // pd = input->GetPointData(); // inScalars = pd->GetScalars(this->InputScalarsSelection); // inVectors = pd->GetVectors(this->InputVectorsSelection); // inNormals = pd->GetNormals(this->InputNormalsSelection); // guru concurrency section #if 0 vtkDataArray* temp = 0; if (pd) { temp = pd->GetArray(vtkDataSetAttributes::GhostArrayName()); } if ( (!temp) || (temp->GetDataType() != VTK_UNSIGNED_CHAR) || (temp->GetNumberOfComponents() != 1)) { vtkDebugMacro("No appropriate ghost levels field available."); } else { inGhostLevels = ((vtkUnsignedCharArray*)temp)->GetPointer(0); } #endif numPts = input->GetNumberOfPoints(); if (numPts < 1) { vtkDebugMacro(<< "No points to glyph!"); return 1; } else { pts = vtkIdList::New(); pts->Allocate(VTK_CELL_SIZE); trans = vtkTransform::New(); } // Check input for consistency // if ((den = this->Range[1] - this->Range[0]) == 0.0) { den = 1.0; } if (this->VectorMode != VTK_VECTOR_ROTATION_OFF && ((this->VectorMode == VTK_USE_VECTOR && inVectors != nullptr) || (this->VectorMode == VTK_USE_NORMAL && inNormals != nullptr))) { haveVectors = 1; } else { haveVectors = 0; } if ((this->IndexMode == VTK_INDEXING_BY_SCALAR && !inScalars) || (this->IndexMode == VTK_INDEXING_BY_VECTOR && ((!inVectors && this->VectorMode == VTK_USE_VECTOR) || (!inNormals && this->VectorMode == VTK_USE_NORMAL)))) { if (this->GetSource(0) == nullptr) { vtkErrorMacro(<< "Indexing on but don't have data to index with"); pts->Delete(); trans->Delete(); return 1; } else { vtkWarningMacro(<< "Turning indexing off: no data to index with"); this->IndexMode = VTK_INDEXING_OFF; } } // Allocate storage for output PolyData // outputPD->CopyVectorsOff(); outputPD->CopyNormalsOff(); if (!this->GetSource(0)) { defaultSource = vtkPolyData::New(); defaultSource->AllocateExact(1024, 1024); vtkPoints* defaultPoints = vtkPoints::New(); defaultPoints->Allocate(6); defaultPoints->InsertNextPoint(0, 0, 0); defaultPoints->InsertNextPoint(1, 0, 0); vtkIdType defaultPointIds[2]; defaultPointIds[0] = 0; defaultPointIds[1] = 1; defaultSource->SetPoints(defaultPoints); defaultSource->InsertNextCell(VTK_LINE, 2, defaultPointIds); defaultSource->Delete(); defaultSource = nullptr; defaultPoints->Delete(); defaultPoints = nullptr; } if (this->IndexMode != VTK_INDEXING_OFF) { pd = nullptr; haveNormals = 1; for (numSourcePts = numSourceCells = i = 0; i < numberOfSources; i++) { if (this->GetSource(i) != nullptr) { numSourcePts = std::max(this->GetSource(i)->GetNumberOfPoints(), numSourcePts); numSourceCells = std::max(this->GetSource(i)->GetNumberOfCells(), numSourceCells); if (!(sourceNormals = this->GetSource(i)->GetPointData()->GetNormals())) { haveNormals = 0; } } } } else { sourcePts = this->GetSource(0)->GetPoints(); numSourcePts = sourcePts->GetNumberOfPoints(); numSourceCells = this->GetSource(0)->GetNumberOfCells(); sourceNormals = this->GetSource(0)->GetPointData()->GetNormals(); if (sourceNormals) { haveNormals = 1; } else { haveNormals = 0; } // Prepare to copy output. // pd = input->GetPointData(); // outputPD->CopyAllocate(pd,numPts*numSourcePts); // AddArray ? } newPts = vtkPoints::New(); newPts->Allocate(numPts * numSourcePts); if (this->GeneratePointIds) { pointIds = vtkIdTypeArray::New(); pointIds->SetName(this->PointIdsName); pointIds->Allocate(numPts * numSourcePts); outputPD->AddArray(pointIds); } if (this->ColorMode == VTK_COLOR_BY_SCALAR && inScalars) { // newScalars = inScalars->NewInstance(); newScalars = vtkDoubleArray::New(); newScalars->SetNumberOfComponents(inScalars->GetNumberOfComponents()); newScalars->Allocate(inScalars->GetNumberOfComponents() * numPts * numSourcePts); newScalars->SetName(inScalars->GetName()); } else if ((this->ColorMode == VTK_COLOR_BY_SCALE) && inScalars) { newScalars = vtkDoubleArray::New(); newScalars->Allocate(numPts * numSourcePts); newScalars->SetName("GlyphScale"); if (this->ScaleMode == VTK_SCALE_BY_SCALAR) { newScalars->SetName(inScalars->GetName()); } } else if ((this->ColorMode == VTK_COLOR_BY_VECTOR) && haveVectors) { newScalars = vtkDoubleArray::New(); newScalars->Allocate(numPts * numSourcePts); newScalars->SetName("VectorMagnitude"); } if (haveVectors) { newVectors = vtkDoubleArray::New(); newVectors->SetNumberOfComponents(3); newVectors->Allocate(3 * numPts * numSourcePts); newVectors->SetName("GlyphVector"); } if (haveNormals) { newNormals = vtkDoubleArray::New(); newNormals->SetNumberOfComponents(3); newNormals->Allocate(3 * numPts * numSourcePts); newNormals->SetName("Normals"); } // Setting up for calls to PolyData::InsertNextCell() if (this->IndexMode != VTK_INDEXING_OFF) { output->AllocateEstimate(3 * numPts * numSourceCells, numPts * numSourceCells); } else { output->AllocateCopy(this->GetSource(0)); } // Traverse all Input points, transforming Source points and copying // point attributes. // ptIncr = 0; inPtId = 0; // used only for the progress information // vtkGenericAdaptorCell *acell=0; // vtkCellIterator *it=input->NewVertexIterator(); vtkGenericPointIterator* it = input->NewPointIterator(); it->Begin(); while (!it->IsAtEnd()) { scalex = scaley = scalez = 1.0; if (!(inPtId % 10000)) { this->UpdateProgress(static_cast(inPtId) / numPts); if (this->CheckAbort()) { break; } } // acell=it->GetCell(); // Get the scalar and vector data if (inScalars) { inScalars->GetTuple(it, &s); // s = inScalars->GetComponent(inPtId, 0); if (this->ScaleMode == VTK_SCALE_BY_SCALAR || this->ScaleMode == VTK_DATA_SCALING_OFF) { scalex = scaley = scalez = s; } } if (haveVectors) { if (this->VectorMode == VTK_USE_NORMAL) { // inNormals->GetTuple(inPtId, v); inNormals->GetTuple(it, v); } else { inVectors->GetTuple(it, v); // inVectors->GetTuple(inPtId, v); } vMag = vtkMath::Norm(v); if (this->ScaleMode == VTK_SCALE_BY_VECTORCOMPONENTS) { scalex = v[0]; scaley = v[1]; scalez = v[2]; } else if (this->ScaleMode == VTK_SCALE_BY_VECTOR) { scalex = scaley = scalez = vMag; } } // Clamp data scale if enabled if (this->Clamping) { scalex = std::clamp(scalex, this->Range[0], this->Range[1]); scalex = (scalex - this->Range[0]) / den; scaley = std::clamp(scaley, this->Range[0], this->Range[1]); scaley = (scaley - this->Range[0]) / den; scalez = std::clamp(scalez, this->Range[0], this->Range[1]); scalez = (scalez - this->Range[0]) / den; } // Compute index into table of glyphs if (this->IndexMode == VTK_INDEXING_OFF) { index = 0; } else { if (this->IndexMode == VTK_INDEXING_BY_SCALAR) { value = s; } else { value = vMag; } index = static_cast((value - this->Range[0]) * numberOfSources / den); index = std::clamp(index, 0, numberOfSources - 1); if (this->GetSource(index) != nullptr) { sourcePts = this->GetSource(index)->GetPoints(); sourceNormals = this->GetSource(index)->GetPointData()->GetNormals(); numSourcePts = sourcePts->GetNumberOfPoints(); numSourceCells = this->GetSource(index)->GetNumberOfCells(); } } // Make sure we're not indexing into empty glyph if (this->GetSource(index) == nullptr) { continue; } // Check ghost points. // If we are processing a piece, we do not want to duplicate // glyphs on the borders. if (inGhostLevels && inGhostLevels[inPtId] & vtkDataSetAttributes::DUPLICATEPOINT) { continue; } // Now begin copying/transforming glyph trans->Identity(); // Copy all topology (transformation independent) for (cellId = 0; cellId < numSourceCells; cellId++) { cell = this->GetSource(index)->GetCell(cellId); cellPts = cell->GetPointIds(); npts = cellPts->GetNumberOfIds(); for (pts->Reset(), i = 0; i < npts; i++) { pts->InsertId(i, cellPts->GetId(i) + ptIncr); } output->InsertNextCell(cell->GetCellType(), pts); } // translate Source to Input point // input->GetPoint(inPtId, x); it->GetPosition(x); trans->Translate(x[0], x[1], x[2]); if (haveVectors) { // Copy Input vector for (i = 0; i < numSourcePts; i++) { newVectors->InsertTuple(i + ptIncr, v); } if (this->Orient && (vMag > 0.0)) { // if there is no y or z component if (v[1] == 0.0 && v[2] == 0.0) { if (v[0] < 0) // just flip x if we need to { trans->RotateWXYZ(180.0, 0, 1, 0); } } else { vNew[0] = (v[0] + vMag) / 2.0; vNew[1] = v[1] / 2.0; vNew[2] = v[2] / 2.0; trans->RotateWXYZ(180.0, vNew[0], vNew[1], vNew[2]); } } } // determine scale factor from scalars if appropriate if (inScalars) { // Copy scalar value if (this->ColorMode == VTK_COLOR_BY_SCALE) { for (i = 0; i < numSourcePts; i++) { newScalars->InsertTuple(i + ptIncr, &scalex); // = scaley = scalez } } else if (this->ColorMode == VTK_COLOR_BY_SCALAR) { for (i = 0; i < numSourcePts; i++) { // outputPD->CopyTuple(inScalars, newScalars, inPtId, ptIncr+i); newScalars->InsertTuple(i + ptIncr, &s); } } } if (haveVectors && this->ColorMode == VTK_COLOR_BY_VECTOR) { for (i = 0; i < numSourcePts; i++) { newScalars->InsertTuple(i + ptIncr, &vMag); } } // scale data if appropriate if (this->Scaling) { if (this->ScaleMode == VTK_DATA_SCALING_OFF) { scalex = scaley = scalez = this->ScaleFactor; } else { scalex *= this->ScaleFactor; scaley *= this->ScaleFactor; scalez *= this->ScaleFactor; } if (scalex == 0.0) { scalex = 1.0e-10; } if (scaley == 0.0) { scaley = 1.0e-10; } if (scalez == 0.0) { scalez = 1.0e-10; } trans->Scale(scalex, scaley, scalez); } // multiply points and normals by resulting matrix trans->TransformPoints(sourcePts, newPts); if (haveNormals) { trans->TransformNormals(sourceNormals, newNormals); } // Copy point data from source (if possible): WRONG to from source but // from input. if (pd) { for (i = 0; i < numSourcePts; i++) { outputPD->CopyData(pd, inPtId, ptIncr + i); } } // If point ids are to be generated, do it here if (this->GeneratePointIds) { for (i = 0; i < numSourcePts; i++) { pointIds->InsertNextValue(inPtId); } } it->Next(); ptIncr += numSourcePts; inPtId++; } it->Delete(); // Update ourselves and release memory // output->SetPoints(newPts); newPts->Delete(); if (newScalars) { int idx = outputPD->AddArray(newScalars); outputPD->SetActiveAttribute(idx, vtkDataSetAttributes::SCALARS); newScalars->Delete(); } if (newVectors) { outputPD->SetVectors(newVectors); newVectors->Delete(); } if (newNormals) { outputPD->SetNormals(newNormals); newNormals->Delete(); } output->Squeeze(); trans->Delete(); pts->Delete(); return 1; } //------------------------------------------------------------------------------ // Since indexing determines size of outputs, EstimatedWholeMemorySize is // truly an estimate. Ignore Indexing (although for a best estimate we // should average the size of the sources instead of using 0). int vtkGenericGlyph3DFilter::RequestInformation(vtkInformation* vtkNotUsed(request), vtkInformationVector** vtkNotUsed(inputVector), vtkInformationVector* vtkNotUsed(outputVector)) { // get the info objects // vtkInformation *inInfo = inputVector[0]->GetInformationObject(0); // vtkInformation *outInfo = outputVector->GetInformationObject(0); if (this->GetInput() == nullptr) { vtkErrorMacro("Missing input"); return 1; } return 1; } //------------------------------------------------------------------------------ // Specify a source object at a specified table location. void vtkGenericGlyph3DFilter::SetSourceData(int id, vtkPolyData* pd) { int numConnections = this->GetNumberOfInputConnections(1); if (id < 0 || id > numConnections) { vtkErrorMacro("Bad index " << id << " for source."); return; } vtkTrivialProducer* tp = nullptr; if (pd) { tp = vtkTrivialProducer::New(); tp->SetOutput(pd); } if (id < numConnections) { if (tp) { this->SetNthInputConnection(1, id, tp->GetOutputPort()); } else { this->SetNthInputConnection(1, id, nullptr); } } else if (id == numConnections && tp) { this->AddInputConnection(1, tp->GetOutputPort()); } if (tp) { tp->Delete(); } } //------------------------------------------------------------------------------ // Get a pointer to a source object at a specified table location. vtkPolyData* vtkGenericGlyph3DFilter::GetSource(int id) { if (id < 0 || id >= this->GetNumberOfInputConnections(1)) { return nullptr; } else { return vtkPolyData::SafeDownCast(this->GetExecutive()->GetInputData(1, id)); } } //------------------------------------------------------------------------------ void vtkGenericGlyph3DFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Generate Point Ids " << (this->GeneratePointIds ? "On\n" : "Off\n"); os << indent << "PointIdsName: " << (this->PointIdsName ? this->PointIdsName : "(none)") << "\n"; os << indent << "Color Mode: " << this->GetColorModeAsString() << endl; if (this->GetNumberOfInputConnections(1) < 2) { if (this->GetSource(0) != nullptr) { os << indent << "Source: (" << this->GetSource(0) << ")\n"; } else { os << indent << "Source: (none)\n"; } } else { os << indent << "A table of " << this->GetNumberOfInputConnections(1) << " glyphs has been defined\n"; } os << indent << "Scaling: " << (this->Scaling ? "On\n" : "Off\n"); os << indent << "Scale Mode: "; if (this->ScaleMode == VTK_SCALE_BY_SCALAR) { os << "Scale by scalar\n"; } else if (this->ScaleMode == VTK_SCALE_BY_VECTOR) { os << "Scale by vector\n"; } else { os << "Data scaling is turned off\n"; } os << indent << "Scale Factor: " << this->ScaleFactor << "\n"; os << indent << "Clamping: " << (this->Clamping ? "On\n" : "Off\n"); os << indent << "Range: (" << this->Range[0] << ", " << this->Range[1] << ")\n"; os << indent << "Orient: " << (this->Orient ? "On\n" : "Off\n"); os << indent << "Orient Mode: " << (this->VectorMode == VTK_USE_VECTOR ? "Orient by vector\n" : "Orient by normal\n"); os << indent << "Index Mode: "; if (this->IndexMode == VTK_INDEXING_BY_SCALAR) { os << "Index by scalar value\n"; } else if (this->IndexMode == VTK_INDEXING_BY_VECTOR) { os << "Index by vector value\n"; } else { os << "Indexing off\n"; } os << indent << "InputScalarsSelection: " << (this->InputScalarsSelection ? this->InputScalarsSelection : "(none)") << "\n"; os << indent << "InputVectorsSelection: " << (this->InputVectorsSelection ? this->InputVectorsSelection : "(none)") << "\n"; os << indent << "InputNormalsSelection: " << (this->InputNormalsSelection ? this->InputNormalsSelection : "(none)") << "\n"; } //------------------------------------------------------------------------------ int vtkGenericGlyph3DFilter::RequestUpdateExtent(vtkInformation* vtkNotUsed(request), vtkInformationVector** inputVector, vtkInformationVector* outputVector) { // get the info objects vtkInformation* inInfo = inputVector[0]->GetInformationObject(0); vtkInformation* outInfo = outputVector->GetInformationObject(0); vtkInformation* sourceInfo = inputVector[1]->GetInformationObject(0); if (sourceInfo) { sourceInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), 0); sourceInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), 1); sourceInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(), 0); } inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER(), outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_PIECE_NUMBER())); inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES(), outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_PIECES())); inInfo->Set(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS(), outInfo->Get(vtkStreamingDemandDrivenPipeline::UPDATE_NUMBER_OF_GHOST_LEVELS())); inInfo->Set(vtkStreamingDemandDrivenPipeline::EXACT_EXTENT(), 1); return 1; } //------------------------------------------------------------------------------ int vtkGenericGlyph3DFilter ::FillInputPortInformation(int port, vtkInformation* info) { if (!this->Superclass::FillInputPortInformation(port, info)) { return 0; } if (port == 1) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkPolyData"); } else { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGenericDataSet"); } return 1; } VTK_ABI_NAMESPACE_END