Ответ 1
Моделирование глазного яблока как следующего эллипса:
Его уравнение:
И строка, соединяющая ее центр и курсор:
(не беспокойтесь об сингулярности)
Затем мы можем решить, чтобы получить точку пересечения:
Где
Теперь вы можете рассчитать расстояние до края глазного яблока, разделив расстояние от центра на курсор сигмой. Остается только интерполировать, чтобы ограничить положение ученика:
Оператор if
, который вы хотите, затем
(N.B. для math-mo там выше было небольшое упрощение, предполагающее, что ваш эллипс не слишком узкий, точное решение не аналитично)
EDIT: мои тесты в VB.NET:
EDIT 2: порт С#
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
: Радиус круга, который вы хотите ограничить (ученик). - Возвращает: точка, в которой вы хотите разместить центр круга
EDIT 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));
}