## Simple Offline OSM Maps viewer

User projects written in or related to FreeBASIC.
jepalza
Posts: 74
Joined: Feb 24, 2010 10:08
Location: Spain (Bilbao)

### Simple Offline OSM Maps viewer

This is a simple OSM (Open Street Maps) viewer. Only for fun!!!
Take "snapshot" from OSM Web, max 50000 NODE.

Example, Guggenheim Bilbao:
https://www.openstreetmap.org/export#ma ... 3/-2.93285
And export it in "osm" (xml text) format.

Another complex example, my little town, Sopelana:
https://www.openstreetmap.org/#map=15/43.3792/-2.9816 (this with almost 50000 NODES)

Using FILL Routine from:
viewtopic.php?t=24242&start=15

named: fill.bas

Code: Select all

`Sub fill_polygon(a() As Long, bound As Integer, ByVal c As ULong)   'translation of a c snippet by Angad   ' jepalza: variable "bound"   'source of c code: http://code-heaven.blogspot.it/2009/10/simple-c-program-for-scan-line-polygon.html   Dim As Long      i, j, k, dy, dx, x, y, temp   Dim As Long      xi(0 to bound)   Dim As Single    slope(0 to bound)      'join first and last vertex   a(bound, 0) = a(0, 0)   a(bound, 1) = a(0, 1)   For i = 0 To bound - 1      dy = a(i+1, 1) - a(i, 1)      dx = a(i+1, 0) - a(i, 0)      If (dy = 0) Then slope(i) = 1.0      If (dx = 0) Then slope(i) = 0.0      If (dy <> 0) AndAlso (dx <> 0) Then slope(i) = dx / dy   Next i   For y = 0 to RESX - 1      k = 0      ' using FB's short-cut operators (which C doesn't have!)      For i = 0 to bound - 1         If (a(i, 1) <= y AndAlso a(i+1, 1) > y) OrElse _             (a(i, 1) > y AndAlso a(i+1, 1) <= y) Then            xi(k) = CLng(a(i, 0) + slope(i) * (y - a(i, 1)))            k += 1         End If      Next i      For j = 0 to k - 2         'Arrange x-intersections in order         For i = 0 To k - 2            If (xi(i) > xi(i + 1)) Then               temp = xi(i)               xi(i) = xi(i + 1)               xi(i + 1) = temp            End If         Next i      Next j      'line filling      For i = 0 To k - 2 Step 2         Line (xi(i), y)-(xi(i + 1) + 1, y), c      Next i   Next yEnd Sub`

viewer:

Code: Select all

