2010-04-20 1 views
3

Я рисую графики в PictureForms WinForms. Теперь я ищу возможность «дублировать» строку (массив точек), так что две результирующие строки расположены на некотором фиксированном расстоянии от исходного. Как и в этой картине, у меня есть красная линия и хочу получить черные:Создание линий вокруг направляющей линии с использованием Miterjoin

Picture of lines http://img227.imageshack.us/img227/2341/linesb.png

Я думал о только перемещении линии на несколько пикселей вверх/вправо/вверх-вправо, но это приводит к странному перекрывающиеся линии.

Есть ли другой подход, который делает то, что я хочу? Любые идеи очень приветствуются. Благодаря!

+0

Обратите внимание, что черные линии не такие же, как у красного. – SLaks

ответ

2

Я создал функцию, которая делает ровно, что вам нужно несколько месяцев назад в качестве части алгоритма построения графа. Я написал это в python и PyQt. Я просто вставил код here at codepad. Это должно быть легко переведено на C#.

Update:

В переводе это один-к-одному из моего питона сниппета (Love сделать это графический материал :)). Поскольку мой оригинальный код был разработан для более чем двух выходных строк, я просто взял это в версию C#. Для двух черных линий, находящихся на расстоянии 20 пикселей от красного, просто пройдите width = 40 и num = 2. Возвращенный зазубренный массив представляет массив строк (внешний массив), причем каждая строка представлена ​​массивом точек (внутренняя).

public PointF[][] MultiplyLine(PointF[] line, int width, int num) 
{ 
    if (num == 1) return new PointF[][] { line }; 
    if (num < 1) throw new ArgumentOutOfRangeException(); 
    if (line.Length < 2) return Enumerable.Range(0, num) 
        .Select(x => line).ToArray(); 

    Func<float, float, PointF> normVec = (x, y) => { 
     float len = (float)Math.Sqrt((double)(x * x + y * y)); 
     return len == 0 ? new PointF(1f, 0f) : new PointF(x/len, y/len); 
    }; 

    PointF[][] newLines = Enumerable.Range(0, num) 
        .Select(x => new PointF[line.Length]).ToArray(); 

    float numinv = 1f/(float)(num - 1), cor = 0f; 
    PointF vec1 = PointF.Empty, vec2 = PointF.Empty, vec3 = PointF.Empty; 

    int j = -1, i = -1; 
    foreach (PointF p in line) 
    { 
     bool first = j == -1, last = j == line.Length - 2; j++; 

     if (!last) 
      vec1 = normVec(line[j + 1].Y - p.Y, -line[j + 1].X + p.X); 
     if (!first) 
      vec2 = normVec(-line[j - 1].Y + p.Y, line[j - 1].X - p.X); 
     if (!first && !last) 
     { 
      vec3 = normVec(vec1.X + vec2.X, vec1.Y + vec2.Y); 
      cor = (float)Math.Sin((Math.PI - 
        Math.Acos(vec1.X * vec2.X + vec1.Y * vec2.Y))/2); 
      cor = cor == 0 ? 1 : cor; 
      vec3 = new PointF(vec3.X/cor, vec3.Y/cor); 
     } 

     i = -1; 
     foreach (PointF[] newLine in newLines) 
     { 
      i++; cor = (float)width * ((float)i * numinv - 0.5f); 
      vec1 = first ? vec1 : last ? vec2 : vec3; 
      newLine[j] = new PointF(vec1.X * cor + p.X, vec1.Y * cor + p.Y); 
     } 
    } 

    return newLines; 
} 

Чтобы попробовать его я взял этот маленький образец (тот же образец, как в моем PyQt коде):

PointF[] pts = new PointF[] { 
    new PointF(100f, 100f), new PointF(300f, 200f), 
    new PointF(500f, 200f), new PointF(300f, 500f), 
    new PointF(600f, 450f), new PointF(650f, 180f), 
    new PointF(800f, 180f), new PointF(800f, 500f), 
    new PointF(200f, 700f) 
}; 

pictureBox1.Image = new Bitmap(pictureBox1.Width, pictureBox1.Height); 
using(Graphics g = Graphics.FromImage(pictureBox1.Image)){ 
    g.DrawLines(new Pen(Color.Red), pts); 

    foreach (PointF[] line in MultiplyLine(pts, 80, 14)) 
     g.DrawLines(new Pen(Color.Black), line); 
} 

Что привело к этому графике:

outlines around line http://img41.imageshack.us/img41/8606/lines2.th.png

+0

Это кажется очень перспективным. Я боюсь, что у меня нет подсказки о питоне. –

+0

Ничего себе, это потрясающе! Большое спасибо, это совершенно то, что я искал, и очень быстрый и подробный ответ! –