private void calculateBoundsForWay(OSMWay way) { foreach (string nodeId in way.NodeReferences) { OSMNode node; if (NodesById.TryGetValue(nodeId, out node)) { way.BoundingBox.ExtendBounds(node.Location); } } }
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); }
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); } }
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); }
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); } } } }
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); }
private void writeWay(XElement parent, OSMWay way) { XElement wayElement = way.ToXElement(); parent.Add(wayElement); }
/// <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); } }