两端画线偏移 [英] Drawline offset at both ends

查看:82
本文介绍了两端画线偏移的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用 DrawLine 方法绘制虚线。但是,它会使端部略有偏移,从而使线条难看。

I am trying to draw dotted lines using the DrawLine method. However, it adds a slight offset to the ends which makes the lines ugly. How can prevent adding offset to the ends?

protected override void OnPaint (PaintEventArgs e) {
   Graphics g = e.Graphics;
   g.DrawLine (Dot, new Point (10, 50), new Point (70, 50));
   g.DrawLine (Dot, new Point (70, 50), new Point (70, 100));
}

Pen Dot = new Pen (Brushes.Black, 2) { DashStyle = DashStyle.Dot };

输出

预期结果

推荐答案

目标简单而合理:


  • 我们希望我们的行以点开始结束。

游戏规则也很简单:


  • 默认情况下,点和间隙均为正方形。 li>
  • 所有线条均使用 PenAlignment.Center 绘制。

  • Both the dots and the gaps are by default squares.
  • All lines are drawn with PenAlignment.Center.

不幸的是,合并的结果相当复杂,所以请耐心等待...

Unfortunately the consequences of the combination are rather complicated, so bear with me...

让我们首先看第一条规则;让我们忽略其他 DashStyles 并继续使用 DashStyle.Dot 。默认情况下,每个点和每个间隙的两边都有 Pen.Width 像素。这就引出了第一个问题:

Let's first look at the 1st rule; let's ignore other DashStyles and stay with DashStyle.Dot. By default each dot and each gap have Pen.Width pixels for both sides. This leads right into the first issues:


  • 如果行的宽度不能除以 Pen。宽度,我们遇到了麻烦。

  • 要以点开头和结尾,我们希望有 n 个点和 n-1 差距。

  • If the width of our lines can't be divided by Pen.Width we are in trouble.
  • To begin and end in a dot we want to have n dots and n-1 gaps.

还有更多,但让我们接下来看一下第二条规则;为了说明这一点,我画了这张10倍的放大图像:

There is more but let's next look into the 2nd rule; to illustrate it I drew this 10x upscaled image:

这是创建彩色部分的代码:

This is the code that created the colored parts:

g.FillRectangle(Brushes.Yellow, 15, 15, 10, 10);
g.DrawRectangle(Pens.Orange, 10, 10, 10, 10);
g.DrawLine(Pens.OrangeRed, 10, 5, 40, 5);
using (Pen pen = new Pen(Color.Red, 2f) { DashStyle = DashStyle.Dot })
    g.DrawLine(pen, 10, 30, 48, 30);
using (Pen pen = new Pen(Color.Crimson, 2f))
    g.DrawLine(pen, 10, 40, 48, 40);
using (Pen pen = new Pen(Color.DarkMagenta, 3f))
    g.DrawLine(pen, 10, 50, 48, 50);

仔细看看线条是如何绘制的!

Look closely to see how the lines are drawn!

(另外:您可能还想看 DrawRectangle FillRectangle !)

(Aside: You may also want to watch the difference of DrawRectangle and FillRectangle!)


  • 水平线在正确的坐标处开始和结束,但它们向下扩展(如果使用Pen的话)。宽度= 1)或大于或小于y-coodinate。

  • 当然,垂直线也一样。

问题在于它们只是无法在(外部)边缘融合在一起。

The problem is that they just won't fit together at the (outer) edges.

那么我们该怎么办?我认为 DashOffset 不能帮助您。但是还有另一种方法可以调整 Pen :我们可以将其 DashPattern 设置为使用自定义值

So what can we do? I don't think a DashOffset can help. But there is another option to tweak a Pen: We can set its DashPattern to use custom values.

我们需要的值是两个 floats ,其中包含 scaling 点和间隙。默认情况下,两个值均为 1f 。我决定使点保持正方形,仅修改间隙。这是一个可以通过

The values we need are two floats, containing the scaling for the dots and the gaps. By default both values are 1f. I decided to keep the dots square and modify only the gaps. Here is a function which solves the issue by


  • 将线宽两侧的笔宽扩大一半以使外边缘相遇的方法来解决该问题 li>
  • 根据需要扩大间距以适合线长

  • expanding the line width by half a pen width on both sides so the outer edges meet
  • expanding the gaps as needed to fit in the line length

这里是线条绘制功能;它需要一个 Graphics 对象,一个 Pen 对象,两个末端的 Points byte 来告诉我们该行是应该独立运行还是将连接连接到其他行,如本例所示。

