Photoshop样式的角度和高度选择器控件

[美]VCSKicks著，野比译

http://www.vcskicks.com

（免积分）

下载DEMO - 9.56KB

（即勾股定理，为尊重原文，以下简称毕氏定理。尽管有点绕口。——野比注）

SOH:  Sine = Opposite ÷ Hypotenuse
CAH:  Cosine = Adjacent ÷ Hypotenuse
TOA:  Tangent = Opposite ÷ Adjacent

• 一个函数接收角度和半径作为参数，返回围绕某个原点的相应点位置。（简单来说，就是把角度转换为点）
• 一个完成相反的功能，以点(X, Y)作为参数，找到最匹配的角度。

private PointF DegreesToXY(float degrees, float radius, Point origin)
{
PointF xy = new PointF();
double radians = degrees * Math.PI / 180.0;
return xy;
}

private float XYToDegrees(Point xy, Point origin)
{
double angle = 0.0;
if (xy.Y < origin.Y)
{
if (xy.X > origin.X)
{
angle = (double)(xy.X - origin.X) / (double)(origin.Y - xy.Y);
angle = Math.Atan(angle);
angle = 90.0 - angle * 180.0 / Math.PI;
}
else if (xy.X < origin.X)
{
//如此这般
}
}
else if (xy.Y > origin.Y)
{
//如此这般
}
if (angle > 180) angle -= 360; //控制角度范围
return (float)angle;
}

• 用宽度为2的Pen绘制外圈圆
• 用40%（约100）不透明度的白色填充
• 控件中心是3x3像素的正方形

protected override void OnPaint(PaintEventArgs e)
{
//...

//Draw
g.SmoothingMode = SmoothingMode.AntiAlias;
g.DrawEllipse(outline, drawRegion);
g.FillEllipse(fill, drawRegion);

//...Marker

g.SmoothingMode = SmoothingMode.HighSpeed;
g.FillRectangle(Brushes.Black, originSquare);

//...
}

private int findNearestAngle(Point mouseXY)
{
int thisAngle = (int)XYToDegrees(mouseXY, origin);
if (thisAngle != 0)
return thisAngle;
else
return -1;
}

private int findAltitude(Point mouseXY)
{
float distance = getDistance(mouseXY, origin);
int alt = 90 - (int)(90.0f * (distance / origin.X));
if (alt < 0) alt = 0;
return alt;
}

public delegate void AngleChangedDelegate();
public event AngleChangedDelegate AngleChanged;

（全文完）