Пример #1
0
 private void calculateBoundsForWay(OSMWay way)
 {
     foreach (string nodeId in way.NodeReferences)
     {
         OSMNode node;
         if (NodesById.TryGetValue(nodeId, out node))
         {
             way.BoundingBox.ExtendBounds(node.Location);
         }
     }
 }
Пример #2
0
        public static XElement ToXElement(OSMWay way)
        {
            XElement output = new XElement("way");

            AddElementDetailsToXElement(way, output);
            foreach (string nodeRef in way.NodeReferences)
            {
                XElement node = new XElement("nd");
                node.SetAttributeValue("ref", nodeRef);

                output.Add(node);
            }
            AddElementTagsToXElement(way, output);

            return(output);
        }
Пример #3
0
        private void searchWayForIntersectionAndSplit(OSMWay way, LatitudeLongitude point1, LatitudeLongitude point2)
        {
            if (way.BoundingBox.IntersectsLine(point1, point2))
            {
                for (int i = 0; i < way.NodeReferences.Count - 1; i++)
                {
                    OSMNode thisNode, thatNode;
                    if (!NodesById.TryGetValue(way.NodeReferences[i], out thisNode) || !NodesById.TryGetValue(way.NodeReferences[i + 1], out thatNode))
                    {
                        continue;
                    }

                    Point2 intersectionPoint = LineSegment2.Intersection(point1, point2, thisNode.Location, thatNode.Location);
                    if (intersectionPoint != null)
                    {
                        splitWayByLine(way, point1, point2, thisNode.Location, thatNode.Location, i, intersectionPoint);
                    }
                }
            }
        }
Пример #4
0
        private void calculateNodeDistancesForWay(OSMWay way)
        {
            OSMNode previousNode = null;
            double  previousDistance = 0, newDistance = 0;

            foreach (string nodeRef in way.NodeReferences)
            {
                OSMNode currentNode;
                if (NodesById.TryGetValue(nodeRef, out currentNode))
                {
                    if (previousNode != null)
                    {
                        double distance = previousNode.Location.DistanceFrom(currentNode.Location);
                        newDistance = previousDistance + distance;
                    }
                    previousDistance = newDistance;
                    previousNode     = currentNode;
                }
                way.NodeDistances.Add(previousDistance);
            }
        }
Пример #5
0
        public static bool SplitWay(this OsmFile osmFile, OSMWay wayToSplit, LatitudeLongitude splitStart, LatitudeLongitude splitEnd)
        {
            try
            {
                // Find where split path intersects way
                List <OSMNode> nodesForWay = new List <OSMNode>();
                foreach (string nodeId in wayToSplit.NodeReferences)
                {
                    OSMNode node;
                    if (osmFile.NodesById.TryGetValue(nodeId, out node))
                    {
                        nodesForWay.Add(node);
                    }
                }

                // Create separate ways
                // Remove intersection connections
                return(true);
            } catch (Exception ex)
            {
            }
            return(false);
        }
