2016-08-18 63 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!