2016-08-18 72 views
0

我對複製路徑涉及的數學有疑問。 比方說,我有這樣的路徑:數學複製距離d的路徑

http://imgur.com/a/42l0t

我想這條道路的除了黑色的一個完全相同的副本。我寫了一個小的C#程序來計算兩點之間的角度。根據角度,添加X或Y值的偏移量。 這樣的工作,這就是結果:

http://imgur.com/bJQDCgq

正如你所看到的,它不是那麼漂亮。 現在,我真正的問題是:什麼是適當的數學用於此?

希望有人知道答案,因爲我有點卡在這一個。 問候, 薩沙

代碼:

void Plot(List<Point> points) 
    { 
     Graphics g = pictureBox.CreateGraphics(); 
     g.Clear(Color.White); 

     for (int i = 0; i < points.Count - 1; i++) 
     { 
      g.DrawLine(Pens.Black, points[i], points[i + 1]); 
     } 

     List<Point> points2 = new List<Point>(); 
     for (int i = 0; i < points.Count - 1; i++) 
     { 
      var angle = getAngleFromPoint(points[i], points[i + 1]); 
      Debug.WriteLine(angle); 

      if (angle < 180 && angle >= 135) 
      { 
       points2.Add(new Point(points[i].X - OFFSET, points[i].Y)); 
      } 
      if (angle < 135 && angle >= 90) 
      { 
       if (points[i].Y < points[i + 1].Y) 
       { 
        points2.Add(new Point(points[i].X - OFFSET/2, points[i].Y + OFFSET)); 
       } 
       else 
       { 
       }     
      } 
      if (angle < 90 && angle >= 45) 
      { 
       if (points[i].Y < points[i + 1].Y) 
       { 
        points2.Add(new Point(points[i].X - OFFSET, points[i].Y)); 
       } 
       else 
       { 
        points2.Add(new Point(points[i].X + OFFSET, points[i].Y)); 
       } 
      } 
      if (angle < 45 && angle >= 0) 
      { 
       if (points[i].Y < points[i + 1].Y) 
       { 
        points2.Add(new Point(points[i].X - OFFSET, points[i].Y)); 
       } 
       else 
       { 
        points2.Add(new Point(points[i].X + OFFSET, points[i].Y)); 
       } 
      } 
      if (angle < 360 && angle >= 315) 
      { 
       if (points[i].Y < points[i + 1].Y) 
       { 
        points2.Add(new Point(points[i].X + OFFSET, points[i].Y)); 
       } 
       else 
       { 
        points2.Add(new Point(points[i].X + 10, points[i].Y - OFFSET)); 
       } 
      } 
      if (angle < 315 && angle >= 270) 
      { 
       points2.Add(new Point(points[i].X, points[i].Y - OFFSET)); 
      } 
      if (angle < 270 && angle >= 225) 
      {      
       if (points[i].Y < points[i + 1].Y) 
       { 
        points2.Add(new Point(points[i].X - OFFSET/2, points[i].Y - OFFSET)); 
       } 
       else 
       { 

       } 
      } 
      if (angle < 225 && angle >= 180) 
      { 
       if (points[i].X < points[i + 1].X) 
       { 
        points2.Add(new Point(points[i].X, points[i].Y - OFFSET)); 
       } 
       else 
       { 
        if (points[i].Y < points[i + 1].Y) //  \ 
        { 
         points2.Add(new Point(points[i].X - OFFSET, points[i].Y)); 
        } 
        else 
        { 

        } 
       } 
      } 
     } 

     for (int i = 0; i < points2.Count - 1; i++) 
     { 
      g.DrawLine(Pens.Red, points2[i], points2[i + 1]); 
     } 
    } 

我想如果我減小角度(45項的措施,或許是30度),我可以imnprove的結果,但必須有一個更好的解決方案。

+0

你能發佈給你第二個輸出的代碼嗎? – Jack

+0

我編輯了我的帖子。這不是很漂亮,我知道;) –

+0

什麼是預期的輸出?所有的生產線都必須與其他生產線平行嗎? – Jack

回答

1

我想解決這個是將其分割成線對(即:三個點)單程

查找該對的每個線的平行線(在距離d)。然後找到這些平行線相交的位置,以便爲您提供新線條上某個點的位置。

在非常粗糙的僞代碼:

points a, b, c 
distance d 

lineab = findLineParallelTo(line(a,b), d) 
linebc = findLineParallelTo(line(b,c), d) 

return intersect(lineab, linebc) 
+0

這聽起來不錯,我會實現它,並會在代碼準備好後發佈。 –

0

我實現從@Jack的解決方案,它的偉大工程:

