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