private void createEndIntersections() { foreach (OSMWay way in Ways) { if (!way.Tags.ContainsKey("highway") || !AcceptedRoadTypes.Contains(way.Tags["highway"]) || way.NodeReferences.Count < 2) { continue; } string firstNodeId = way.NodeReferences[0]; string lastNodeId = way.NodeReferences[way.NodeReferences.Count - 1]; OSMNode firstNode, lastNode; if (NodesById.TryGetValue(firstNodeId, out firstNode) && firstNode.References == 1 && !Intersections.ContainsKey(firstNode.ID)) { OSMIntersection intersection = new OSMIntersection(); intersection.ID = firstNode.ID; intersection.Location = firstNode.Location; Intersections[firstNode.ID] = intersection; } if (NodesById.TryGetValue(lastNodeId, out lastNode) && lastNode.References == 1 && !Intersections.ContainsKey(lastNode.ID)) { OSMIntersection intersection = new OSMIntersection(); intersection.ID = lastNode.ID; intersection.Location = lastNode.Location; Intersections[lastNode.ID] = intersection; } } }
public List <OSMWay> GetWaysIntersectingLine(LatitudeLongitude point1, LatitudeLongitude point2) { List <OSMWay> output = new List <OSMWay>(); try { foreach (OSMWay way in Ways) { 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) { output.Add(way); } } } } return(output); } catch (Exception ex) { LogHelper.LogException(ex, "Error getting intersecting ways", true); } return(output); }
private void clearValues() { NodesById.Clear(); WaysById.Clear(); RelationsById.Clear(); Intersections.Clear(); Bounds = new BoundingBox(); }
private void findConnectedIntersections() { foreach (OSMWay way in Ways) { if (way.NodeReferences.Count < 2) { continue; } if (!way.Tags.ContainsKey("highway") || !AcceptedRoadTypes.Contains(way.Tags["highway"])) { continue; } bool firstLoop = true; double distSinceMatch = 0; LatitudeLongitude previousLoc = null; OSMIntersection intersection = null, previousIntersection = null; foreach (string nodeId in way.NodeReferences) { if (nodeId == "149232745" && previousIntersection != null && previousIntersection.ID == "149161225") { var str = "str"; } OSMNode node; if (!NodesById.TryGetValue(nodeId, out node)) { int index = way.NodeReferences.IndexOf(nodeId); way.NodeReferences.RemoveAt(index); way.NodeDistances.RemoveAt(index); continue; } if (!firstLoop) { distSinceMatch += previousLoc.DistanceFrom(node.Location); } previousLoc = node.Location; firstLoop = false; if (Intersections.TryGetValue(nodeId, out intersection)) { if (previousIntersection != null) { previousIntersection.ConnectedIntersectionDistances[nodeId] = distSinceMatch; if (!way.Oneway) { intersection.ConnectedIntersectionDistances[previousIntersection.ID] = distSinceMatch; } distSinceMatch = 0; } previousIntersection = intersection; } } } }
private void flagIntersectionInNodes() { foreach (string nodeId in Intersections.Keys) { OSMNode node; if (NodesById.TryGetValue(nodeId, out node)) { node.IsIntersection = true; } } }
private void calculateBoundsForWay(OSMWay way) { foreach (string nodeId in way.NodeReferences) { OSMNode node; if (NodesById.TryGetValue(nodeId, out node)) { way.BoundingBox.ExtendBounds(node.Location); } } }
private string getValidOsmId() { // Gives a random number between 9 and 10 billion. At the time of writing (05-2020) there were only 6 billion OSM nodes. Should be safe for a year or two. string output = string.Empty; while (string.IsNullOrEmpty(output)) { double variance = m_rand.NextDouble() * Math.Pow(10, 9); long nodeId = (long)Math.Floor((Math.Pow(10, 9) * 9) + variance); output = nodeId.ToString(); if (NodesById.ContainsKey(output) || WaysById.ContainsKey(output)) { output = string.Empty; } } return(output); }
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); } } } }
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); } }
private void generateIntersections() { foreach (OSMWay way in Ways) { List <string> nodeIdsForWay = way.NodeReferences; if (nodeIdsForWay.Count < 2) { continue; } if (!way.Tags.ContainsKey("highway") || !AcceptedRoadTypes.Contains(way.Tags["highway"])) { continue; } string firstNodeId = way.NodeReferences[0]; string lastNodeId = way.NodeReferences[way.NodeReferences.Count - 1]; if (NodesById.ContainsKey(firstNodeId)) { NodesById[firstNodeId].EndNodeFlag = true; } if (NodesById.ContainsKey(lastNodeId)) { NodesById[lastNodeId].EndNodeFlag = true; } foreach (string nodeId in nodeIdsForWay) { OSMNode node; if (!NodesById.TryGetValue(nodeId, out node)) { continue; } node.References++; if (firstNodeId != nodeId && lastNodeId != nodeId) { node.References++; } else { int nodeIndex = nodeIdsForWay.IndexOf(nodeId); if (nodeIndex != 0 && nodeIndex < nodeIdsForWay.Count - 1) // Handles instances where a node appears twice in a way, once in the middle and once at the end { node.References++; } } if (node.References >= 3 && !Intersections.ContainsKey(nodeId)) { OSMIntersection intersection = new OSMIntersection(); intersection.ID = nodeId; intersection.Location = node.Location; Intersections[nodeId] = intersection; } else if (way.Name != null && !node.InternalName.Contains(way.Name)) { node.InternalName = string.IsNullOrWhiteSpace(node.Name) ? way.Name : string.Format("{0} / {1}", node.Name, way.Name); } } } }
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); }
/// <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); } }