/*========================================================================= Program: Visualization Toolkit Module: vtkGraphMapper.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 "vtkGraphMapper.h" #include "vtkActor.h" #include "vtkActor2D.h" #include "vtkMapArrayValues.h" #include "vtkCamera.h" #include "vtkCellArray.h" #include "vtkCellData.h" #include "vtkDirectedGraph.h" #include "vtkExecutive.h" #include "vtkFollower.h" #include "vtkGarbageCollector.h" #include "vtkGlyph3D.h" #include "vtkGraphToPolyData.h" #include "vtkIconGlyphFilter.h" #include "vtkImageData.h" #include "vtkInformation.h" #include "vtkLookupTableWithEnabling.h" #include "vtkMath.h" #include "vtkObjectFactory.h" #include "vtkPlaneSource.h" #include "vtkPointData.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkPolyDataMapper2D.h" #include "vtkProperty.h" #include "vtkRenderer.h" #include "vtkTexture.h" #include "vtkTexturedActor2D.h" #include "vtkTransformCoordinateSystems.h" #include "vtkUndirectedGraph.h" #include "vtkVertexGlyphFilter.h" vtkStandardNewMacro(vtkGraphMapper); #define VTK_CREATE(type,name) \ vtkSmartPointer name = vtkSmartPointer::New() //---------------------------------------------------------------------------- vtkGraphMapper::vtkGraphMapper() { this->GraphToPoly = vtkSmartPointer::New(); this->VertexGlyph = vtkSmartPointer::New(); this->IconTypeToIndex = vtkSmartPointer::New(); this->CircleGlyph = vtkSmartPointer::New(); this->CircleOutlineGlyph = vtkSmartPointer::New(); this->IconGlyph = vtkSmartPointer::New(); this->IconTransform = vtkSmartPointer::New(); this->EdgeMapper = vtkSmartPointer::New(); this->VertexMapper = vtkSmartPointer::New(); this->OutlineMapper = vtkSmartPointer::New(); this->IconMapper = vtkSmartPointer::New(); this->EdgeActor = vtkSmartPointer::New(); this->VertexActor = vtkSmartPointer::New(); this->OutlineActor = vtkSmartPointer::New(); this->IconActor = vtkSmartPointer::New(); this->VertexLookupTable = vtkLookupTableWithEnabling::New(); this->EdgeLookupTable = vtkLookupTableWithEnabling::New(); this->VertexColorArrayNameInternal = nullptr; this->EdgeColorArrayNameInternal = nullptr; this->EnabledEdgesArrayName = nullptr; this->EnabledVerticesArrayName = nullptr; this->VertexPointSize = 5; this->EdgeLineWidth = 1; this->ScaledGlyphs = false; this->ScalingArrayName = nullptr; this->VertexMapper->SetScalarModeToUsePointData(); this->VertexMapper->SetLookupTable(this->VertexLookupTable); this->VertexMapper->SetScalarVisibility(false); this->VertexActor->PickableOff(); this->VertexActor->GetProperty()->SetPointSize(this->GetVertexPointSize()); this->OutlineActor->PickableOff(); this->OutlineActor->GetProperty()->SetPointSize(this->GetVertexPointSize()+2); this->OutlineActor->SetPosition(0, 0, -0.001); this->OutlineActor->GetProperty()->SetRepresentationToWireframe(); this->OutlineMapper->SetScalarVisibility(false); this->EdgeMapper->SetScalarModeToUseCellData(); this->EdgeMapper->SetLookupTable(this->EdgeLookupTable); this->EdgeMapper->SetScalarVisibility(false); this->EdgeActor->SetPosition(0, 0, -0.003); this->EdgeActor->GetProperty()->SetLineWidth(this->GetEdgeLineWidth()); this->IconTransform->SetInputCoordinateSystemToWorld(); this->IconTransform->SetOutputCoordinateSystemToDisplay(); this->IconTransform->SetInputConnection(this->VertexGlyph->GetOutputPort()); this->IconTypeToIndex->SetInputConnection(this->IconTransform->GetOutputPort()); this->IconTypeToIndex->SetFieldType(vtkMapArrayValues::POINT_DATA); this->IconTypeToIndex->SetOutputArrayType(VTK_INT); this->IconTypeToIndex->SetPassArray(0); this->IconTypeToIndex->SetFillValue(-1); this->IconGlyph->SetInputConnection(this->IconTypeToIndex->GetOutputPort()); this->IconGlyph->SetUseIconSize(true); this->IconMapper->SetInputConnection(this->IconGlyph->GetOutputPort()); this->IconMapper->ScalarVisibilityOff(); this->IconActor->SetMapper(this->IconMapper); this->IconArrayNameInternal = nullptr; this->VertexMapper->SetInputConnection(this->VertexGlyph->GetOutputPort()); this->OutlineMapper->SetInputConnection(this->VertexGlyph->GetOutputPort()); this->VertexActor->SetMapper(this->VertexMapper); this->OutlineActor->SetMapper(this->OutlineMapper); this->EdgeMapper->SetInputConnection(this->GraphToPoly->GetOutputPort()); this->EdgeActor->SetMapper(this->EdgeMapper); // Set default parameters this->SetVertexColorArrayName("VertexDegree"); this->ColorVerticesOff(); this->SetEdgeColorArrayName("weight"); this->ColorEdgesOff(); this->SetEnabledEdgesArrayName("weight"); this->SetEnabledVerticesArrayName("VertexDegree"); this->EnableEdgesByArray = 0; this->EnableVerticesByArray = 0; this->IconVisibilityOff(); } //---------------------------------------------------------------------------- vtkGraphMapper::~vtkGraphMapper() { // Delete internally created objects. // Note: All of the smartpointer objects // will be deleted for us this->SetVertexColorArrayNameInternal(nullptr); this->SetEdgeColorArrayNameInternal(nullptr); this->SetEnabledEdgesArrayName(nullptr); this->SetEnabledVerticesArrayName(nullptr); this->SetIconArrayNameInternal(nullptr); this->VertexLookupTable->Delete(); this->VertexLookupTable = nullptr; this->EdgeLookupTable->Delete(); this->EdgeLookupTable = nullptr; delete[] this->ScalingArrayName; } //---------------------------------------------------------------------------- void vtkGraphMapper::SetIconArrayName(const char* name) { this->SetIconArrayNameInternal(name); this->IconGlyph->SetInputArrayToProcess(0,0,0, vtkDataObject::FIELD_ASSOCIATION_POINTS,name); this->IconTypeToIndex->SetInputArrayName(name); } //---------------------------------------------------------------------------- const char* vtkGraphMapper::GetIconArrayName() { return this->GetIconArrayNameInternal(); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetScaledGlyphs(bool arg) { if (arg) { if (this->ScalingArrayName) { vtkPolyData *circle = this->CreateCircle(true); this->CircleGlyph->SetSourceData(circle); circle->Delete(); this->CircleGlyph->SetInputConnection(this->VertexGlyph->GetOutputPort()); this->CircleGlyph->SetScaling(1); //this->CircleGlyph->SetScaleFactor(.1); // Total hack this->CircleGlyph->SetInputArrayToProcess(0,0,0, vtkDataObject::FIELD_ASSOCIATION_POINTS, this->ScalingArrayName); this->VertexMapper->SetInputConnection(this->CircleGlyph->GetOutputPort()); vtkPolyData *outline = this->CreateCircle(false); this->CircleOutlineGlyph->SetSourceData(outline); outline->Delete(); this->CircleOutlineGlyph->SetInputConnection(this->VertexGlyph->GetOutputPort()); this->CircleOutlineGlyph->SetScaling(1); //this->CircleOutlineGlyph->SetScaleFactor(.1); // Total hack this->CircleOutlineGlyph->SetInputArrayToProcess(0,0,0, vtkDataObject::FIELD_ASSOCIATION_POINTS, this->ScalingArrayName); this->OutlineMapper->SetInputConnection(this->CircleOutlineGlyph->GetOutputPort()); this->OutlineActor->SetPosition(0, 0, 0.001); this->OutlineActor->GetProperty()->SetLineWidth(2); } else { vtkErrorMacro("No scaling array name set"); } } else { this->VertexMapper->SetInputConnection(this->VertexGlyph->GetOutputPort()); this->OutlineActor->SetPosition(0, 0, -0.001); this->OutlineMapper->SetInputConnection(this->VertexGlyph->GetOutputPort()); } } //---------------------------------------------------------------------------- // Helper method vtkPolyData* vtkGraphMapper::CreateCircle(bool filled) { int circleRes = 16; vtkIdType ptIds[17]; double x[3], theta; // Allocate storage vtkPolyData *poly = vtkPolyData::New(); VTK_CREATE(vtkPoints,pts); VTK_CREATE(vtkCellArray, circle); VTK_CREATE(vtkCellArray, outline); // generate points around the circle x[2] = 0.0; theta = 2.0 * vtkMath::Pi() / circleRes; for (int i=0; iInsertNextPoint(x); } circle->InsertNextCell(circleRes,ptIds); // Outline ptIds[circleRes] = ptIds[0]; outline->InsertNextCell(circleRes+1,ptIds); // Set up polydata poly->SetPoints(pts); if (filled) { poly->SetPolys(circle); } else { poly->SetLines(outline); } return poly; } //---------------------------------------------------------------------------- void vtkGraphMapper::SetVertexColorArrayName(const char* name) { this->SetVertexColorArrayNameInternal(name); this->VertexMapper->SetScalarModeToUsePointFieldData(); this->VertexMapper->SelectColorArray(name); } //---------------------------------------------------------------------------- const char* vtkGraphMapper::GetVertexColorArrayName() { return this->GetVertexColorArrayNameInternal(); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetColorVertices(bool vis) { this->VertexMapper->SetScalarVisibility(vis); } //---------------------------------------------------------------------------- bool vtkGraphMapper::GetColorVertices() { return this->VertexMapper->GetScalarVisibility() ? true : false; } //---------------------------------------------------------------------------- void vtkGraphMapper::ColorVerticesOn() { this->VertexMapper->SetScalarVisibility(true); } //---------------------------------------------------------------------------- void vtkGraphMapper::ColorVerticesOff() { this->VertexMapper->SetScalarVisibility(false); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetIconVisibility(bool vis) { this->IconActor->SetVisibility(vis); } //---------------------------------------------------------------------------- bool vtkGraphMapper::GetIconVisibility() { return this->IconActor->GetVisibility() ? true : false; } //---------------------------------------------------------------------------- void vtkGraphMapper::SetEdgeColorArrayName(const char* name) { this->SetEdgeColorArrayNameInternal(name); this->EdgeMapper->SetScalarModeToUseCellFieldData(); this->EdgeMapper->SelectColorArray(name); } //---------------------------------------------------------------------------- const char* vtkGraphMapper::GetEdgeColorArrayName() { return this->GetEdgeColorArrayNameInternal(); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetColorEdges(bool vis) { this->EdgeMapper->SetScalarVisibility(vis); } //---------------------------------------------------------------------------- bool vtkGraphMapper::GetColorEdges() { return this->EdgeMapper->GetScalarVisibility() ? true : false; } //---------------------------------------------------------------------------- void vtkGraphMapper::ColorEdgesOn() { this->EdgeMapper->SetScalarVisibility(true); } //---------------------------------------------------------------------------- void vtkGraphMapper::ColorEdgesOff() { this->EdgeMapper->SetScalarVisibility(false); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetVertexPointSize(float size) { this->VertexPointSize = size; this->VertexActor->GetProperty()->SetPointSize(this->GetVertexPointSize()); this->OutlineActor->GetProperty()->SetPointSize(this->GetVertexPointSize()+2); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetEdgeLineWidth(float width) { this->EdgeLineWidth = width; this->EdgeActor->GetProperty()->SetLineWidth(this->GetEdgeLineWidth()); } //---------------------------------------------------------------------------- void vtkGraphMapper::AddIconType(char *type, int index) { this->IconTypeToIndex->AddToMap(type, index); } //---------------------------------------------------------------------------- void vtkGraphMapper::ClearIconTypes() { this->IconTypeToIndex->ClearMap(); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetEdgeVisibility(bool vis) { this->EdgeActor->SetVisibility(vis); } //---------------------------------------------------------------------------- bool vtkGraphMapper::GetEdgeVisibility() { return this->EdgeActor->GetVisibility() ? true : false; } //---------------------------------------------------------------------------- void vtkGraphMapper::SetIconSize(int *size) { this->IconGlyph->SetIconSize(size); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetIconAlignment(int alignment) { this->IconGlyph->SetGravity(alignment); } //---------------------------------------------------------------------------- int *vtkGraphMapper::GetIconSize() { return this->IconGlyph->GetIconSize(); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetIconTexture(vtkTexture *texture) { this->IconActor->SetTexture(texture); } //---------------------------------------------------------------------------- vtkTexture *vtkGraphMapper::GetIconTexture() { return this->IconActor->GetTexture(); } //---------------------------------------------------------------------------- void vtkGraphMapper::SetInputData(vtkGraph *input) { this->SetInputDataInternal(0, input); } //---------------------------------------------------------------------------- vtkGraph *vtkGraphMapper::GetInput() { vtkGraph *inputGraph = vtkGraph::SafeDownCast(this->Superclass::GetInputAsDataSet()); return inputGraph; } //---------------------------------------------------------------------------- void vtkGraphMapper::ReleaseGraphicsResources( vtkWindow *renWin ) { if (this->EdgeActor) { this->EdgeActor->ReleaseGraphicsResources( renWin ); } if (this->VertexActor) { this->VertexActor->ReleaseGraphicsResources( renWin ); } if (this->OutlineActor) { this->OutlineActor->ReleaseGraphicsResources( renWin ); } if (this->IconActor) { this->IconActor->ReleaseGraphicsResources( renWin ); } } //---------------------------------------------------------------------------- // Receives from Actor -> maps data to primitives // void vtkGraphMapper::Render(vtkRenderer *ren, vtkActor * vtkNotUsed(act)) { // make sure that we've been properly initialized if ( !this->GetExecutive()->GetInputData(0, 0) ) { vtkErrorMacro(<< "No input!\n"); return; } // Update the pipeline up until the graph to poly data vtkGraph *input = vtkGraph::SafeDownCast(this->GetExecutive()->GetInputData(0, 0)); if (!input) { vtkErrorMacro(<< "Input is not a graph!\n"); return; } vtkGraph *graph = nullptr; if (vtkDirectedGraph::SafeDownCast(input)) { graph = vtkDirectedGraph::New(); } else { graph = vtkUndirectedGraph::New(); } graph->ShallowCopy(input); this->GraphToPoly->SetInputData(graph); this->VertexGlyph->SetInputData(graph); graph->Delete(); this->GraphToPoly->Update(); this->VertexGlyph->Update(); vtkPolyData* edgePd = this->GraphToPoly->GetOutput(); vtkPolyData* vertPd = this->VertexGlyph->GetOutput(); // Try to find the range the user-specified color array. // If we cannot find that array, use the scalar range. double range[2]; vtkDataArray* arr = nullptr; if (this->GetColorEdges()) { if (this->GetEdgeColorArrayName()) { arr = edgePd->GetCellData()->GetArray(this->GetEdgeColorArrayName()); } if (!arr) { arr = edgePd->GetCellData()->GetScalars(); } if (arr) { arr->GetRange(range); this->EdgeMapper->SetScalarRange(range[0], range[1]); } } arr = nullptr; if (this->EnableEdgesByArray && this->EnabledEdgesArrayName) { vtkLookupTableWithEnabling::SafeDownCast(this->EdgeLookupTable)->SetEnabledArray( edgePd->GetCellData()->GetArray(this->GetEnabledEdgesArrayName())); } else { vtkLookupTableWithEnabling::SafeDownCast(this->EdgeLookupTable)->SetEnabledArray(nullptr); } // Do the same thing for the vertex array. arr = nullptr; if (this->GetColorVertices()) { if (this->GetVertexColorArrayName()) { arr = vertPd->GetPointData()->GetArray(this->GetVertexColorArrayName()); } if (!arr) { arr = vertPd->GetPointData()->GetScalars(); } if (arr) { arr->GetRange(range); this->VertexMapper->SetScalarRange(range[0], range[1]); } } arr = nullptr; if (this->EnableVerticesByArray && this->EnabledVerticesArrayName) { vtkLookupTableWithEnabling::SafeDownCast(this->VertexLookupTable)->SetEnabledArray( vertPd->GetPointData()->GetArray(this->GetEnabledVerticesArrayName())); } else { vtkLookupTableWithEnabling::SafeDownCast(this->VertexLookupTable)->SetEnabledArray(nullptr); } if (this->IconActor->GetTexture() && this->IconActor->GetTexture()->GetInput() && this->IconActor->GetVisibility()) { this->IconTransform->SetViewport(ren); this->IconActor->GetTexture()->SetColorMode(VTK_COLOR_MODE_DEFAULT); this->IconActor->GetTexture()->GetInputAlgorithm()->Update(); int *dim = this->IconActor->GetTexture()->GetInput()->GetDimensions(); this->IconGlyph->SetIconSheetSize(dim); // Override the array for vtkIconGlyphFilter to process if we have // a map of icon types. if(this->IconTypeToIndex->GetMapSize()) { this->IconGlyph->SetInputArrayToProcess(0,0,0, vtkDataObject::FIELD_ASSOCIATION_POINTS, this->IconTypeToIndex->GetOutputArrayName()); } } if (this->EdgeActor->GetVisibility()) { this->EdgeActor->RenderOpaqueGeometry(ren); } if (this->OutlineActor->GetVisibility()) { this->OutlineActor->RenderOpaqueGeometry(ren); } this->VertexActor->RenderOpaqueGeometry(ren); if (this->IconActor->GetVisibility()) { this->IconActor->RenderOpaqueGeometry(ren); } if (this->EdgeActor->GetVisibility()) { this->EdgeActor->RenderTranslucentPolygonalGeometry(ren); } this->VertexActor->RenderTranslucentPolygonalGeometry(ren); if (this->OutlineActor->GetVisibility()) { this->OutlineActor->RenderTranslucentPolygonalGeometry(ren); } if (this->IconActor->GetVisibility()) { this->IconActor->RenderTranslucentPolygonalGeometry(ren); } if(this->IconActor->GetVisibility()) { this->IconActor->RenderOverlay(ren); } this->TimeToDraw = this->EdgeMapper->GetTimeToDraw() + this->VertexMapper->GetTimeToDraw() + this->OutlineMapper->GetTimeToDraw() + this->IconMapper->GetTimeToDraw(); } //---------------------------------------------------------------------------- void vtkGraphMapper::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); if ( this->CircleGlyph ) { os << indent << "CircleGlyph: (" << this->CircleGlyph << ")\n"; } else { os << indent << "CircleGlyph: (none)\n"; } if ( this->CircleOutlineGlyph ) { os << indent << "CircleOutlineGlyph: (" << this->CircleOutlineGlyph << ")\n"; } else { os << indent << "CircleOutlineGlyph: (none)\n"; } if ( this->EdgeMapper ) { os << indent << "EdgeMapper: (" << this->EdgeMapper << ")\n"; } else { os << indent << "EdgeMapper: (none)\n"; } if ( this->VertexMapper ) { os << indent << "VertexMapper: (" << this->VertexMapper << ")\n"; } else { os << indent << "VertexMapper: (none)\n"; } if ( this->OutlineMapper ) { os << indent << "OutlineMapper: (" << this->OutlineMapper << ")\n"; } else { os << indent << "OutlineMapper: (none)\n"; } if ( this->EdgeActor ) { os << indent << "EdgeActor: (" << this->EdgeActor << ")\n"; } else { os << indent << "EdgeActor: (none)\n"; } if ( this->VertexActor ) { os << indent << "VertexActor: (" << this->VertexActor << ")\n"; } else { os << indent << "VertexActor: (none)\n"; } if ( this->OutlineActor ) { os << indent << "OutlineActor: (" << this->OutlineActor << ")\n"; } else { os << indent << "OutlineActor: (none)\n"; } if ( this->GraphToPoly ) { os << indent << "GraphToPoly: (" << this->GraphToPoly << ")\n"; } else { os << indent << "GraphToPoly: (none)\n"; } if ( this->VertexLookupTable ) { os << indent << "VertexLookupTable: (" << this->VertexLookupTable << ")\n"; } else { os << indent << "VertexLookupTable: (none)\n"; } if ( this->EdgeLookupTable ) { os << indent << "EdgeLookupTable: (" << this->EdgeLookupTable << ")\n"; } else { os << indent << "EdgeLookupTable: (none)\n"; } os << indent << "VertexPointSize: " << this->VertexPointSize << endl; os << indent << "EdgeLineWidth: " << this->EdgeLineWidth << endl; os << indent << "ScaledGlyphs: " << this->ScaledGlyphs << endl; os << indent << "ScalingArrayName: " << (this->ScalingArrayName ? "" : "(null)") << endl; os << indent << "EnableEdgesByArray: " << this->EnableEdgesByArray << endl; os << indent << "EnableVerticesByArray: " << this->EnableVerticesByArray << endl; os << indent << "EnabledEdgesArrayName: " << (this->EnabledEdgesArrayName ? "" : "(null)") << endl; os << indent << "EnabledVerticesArrayName: " << (this->EnabledVerticesArrayName ? "" : "(null)") << endl; } //---------------------------------------------------------------------------- vtkMTimeType vtkGraphMapper::GetMTime() { vtkMTimeType mTime=this->vtkMapper::GetMTime(); vtkMTimeType time; if ( this->LookupTable != nullptr ) { time = this->LookupTable->GetMTime(); mTime = ( time > mTime ? time : mTime ); } return mTime; } //---------------------------------------------------------------------------- int vtkGraphMapper::FillInputPortInformation( int vtkNotUsed(port), vtkInformation* info) { info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkGraph"); return 1; } //---------------------------------------------------------------------------- double *vtkGraphMapper::GetBounds() { vtkGraph *graph = vtkGraph::SafeDownCast(this->GetExecutive()->GetInputData(0, 0)); if (!graph) { vtkMath::UninitializeBounds(this->Bounds); return this->Bounds; } if (!this->Static) { this->Update(); graph = vtkGraph::SafeDownCast(this->GetExecutive()->GetInputData(0, 0)); } if (!graph) { vtkMath::UninitializeBounds(this->Bounds); return this->Bounds; } graph->GetBounds(this->Bounds); return this->Bounds; } #if 1 //---------------------------------------------------------------------------- void vtkGraphMapper::ReportReferences(vtkGarbageCollector* collector) { this->Superclass::ReportReferences(collector); // These filters share our input and are therefore involved in a // reference loop. //vtkGarbageCollectorReport(collector, this->GraphToPoly, // "GraphToPoly"); } #endif