Here is the line drawing function; it takes the Graphics object, a Pen, the two end Points and a byte that tells us if the line is meant to stand alone or will connect to other lines, as in our example cases.

要建立良好的连接,使其与半透明画笔一起使用,我们需要能够跳过在开头或结尾或什至两者都加一个点a,例如当我们想在下面的测试中插入一条对角线时。

To make a good connection, that will work well with semi-tranparent brushes we need the ability to skip a dot a at the beginning or end or even both, e.g. when we want to insert a diaogonal line as in my test below.

跳过值是 0 以跳过任何一条, 1或2 跳过第一个或最后一个点,而 3 跳过两个点。当然,您可能想使用枚举

The skip values are 0 to skip none, 1 or 2 to skip the 1st or last dot and 3 to skip both. Of course you may want to use an enumeration instead.

void DrawDottedLine(Graphics g, Pen pen_, Point pa_, Point pb, byte skipDots)
{
    float pw = pen_.Width;
    float pw2 = pen_.Width / 2f;
    Pen pen = (Pen)pen_.Clone();
    // find out directions:
    int sigX = Math.Sign(pb_.X - pa_.X);
    int sigY = Math.Sign(pb_.Y - pa_.Y);
    // move the end points out a bit:
    PointF pa = new PointF(pa_.X - pw2 * sigX, pa_.Y - pw2 * sigY);
    PointF pb = new PointF(pb_.X + pw2 * sigX, pb_.Y + pw2 * sigY);
    // find line new length:
    float lw = (float)(Math.Abs(pb.X - pa.X));
    float lh = (float)(Math.Abs(pb.Y - pa.Y));
    float ll = (float)(Math.Sqrt(lw * lw + lh * lh));
    // dot length:
    float dl = ll / pw;
    // dot+gap count: round to nearest odd int:
    int dc = (int)(2 * Math.Round((dl + 1) / 2) - 1);
    //  gap count:
    int gc = dc / 2 ;
    // dot count:
    dc = gc + 1;
    // gap scaling
    float gs = (ll - dc * pw) / (pw * gc);
    // our custom dashpattern 
    pen.DashPattern = new float[] { 1, gs };
    // maybe skip 1st and/or last dots:
    if (skipDots % 2 == 1) pa = new PointF(pa_.X + pw * sigX, pa_.Y + pw * sigY);
    if (skipDots > 1) pb = new PointF(pb_.X - pw * sigX, pb_.Y - pw * sigY);
    // finally we can draw the line:
    g.DrawLine(pen, pa, pb);
    // dispose of pen clone
    pen.Dispose();
}

经过一些明显的准备后,我将分数略微移开,然后计算出数字点和垂直线或水平线的间隙。然后我计算出修改后的间隙比例。

After some obvious preparations I move the points out a bit and then calculate the number of dots and of gaps for vertical or horizontal lines. Then I calculate the modified the gap scale.

这里是放大4倍的结果,它绘制了4条线以形成一个矩形,矩形的笔宽从<$ c开始$ c> 1/3-10/3 :

Here is the result, scaled up 4x, of drawing four lines to form a rectangle with varying pen widths going from 1/3 - 10/3:

这是我使用的测试床;请注意使用半透明的黑色来说明如何正确绘制角,即不重叠:

This is the testbed I used; note the use of semi-transparent black to illustrate how the corners are drawn correctly, i.e. non-overlapping:

Pen Dot = new Pen(Color.Black, 1f);
Point pa = new Point(10, 50);
Point pb = new Point(70, 50);
Point pc = new Point(70, 100);
Point pd = new Point(10, 100);

for (int i = 1; i < 10; i++ )
{
    Dot = new Pen(Color.FromArgb(128, Color.Black), i / 3f){ DashStyle = DashStyle.Dot };
    g.TranslateTransform(10, 10);
    DrawDottedLine(g, Dot, pa, pb, 2);
    DrawDottedLine(g, Dot, pb, pc, 2);
    DrawDottedLine(g, Dot, pc, pd, 2);
    DrawDottedLine(g, Dot, pd, pa, 2);
    DrawDottedLine(g, Dot, pd, pb, 3);
}

我真的希望有人可以通过使用<$ c $来避免连接问题c> DrawLines ,但这没用,弄清楚这个解决方案后,我并不感到惊讶。

I really wish one could avoid the connection problems by simply using DrawLines, but this didn't work and after figuring out this solution I'm not really amazed it didn't..

这篇关于两端画线偏移的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