当路径转弯时,从路径计算XY位置会反转

时间:2012-07-02 01:02:22

标签: c++ math coordinate-systems polygons

向下滚动到编辑以阅读第2部分

所以我正在开发一个项目,我需要使用给定的X和Y坐标创建一个多边形。坐标以逻辑顺序给出并创建路径。现在我需要计算一个poligon的所有位置,如果路径宽度是[w](例如20米)。我们都知道线条没有宽度。

这张图片解释了我想要做的事情:

Path

黑点是路径的位置,它们的X和Y坐标是已知的。 红线的宽度是已知的,它们都是[w](例如20米,路径将它们切割在中心)。

我不知道如何获得所有紫色圆点的X,Y位置。我需要它们,所以我可以创建绿色多边形形状。

如何在C ++中计算这些位置?是否有任何功能使其更容易?

P.S:如你所见,红线是在两条蓝线角度的一半处变成的。


编辑:

我在Visual Basic .NET中创建了一个可视化应用程序,我得到了可以移植到C ++的公式。还有一个问题,请看这个图片: enter image description here

(应用下载链接:http://gpb.googlecode.com/files/DRAWER2.zip

现在的问题是,当路径转动时,它会反转创建多边形点的边。这会使一个损坏的多边形(或者,它不能提供想要的效果)。

代码如下:

Dim MainImage As New DynamicBitmap

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    Dim temp As New DynamicBitmap
    MainImage.CreateGrid(500, 500, 1, 1)
    temp.LoadBitmap("map.jpg")
    MainImage.DrawOnSurface(temp.Bitmap, temp.Rectangle, MainImage.Rectangle)
    MainImage.Surface.DrawLine(Pens.Black, 0, 250, 500, 250)
    MainImage.Surface.DrawLine(Pens.Black, 250, 0, 250, 500)
    PictureBox1.Image = MainImage.Bitmap
    PictureBox1.Refresh()
End Sub
Dim CPG(0) As Point
Dim CurrCount As Integer = 0
Dim Distance As Double = 30.0
Function CalculatePositions(ByVal PointStart As Point, ByVal PointMiddle As Point, ByVal PointEnd As Point) As Point()

    Dim DeltaX As Double
    Dim DeltaY As Double
    Dim AdderX As Double
    Dim AdderY As Double
    Dim Length As Double
    Dim CP(9) As Point
    CP(0) = PointMiddle
    CP(1) = PointStart
    CP(2) = PointEnd
    Dim RetP(1) As Point
    DeltaX = CP(1).X - CP(0).X
    DeltaY = CP(1).Y - CP(0).Y
    Length = Math.Sqrt(((DeltaX * DeltaX) + (DeltaY * DeltaY))) + 0.0000000001
    AdderX = (DeltaX / Length)
    AdderY = (DeltaY / Length)
    CP(3).X = (CP(0).X + (AdderX * Distance))
    CP(3).Y = (CP(0).Y + (AdderY * Distance))

    DeltaX = CP(2).X - CP(0).X
    DeltaY = CP(2).Y - CP(0).Y
    Length = Math.Sqrt(((DeltaX * DeltaX) + (DeltaY * DeltaY))) + 0.0000000001
    AdderX = (DeltaX / Length)
    AdderY = (DeltaY / Length)
    CP(4).X = (CP(0).X + (AdderX * Distance))
    CP(4).Y = (CP(0).Y + (AdderY * Distance))

    DeltaX = CP(3).X - CP(4).X
    DeltaY = CP(3).Y - CP(4).Y
    Length = Math.Sqrt(((DeltaX * DeltaX) + (DeltaY * DeltaY))) + 0.0000000001
    AdderX = (DeltaX / Length)
    AdderY = (DeltaY / Length)
    CP(8).X = (CP(4).X + (AdderX * Length / 2.0))
    CP(8).Y = (CP(4).Y + (AdderY * Length / 2.0))

    DeltaX = CP(8).X - CP(0).X
    DeltaY = CP(8).Y - CP(0).Y
    Length = Math.Sqrt(((DeltaX * DeltaX) + (DeltaY * DeltaY))) + 0.0000000001
    AdderX = (DeltaX / Length)
    AdderY = (DeltaY / Length)
    CP(7).X = (CP(0).X - (AdderX * Distance))
    CP(7).Y = (CP(0).Y - (AdderY * Distance))
    CP(9).X = (CP(0).X + (AdderX * Distance))
    CP(9).Y = (CP(0).Y + (AdderY * Distance))

    MainImage.Surface.DrawLine(Pens.Red, New Point(CP(7).X - 3, CP(7).Y - 3), New Point(CP(7).X + 3, CP(7).Y + 3))
    MainImage.Surface.DrawLine(Pens.Red, New Point(CP(7).X + 3, CP(7).Y - 3), New Point(CP(7).X - 3, CP(7).Y + 3))
    MainImage.Surface.DrawLine(Pens.Blue, New Point(CP(9).X - 3, CP(9).Y - 3), New Point(CP(9).X + 3, CP(9).Y + 3))
    MainImage.Surface.DrawLine(Pens.Blue, New Point(CP(9).X + 3, CP(9).Y - 3), New Point(CP(9).X - 3, CP(9).Y + 3))
    Return RetP
End Function

Private Sub PictureBox1_Click(sender As System.Object, e As System.EventArgs) Handles PictureBox1.Click
    'MsgBox(DirectCast(e, MouseEventArgs).X.ToString() + ":" + DirectCast(e, MouseEventArgs).Y.ToString())

    ReDim Preserve CPG(CurrCount)
    'i -= 1
    CPG(CurrCount) = New Point(DirectCast(e, MouseEventArgs).X, DirectCast(e, MouseEventArgs).Y)
    MainImage.Surface.DrawLine(Pens.Yellow, New Point(CPG(CurrCount).X - 3, CPG(CurrCount).Y - 3), New Point(CPG(CurrCount).X + 3, CPG(CurrCount).Y + 3))
    MainImage.Surface.DrawLine(Pens.Yellow, New Point(CPG(CurrCount).X + 3, CPG(CurrCount).Y - 3), New Point(CPG(CurrCount).X - 3, CPG(CurrCount).Y + 3))
    CurrCount += 1
    If CurrCount = 1 Then

    Else
        If CurrCount = 2 Then
            Dim DeltaX As Double
            Dim DeltaY As Double
            Dim AdderX As Double
            Dim AdderY As Double
            Dim Length As Double
            DeltaX = CPG(CurrCount - 2).X - CPG(CurrCount - 1).X
            DeltaY = CPG(CurrCount - 2).Y - CPG(CurrCount - 1).Y
            Length = Math.Sqrt(((DeltaX * DeltaX) + (DeltaY * DeltaY))) + 0.0000000001
            AdderX = (DeltaX / Length)
            AdderY = (DeltaY / Length)
            Dim Temp(1) As Point
            Dim Angle01 As Double = Math.Atan2(CPG(CurrCount - 1).X - CPG(CurrCount - 2).X, CPG(CurrCount - 1).Y - CPG(CurrCount - 2).Y) * 180.0 / Math.PI
            Dim SinMin As Double
            Dim CosMin As Double
            SinMin = Math.Sin(((-Angle01) + 0.0) / 180.0 * Math.PI)
            CosMin = Math.Cos(((-Angle01) + 0.0) / 180.0 * Math.PI)
            Temp(0).X = CPG(CurrCount - 2).X + (CosMin * Distance) + AdderX * Distance
            Temp(0).Y = CPG(CurrCount - 2).Y + (SinMin * Distance) + AdderY * Distance
            Temp(1).X = CPG(CurrCount - 2).X - (CosMin * Distance) + AdderX * Distance
            Temp(1).Y = CPG(CurrCount - 2).Y - (SinMin * Distance) + AdderY * Distance
            MainImage.Surface.DrawLine(Pens.Red, New Point(Temp(0).X - 3, Temp(0).Y - 3), New Point(Temp(0).X + 3, Temp(0).Y + 3))
            MainImage.Surface.DrawLine(Pens.Red, New Point(Temp(0).X + 3, Temp(0).Y - 3), New Point(Temp(0).X - 3, Temp(0).Y + 3))
            MainImage.Surface.DrawLine(Pens.Blue, New Point(Temp(1).X - 3, Temp(1).Y - 3), New Point(Temp(1).X + 3, Temp(1).Y + 3))
            MainImage.Surface.DrawLine(Pens.Blue, New Point(Temp(1).X + 3, Temp(1).Y - 3), New Point(Temp(1).X - 3, Temp(1).Y + 3))
        End If
        MainImage.Surface.DrawLine(Pens.Blue, CPG(CurrCount - 2), CPG(CurrCount - 1))
        If CurrCount > 2 Then
            CalculatePositions(CPG(CurrCount - 3), CPG(CurrCount - 2), CPG(CurrCount - 1))
        End If
    End If

    PictureBox1.Image = MainImage.Bitmap
    PictureBox1.Refresh()

    'MsgBox(CP(i).ToString())
End Sub

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    Dim DeltaX As Double
    Dim DeltaY As Double
    Dim AdderX As Double
    Dim AdderY As Double
    Dim Length As Double
    DeltaX = CPG(CurrCount - 2).X - CPG(CurrCount - 1).X
    DeltaY = CPG(CurrCount - 2).Y - CPG(CurrCount - 1).Y
    Length = Math.Sqrt(((DeltaX * DeltaX) + (DeltaY * DeltaY))) + 0.0000000001
    AdderX = (DeltaX / Length)
    AdderY = (DeltaY / Length)
    Dim Temp(1) As Point
    Dim Angle01 As Double = Math.Atan2(CPG(CurrCount - 1).X - CPG(CurrCount - 2).X, CPG(CurrCount - 1).Y - CPG(CurrCount - 2).Y) * 180.0 / Math.PI
    Dim SinMin As Double
    Dim CosMin As Double
    SinMin = Math.Sin(((-Angle01) + 0.0) / 180.0 * Math.PI)
    CosMin = Math.Cos(((-Angle01) + 0.0) / 180.0 * Math.PI)
    Temp(0).X = CPG(CurrCount - 1).X + (CosMin * Distance) - AdderX * Distance
    Temp(0).Y = CPG(CurrCount - 1).Y + (SinMin * Distance) - AdderY * Distance
    Temp(1).X = CPG(CurrCount - 1).X - (CosMin * Distance) - AdderX * Distance
    Temp(1).Y = CPG(CurrCount - 1).Y - (SinMin * Distance) - AdderY * Distance
    MainImage.Surface.DrawLine(Pens.Red, New Point(Temp(0).X - 3, Temp(0).Y - 3), New Point(Temp(0).X + 3, Temp(0).Y + 3))
    MainImage.Surface.DrawLine(Pens.Red, New Point(Temp(0).X + 3, Temp(0).Y - 3), New Point(Temp(0).X - 3, Temp(0).Y + 3))
    MainImage.Surface.DrawLine(Pens.Blue, New Point(Temp(1).X - 3, Temp(1).Y - 3), New Point(Temp(1).X + 3, Temp(1).Y + 3))
    MainImage.Surface.DrawLine(Pens.Blue, New Point(Temp(1).X + 3, Temp(1).Y - 3), New Point(Temp(1).X - 3, Temp(1).Y + 3))

    PictureBox1.Image = MainImage.Bitmap
    PictureBox1.Refresh()
End Sub

如何解决此问题?我想要一侧的红色X-es和另一侧的蓝色X-es,我希望它不会依赖于路径如何转动。如何做到这一点?

2 个答案:

答案 0 :(得分:2)

您可以检测到一条线在哪一侧。

position = Math.Sign( (Bx-Ax)*(Y-Ay) - (By-Ay)*(X-Ax) )

其中(Ax,Ay)是起点,(Bx,By)是该行的终点。 (X,Y)是您要检查的要点。

如果position为正数,则为左侧,右侧为负数(行上为0)。

如果它们位于路径的错误一侧,则交换粉红点。

答案 1 :(得分:1)

首先,获取第一段和最后一段的紫色点的位置(这非常简单)。

然后,对于每条蓝线,创建两条与其平行但与其间隔开的绿线。对于最后一行和第一行,您必须在这些点处明确终止这些行。这是最简单的方法,通过创建一个适当长度的蓝线,例如0,0,生成两条绿线,然后将它们转换为位置。它还可以让您更容易地跟踪哪条线。

然后,只需计算每一侧绿线与下一段绿线的交点。

这是我相当蹩脚的paintathon。Awful, I know. It's hand-drawn. In Paint.

如您所见,紫点的位置很容易到达。