private bool GetGridDataValue(GraphPatch graphPatch, Coordinate coords, out string cellValue) { var gridData = graphPatch.grid; if (gridData.values != null && gridData.IsInside(coords.Longitude, coords.Latitude)) { int classification = (int)gridData.GetValue(coords.Longitude, coords.Latitude); if (classification == 0) { cellValue = "None"; } else { cellValue = ""; var classificationNames = Enum.GetNames(typeof(ClassificationIndex)); for (int i = 1, k = 1; i < (int)ClassificationIndex.Count; i++, k *= 2) { if ((classification & k) != 0) { cellValue += classificationNames[i] + ", "; } } cellValue = cellValue.Remove(cellValue.Length - 2); } return(true); } cellValue = "N/A"; return(false); }
// // Public Method // public void Init(GraphPatch networkPatch, GridPatch reachabilityPatch, float[] minutesPerMeter, float travelTime) { this.networkPatch = networkPatch; this.reachabilityPatch = reachabilityPatch; this.map = ComponentManager.Instance.Get <MapController>(); SetMinutesPerMeter(minutesPerMeter); SetTravelTime(travelTime); }
private void CreateReachabilityPatch(GraphPatch graphPatch) { GridData grid = new GridData(graphPatch.grid, false); grid.InitGridValues(); grid.minValue = 0; grid.maxValue = traveTimeSlider.value * travelTimeScale; grid.minFilter = grid.maxFilter = 0; grid.metadata = null; reachabilityPatch = reachabilityLayer.CreateGridPatch(graphPatch.GetSiteName(), graphPatch.Level, DateTime.Now.Year, grid); dataLayers.UpdateLayer(reachabilityLayer); }
private void ResetTool(bool turnOff) { editSpeedToggle.isOn = false; // Disable layers visibility event dataLayers.OnLayerVisibilityChange -= OnLayerVisibilityChange; // Clear layers dropdown if (!turnOff) { layerDropdown.ClearOptions(); } ClearAllUserChanges(); // Deactivate layers if (networkLayer != null) { // Disable patches visibility events networkLayer.OnPatchVisibilityChange -= OnPatchVisibilityChange; if (turnOff && dataLayers.IsLayerActive(networkLayer)) { dataLayers.ActivateLayer(networkLayer, false); } } if (reachabilityLayer != null) { reachabilityLayer.OnPatchVisibilityChange -= OnPatchVisibilityChange; if (turnOff && dataLayers.IsLayerActive(reachabilityLayer)) { dataLayers.ActivateLayer(reachabilityLayer, false); } } newRoadPanel.SetActive(false); mainPanel.SetActive(true); // Reset path references networkPatch = null; reachabilityPatch = null; ResetErrorMessage(); movedAwayError = false; deactivatedLayerError = false; // Re-enable layers visibility event dataLayers.OnLayerVisibilityChange += OnLayerVisibilityChange; }
// // Public Method // public void Init(GraphPatch patch, int classification, List <Coordinate> points) { graph = new GraphData(); this.classification = classification; GraphData g = patch.graph; graph.cellSizeX = g.cellSizeX; graph.cellSizeY = g.cellSizeY; graph.west = g.west; graph.east = g.east; graph.north = g.north; graph.south = g.south; grid = new GridData(patch.grid, false); SetPoints(points); }
private void SetNetworkPatch(GraphPatch patch) { networkPatch = patch; if (placeStart != null) { placeStart.NetworkPatch = networkPatch; } if (patch == null) { ClearAllUserChanges(); return; } var bounds = map.MapCoordBounds; if (!reachabilityLayer.HasPatches(siteBrowser.ActiveSite, map.CurrentLevel, bounds.west, bounds.east, bounds.north, bounds.south)) { CreateReachabilityPatch(patch); } if (!dataLayers.IsLayerActive(reachabilityLayer)) { dataLayers.ActivateLayer(reachabilityLayer, true); } if (placeStart != null) { placeStart.ReachabilityPatch = reachabilityPatch; } // Hide Loading Message if (!HasErrorMessage) { HideMessage(); } }
private IEnumerator Traverse(int countPerFrame) { GraphPatch graphPatch = networkPatch; GraphData graph = graphPatch.graph; GridData grid = reachabilityPatch.grid; // Initialize the grid values and the node costs to infinite PrepareGrid(); yield return(null); // Prepare the starting cells/nodes var nodes = new Queue <int>(); var nodesSet = new HashSet <int>(); foreach (var coord in startPoints) { // For each point find its grid index var startIndex = networkPatch.GetIndex(coord.Longitude, coord.Latitude); // Check if highway node is available and we're allowed to be on it if (graph.indexToNode.TryGetValue(-startIndex, out GraphNode highwayNode) && classificationToMinutesPerMeter[highwayNode.classifications] > 0) { startIndex = -startIndex; } // Snap to the nearest network node? if (SnapToNetwork) { if (startIndex > 0 && !graph.indexToNode.ContainsKey(startIndex)) { FindClosestNode(coord.Longitude, coord.Latitude, ref startIndex); yield return(null); } } // Initialize the cell value and node cost int gridIndex = Math.Abs(startIndex); grid.values[gridIndex] = 0f; grid.valuesMask[gridIndex] = 1; if (graph.indexToNode.TryGetValue(startIndex, out GraphNode first)) { first.cost = 0; } nodes.Enqueue(startIndex); nodesSet.Add(startIndex); } // Prepare data for off-grid computation GeoCalculator.GetDistanceInMeters(grid.west, grid.south, grid.east, grid.north, out double cellSizeX, out double cellSizeY); cellSizeX /= grid.countX; cellSizeY /= grid.countY; float distanceXY = (float)Math.Sqrt(cellSizeX * cellSizeX + cellSizeY * cellSizeY); float distanceX = (float)cellSizeX; float distanceY = (float)cellSizeY; int lastIndexX = grid.countX - 1; int lastIndexY = grid.countY - 1; var visitedNeighbours = new bool[8]; var indexToOffsetMap = new int[8] { -grid.countX - 1, -grid.countX, -grid.countX + 1, -1, +1, grid.countX - 1, grid.countX, grid.countX + 1, }; var offsetToIndexMap = new Dictionary <int, int>() { { -grid.countX - 1, 0 }, { -grid.countX, 1 }, { -grid.countX + 1, 2 }, { -1, 3 }, { +1, 4 }, { grid.countX - 1, 5 }, { grid.countX, 6 }, { grid.countX + 1, 7 } }; var linkDistances = new float[8] { distanceXY, distanceY, distanceXY, distanceX, distanceX, distanceXY, distanceY, distanceXY, }; float invWalkingSpeed = classificationToMinutesPerMeter[0]; int count = 0; int nodeIndex, neighbourIndex; var overlapedLink = new HashSet <int>(); // Start going thru the nodes while (nodes.Count > 0) { nodeIndex = nodes.Dequeue(); nodesSet.Remove(nodeIndex); // Check if it's a node. It could be an empty cell when going off-track if (graph.indexToNode.TryGetValue(nodeIndex, out GraphNode node)) { nodeIndex = Math.Abs(node.index); overlapedLink.Clear(); for (int k = 0; k < newRoads.Count; k++) { var newGraph = newRoads[k].graph; // if the node is overlapped by new road if (newRoads[k].graph.indexToNode.ContainsKey(nodeIndex)) { var newNode = newGraph.indexToNode[nodeIndex]; for (int i = newNode.links.Count - 1; i >= 0; i--) { neighbourIndex = Math.Abs(newNode.links[i].index); overlapedLink.Add(neighbourIndex); if (!graph.indexToNode.ContainsKey(neighbourIndex)) { neighbourIndex = -neighbourIndex; } var neighbour = graph.indexToNode[neighbourIndex]; // Calculate time: cost (minutes) = distance (meters) / speed (meters/minute) float invSpeed = classificationToMinutesPerMeter[newNode.linkClassifications[i]]; float cost = newNode.linkDistances[i] * invSpeed + node.cost; if (cost < neighbour.cost && cost <= grid.maxFilter) { neighbour.cost = cost; grid.values[neighbourIndex] = Math.Min(cost, grid.values[neighbourIndex]); grid.valuesMask[neighbourIndex] = 1; if (!nodesSet.Contains(neighbour.index)) { nodes.Enqueue(neighbour.index); nodesSet.Add(neighbour.index); } count++; } } } } for (int i = node.links.Count - 1; i >= 0; i--) { var neighbour = node.links[i]; neighbourIndex = Math.Abs(neighbour.index); var indexOffset = neighbourIndex - nodeIndex; var idx = offsetToIndexMap[indexOffset]; visitedNeighbours[idx] = true; if (overlapedLink.Contains(neighbourIndex)) { continue; } // Calculate time: cost (minutes) = distance (meters) / speed (meters/minute) float invSpeed = classificationToMinutesPerMeter[node.linkClassifications[i]]; float cost = node.linkDistances[i] * invSpeed + node.cost; if (cost < neighbour.cost && cost <= travelTime) { neighbour.cost = cost; // Note: a cell may have 2 nodes (e.g. primary + highway). Therefore we need to check the min value grid.values[neighbourIndex] = cost < grid.values[neighbourIndex]? cost : grid.values[neighbourIndex]; grid.valuesMask[neighbourIndex] = 1; if (!nodesSet.Contains(neighbour.index)) { nodes.Enqueue(neighbour.index); nodesSet.Add(neighbour.index); } count++; } } } // Calculate off-track if (node == null || node.classifications < ClassificationValue.HighwayLink) { int nodeY = nodeIndex / grid.countX; int nodeX = nodeIndex - nodeY * grid.countX; float nodeCost = node == null? grid.values[nodeIndex] : node.cost; // Check non-visited neighbours for (int i = 0; i < 8; ++i) { if (!visitedNeighbours[i]) { int x = nodeX + indexToOffsetXMap[i]; int y = nodeY + indexToOffsetYMap[i]; if (x < 0 || y < 0 || x > lastIndexX || y > lastIndexY) { continue; } neighbourIndex = nodeIndex + indexToOffsetMap[i]; // Calculate time: cost (minutes) = distance (meters) / speed (meters/minute) float cost = linkDistances[i] * invWalkingSpeed + nodeCost; if (cost < grid.values[neighbourIndex] && cost <= travelTime) { bool valid = false; if (graph.indexToNode.TryGetValue(neighbourIndex, out GraphNode neighbour)) { if (neighbour.classifications < ClassificationValue.HighwayLink) { neighbour.cost = cost; valid = true; } } else { valid = true; } if (valid) { grid.values[neighbourIndex] = cost; grid.valuesMask[neighbourIndex] = 1; if (!nodesSet.Contains(neighbourIndex)) { nodes.Enqueue(neighbourIndex); nodesSet.Add(neighbourIndex); } } count++; } } else { visitedNeighbours[i] = false; } } } if (count > countPerFrame) { count = 0; grid.ValuesChanged(); yield return(null); } } yield return(null); CommitPatchChanges(); gridGeneration = null; }