github.com/LdDl/ch@v1.7.8/isochrones.go (about)

     1  package ch
     2  
     3  import (
     4  	"container/heap"
     5  	"fmt"
     6  )
     7  
     8  // Isochrones Returns set of vertices and corresponding distances restricted by maximum travel cost for source vertex
     9  // source - source vertex (user defined label)
    10  // maxCost - restriction on travel cost for breadth search
    11  // See ref. https://wiki.openstreetmap.org/wiki/Isochrone and https://en.wikipedia.org/wiki/Isochrone_map
    12  // Note: implemented breadth-first searching path algorithm does not guarantee shortest pathes to reachable vertices (until all edges have cost 1.0). See ref: https://en.wikipedia.org/wiki/Breadth-first_search
    13  // Note: result for estimated costs could be also inconsistent due nature of data structure
    14  func (graph *Graph) Isochrones(source int64, maxCost float64) (map[int64]float64, error) {
    15  	var ok bool
    16  	if source, ok = graph.mapping[source]; !ok {
    17  		return nil, fmt.Errorf("no such source")
    18  	}
    19  	Q := &minHeap{}
    20  	heap.Init(Q)
    21  	distance := make(map[int64]float64, len(graph.Vertices))
    22  	Q.Push(&minHeapVertex{id: source, distance: 0})
    23  	visit := make(map[int64]bool)
    24  	for Q.Len() != 0 {
    25  		next := heap.Pop(Q).(*minHeapVertex)
    26  		visit[next.id] = true
    27  		if next.distance <= maxCost {
    28  			distance[graph.Vertices[next.id].Label] = next.distance
    29  			vertexList := graph.Vertices[next.id].outIncidentEdges
    30  			for i := range vertexList {
    31  				neighbor := vertexList[i].vertexID
    32  				if v1, ok1 := graph.shortcuts[next.id]; ok1 {
    33  					if _, ok2 := v1[neighbor]; ok2 {
    34  						// Ignore shortcut
    35  						continue
    36  					}
    37  				}
    38  				target := vertexList[i].vertexID
    39  				cost := vertexList[i].weight
    40  				alt := distance[graph.Vertices[next.id].Label] + cost
    41  				if visit[target] {
    42  					continue
    43  				}
    44  				Q.Push(&minHeapVertex{id: target, distance: alt})
    45  			}
    46  		}
    47  	}
    48  	return distance, nil
    49  }