vtkCategoryLegend.cxx 8.55 KB
Newer Older
Zack Galbreath's avatar
Zack Galbreath committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkCategoryLegend.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.

=========================================================================*/

#include "vtkBrush.h"
#include "vtkCategoryLegend.h"
#include "vtkContext2D.h"
#include "vtkObjectFactory.h"
#include "vtkScalarsToColors.h"
#include "vtkTextProperty.h"
#include "vtkVariantArray.h"

//-----------------------------------------------------------------------------
vtkStandardNewMacro(vtkCategoryLegend);

//-----------------------------------------------------------------------------
vtkCategoryLegend::vtkCategoryLegend()
{
  this->SetInline(false);
  this->SetHorizontalAlignment(vtkChartLegend::RIGHT);
  this->SetVerticalAlignment(vtkChartLegend::BOTTOM);

34 35
  this->ScalarsToColors = nullptr;
  this->Values = nullptr;
Zack Galbreath's avatar
Zack Galbreath committed
36 37 38 39 40 41 42 43 44 45 46 47 48 49

  this->TitleProperties->SetColor(this->LabelProperties->GetColor());
  this->TitleProperties->SetFontSize(this->LabelProperties->GetFontSize());
  this->TitleProperties->SetFontFamily(this->LabelProperties->GetFontFamily());
  this->TitleProperties->SetJustificationToCentered();
  this->TitleProperties->SetVerticalJustificationToTop();
  this->TitleProperties->SetBold(1);

  this->TitleWidthOffset = 0.0;
  this->HasOutliers = false;
  this->OutlierLabel = "outliers";
}

//-----------------------------------------------------------------------------
50
vtkCategoryLegend::~vtkCategoryLegend() = default;
Zack Galbreath's avatar
Zack Galbreath committed
51 52 53 54

//-----------------------------------------------------------------------------
bool vtkCategoryLegend::Paint(vtkContext2D* painter)
{
55
  if (!this->Visible || this->ScalarsToColors == nullptr || this->Values == nullptr)
56
  {
Zack Galbreath's avatar
Zack Galbreath committed
57
    return true;
58
  }
Zack Galbreath's avatar
Zack Galbreath committed
59 60

  // Draw a box around the legend.
61 62
  painter->ApplyPen(this->Pen);
  painter->ApplyBrush(this->Brush);
Zack Galbreath's avatar
Zack Galbreath committed
63 64 65 66 67 68 69
  this->GetBoundingRect(painter);
  painter->DrawRect(this->Rect.GetX(), this->Rect.GetY(),
                    this->Rect.GetWidth(), this->Rect.GetHeight());

  // Draw the title (if any)
  vtkVector2f stringBounds[2];
  float titleHeight = 0.0;
70
  if (!this->Title.empty())
71
  {
72
    painter->ApplyTextProp(this->TitleProperties);
Zack Galbreath's avatar
Zack Galbreath committed
73 74 75 76 77 78
    painter->ComputeStringBounds(this->Title, stringBounds->GetData());
    titleHeight = stringBounds[1].GetY() + this->Padding;

    float x = this->Rect.GetX() + this->Rect.GetWidth() / 2.0;
    float y = this->Rect.GetY() + this->Rect.GetHeight() - this->Padding;
    painter->DrawString(x, y, this->Title);
79
  }
Zack Galbreath's avatar
Zack Galbreath committed
80

81
  painter->ApplyTextProp(this->LabelProperties);
Zack Galbreath's avatar
Zack Galbreath committed
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98

  // compute the height of a sample string.
  // The height of this string will also be used as the size of
  // the color marks.
  painter->ComputeStringBounds("Tgyf", stringBounds->GetData());
  float stringHeight = stringBounds[1].GetY();

  // the starting X positions of our marks & labels
  float markX = this->Rect.GetX() + this->TitleWidthOffset + this->Padding;
  float labelX = markX + stringHeight + this->Padding;

  // the Y value of the row that we're currently drawing
  float y = this->Rect.GetY() + this->Rect.GetHeight() -
                  this->Padding - floor(stringHeight) - titleHeight;

  // draw all of the marks & labels
  for (vtkIdType l = 0; l < this->Values->GetNumberOfTuples(); ++l)
99
  {
Zack Galbreath's avatar
Zack Galbreath committed
100
    vtkStdString currentString = this->Values->GetValue(l).ToString();
101
    if (currentString.empty())
102
    {
Zack Galbreath's avatar
Zack Galbreath committed
103
      continue;
104
    }
Zack Galbreath's avatar
Zack Galbreath committed
105 106 107

    if (this->ScalarsToColors->GetAnnotatedValueIndex(
      this->Values->GetValue(l)) == -1)
108
    {
Zack Galbreath's avatar
Zack Galbreath committed
109
      continue;
110
    }
Zack Galbreath's avatar
Zack Galbreath committed
111 112 113 114 115 116 117 118 119 120 121 122

    // paint the color mark for this category
    double color[4];
    this->ScalarsToColors->GetAnnotationColor(this->Values->GetValue(l), color);
    painter->GetBrush()->SetColorF(color[0], color[1], color[2]);
    painter->DrawRect(markX, y, stringHeight, stringHeight);

    // draw this category's label
    painter->DrawString(labelX, y, this->Values->GetValue(l).ToString());

    // Move y position down another row
    y -= stringHeight + this->Padding;
123
  }
Zack Galbreath's avatar
Zack Galbreath committed
124 125

  if (this->HasOutliers)
126
  {
Zack Galbreath's avatar
Zack Galbreath committed
127 128 129 130 131 132 133 134 135
    // paint the outlier color mark
    double color[4];
    this->ScalarsToColors->GetAnnotationColor(
      this->ScalarsToColors->GetAnnotatedValue(-1), color);
    painter->GetBrush()->SetColorF(color[0], color[1], color[2]);
    painter->DrawRect(markX, y, stringHeight, stringHeight);

    // draw the outlier label
    painter->DrawString(labelX, y, this->OutlierLabel);
136
  }
Zack Galbreath's avatar
Zack Galbreath committed
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159

  return true;
}

