// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkOutlineFilter.h" #include "vtkCompositeDataIterator.h" #include "vtkCompositeDataSet.h" #include "vtkDataObjectTreeIterator.h" #include "vtkDataSet.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkNew.h" #include "vtkPolyData.h" #include VTK_ABI_NAMESPACE_BEGIN class vtkOutlineFilter::vtkIndexSet : public std::set { }; vtkStandardNewMacro(vtkOutlineFilter); //------------------------------------------------------------------------------ vtkOutlineFilter::vtkOutlineFilter() { this->GenerateFaces = 0; this->CompositeStyle = vtkOutlineFilter::ROOT_AND_LEAFS; this->OutputPointsPrecision = SINGLE_PRECISION; this->Indices = new vtkOutlineFilter::vtkIndexSet(); } //------------------------------------------------------------------------------ vtkOutlineFilter::~vtkOutlineFilter() { delete this->Indices; } //------------------------------------------------------------------------------ void vtkOutlineFilter::AddIndex(unsigned int index) { if (this->Indices->find(index) == this->Indices->end()) { this->Indices->insert(index); this->Modified(); } } //------------------------------------------------------------------------------ void vtkOutlineFilter::RemoveIndex(unsigned int index) { if (this->Indices->find(index) != this->Indices->end()) { this->Indices->erase(index); this->Modified(); } } //------------------------------------------------------------------------------ void vtkOutlineFilter::RemoveAllIndices() { if (!this->Indices->empty()) { this->Indices->clear(); this->Modified(); } } //------------------------------------------------------------------------------ void vtkOutlineFilter::AppendOutline( vtkPoints* points, vtkCellArray* lines, vtkCellArray* faces, double bounds[6]) { // Since points have likely been inserted before, keep track of the point // offsets vtkIdType offset[8]; // Insert points double x[3]; x[0] = bounds[0]; x[1] = bounds[2]; x[2] = bounds[4]; offset[0] = points->InsertNextPoint(x); x[0] = bounds[1]; x[1] = bounds[2]; x[2] = bounds[4]; offset[1] = points->InsertNextPoint(x); x[0] = bounds[0]; x[1] = bounds[3]; x[2] = bounds[4]; offset[2] = points->InsertNextPoint(x); x[0] = bounds[1]; x[1] = bounds[3]; x[2] = bounds[4]; offset[3] = points->InsertNextPoint(x); x[0] = bounds[0]; x[1] = bounds[2]; x[2] = bounds[5]; offset[4] = points->InsertNextPoint(x); x[0] = bounds[1]; x[1] = bounds[2]; x[2] = bounds[5]; offset[5] = points->InsertNextPoint(x); x[0] = bounds[0]; x[1] = bounds[3]; x[2] = bounds[5]; offset[6] = points->InsertNextPoint(x); x[0] = bounds[1]; x[1] = bounds[3]; x[2] = bounds[5]; offset[7] = points->InsertNextPoint(x); // Produce topology, either lines or quad faces vtkIdType pts[4]; // Always generate wire edges. I think this is dumb but historical.... pts[0] = offset[0]; pts[1] = offset[1]; lines->InsertNextCell(2, pts); pts[0] = offset[2]; pts[1] = offset[3]; lines->InsertNextCell(2, pts); pts[0] = offset[4]; pts[1] = offset[5]; lines->InsertNextCell(2, pts); pts[0] = offset[6]; pts[1] = offset[7]; lines->InsertNextCell(2, pts); pts[0] = offset[0]; pts[1] = offset[2]; lines->InsertNextCell(2, pts); pts[0] = offset[1]; pts[1] = offset[3]; lines->InsertNextCell(2, pts); pts[0] = offset[4]; pts[1] = offset[6]; lines->InsertNextCell(2, pts); pts[0] = offset[5]; pts[1] = offset[7]; lines->InsertNextCell(2, pts); pts[0] = offset[0]; pts[1] = offset[4]; lines->InsertNextCell(2, pts); pts[0] = offset[1]; pts[1] = offset[5]; lines->InsertNextCell(2, pts); pts[0] = offset[2]; pts[1] = offset[6]; lines->InsertNextCell(2, pts); pts[0] = offset[3]; pts[1] = offset[7]; lines->InsertNextCell(2, pts); if (this->GenerateFaces) { pts[0] = offset[1]; pts[1] = offset[0]; pts[2] = offset[2]; pts[3] = offset[3]; faces->InsertNextCell(4, pts); pts[0] = offset[0]; pts[1] = offset[1]; pts[2] = offset[5]; pts[3] = offset[4]; faces->InsertNextCell(4, pts); pts[0] = offset[2]; pts[1] = offset[0]; pts[2] = offset[4]; pts[3] = offset[6]; faces->InsertNextCell(4, pts); pts[0] = offset[3]; pts[1] = offset[2]; pts[2] = offset[6]; pts[3] = offset[7]; faces->InsertNextCell(4, pts); pts[0] = offset[1]; pts[1] = offset[3]; pts[2] = offset[7]; pts[3] = offset[5]; faces->InsertNextCell(4, pts); pts[0] = offset[7]; pts[1] = offset[6]; pts[2] = offset[4]; pts[3] = offset[5]; faces->InsertNextCell(4, pts); } } //------------------------------------------------------------------------------ int vtkOutlineFilter::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. Differentiate between composite and typical datasets. vtkDataSet* input = vtkDataSet::SafeDownCast(inInfo->Get(vtkDataObject::DATA_OBJECT())); vtkCompositeDataSet* compInput = vtkCompositeDataSet::SafeDownCast(inInfo->Get(vtkCompositeDataSet::DATA_OBJECT())); if (input == nullptr && compInput == nullptr) { vtkErrorMacro(<< "Invalid or missing input"); return 0; } vtkPolyData* output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); vtkDebugMacro(<< "Creating outline"); // Each outline is passed down to the core generation function vtkNew pts; // Set the desired precision for the points in the output. if (this->OutputPointsPrecision == vtkAlgorithm::DOUBLE_PRECISION) { pts->SetDataType(VTK_DOUBLE); } else { pts->SetDataType(VTK_FLOAT); } vtkNew lines; vtkNew faces; // If vtkDataSet input just create one bounding box. Composites may require multiple. double bds[6]; if (input) { // dataset bounding box input->GetBounds(bds); this->AppendOutline(pts.GetPointer(), lines.GetPointer(), faces.GetPointer(), bds); } else { // Root bounding box if (this->CompositeStyle == ROOT_LEVEL || this->CompositeStyle == ROOT_AND_LEAFS) { compInput->GetBounds(bds); this->AppendOutline(pts.GetPointer(), lines.GetPointer(), faces.GetPointer(), bds); } // Leafs if (this->CompositeStyle == LEAF_DATASETS || this->CompositeStyle == ROOT_AND_LEAFS) { vtkCompositeDataIterator* iter = compInput->NewIterator(); for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem()) { if (this->CheckAbort()) { break; } vtkDataSet* ds = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject()); if (ds) { ds->GetBounds(bds); this->AppendOutline(pts.GetPointer(), lines.GetPointer(), faces.GetPointer(), bds); } } iter->Delete(); } // Specified flat indices if (this->CompositeStyle == SPECIFIED_INDEX) { vtkCompositeDataIterator* iter = compInput->NewIterator(); vtkDataObjectTreeIterator* treeIter = vtkDataObjectTreeIterator::SafeDownCast(iter); if (treeIter) { treeIter->VisitOnlyLeavesOff(); } unsigned int index; for (iter->InitTraversal(); !iter->IsDoneWithTraversal(); iter->GoToNextItem()) { if (this->CheckAbort()) { break; } vtkDataSet* ds = vtkDataSet::SafeDownCast(iter->GetCurrentDataObject()); if (ds) { index = iter->GetCurrentFlatIndex(); if (this->Indices->find(index) != this->Indices->end()) { ds->GetBounds(bds); this->AppendOutline(pts.GetPointer(), lines.GetPointer(), faces.GetPointer(), bds); } } // if a dataset } iter->Delete(); } } // Specify output output->SetPoints(pts.GetPointer()); output->SetLines(lines.GetPointer()); if (this->GenerateFaces) { output->SetPolys(faces.GetPointer()); } this->CheckAbort(); return 1; } //------------------------------------------------------------------------------ int vtkOutlineFilter::FillInputPortInformation(int, vtkInformation* info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkDataSet"); info->Append(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkCompositeDataSet"); return 1; } //------------------------------------------------------------------------------ void vtkOutlineFilter::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Generate Faces: " << (this->GenerateFaces ? "On\n" : "Off\n"); os << indent << "Composite Style: " << this->CompositeStyle << endl; os << indent << "Output Points Precision: " << this->OutputPointsPrecision << "\n"; os << indent << "Composite indices: " << (!this->Indices->empty() ? "(Specified)\n" : "(Not specified)\n"); } VTK_ABI_NAMESPACE_END