Scroll down to the edit to read part 2
So I am working on a project where I need to create a polygon using given X and Y coordinates. The coordinates a given in logical order and create a path. Now I need to calculate all positions of a poligon, if the path width would be [w] (for example 20 meters). We all know lines have no width.
This image explains a bit what I want to do:
The black dots are the positions of the path, their X and Y coordinates are known. The width of the red lines is known, they are all [w] (for example 20 meters, the path cuts them in the center).
I do not know how to get the X,Y positions of all the purple dots. I need them so I can create the green polygon shape.
How can I calculate these positions in C++? Are there any functions which make it easier?
P.S: As you see the red lines are angeled at the half of the angle of two blue lines.
Edit:
I created a visualisation app in Visual Basic .NET and I got the formulas which I can port to C++. There is still one problem, please look at this image:
(app download link: http://gpb.googlecode.com/files/DRAWER2.zip )
The problem now is that when the path turns, it reverses the sides on which the points of the polygon get created. This makes an corrupted polygon (or well, it doesn't provide the wanted effect).
The code looks as following:
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
How can I fix this issue? I want the red X-es on one side and the blue X-es on the other side, and I want it to not be dependable on how the path turns. How to accomplish this?
You an detect which side of a line a point is on.
position = Math.Sign( (Bx-Ax)*(Y-Ay) - (By-Ay)*(X-Ax) )
where (Ax,Ay)
is the starting point, and (Bx,By)
is the ending point of the line. (X,Y)
is the point you want to check.
If the position
is positive, it is on the left side, negative on the right (0
on the line).
With this you swap the pink dots if they are on the wrong side of the path.