Beispiel #1
0
        /// <summary>
        /// Convert the given Overpass query result to GeoJSON.
        /// </summary>
        /// <param name="ResultTask">A Overpass query result task.</param>
        public static Task <JObject> ToGeoJSON(this Task <OverpassResult> ResultTask)
        {
            return(ResultTask.ContinueWith(task => {
                // The order of the nodes, ways and relations seem not to be sorted by default!

                #region 1st: Add all nodes

                Node Node;
                var Nodes = new Dictionary <UInt64, Node>();

                foreach (var element in ResultTask.Result.Elements)
                {
                    // {
                    //   "type": "node",
                    //   "id":    35304749,
                    //   "lat":   50.8926376,
                    //   "lon":   11.6023278,
                    //   "tags": {
                    //       "highway":     "bus_stop",
                    //       "name":        "Lobeda",
                    //       "operator":    "JES",
                    //       "wheelchair":  "yes"
                    //   }
                    // }

                    if (element["type"].ToString() == "node")
                    {
                        Node = Node.Parse(element);

                        if (Nodes.ContainsKey(Node.Id))
                        {
                            Console.WriteLine("Duplicate node id detected!");
                        }
                        else
                        {
                            Nodes.Add(Node.Id, Node);
                        }
                    }
                }

                #endregion

                #region 2nd: Add all ways

                Way Way;
                var Ways = new Dictionary <UInt64, Way>();

                foreach (var element in ResultTask.Result.Elements)
                {
                    // {
                    //   "type": "way",
                    //   "id":   154676600,
                    //   "nodes": [
                    //     747761494,
                    //     582476538,
                    //     582476541,
                    //     582476543,
                    //     1671750275,
                    //     407850195,
                    //     407850192,
                    //     407850188,
                    //     1671750245,
                    //     1671750330,
                    //     1671750408,
                    //     1671750415,
                    //     1671750433,
                    //     1671750438,
                    //     1671750441,
                    //     747761494
                    //   ],
                    //   "tags": {
                    //     "landuse": "farm"
                    //   }
                    // }

                    if (element["type"].ToString() == "way")
                    {
                        Way = Way.Parse(element,
                                        NodeResolver: nodeId => Nodes[nodeId]);

                        if (Ways.ContainsKey(Way.Id))
                        {
                            Console.WriteLine("Duplicate way id detected!");
                        }
                        else
                        {
                            Ways.Add(Way.Id, Way);
                        }
                    }
                }

                #endregion

                #region 3rd: Add all relations

                Relation Relation;
                var Relations = new Dictionary <UInt64, Relation>();

                foreach (var element in ResultTask.Result.Elements)
                {
                    // {
                    //   "type": "relation",
                    //   "id":   3806843,
                    //   "members": [
                    //        {
                    //          "type": "way",
                    //          "ref":  71002045,
                    //          "role": "outer"
                    //        },
                    //        {
                    //          "type": "way",
                    //          "ref":  286959663,
                    //          "role": "outer"
                    //        },
                    //        {
                    //          "type": "way",
                    //          "ref":  286959664,
                    //          "role": "outer"
                    //        },
                    //        {
                    //          "type": "way",
                    //          "ref":  286959641,
                    //          "role": "outer"
                    //        }
                    //   ],
                    //   "tags": {
                    //       "landuse": "farm",
                    //       "type":    "multipolygon"
                    //   }
                    // }

                    if (element["type"].ToString() == "relation")
                    {
                        Relation = Relation.Parse(element,
                                                  NodeResolver: nodeId => Nodes[nodeId],
                                                  WayResolver:  wayId => Ways [wayId]);

                        if (Relations.ContainsKey(Relation.Id))
                        {
                            Console.WriteLine("Duplicate relation id detected!");
                        }
                        else
                        {
                            Relations.Add(Relation.Id, Relation);
                        }
                    }
                }

                #endregion

                // {
                //    "type":      "FeatureCollection",
                //    "generator": "overpass-turbo",
                //    "copyright": "The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.",
                //    "timestamp": "2014-11-29T23:08:02Z",
                //    "features": [ ]
                // }

                return new JObject(

                    new JProperty("type", "FeatureCollection"),
                    new JProperty("generator", "GraphDefined OSM Importer"),
                    new JProperty("copyright", ResultTask.Result.Copyright),
                    new JProperty("timestamp", DateTime.Now.ToIso8601()),

                    new JProperty("features", new JArray(Nodes.Values.
                                                         // Do not include nodes which only have a geo coordinate, but not tags!
                                                         // (They will be most likely only be useful within ways or relations)
                                                         Where(n => n.Tags.Count > 0).
                                                         Select(n => n.ToGeoJSON())).

                                  Concat(
                                      new JArray(Ways.Values.
                                                 // Do not include ways which do not have any tags!
                                                 // (They will be most likely only be useful within relations)
                                                 Where(w => w.Tags.Count > 0).
                                                 Select(w => w.ToGeoJSON()))).

                                  Concat(
                                      new JArray(Relations.Values.
                                                 // Do not include nodes which only have a geo coordinate, but not tags!
                                                 // (They will be most likely only be useful within ways or relations)
                                                 //Where (r => r.Tags.Count > 0).
                                                 Select(r => r.ToGeoJSON())))

                                  )

                    );
            }));
        }
