B4J Code Snippet Load and Save KML file

Star-Dust

Expert
Licensed User
Several have asked how to create a KML file (or KMZ if compressed) starting from a map generated with the GMap library.

A KMZ specification is not simply a compressed KML file, but it can also contain other files, such as marker images if they are customized.

I started from a precious example created by @klaus in this thread. Indeed I take this opportunity and thank him warmly, because in addition to making his project available, it allowed him to know the GoogleMapExt class code and was very instructive.

Starting from this project, I can save the polygons created in a KML with this sub and be opened by Google Earth or absorbed in Google Map or My Map.

You can extend this library to add PolyLine, Markers and other shapes. This then is up to you. I believe that giving the starting point and then allowing others to develop on it is more useful than giving everything ready.

I omitted some function that allow you to find the name and the color of the Polygon, but I am sure you will be able to do it yourself.

Save KML:
SaveKml(file.DirApp,"mypol.kml")

Sub SaveKml(Path As String, NameFile As String)
    Dim PolygonColor As String = "ff0f0f0f" ' gray

    ' KML String
    Dim Kml As String = $"<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
    <Document>
     <name>${NameFile.Replace(".kml","")}</name>
####
[[]]
    </Document>
</kml>"$

        'Style Polygon
        Dim Style As String =""
        For ii= 0 To ListPolygon.Size-1
            ' If possible, the color of the polygons should be different
            Style=$"${Style}
            <Style id="poly-${ii}">
                  <LineStyle>
                    <color>ff000000</color>
                    <width>1.2</width>
                  </LineStyle>
                  <PolyStyle>
                    <color>${PolygonColor}</color>
                    <fill>1</fill>
                    <outline>1</outline>
                  </PolyStyle>
            </Style>"$
        Next

        'Polygon
        Dim PolygonKml As String = $"
    <Folder>
     <name>Congregazioni</name>"$
        Private joPoint, joCurrentDrawPath As JavaObject
        Private joCurrentDrawPath As JavaObject
        joCurrentMapShape = joCurrentMapShape.InitializeNewInstance("com.lynden.gmapsfx.shapes.Polygon", Null)
        Dim NumeroPoligono As Int = 0
        For Each mpg As MapPolygon In ListPolygon
            joCurrentMapShape = mpg
            joCurrentDrawPath = joCurrentDrawPath.InitializeNewInstance("com.lynden.gmapsfx.javascript.object.MVCArray", Null)
            joCurrentDrawPath = joCurrentMapShape.RunMethod("getPath", Null)

        PolygonKml=$"${Poligoni}
      <Placemark>
        <name>${NamePolygon.get(i))}</name>
        <styleUrl>#poly-$1.0{NumeroPoligono}</styleUrl>
        <Polygon>
            <outerBoundaryIs>
            <LinearRing>
            <tessellate>1</tessellate>
            <coordinates>"$
   
            Private i As Int
            Private Size As Int = joCurrentDrawPath.RunMethod("getLength", Null)
 
            For i = 0 To Size - 1
                joPoint = joCurrentDrawPath.RunMethod("getAt", Array As Object (i))
                Private ll As LatLng = joPoint.InitializeNewInstance("com.lynden.gmapsfx.javascript.object.LatLong", Array(joPoint))
                PolygonKml=$"${PolygonKml}
                ${ll.Longitude},${ll.Latitude},0"$
            Next
            PolygonKml=$"${PolygonKml}
            </coordinates>
            </LinearRing>
              </outerBoundaryIs>
      </Polygon>
    </Placemark>"$
            NumeroPoligono=NumeroPoligono+1
        Next
        PolygonKml=$"${PolygonKml}
        </Folder>"$


        Kml=Kml.Replace("[[]]",PolygonKml).Replace("####",Style)
        File.WriteString(Path,NameFile,Kml)

End Sub
P.S: A little note:
The characters #### and [[]] inserted in the KML string, are inserted to be subsequently replaced by the style and coordinates of the polygons. (see row 76)

Each style will be assigned an ID. Each polygon can recall a style by indicating its ID. In this example I numbered them with poly-nn... to facilitate the example.
 
Last edited:

Star-Dust

Expert
Licensed User
For those who want to add markers this is the format.

Obviously I added a staff for the Polygons but empty

Marker:
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2">
<Document>
<name>DocumentName</name>

