Converting from polar coordinates to rectangular coordinates

Posted on

Problem

This is performance critical. I measured and determined that using the sqrt is faster then using the cos method.

I am aware that this code only works for some points, so that is not an issue.

Point is System.Drawing.Point. _offset is also of type Point.

I assumed, and the profiler seemed to confirm, that the try/catch will not slow down the code unless an exception occurs. Please correct me if that is wrong.

/// <summary>
/// Convert from polar coordinates to rectangular coordinates.
/// Only works for points to the left of the origin.
/// </summary>
/// <param name="radius">The radius of the point in pixels.</param>
/// <param name="theta">The angle of the point in radians.</param>
/// <returns>The point in rectangular coordinates.</returns>
internal Point PolarToRectangular(
        double radius,
        double theta)
{
    try
    {
        double sin = Math.Sin(theta);

        // This is faster then:
        // double cos = Math.Cos(theta);
        double cos = -Math.Sqrt(1 - (sin * sin));

        Int32 x = _offset.X + (Int32)Math.Round(radius * cos);
        Int32 y = _offset.Y + (Int32)Math.Round(radius * sin);

        return new Point(x, y);
    }
    catch (OverflowException ex)
    {
        ex.Data.Add("Screen polar Radius", radius);
        ex.Data.Add("Screen polar Theta", theta);
        throw;
    }
}

Solution

Yes I think that is going to be pretty quick. It might be tempting to move the cos calc so that it does a full Pythagoras with the radius. This will save an assignment, but I thi it requires an additional multiplication (1*1 being known already in your current version).

As a matter of personal style (possible because I code in multiple languages) but I would use different names for your sin and cos variables. most languages would not accept this, and it would, personally, have the potential to confuse me.

I would consider using a lookup table to find your sines. How precise an angle are you calculating for? This answer on stackoverflow has some interesting information on how to construct one and the benchmarks for using it to two decimal points. If you are using the full precision of a double, then your current method will be faster, but if you have a fixed precision, a lookup table will be benificial.

As long as the exception IS exceptional (and it looks to me like it is) it will add very little overhead to your run times. See: https://stackoverflow.com/q/52312/487663.

As a completely untested micro-optimisation, I would suspect (Int32)(radius * cosTheta + 0.5) is going to be marginally quicker than (Int32)Math.Round(radius * cosTheta). It does, however, round up on 0.5 instead of rounding down, which may not be what you want.

Leave a Reply

Your email address will not be published. Required fields are marked *