//-----------------------------------------------------------------------------
void vtkCategoryLegend::SetScalarsToColors(vtkScalarsToColors* stc)
{
  this->ScalarsToColors = stc;
}

//-----------------------------------------------------------------------------
vtkScalarsToColors * vtkCategoryLegend::GetScalarsToColors()
{
  return this->ScalarsToColors;
}

//-----------------------------------------------------------------------------
vtkRectf vtkCategoryLegend::GetBoundingRect(vtkContext2D *painter)
{
  if (this->CacheBounds && this->RectTime > this->GetMTime() &&
      this->RectTime > this->PlotTime &&
      this->RectTime > this->ScalarsToColors->GetMTime() &&
      this->RectTime > this->Values->GetMTime())
160
  {
Zack Galbreath's avatar
Zack Galbreath committed
161
    return this->Rect;
162
  }
Zack Galbreath's avatar
Zack Galbreath committed
163

164
  painter->ApplyTextProp(this->LabelProperties);
Zack Galbreath's avatar
Zack Galbreath committed
165 166 167 168 169 170 171

  vtkVector2f stringBounds[2];
  painter->ComputeStringBounds("Tgyf", stringBounds->GetData());
  float height = stringBounds[1].GetY();

  // programmatically set Padding here.  This results in better
  // appearance when we zoom in or out on the legend.
172
  this->Padding = static_cast<int>(height / 4.0);
Zack Galbreath's avatar
Zack Galbreath committed
173
  if (this->Padding < 1)
174
  {
Zack Galbreath's avatar
Zack Galbreath committed
175
    this->Padding = 1;
176
  }
Zack Galbreath's avatar
Zack Galbreath committed
177 178 179 180

  // Calculate size of title (if any)
  float titleHeight = 0.0f;
  float titleWidth = 0.0f;
181
  if (!this->Title.empty())
182
  {
183
    painter->ApplyTextProp(this->TitleProperties);
Zack Galbreath's avatar
Zack Galbreath committed
184 185 186 187 188

    painter->ComputeStringBounds(this->Title, stringBounds->GetData());
    titleWidth = stringBounds[1].GetX();
    titleHeight = stringBounds[1].GetY() + this->Padding;

189
    painter->ApplyTextProp(this->LabelProperties);
190
  }
Zack Galbreath's avatar
Zack Galbreath committed
191 192 193 194 195 196 197 198

  // Calculate the widest legend label
  float maxWidth = 0.0;
  int numSkippedValues = 0;
  this->TitleWidthOffset = 0.0;
  this->HasOutliers = false;

  for (vtkIdType l = 0; l < this->Values->GetNumberOfTuples(); ++l)
199
  {
200
    if (this->Values->GetValue(l).ToString().empty())
201
    {
Zack Galbreath's avatar
Zack Galbreath committed
202 203
      ++numSkippedValues;
      continue;
204
    }
Zack Galbreath's avatar
Zack Galbreath committed
205 206
    if (this->ScalarsToColors->GetAnnotatedValueIndex(
      this->Values->GetValue(l)) == -1)
207
    {
Zack Galbreath's avatar
Zack Galbreath committed
208 209 210
      ++numSkippedValues;
      this->HasOutliers = true;
      continue;
211
    }
Zack Galbreath's avatar
Zack Galbreath committed
212 213 214
    painter->ComputeStringBounds(this->Values->GetValue(l).ToString(),
                                 stringBounds->GetData());
    if (stringBounds[1].GetX() > maxWidth)
215
    {
Zack Galbreath's avatar
Zack Galbreath committed
216 217
      maxWidth = stringBounds[1].GetX();
    }
218
  }
Zack Galbreath's avatar
Zack Galbreath committed
219 220 221

  // Calculate size of outlier label (if necessary)
  if (this->HasOutliers)
222
  {
Zack Galbreath's avatar
Zack Galbreath committed
223 224 225
    painter->ComputeStringBounds(this->OutlierLabel,
                                 stringBounds->GetData());
    if (stringBounds[1].GetX() > maxWidth)
226
    {
Zack Galbreath's avatar
Zack Galbreath committed
227 228
      maxWidth = stringBounds[1].GetX();
    }
229
  }
Zack Galbreath's avatar
Zack Galbreath committed
230 231

  if (titleWidth > maxWidth)
232
  {
Zack Galbreath's avatar
Zack Galbreath committed
233 234
    this->TitleWidthOffset = (titleWidth - maxWidth) / 2.0;
    maxWidth = titleWidth;
235
  }
Zack Galbreath's avatar
Zack Galbreath committed
236 237 238

  int numLabels = this->Values->GetNumberOfTuples() - numSkippedValues;
  if (this->HasOutliers)
239
  {
Zack Galbreath's avatar
Zack Galbreath committed
240
    ++numLabels;
241
  }
Zack Galbreath's avatar
Zack Galbreath committed
242 243 244 245 246 247 248 249 250 251 252 253 254

  // 3 paddings: one on the left, one on the right, and one between the
  // color mark and its label.
  float w = ceil(maxWidth + 3 * this->Padding + height);

  float h = ceil((numLabels * (height + this->Padding)) + this->Padding
            + titleHeight);

  float x = floor(this->Point[0]);
  float y = floor(this->Point[1]);

  // Compute bottom left point based on current alignment.
  if (this->HorizontalAlignment == vtkChartLegend::CENTER)
255
  {
Zack Galbreath's avatar
Zack Galbreath committed
256
    x -= w / 2.0;
257
  }
Zack Galbreath's avatar
Zack Galbreath committed
258
  else if (this->HorizontalAlignment == vtkChartLegend::RIGHT)
259
  {
Zack Galbreath's avatar
Zack Galbreath committed
260
    x -= w;
261
  }
Zack Galbreath's avatar
Zack Galbreath committed
262
  if (this->VerticalAlignment == vtkChartLegend::CENTER)
263
  {
Zack Galbreath's avatar
Zack Galbreath committed
264
    y -= h / 2.0;
265
  }
Zack Galbreath's avatar
Zack Galbreath committed
266
  else if (this->VerticalAlignment == vtkChartLegend::TOP)
267
  {
Zack Galbreath's avatar
Zack Galbreath committed
268
    y -= h;
269
  }
Zack Galbreath's avatar
Zack Galbreath committed
270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286

  this->Rect = vtkRectf(x, y, w, h);
  this->RectTime.Modified();
  return this->Rect;
}

//-----------------------------------------------------------------------------
void vtkCategoryLegend::SetTitle(const vtkStdString &title)
{
  this->Title = title;
}

//-----------------------------------------------------------------------------
vtkStdString vtkCategoryLegend::GetTitle()
{
  return this->Title;
}