public class Line 
{ 
    public PointF P { get; private set; } 
    public PointF Q { get; private set; } 

    public float Pitch 
    { 
     get; private set; 
    } 

    public Line() 
    { 

    } 

    public Line(float px, float py, float qx, float qy) : this(new PointF(px, py), new PointF(qx, qy)) 
    { 

    } 

    public Line(PointF p, PointF q) 
    { 
     P = p; 
     Q = q; 
    } 

    #region Methods 

    /// <summary> 
    /// http://stackoverflow.com/questions/2825412/draw-a-parallel-line 
    /// </summary> 
    public Line FindParallelLine(float distance) 
    { 
     float length = (float)Math.Sqrt((P.X - Q.X) * (P.X - Q.X) + (P.Y - Q.Y) * (P.Y - Q.Y)); 

     // This is the second line 
     float px = P.X + distance * (Q.Y - P.Y)/length; 
     float qx = Q.X + distance * (Q.Y - P.Y)/length; 
     float py = P.Y + distance * (P.X - Q.X)/length; 
     float qy = Q.Y + distance * (P.X - Q.X)/length; 

     return new Line(px, py, qx, qy); 
    }   

    public override string ToString() 
    { 
     return string.Format("P({0}|{1}), Q({2}|{3}) - Pitch: {4}", P.X, P.Y, Q.X, Q.Y, Pitch); 
    } 

    #endregion 
} 

private PointF FindIntersection(Line a, Line b) 
    { 
     PointF A = a.P; 
     PointF B = a.Q; 
     PointF C = b.P; 
     PointF D = b.Q; 

     float dy1 = B.Y - A.Y; 
     float dx1 = B.X - A.X; 
     float dy2 = D.Y - C.Y; 
     float dx2 = D.X - C.X;    

     // Check whether the two line parallel. 
     if (dy1 * dx2 == dy2 * dx1) 
     { 
      return PointF.Empty; 
     } 
     else 
     { 
      float x = ((C.Y - A.Y) * dx1 * dx2 + dy1 * dx2 * A.X - dy2 * dx1 * C.X)/(dy1 * dx2 - dy2 * dx1); 
      float y = A.Y + (dy1/dx1) * (x - A.X); 
      return new PointF(x, y); 
     } 
    } 

    private PointF FindIntersection(PointF a, PointF b, PointF c, float distance) 
    { 
     Line line1 = new Line(a, b); 
     Line line2 = new Line(b, c); 

     Line parallel = line1.FindParallelLine(distance); 
     Line parallel2 = line2.FindParallelLine(distance); 

     return FindIntersection(parallel, parallel2); 
    } 

    private List<PointF> FindIntersections(PointF[] points, float distance) 
    { 
     List<PointF> intersections = new List<PointF>(); 

     for (int i = 0; i < points.Length - 2; i++) 
     { 
      PointF intersection = FindIntersection(points[i], points[i + 1], points[i + 2], distance); 
      if (!intersection.IsEmpty && !double.IsNaN(intersection.X) && !double.IsNaN(intersection.Y)) 
      { 
       intersections.Add(intersection); 
      }     
     } 

     return intersections; 
    } 

    private PointF GetFirstPoint(PointF[] points, float distance) 
    { 
     Line parallel = new Line(points[0], points[1]).FindParallelLine(distance); 
     return parallel.P; 
    } 

    private PointF GetLastPoint(PointF[] points, float distance) 
    { 
     Line parallel = new Line(points[points.Length - 2], points[points.Length - 1]).FindParallelLine(distance); 
     return parallel.Q; 
    } 

調用示例:

OFFSET = float.Parse(textBox1.Text); 
     List<PointF> points = new List<PointF>(); 
     points.Add(new PointF(200, 180)); 
     points.Add(new PointF(160, 160)); 
     points.Add(new PointF(100, 160)); 
     points.Add(new PointF(60, 140)); 
     points.Add(new PointF(40, 100)); 
     points.Add(new PointF(80, 60)); 
     points.Add(new PointF(140, 100)); 
     points.Add(new PointF(180, 140)); 
     points.Add(new PointF(220, 80)); 

     List<PointF> intersections = FindIntersections(points.ToArray(), OFFSET); 
     intersections.Insert(0, GetFirstPoint(points.ToArray(), OFFSET)); 
     intersections.Add(GetLastPoint(points.ToArray(), OFFSET)); 

     Graphics g = pictureBox.CreateGraphics(); 
     g.Clear(Color.White); 

     g.DrawLines(Pens.Black, points.ToArray()); 
     // Connect the intersection points. 
     g.DrawLines(Pens.Red, intersections.ToArray()); 

示例圖片:

http://imgur.com/onUstGT

再次感謝@Jack!