/*========================================================================= Program: Visualization Toolkit Module: vtkDendrogramItem.h 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. =========================================================================*/ /** * @class vtkDendrogramItem * @brief A 2D graphics item for rendering a tree as * a dendrogram * * * Draw a tree as a dendrogram * The input tree's vertex data must contain at least two arrays. * The first required array is a vtkStringArray called "node name". * This array is used to label the leaf nodes of the tree. * The second required array is a scalar array called "node weight". * This array is used by vtkTreeLayoutStrategy to set any particular * node's distance from the root of the tree. * * The vtkNewickTreeReader automatically initializes both of these * required arrays in its output tree. * * .SEE ALSO * vtkTree vtkNewickTreeReader */ #ifndef vtkDendrogramItem_h #define vtkDendrogramItem_h #include "vtkContextItem.h" #include "vtkViewsInfovisModule.h" // For export macro #include "vtkNew.h" // For vtkNew ivars #include "vtkSmartPointer.h" // For vtkSmartPointer ivars #include "vtkStdString.h" // For SetGet ivars #include "vtkVector.h" // For vtkVector2f ivar class vtkColorLegend; class vtkDoubleArray; class vtkGraphLayout; class vtkLookupTable; class vtkPruneTreeFilter; class vtkTree; class VTKVIEWSINFOVIS_EXPORT vtkDendrogramItem : public vtkContextItem { public: static vtkDendrogramItem* New(); vtkTypeMacro(vtkDendrogramItem, vtkContextItem); void PrintSelf(ostream& os, vtkIndent indent) override; /** * Set the tree that this item draws. Note that this tree's vertex data * must contain a vtkStringArray called "node name". The vtkNewickTreeReader * automatically creates this required array for you. */ virtual void SetTree(vtkTree* tree); /** * Get the tree that this item draws. */ vtkTree* GetTree(); /** * Collapse subtrees until there are only n leaf nodes left in the tree. * The leaf nodes that remain are those that are closest to the root. * Any subtrees that were collapsed prior to this function being called * may be re-expanded. */ void CollapseToNumberOfLeafNodes(unsigned int n); /** * Get the collapsed tree */ vtkTree* GetPrunedTree(); /** * Indicate which array within the Tree's VertexData should be used to * color the tree. The specified array must be a vtkDoubleArray. * By default, the tree will be drawn in black. */ void SetColorArray(const char* arrayName); //@{ /** * Get/set whether or not leaf nodes should be extended so that they all line * up vertically. The default is to NOT extend leaf nodes. When extending * leaf nodes, the extra length is drawn in grey so as to distinguish it from * the actual length of the leaf node. */ vtkSetMacro(ExtendLeafNodes, bool); vtkGetMacro(ExtendLeafNodes, bool); vtkBooleanMacro(ExtendLeafNodes, bool); //@} /** * Set which way the tree should face within the visualization. The default * is for the tree to be drawn left to right. */ void SetOrientation(int orientation); /** * Get the current tree orientation. */ int GetOrientation(); /** * Get the rotation angle (in degrees) that corresponds to the given * tree orientation. For the default orientation (LEFT_TO_RIGHT), this * is 90 degrees. */ double GetAngleForOrientation(int orientation); /** * Get the angle that vertex labels should be rotated for the corresponding * tree orientation. For the default orientation (LEFT_TO_RIGHT), this * is 0 degrees. */ double GetTextAngleForOrientation(int orientation); //@{ /** * Get/Set whether or not leaf nodes should be labeled by this class. * Default is true. */ vtkSetMacro(DrawLabels, bool); vtkGetMacro(DrawLabels, bool); vtkBooleanMacro(DrawLabels, bool); //@} //@{ /** * Set the position of the dendrogram. */ vtkSetVector2Macro(Position, float); void SetPosition(const vtkVector2f& pos); //@} //@{ /** * Get position of the dendrogram. */ vtkGetVector2Macro(Position, float); vtkVector2f GetPositionVector(); //@} //@{ /** * Get/Set the spacing between the leaf nodes in our dendrogram. * Default is 18 pixels. */ vtkGetMacro(LeafSpacing, double); vtkSetMacro(LeafSpacing, double); //@} /** * This function calls RebuildBuffers() if necessary. * Once PrepareToPaint() has been called, GetBounds() is guaranteed * to provide useful information. */ void PrepareToPaint(vtkContext2D* painter); /** * Get the bounds for this item as (Xmin,Xmax,Ymin,Ymax). * These bounds are only guaranteed to be accurate after Paint() or * PrepareToPaint() has been called. */ virtual void GetBounds(double bounds[4]); /** * Compute the width of the longest leaf node label. */ void ComputeLabelWidth(vtkContext2D* painter); /** * Get the width of the longest leaf node label. */ float GetLabelWidth(); /** * Find the position of the vertex with the specified name. Store * this information in the passed array. Returns true if the vertex * was found, false otherwise. */ bool GetPositionOfVertex(const std::string& vertexName, double position[2]); /** * Paints the input tree as a dendrogram. */ bool Paint(vtkContext2D* painter) override; //@{ /** * Get/Set how wide the edges of this dendrogram should be. Default is one pixel. */ vtkGetMacro(LineWidth, float); vtkSetMacro(LineWidth, float); //@} //@{ /** * Get/set whether or not the number of collapsed leaf nodes should be written * inside the triangle representing a collapsed subtree. Default is true. */ vtkSetMacro(DisplayNumberOfCollapsedLeafNodes, bool); vtkGetMacro(DisplayNumberOfCollapsedLeafNodes, bool); vtkBooleanMacro(DisplayNumberOfCollapsedLeafNodes, bool); //@} //@{ /** * Get/Set the name of the array that specifies the distance of each vertex * from the root (NOT the vertex's parent). This array should be a part of * the input tree's VertexData. By default, this value is "node weight", * which is the name of the array created by vtkNewickTreeReader. */ vtkGetMacro(DistanceArrayName, vtkStdString); vtkSetMacro(DistanceArrayName, vtkStdString); //@} //@{ /** * Get/Set the name of a vtkStringArray that specifies the names of the * vertices of the input tree. This array should be a part of the input * tree's VertexData. By default, this value is "node name", which is the * name of the array created by vtkNewickTreeReader. */ vtkGetMacro(VertexNameArrayName, vtkStdString); vtkSetMacro(VertexNameArrayName, vtkStdString); //@} // this struct & class allow us to generate a priority queue of vertices. struct WeightedVertex { vtkIdType ID; double weight; }; class CompareWeightedVertices { public: // Returns true if v2 is higher priority than v1 bool operator()(WeightedVertex& v1, WeightedVertex& v2) { if (v1.weight <= v2.weight) { return false; } return true; } }; /** * Enum for Orientation. */ enum { LEFT_TO_RIGHT, UP_TO_DOWN, RIGHT_TO_LEFT, DOWN_TO_UP }; /** * Returns true if the transform is interactive, false otherwise. */ bool Hit(const vtkContextMouseEvent& mouse) override; /** * Collapse or expand a subtree when the user double clicks on an * internal node. */ bool MouseDoubleClickEvent(const vtkContextMouseEvent& event) override; protected: vtkDendrogramItem(); ~vtkDendrogramItem() override; vtkVector2f PositionVector; float* Position; /** * Generate some data needed for painting. We cache this information as * it only needs to be generated when the input data changes. */ virtual void RebuildBuffers(); /** * This function does the bulk of the actual work in rendering our dendrogram */ virtual void PaintBuffers(vtkContext2D* painter); /** * This function returns a bool indicating whether or not we need to rebuild * our cached data before painting. */ virtual bool IsDirty(); /** * Compute how to scale our data so that text labels will fit within the * bounds determined by the spacing between the leaf nodes of the tree. */ void ComputeMultipliers(); /** * Compute the bounds of our tree in pixel coordinates. */ void ComputeBounds(); /** * Count the number of leaf nodes in the tree */ void CountLeafNodes(); /** * Count the number of leaf nodes that descend from a given vertex. */ int CountLeafNodes(vtkIdType vertex); /** * Get the tree vertex closest to the specified coordinates. */ vtkIdType GetClosestVertex(double x, double y); /** * Collapse the subtree rooted at vertex. */ void CollapseSubTree(vtkIdType vertex); /** * Expand the previously collapsed subtree rooted at vertex. */ void ExpandSubTree(vtkIdType vertex); /** * Look up the original ID of a vertex in the pruned tree. */ vtkIdType GetOriginalId(vtkIdType vertex); /** * Look up the ID of a vertex in the pruned tree from a vertex ID * of the input tree. */ vtkIdType GetPrunedIdForOriginalId(vtkIdType originalId); /** * Check if the click at (x, y) should be considered as a click on * a collapsed subtree. Returns the vtkIdType of the pruned subtree * if so, -1 otherwise. */ vtkIdType GetClickedCollapsedSubTree(double x, double y); /** * Calculate the extent of the data that is visible within the window. * This information is used to ensure that we only draw details that * will be seen by the user. This improves rendering speed, particularly * for larger data. */ void UpdateVisibleSceneExtent(vtkContext2D* painter); /** * Returns true if any part of the line segment defined by endpoints * (x0, y0), (x1, y1) falls within the extent of the currently * visible scene. Returns false otherwise. */ bool LineIsVisible(double x0, double y0, double x1, double y1); /** * Internal function. Use SetOrientation(int orientation) instead. */ void SetOrientation(vtkTree* tree, int orientation); // Setup the position, size, and orientation of this dendrogram's color // legend based on the dendrogram's current orientation. void PositionColorLegend(); vtkSmartPointer Tree; vtkSmartPointer LayoutTree; private: vtkDendrogramItem(const vtkDendrogramItem&) = delete; void operator=(const vtkDendrogramItem&) = delete; vtkSmartPointer PrunedTree; vtkMTimeType DendrogramBuildTime; vtkNew Layout; vtkNew PruneFilter; vtkNew TriangleLookupTable; vtkNew TreeLookupTable; vtkNew ColorLegend; vtkDoubleArray* ColorArray; double MultiplierX; double MultiplierY; int NumberOfLeafNodes; double LeafSpacing; double MinX; double MinY; double MaxX; double MaxY; double SceneBottomLeft[3]; double SceneTopRight[3]; float LabelWidth; float LineWidth; bool ColorTree; bool ExtendLeafNodes; bool DrawLabels; bool DisplayNumberOfCollapsedLeafNodes; bool LegendPositionSet; vtkStdString DistanceArrayName; vtkStdString VertexNameArrayName; }; #endif