Individuare il punto di intersezione degli angoli di direzione di due elementi geografici rispetto all'osservatore

Da Gambas-it.org - Wikipedia.

E' possibile conoscere la propria posizione sulla mappa, se non si è in possesso di dispositivo di rilevamento delle porprie coordinate (GPS, Galileo, etc), purché si disponga di una bussola (possibilmente di tipo "da rilevamento" o "da orientamento").

Bisognerà effettuare mediante la bussola la misurazione degli angoli di direzione che la propria posizione (ossia quella dell'osservatore) forma con ciascuno dei due elementi geografici reali rispetto alla direzione al nord (azimut). [Nota 1]

 1° elemento      Ⓝ           2° elemento
  geografico      :            geografico
      :               
       \          :              /
         \        :            /
          \       :          /
            \     :        /
             \  a :  b   /
               \^^:^^^^/
                \ :  /
                 \:/
                  🔭
              Osservatore

Ottenuti gli angoli dei due azimut (a° e b°), si potrà anche ottenere il punto di intersezione delle due direzioni che congiungono rispettivamente il 1° e il 2° elemento geografico con la posizione dell'Osservatore.

Mostriamo di seguito un possibile programma Gambas per ottenere il punto di intersezione delle due direzioni rispetto all'Osservatore, e quindi la posizione dell'Osservatore medesimo sulla mappa.
E' necessario attivare il Componente gb.map .
Modalità di funzionamento:
1) aumentare lo zoom della mappa al valore desiderato, usando l'apposito Slider in alto a sinistra sulla mappa oppure ruotando la rotellina del mouse;
2) cliccare con il tasto centrale del mouse sul primo punto (preso sempre in considerazione in senso orario rispetto a quello che sarà il secondo punto);
3) inserire i gradi rilevati dalla bussola e premere OK;
4) cliccare con il tasto centrale del mouse sul secondo punto (preso sempre in considerazione in senso orario rispetto a quello che è il primo punto);
3) inserire i gradi rilevati dalla bussola e premere OK.
Il punto di convergenza delle rette che attraversano i due punto presi in considerazione rappresenta il punto ove l'osservatore si trova sulla mappa.

Private MapView1 As MapView
Private pn As Panel
Private c As Short[]
Private r As Short
Private mmpp As New MapPoint[]


Public Sub Form_Open()

 With Me
   .W = Screen.AvailableWidth
   .H = Screen.AvailableHeight
   .Arrangement = Arrange.Fill
 End With
 
' Imposta la dimensione del raggio:
 r = 30000
 
 With MapView1 = New MapView(Me) As "MapView1"
  .Map.AddTile("topo", "https://a.tile.opentopomap.org/{z}/{x}/{y}.png")
  .Font.Size = 8
  .Map["topo"].Copyright = "© OpenTopoMap"
' Individua dapprima l'Oggetto "Figlio" della "MapView", che è un "Panel":
  pn = .Children[0]
 End With 
  
End

Public Sub Form_Close()
 
 Quit
 
End 


Public Sub MapView1_MouseWheel()
 
 Me.Caption = "Zoom = " & CStr(MapView1.Map.Zoom)
 
End

Public Sub MapView1_MouseDown()
 
 Dim pt As New Point(Mouse.X, Mouse.Y)
 
 Me.Caption = "Lat. " & Format(MapView1.Map.PixelToMapPointRel(pt).Lat, "0.000000") &
              " -  Lon. " & Format(MapView1.Map.PixelToMapPointRel(pt).Lon, "0.000000")
 
End

Public Sub MapView1_MouseUp()
 
 Dim pt As Point
 
 If Not Mouse.Middle Then 
   Me.Caption = "Zoom = " & CStr(MapView1.Map.Zoom)
   Return 
 Endif
 
 pt = New Point(Mouse.X, Mouse.Y)

 If Object.IsValid(c) Then 
   If c.Count == 2 Then
     c = Null
     mmpp = Null
   Endif
 Endif
 If Not Object.IsValid(c) Then
    c = New Short[]
    mmpp = New MapPoint[]
 Endif
 
 c.Push(ImmissioneGradi())
 
