vtkCategoryLegend.cxx 8.62 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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*=========================================================================

  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);

  this->ScalarsToColors = NULL;
  this->Values = NULL;

  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";
}

//-----------------------------------------------------------------------------
vtkCategoryLegend::~vtkCategoryLegend()
{
}

//-----------------------------------------------------------------------------
bool vtkCategoryLegend::Paint(vtkContext2D* painter)
{
  if (!this->Visible || this->ScalarsToColors == NULL || this->Values == NULL)
58
  {
Zack Galbreath's avatar
Zack Galbreath committed
59
    return true;
60
  }
Zack Galbreath's avatar
Zack Galbreath committed
61
62
63
64
65
66
67
68
69
70
71

  // Draw a box around the legend.
  painter->ApplyPen(this->Pen.GetPointer());
  painter->ApplyBrush(this->Brush.GetPointer());
  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;
72
  if (!this->Title.empty())
73
  {
Zack Galbreath's avatar
Zack Galbreath committed
74
75
76
77
78
79
80
    painter->ApplyTextProp(this->TitleProperties.GetPointer());
    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);
81
  }
Zack Galbreath's avatar
Zack Galbreath committed
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100

  painter->ApplyTextProp(this->LabelProperties.GetPointer());

  // 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)
101
  {
Zack Galbreath's avatar
Zack Galbreath committed
102
    vtkStdString currentString = this->Values->GetValue(l).ToString();
103
    if (currentString.empty())
104
    {
Zack Galbreath's avatar
Zack Galbreath committed
105
      continue;
106
    }
Zack Galbreath's avatar
Zack Galbreath committed
107
108
109

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

    // 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;
125
  }
Zack Galbreath's avatar
Zack Galbreath committed
126
127

  if (this->HasOutliers)
128
  {
Zack Galbreath's avatar
Zack Galbreath committed
129
130
131
132
133
134
135
136
137
    // 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);
138
  }
Zack Galbreath's avatar
Zack Galbreath committed
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161

  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())
162
  {
Zack Galbreath's avatar
Zack Galbreath committed
163
    return this->Rect;
164
  }
Zack Galbreath's avatar
Zack Galbreath committed
165
166
167
168
169
170
171
172
173

  painter->ApplyTextProp(this->LabelProperties.GetPointer());

  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.
174
  this->Padding = static_cast<int>(height / 4.0);
Zack Galbreath's avatar
Zack Galbreath committed
175
  if (this->Padding < 1)
176
  {
Zack Galbreath's avatar
Zack Galbreath committed
177
    this->Padding = 1;
178
  }
Zack Galbreath's avatar
Zack Galbreath committed
179
180
181
182

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

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

    painter->ApplyTextProp(this->LabelProperties.GetPointer());
192
  }
Zack Galbreath's avatar
Zack Galbreath committed
193
194
195
196
197
198
199
200

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

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

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

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

  // 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)
257
  {
Zack Galbreath's avatar
Zack Galbreath committed
258
    x -= w / 2.0;
259
  }
Zack Galbreath's avatar
Zack Galbreath committed
260
  else if (this->HorizontalAlignment == vtkChartLegend::RIGHT)
261
  {
Zack Galbreath's avatar
Zack Galbreath committed
262
    x -= w;
263
  }
Zack Galbreath's avatar
Zack Galbreath committed
264
  if (this->VerticalAlignment == vtkChartLegend::CENTER)
265
  {
Zack Galbreath's avatar
Zack Galbreath committed
266
    y -= h / 2.0;
267
  }
Zack Galbreath's avatar
Zack Galbreath committed
268
  else if (this->VerticalAlignment == vtkChartLegend::TOP)
269
  {
Zack Galbreath's avatar
Zack Galbreath committed
270
    y -= h;
271
  }
Zack Galbreath's avatar
Zack Galbreath committed
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288

  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;
}