Пример #6
0
        private void cleanSplitWays()
        {
            // This function is a doozy! Hopefully I translated its functionality okay, but if you're running into a problem with intersections it probably lies here.
            Dictionary <string, string> removedWays = new Dictionary <string, string>();
            List <OSMNode> nodes = Nodes;

            for (int i = 0; i < nodes.Count; i++)
            {
                OSMNode       node = nodes[i];
                List <OSMWay> filteredWaysForNode = new List <OSMWay>();

                // Need to create a mega way of the two ways the node is splitting. Otherwise multiple things get screwed up down the line.
                foreach (string usedInWay in node.WayReferences.ToList())
                {
                    string newID = usedInWay;
                    while (removedWays.ContainsKey(newID))
                    {
                        node.WayReferences.Remove(newID);
                        newID = removedWays[newID];
                        node.WayReferences.Add(newID);
                    }
                }

                foreach (string wayId in node.WayReferences)
                {
                    OSMWay way;
                    if (WaysById.TryGetValue(wayId, out way))
                    {
                        if (way.Tags.ContainsKey("highway") && AcceptedRoadTypes.Contains(way.Tags["highway"]))
                        {
                            filteredWaysForNode.Add(way);
                        }
                    }
                }

                if (node.References == 2 && filteredWaysForNode.Count == 2)
                {
                    OSMWay megaWay, dyingWay;

                    bool reversedDyingWay = false;

                    OSMWay way1 = filteredWaysForNode[0];
                    OSMWay way2 = filteredWaysForNode[1];

                    bool isLastNodeForWayOne = way1.NodeReferences[way1.NodeReferences.Count - 1] == node.ID;
                    bool isLastNodeForWayTwo = way2.NodeReferences[way2.NodeReferences.Count - 1] == node.ID;

                    if (isLastNodeForWayOne)
                    {
                        megaWay  = way1;
                        dyingWay = way2;

                        if (isLastNodeForWayTwo)
                        {
                            // Situation where they are both facing towards the split way node
                            reversedDyingWay = true;
                        }
                    }
                    else if (isLastNodeForWayTwo)
                    {
                        megaWay  = way2;
                        dyingWay = way1;
                    }
                    else
                    {
                        // Weird scenario where they are both facing away from the split way node
                        OSMIntersection intersection = new OSMIntersection();
                        intersection.ID        = node.ID;
                        intersection.Location  = node.Location;
                        Intersections[node.ID] = intersection;
                        continue;
                    }

                    // This is when one way loops around and connects to the other way more than once
                    bool multipleConnections = false;
                    foreach (string nodeId in dyingWay.NodeReferences)
                    {
                        if (nodeId != node.ID && megaWay.NodeReferences.Contains(nodeId))
                        {
                            multipleConnections = true;
                            if (!Intersections.ContainsKey(nodeId))
                            {
                                OSMNode multiNode = NodesById[nodeId];
                                multiNode.IsIntersection = true;

                                OSMIntersection intersection = new OSMIntersection();
                                intersection.ID       = nodeId;
                                intersection.Location = multiNode.Location;
                                Intersections[nodeId] = intersection;
                            }

                            break;
                        }
                    }

                    if (multipleConnections)
                    {
                        continue;
                    }

                    if (megaWay.ID == dyingWay.ID)
                    {
                        node.References--;
                        node.WayReferences.RemoveAt(1);
                        continue;
                    }

                    if ((megaWay.Oneway || dyingWay.Oneway) ^ (megaWay.Oneway && dyingWay.Oneway))
                    {
                        //If there is just one one-way street, add an intersection. If they both are, ...way murder time!
                        if (!Intersections.ContainsKey(node.ID))
                        {
                            OSMIntersection intersection = new OSMIntersection();
                            intersection.ID        = node.ID;
                            intersection.Location  = node.Location;
                            Intersections[node.ID] = intersection;
                        }
                        continue;
                    }

                    // Identity theft
                    megaWay.Name = string.IsNullOrWhiteSpace(megaWay.Name) ? dyingWay.Name : megaWay.Name;

                    // Combine max speeds
                    double mwMaxSpeed, dwMaxSpeed;
                    if (double.TryParse(megaWay.MaxSpeed, out mwMaxSpeed) && double.TryParse(dyingWay.MaxSpeed, out dwMaxSpeed))
                    {
                        megaWay.MaxSpeed = Math.Max(mwMaxSpeed, dwMaxSpeed).ToString();
                    }
                    else if (string.IsNullOrWhiteSpace(megaWay.MaxSpeed))
                    {
                        megaWay.MaxSpeed = dyingWay.MaxSpeed;
                    }

                    if (!reversedDyingWay)
                    {
                        foreach (string nodeId in dyingWay.NodeReferences)
                        {
                            if (nodeId != node.ID)
                            {
                                megaWay.NodeReferences.Add(nodeId);
                            }
                        }
                    }
                    else
                    {
                        for (int j = dyingWay.NodeReferences.Count - 1; j >= 0; j--)
                        {
                            if (dyingWay.NodeReferences[j] != node.ID)
                            {
                                megaWay.NodeReferences.Add(dyingWay.NodeReferences[j]);
                            }
                        }
                    }

                    double previousLength = megaWay.NodeDistances[megaWay.NodeDistances.Count - 1];
                    if (!reversedDyingWay)
                    {
                        for (int h = 0; h < dyingWay.NodeReferences.Count; h++)
                        {
                            string nodeId = dyingWay.NodeReferences[h];
                            if (nodeId != node.ID)
                            {
                                megaWay.NodeDistances.Add(previousLength + dyingWay.NodeDistances[h]);
                            }
                        }
                    }
                    else
                    {
                        for (int j = dyingWay.NodeReferences.Count - 1; j >= 0; j--)
                        {
                            string nodeId = dyingWay.NodeReferences[j];
                            if (nodeId != node.ID)
                            {
                                int inverseIndex = dyingWay.NodeReferences.Count - 1 - j;
                                megaWay.NodeDistances.Add(dyingWay.NodeDistances[inverseIndex] + previousLength);
                            }
                        }
                    }

                    //megaWay uses mega drain...
                    WaysById.Remove(dyingWay.ID);
                    node.WayReferences.Remove(dyingWay.ID);
                    node.References--;
                    removedWays[dyingWay.ID] = megaWay.ID;
                    foreach (var murderedWay in removedWays.ToList())
                    {
                        if (murderedWay.Value == dyingWay.ID)
                        {
                            removedWays[murderedWay.Key] = megaWay.ID;
                        }
                    }
                    //Its super effective!
                    //megaWay regains some HP
                    //dyingWay has fainted!

                    //Levrum used ULTRA BALL!
                    //Gotcha! megaWay was caught!
                    //megaWay's data was added to the POKEDEX
                    //Give a nickname to the captured megaWay?
                    claimOsmObjectAsLevrums(megaWay);
                }
            }

            // Fix any references that may have changed after the last loop
            foreach (OSMNode node in NodesById.Values.ToList())
            {
                foreach (string usedInWay in node.WayReferences.ToList())
                {
                    string newID = usedInWay;
                    while (removedWays.ContainsKey(newID))
                    {
                        node.WayReferences.Remove(newID);
                        newID = removedWays[newID];
                        node.WayReferences.Add(newID);
                    }
                }
            }
        }
