Suppose we have start angle θ1, end angle θ2 (both in radians), radus r, direction of the arc counterclockwise. We'd like to find Xmax,Ymax,Xmin and Ymin. Consider this values as functions of quadrants q=f(θ):
Xmax=f(q1,q2,r), Ymax=f(q1,q2,r), Xmin=f(q1,q2,r), Ymin=f(q1,q2,r).
Instead of writing huge number of "if" statements it's convenient to represent this functions as an "extremum matrices". Evaluating functions f(q1,q2,r) we'll end up with this matrices.
So here is the algorithm:
- Find quadrants (q1,q2) of θ1 and θ2;
- Convert θ1,θ2,r to the Cartesian coordinates;
- Find bounding box excluding extreme points;
- Build extremum matrices;
- Select Xmax,Ymax,Xmin,Ymin accoding to q1 and q2 from this matrices.
Here's my C#6 implementation:
using System;
using System.Windows;
using static System.Math;
public static class GeomTools
{
public static Byte GetQuadrant(this Double angle)
{
var trueAngle = angle%(2*PI);
if (trueAngle >= 0.0 && trueAngle < PI/2.0)
return 1;
if (trueAngle >= PI/2.0 && trueAngle < PI)
return 2;
if (trueAngle >= PI && trueAngle < PI*3.0/2.0)
return 3;
if (trueAngle >= PI*3.0/2.0 && trueAngle < PI*2)
return 4;
return 0;
}
public static Rect GetBounds(Double startAngle, Double endAngle, Double r)
{
var startQuad = startAngle.GetQuadrant() - 1;
var endQuad = endAngle.GetQuadrant() - 1;
// Convert to Cartesian coordinates.
var stPt = new Point(Round(r*Cos(startAngle), 14), Round(r*Sin(startAngle), 14));
var enPt = new Point(Round(r*Cos(endAngle), 14), Round(r*Sin(endAngle), 14));
// Find bounding box excluding extremum.
var minX = stPt.X;
var minY = stPt.Y;
var maxX = stPt.X;
var maxY = stPt.Y;
if (maxX < enPt.X) maxX = enPt.X;
if (maxY < enPt.Y) maxY = enPt.Y;
if (minX > enPt.X) minX = enPt.X;
if (minY > enPt.Y) minY = enPt.Y;
// Build extremum matrices.
var xMax = new[,] {{maxX, r, r, r}, {maxX, maxX, r, r}, {maxX, maxX, maxX, r}, {maxX, maxX, maxX, maxX}};
var yMax = new[,] {{maxY, maxY, maxY, maxY}, {r, maxY, r, r}, {r, maxY, maxY, r}, {r, maxY, maxY, maxY}};
var xMin = new[,] {{minX, -r, minX, minX}, {minX, minX, minX, minX}, {-r, -r, minX, -r}, {-r, -r, minX, minX}};
var yMin = new[,] {{minY, -r, -r, minY}, {minY, minY, -r, minY}, {minY, minY, minY, minY}, {-r, -r, -r, minY}};
// Select desired values
var startPt =new Point(xMin[endQuad, startQuad], yMin[endQuad, startQuad]);
var endPt=new Point(xMax[endQuad, startQuad], yMax[endQuad, startQuad]);
return new Rect(startPt,endPt);
}
}
It is fair for arc centre point at (0,0) but you can easily move resulting bounding box to your Cx,Cy.
Unlike Tim Buegeleisen's approximate solution this solution is exact, though it may be a little bit more memory expensive.