将线条缩短多个像素

发布于 2024-08-13 20:39:30 字数 1499 浏览 4 评论 0原文

我正在使用 .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);
  }
}

I'm drawing a custom diagram of business objects using .NET GDI+. Among other things, the diagram consists of several lines that are connecting the objects.

In a particular scenario, I need to shorten a line by a specific number of pixels, let's say 10 pixels, i.e. find the point on the line that lies 10 pixels before the end point of the line.

Imagine a circle with radius r = 10 pixels, and a line with start point (x1, y1) and end point (x2, y2). The circle is centered at the end point of the line, as in the following illustration.

Illustration

How do I calculate the point marked with a red circle, i.e. the intersection between circle and line? This would give me the new end point of the line, shortening it by 10 pixels.


Solution

Thank you for your answers from which I was able to put together the following procedure. I named it LengthenLine, since I find it more natural to pass a negative number of pixels if I want the line shortened.

Specifically, I was trying to put together a function that could draw a line with rounded corners, which can be found here.

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);
  }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

情域 2024-08-20 20:39:30

找到方向向量,即让位置向量为(使用浮点数)B = (x2, y2) 和 A = (x1, y1),然后 AB = B - A。通过除以向量的长度来标准化该向量 (Math.Sqrt (xx + yy) )。然后将方向向量 AB 乘以原始长度减去圆的半径,然后加回线的起始位置:

double dx = x2 - x1;
double dy = y2 - y1;
double length = Math.Sqrt(dx * dx + dy * dy);
if (length > 0)
{
    dx /= length;
    dy /= length;
}
dx *= length - radius;
dy *= length - radius;
int x3 = (int)(x1 + dx);
int y3 = (int)(y1 + dy);

编辑:修复代码,aa 并修复初始解释(认为您希望线从圆的中心延伸到其周长:P)

Find the direction vector, i.e. let the position vectors be (using floats) B = (x2, y2) and A = (x1, y1), then AB = B - A. Normalize that vector by dividing by its length ( Math.Sqrt(xx + yy) ). Then multiply the direction vector AB by the original length minus the circle's radius, and add back to the lines starting position:

double dx = x2 - x1;
double dy = y2 - y1;
double length = Math.Sqrt(dx * dx + dy * dy);
if (length > 0)
{
    dx /= length;
    dy /= length;
}
dx *= length - radius;
dy *= length - radius;
int x3 = (int)(x1 + dx);
int y3 = (int)(y1 + dy);

Edit: Fixed the code, aaand fixed the initial explanation (thought you wanted the line to go out from the circle's center to its perimeter :P)

梦言归人 2024-08-20 20:39:30

我不知道你为什么还要介绍这个圈子。对于从 (x2,y2) 延伸到 (x1,y1) 的直线,您可以将该直线上的任意点计算为:

(x2+p*(x1-x2),y2+p*(y1-y2))

其中 p是您想要走的路线的百分比。

要计算百分比,您只需要:

p = r/L

因此,在您的情况下,(x3,y3) 可以计算为:

(x2+(10/L)*(x1-x2),y2+(10/L)*(y1-y2))

例如,如果您有两个点 (x2=1,y2= 5)(x1=-6,y1=22),它们的长度为 sqrt(72 + 172 或 18.38477631 和 10 除以 0.543928293 将所有这些数字代入上面的等式:

  (x2 + (10/l)      * (x1-x2) , y2 + (10/l)      * (y1-y2))
= (1  + 0.543928293 * (-6- 1) , 5  + 0.543928293 * (22- 5))
= (1  + 0.543928293 * -7      , 5  + 0.543928293 * 17     )
= (x3=-2.807498053,y3=14.24678098)

(x3,y3)(x1,y1) 之间的距离为 sqrt。 (3.1925019472 + 7.7532190152) 或 8.384776311,相差 10 到千分之一以内,这只是因为计算器上的舍入误差。

I'm not sure why you even had to introduce the circle. For a line stretching from (x2,y2) to (x1,y1), you can calculate any point on that line as:

(x2+p*(x1-x2),y2+p*(y1-y2))

where p is the percentage along the line you wish to go.

To calculate the percentage, you just need:

p = r/L

So in your case, (x3,y3) can be calculated as:

(x2+(10/L)*(x1-x2),y2+(10/L)*(y1-y2))

For example, if you have the two points (x2=1,y2=5) and (x1=-6,y1=22), they have a length of sqrt(72 + 172 or 18.38477631 and 10 divided by that is 0.543928293. Putting all those figures into the equation above:

  (x2 + (10/l)      * (x1-x2) , y2 + (10/l)      * (y1-y2))
= (1  + 0.543928293 * (-6- 1) , 5  + 0.543928293 * (22- 5))
= (1  + 0.543928293 * -7      , 5  + 0.543928293 * 17     )
= (x3=-2.807498053,y3=14.24678098)

The distance between (x3,y3) and (x1,y1) is sqrt(3.1925019472 + 7.7532190152) or 8.384776311, a difference of 10 to within one part in a thousand million, and that's only because of rounding errors on my calculator.

七月上 2024-08-20 20:39:30

您可以使用类似的三角形。对于主三角形,d 是斜边,r 的延长线是与直角相交的垂直线。在圆内,您将有一个较小的三角形,其斜边长度为r

r/d = (x2-a0)/(x2-x1) = (y2-b0)/(y2-y1)

a0 = x2 + (x2-x1)r/d

b0 = y2 + (y2-y1)r/d

You can use similar triangles. For the main triangle, d is the hypotenuses and the extension of r is the vertical line that meets the right angle. Inside the circle you will have a smaller triangle with a hypotenuses of length r.

r/d = (x2-a0)/(x2-x1) = (y2-b0)/(y2-y1)

a0 = x2 + (x2-x1)r/d

b0 = y2 + (y2-y1)r/d
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文