1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkChart.cxx
5
6 Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7 All rights reserved.
8 See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10 This software is distributed WITHOUT ANY WARRANTY; without even
11 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12 PURPOSE. See the above copyright notice for more information.
13
14 =========================================================================*/
15
16 #include "vtkChart.h"
17 #include "vtkAxis.h"
18 #include "vtkBrush.h"
19 #include "vtkTransform2D.h"
20 #include "vtkContextMouseEvent.h"
21
22 #include "vtkAnnotationLink.h"
23 #include "vtkContextScene.h"
24 #include "vtkTextProperty.h"
25 #include "vtkObjectFactory.h"
26
27 //-----------------------------------------------------------------------------
MouseActions()28 vtkChart::MouseActions::MouseActions()
29 {
30 this->Pan() = vtkContextMouseEvent::LEFT_BUTTON;
31 this->Zoom() = vtkContextMouseEvent::MIDDLE_BUTTON;
32 this->Select() = vtkContextMouseEvent::RIGHT_BUTTON;
33 this->ZoomAxis() = -1;
34 this->SelectPolygon() = -1;
35 this->ClickAndDrag() = -1;
36 }
37
38 //-----------------------------------------------------------------------------
MouseClickActions()39 vtkChart::MouseClickActions::MouseClickActions()
40 {
41 this->Data[0] = vtkContextMouseEvent::LEFT_BUTTON;
42 this->Data[1] = vtkContextMouseEvent::RIGHT_BUTTON;
43 }
44
45 //-----------------------------------------------------------------------------
46 vtkCxxSetObjectMacro(vtkChart, AnnotationLink, vtkAnnotationLink);
47
48 //-----------------------------------------------------------------------------
vtkChart()49 vtkChart::vtkChart()
50 {
51 this->Geometry[0] = 0;
52 this->Geometry[1] = 0;
53 this->Point1[0] = 0;
54 this->Point1[1] = 0;
55 this->Point2[0] = 0;
56 this->Point2[1] = 0;
57 this->Size.Set(0, 0, 0, 0);
58 this->ShowLegend = false;
59 this->TitleProperties = vtkTextProperty::New();
60 this->TitleProperties->SetJustificationToCentered();
61 this->TitleProperties->SetColor(0.0, 0.0, 0.0);
62 this->TitleProperties->SetFontSize(12);
63 this->TitleProperties->SetFontFamilyToArial();
64 this->AnnotationLink = nullptr;
65 this->LayoutStrategy = vtkChart::FILL_SCENE;
66 this->RenderEmpty = false;
67 this->BackgroundBrush = vtkSmartPointer<vtkBrush>::New();
68 this->BackgroundBrush->SetColorF(1, 1, 1, 0);
69 this->SelectionMode = vtkContextScene::SELECTION_NONE;
70 this->SelectionMethod = vtkChart::SELECTION_ROWS;
71 }
72
73 //-----------------------------------------------------------------------------
~vtkChart()74 vtkChart::~vtkChart()
75 {
76 for(int i=0; i < 4; i++)
77 {
78 if(this->GetAxis(i))
79 {
80 this->GetAxis(i)->RemoveObservers(vtkChart::UpdateRange);
81 }
82 }
83 this->TitleProperties->Delete();
84 if (this->AnnotationLink)
85 {
86 this->AnnotationLink->Delete();
87 }
88 }
89
90 //-----------------------------------------------------------------------------
AddPlot(int)91 vtkPlot * vtkChart::AddPlot(int)
92 {
93 return nullptr;
94 }
95
96 //-----------------------------------------------------------------------------
AddPlot(vtkPlot *)97 vtkIdType vtkChart::AddPlot(vtkPlot*)
98 {
99 return -1;
100 }
101
102 //-----------------------------------------------------------------------------
RemovePlot(vtkIdType)103 bool vtkChart::RemovePlot(vtkIdType)
104 {
105 return false;
106 }
107
108 //-----------------------------------------------------------------------------
RemovePlotInstance(vtkPlot * plot)109 bool vtkChart::RemovePlotInstance(vtkPlot* plot)
110 {
111 if (plot)
112 {
113 vtkIdType numberOfPlots = this->GetNumberOfPlots();
114 for (vtkIdType i = 0; i < numberOfPlots; ++i)
115 {
116 if (this->GetPlot(i) == plot)
117 {
118 return this->RemovePlot(i);
119 }
120 }
121 }
122 return false;
123 }
124
125 //-----------------------------------------------------------------------------
ClearPlots()126 void vtkChart::ClearPlots()
127 {
128 }
129
130 //-----------------------------------------------------------------------------
GetPlot(vtkIdType)131 vtkPlot* vtkChart::GetPlot(vtkIdType)
132 {
133 return nullptr;
134 }
135
136 //-----------------------------------------------------------------------------
GetNumberOfPlots()137 vtkIdType vtkChart::GetNumberOfPlots()
138 {
139 return 0;
140 }
141
142 //-----------------------------------------------------------------------------
GetAxis(int)143 vtkAxis* vtkChart::GetAxis(int)
144 {
145 return nullptr;
146 }
147
148 //-----------------------------------------------------------------------------
SetAxis(int,vtkAxis *)149 void vtkChart::SetAxis(int, vtkAxis*)
150 {
151 }
152
153 //-----------------------------------------------------------------------------
GetNumberOfAxes()154 vtkIdType vtkChart::GetNumberOfAxes()
155 {
156 return 0;
157 }
158
159 //-----------------------------------------------------------------------------
RecalculateBounds()160 void vtkChart::RecalculateBounds()
161 {
162 }
163
164 //-----------------------------------------------------------------------------
SetSelectionMethod(int method)165 void vtkChart::SetSelectionMethod(int method)
166 {
167 if (method == this->SelectionMethod)
168 {
169 return;
170 }
171 this->SelectionMethod = method;
172 this->Modified();
173 }
174
175 //-----------------------------------------------------------------------------
GetSelectionMethod()176 int vtkChart::GetSelectionMethod()
177 {
178 return this->SelectionMethod;
179 }
180
181 //-----------------------------------------------------------------------------
SetShowLegend(bool visible)182 void vtkChart::SetShowLegend(bool visible)
183 {
184 if (this->ShowLegend != visible)
185 {
186 this->ShowLegend = visible;
187 this->Modified();
188 }
189 }
190
191 //-----------------------------------------------------------------------------
GetShowLegend()192 bool vtkChart::GetShowLegend()
193 {
194 return this->ShowLegend;
195 }
196
GetLegend()197 vtkChartLegend * vtkChart::GetLegend()
198 {
199 return nullptr;
200 }
201
202 //-----------------------------------------------------------------------------
SetTitle(const vtkStdString & title)203 void vtkChart::SetTitle(const vtkStdString &title)
204 {
205 if (this->Title != title)
206 {
207 this->Title = title;
208 this->Modified();
209 }
210 }
211
212 //-----------------------------------------------------------------------------
GetTitle()213 vtkStdString vtkChart::GetTitle()
214 {
215 return this->Title;
216 }
217
218 //-----------------------------------------------------------------------------
CalculatePlotTransform(vtkAxis * x,vtkAxis * y,vtkTransform2D * transform)219 bool vtkChart::CalculatePlotTransform(vtkAxis *x, vtkAxis *y,
220 vtkTransform2D *transform)
221 {
222 if (!x || !y || !transform)
223 {
224 vtkWarningMacro("Called with null arguments.");
225 return false;
226 }
227
228 vtkVector2d origin(x->GetMinimum(), y->GetMinimum());
229 vtkVector2d scale(x->GetMaximum() - x->GetMinimum(),
230 y->GetMaximum() - y->GetMinimum());
231 vtkVector2d shift(0.0, 0.0);
232 vtkVector2d factor(1.0, 1.0);
233
234 for (int i = 0; i < 2; ++i)
235 {
236 if (fabs(log10(origin[i] / scale[i])) > 2)
237 {
238 shift[i] = floor(log10(origin[i] / scale[i]) / 3.0) * 3.0;
239 shift[i] = -origin[i];
240 }
241 if (fabs(log10(scale[i])) > 10)
242 {
243 // We need to scale the transform to show all data, do this in blocks.
244 factor[i] = pow(10.0, floor(log10(scale[i]) / 10.0) * -10.0);
245 scale[i] = scale[i] * factor[i];
246 }
247 }
248 x->SetScalingFactor(factor[0]);
249 x->SetShift(shift[0]);
250 y->SetScalingFactor(factor[1]);
251 y->SetShift(shift[1]);
252
253 // Get the scale for the plot area from the x and y axes
254 float *min = x->GetPoint1();
255 float *max = x->GetPoint2();
256 if (fabs(max[0] - min[0]) == 0.0)
257 {
258 return false;
259 }
260 float xScale = scale[0] / (max[0] - min[0]);
261
262 // Now the y axis
263 min = y->GetPoint1();
264 max = y->GetPoint2();
265 if (fabs(max[1] - min[1]) == 0.0)
266 {
267 return false;
268 }
269 float yScale = scale[1] / (max[1] - min[1]);
270
271 transform->Identity();
272 transform->Translate(this->Point1[0], this->Point1[1]);
273 // Get the scale for the plot area from the x and y axes
274 transform->Scale(1.0 / xScale, 1.0 / yScale);
275 transform->Translate(-(x->GetMinimum() + shift[0]) * factor[0],
276 -(y->GetMinimum() + shift[1]) * factor[1]);
277 return true;
278 }
279
280 //-----------------------------------------------------------------------------
CalculateUnscaledPlotTransform(vtkAxis * x,vtkAxis * y,vtkTransform2D * transform)281 bool vtkChart::CalculateUnscaledPlotTransform(vtkAxis *x, vtkAxis *y,
282 vtkTransform2D *transform)
283 {
284 if (!x || !y || !transform)
285 {
286 vtkWarningMacro("Called with null arguments.");
287 return false;
288 }
289
290 vtkVector2d scale(x->GetMaximum() - x->GetMinimum(),
291 y->GetMaximum() - y->GetMinimum());
292
293 // Get the scale for the plot area from the x and y axes
294 float *min = x->GetPoint1();
295 float *max = x->GetPoint2();
296 if (fabs(max[0] - min[0]) == 0.0)
297 {
298 return false;
299 }
300 double xScale = scale[0] / (max[0] - min[0]);
301
302 // Now the y axis
303 min = y->GetPoint1();
304 max = y->GetPoint2();
305 if (fabs(max[1] - min[1]) == 0.0)
306 {
307 return false;
308 }
309 double yScale = scale[1] / (max[1] - min[1]);
310
311 transform->Identity();
312 transform->Translate(this->Point1[0], this->Point1[1]);
313 // Get the scale for the plot area from the x and y axes
314 transform->Scale(1.0 / xScale, 1.0 / yScale);
315 transform->Translate(-x->GetMinimum(), -y->GetMinimum());
316 return true;
317 }
318
319 //-----------------------------------------------------------------------------
SetBottomBorder(int border)320 void vtkChart::SetBottomBorder(int border)
321 {
322 this->Point1[1] = border >= 0 ? border : 0;
323 this->Point1[1] += static_cast<int>(this->Size.GetY());
324 }
325
326 //-----------------------------------------------------------------------------
SetTopBorder(int border)327 void vtkChart::SetTopBorder(int border)
328 {
329 this->Point2[1] = border >=0 ?
330 this->Geometry[1] - border :
331 this->Geometry[1];
332 this->Point2[1] += static_cast<int>(this->Size.GetY());
333 }
334
335 //-----------------------------------------------------------------------------
SetLeftBorder(int border)336 void vtkChart::SetLeftBorder(int border)
337 {
338 this->Point1[0] = border >= 0 ? border : 0;
339 this->Point1[0] += static_cast<int>(this->Size.GetX());
340 }
341
342 //-----------------------------------------------------------------------------
SetRightBorder(int border)343 void vtkChart::SetRightBorder(int border)
344 {
345 this->Point2[0] = border >=0 ?
346 this->Geometry[0] - border :
347 this->Geometry[0];
348 this->Point2[0] += static_cast<int>(this->Size.GetX());
349 }
350
351 //-----------------------------------------------------------------------------
SetBorders(int left,int bottom,int right,int top)352 void vtkChart::SetBorders(int left, int bottom, int right, int top)
353 {
354 this->SetLeftBorder(left);
355 this->SetRightBorder(right);
356 this->SetTopBorder(top);
357 this->SetBottomBorder(bottom);
358 }
359
SetSize(const vtkRectf & rect)360 void vtkChart::SetSize(const vtkRectf &rect)
361 {
362 this->Size = rect;
363 this->Geometry[0] = static_cast<int>(rect.GetWidth());
364 this->Geometry[1] = static_cast<int>(rect.GetHeight());
365 }
366
GetSize()367 vtkRectf vtkChart::GetSize()
368 {
369 return this->Size;
370 }
371
SetActionToButton(int action,int button)372 void vtkChart::SetActionToButton(int action, int button)
373 {
374 if (action < -1 || action >= MouseActions::MaxAction)
375 {
376 vtkErrorMacro("Error, invalid action value supplied: " << action)
377 return;
378 }
379 this->Actions[action] = button;
380 for (int i = 0; i < MouseActions::MaxAction; ++i)
381 {
382 if (this->Actions[i] == button && i != action)
383 {
384 this->Actions[i] = -1;
385 }
386 }
387 }
388
GetActionToButton(int action)389 int vtkChart::GetActionToButton(int action)
390 {
391 return this->Actions[action];
392 }
393
SetClickActionToButton(int action,int button)394 void vtkChart::SetClickActionToButton(int action, int button)
395 {
396 if (action != vtkChart::SELECT && action != vtkChart::NOTIFY)
397 {
398 vtkErrorMacro("Error, invalid click action value supplied: " << action)
399 return;
400 }
401
402 if (action == vtkChart::NOTIFY)
403 {
404 this->ActionsClick[0] = button;
405 }
406 else if (action == vtkChart::SELECT)
407 {
408 this->ActionsClick[1] = button;
409 }
410 }
411
GetClickActionToButton(int action)412 int vtkChart::GetClickActionToButton(int action)
413 {
414 if (action == vtkChart::NOTIFY)
415 {
416 return this->ActionsClick[0];
417 }
418 else if (action == vtkChart::SELECT)
419 {
420 return this->ActionsClick[1];
421 }
422
423 return -1;
424 }
425
426 //-----------------------------------------------------------------------------
SetBackgroundBrush(vtkBrush * brush)427 void vtkChart::SetBackgroundBrush(vtkBrush *brush)
428 {
429 if(brush == nullptr)
430 {
431 // set to transparent white if brush is null
432 this->BackgroundBrush->SetColorF(1, 1, 1, 0);
433 }
434 else
435 {
436 this->BackgroundBrush = brush;
437 }
438
439 this->Modified();
440 }
441
442 //-----------------------------------------------------------------------------
GetBackgroundBrush()443 vtkBrush* vtkChart::GetBackgroundBrush()
444 {
445 return this->BackgroundBrush;
446 }
447
448 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)449 void vtkChart::PrintSelf(ostream &os, vtkIndent indent)
450 {
451 this->Superclass::PrintSelf(os, indent);
452 // Print out the chart's geometry if it has been set
453 os << indent << "Point1: " << this->Point1[0] << "\t" << this->Point1[1]
454 << endl;
455 os << indent << "Point2: " << this->Point2[0] << "\t" << this->Point2[1]
456 << endl;
457 os << indent << "Width: " << this->Geometry[0] << endl
458 << indent << "Height: " << this->Geometry[1] << endl;
459 os << indent << "SelectionMode: " << this->SelectionMode << endl;
460 }
461 //-----------------------------------------------------------------------------
AttachAxisRangeListener(vtkAxis * axis)462 void vtkChart::AttachAxisRangeListener(vtkAxis* axis)
463 {
464 axis->AddObserver(vtkChart::UpdateRange, this, &vtkChart::AxisRangeForwarderCallback);
465 }
466
467 //-----------------------------------------------------------------------------
AxisRangeForwarderCallback(vtkObject *,unsigned long,void *)468 void vtkChart::AxisRangeForwarderCallback(vtkObject*, unsigned long, void*)
469 {
470 double fullAxisRange[8];
471 for(int i=0; i < 4; i++)
472 {
473 this->GetAxis(i)->GetRange(&fullAxisRange[i*2]);
474 }
475 this->InvokeEvent(vtkChart::UpdateRange, fullAxisRange);
476 }
477
478 //-----------------------------------------------------------------------------
SetSelectionMode(int selMode)479 void vtkChart::SetSelectionMode(int selMode)
480 {
481 if (this->SelectionMode == selMode ||
482 selMode < vtkContextScene::SELECTION_NONE ||
483 selMode > vtkContextScene::SELECTION_TOGGLE)
484 {
485 return;
486 }
487 this->SelectionMode = selMode;
488 this->Modified();
489 }
490