2016-10-03 69 views
2

我想用DrawLine方法绘制虚线。然而,它增加了一个微小的偏移量,使线条变得丑陋。如何防止添加抵消到目的地?两端的绘图偏移

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

输出

enter image description here

预期结果

enter image description here

+1

这是[放大的结果绘图](http://i.stack.imgur.com/ARXbp.png)。绘图有什么问题,你期望什么? (虚线是原始的虚线图,红线显示的是用于绘制的框。 –

+0

@RezaAghaei为什么会有偏移?从技术上讲,线应该重合,因为第一行的终点和第一行的起点第二行是相同的 – kakkarot

+0

你可以使用链接的图像,并在图像上显示意想不到的部分,同时显示期望的结果,我不明白你提到的偏移量是什么,它是一个虚线,宽度为2它是不同的 –

回答

2

的目标很简单的和可信的:

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

而游戏规则也很简单:

  • 无论是点和差距是默认的正方形。
  • 所有线条均采用PenAlignment.Center绘制。

不幸的是,组合的后果是相当复杂的,所以我承担......

让我们先来看看第一个规则;让我们忽略其他DashStyles并留在DashStyle.Dot。默认情况下,每个点和每个间隙的两侧都有Pen.Width像素。这导致右转入第一问题:

  • 如果我们的线的宽度不能Pen.Width分,我们就有麻烦了。
  • 要开始和结束点我们想要有n点和n-1的空白。

还有更多,但让我们来看看第二条规则;来说明吧,我画这个10倍放大图像:

enter image description here

这是创建着色部代码:

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

仔细看才能看到线条的绘制方式!

(旁白:你可能也想观看的DrawRectangleFillRectangle差)

  • 水平线开始,并在合适的坐标结束,但他们要么扩大向下(如果他们的Pen.Width = 1 )或高于和低于γ-辅酸盐。
  • 当然,垂直线条也是一样。

问题是,他们只是不会在(外)边缘放在一起。

那么我们该怎么办?我不认为DashOffset可以提供帮助。但有另一个选项来调整Pen:我们可以将其设置为DashPattern以使用自定义值

我们需要的值是两个floats,包含缩放的点和空白。默认情况下,这两个值都是1f。我决定保持点平方,只修改差距。这里是通过

  • 解决该问题通过在两侧上半笔宽度扩展的线宽度,以便外边缘满足
  • 扩大的间隙根据需要,以适应线路长度的函数

这里是画线功能;它需要Graphics对象,一个Pen,两端Points和一个byte告诉我们该线是否意味着独立或将连接到其他行,如我们的示例中。

为了使良好的连接,将与半tranparent很好地工作刷我们需要在开头或结尾,甚至两者,例如跳过一个点的能力当我们想要插入一个正交线,如下面我的测试。

跳过值为0跳过没有,1 or 2跳过第一个或最后一个点和3跳过这两个。当然,您也可以使用enumeration

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

经过一些明显的准备工作后,我将点移出一点,然后计算垂直线或水平线的点数和间距。然后我计算修改后的差距比例。

下面是结果,按比例增加4倍,拉伸四行以形成具有不同宽度的笔从1/3 - 10/3去矩形的:

enter image description here

这是我所使用的测试平台;注意使用半透明的黑色来说明如何角被正确地绘制,即非重叠:

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

我真的希望人们可以简单地使用DrawLines避免了连接问题,但这并没有工作,找出这个解决方案后,我并不是真的很惊讶它没有..

1

offset line by width of line

您提供的坐标是指向生成线的左上角位置的点。所以当你绘制一条宽度为两个像素的线时,你应该计算你的开始点和结束点以包含该线的宽度。

在这种情况下,您需要将垂直线略微偏移到左侧和顶部(准确地说是borderwith)。

因此,通过增加(或减少)的偏移等于线的宽度,结果是这样的:

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 (69, 49), new Point (69, 100)); 
} 

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

我听不懂你在说什么,有点代码 可能有帮助。 – kakkarot

+0

67,49和67,100看起来很完美 – kakkarot

+0

@kakkarot,在这种情况下,你必须加入这样的事实,即点有间隙,所以根据点开始或结束的点,偏移量可以更大或更小。 – Adimeus