2016-10-03 73 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