这篇文章的标题很难想到,所以如果你能想到更具描述性的标题,请告诉我。无论如何,我的问题非常具体,需要一些简单的数学知识。我正在编写一个C#WinForms应用程序,它有点像旧的'xeyes'Linux应用程序。它基本上是一组跟随鼠标光标的眼睛。这听起来可能很容易,但是如果你像我这样的完美主义者会变得相当复杂:P。这是我到目前为止的代码(只有paint方法,间隔为16)。
int lx = 35;
int ly = 50;
int rx;
int ry;
int wx = Location.X + Width / 2;
int wy = Location.Y + Height / 2;
Rectangle bounds = Screen.FromControl(this).Bounds;
// Calculate X
float tempX = (mx - wx) / (float)(bounds.Width / 2);
// Calculate Y
float tempY = (my - wy) / (float)(bounds.Height / 2);
// Draw eyes
e.Graphics.FillEllipse(Brushes.LightGray, 10, 10, 70, 100);
e.Graphics.FillEllipse(Brushes.LightGray, 90, 10, 70, 100);
// Draw pupils (this only draws the left one)
e.Graphics.FillEllipse(Brushes.Black, lx += (int)(25 * tempX), ly += (int)(40 * tempY), 20, 20);
现在这在基本级别上有效,但是如果用户将光标置于0,0,有时会发生这种情况。
现在我的问题是如何解决这个问题? IF语句将检查鼠标指针的位置,然后根据它减少瞳孔X?
感谢。
修改:这是我获取鼠标位置的位置(my
和mx
):
private void timer_Tick(object sender, EventArgs e)
{
mx = Cursor.Position.X;
my = Cursor.Position.Y;
Invalidate();
}
计时器在eyes_Load事件中启动,间隔为16。
编辑2:最终解决方案:http://pastebin.com/fT5HfiQR
答案 0 :(得分:15)
将眼球建模为以下椭圆:
它的等式是:
加入其中心和光标的那条线:
(不要担心奇点)
然后我们可以求解得到交点:
其中
现在,您可以通过西格玛将距离中心到光标的距离除以眼球边缘的距离来计算。剩下的只是内插以限制学生的位置:
您想要的if
语句是
(N.B。对于数学模型,上面是一个略微的简化,假设你的椭圆不是太窄; 完全解决方案是非分析性的)
编辑:我在VB.NET中的测试:
编辑2:C#端口
PointF Bound(double xc, double yc, double w, double h, double xm, double ym, double r)
{
double dx = xm - xc, dy = ym - yc;
if (Math.Abs(dx) > 0.001 && Math.Abs(dy) > 0.001)
{
double dx2 = dx * dx, dy2 = dy * dy;
double sig = 1.0 / Math.Sqrt(dx2 / (w * w * 0.25) + dy2 / (h * h * 0.25));
double d = Math.Sqrt(dx2 + dy2), e = d * sig;
if (d > e - r)
{
double ratio = (e - r) / d;
return new PointF((float)(xc + dx * ratio),
(float)(yc + dy * ratio));
}
}
return new PointF((float)xm, (float)ym);
}
xc
,yc
:椭圆的中心坐标w
,h
:椭圆的宽度和高度xm
,ym
:鼠标坐标r
:你想要约束的圆的半径(瞳孔)编辑3:非常感谢Quinchilion进行了以下优化(gawd该死的,这让我脸红了)
PointF Bound(double xc, double yc, double w, double h, double xm, double ym, double r)
{
double x = (xm - xc) / (w - r);
double y = (ym - yc) / (h - r);
double dot = x*x + y*y;
if (dot > 1) {
double mag = 1.0 / Math.Sqrt(dot);
x *= mag; y *= mag;
}
return new PointF((float)(x * (w - r) + xc), (float)(y * (h - r) + yc));
}