Пример #7
0
        private void splitWayByLine(OSMWay way, LatitudeLongitude point1, LatitudeLongitude point2, LatitudeLongitude nodeLoc1, LatitudeLongitude nodeLoc2, int nodeIndex, Point2 intersectionPoint)
        {
            // Make new way
            OSMWay newWay = new OSMWay();

            newWay.ID        = getValidOsmId();
            newWay.Name      = way.Name;
            newWay.MaxSpeed  = way.MaxSpeed;
            newWay.Oneway    = way.Oneway;
            newWay.Version   = "1";
            newWay.Changeset = DateTime.Now.ToString("yyMMddHHmm");
            foreach (KeyValuePair <string, string> kvp in way.Tags)
            {
                newWay.Tags[kvp.Key] = kvp.Value;
            }
            claimOsmObjectAsLevrums(newWay);
            WaysById.Add(newWay.ID, newWay);

            claimOsmObjectAsLevrums(way);

            // Make new nodes
            OSMNode oldWayTerminator = new OSMNode(), newWayTerminator = new OSMNode();

            // Move the terminators towards their nodes slightly to prevent infinite recursion
            double oldWayDistance           = Math.Sqrt(Math.Pow(nodeLoc1.Latitude - intersectionPoint.Y, 2) + Math.Pow(nodeLoc1.Longitude - intersectionPoint.X, 2));
            double oldWayTerminatorDistance = oldWayDistance - .00002;
            double ratio = oldWayTerminatorDistance / oldWayDistance;

            oldWayTerminator.Location = new LatitudeLongitude(((1 - ratio) * nodeLoc1.Latitude) + (ratio * intersectionPoint.Y), ((1 - ratio) * nodeLoc1.Longitude) + (ratio * intersectionPoint.X));

            double newWayDistance           = Math.Sqrt(Math.Pow(nodeLoc2.Latitude - intersectionPoint.Y, 2) + Math.Pow(nodeLoc2.Longitude - intersectionPoint.X, 2));
            double newWayTerminatorDistance = newWayDistance - .00002;

            ratio = newWayTerminatorDistance / newWayDistance;
            newWayTerminator.Location = new LatitudeLongitude(((1 - ratio) * nodeLoc2.Latitude) + (ratio * intersectionPoint.Y), ((1 - ratio) * nodeLoc2.Longitude) + (ratio * intersectionPoint.X));

            newWayTerminator.EndNodeFlag = oldWayTerminator.EndNodeFlag = true;

            newWayTerminator.ID = getValidOsmId();
            NodesById.Add(newWayTerminator.ID, newWayTerminator);

            oldWayTerminator.ID = getValidOsmId();
            NodesById.Add(oldWayTerminator.ID, oldWayTerminator);

            newWayTerminator.Tags.Add("roadCut", oldWayTerminator.ID);
            oldWayTerminator.Tags.Add("roadCut", newWayTerminator.ID);

            claimOsmObjectAsLevrums(newWayTerminator);
            claimOsmObjectAsLevrums(oldWayTerminator);
            newWayTerminator.Version = "1";
            oldWayTerminator.Version = "1";

            // Not exactly true but this is somewhat hard to fake reasonably?
            newWayTerminator.Changeset = newWay.Changeset;
            oldWayTerminator.Changeset = newWay.Changeset;

            // Cleanup node references
            newWay.NodeReferences.Add(newWayTerminator.ID);
            for (int j = nodeIndex + 1; j < way.NodeReferences.Count; j++)
            {
                newWay.NodeReferences.Add(way.NodeReferences[j]);
            }

            for (int j = way.NodeReferences.Count - 1; j > nodeIndex; j--)
            {
                way.NodeReferences.RemoveAt(j);
            }

            way.NodeReferences.Add(oldWayTerminator.ID);
            way.NodeDistances.Clear();
            calculateNodeDistancesForWay(way);
            calculateNodeDistancesForWay(newWay);

            calculateBoundsForWay(newWay);
            searchWayForIntersectionAndSplit(newWay, point1, point2);
        }
