【问题标题】:Calculating XY positions from path reverses when path turns路径转弯时从路径反向计算 XY 位置
【发布时间】:2012-07-02 01:02:21
【问题描述】:

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

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

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

黑点是路径的位置,它们的 X 和 Y 坐标是已知的。 红线的宽度是已知的,都是[w](比如20米,路径从中间切开)。

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

如何在 C++ 中计算这些位置?有什么功能可以让它更简单吗?

P.S:如您所见,红线的角度为两条蓝线的一半。


编辑:

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

(应用下载链接: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,并且我希望它不依赖于路径的转弯方式。如何做到这一点?

【问题讨论】:

  • 这本质上是一个数学/几何问题,因此题外话。解决它的一种方法是找到两条相邻绿线的方程,并找到它们的交点。另一种方法是注意红线平分两条相邻蓝线形成的角度。同样,所有这些都可以通过一些简单的数学来解决。
  • 你知道如何得到两个向量之间的角度吗?使用 3 个黑点,您可以创建 2 个向量,获取它们之间的角度,然后创建一个新向量以按宽度缩放以生成紫色点。
  • 任何工作示例? :P
  • 如果你能理解代码背后的概念,我相信你可以自己想出工作示例。
  • @Blender,看看我的编辑,现在我有一个需要解决的最后一个问题,我设法自己进行了计算,;o

标签: c++ math coordinate-systems polygons


【解决方案1】:

您可以检测点在直线的哪一侧。

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

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

如果position为正,则在左侧,负在右侧(0就行了)。

如果粉红色的点在路径的错误一侧,您可以使用它交换它们。

【讨论】:

    【解决方案2】:

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

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

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

    这是我相当糟糕的绘画马拉松。

    如您所见,紫色点的位置很容易得出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-24
      • 2010-11-11
      • 2020-11-05
      • 1970-01-01
      • 1970-01-01
      • 2023-01-30
      • 1970-01-01
      • 2020-10-04
      相关资源
      最近更新 更多