using System; using System.ComponentModel; using System.Collections.Generic; using System.Diagnostics; using System.Text; using System.Xml; using System.Globalization; using System.Windows.Forms; namespace FastReport.Map.Import.Osm { internal class OsmMapImport : MapImport { #region Fields private MapObject map; private MapLayer layer; private XmlDocument document; private Dictionary nodes; private Dictionary ways; private Dictionary relations; private double normalScale; private BoundingBox realOsmBox; #endregion // Fields #region Constructors public OsmMapImport() { map = new MapObject(); document = new XmlDocument(); nodes = new Dictionary(); ways = new Dictionary(); relations = new Dictionary(); normalScale = 0.0; realOsmBox = new BoundingBox(); map.MercatorProjection = false; } #endregion // Constructors #region Private Methods private double CalculateNormalScale() { double scaleByWidth = map.Width / (realOsmBox.MaxX - realOsmBox.MinX); double scaleByHeight = map.Height / (realOsmBox.MaxY - realOsmBox.MinY); return scaleByWidth < scaleByHeight ? scaleByWidth : scaleByHeight; } private void NormalizeLayerBox() { layer.Box.MinX = 0.0; layer.Box.MinY = 0.0; layer.Box.MaxX = (realOsmBox.MaxX - realOsmBox.MinX) * normalScale; layer.Box.MaxY = (realOsmBox.MaxY - realOsmBox.MinY) * normalScale; } private double ConvertToDouble(string value) { return Double.Parse(value, CultureInfo.InvariantCulture); } private void LoadBounds() { XmlNode bounds = document.GetElementsByTagName("bounds")[0]; realOsmBox.MinX = ConvertToDouble(bounds.Attributes["minlon"].Value); realOsmBox.MinY = ConvertToDouble(bounds.Attributes["minlat"].Value); realOsmBox.MaxX = ConvertToDouble(bounds.Attributes["maxlon"].Value); realOsmBox.MaxY = ConvertToDouble(bounds.Attributes["maxlat"].Value); normalScale = CalculateNormalScale(); } private void NormalizeNodes() { foreach (OsmNode node in nodes.Values) { node.Lon = (node.Lon - realOsmBox.MinX) * normalScale; node.Lat = (node.Lat - realOsmBox.MinY) * normalScale; } } private void LoadNodes() { foreach (XmlNode node in document.GetElementsByTagName("node")) { ulong id = Convert.ToUInt64(node.Attributes["id"].Value); double lon = ConvertToDouble(node.Attributes["lon"].Value); double lat = ConvertToDouble(node.Attributes["lat"].Value); Dictionary tags = new Dictionary(); foreach (XmlNode tagNode in node.ChildNodes) { if (tagNode.Name == "tag") { tags.Add(tagNode.Attributes["k"].Value, tagNode.Attributes["v"].Value); } } nodes.Add(id, new OsmNode(lat, lon, tags)); } NormalizeNodes(); } private void LoadWays() { foreach (XmlNode node in document.GetElementsByTagName("way")) { ulong id = Convert.ToUInt64(node.Attributes["id"].Value); List refs = new List(); Dictionary tags = new Dictionary(); foreach (XmlNode refNode in node.ChildNodes) { if (refNode.Name == "nd") { refs.Add(Convert.ToUInt64(refNode.Attributes["ref"].Value)); } if (refNode.Name == "tag") { tags.Add(refNode.Attributes["k"].Value, refNode.Attributes["v"].Value); } } ways.Add(id, new OsmWay(refs, tags)); } } private void LoadRelations() { foreach (XmlNode node in document.GetElementsByTagName("relation")) { ulong id = Convert.ToUInt64(node.Attributes["id"].Value); List nodeRefs = new List(); List wayRefs = new List(); foreach (XmlNode refNode in node.ChildNodes) { if (refNode.Name == "member") { switch (refNode.Attributes["type"].Value) { case "node": nodeRefs.Add(Convert.ToUInt64(refNode.Attributes["ref"].Value)); break; case "way": wayRefs.Add(Convert.ToUInt64(refNode.Attributes["ref"].Value)); break; } } } relations.Add(id, new OsmRelation(nodeRefs, wayRefs)); } } private void ConvertWays() { List lines = new List(); List polygons = new List(); foreach (OsmWay way in ways.Values) { bool isPolygon = false; ShapePolygon shape = null; if (way.NodeRefs[0] == way.NodeRefs[way.NodeRefs.Count - 1]) { shape = new ShapePolygon(); isPolygon = true; } else { shape = new ShapePolyLine(); isPolygon = false; } shape.Parts.Clear(); PointD[] part = new PointD[way.NodeRefs.Count]; shape.Parts.Add(part); for (int i = 0; i < way.NodeRefs.Count; i++) { PointD point = new PointD(); point.X = nodes[way.NodeRefs[i]].Lon; point.Y = nodes[way.NodeRefs[i]].Lat; part[i] = point; nodes[way.NodeRefs[i]].HasParent = true; } foreach (KeyValuePair tag in way.Tags) { shape.SpatialData.SetValue(tag.Key, tag.Value); } if (isPolygon) { polygons.Add((ShapePolygon)shape); } else { lines.Add((ShapePolyLine)shape); } } if (lines.Count > 0) { layer = new MapLayer(); NormalizeLayerBox(); layer.Type = LayerType.Line; map.Layers.Add(layer); foreach (ShapePolyLine line in lines) { line.Box = layer.Box; layer.Shapes.Add(line); } } if (polygons.Count > 0) { layer = new MapLayer(); NormalizeLayerBox(); layer.Type = LayerType.Polygon; map.Layers.Add(layer); foreach (ShapePolygon polygon in polygons) { polygon.Box = layer.Box; layer.Shapes.Add(polygon); } } } private void ConvertNodes() { layer = new MapLayer(); NormalizeLayerBox(); layer.Type = LayerType.Point; map.Layers.Add(layer); foreach (OsmNode node in nodes.Values) { if (!node.HasParent) { ShapePoint point = new ShapePoint(); point.X = node.Lon; point.Y = node.Lat; foreach (KeyValuePair tag in node.Tags) { point.SpatialData.SetValue(tag.Key, tag.Value); } layer.Shapes.Add(point); } } } private void LoadMap() { LoadBounds(); LoadNodes(); LoadWays(); ConvertWays(); ConvertNodes(); } #endregion // Private Methods #region Public Methods public override void ImportMap(MapObject map, MapLayer layer, string filename) { try { this.map = map; this.layer = layer; document.Load(filename); LoadMap(); } catch { if (!FastReport.Utils.Config.WebMode) { MessageBox.Show(new FastReport.Utils.MyRes("Messages").Get("WrongFileFormat") + "."); } } } #endregion // Public Methods } }