Пример #8
0
        private void writeWay(XElement parent, OSMWay way)
        {
            XElement wayElement = way.ToXElement();

            parent.Add(wayElement);
        }
Пример #9
0
        /// <summary>
        /// Load OSM objects from an OSM XML file
        /// </summary>
        /// <param name="calculateDistances">Calculate distances between nodes on load</param>
        /// <param name="calculateBounds">Calculate way bounding boxes on load</param>
        /// <param name="strictMode">Discard node references from ways if the nodes to not exist</param>
        /// <returns></returns>
        public bool Load(bool calculateDistances = false, bool calculateBounds = false, bool strictMode = false)
        {
            try
            {
                clearValues();

                XDocument       doc              = XDocument.Load(File.FullName);
                List <XElement> nodeElements     = doc.Descendants("node").ToList();
                List <XElement> wayElements      = doc.Descendants("way").ToList();
                List <XElement> relationElements = doc.Descendants("relation").ToList();

                double lat, lon;
                foreach (XElement nodeElement in nodeElements)
                {
                    OSMNode node = new OSMNode();
                    node.GetElementDetailsFromXElement(nodeElement);
                    if (double.TryParse(nodeElement.Attribute("lat").Value, out lat))
                    {
                        node.Latitude = lat;
                    }

                    if (double.TryParse(nodeElement.Attribute("lon").Value, out lon))
                    {
                        node.Longitude = lon;
                    }
                    node.Latitude  = double.TryParse(nodeElement.Attribute("lat").Value, out lat) ? lat : double.NaN;
                    node.Longitude = double.TryParse(nodeElement.Attribute("lon").Value, out lon) ? lon : double.NaN;

                    Bounds.ExtendBounds(node.Latitude, node.Longitude);

                    NodesById[node.ID] = node;
                    //WaysForNodes[node.ID] = new List<OSMNodeWayInfo>();
                }

                foreach (XElement wayElement in wayElements)
                {
                    OSMWay way = new OSMWay();
                    way.GetElementDetailsFromXElement(wayElement);
                    if (way.ID == "15200801")
                    {
                        var str = "str";
                    }

                    List <XElement> nodes = wayElement.Descendants("nd").ToList();
                    foreach (XElement node in nodes)
                    {
                        string refValue = node.Attribute("ref").Value;
                        if (!string.IsNullOrEmpty(refValue))
                        {
                            OSMNode osmNode;
                            if (!NodesById.TryGetValue(refValue, out osmNode))
                            {
                                if (strictMode)
                                {
                                    continue;
                                }
                                else
                                {
                                    osmNode = new OSMNode()
                                    {
                                        ID = refValue
                                    };
                                    NodesById.Add(refValue, osmNode);
                                }
                            }
                            osmNode.WayReferences.Add(way.ID);
                            way.NodeReferences.Add(osmNode.ID);
                        }
                    }

                    XElement oneWayTag = wayElement.Descendants("tag").Where(t => t.Attribute("k").Value == "oneway").SingleOrDefault();
                    if (oneWayTag != null && (oneWayTag.Attribute("v").Value == "yes" || oneWayTag.Attribute("v").Value == "true"))
                    {
                        way.Oneway = true;
                    }

                    XElement maxSpeedTag = wayElement.Descendants("tag").Where(t => t.Attribute("k").Value == "maxspeed").SingleOrDefault();
                    if (maxSpeedTag != null)
                    {
                        way.MaxSpeed = maxSpeedTag.Attribute("v").Value;
                    }

                    WaysById[way.ID] = way;
                }

                foreach (XElement relationElement in relationElements)
                {
                    OSMRelation relation = new OSMRelation();
                    relation.GetElementDetailsFromXElement(relationElement);

                    List <XElement> members = relationElement.Descendants("member").ToList();
                    foreach (XElement member in members)
                    {
                        OSMRelationMember rm = new OSMRelationMember();
                        rm.Type = member.Attribute("type")?.Value;
                        rm.Ref  = member.Attribute("ref")?.Value;
                        rm.Role = member.Attribute("role")?.Value;

                        relation.Members.Add(rm);
                    }

                    RelationsById[relation.ID] = relation;
                }

                if (calculateDistances)
                {
                    CalculateNodeDistances();
                }

                if (calculateBounds)
                {
                    CalculateWayBounds();
                }


                return(true);
            }
            catch (Exception ex)
            {
                LogHelper.LogException(ex, "Error loading OSM file", true);
                return(false);
            }
        }