Я рисую пользовательскую диаграмму бизнес-объектов, используя .NET GDI+. Помимо прочего, диаграмма состоит из нескольких линий, соединяющих объекты.
В конкретном сценарии мне нужно сократить линию на определенное количество пикселей, скажем, на 10 пикселей, то есть найти точку на линии, которая лежит на 10 пикселей раньше конечной точки линии.
Представьте круг с радиусом r = 10 пикселей и линию с начальной точкой (x1, y1) и конечной точкой (x2, y2). Круг центрируется в конечной точке линии, как показано на следующем рисунке.
Как рассчитать точку, отмеченную красным кругом, то есть пересечение между кругом и линией? Это даст мне новую конечную точку линии, сократив ее на 10 пикселей.
Решение
Спасибо за ваши ответы, из которых мне удалось собрать следующую процедуру. Я назвал его "LengthenLine", так как считаю более естественным пропускать отрицательное число пикселей, если я хочу сократить линию.
В частности, я пытался собрать функцию, которая могла бы нарисовать линию с закругленными углами, которую можно найти здесь.
public void LengthenLine(PointF startPoint, ref PointF endPoint, float pixelCount)
{
if (startPoint.Equals(endPoint))
return; // not a line
double dx = endPoint.X - startPoint.X;
double dy = endPoint.Y - startPoint.Y;
if (dx == 0)
{
// vertical line:
if (endPoint.Y < startPoint.Y)
endPoint.Y -= pixelCount;
else
endPoint.Y += pixelCount;
}
else if (dy == 0)
{
// horizontal line:
if (endPoint.X < startPoint.X)
endPoint.X -= pixelCount;
else
endPoint.X += pixelCount;
}
else
{
// non-horizontal, non-vertical line:
double length = Math.Sqrt(dx * dx + dy * dy);
double scale = (length + pixelCount) / length;
dx *= scale;
dy *= scale;
endPoint.X = startPoint.X + Convert.ToSingle(dx);
endPoint.Y = startPoint.Y + Convert.ToSingle(dy);
}
}