`' variables de uso generalDim As String sa, scDim As Integer a, b, c, d, e, f, g, h, nDim shared As Integer RESX,RESY,MICOLORRESX=1280RESY=1000#Include "fill.bas"' WAY ID, NODO ID, numero de nodos leidos, num. de bordes leidos, num. de ways leidas, y su numero de nodos internosDim As ulong WID,NIDDim As Integer NODES,BOUNDS,WAYS,WAYSN Dim As ULong REF ' las asociaciones leidas dentro de los WAYDim As Double LAT,LON ' NODESDim As Double MINLAT,MAXLAT,MINLON,MAXLON ' BOUNDSDim As Integer MAXNODES=50000 ' por el momento, maximo en 50k, por que es el limite impuesto por OSM en los EXPORT!!MINLAT=9999MAXLAT=-9999MINLON=9999MAXLON=-9999BOUNDS=0Dim As Integer hayway=0 ' si hay WAY se activa para ir leyendo todos los nodos que lo componenDim shared As Double nodosc(MAXNODES,1) ' latitud y longitud de nodos leidosDim shared As ULong nodosi(MAXNODES) ' su indentificacionDim shared As uLong waysi(5000,1000) ' ways leidas y su asociaciones de nodos dentro del way, vamos, la polilineaDim As Integer x1,x2,y1,y2,xini,yiniDim As Double factorx,factory ' no es real, falla en cuadratura, pero es suficiente para ver mapaScreenRes RESX,RESY,32Line(0,0)-(RESX,RESY), RGB(255,255,255),bf ' fondo blanco , para fondo negro quitarDim Shared As long w(1000,1) ' guarda las coord. X e Y para la rutina de relleno FILLsc=CommandIf sc="" Then sc="Guggenheim_Bilbao.osm" ' para pruebasOpen sc For Input As 1'Open "salida.txt" For Output As 2While Not Eof(1)   Line Input #1, sa      If InStr(sa,"<node ") Then      a=InStr(sa,"visible=")      If Mid(sa,a+8,5)="false" Then end If      a=InStr(sa,"id=")      NID=Val(Mid(sa,a+4))      a=InStr(sa,"lat=")      LAT=Val(Mid(sa,a+5))      a=InStr(sa,"lon=")      LON=Val(Mid(sa,a+5))      'Print "NODO :";NODE,NID,LAT,LON      nodosc(NODES,0)=LON      nodosc(NODES,1)=LAT      nodosi(NODES)=NID      ' si no se localiza BOUNDS, los calculo segun leo NODOS      If BOUNDS=0 Then         if LAT<MINLAT Then MINLAT=LAT         if LAT>MAXLAT Then MAXLAT=LAT         if LON<MINLON Then MINLON=LON         if LON>MAXLON Then MAXLON=LON         factorx=RESX/Abs(MAXLON-MINLON)         factory=RESY/Abs(MAXLAT-MINLAT)      End If      'Sleep      NODES+=1      If NODES>MAXNODES Then Print "Superados 50000 nodos!!!":Sleep:end   EndIf   If InStr(sa,"<bounds ") Then      a=InStr(sa,"minlat=")      MINLAT=Val(Mid(sa,a+8))      a=InStr(sa,"maxlat=")      MAXLAT=Val(Mid(sa,a+8))      a=InStr(sa,"minlon=")      MINLON=Val(Mid(sa,a+8))      a=InStr(sa,"maxlon=")      MAXLON=Val(Mid(sa,a+8))      Print "BOUND ENCONTRADO:";BOUNDS,MINLAT,MAXLAT,MINLON,MAXLON':sleep      factorx=RESX/Abs(MAXLON-MINLON)      factory=RESY/Abs(MAXLAT-MINLAT)      BOUNDS+=1   EndIf      ' si tenemos WAY vamos leyendo sus asociaciones   If hayway=1 Then      If InStr(sa,"<nd ") Then         a=InStr(sa,"ref=")         REF=Val(Mid(sa,a+5))         waysi(WAYS-1,n)=REF         'Print WAYS,REF         n+=1      EndIf         EndIf         If InStr(sa,"<way ") Then      a=InStr(sa,"visible=")      If Mid(sa,a+8,5)="false" Then end If      a=InStr(sa,"id=")      WID=Val(Mid(sa,a+4)) ' no es necesario por ahora, pero lo guardo para un futuro      'Print "WAY  :";WAYS,WID      'sleep      WAYS+=1      n=0      hayway=1   EndIf   If InStr(sa,"</way>") Then ' se acabo, salimos de buscar WAY      'For f=0 To a      '   w(f,0)=0      '   w(f,1)=0      'Next      a=0            'Print "BOUND:";BOUNDS,MINLAT,MAXLAT,MINLON,MAXLON      'ScreenLock      MICOLOR=RGB(Rnd(1)*255,Rnd(1)*255,Rnd(1)*255)      For f=0 To n-1         NID=waysi(WAYS-1,f)         For g=0 To NODES-1            If NID=nodosi(g) Then               LON=nodosc(g,0)               LAT=nodosc(g,1)            EndIf         Next         'Print NID,LON,LAT         If a Then            x2=((LON-MINLON)*factorx)'*1000            y2=((LAT-MINLAT)*factory)'*1000            'Print x1,y1,x2,y2            Line (x1,RESY-y1)-(x2,RESY-y2),MICOLOR            x1=x2            y1=y2            w(a,0)=x1            w(a,1)=RESY-y1            a+=1         EndIf         If a=0 Then            a=1            x1=((LON-MINLON)*factorx)'*1000            y1=((LAT-MINLAT)*factory)'*1000            xini=x1 ' las guardo para luego calcular poligono cerrado o no            yini=y1            w(a-1,0)=x1            w(a-1,1)=RESY-y1         EndIf      Next      'ScreenUnLock      ' si coinciden punto de entrada y salida, es poligono cerrado, rellenamos      If xini=x1 And yini=y1 And a<1000 Then ' si el FILL tiene mas de 1000 elementos, no actua, porque da error         fill_polygon w(),a-1,MICOLOR      EndIf      If BOUNDS=0 Then          Exit while      EndIf      hayway=0   EndIf   Wend   ' activar para ver los NODOS      'ScreenLock      '   For g=0 To NODES-1      '      NID=nodosi(g)      '      LON=nodosc(g,0)      '      LAT=nodosc(g,1)      '      x2=((LON-MINLON)*factorx)'*1000      '      y2=((LAT-MINLAT)*factory)'*1000      '      Circle (x2,RESY-y2),2,NID      '   Next      'ScreenUnLockPrint "WAY   TOTAL :";WAYSPrint "NODE  TOTAL :";NODESPrint "BOUND TOTAL :";BOUNDSIf BOUNDS=0 Then Print "BOUND CALCULADO:";MINLAT,MAXLAT,MINLON,MAXLONClose 1, 2Print "...FIN"sleep`

notes:
-is not perfect, not control about NODES number, and maybe can fail.
-colors is random, only for fun

It's good skeleton for a big maps project!!

edit: little bug with bound out
Last edited by jepalza on Jun 21, 2021 16:48, edited 1 time in total.
Posts: 2340
Joined: May 24, 2007 22:10
Location: The Netherlands

### Re: Simple Offline OSM Maps viewer

Hi, that code could be useful, but I get an error with "-exx" compile option:
"Aborting due to runtime error 6 (out of bounds array access) at line 156 of test.bas::()"
The maps is shown briefly, before the runtime error. Without "-exx" it segfaults.

Also with 64-fbc the code does not compile, but that can be fixed quickly by changing array w() to type long.
jepalza
Posts: 74
Joined: Feb 24, 2010 10:08
Location: Spain (Bilbao)

### Re: Simple Offline OSM Maps viewer

I'm using lastest FB version (1.08) 32 bits in win7 without -exx, and i's running good.
I'm working on it in order to get best performance, and then publish it.

This first version not verify bounds limits, and if they goes out of limits, crashed.

edit: simple check in NODES limit to 50k in first post. This 50k limit is from OSM EXPORT in format XML. Did check my code with FB v1.08 x64 in Win10, and it's run fine.