Beispiel #2
0
        /// <summary>
        /// Convert the given OSM relation to a GeoJSON line feature.
        /// </summary>
        /// <param name="Relation">An OSM relation.</param>
        public static JObject ToGeoJSON(this Relation Relation)
        {
            // {
            //     "type":  "Feature",
            //     "id":    "way/305352912",
            //     "properties": {
            //         "@id":         "way/305352912",
            //     },
            //     "geometry": {
            //         "type":        "LineString",
            //         "coordinates": [ [ 11.6023278, 50.8926376 ], [ 11.5054540, 50.7980146 ], [ 11.6023278, 50.8926376 ] ]
            //     }
            // }

            // https://wiki.openstreetmap.org/wiki/Overpass_turbo/Polygon_Features

            // 1) Combine all ways into a single big list of geo coordinate (it's a puzzle! Some ways must be reversed in order to find matches!)
            // 2) Check if first geo coordinate is the same as the last
            // 3) If yes => polygon (exceptions see wiki link)


            // Relation.Ways.Select(Way => new JArray(Way.Nodes.Select(Node => new JArray(Node.Longitude, Node.Latitude))))

            var RemainingGeoFeatures = Relation.Ways.Select(Way => new GeoFeature(Way.Nodes.Select(Node => new GeoCoord(Node.Longitude, Node.Latitude)))).ToList();
            var ResultList           = new List <GeoFeature>();

            Byte       Found = 0;
            GeoFeature CurrentGeoFeature;

            if (Relation.Id == 3484638)
            {
            }

            //if (Relation.Tags["type"].ToString() != "multipolygon")
            //{
            //    Console.WriteLine("Broken OSM multipolygon relation found!");
            //}

            do
            {
                CurrentGeoFeature = RemainingGeoFeatures.RemoveAndReturnFirst();

                // The current geo feature is closed -> a polygon!
                if (Relation.Tags["type"].ToString() != "route" &&
                    CurrentGeoFeature.GeoCoordinates.First() == CurrentGeoFeature.GeoCoordinates.Last())
                {
                    CurrentGeoFeature.Type = GeoFeature.GeoType.Polygon;
                    ResultList.Add(CurrentGeoFeature);
                }

                // The current geo feature is not closed
                // Try to extend the geo feature by finding fitting other geo features
                else
                {
                    do
                    {
                        Found = 0;

                        foreach (var AdditionalPath in RemainingGeoFeatures)
                        {
                            if (AdditionalPath.GeoCoordinates.First() == CurrentGeoFeature.GeoCoordinates.Last())
                            {
                                RemainingGeoFeatures.Remove(AdditionalPath);
                                // Skip first GeoCoordinate as it is redundant!
                                CurrentGeoFeature.GeoCoordinates.AddRange(AdditionalPath.GeoCoordinates);//.Skip(1));
                                Found = 1;
                                break;
                            }

                            else if (AdditionalPath.GeoCoordinates.Last() == CurrentGeoFeature.GeoCoordinates.Last())
                            {
                                RemainingGeoFeatures.Remove(AdditionalPath);
                                // Skip first GeoCoordinate as it is redundant!
                                CurrentGeoFeature.GeoCoordinates.AddRange(AdditionalPath.GeoCoordinates.ReverseAndReturn());//.Skip(1));
                                Found = 1;
                                break;
                            }

                            else if (AdditionalPath.GeoCoordinates.First() == CurrentGeoFeature.GeoCoordinates.First())
                            {
                                RemainingGeoFeatures.Remove(AdditionalPath);
                                CurrentGeoFeature.GeoCoordinates.Reverse();
                                // Skip first GeoCoordinate as it is redundant!
                                CurrentGeoFeature.GeoCoordinates.AddRange(AdditionalPath.GeoCoordinates);//.Skip(1));
                                Found = 1;
                                break;
                            }

                            else if (AdditionalPath.GeoCoordinates.Last() == CurrentGeoFeature.GeoCoordinates.First())
                            {
                                RemainingGeoFeatures.Remove(AdditionalPath);
                                CurrentGeoFeature.GeoCoordinates.Reverse();
                                // Skip first GeoCoordinate as it is redundant!
                                CurrentGeoFeature.GeoCoordinates.AddRange(AdditionalPath.GeoCoordinates.ReverseAndReturn());//.Skip(1));
                                Found = 1;
                                break;
                            }
                        }
                    } while (RemainingGeoFeatures.Count > 0 && Found > 0);

                    CurrentGeoFeature.Type = (Relation.Tags["type"].ToString() != "route" &&
                                              CurrentGeoFeature.GeoCoordinates.First() == CurrentGeoFeature.GeoCoordinates.Last())
                                                  ? GeoFeature.GeoType.Polygon
                                                  : GeoFeature.GeoType.LineString;

                    ResultList.Add(CurrentGeoFeature);
                }
            } while (RemainingGeoFeatures.Count > 0);


            JProperty FeatureGeometry = null;

            if (ResultList.Count == 1)
            {
                if (ResultList.First().Type == GeoFeature.GeoType.Polygon)
                {
                    FeatureGeometry = new JProperty("geometry", new JObject(
                                                        new JProperty("type", "Polygon"),
                                                        new JProperty("coordinates", new JArray()
                    {
                        new JArray(CurrentGeoFeature.GeoCoordinates.Select(geo => new JArray(geo.Longitude, geo.Latitude)))
                    })
                                                        ));
                }
                else
                {
                    FeatureGeometry = new JProperty("geometry", new JObject(
                                                        new JProperty("type", "LineString"),
                                                        new JProperty("coordinates", new JArray(CurrentGeoFeature.GeoCoordinates.Select(geo => new JArray(geo.Longitude, geo.Latitude))))
                                                        ));
                }
            }
            else
            {
                if (ResultList.First().Type == GeoFeature.GeoType.Polygon)
                {
                    FeatureGeometry = new JProperty("geometry", new JObject(
                                                        new JProperty("type", "Polygon"),
                                                        new JProperty("coordinates", new JArray(ResultList.Select(items => new JArray(items.GeoCoordinates.Select(geo => new JArray(geo.Longitude, geo.Latitude))))))
                                                        ));
                }
                else
                {
                    FeatureGeometry = new JProperty("geometry", new JObject(
                                                        new JProperty("type", "MultiLineString"),
                                                        new JProperty("coordinates", new JArray(ResultList.Select(items => new JArray(items.GeoCoordinates.Select(geo => new JArray(geo.Longitude, geo.Latitude))))))
                                                        ));
                }
            }


            return(new JObject(

                       new JProperty("type", "Feature"),
                       new JProperty("id", "relation/" + Relation.Id),

                       new JProperty("properties", new JObject(
                                         new List <JProperty>()
            {
                new JProperty("@id", "relation/" + Relation.Id)
            }.
                                         AddAndReturnList(Relation.Tags.Select(kvp => new JProperty(kvp.Key, kvp.Value))).
                                         ToArray()
                                         )),
                       FeatureGeometry
                       ));
        }