/*========================================================================= Program: Visualization Toolkit Module: vtkBoostBreadthFirstSearchTree.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /*------------------------------------------------------------------------- Copyright 2008 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. -------------------------------------------------------------------------*/ #include "vtkBoostBreadthFirstSearchTree.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkMath.h" #include "vtkIdTypeArray.h" #include "vtkInformation.h" #include "vtkInformationVector.h" #include "vtkObjectFactory.h" #include "vtkPointData.h" #include "vtkPoints.h" #include "vtkFloatArray.h" #include "vtkDataArray.h" #include "vtkSmartPointer.h" #include "vtkStringArray.h" #include "vtkBoostGraphAdapter.h" #include "vtkMutableDirectedGraph.h" #include "vtkUndirectedGraph.h" #include "vtkTree.h" #include #include #include using namespace boost; vtkStandardNewMacro(vtkBoostBreadthFirstSearchTree); #if BOOST_VERSION >= 104800 // Boost 1.48.x namespace { vtkIdType unwrap_edge_id(vtkEdgeType const &e) { return e.Id; } vtkIdType unwrap_edge_id(boost::detail::reverse_graph_edge_descriptor const &e) { # if BOOST_VERSION == 104800 return e.underlying_desc.Id; # else return e.underlying_descx.Id; # endif } } #endif // Redefine the bfs visitor, the only visitor we // are using is the tree_edge visitor. template class bfs_tree_builder : public default_bfs_visitor { public: bfs_tree_builder() { } bfs_tree_builder(IdMap& g2t, IdMap& t2g, vtkGraph* g, vtkMutableDirectedGraph* t, vtkIdType root) : graph_to_tree(g2t), tree_to_graph(t2g), tree(t), graph(g) { double x[3]; graph->GetPoints()->GetPoint(root, x); tree->GetPoints()->InsertNextPoint(x); vtkIdType tree_root = t->AddVertex(); put(graph_to_tree, root, tree_root); put(tree_to_graph, tree_root, root); tree->GetVertexData()->CopyData(graph->GetVertexData(), root, tree_root); } template void tree_edge(Edge e, const Graph& g) const { typename graph_traits::vertex_descriptor u, v; u = source(e, g); v = target(e, g); // Get the source vertex id (it has already been visited). vtkIdType tree_u = get(graph_to_tree, u); // Add the point before the vertex so that // points match the number of vertices, so that GetPoints() // doesn't reallocate and zero-out points. double x[3]; graph->GetPoints()->GetPoint(v, x); tree->GetPoints()->InsertNextPoint(x); // Create the target vertex in the tree. vtkIdType tree_v = tree->AddVertex(); vtkEdgeType tree_e = tree->AddEdge(tree_u, tree_v); // Store the mapping from graph to tree. put(graph_to_tree, v, tree_v); put(tree_to_graph, tree_v, v); // Copy the vertex and edge data from the graph to the tree. tree->GetVertexData()->CopyData(graph->GetVertexData(), v, tree_v); #if BOOST_VERSION < 104800 // Boost 1.48.x tree->GetEdgeData()->CopyData(graph->GetEdgeData(), e.Id, tree_e.Id); #else tree->GetEdgeData()->CopyData(graph->GetEdgeData(), unwrap_edge_id(e), tree_e.Id); #endif } private: IdMap graph_to_tree; IdMap tree_to_graph; vtkMutableDirectedGraph *tree; vtkGraph *graph; }; // Constructor/Destructor vtkBoostBreadthFirstSearchTree::vtkBoostBreadthFirstSearchTree() { // Default values for the origin vertex this->OriginVertexIndex = 0; this->ArrayName = 0; this->SetArrayName("Not Set"); this->ArrayNameSet = false; this->OriginValue = 0; this->CreateGraphVertexIdArray = false; this->ReverseEdges = false; } vtkBoostBreadthFirstSearchTree::~vtkBoostBreadthFirstSearchTree() { this->SetArrayName(nullptr); } // Description: // Set the index (into the vertex array) of the // breadth first search 'origin' vertex. void vtkBoostBreadthFirstSearchTree::SetOriginVertex(vtkIdType index) { this->OriginVertexIndex = index; this->ArrayNameSet = false; this->Modified(); } // Description: // Set the breadth first search 'origin' vertex. // This method is basically the same as above // but allows the application to simply specify // an array name and value, instead of having to // know the specific index of the vertex. void vtkBoostBreadthFirstSearchTree::SetOriginVertex( vtkStdString arrayName, vtkVariant value) { this->SetArrayName(arrayName); this->ArrayNameSet = true; this->OriginValue = value; this->Modified(); } vtkIdType vtkBoostBreadthFirstSearchTree::GetVertexIndex( vtkAbstractArray *abstract,vtkVariant value) { // Okay now what type of array is it if (abstract->IsNumeric()) { vtkDataArray *dataArray = vtkArrayDownCast(abstract); int intValue = value.ToInt(); for(int i=0; iGetNumberOfTuples(); ++i) { if (intValue == static_cast(dataArray->GetTuple1(i))) { return i; } } } else { vtkStringArray *stringArray = vtkArrayDownCast(abstract); vtkStdString stringValue(value.ToString()); for(int i=0; iGetNumberOfTuples(); ++i) { if (stringValue == stringArray->GetValue(i)) { return i; } } } // Failed vtkErrorMacro("Did not find a valid vertex index..."); return 0; } int vtkBoostBreadthFirstSearchTree::FillInputPortInformation( int vtkNotUsed(port), vtkInformation* info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGraph"); return 1; } int vtkBoostBreadthFirstSearchTree::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 vtkGraph *input = vtkGraph::SafeDownCast( inInfo->Get(vtkDataObject::DATA_OBJECT())); // Now figure out the origin vertex of the // breadth first search if (this->ArrayNameSet) { vtkAbstractArray* abstract = input->GetVertexData()->GetAbstractArray(this->ArrayName); // Does the array exist at all? if (abstract == nullptr) { vtkErrorMacro("Could not find array named " << this->ArrayName); return 0; } this->OriginVertexIndex = this->GetVertexIndex(abstract,this->OriginValue); } // Create tree to graph id map array vtkIdTypeArray* treeToGraphIdMap = vtkIdTypeArray::New(); // Create graph to tree id map array vtkIdTypeArray* graphToTreeIdMap = vtkIdTypeArray::New(); // Create a color map (used for marking visited nodes) vector_property_map color; // Create a queue to hand off to the BFS queue q; // Create the mutable graph to build the tree vtkSmartPointer temp = vtkSmartPointer::New(); // Initialize copying data into tree temp->GetFieldData()->PassData(input->GetFieldData()); temp->GetVertexData()->CopyAllocate(input->GetVertexData()); temp->GetEdgeData()->CopyAllocate(input->GetEdgeData()); // Create the visitor which will build the tree bfs_tree_builder builder( graphToTreeIdMap, treeToGraphIdMap, input, temp, this->OriginVertexIndex); // Run the algorithm if (vtkDirectedGraph::SafeDownCast(input)) { vtkDirectedGraph *g = vtkDirectedGraph::SafeDownCast(input); if (this->ReverseEdges) { #if BOOST_VERSION < 104100 // Boost 1.41.x vtkErrorMacro("ReverseEdges requires Boost 1.41.x or higher"); return 0; #else boost::reverse_graph r(g); breadth_first_search(r, this->OriginVertexIndex, q, builder, color); #endif } else { breadth_first_search(g, this->OriginVertexIndex, q, builder, color); } } else { vtkUndirectedGraph *g = vtkUndirectedGraph::SafeDownCast(input); breadth_first_search(g, this->OriginVertexIndex, q, builder, color); } // If the user wants it, store the mapping back to graph vertices if (this->CreateGraphVertexIdArray) { treeToGraphIdMap->SetName("GraphVertexId"); temp->GetVertexData()->AddArray(treeToGraphIdMap); } // Copy the builder graph structure into the output tree vtkTree *output = vtkTree::SafeDownCast( outInfo->Get(vtkDataObject::DATA_OBJECT())); if (!output->CheckedShallowCopy(temp)) { vtkErrorMacro(<<"Invalid tree."); return 0; } // Clean up output->Squeeze(); graphToTreeIdMap->Delete(); treeToGraphIdMap->Delete(); return 1; } void vtkBoostBreadthFirstSearchTree::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "OriginVertexIndex: " << this->OriginVertexIndex << endl; os << indent << "ArrayName: " << (this->ArrayName ? this->ArrayName : "(none)") << endl; os << indent << "OriginValue: " << this->OriginValue.ToString() << endl; os << indent << "ArrayNameSet: " << (this->ArrayNameSet ? "true" : "false") << endl; os << indent << "CreateGraphVertexIdArray: " << (this->CreateGraphVertexIdArray ? "on" : "off") << endl; os << indent << "ReverseEdges: " << (this->ReverseEdges ? "on" : "off") << endl; }