<Folder>
'''''' Polygon
</Folder>

<Folder>
<name>Marker</name>
    <Placemark>
        <name>Star-Dust</name>
        <address>12 Street , 12 NY</address>
        <description>Developer</description>
        <MultiGeometry>
            <Point>
            <coordinates>18.00000,37.000000,0</coordinates>
            </Point>
        </MultiGeometry>
    </Placemark>

    <Placemark>
        <name>DOnPerigno</name>
        <address>20 Street , 20 BK</address>
        <description>Developer</description>
        <MultiGeometry>
            <Point>
            <coordinates>18.00000,38.000000,0</coordinates>
            </Point>
        </MultiGeometry>
    </Placemark>

</Folder>
</Document>
</kml>
 

Star-Dust

Expert
Licensed User
To the code already posted, I add a method to load the KML files on the map. In case you have a KMZ, you need to unzip it and upload doc.kml.

P.S. For convenience I don't read the polygon style labels, so I assign the colors around a list of colors.
N.B. This method can also be used for Markers .... but you will know how to modify the source to obtain this too

B4X:
Private Sub LoadMapKML(Path As String,Namefile As String)
    Dim WheelColor as Int = 0
    Dim Kml As String = File.ReadString(Path,Namefile)

    Dim Placemarks As Matcher = Regex.Matcher("<Placemark>[\s\S]*?<\/Placemark>",Kml)
 
    Do While Placemarks.Find
        Dim Placemark As String = Placemarks.Match
        If Placemark.IndexOf("<Polygon>")>-1 Then ' ONLY FOR POLYGON
            Dim ListaCoordinate As List
            ListaCoordinate.Initialize
         
            Dim Name As Matcher =Regex.Matcher("<name>[\s\S]*?<\/name>",Placemark)
            Dim Polygons As Matcher = Regex.Matcher("<Polygon>[\s\S]*?<\/Polygon>",Placemark)
            Do While Polygons.Find
                ' singolo poligono
                Dim Polygon As String = Polygons.Match
                Dim Coordinates As Matcher = Regex.Matcher("<coordinates>[\s\S]*?<\/coordinates>",Polygon)
                Do While Coordinates.Find
                    Dim Coordinate As String = Coordinates.Match
                    Coordinate=Coordinate.Replace(Chr(10),"").Replace(Chr(13),"").Replace("<coordinates>","").Replace("</coordinates>","").Trim
                    Dim ArrayCoordinate() As String = Regex.Split(" ",Coordinate)
                    For Each RowCoo As String In ArrayCoordinate
                        Dim SingleCoord() As String = Regex.Split(",",RowCoo)
                        Dim LatLon As LatLng
                        LatLon.Initialize(SingleCoord(1),SingleCoord(0))
                        ListaCoordinate.Add(LatLon)
                    Next
                Loop
            Loop
            'Add Polygon
            If Name .Find Then
                log(Name) ' Name of Polygon
            End If
            Private mpg As MapPolygon = GMap.AddPolygon(ListaCoordinate, LineWidthPolygon, LineColorPolygon, SelectColor(WheelColor), OpacityPolygon)
            WheelColor = WheelColor  + 1
        End If
    Loop
End Sub

Sub SelectColor(ColorProgress As Int) As Paint
    Dim C As Paint
    Select ColorProgress mod 16
        Case 0
            C=fx.Colors.Black
        Case 1
            c=fx.Colors.Blue
        Case 2
            c=fx.Colors.Yellow
        Case 3
            c=fx.Colors.DarkGray
        Case 4
            c=fx.Colors.Green
        Case 5
            c=fx.Colors.Magenta
        Case 6
            c=fx.Colors.RGB(120,40,60)
        Case 7
            c=fx.Colors.Gray
        Case 8
            c=fx.Colors.Red
        Case 9
            c=fx.Colors.Cyan
        Case 10
            c=fx.Colors.RGB(100,100,0)
        Case 11
            c=fx.Colors.RGB(250,50,100)
        Case 12
            c=fx.Colors.RGB(100,10,180)
        Case 13
            c=fx.Colors.RGB(150,100,50)
        Case 14
            c=fx.Colors.RGB(50,150,100)
        Case Else
            c=fx.Colors.RGB(180,180,180)
    End Select

    Return C
End Sub
 
Last edited:
Top