Thanks, will have a look at that.Given that (presumably) it's for screen display and that thus near-enough-is-good-enough, I'd scale the longitude so that a degree of longitude was the same physical distance as a degree of latitude, effectively cartesian coordinates (x, y), and then it's easy, just add... probably easier to work an example through:
Say the pointy end of the line is (px, py) and the tail end is (tx, ty)
So the "size" of the line is (sx, sy) = (px - tx, py - ty)
You'd think we need to know the length of the line, by Pythagoras, but we don't.
Then let's say we make the edge length of the triangle one-tenth of that (1/10)
Work out the left-base point as (lx, ly) = (px - sy / 10 / 2, py - sx / 10 / 2)
the divide-by-twos are because the triangle base goes one-half left and one-half right from the end of the line
And the right-base point as (rx, ry) = (px + sy / 10 / 2, py + sx / 10 / 2)
And the sharp (ouch) point of the arrow triangle is (ox, oy) = (px + sx / 10 / 2 * sqrt(3), py + sy / 10 / 2 * sqrt(3))
I think.
(x, y) = (lon * cos(lat), lat)
which is close enough for smallish distances eg 1 degree is 100 km.
Sub GetArrowRotation(tLL1 As TMapLatLng, tLL2 As TMapLatLng) As Int
Dim dLatDiff As Double
Dim dLngDiff As Double
Dim dLatLngDiffRatio As Double
dLatDiff = tLL2.fLat - tLL1.flat
dLngDiff = tLL2.fLng - tLL1.flng
dLatLngDiffRatio = Abs(dLatDiff) / Abs(dLngDiff)
If dLatDiff < 0 Then
'going down
If dLngDiff > 0 Then
'going down and right 90 to 180
If dLatLngDiffRatio <= 1 Then
'more right than down
Return 90 + dLatLngDiffRatio * 45
Else
'more down than right
Return 135 + Min((dLatLngDiffRatio / 20) * 45, 45)
End If
Else
'going down and left 180 to 270
If dLatLngDiffRatio <= 1 Then
'more left than down
Return 270 - dLatLngDiffRatio * 45
Else
'more down than left
Return 225 + Min((dLatLngDiffRatio / 20) * 45, 45)
End If
End If
Else
'going up
If dLngDiff > 0 Then
'going up and right 0 to 90
If dLatLngDiffRatio <= 1 Then
'more right than up
Return 90 - dLatLngDiffRatio * 45
Else
'more up than right
Return 45 - Min((dLatLngDiffRatio / 20) * 45, 45)
End If
Else
'going up and left 270 to 360
If dLatLngDiffRatio <= 1 Then
'more left than up
Return 270 + dLatLngDiffRatio * 45
Else
'more up than left
Return 315 + Min((dLatLngDiffRatio / 20) * 45, 45)
End If
End If
End If
End Sub
This gives a bit better results:Thanks, will have a look at that.
For now I have gone with a B4XBitmap with rotation.
It is indeed just for a screen display and as you say, the direction doesn't have to be very precise.
It may need a bit of adjustment, but I get the rotation in this B4A Sub:
B4X:Sub GetArrowRotation(tLL1 As TMapLatLng, tLL2 As TMapLatLng) As Int Dim dLatDiff As Double Dim dLngDiff As Double Dim dLatLngDiffRatio As Double dLatDiff = tLL2.fLat - tLL1.flat dLngDiff = tLL2.fLng - tLL1.flng dLatLngDiffRatio = Abs(dLatDiff) / Abs(dLngDiff) If dLatDiff < 0 Then 'going down If dLngDiff > 0 Then 'going down and right 90 to 180 If dLatLngDiffRatio <= 1 Then 'more right than down Return 90 + dLatLngDiffRatio * 45 Else 'more down than right Return 135 + Min((dLatLngDiffRatio / 20) * 45, 45) End If Else 'going down and left 180 to 270 If dLatLngDiffRatio <= 1 Then 'more left than down Return 270 - dLatLngDiffRatio * 45 Else 'more down than left Return 225 + Min((dLatLngDiffRatio / 20) * 45, 45) End If End If Else 'going up If dLngDiff > 0 Then 'going up and right 0 to 90 If dLatLngDiffRatio <= 1 Then 'more right than up Return 90 - dLatLngDiffRatio * 45 Else 'more up than right Return 45 - Min((dLatLngDiffRatio / 20) * 45, 45) End If Else 'going up and left 270 to 360 If dLatLngDiffRatio <= 1 Then 'more left than up Return 270 + dLatLngDiffRatio * 45 Else 'more up than left Return 315 + Min((dLatLngDiffRatio / 20) * 45, 45) End If End If End If End Sub
RBS
Sub GetArrowRotation(tLL1 As TMapLatLng, tLL2 As TMapLatLng) As Int
Dim dLatDiff As Double
Dim dLngDiff As Double
Dim dLatLngDiffRatio As Double
Dim iMaxLatLngDiffRatio As Int = 6
dLatDiff = tLL2.fLat - tLL1.flat
dLngDiff = tLL2.fLng - tLL1.flng
dLatLngDiffRatio = Abs(dLatDiff) / Abs(dLngDiff)
Log("dLatLngDiffRatio: " & dLatLngDiffRatio)
If dLatDiff < 0 Then
'going down
If dLngDiff > 0 Then
'going down and right 90 to 180
If dLatLngDiffRatio <= 1 Then
'more right than down
Return 90 + dLatLngDiffRatio * 45
Else
'more down than right
Return 135 + Min((dLatLngDiffRatio / iMaxLatLngDiffRatio) * 45, 45)
End If
Else
'going down and left 180 to 270
If dLatLngDiffRatio <= 1 Then
'more left than down
Return 270 - dLatLngDiffRatio * 45
Else
'more down than left
Return 225 + Min((dLatLngDiffRatio / iMaxLatLngDiffRatio) * 45, 45)
End If
End If
Else
'going up
If dLngDiff > 0 Then
'going up and right 0 to 90
If dLatLngDiffRatio <= 1 Then
'more right than up
Return 90 - dLatLngDiffRatio * 45
Else
'more up than right
Return 45 - Min((dLatLngDiffRatio / iMaxLatLngDiffRatio) * 45, 45)
End If
Else
'going up and left 270 to 360
If dLatLngDiffRatio <= 1 Then
'more left than up
Return 270 + dLatLngDiffRatio * 45
Else
'more up than left
Return 315 + Min((dLatLngDiffRatio / iMaxLatLngDiffRatio) * 45, 45)
End If
End If
End If
End Sub
Public Sub CalculateThirdEquilateralVertex(lat1 As Double, lon1 As Double, lat2 As Double, lon2 As Double) As List
Dim METERS_PER_DEGREE_LATITUDE As Double = 111320
Dim Middle_latitude As Double = (lat1 + lat2) / 2
Dim METERS_PER_DEGREE_LONGITUDE As Double = 111320 * Cos(Middle_latitude * cPI / 180)
Dim deltaX As Double = (lon2 - lon1) * METERS_PER_DEGREE_LONGITUDE
Dim deltaY As Double = (lat2 - lat1) * METERS_PER_DEGREE_LATITUDE
Dim a As Double = Sqrt(Power(deltaX, 2) + Power(deltaY, 2))
Dim h As Double = (Sqrt(3) / 2) * a
Dim mx As Double = deltaX / 2
Dim my As Double = deltaY / 2
Dim vx As Double = -deltaY
Dim vy As Double = deltaX
Dim moduloV As Double = Sqrt(Power(vx, 2) + Power(vy, 2))
Dim ux As Double = vx / moduloV
Dim uy As Double = vy / moduloV
Dim cx1_m As Double = mx + h * ux
Dim cy1_m As Double = my + h * uy
Dim cx2_m As Double = mx - h * ux
Dim cy2_m As Double = my - h * uy
Dim cx1_lat As Double = lat1 + (cy1_m / METERS_PER_DEGREE_LATITUDE)
Dim cx1_lon As Double = lon1 + (cx1_m / METERS_PER_DEGREE_LONGITUDE)
Dim cx2_lat As Double = lat1 + (cy2_m / METERS_PER_DEGREE_LATITUDE)
Dim cx2_lon As Double = lon1 + (cx2_m / METERS_PER_DEGREE_LONGITUDE)
Dim Result As List
Result.Initialize
Result.Add(Array As Double(cx1_lat, cx1_lon))
Result.Add(Array As Double(cx2_lat, cx2_lon))
Return Result
End Sub
Dim KILOMETERS_PER_DEGREE_LATITUDE As Double = 111.32
Dim Middle_Latitude As Double = (lat1 + lat2) / 2
Dim KILOMETERS_PER_DEGREE_LONGITUDE As Double = 111.32 * Cos(Middle_Latitude * cPI / 180)
Thanks, will have a look at that as well.Test
B4X:Public Sub CalculateThirdEquilateralVertex(lat1 As Double, lon1 As Double, lat2 As Double, lon2 As Double) As List Dim METERS_PER_DEGREE_LATITUDE As Double = 111320 Dim Middle_latitude As Double = (lat1 + lat2) / 2 Dim METERS_PER_DEGREE_LONGITUDE As Double = 111320 * Cos(Middle_latitude * cPI / 180) Dim deltaX As Double = (lon2 - lon1) * METERS_PER_DEGREE_LONGITUDE Dim deltaY As Double = (lat2 - lat1) * METERS_PER_DEGREE_LATITUDE Dim a As Double = Sqrt(Power(deltaX, 2) + Power(deltaY, 2)) Dim h As Double = (Sqrt(3) / 2) * a Dim mx As Double = deltaX / 2 Dim my As Double = deltaY / 2 Dim vx As Double = -deltaY Dim vy As Double = deltaX Dim moduloV As Double = Sqrt(Power(vx, 2) + Power(vy, 2)) Dim ux As Double = vx / moduloV Dim uy As Double = vy / moduloV Dim cx1_m As Double = mx + h * ux Dim cy1_m As Double = my + h * uy Dim cx2_m As Double = mx - h * ux Dim cy2_m As Double = my - h * uy Dim cx1_lat As Double = lat1 + (cy1_m / METERS_PER_DEGREE_LATITUDE) Dim cx1_lon As Double = lon1 + (cx1_m / METERS_PER_DEGREE_LONGITUDE) Dim cx2_lat As Double = lat1 + (cy2_m / METERS_PER_DEGREE_LATITUDE) Dim cx2_lon As Double = lon1 + (cx2_m / METERS_PER_DEGREE_LONGITUDE) Dim Result As List Result.Initialize Result.Add(Array As Double(cx1_lat, cx1_lon)) Result.Add(Array As Double(cx2_lat, cx2_lon)) Return Result End Sub
Note:
Use drawing: Polygon or polyline, boundsBuilder for camera view
Dim bmp As B4XBitmap = DrawEquilateralTriangleOnBitmap(19.4326, -99.1332, 19.4426, -99.1432)
ImageView1.SetBitmap(bmp)
Dim vertices As List = CalculateThirdEquilateralVertex(latA, lonA, latB, lonB)
Dim vertice1 As Map = vertices.Get(0)
Dim vertices As List = CalculateThirdEquilateralVertex(latA, lonA, latB, lonB)
Dim vertice1 As Map = vertices.Get(1)
Thanks, will also have a look at that one.Just for fun, here's another example using the CalculateThirdEquilateralVertex function, converting the coordinates to draw a bitmap.
B4X:Dim bmp As B4XBitmap = DrawEquilateralTriangleOnBitmap(19.4326, -99.1332, 19.4426, -99.1432) ImageView1.SetBitmap(bmp)
View attachment 165750B4X:Dim vertices As List = CalculateThirdEquilateralVertex(latA, lonA, latB, lonB) Dim vertice1 As Map = vertices.Get(0)
View attachment 165751B4X:Dim vertices As List = CalculateThirdEquilateralVertex(latA, lonA, latB, lonB) Dim vertice1 As Map = vertices.Get(1)
It may need a bit of adjustment, but I get the rotation in this B4A Sub
Test
B4X:Public Sub CalculateThirdEquilateralVertex(lat1 As Double, lon1 As Double, lat2 As Double, lon2 As Double) As List Dim METERS_PER_DEGREE_LATITUDE As Double = 111320 Dim Middle_latitude As Double = (lat1 + lat2) / 2 Dim METERS_PER_DEGREE_LONGITUDE As Double = 111320 * Cos(Middle_latitude * cPI / 180) Dim deltaX As Double = (lon2 - lon1) * METERS_PER_DEGREE_LONGITUDE Dim deltaY As Double = (lat2 - lat1) * METERS_PER_DEGREE_LATITUDE Dim a As Double = Sqrt(Power(deltaX, 2) + Power(deltaY, 2)) Dim h As Double = (Sqrt(3) / 2) * a Dim mx As Double = deltaX / 2 Dim my As Double = deltaY / 2 Dim vx As Double = -deltaY Dim vy As Double = deltaX Dim moduloV As Double = Sqrt(Power(vx, 2) + Power(vy, 2)) Dim ux As Double = vx / moduloV Dim uy As Double = vy / moduloV Dim cx1_m As Double = mx + h * ux Dim cy1_m As Double = my + h * uy Dim cx2_m As Double = mx - h * ux Dim cy2_m As Double = my - h * uy Dim cx1_lat As Double = lat1 + (cy1_m / METERS_PER_DEGREE_LATITUDE) Dim cx1_lon As Double = lon1 + (cx1_m / METERS_PER_DEGREE_LONGITUDE) Dim cx2_lat As Double = lat1 + (cy2_m / METERS_PER_DEGREE_LATITUDE) Dim cx2_lon As Double = lon1 + (cx2_m / METERS_PER_DEGREE_LONGITUDE) Dim Result As List Result.Initialize Result.Add(Array As Double(cx1_lat, cx1_lon)) Result.Add(Array As Double(cx2_lat, cx2_lon)) Return Result End Sub
Note:
Use drawing: Polygon or polyline, boundsBuilder for camera view
EDIT:
If you want measurements in kilometers, change the measurement variable
B4X:Dim KILOMETERS_PER_DEGREE_LATITUDE As Double = 111.32 Dim Middle_Latitude As Double = (lat1 + lat2) / 2 Dim KILOMETERS_PER_DEGREE_LONGITUDE As Double = 111.32 * Cos(Middle_Latitude * cPI / 180)
Dim KILOMETERS_PER_DEGREE_LATITUDE As Double = 40000 / 360 'or 10000 / 90
Dim NAUTICAL_MILES_PER_DEGREE_LATITUDE As Double = 60
Can you post code that gets the rotation of a lat/lng point line (so 2 lat/lng points)?Just for fun, here's another example using the CalculateThirdEquilateralVertex function, converting the coordinates to draw a bitmap.
B4X:Dim bmp As B4XBitmap = DrawEquilateralTriangleOnBitmap(19.4326, -99.1332, 19.4426, -99.1432) ImageView1.SetBitmap(bmp)
View attachment 165750B4X:Dim vertices As List = CalculateThirdEquilateralVertex(latA, lonA, latB, lonB) Dim vertice1 As Map = vertices.Get(0)
View attachment 165751B4X:Dim vertices As List = CalculateThirdEquilateralVertex(latA, lonA, latB, lonB) Dim vertice1 As Map = vertices.Get(1)
I just want the rotation in degrees (0 to 360) to rotate a bitmap.Do you want to include the angle between 0 and 360 degrees to obtain the third point corresponding to that rotation?
And if your solution works for you, why do you want it?
Sub GetArrowRotation4(tLL1 As TMapLatLng, tLL2 As TMapLatLng) As Int
' Let's say you want to find the rotation angle of a line connecting two points:
' Point A: Latitude 34°N, Longitude 118°W (Los Angeles)
' Point B: Latitude 37°N, Longitude 122°W (San Francisco)
' Convert latitudes And longitudes To radians:
' lat1 = 34 * π / 180
' lon1 = -118 * π / 180
' lat2 = 37 * π / 180
' lon2 = -122 * π / 180
' Calculate differences:
' Δlat = lat2 - lat1
' Δlon = lon2 - lon1
' Calculate the bearing in radians:
' bearingRad = ATan2(Δlon * Cos(lat2), Δlat)
' Convert To degrees:
' bearingDeg = bearingRad * 180 / π
Dim dLatDiff As Double
Dim dLngDiff As Double
Dim dBearingRad As Double
Dim iRotation As Int
Dim dToRad As Double = dPi / 180
Dim dY1 As Double = tLL1.fLat * dToRad
Dim dY2 As Double = tLL2.fLat * dToRad
Dim dX1 As Double = tLL1.fLng * dToRad
Dim dX2 As Double = tLL2.fLng * dToRad
dLatDiff = dY2 - dY1
dLngDiff = dX2 - dX1
dBearingRad = ATan2(dLngDiff * Cos(dY2), dLatDiff)
iRotation = dBearingRad * dToRad
Return iRotation
End Sub
?I just want the rotation in degrees (0 to 360) to rotate a bitmap.
My solution works OK, but the rotated bitmap doesn't have the exact same rotation as the lat/lng line, but not far off.
I a few examples from the net, eg:
B4X:Sub GetArrowRotation4(tLL1 As TMapLatLng, tLL2 As TMapLatLng) As Int ' Let's say you want to find the rotation angle of a line connecting two points: ' Point A: Latitude 34°N, Longitude 118°W (Los Angeles) ' Point B: Latitude 37°N, Longitude 122°W (San Francisco) ' Convert latitudes And longitudes To radians: ' lat1 = 34 * π / 180 ' lon1 = -118 * π / 180 ' lat2 = 37 * π / 180 ' lon2 = -122 * π / 180 ' Calculate differences: ' Δlat = lat2 - lat1 ' Δlon = lon2 - lon1 ' Calculate the bearing in radians: ' bearingRad = ATan2(Δlon * Cos(lat2), Δlat) ' Convert To degrees: ' bearingDeg = bearingRad * 180 / π Dim dLatDiff As Double Dim dLngDiff As Double Dim dBearingRad As Double Dim iRotation As Int Dim dToRad As Double = dPi / 180 Dim dY1 As Double = tLL1.fLat * dToRad Dim dY2 As Double = tLL2.fLat * dToRad Dim dX1 As Double = tLL1.fLng * dToRad Dim dX2 As Double = tLL2.fLng * dToRad dLatDiff = dY2 - dY1 dLngDiff = dX2 - dX1 dBearingRad = ATan2(dLngDiff * Cos(dY2), dLatDiff) iRotation = dBearingRad * dToRad Return iRotation End Sub
But can't get it to work yet.
RBS
Sub Process_Globals
Type Coordenates (Latitude As Double, Longitude As Double)
End Sub
Public Sub GetAngleCoordenates(p1 As Coordenates, p2 As Coordenates) As Double
Dim toRadian = cPI / 180 As Double
Dim dLng As Double = (p2.Longitude - p1.Longitude) * toRadian
Dim Lat1 As Double = p1.Latitude * toRadian
Dim Lat2 As Double = p2.Latitude * toRadian
Dim y As Double = Sin(dLng) * Cos(Lat2)
Dim x As Double = Cos(Lat1) * Sin(Lat2) - Sin(Lat1) * Cos(Lat2) * Cos(dLng)
Dim Angle As Double = ATan2(y,x) * toRadian
If Angle < 0 Then
Angle = 360 + Angle
End If
Return Abs(Round(Angle))
End Sub
Can't get it to work yet.?
It is of utilitarian class.
B4X:Sub Process_Globals Type Coordenates (Latitude As Double, Longitude As Double) End Sub
B4X:Public Sub GetAngleCoordenates(p1 As Coordenates, p2 As Coordenates) As Double Dim toRadian = cPI / 180 As Double Dim dLng As Double = (p2.Longitude - p1.Longitude) * toRadian Dim Lat1 As Double = p1.Latitude * toRadian Dim Lat2 As Double = p2.Latitude * toRadian Dim y As Double = Sin(dLng) * Cos(Lat2) Dim x As Double = Cos(Lat1) * Sin(Lat2) - Sin(Lat1) * Cos(Lat2) * Cos(dLng) Dim Angle As Double = ATan2(y,x) * toRadian If Angle < 0 Then Angle = 360 + Angle End If Return Abs(Round(Angle)) End Sub
Sub GetArrowRotation5(tLL1 As TMapLatLng, tLL2 As TMapLatLng) As Int
Log(tLL1.fLat & "," & tLL1.fLng & " _ " & tLL2.fLat & "," & tLL2.fLng)
Dim toRadian = cPI / 180 As Double
Dim dLng As Double = (tLL2.fLng - tLL1.flng) * toRadian
Dim Lat1 As Double = tLL1.flat * toRadian
Dim Lat2 As Double = tLL2.flat * toRadian
Dim y As Double = Sin(dLng) * Cos(Lat2)
Dim x As Double = Cos(Lat1) * Sin(Lat2) - Sin(Lat1) * Cos(Lat2) * Cos(dLng)
Dim Angle As Double = ATan2(y,x) * toRadian
Log(Angle)
If Angle < 0 Then
Angle = 360 + Angle
End If
Return Abs(Round(Angle))
End Sub
Private Lat1, Lat2, Lon1, Lon2 As Double
Private x1, y1, x2, y2, angle As Double
Lat1 = 52.62160980510403
Lon1 = -2.153019905090332
Lat2 = 52.620550308374774
Lon2 =-2.153348922729492
x1 = Lon1 * CosD(Lat1) 'converts Lon to a distance
y1 = Lat1
x2 = Lon2 * CosD(Lat2) 'converts Lon to a distance
y2 = Lat2
angle = ATan2D((y2 - y1), (x2 - x1)) 'trigonometric angle 3 o'clock, positve couterclockwise
angle = ATan2D((y1 - y2), (x2 - x1)) 'trigonometric angle 3 o'clock, positve clockwise
angle = angle + 90 'angle 12 o'clock, positve clockwise
angle = angle + 360 'only positive values
angle = angle Mod 360 'values between 0 and 360
angle = ATan2D((y1 - y2), (x2 - x1)) + 90 + 360 Mod 360 'the angle in one line
Log(angle)
angle = ATan2D((Lat1 - Lat2), (Lon2 * CosD(Lat2) - Lon1 * CosD(Lat1))) + 90 + 360 Mod 360 'all in one line
Log(angle)
Thanks, will give that a try.Try this:
B4X:Private Lat1, Lat2, Lon1, Lon2 As Double Private x1, y1, x2, y2, angle As Double Lat1 = 52.62160980510403 Lon1 = -2.153019905090332 Lat2 = 52.620550308374774 Lon2 =-2.153348922729492 x1 = Lon1 * CosD(Lat1) 'converts Lon to a distance y1 = Lat1 x2 = Lon2 * CosD(Lat2) 'converts Lon to a distance y2 = Lat2 angle = ATan2D((y2 - y1), (x2 - x1)) 'trigonometric angle 3 o'clock, positve couterclockwise angle = ATan2D((y1 - y2), (x2 - x1)) 'trigonometric angle 3 o'clock, positve clockwise angle = angle + 90 'angle 12 o'clock, positve clockwise angle = angle + 360 'only positive values angle = angle Mod 360 'values between 0 and 360 angle = ATan2D((y1 - y2), (x2 - x1)) + 90 + 360 Mod 360 'the angle in one line Log(angle) angle = ATan2D((Lat1 - Lat2), (Lon2 * CosD(Lat2) - Lon1 * CosD(Lat1))) + 90 + 360 Mod 360 'all in one line Log(angle)
Sure !Otherwise the first of these lines can be left out.
Thanks, that code works perfect indeed, using that now.Sure !
It was to explain why y1 - y2 instead of y2 - y1.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?