create changelog entry
[debian/openrocket] / android-libraries / achartengine / src / org / achartengine / chart / DialChart.java
1 /**\r
2  * Copyright (C) 2009 - 2012 SC 4ViewSoft SRL\r
3  *  \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *  \r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *  \r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 package org.achartengine.chart;\r
17 \r
18 import org.achartengine.model.CategorySeries;\r
19 import org.achartengine.renderer.DefaultRenderer;\r
20 import org.achartengine.renderer.DialRenderer;\r
21 import org.achartengine.renderer.DialRenderer.Type;\r
22 import org.achartengine.util.MathHelper;\r
23 \r
24 import android.graphics.Canvas;\r
25 import android.graphics.Paint;\r
26 import android.graphics.Paint.Align;\r
27 import android.graphics.Paint.Style;\r
28 \r
29 /**\r
30  * The dial chart rendering class.\r
31  */\r
32 public class DialChart extends RoundChart {\r
33   /** The radius of the needle. */\r
34   private static final int NEEDLE_RADIUS = 10;\r
35   /** The series renderer. */\r
36   private DialRenderer mRenderer;\r
37 \r
38   /**\r
39    * Builds a new dial chart instance.\r
40    * \r
41    * @param dataset the series dataset\r
42    * @param renderer the dial renderer\r
43    */\r
44   public DialChart(CategorySeries dataset, DialRenderer renderer) {\r
45     super(dataset, renderer);\r
46     mRenderer = renderer;\r
47   }\r
48 \r
49   /**\r
50    * The graphical representation of the dial chart.\r
51    * \r
52    * @param canvas the canvas to paint to\r
53    * @param x the top left x value of the view to draw to\r
54    * @param y the top left y value of the view to draw to\r
55    * @param width the width of the view to draw to\r
56    * @param height the height of the view to draw to\r
57    * @param paint the paint\r
58    */\r
59   @Override\r
60   public void draw(Canvas canvas, int x, int y, int width, int height, Paint paint) {\r
61     paint.setAntiAlias(mRenderer.isAntialiasing());\r
62     paint.setStyle(Style.FILL);\r
63     paint.setTextSize(mRenderer.getLabelsTextSize());\r
64     int legendSize = getLegendSize(mRenderer, height / 5, 0);\r
65     int left = x;\r
66     int top = y;\r
67     int right = x + width;\r
68 \r
69     int sLength = mDataset.getItemCount();\r
70     String[] titles = new String[sLength];\r
71     for (int i = 0; i < sLength; i++) {\r
72       titles[i] = mDataset.getCategory(i);\r
73     }\r
74 \r
75     if (mRenderer.isFitLegend()) {\r
76       legendSize = drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize,\r
77           paint, true);\r
78     }\r
79     int bottom = y + height - legendSize;\r
80     drawBackground(mRenderer, canvas, x, y, width, height, paint, false, DefaultRenderer.NO_COLOR);\r
81 \r
82     int mRadius = Math.min(Math.abs(right - left), Math.abs(bottom - top));\r
83     int radius = (int) (mRadius * 0.35 * mRenderer.getScale());\r
84     if (mCenterX == NO_VALUE) {\r
85       mCenterX = (left + right) / 2;\r
86     }\r
87     if (mCenterY == NO_VALUE) {\r
88       mCenterY = (bottom + top) / 2;\r
89     }\r
90     float shortRadius = radius * 0.9f;\r
91     float longRadius = radius * 1.1f;\r
92     double min = mRenderer.getMinValue();\r
93     double max = mRenderer.getMaxValue();\r
94     double angleMin = mRenderer.getAngleMin();\r
95     double angleMax = mRenderer.getAngleMax();\r
96     if (!mRenderer.isMinValueSet() || !mRenderer.isMaxValueSet()) {\r
97       int count = mRenderer.getSeriesRendererCount();\r
98       for (int i = 0; i < count; i++) {\r
99         double value = mDataset.getValue(i);\r
100         if (!mRenderer.isMinValueSet()) {\r
101           min = Math.min(min, value);\r
102         }\r
103         if (!mRenderer.isMaxValueSet()) {\r
104           max = Math.max(max, value);\r
105         }\r
106       }\r
107     }\r
108     if (min == max) {\r
109       min = min * 0.5;\r
110       max = max * 1.5;\r
111     }\r
112 \r
113     paint.setColor(mRenderer.getLabelsColor());\r
114     double minorTicks = mRenderer.getMinorTicksSpacing();\r
115     double majorTicks = mRenderer.getMajorTicksSpacing();\r
116     if (minorTicks == MathHelper.NULL_VALUE) {\r
117       minorTicks = (max - min) / 30;\r
118     }\r
119     if (majorTicks == MathHelper.NULL_VALUE) {\r
120       majorTicks = (max - min) / 10;\r
121     }\r
122     drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, radius,\r
123         minorTicks, paint, false);\r
124     drawTicks(canvas, min, max, angleMin, angleMax, mCenterX, mCenterY, longRadius, shortRadius,\r
125         majorTicks, paint, true);\r
126 \r
127     int count = mRenderer.getSeriesRendererCount();\r
128     for (int i = 0; i < count; i++) {\r
129       double angle = getAngleForValue(mDataset.getValue(i), angleMin, angleMax, min, max);\r
130       paint.setColor(mRenderer.getSeriesRendererAt(i).getColor());\r
131       boolean type = mRenderer.getVisualTypeForIndex(i) == Type.ARROW;\r
132       drawNeedle(canvas, angle, mCenterX, mCenterY, shortRadius, type, paint);\r
133     }\r
134     drawLegend(canvas, mRenderer, titles, left, right, y, width, height, legendSize, paint, false);\r
135     drawTitle(canvas, x, y, width, paint);\r
136   }\r
137 \r
138   /**\r
139    * Returns the angle for a specific chart value.\r
140    * \r
141    * @param value the chart value\r
142    * @param minAngle the minimum chart angle value\r
143    * @param maxAngle the maximum chart angle value\r
144    * @param min the minimum chart value\r
145    * @param max the maximum chart value\r
146    * @return the angle\r
147    */\r
148   private double getAngleForValue(double value, double minAngle, double maxAngle, double min,\r
149       double max) {\r
150     double angleDiff = maxAngle - minAngle;\r
151     double diff = max - min;\r
152     return Math.toRadians(minAngle + (value - min) * angleDiff / diff);\r
153   }\r
154 \r
155   /**\r
156    * Draws the chart tick lines.\r
157    * \r
158    * @param canvas the canvas\r
159    * @param min the minimum chart value\r
160    * @param max the maximum chart value\r
161    * @param minAngle the minimum chart angle value\r
162    * @param maxAngle the maximum chart angle value\r
163    * @param centerX the center x value\r
164    * @param centerY the center y value\r
165    * @param longRadius the long radius\r
166    * @param shortRadius the short radius\r
167    * @param ticks the tick spacing\r
168    * @param paint the paint settings\r
169    * @param labels paint the labels\r
170    * @return the angle\r
171    */\r
172   private void drawTicks(Canvas canvas, double min, double max, double minAngle, double maxAngle,\r
173       int centerX, int centerY, double longRadius, double shortRadius, double ticks, Paint paint,\r
174       boolean labels) {\r
175     for (double i = min; i <= max; i += ticks) {\r
176       double angle = getAngleForValue(i, minAngle, maxAngle, min, max);\r
177       double sinValue = Math.sin(angle);\r
178       double cosValue = Math.cos(angle);\r
179       int x1 = Math.round(centerX + (float) (shortRadius * sinValue));\r
180       int y1 = Math.round(centerY + (float) (shortRadius * cosValue));\r
181       int x2 = Math.round(centerX + (float) (longRadius * sinValue));\r
182       int y2 = Math.round(centerY + (float) (longRadius * cosValue));\r
183       canvas.drawLine(x1, y1, x2, y2, paint);\r
184       if (labels) {\r
185         paint.setTextAlign(Align.LEFT);\r
186         if (x1 <= x2) {\r
187           paint.setTextAlign(Align.RIGHT);\r
188         }\r
189         String text = i + "";\r
190         if (Math.round(i) == (long) i) {\r
191           text = (long) i + "";\r
192         }\r
193         canvas.drawText(text, x1, y1, paint);\r
194       }\r
195     }\r
196   }\r
197 \r
198   /**\r
199    * Returns the angle for a specific chart value.\r
200    * \r
201    * @param canvas the canvas\r
202    * @param angle the needle angle value\r
203    * @param centerX the center x value\r
204    * @param centerY the center y value\r
205    * @param radius the radius\r
206    * @param arrow if a needle or an arrow to be painted\r
207    * @param paint the paint settings\r
208    * @return the angle\r
209    */\r
210   private void drawNeedle(Canvas canvas, double angle, int centerX, int centerY, double radius,\r
211       boolean arrow, Paint paint) {\r
212     double diff = Math.toRadians(90);\r
213     int needleSinValue = (int) (NEEDLE_RADIUS * Math.sin(angle - diff));\r
214     int needleCosValue = (int) (NEEDLE_RADIUS * Math.cos(angle - diff));\r
215     int needleX = (int) (radius * Math.sin(angle));\r
216     int needleY = (int) (radius * Math.cos(angle));\r
217     int needleCenterX = centerX + needleX;\r
218     int needleCenterY = centerY + needleY;\r
219     float[] points;\r
220     if (arrow) {\r
221       int arrowBaseX = centerX + (int) (radius * 0.85 * Math.sin(angle));\r
222       int arrowBaseY = centerY + (int) (radius * 0.85 * Math.cos(angle));\r
223       points = new float[] { arrowBaseX - needleSinValue, arrowBaseY - needleCosValue,\r
224           needleCenterX, needleCenterY, arrowBaseX + needleSinValue, arrowBaseY + needleCosValue };\r
225       float width = paint.getStrokeWidth();\r
226       paint.setStrokeWidth(5);\r
227       canvas.drawLine(centerX, centerY, needleCenterX, needleCenterY, paint);\r
228       paint.setStrokeWidth(width);\r
229     } else {\r
230       points = new float[] { centerX - needleSinValue, centerY - needleCosValue, needleCenterX,\r
231           needleCenterY, centerX + needleSinValue, centerY + needleCosValue };\r
232     }\r
233     drawPath(canvas, points, paint, true);\r
234   }\r
235 \r
236 }\r