mormon 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +35 -0
- data/LICENSE.txt +22 -0
- data/README.md +20 -0
- data/Rakefile +1 -0
- data/lib/mormon/osm_loader.rb +229 -0
- data/lib/mormon/osm_router.rb +107 -0
- data/lib/mormon/tile_data.rb +67 -0
- data/lib/mormon/tile_name.rb +112 -0
- data/lib/mormon/version.rb +3 -0
- data/lib/mormon/weight.rb +32 -0
- data/lib/mormon.rb +7 -0
- data/mormon.gemspec +25 -0
- data/spec/mormon_spec.rb +94 -0
- data/spec/spec.osm +2459 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/tandil.osm +27140 -0
- metadata +116 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
mormon (0.0.1)
|
5
|
+
nokogiri
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
columnize (0.3.6)
|
11
|
+
debugger (1.2.0)
|
12
|
+
columnize (>= 0.3.1)
|
13
|
+
debugger-linecache (~> 1.1.1)
|
14
|
+
debugger-ruby_core_source (~> 1.1.3)
|
15
|
+
debugger-linecache (1.1.2)
|
16
|
+
debugger-ruby_core_source (>= 1.1.1)
|
17
|
+
debugger-ruby_core_source (1.1.3)
|
18
|
+
diff-lcs (1.1.3)
|
19
|
+
nokogiri (1.5.5)
|
20
|
+
rspec (2.11.0)
|
21
|
+
rspec-core (~> 2.11.0)
|
22
|
+
rspec-expectations (~> 2.11.0)
|
23
|
+
rspec-mocks (~> 2.11.0)
|
24
|
+
rspec-core (2.11.1)
|
25
|
+
rspec-expectations (2.11.3)
|
26
|
+
diff-lcs (~> 1.1.3)
|
27
|
+
rspec-mocks (2.11.2)
|
28
|
+
|
29
|
+
PLATFORMS
|
30
|
+
ruby
|
31
|
+
|
32
|
+
DEPENDENCIES
|
33
|
+
debugger
|
34
|
+
mormon!
|
35
|
+
rspec
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Geronimo Diaz
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Mormon
|
2
|
+
======
|
3
|
+
|
4
|
+
OSM Routing in Ruby, based on pyroutelib2
|
5
|
+
|
6
|
+
Usage
|
7
|
+
=====
|
8
|
+
|
9
|
+
osm_loader = Mormon::OSM::Loader.new "path/to/file.osm"
|
10
|
+
osm_router = Mormon::OSM::Router.new osm_loader
|
11
|
+
osm_router.find_route node_start, node_end, transport
|
12
|
+
|
13
|
+
- Notes:
|
14
|
+
- trasnports: must be one in [:cycle, :car, :train, :foot, :horse]
|
15
|
+
- node_start and node_end must be node ids
|
16
|
+
|
17
|
+
License
|
18
|
+
=======
|
19
|
+
|
20
|
+
- WTFYW License
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,229 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module Mormon
|
4
|
+
module OSM
|
5
|
+
class Loader
|
6
|
+
attr_reader :options, :routing, :nodes, :ways, :tiles, :routeable_nodes, :route_types
|
7
|
+
|
8
|
+
def initialize(filename, options = {})
|
9
|
+
@options = options
|
10
|
+
|
11
|
+
@tiles = {}
|
12
|
+
@nodes = {}
|
13
|
+
@ways = {}
|
14
|
+
|
15
|
+
@routing = {}
|
16
|
+
@routeable_nodes = {}
|
17
|
+
@route_types = [:cycle, :car, :train, :foot, :horse]
|
18
|
+
|
19
|
+
@route_types.each do |type|
|
20
|
+
@routing[type] = {}
|
21
|
+
@routeable_nodes[type] = {}
|
22
|
+
end
|
23
|
+
|
24
|
+
# @tilename = Mormon::Tile::Name.new
|
25
|
+
# @tiledata = Mormon::Tile::Data.new
|
26
|
+
|
27
|
+
parse filename
|
28
|
+
end
|
29
|
+
|
30
|
+
def parse(filename)
|
31
|
+
puts "Loading %s.." % filename
|
32
|
+
|
33
|
+
if !File.exists?(filename)
|
34
|
+
print "No such data file %s" % filename
|
35
|
+
return false
|
36
|
+
end
|
37
|
+
|
38
|
+
osm = Nokogiri::XML(File.open(filename))
|
39
|
+
|
40
|
+
load_nodes osm
|
41
|
+
load_ways osm
|
42
|
+
end
|
43
|
+
|
44
|
+
def report
|
45
|
+
report = "Loaded %d nodes,\n" % @nodes.keys.size
|
46
|
+
report += "%d ways, and...\n" % @ways.keys.size
|
47
|
+
|
48
|
+
@route_types.each do |type|
|
49
|
+
report += " %d %s routes\n" % [@routing[type].keys.size, type]
|
50
|
+
end
|
51
|
+
|
52
|
+
report
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def load_nodes(nokosm)
|
58
|
+
nokosm.css('node').each do |node|
|
59
|
+
node_id = node[:id]
|
60
|
+
|
61
|
+
@nodes[node_id] = {
|
62
|
+
lat: node[:lat].to_f,
|
63
|
+
lon: node[:lon].to_f,
|
64
|
+
tags: {}
|
65
|
+
}
|
66
|
+
|
67
|
+
node.css('tag').each do |t|
|
68
|
+
k,v = t[:k].to_sym, t[:v]
|
69
|
+
@nodes[node_id][:tags][k] = v unless useless_tags.include?(k)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def load_ways(nokosm)
|
75
|
+
nokosm.css('way').each do |way|
|
76
|
+
way_id = way[:id]
|
77
|
+
|
78
|
+
@ways[way_id] = {
|
79
|
+
nodes: way.css('nd').map { |nd| nd[:ref] },
|
80
|
+
tags: {}
|
81
|
+
}
|
82
|
+
|
83
|
+
way.css('tag').each do |t|
|
84
|
+
k,v = t[:k].to_sym, t[:v]
|
85
|
+
@ways[way_id][:tags][k] = v unless useless_tags.include?(k)
|
86
|
+
end
|
87
|
+
|
88
|
+
store_way @ways[way_id]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def useless_tags
|
93
|
+
[:created_by]
|
94
|
+
end
|
95
|
+
|
96
|
+
def way_access(highway, railway)
|
97
|
+
access = {}
|
98
|
+
access[:cycle] = [:primary, :secondary, :tertiary, :unclassified, :minor, :cycleway,
|
99
|
+
:residential, :track, :service].include? highway.to_sym
|
100
|
+
|
101
|
+
access[:car] = [:motorway, :trunk, :primary, :secondary, :tertiary,
|
102
|
+
:unclassified, :minor, :residential, :service].include? highway.to_sym
|
103
|
+
|
104
|
+
access[:train] = [:rail, :light_rail, :subway].include? railway.to_sym
|
105
|
+
access[:foot] = access[:cycle] || [:footway, :steps].include?(highway.to_sym)
|
106
|
+
access[:horse] = [:track, :unclassified, :bridleway].include? highway.to_sym
|
107
|
+
access
|
108
|
+
end
|
109
|
+
|
110
|
+
def store_way(way)
|
111
|
+
tags = way[:tags]
|
112
|
+
|
113
|
+
highway = equivalent tags.fetch(:highway, "")
|
114
|
+
railway = equivalent tags.fetch(:railway, "")
|
115
|
+
oneway = tags.fetch(:oneway, "")
|
116
|
+
reversible = !['yes','true','1'].include?(oneway)
|
117
|
+
|
118
|
+
access = way_access highway, railway
|
119
|
+
|
120
|
+
# Store routing information
|
121
|
+
last = -1
|
122
|
+
way[:nodes].each do |node|
|
123
|
+
if last != -1
|
124
|
+
@route_types.each do |route_type|
|
125
|
+
if access[route_type]
|
126
|
+
weight = Mormon::Weight.get route_type, highway.to_sym
|
127
|
+
add_link(last, node, route_type, weight)
|
128
|
+
add_link(node, last, route_type, weight) if reversible || route_type == :foot
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
last = node
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def routeable_from(node, route_type)
|
137
|
+
@routeable_nodes[route_type][node] = 1
|
138
|
+
end
|
139
|
+
|
140
|
+
def add_link(fr, to, route_type, weight = 1)
|
141
|
+
routeable_from fr, route_type
|
142
|
+
return if @routing[route_type][fr].keys.include?(to)
|
143
|
+
@routing[route_type][fr][to] = weight
|
144
|
+
rescue
|
145
|
+
@routing[route_type][fr] = { to => weight }
|
146
|
+
end
|
147
|
+
|
148
|
+
def way_type(tags)
|
149
|
+
# Look for a variety of tags (priority order - first one found is used)
|
150
|
+
[:highway, :railway, :waterway, :natural].each do |type|
|
151
|
+
value = tags.fetch(type, '')
|
152
|
+
return equivalent(value) if value
|
153
|
+
end
|
154
|
+
nil
|
155
|
+
end
|
156
|
+
|
157
|
+
def equivalent(tag)
|
158
|
+
{
|
159
|
+
primary_link: "primary",
|
160
|
+
trunk: "primary",
|
161
|
+
trunk_link: "primary",
|
162
|
+
secondary_link: "secondary",
|
163
|
+
tertiary: "secondary",
|
164
|
+
tertiary_link: "secondary",
|
165
|
+
residential: "unclassified",
|
166
|
+
minor: "unclassified",
|
167
|
+
steps: "footway",
|
168
|
+
driveway: "service",
|
169
|
+
pedestrian: "footway",
|
170
|
+
bridleway: "cycleway",
|
171
|
+
track: "cycleway",
|
172
|
+
arcade: "footway",
|
173
|
+
canal: "river",
|
174
|
+
riverbank: "river",
|
175
|
+
lake: "river",
|
176
|
+
light_rail: "railway"
|
177
|
+
}[tag.to_sym] || tag
|
178
|
+
end
|
179
|
+
|
180
|
+
# def find_node(lat, lon, route_type)
|
181
|
+
# # find the nearest node that can be the start of a route
|
182
|
+
# load_area(lat, lon)
|
183
|
+
|
184
|
+
# max_dist = 1E+20
|
185
|
+
# node_found = nil
|
186
|
+
# pos_found = nil
|
187
|
+
|
188
|
+
# rnodes.values.each do |node_id, pos|
|
189
|
+
# dy = pos[0] - lat
|
190
|
+
# dx = pos[1] - lon
|
191
|
+
# dist = dx * dx + dy * dy
|
192
|
+
|
193
|
+
# if dist < maxDist
|
194
|
+
# max_dist = dist
|
195
|
+
# node_found = node_id
|
196
|
+
# pos_found = pos
|
197
|
+
# end
|
198
|
+
|
199
|
+
# node_found
|
200
|
+
# end
|
201
|
+
# end
|
202
|
+
|
203
|
+
# @unused: load the specific area instead an osm file
|
204
|
+
# def load_area(lat, lon)
|
205
|
+
# if options[:file]
|
206
|
+
# puts "The %s file was already loaded" % options[:file]
|
207
|
+
# return
|
208
|
+
# end
|
209
|
+
|
210
|
+
# # Download data in the vicinity of a lat/long
|
211
|
+
# z = Mormon::Tile::Data.download_level
|
212
|
+
# (x,y) = @tilename.xy(lat, lon, z)
|
213
|
+
|
214
|
+
# tile_id = '%d,%d' % [x, y]
|
215
|
+
|
216
|
+
# return if @tiles[tile_id]
|
217
|
+
|
218
|
+
# @tiles[tile_id] = true
|
219
|
+
|
220
|
+
# filename = @tiledata.get_osm(z, x, y)
|
221
|
+
# # print "Loading %d,%d at z%d from %s" % (x,y,z,filename)
|
222
|
+
|
223
|
+
# parse filename
|
224
|
+
# end
|
225
|
+
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
@@ -0,0 +1,107 @@
|
|
1
|
+
module Mormon
|
2
|
+
module OSM
|
3
|
+
class Router
|
4
|
+
# attr_reader :data
|
5
|
+
|
6
|
+
def initialize(loader)
|
7
|
+
@loader = loader
|
8
|
+
end
|
9
|
+
|
10
|
+
# Calculate distance between two nodes via pitagoras c**2 = a**2 + b**2
|
11
|
+
def distance(n1, n2)
|
12
|
+
node1, node2 = @loader.nodes[n1.to_s], @loader.nodes[n2.to_s]
|
13
|
+
|
14
|
+
lat1, lon1 = node1[:lat], node1[:lon]
|
15
|
+
lat2, lon2 = node2[:lat], node2[:lon]
|
16
|
+
|
17
|
+
# TODO: projection issues
|
18
|
+
dlat = lat2 - lat1
|
19
|
+
dlon = lon2 - lon1
|
20
|
+
|
21
|
+
Math.sqrt dlat**2 + dlon**2
|
22
|
+
end
|
23
|
+
|
24
|
+
def find_route(node_start, node_end, transport)
|
25
|
+
result, nodes = route(node_start, node_end, transport)
|
26
|
+
|
27
|
+
return [result,[]] if result != 'success'
|
28
|
+
|
29
|
+
nodes.map! do |node|
|
30
|
+
data = @loader.nodes[node.to_s]
|
31
|
+
[data[:lat], data[:lon]]
|
32
|
+
end
|
33
|
+
|
34
|
+
[result, nodes]
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def route(node_start, node_end, transport)
|
40
|
+
return "no_such_transport" unless @loader.routing[transport]
|
41
|
+
return "no_such_node" unless @loader.routing[transport][node_start.to_s]
|
42
|
+
|
43
|
+
@_end = node_end
|
44
|
+
@queue = []
|
45
|
+
|
46
|
+
# Start by queueing all outbound links from the start node
|
47
|
+
@loader.routing[transport][node_start.to_s].each do |neighbor, weight|
|
48
|
+
add_to_queue(node_start, neighbor, { node_end: nil, distance: 0, nodes: [node_start] }, weight)
|
49
|
+
end
|
50
|
+
|
51
|
+
closed = [node_start]
|
52
|
+
|
53
|
+
# Limit for how long it will search
|
54
|
+
(0..10000).each do
|
55
|
+
next_item = @queue.shift
|
56
|
+
return "no_route" unless next_item
|
57
|
+
|
58
|
+
x = next_item[:node_end]
|
59
|
+
next if closed.include?(x)
|
60
|
+
|
61
|
+
# Found the end node - success
|
62
|
+
return ['success', next_item[:nodes]] if x == node_end
|
63
|
+
|
64
|
+
closed << x
|
65
|
+
|
66
|
+
@loader.routing[transport][x.to_s].each do |node, weight|
|
67
|
+
add_to_queue(x, node, next_item, weight) unless closed.include?(node)
|
68
|
+
end if @loader.routing[transport][x.to_s]
|
69
|
+
end
|
70
|
+
|
71
|
+
'gave_up'
|
72
|
+
end
|
73
|
+
|
74
|
+
def add_to_queue(node_start, node_end, current_queue, weight = 1)
|
75
|
+
# Add another potential route to the queue
|
76
|
+
|
77
|
+
node_start = node_start.to_i
|
78
|
+
node_end = node_end.to_i
|
79
|
+
|
80
|
+
# if already in queue
|
81
|
+
@queue.each { |other| return if other[:node_end] == node_end }
|
82
|
+
|
83
|
+
distance = distance(node_start, node_end)
|
84
|
+
|
85
|
+
return if weight.zero?
|
86
|
+
distance = distance / weight
|
87
|
+
|
88
|
+
# Create a hash for all the route's attributes
|
89
|
+
current_distance = current_queue[:distance]
|
90
|
+
nodes = current_queue[:nodes].dup
|
91
|
+
nodes << node_end
|
92
|
+
|
93
|
+
queue_item = {
|
94
|
+
distance: current_distance + distance,
|
95
|
+
max_distance: current_distance + distance(node_end, @_end),
|
96
|
+
nodes: nodes,
|
97
|
+
node_end: node_end
|
98
|
+
}
|
99
|
+
|
100
|
+
# Try to insert, keeping the queue ordered by decreasing worst-case distance
|
101
|
+
found = @queue.find { |other| other[:max_distance] > queue_item[:max_distance] }
|
102
|
+
found ? @queue.insert(@queue.index(found), queue_item) : @queue << queue_item
|
103
|
+
end
|
104
|
+
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'open-uri'
|
2
|
+
require 'fileutils'
|
3
|
+
|
4
|
+
module Mormon
|
5
|
+
module Tile
|
6
|
+
class Data
|
7
|
+
TILE_DIR = 'cache/%d/%d/%d'
|
8
|
+
TILE_URL = 'http://dev.openstreetmap.org/~ojw/api/?/map/%d/%d/%d'
|
9
|
+
|
10
|
+
attr_reader :options
|
11
|
+
|
12
|
+
def initialize(options = {})
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.download_level
|
17
|
+
# All primary downloads are done at a particular zoom level
|
18
|
+
15
|
19
|
+
end
|
20
|
+
|
21
|
+
def get_osm(z, x, y)
|
22
|
+
# Download OSM data for the region covering a slippy-map tile
|
23
|
+
if x < 0 or y < 0 or z < 0 or z > 25
|
24
|
+
puts "Disallowed %d,%d at %d" % [x, y, z]
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
directory = TILE_DIR % [z,x,y]
|
29
|
+
FileUtils.mkdir_p(directory) unless Dir.exists?(directory)
|
30
|
+
|
31
|
+
if z == Data.download_level
|
32
|
+
url = TILE_URL % [z,x,y]
|
33
|
+
filename = '%s/data.osm' % directory
|
34
|
+
|
35
|
+
# puts "URL: %s" % url
|
36
|
+
# puts "filename: %s" % filename
|
37
|
+
|
38
|
+
# download the data
|
39
|
+
if options[:reset_cache] || !File.exists?(filename)
|
40
|
+
begin
|
41
|
+
open(url) do |content|
|
42
|
+
File.new(filename) { |f| f.write content }
|
43
|
+
end
|
44
|
+
filename
|
45
|
+
rescue OpenURI::HTTPError
|
46
|
+
"Tile not found in #{url}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
elsif z > Data.download_level
|
51
|
+
# use larger tile
|
52
|
+
while z > Data.download_level
|
53
|
+
z = z - 1
|
54
|
+
x = (x / 2).to_i
|
55
|
+
y = (y / 2).to_i
|
56
|
+
end
|
57
|
+
get_osm z, x, y
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# tile = Mormon::Tile::Data.new :reset_cache => true
|
67
|
+
# puts tile.get_osm(15, 16218, 10741)
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Mormon
|
2
|
+
module Tile
|
3
|
+
class Name
|
4
|
+
|
5
|
+
# "http://cassini.toolserver.org:8080/"
|
6
|
+
# "http://a.tile.openstreetmap.org/"
|
7
|
+
# "http://toolserver.org/~cmarqu/hill/",
|
8
|
+
# "http://tah.openstreetmap.org/Tiles/tile/"
|
9
|
+
LAYERS_URL = {
|
10
|
+
tah: "http://a.tile.openstreetmap.org/",
|
11
|
+
oam: "http://oam1.hypercube.telascience.org/tiles/1.0.0/openaerialmap-900913/",
|
12
|
+
mapnik: "http://tile.openstreetmap.org/mapnik/"
|
13
|
+
}
|
14
|
+
|
15
|
+
def edges(x, y, z)
|
16
|
+
lat1, lat2 = lat_edges(y, z)
|
17
|
+
lon1, lon2 = lon_edges(x, z)
|
18
|
+
[lat2, lon1, lat1, lon2] # S,W,N,E
|
19
|
+
end
|
20
|
+
|
21
|
+
def px_size
|
22
|
+
256
|
23
|
+
end
|
24
|
+
|
25
|
+
def layer_ext(layer)
|
26
|
+
layer == 'oam' ? 'jpg' : 'png'
|
27
|
+
end
|
28
|
+
|
29
|
+
def layer_base(layer)
|
30
|
+
LAYERS_URL[layer]
|
31
|
+
end
|
32
|
+
|
33
|
+
def url(x, y, z, layer = :mapnik)
|
34
|
+
"%s%d/%d/%d.%s" % [layer_base(layer), z, x, y, layer_ext(layer)]
|
35
|
+
end
|
36
|
+
|
37
|
+
def xy(lat, lon, z)
|
38
|
+
x, y = latlon_2_xy(lat, lon, z)
|
39
|
+
[x.to_i, y.to_i]
|
40
|
+
end
|
41
|
+
|
42
|
+
def xy_2_latlon(x, y, z)
|
43
|
+
n = num_tiles(z)
|
44
|
+
rel_y = y / n
|
45
|
+
lat = mercator_to_lat(Math::PI * (1 - 2 * rel_y))
|
46
|
+
lon = -180.0 + 360.0 * x / n
|
47
|
+
[lat, lon]
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def num_tiles(z)
|
54
|
+
2 ** z.to_f
|
55
|
+
end
|
56
|
+
|
57
|
+
def sec(x)
|
58
|
+
1 / Math.cos(x)
|
59
|
+
end
|
60
|
+
|
61
|
+
def latlon_2_relative_xy(lat,lon)
|
62
|
+
x = (lon + 180) / 360
|
63
|
+
y = (1 - Math.log(Math.tan(to_radians(lat)) + sec(to_radians(lat))) / Math::PI) / 2
|
64
|
+
[x,y]
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_radians(degrees)
|
68
|
+
degrees * Math::PI / 180
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_degrees(radians)
|
72
|
+
radians * 180 / Math::PI
|
73
|
+
end
|
74
|
+
|
75
|
+
def latlon_2_xy(lat, lon, z)
|
76
|
+
n = num_tiles(z)
|
77
|
+
x, y = latlon_2_relative_xy(lat, lon)
|
78
|
+
[n * x, n * y]
|
79
|
+
end
|
80
|
+
|
81
|
+
def mercator_to_lat(mercator_y)
|
82
|
+
to_degrees Math.atan(Math.sinh(mercator_y))
|
83
|
+
end
|
84
|
+
|
85
|
+
def lat_edges(y, z)
|
86
|
+
n = num_tiles(z)
|
87
|
+
unit = 1 / n
|
88
|
+
rel_y1 = y * unit
|
89
|
+
rel_y2 = rel_y1 + unit
|
90
|
+
lat1 = mercator_to_lat(Math::PI * (1 - 2 * rel_y1))
|
91
|
+
lat2 = mercator_to_lat(Math::PI * (1 - 2 * rel_y2))
|
92
|
+
[lat1, lat2]
|
93
|
+
end
|
94
|
+
|
95
|
+
def lon_edges(x, z)
|
96
|
+
n = num_tiles(z)
|
97
|
+
unit = 360 / n
|
98
|
+
lon1 = -180 + x * unit
|
99
|
+
lon2 = lon1 + unit
|
100
|
+
[lon1, lon2]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# tile = Mormon::Tile::Name.new
|
107
|
+
|
108
|
+
# (0..16).each do |z|
|
109
|
+
# x, y = tile.xy 51.50610, -0.119888, z
|
110
|
+
# s, w, n, e = tile.edges(x, y, z)
|
111
|
+
# # puts tile.url(x,y,z, :tah)
|
112
|
+
# end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Mormon
|
2
|
+
class Weight
|
3
|
+
# Represents an hipotetical velocity of the transport in the way type
|
4
|
+
@weightings = {
|
5
|
+
motorway: { car: 10 },
|
6
|
+
trunk: { car: 10, cycle: 0.05 },
|
7
|
+
primary: { cycle: 0.3, car: 2, foot: 1, horse: 0.1 },
|
8
|
+
secondary: { cycle: 1, car: 1.5, foot: 1, horse: 0.2 },
|
9
|
+
tertiary: { cycle: 1, car: 1, foot: 1, horse: 0.3 },
|
10
|
+
unclassified: { cycle: 1, car: 1, foot: 1, horse: 1 },
|
11
|
+
minor: { cycle: 1, car: 1, foot: 1, horse: 1 },
|
12
|
+
cycleway: { cycle: 3, foot: 0.2 },
|
13
|
+
residential: { cycle: 3, car: 0.7, foot: 1, horse: 1 },
|
14
|
+
track: { cycle: 1, car: 1, foot: 1, horse: 1, mtb: 3 },
|
15
|
+
service: { cycle: 1, car: 1, foot: 1, horse: 1 },
|
16
|
+
bridleway: { cycle: 0.8, foot: 1, horse: 10, mtb: 3 },
|
17
|
+
footway: { cycle: 0.2, foot: 1 },
|
18
|
+
steps: { foot: 1, cycle: 0.3 },
|
19
|
+
rail: { train: 1 },
|
20
|
+
light_rail: { train: 1 },
|
21
|
+
subway: { train: 1 }
|
22
|
+
}
|
23
|
+
|
24
|
+
def self.weightings
|
25
|
+
@weightings
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.get(transport, way_type)
|
29
|
+
@weightings[way_type] && @weightings[way_type][transport]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/mormon.rb
ADDED
data/mormon.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'mormon/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "mormon"
|
8
|
+
gem.version = Mormon::VERSION
|
9
|
+
gem.authors = ["Geronimo Diaz"]
|
10
|
+
gem.email = ["geronimod@gmail.com"]
|
11
|
+
gem.description = %q{ OSM Router }
|
12
|
+
gem.summary = %q{ OSM Routing with some extra features: reset tiles cache and random routes. It's based on Pyroute library. }
|
13
|
+
gem.homepage = "https://github.com/geronimod/mormon"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.rubyforge_project = "mormon"
|
21
|
+
|
22
|
+
gem.add_dependency "nokogiri"
|
23
|
+
gem.add_development_dependency "rspec"
|
24
|
+
gem.add_development_dependency "debugger"
|
25
|
+
end
|