In Xamarin google maps for Android using C# you can create polygons like so based on this tutorial:
public void OnMapReady(GoogleMap googleMap)
{
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Xml.Linq;
namespace ConsoleApplication35
{
public class LatLng
{
public LatLng(double lat, double lng)
{
}
}
class Program
{
private static IEnumerable<LatLng> GetCoordinates(string polygon)
{
var xElement = XElement.Parse(polygon);
//var innerBoundaryCoordinates = xElement.Elements("innerBoundaryIs").FirstOrDefault()?.Value ?? "";
var outerBoundaryCoordinates = xElement.Elements("outerBoundaryIs").Single()?.Value ?? "";
return outerBoundaryCoordinates
.Split(' ')
.Select(latLng =>
{
var splits = latLng.Split(',');
var lat = double.Parse(splits[0], CultureInfo.InvariantCulture);
var lng = double.Parse(splits[1], CultureInfo.InvariantCulture);
return new LatLng(lat, lng);
});
}
static void Main()
{
const string header = "description,name,label,geometry";
var latLngs = File.ReadLines("file.csv")
.SelectMany(x => x.Split(new[] { header }, StringSplitOptions.RemoveEmptyEntries)) //all geometry`s in one array
.Select(x => x.Split('"'))
.SelectMany(x => GetCoordinates(x[1]))
.ToArray();
}
}
}
If I understand correctly, the question is how to parse the above CSV file.
Each line (except the first one with headers) can be represented with the following class:
class MapEntry
{
public string Description { get; set; }
public string Name { get; set; }
public string Label { get; set; }
public IEnumerable<LatLng> InnerCoordinates { get; set; }
public IEnumerable<LatLng> OuterCoordinates { get; set; }
}
Note the Inner
and Outer
coordinates. They are represented inside the XML by outerBoundaryIs
(required) and innerBoundaryIs
(optional) elements.
A side note: the Highland
line in your post is incorrect - you seem to trimmed part of the line, leading to incorrect XML (<outerBoundaryIs>...</innerBoundaryIs>
).
Here is the code that does the parsing:
static IEnumerable<MapEntry> ParseMap(string csvFile)
{
return from line in File.ReadLines(csvFile).Skip(1)
let tokens = line.Split(new[] { ',' }, 4)
let xmlToken = tokens[3]
let xmlText = xmlToken.Substring(1, xmlToken.Length - 2)
let xmlRoot = XElement.Parse(xmlText)
select new MapEntry
{
Description = tokens[0],
Name = tokens[1],
Label = tokens[2],
InnerCoordinates = GetCoordinates(xmlRoot.Element("innerBoundaryIs")),
OuterCoordinates = GetCoordinates(xmlRoot.Element("outerBoundaryIs")),
};
}
static IEnumerable<LatLng> GetCoordinates(XElement node)
{
if (node == null) return Enumerable.Empty<LatLng>();
var element = node.Element("LinearRing").Element("coordinates");
return from token in element.Value.Split(' ')
let values = token.Split(',')
select new LatLng(XmlConvert.ToDouble(values[0]), XmlConvert.ToDouble(values[1]));
}
I think the code is self explanatory. The only details to be mentioned are:
let tokens = line.Split(new[] { ',' }, 4)
Here we use the string.Split
overload that allows us to specify the maximum number of substrings to return, thus avoiding the trap of processing the commas inside the XML token.
and:
let xmlText = xmlToken.Substring(1, xmlToken.Length - 2)
which strips the quotes from the XML token.
Finally, a sample usage for your case:
foreach (var entry in ParseMap(csv_file_full_path))
{
PolylineOptions geometry = new PolylineOptions()
foreach (var item in entry.OuterCoordinates)
geometry.Add(item)
Polyline polyline = mMap.AddPolyline(geometry);
}
UPDATE: To make Xamarin happy (as mentioned in the comments), replace the File.ReadLines
call with a call to the following helper:
static IEnumerable<string> ReadLines(string path)
{
var sr = new StreamReader(Assets.Open(path));
try
{
string line;
while ((line = sr.ReadLine()) != null)
yield return line;
}
finally { sr.Dispose(); }
}
I'm not sure to understand your questions but I think that can help:
You have to read the csv file line by line and foreach line extract the third argument, remove the quote and read the result with a XMLReader for extract the line you want (coordinate). After you split the result on white space, you get the list of LatLng and you split each LatLng on ",", then you've got all the information you need.
System.IO.StreamReader file = new System.IO.StreamReader(@"file.csv");
string line = file.ReadLine(); //escape the first line
while((line = file.ReadLine()) != null)
{
var xmlString = line.Split({","})[2]; // or 3
**Update**
xmlString = xmlString.Replace("\"","")
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
reader.ReadToFollowing("coordinate");
string coordinate = reader.Value;
PolylineOptions geometry = new PolylineOptions();
var latLngs = coordinate.Split({' '});
foreach (var latLng in latLngs)
{
double lat = 0;
double lng = 0;
var arr = latLng.Split({','});
double.TryParse(arr[0], out lat);
double.TryParse(arr[1], out lng);
geometry.Add(new LatLng(lat, lng));
}
Polyline polyline = mMap.AddPolyline(geometry);
// Do something with your polyline
}
}
file.Close();