Skip to content

Commit d448f5c

Browse files
authored
halfhp#55 Fixes PieRenderer.getContainingSegment for segments larger than 50% of the pie. (halfhp#57)
1 parent e6ac20a commit d448f5c

2 files changed

Lines changed: 63 additions & 16 deletions

File tree

androidplot-core/src/main/java/com/androidplot/pie/PieRenderer.java

Lines changed: 23 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@
3030
*/
3131
public class PieRenderer extends SeriesRenderer<PieChart, Segment, SegmentFormatter> {
3232

33+
private static final float FULL_PIE_DEGS = 360f;
34+
private static final float HALF_PIE_DEGS = 180f;
35+
3336
// starting angle to use when drawing the first radial line of the first segment.
3437
private float startDegs = 0;
3538

3639
// number of degrees to extend from startDegs; can be used to "shape" the pie chart.
37-
private float extentDegs = 360;
40+
private float extentDegs = FULL_PIE_DEGS;
3841

3942
// TODO: express donut in units other than px.
4043
private float donutSize = 0.5f;
@@ -240,7 +243,7 @@ protected PointF calculateLineEnd(float x, float y, float rad, float deg) {
240243

241244
protected PointF calculateLineEnd(PointF origin, float rad, float deg) {
242245

243-
double radians = deg * Math.PI / 180F;
246+
double radians = deg * Math.PI / HALF_PIE_DEGS;
244247
double x = rad * Math.cos(radians);
245248
double y = rad * Math.sin(radians);
246249

@@ -292,11 +295,10 @@ public Segment getContainingSegment(PointF point) {
292295
float dx = point.x - origin.x;
293296
float dy = point.y - origin.y;
294297
double theta = Math.atan2(dy, dx);
295-
double angle = (theta * (180f / Math.PI));
298+
double angle = (theta * (HALF_PIE_DEGS / Math.PI));
296299
if (angle < 0) {
297-
// convert angle to 0-360 range with 0 being in the
298-
// traditional "east" orientation:
299-
angle += 360f;
300+
// bring into 0-360 range
301+
angle += FULL_PIE_DEGS;
300302
}
301303

302304
// find the segment whose starting and ending angle (degs) contains
@@ -310,10 +312,16 @@ public Segment getContainingSegment(PointF point) {
310312
float lastOffset = offset;
311313
float sweep = (float) (scale * (values[i]) * extentDegs);
312314
offset += sweep;
313-
offset = offset % 360;
315+
offset = offset % FULL_PIE_DEGS;
314316

315317
final double dist = signedDistance(offset, angle);
316-
if(dist > 0 && dist <= signedDistance(offset, lastOffset)) {
318+
double endDist = signedDistance(offset, lastOffset);
319+
if(endDist < 0) {
320+
// segment accounts for more than 50% of the pie and wrapped around
321+
// need to correct:
322+
endDist = FULL_PIE_DEGS + endDist;
323+
}
324+
if(dist > 0 && dist <= endDist) {
317325
return sfPair.getSeries();
318326
}
319327
i++;
@@ -328,10 +336,10 @@ public Segment getContainingSegment(PointF point) {
328336
* @return
329337
*/
330338
protected static float degsToScreenDegs(float degs) {
331-
degs = degs % 360;
339+
degs = degs % FULL_PIE_DEGS;
332340

333341
if (degs > 0) {
334-
return 360 - degs;
342+
return FULL_PIE_DEGS - degs;
335343
} else {
336344
return degs;
337345
}
@@ -344,12 +352,12 @@ protected static float degsToScreenDegs(float degs) {
344352
* @return
345353
*/
346354
protected static double signedDistance(double angle1, double angle2) {
347-
double d = Math.abs(angle1 - angle2) % 360;
348-
double r = d > 180 ? 360 - d : d;
355+
double d = Math.abs(angle1 - angle2) % FULL_PIE_DEGS;
356+
double r = d > HALF_PIE_DEGS ? FULL_PIE_DEGS - d : d;
349357

350358
//calculate sign
351-
int sign = (angle1 - angle2 >= 0 && angle1 - angle2 <= 180)
352-
|| (angle1 - angle2 <= -180 && angle1 - angle2 >= -360) ? 1 : -1;
359+
int sign = (angle1 - angle2 >= 0 && angle1 - angle2 <= HALF_PIE_DEGS)
360+
|| (angle1 - angle2 <= -HALF_PIE_DEGS && angle1 - angle2 >= -FULL_PIE_DEGS) ? 1 : -1;
353361
r *= sign;
354362
return r;
355363
}
@@ -359,7 +367,7 @@ protected static double signedDistance(double angle1, double angle2) {
359367
* @param degs
360368
*/
361369
protected static void validateInputDegs(float degs) {
362-
if(degs < 0 || degs > 360) {
370+
if(degs < 0 || degs > FULL_PIE_DEGS) {
363371
throw new IllegalArgumentException("Degrees values must be between 0.0 and 360.");
364372
}
365373
}

androidplot-core/src/test/java/com/androidplot/pie/PieRendererTest.java

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public void testOnRender() throws Exception {
110110
}
111111

112112
@Test
113-
public void testGetContainingSegment() throws Exception {
113+
public void getContainingSegment_returnsCorrectSegment() throws Exception {
114114
Segment segment1 = spy(new Segment("s1", 25));
115115
Segment segment2 = spy(new Segment("s2", 25));
116116
Segment segment3 = spy(new Segment("s3", 25));
@@ -150,6 +150,45 @@ public void testGetContainingSegment() throws Exception {
150150
assertEquals(segment1, renderer.getContainingSegment(new PointF(100, 0)));
151151
}
152152

153+
@Test
154+
public void getContainingSegment_handlesSegmentsLargerThanHalfPie() throws Exception {
155+
Segment segment1 = spy(new Segment("s1", 25));
156+
Segment segment2 = spy(new Segment("s2", 24));
157+
Segment segment3 = spy(new Segment("s3", 51));
158+
SegmentFormatter formatter = spy(
159+
new SegmentFormatter(Color.GREEN, Color.GREEN, Color.GREEN, Color.GREEN));
160+
PieRenderer renderer = formatter.getRendererInstance(pieChart);
161+
162+
pieChart.addSegment(segment1, formatter);
163+
pieChart.addSegment(segment2, formatter);
164+
pieChart.addSegment(segment3, formatter);
165+
166+
// southeast
167+
assertEquals(segment1, renderer.getContainingSegment(new PointF(100, 100)));
168+
169+
// southwest
170+
assertEquals(segment2, renderer.getContainingSegment(new PointF(0, 100)));
171+
172+
// northwest
173+
assertEquals(segment3, renderer.getContainingSegment(new PointF(0, 0)));
174+
175+
// northeast
176+
assertEquals(segment3, renderer.getContainingSegment(new PointF(100, 0)));
177+
178+
renderer.setStartDegs(90);
179+
// southeast
180+
assertEquals(segment2, renderer.getContainingSegment(new PointF(100, 100)));
181+
182+
// southwest
183+
assertEquals(segment3, renderer.getContainingSegment(new PointF(0, 100)));
184+
185+
// northwest
186+
assertEquals(segment3, renderer.getContainingSegment(new PointF(0, 0)));
187+
188+
// northeast
189+
assertEquals(segment1, renderer.getContainingSegment(new PointF(100, 0)));
190+
}
191+
153192
@Test
154193
public void testDegsToScreenDegs() throws Exception {
155194
assertEquals(0f, PieRenderer.degsToScreenDegs(0));

0 commit comments

Comments
 (0)