1 /*=========================================================================
2
3 Program: Visualization Toolkit
4 Module: vtkPlotPie.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 "vtkPlotPie.h"
17
18 #include "vtkContext2D.h"
19 #include "vtkPen.h"
20 #include "vtkBrush.h"
21 #include "vtkColorSeries.h"
22 #include "vtkPoints2D.h"
23 #include "vtkContextMapper2D.h"
24 #include "vtkTable.h"
25 #include "vtkMath.h"
26 #include "vtkRect.h"
27
28 #include "vtkObjectFactory.h"
29
30 #include <algorithm>
31
32 namespace {
33
34 template<class A>
SumData(A * a,int n)35 A SumData(A *a, int n)
36 {
37 A sum = 0;
38 for (int i = 0; i < n; ++i)
39 {
40 sum += a[i];
41 }
42 return sum;
43 }
44
45 template<class A>
CopyToPoints(vtkPoints2D * points,A * a,int n)46 void CopyToPoints(vtkPoints2D *points, A *a, int n)
47 {
48 points->SetNumberOfPoints(n);
49
50 A sum = SumData(a,n);
51 float* data = static_cast<float*>(points->GetVoidPointer(0));
52 float startAngle = 0.0;
53
54 for (int i = 0; i < n; ++i)
55 {
56 data[2*i] = startAngle;
57 data[2*i+1] = startAngle + ((static_cast<float>(a[i]) / sum) * 360.0);
58 startAngle = data[2*i+1];
59 }
60 }
61 }
62
63 class vtkPlotPiePrivate
64 {
65 public:
vtkPlotPiePrivate()66 vtkPlotPiePrivate()
67 {
68 this->CenterX = 0;
69 this->CenterY = 0;
70 this->Radius = 0;
71 }
72
73 float CenterX;
74 float CenterY;
75 float Radius;
76 };
77
78 //-----------------------------------------------------------------------------
79 vtkStandardNewMacro(vtkPlotPie);
80
81 //-----------------------------------------------------------------------------
vtkPlotPie()82 vtkPlotPie::vtkPlotPie()
83 {
84 this->ColorSeries = vtkSmartPointer<vtkColorSeries>::New();
85 this->Points = 0;
86 this->Private = new vtkPlotPiePrivate();
87 this->Dimensions[0] = this->Dimensions[1] = this->Dimensions[2] =
88 this->Dimensions[3] = 0;
89 }
90
91 //-----------------------------------------------------------------------------
~vtkPlotPie()92 vtkPlotPie::~vtkPlotPie()
93 {
94 delete this->Private;
95 if (this->Points)
96 {
97 this->Points->Delete();
98 this->Points = 0;
99 }
100 this->Private = 0;
101 }
102
103 //-----------------------------------------------------------------------------
Paint(vtkContext2D * painter)104 bool vtkPlotPie::Paint(vtkContext2D *painter)
105 {
106 if (!this->Visible)
107 {
108 return false;
109 }
110
111 // First check if we have an input
112 vtkTable *table = this->Data->GetInput();
113 if (!table)
114 {
115 vtkDebugMacro(<< "Paint event called with no input table set.");
116 return false;
117 }
118 else if(this->Data->GetMTime() > this->BuildTime ||
119 table->GetMTime() > this->BuildTime ||
120 this->MTime > this->BuildTime)
121 {
122 vtkDebugMacro(<< "Paint event called with outdated table cache. Updating.");
123 this->UpdateTableCache(table);
124 }
125
126 float* data = static_cast<float*>(this->Points->GetVoidPointer(0));
127
128 for (int i = 0; i < this->Points->GetNumberOfPoints(); ++i)
129 {
130 painter->GetBrush()
131 ->SetColor(this->ColorSeries->GetColorRepeating(i).GetData());
132
133 painter->DrawEllipseWedge(this->Private->CenterX, this->Private->CenterY,
134 this->Private->Radius, this->Private->Radius,
135 0.0, 0.0,
136 data[2*i], data[2*i+1]
137 );
138 }
139
140 this->PaintChildren(painter);
141 return true;
142 }
143
144 //-----------------------------------------------------------------------------
145
PaintLegend(vtkContext2D * painter,const vtkRectf & rect,int legendIndex)146 bool vtkPlotPie::PaintLegend(vtkContext2D *painter, const vtkRectf& rect,
147 int legendIndex)
148 {
149 if (this->ColorSeries)
150 this->Brush
151 ->SetColor(this->ColorSeries->GetColorRepeating(legendIndex).GetData());
152
153 painter->ApplyPen(this->Pen);
154 painter->ApplyBrush(this->Brush);
155 painter->DrawRect(rect[0], rect[1], rect[2], rect[3]);
156 return true;
157 }
158
159 //-----------------------------------------------------------------------------
160
SetDimensions(int arg1,int arg2,int arg3,int arg4)161 void vtkPlotPie::SetDimensions(int arg1, int arg2, int arg3, int arg4)
162 {
163 if (arg1 != this->Dimensions[0] || arg2 != this->Dimensions[1] ||
164 arg3 != this->Dimensions[2] || arg4 != this->Dimensions[3])
165 {
166 this->Dimensions[0] = arg1;
167 this->Dimensions[1] = arg2;
168 this->Dimensions[2] = arg3;
169 this->Dimensions[3] = arg4;
170
171 this->Private->CenterX = this->Dimensions[0] + 0.5 * this->Dimensions[2];
172 this->Private->CenterY = this->Dimensions[1] + 0.5 * this->Dimensions[3];
173 this->Private->Radius = this->Dimensions[2] < this->Dimensions[3]
174 ? 0.5 * this->Dimensions[2] : 0.5 * this->Dimensions[3];
175 this->Modified();
176 }
177 }
178
SetDimensions(int arg[4])179 void vtkPlotPie::SetDimensions(int arg[4])
180 {
181 this->SetDimensions(arg[0],arg[1],arg[2],arg[3]);
182 }
183
184
185 //-----------------------------------------------------------------------------
SetColorSeries(vtkColorSeries * colorSeries)186 void vtkPlotPie::SetColorSeries(vtkColorSeries *colorSeries)
187 {
188 if (this->ColorSeries == colorSeries)
189 {
190 return;
191 }
192 this->ColorSeries = colorSeries;
193 this->Modified();
194 }
195
196 //-----------------------------------------------------------------------------
GetColorSeries()197 vtkColorSeries *vtkPlotPie::GetColorSeries()
198 {
199 return this->ColorSeries;
200 }
201
202 //-----------------------------------------------------------------------------
GetNearestPoint(const vtkVector2f & point,const vtkVector2f &,vtkVector2f * value)203 vtkIdType vtkPlotPie::GetNearestPoint(const vtkVector2f& point,
204 const vtkVector2f&,
205 vtkVector2f* value)
206 {
207 float x = point.GetX() - this->Private->CenterX;
208 float y = point.GetY() - this->Private->CenterY;
209
210 if (sqrt((x*x) + (y*y)) <= this->Private->Radius)
211 {
212 float *angles = static_cast<float *>(this->Points->GetVoidPointer(0));
213 float pointAngle = vtkMath::DegreesFromRadians(atan2(y,x));
214 if (pointAngle < 0)
215 {
216 pointAngle = 180.0 + (180.0 + pointAngle);
217 }
218 float *lbound = std::lower_bound(angles,
219 angles + (this->Points->GetNumberOfPoints() * 2),
220 pointAngle);
221 // Location in the array
222 int ret = lbound - angles;
223 // There are two of each angle in the array (start,end for each point)
224 ret = ret / 2;
225
226 vtkTable *table = this->Data->GetInput();
227 vtkDataArray* data = this->Data->GetInputArrayToProcess(0, table);
228 value->SetX(ret);
229 value->SetY(data->GetTuple1(ret));
230 return ret;
231 }
232
233 return -1;
234 }
235
236 //-----------------------------------------------------------------------------
PrintSelf(ostream & os,vtkIndent indent)237 void vtkPlotPie::PrintSelf(ostream &os, vtkIndent indent)
238 {
239 this->Superclass::PrintSelf(os, indent);
240 }
241
242 //-----------------------------------------------------------------------------
UpdateTableCache(vtkTable * table)243 bool vtkPlotPie::UpdateTableCache(vtkTable *table)
244 {
245 // Get the x and y arrays (index 0 and 1 respectively)
246 vtkDataArray* data = this->Data->GetInputArrayToProcess(0, table);
247
248 if (!data)
249 {
250 vtkErrorMacro(<< "No data set (index 0).");
251 return false;
252 }
253
254 if (!this->Points)
255 {
256 this->Points = vtkPoints2D::New();
257 }
258
259
260 switch (data->GetDataType())
261 {
262 vtkTemplateMacro(
263 CopyToPoints(this->Points,
264 static_cast<VTK_TT*>(data->GetVoidPointer(0)),
265 data->GetNumberOfTuples()));
266 }
267
268 this->BuildTime.Modified();
269 return true;
270 }
271