' Si usa l'Oggetto "MapPoint" per garantire la coerenza del puntamento su un punto della mappa anche nel caso di spostamento o variazione dello zoom della mappa medesima:
 mmpp.Push(MapView1.Map.PixelToMapPointRel(pt))
 
 If mmpp.count == 2 Then
    Me.Caption = "Distanza fra i due punti: m. " & Format(MapPoint.Distance(mmpp[0], mmpp[1]), "0.00") &
    "  -  Bearing: " & Geo.DecToSex(MapPoint.Bearing(mmpp[0], mmpp[1]), 0)
 Endif 
 
End

Public Sub MapView1_Draw()
 
 If Not Object.IsValid(c) Then
   Return 
 Else
   If c.Count < 2 Then Return
 Endif 
 
 With Paint
' Disegna sull'Oggetto "Figlio" del "Panel", che è una "DrawingArea", la stessa che la Classe "MapView" usa per mostrare la mappa:
   .Begin(pn.Children[0])
' Disegna il primo obiettivo con un cerchietto rosso:
   .Brush = Paint.Color(Color.Red)
   .Arc(MapView1.Map.MapPointToPixelRel(mmpp[0]).X, MapView1.Map.MapPointToPixelRel(mmpp[0]).Y, 3, Rad(0), Rad(360), False)
' Disegna la linea del primo obiettivo:
   .MoveTo(MapView1.Map.MapPointToPixelRel(mmpp[0]).X, MapView1.Map.MapPointToPixelRel(mmpp[0]).Y)
   .LineTo(MapView1.Map.MapPointToPixelRel(mmpp[0]).X + (r * Cos(Rad(c[0]))), MapView1.Map.MapPointToPixelRel(mmpp[0]).Y + (r * Sin(Rad(c[0]))))
   .Stroke
   .MoveTo(MapView1.Map.MapPointToPixelRel(mmpp[0]).X, MapView1.Map.MapPointToPixelRel(mmpp[0]).Y)
' Aggiunge 180° per disegnare anche la parte opposta del raggio, completando così il diametro:
   .LineTo(MapView1.Map.MapPointToPixelRel(mmpp[0]).X + (r * Cos(Rad(c[0] + 180))), MapView1.Map.MapPointToPixelRel(mmpp[0]).Y + (r * Sin(Rad(c[0] + 180))))
   .Stroke
   
' Disegna il secondo obiettivo con un cerchietto rosso:
   .Brush = Paint.Color(Color.Blue)
   .Arc(MapView1.Map.MapPointToPixelRel(mmpp[1]).X, MapView1.Map.MapPointToPixelRel(mmpp[1]).Y, 3, Rad(0), Rad(360), False)
' Disegna la linea del secondo obiettivo:
   .MoveTo(MapView1.Map.MapPointToPixelRel(mmpp[1]).X, MapView1.Map.MapPointToPixelRel(mmpp[1]).Y)
   .LineTo(MapView1.Map.MapPointToPixelRel(mmpp[1]).X + (r * Cos(Rad(c[1]))), MapView1.Map.MapPointToPixelRel(mmpp[1]).Y + (r * Sin(Rad(c[1]))))
   .Stroke
   .MoveTo(MapView1.Map.MapPointToPixelRel(mmpp[1]).X, MapView1.Map.MapPointToPixelRel(mmpp[1]).Y)
' Aggiunge 180° per disegnare anche la parte opposta del raggio, completando così il diametro:
   .LineTo(MapView1.Map.MapPointToPixelRel(mmpp[1]).X + (r * Cos(Rad(c[1] + 180))), MapView1.Map.MapPointToPixelRel(mmpp[1]).Y + (r * Sin(Rad(c[1] + 180))))
   .Stroke
   .End
 End With
 
End


Private Function ImmissioneGradi() As Short
 
 Dim s As String
 
 s = InputBox("Immettere un valore intero (tra 0 e 360):")
 If IsNull(s) Then ImmissioneGradi() 
 If (Not IsNumber(s)) Or (Val(s) > 360) Or (Val(s) < 0) Then ImmissioneGradi()  
 
' Poiché il punto corrispondente a 0° è posto tra il I e il IV quadrante, sottrae 90° per porlo tra il I e il II quadrante lungo il verso ideale del Polo Nord magnetico:
 Return (CShort(Val(s)) - 90)
 
End


Note

[1] Come è noto, il Polo Nord "magnetico" non coincide esattamente con il Polo Nord "geografico" (che corrisponde a una delle estremità dell'asse di rotazione terrestre). Per ottenere la direzione esatta del Polo Nord "geografico", è necessario compensare la declinazione magnetica, ossia lo scostamento della direzione magnetica da quella geografica.


Riferimenti