Android AddArc doesn't work as expected

I am having problems with the correct arc on Android. I suspect my math is failing here, but I've checked and rechecked and can't figure out the problem.

Consider the following:

Geometric rendering

Where:

  • R

    - bounding box for ellipse
  • O

    is the source of the ellipse
  • a

    - radius x of the ellipse
  • b

    - radius y of the ellipse
  • P1

    - the first point on the ellipse
  • P2

    - the second point on the ellipse

I want the arc to expand between P1 and P2, but as you can see, it starts early and ends late.

Once I have defined a bounding box for the ellipse (which is correct), I first draw some debug information:

// highlight each important point
path.AddCircle(P1.X, P1.Y, 3, Graphics.Path.Direction.Cw);
path.AddCircle(P2.X, P2.Y, 3, Graphics.Path.Direction.Cw);
path.AddCircle(O.X, O.Y, 3, Graphics.Path.Direction.Cw);

// draw bounding rectangle
path.AddRect(rect, Graphics.Path.Direction.Cw);

// draw in ellipse radii (a and b)
path.MoveTo(O.X, O.Y);
path.RLineTo(radius.Width, 0);
path.MoveTo(O.X, O.Y);
path.RLineTo(0, radius.Height);

      

In the specific example pictured above, these are the values ​​I'm working with (I'll round all the values ​​a little for clarity):

O = (644, 850.154)
P1 = (528.08, 1030.4)
P2 = (759.92, 1030.4)
R = (322, 656.954, 644, 386.4)

      

So far so good. Everything above is where it should be. Then I calculate the normalized vectors from O

to P1

and P2

:

var P1Vec = (P1 - O).Normalize();
var P2Vec = (P2 - O).Normalize();

      

They come out as:

P1Vec = (-0.541, 0.841)
P2Vec = (0.541, 0.841)

      

To be sure this was correct, I added some more debug graphs:

path.MoveTo(O.X, O.Y);
var end = startVec * 400;
path.RLineTo(end.X, end.Y);
path.MoveTo(O.X, O.Y);
end = endVec * 400;
path.RLineTo(end.X, end.Y);

      

As you can see from the image, these lines are cut exactly through P1

and P2

as expected.

So the next step is to figure out the angles, as the Android method suggests AddArc

:

var P1VecDot = Point.UnitX.Dot(P1Vec);
var P2VecDot = Point.UnitX.Dot(P2Vec);

var P1Acos = Math.Acos(P1VecDot);
var P2Acos = Math.Acos(P2VecDot);

var P1Angle = P1Acos.ToDegrees();
var P2Angle = P2Acos.ToDegrees();

      

The values ​​I get here:

P1VecDot = -0.541
P2VecDot = 0.541
P1Acos = 2.142
P2Acos = 0.999
P1Angle = 122.745
P2Angle = 57.254

      

The span between these angles is about 65 °, which seems correct. So, P1Angle

is our starting angle, so I only need to compute the sweep and then draw an arc:

var sweepAngle = P2Angle - P1Angle;
path.AddArc(R, startAngle, sweepAngle);

      

But the drawn arc doesn't look like this.

I'm sure it has to do with drawing an elliptical arc as opposed to a circular one, because if I make the arc circular, then everything works. I figured out that I needed to project points on an ellipse to equivalent points on a circle and use those points to calculate angles, but I haven't clicked on how to do that yet.

Any thoughts on how to fix it?

UPDATE . I figured out what's going on here, and this is completely undocumented behavior as far as I can tell. I'll strip my code over the weekend and post an answer (actually, might make a blog post on that).

+3


source to share





All Articles