假设我们有起始角θ1,结束角θ2(都是弧度),半径r,弧线方向逆时针。我们希望找到 Xmax、Ymax、Xmin 和 Ymin。将此值视为象限 q=f(θ) 的函数:
Xmax=f(q1,q2,r), Ymax=f(q1,q2,r), Xmin=f(q1,q2,r), Ymin=f(q1,q2,r)。
与其编写大量的“if”语句,不如将这个函数表示为“极值矩阵”。评估函数 f(q1,q2,r) 我们将得到 this matrices。
所以这里是算法:
- 找到θ1和θ2的象限(q1,q2);
- 将θ1,θ2,r转换为笛卡尔坐标;
- 查找不包括极值点的边界框;
- 构建极值矩阵;
- 根据q1选择Xmax、Ymax、Xmin、Ymin和q2 来自这个矩阵。
这是我的 C#6 实现:
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);
}
}
圆弧中心点位于 (0,0) 是公平的,但您可以轻松地将生成的边界框移动到 Cx,Cy。
与Tim Buegeleisen 的近似解决方案不同,此解决方案是精确的,尽管它可能会更贵一点。