2
$\begingroup$

Let's say I have to draw a pie chart with X slices. That's pretty simple - calculating the point on the arc for the first angle, drawing a line to the other point on the arc, then to the center - and filling the whole thing with color.

Now it gets complicated when I want to add fixed spacing between slices. There are two situations here:

  1. Pie chart has a hole inside - in which case I calculate the angle for the spacing on the outer circle and on the inner circle. Using a formula like this spacing / (PI / 180 * R). This works great.

  2. No hole inside - so they go until the center of the circle. Now I need to shift the tip of the slice a few pixels outside, to make sure that the spacing stays even. This is where I'm having trouble.

The only things that I can say for sure are:

  • The distance of the tip from the center grows as the slice gets smaller.
  • For a full pie (360 circle) the distance is 0...
  • For a 50/50 pie the distance is half the spacing size.

Some screenshots:

  • This is the simple case: (which we do not have trouble with, because there's a fixed shift - and we just need to calculate angles)

Simple case

  • This is what we want to achieve:

Complicated case

  • This is what we want to avoid:

Avoid this

This is usually done with stroking the path being drawn - but is problematic for two reasons: 1. The stroke must be solid in order to erase the pie-slice's edges and emulate the background color 2. When the slice is too small and the stroke is to wide - it overflows into the other side and covers parts of other slices.

Any ideas?

Edit:

So I took the problem apart, and I noticed that: It seems that after taking out the spacing (half from each side of the slice) - the angle stays the same.
So then I calculated the distance between two points of the slice on the arc, and use that as one side of a triangle and calculate the height of a triangle for the slice angle.

Then I took the full radius, subtracted the triangle height from it, and then subtracted the height of the arc leftover (since the triangle is contained in the arc and the arc goes over its base, there's a leftover, which is basically the distance from the midpoint on the arc and the midpoint on the triangle base).

My implementation looks like this:

$midpoint = \frac{X_1 + X_2}{2}, \frac{Y_1 + Y_2}{2}$
$distance = \sqrt{ {(X_1 - X_2)}^2 + {(Y_1 - Y_2)}^2 }$
$arcpoint = Cx + R + cos(\alpha), Cy + R + sin(\alpha)$

$spacingAngle = spacing / R$

$arcPt1 = arcpoint(startAngle + spacingAngle / 2)$
$arcPt2 = arcpoint(startAngle + \alpha - spacingAngle)$
$arcMid = arcpoint(startAngle + \alpha / 2)$
$triHeight = (distance(arcPt1, arcPt2) / 2 * tan((180 - \alpha) / 2))$
$D = radius - triHeight - distance(arcMid, midPoint(arcPt1, arcPt2))$

The problem is - this only works for the small angles! If I have a slice which is 300 degrees, it does not fit into the isosceles triangle model.

Edit: For angles more than 180 - I just take the ABS value of the result. It works!

$\endgroup$
0
$\begingroup$

So I took the problem apart, and I noticed that: It seems that after taking out the spacing (half from each side of the slice) - the angle stays the same.
So then I calculated the distance between two points of the slice on the arc, and use that as one side of a triangle and calculate the height of a triangle for the slice angle.

Then I took the full radius, subtracted the triangle height from it, and then subtracted the height of the arc leftover (since the triangle is contained in the arc and the arc goes over its base, there's a leftover, which is basically the distance from the midpoint on the arc and the midpoint on the triangle base).

My implementation looks like this:

$midpoint = \frac{X_1 + X_2}{2}, \frac{Y_1 + Y_2}{2}$
$distance = \sqrt{ {(X_1 - X_2)}^2 + {(Y_1 - Y_2)}^2 }$
$arcpoint = Cx + R + cos(\alpha), Cy + R + sin(\alpha)$

$spacingAngle = spacing / R$

$arcPt1 = arcpoint(startAngle + spacingAngle / 2)$
$arcPt2 = arcpoint(startAngle + \alpha - spacingAngle)$
$arcMid = arcpoint(startAngle + \alpha / 2)$
$triHeight = (distance(arcPt1, arcPt2) / 2 * tan((180 - \alpha) / 2))$
$D = radius - triHeight - distance(arcMid, midPoint(arcPt1, arcPt2))$

If anyone has a "shorter" way of achieving the same result, I'll be happy to hear :-)

Update: I had trouble with handling slices which have angles bigger than 180 degrees. Apparently all I had to do was take the ABS value of the result - and the values is still correct!

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.