active_road 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.rspec +1 -0
- data/.travis.yml +7 -2
- data/Gemfile +8 -2
- data/Guardfile +2 -6
- data/README.md +69 -9
- data/Rakefile +8 -7
- data/active_road.gemspec +19 -15
- data/app/models/active_road/access_link.rb +4 -4
- data/app/models/active_road/access_point.rb +5 -9
- data/app/models/active_road/boundary.rb +41 -0
- data/app/models/active_road/junction.rb +4 -18
- data/app/models/active_road/junction_conditionnal_cost.rb +2 -0
- data/app/models/active_road/junctions_physical_road.rb +5 -0
- data/app/models/active_road/logical_road.rb +5 -4
- data/app/models/active_road/osm_pbf_importer.rb +293 -0
- data/app/models/active_road/osm_pbf_importer_level_db.rb +784 -0
- data/app/models/active_road/path.rb +40 -9
- data/app/models/active_road/physical_road.rb +22 -27
- data/app/models/active_road/physical_road_conditionnal_cost.rb +3 -1
- data/app/models/active_road/request_conditionnal_cost_linker.rb +59 -0
- data/app/models/active_road/street_number.rb +60 -57
- data/app/models/active_road/terra_importer.rb +161 -0
- data/db/migrate/20120419093427_add_kind_to_physical_roads.rb +2 -2
- data/db/migrate/20140206091734_create_boundaries.rb +16 -0
- data/db/migrate/20140210132933_add_attributes_to_physical_road.rb +9 -0
- data/db/migrate/20140219095521_add_boundary_id_to_logical_road.rb +5 -0
- data/db/migrate/20140228072448_add_boundary_id_to_physical_road.rb +5 -0
- data/db/migrate/20140304141150_add_marker_to_physical_road.rb +5 -0
- data/db/migrate/20140310083550_add_tags_to_street_number.rb +5 -0
- data/db/migrate/20140317153437_add_index_to_conditionnal_costs.rb +6 -0
- data/db/migrate/20140602160047_add_physical_road_index_to_junctions_physical_road.rb +5 -0
- data/lib/active_road.rb +8 -2
- data/lib/active_road/engine.rb +4 -1
- data/lib/active_road/shortest_path/finder.rb +37 -46
- data/lib/active_road/simulation_tool.rb +73 -0
- data/lib/active_road/version.rb +1 -1
- data/lib/tasks/activeroad_tasks.rake +88 -4
- data/script/benchmark_import_kyotocabinet.rb +148 -0
- data/script/benchmark_shortest_path.rb +22 -0
- data/script/count_tag_in_osm_data.rb +114 -0
- data/script/import-tiger-numbers +3 -3
- data/spec/dummy/db/schema.rb +2 -1
- data/spec/dummy/db/structure.sql +100 -11
- data/spec/factories/boundary.rb +8 -0
- data/spec/factories/junction.rb +1 -1
- data/spec/factories/physical_road.rb +1 -2
- data/spec/fixtures/test.osm +120 -0
- data/spec/fixtures/test.osm.bz2 +0 -0
- data/spec/fixtures/test.osm.pbf +0 -0
- data/spec/lib/active_road/shortest_path/finder_spec.rb +143 -90
- data/spec/lib/active_road/shortest_path/performance_finder_spec.rb +59 -0
- data/spec/models/active_road/access_point_spec.rb +9 -18
- data/spec/models/active_road/junction_conditionnal_cost_spec.rb +4 -4
- data/spec/models/active_road/junction_spec.rb +34 -11
- data/spec/models/active_road/logical_road_spec.rb +20 -19
- data/spec/models/active_road/osm_pbf_importer_level_db_spec.rb +410 -0
- data/spec/models/active_road/path_spec.rb +1 -1
- data/spec/models/active_road/physical_road_conditionnal_cost_spec.rb +4 -4
- data/spec/models/active_road/physical_road_spec.rb +14 -3
- data/spec/models/active_road/request_conditionnal_cost_linker_spec.rb +65 -0
- data/spec/models/active_road/shared_examples/osm_pbf_importer_spec.rb +148 -0
- data/spec/models/active_road/street_number_spec.rb +58 -58
- data/spec/models/active_road/terra_importer_spec.rb +140 -0
- data/spec/spec_helper.rb +14 -9
- data/spec/support/geometry_support.rb +36 -0
- data/spec/support/profile.rb +19 -0
- data/tmp/performance/.gitignore +0 -0
- data/travis/before_install.sh +5 -9
- data/travis/before_script.sh +7 -7
- metadata +118 -121
- data/app/models/active_road/physical_road_filter.rb +0 -41
- data/app/models/active_road/terra_import.rb +0 -148
- data/spec/models/active_road/physical_road_filter_spec.rb +0 -85
- data/spec/models/active_road/terra_import_spec.rb +0 -113
- data/spec/support/georuby_ext.rb +0 -15
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
YWZlZDYwNDEyOGU0Yjk4OGU5NDU1ZmMxYjA4ZmIzNjk4ODAwZjMxOA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
MjA5NTk3MTgzMDk1MWJkNWQ3YzNjYzEyMTA3YzZhMGI5YTM1ZDkyOA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZDUxMTViZDcyNGFhZGZkN2JlYjAzMjQ3ZWU0NzI5NWRkZjY5Yzg1M2FlZjQ3
|
10
|
+
ZWNlNzg1OGFmYWNjZWZiOThiYjIyYWZlYzVhODFlNDUzZjIyZDMzNmY1NjQx
|
11
|
+
MjA4NWFhYjZiZjVlZGM3NjVhOWU1ZWFhNDBkZTk2YmM3YTNmNWQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
YzIyYWIyYjY1ZjM2Yjc3NTkyM2ZhODBkYzRkZGFhYzgxYTZhNzQzNjM3Y2M5
|
14
|
+
MDgwZDNhMTczZDQ0OWI4MDBmMDQyZGE4MjZhMmU2ODMwNDIzMmNjYWNjMjJk
|
15
|
+
OTY3MzZkMDI1YTVkZWNhN2IxMTQ5ODIxZGRlZDI4Njc3YmVkOGE=
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--colour
|
data/.travis.yml
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
language: ruby
|
2
|
+
addons:
|
3
|
+
postgresql: "9.2"
|
2
4
|
rvm:
|
3
5
|
- 1.9.3
|
4
|
-
|
5
|
-
|
6
|
+
- 2.0
|
7
|
+
notifications:
|
8
|
+
recipients:
|
9
|
+
- mflorisson@cityway.fr
|
10
|
+
- ldonnet@cityway.fr
|
6
11
|
before_install: ./travis/before_install.sh
|
7
12
|
before_script:
|
8
13
|
- ./travis/before_script.sh
|
data/Gemfile
CHANGED
@@ -3,12 +3,18 @@ source "http://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in activeroad.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
gem 'dr-postgis_adapter', :require =>
|
6
|
+
gem 'dr-postgis_adapter', :require => 'postgis_adapter'
|
7
|
+
gem 'coveralls', require: false
|
7
8
|
|
8
9
|
group :development do
|
9
|
-
gem
|
10
|
+
gem "rails-erd" # Tool to make schema class
|
10
11
|
group :linux do
|
11
12
|
gem 'rb-inotify', :require => RUBY_PLATFORM.include?('linux') && 'rb-inotify'
|
12
13
|
gem 'rb-fsevent', :require => RUBY_PLATFORM.include?('darwin') && 'rb-fsevent'
|
13
14
|
end
|
14
15
|
end
|
16
|
+
|
17
|
+
group :development, :test do
|
18
|
+
gem "ruby-prof"
|
19
|
+
gem "bullet"
|
20
|
+
end
|
data/Guardfile
CHANGED
@@ -2,8 +2,9 @@ guard 'bundler' do
|
|
2
2
|
watch('Gemfile')
|
3
3
|
end
|
4
4
|
|
5
|
-
guard 'rspec', :
|
5
|
+
guard 'rspec', :notification => false do
|
6
6
|
watch(%r{^spec/.+_spec\.rb$})
|
7
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
7
8
|
watch('spec/spec_helper.rb') { "spec" }
|
8
9
|
|
9
10
|
# Rails example
|
@@ -19,8 +20,3 @@ guard 'rspec', :version => 2, :notification => false, :bundler => true, :binstub
|
|
19
20
|
watch(%r{^app/views/(.+)/.*\.(erb|haml)$}) { |m| "spec/requests/#{m[1]}_spec.rb" }
|
20
21
|
end
|
21
22
|
|
22
|
-
guard 'migrate' do
|
23
|
-
watch(%r{^db/migrate/(\d+).+\.rb})
|
24
|
-
watch('db/seeds.rb')
|
25
|
-
end
|
26
|
-
|
data/README.md
CHANGED
@@ -1,29 +1,89 @@
|
|
1
|
-
# ActiveRoad
|
1
|
+
# ActiveRoad
|
2
|
+
[![Build Status](https://travis-ci.org/cityway-transdev/activeroad.png)](http://travis-ci.org/cityway-transdev/activeroad?branch=master) [![Dependency Status](https://gemnasium.com/cityway-transdev/activeroad.png)](https://gemnasium.com/cityway-transdev/activeroad) [![Code Climate](https://codeclimate.com/github/cityway-transdev/activeroad.png)](https://codeclimate.com/github/cityway-transdev/activeroad) [![Coverage Status](https://img.shields.io/coveralls/cityway-transdev/activeroad.svg)](https://coveralls.io/r/cityway-transdev/activeroad?branch=master)
|
2
3
|
|
3
|
-
|
4
|
+
ActiveRoads is a rails engine with a specific models for transport networks. It allows to :
|
5
|
+
- import osm ways form openstreetmap datas (PBF file format)
|
6
|
+
- make an itinerary research
|
7
|
+
The goal of this project is not to make the faster itinerary search engine like [OSRM](http://map.project-osrm.org/) or [OpenTripPlanner](http://www.opentripplanner.org/) but the more flexible because it doesn't need to binarize datas.
|
4
8
|
|
5
9
|
Requirements
|
6
10
|
------------
|
7
11
|
|
8
|
-
This code has been run and tested on
|
12
|
+
This code has been run and tested on :
|
13
|
+
* Ruby 1.9.3 and ruby 2.0
|
14
|
+
* Postgresql 9.X
|
15
|
+
* Postgis 2.X
|
16
|
+
|
17
|
+
External Deps
|
18
|
+
-------------
|
19
|
+
On Debian/Ubuntu/Kubuntu OS :
|
20
|
+
```sh
|
21
|
+
sudo apt-get install git postgresql postgis build-essential ruby-dev libproj-dev libgeos-dev libffi-dev zlib1g-dev libxslt1-dev libxml2-dev libbz2-dev libleveldb-dev libsnappy-dev
|
22
|
+
```
|
9
23
|
|
10
24
|
Installation
|
11
25
|
------------
|
12
26
|
|
13
27
|
This package is available in RubyGems and can be installed with:
|
14
|
-
|
15
|
-
|
28
|
+
```sh
|
29
|
+
gem install active_road
|
30
|
+
```
|
16
31
|
|
17
32
|
More Information
|
18
33
|
----------------
|
19
34
|
|
20
|
-
More information can be found on the [project website on GitHub](http://github.com/
|
21
|
-
There is extensive usage documentation available [on the wiki](https://github.com/
|
35
|
+
More information can be found on the [project website on GitHub](http://github.com/cityway-transdev/activeroad).
|
36
|
+
There is extensive usage documentation available [on the wiki](https://github.com/cityway-transdev/activeroad/wiki).
|
22
37
|
|
23
38
|
Example Usage
|
24
39
|
------------
|
25
40
|
|
26
|
-
|
41
|
+
### Import OSM ways
|
42
|
+
|
43
|
+
```sh
|
44
|
+
bundle exec rake "app:active_road:import:osm_pbf_data[/home/user/test.osm.pbf]"
|
45
|
+
|
46
|
+
```
|
47
|
+
|
48
|
+
### Itinerary research
|
49
|
+
|
50
|
+
Example of basic finder :
|
51
|
+
|
52
|
+
Actually we can use only 4 transport modes :
|
53
|
+
* car
|
54
|
+
* train
|
55
|
+
* pedestrian
|
56
|
+
* bike
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
from = GeoRuby::SimpleFeatures::Point.from_x_y(-52.652771, 5.174379)
|
60
|
+
to = GeoRuby::SimpleFeatures::Point.from_x_y(-52.323182, 4.941829)
|
61
|
+
speed = 4 # In kilometer/hour
|
62
|
+
finder = ActiveRoad::ShortestPath::Finder.new(from, to, speed).tap do |finder|
|
63
|
+
finder.timeout = 30.seconds
|
64
|
+
end
|
65
|
+
|
66
|
+
# Get geometry
|
67
|
+
finder.geometry
|
68
|
+
|
69
|
+
# Get steps
|
70
|
+
finder.paths
|
71
|
+
```
|
72
|
+
|
73
|
+
For a more complex query, you can use constraints arguments. It's an array of string which
|
74
|
+
describes :
|
75
|
+
* if we use conditionnal cost for a physical road Ex : ["car"]
|
76
|
+
* if we not use a physical road because it contains a specific conditionnal cost Ex : ["~car"]
|
77
|
+
|
78
|
+
```ruby
|
79
|
+
from = GeoRuby::SimpleFeatures::Point.from_x_y(-52.652771, 5.174379)
|
80
|
+
to = GeoRuby::SimpleFeatures::Point.from_x_y(-52.323182, 4.941829)
|
81
|
+
speed = 50 # In kilometer/hour
|
82
|
+
constraints = ["car"]
|
83
|
+
finder = ActiveRoad::ShortestPath::Finder.new(from, to, speed, constraints).tap do |finder|
|
84
|
+
finder.timeout = 30.seconds
|
85
|
+
end
|
86
|
+
```
|
27
87
|
|
28
88
|
License
|
29
89
|
-------
|
@@ -34,4 +94,4 @@ This project is licensed under the MIT license, a copy of which can be found in
|
|
34
94
|
Support
|
35
95
|
-------
|
36
96
|
|
37
|
-
Users looking for support should file an issue on the GitHub issue tracking page (https://github.com/
|
97
|
+
Users looking for support should file an issue on the GitHub issue tracking page (https://github.com/cityway-transdev/activeroad/issues), or file a pull request (https://github.com/cityway-transdev/activeroad/pulls) if you have a fix available.
|
data/Rakefile
CHANGED
@@ -5,13 +5,6 @@ rescue LoadError
|
|
5
5
|
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
6
|
end
|
7
7
|
|
8
|
-
namespace :ci do
|
9
|
-
task :prepare do
|
10
|
-
cp "config/database.yml.ci", "config/database.yml"
|
11
|
-
end
|
12
|
-
task :build => ["db:migrate", "spec"]
|
13
|
-
end
|
14
|
-
|
15
8
|
begin
|
16
9
|
require 'rdoc/task'
|
17
10
|
rescue LoadError
|
@@ -44,3 +37,11 @@ RSpec::Core::RakeTask.new(:rcov) do |t|
|
|
44
37
|
end
|
45
38
|
|
46
39
|
task :spec => "app:db:test:prepare"
|
40
|
+
|
41
|
+
namespace :ci do
|
42
|
+
task :prepare do
|
43
|
+
cp "config/database.yml.ci", "config/database.yml"
|
44
|
+
end
|
45
|
+
task :build => ["db:migrate", "spec"]
|
46
|
+
end
|
47
|
+
|
data/active_road.gemspec
CHANGED
@@ -7,9 +7,12 @@ Gem::Specification.new do |s|
|
|
7
7
|
s.version = ActiveRoad::VERSION
|
8
8
|
s.authors = ["Alban Peignier", "Luc Donnet", "Marc Florisson"]
|
9
9
|
s.email = ["alban@tryphon.eu", "luc.donnet@free.fr", "mflorisson@gmail.com"]
|
10
|
-
s.homepage = ""
|
11
|
-
s.summary = %q{Rails engine to
|
12
|
-
s.description = %q{
|
10
|
+
s.homepage = "https://rubygems.org/gems/active_road"
|
11
|
+
s.summary = %q{Rails engine to import openstreetmap datas and make an itinerary research}
|
12
|
+
s.description = %q{Import openstreetmap datas and make an itinerary research}
|
13
|
+
s.required_ruby_version = '>= 1.9.3'
|
14
|
+
s.license = 'MIT'
|
15
|
+
#spec.requirements << 'libsnappy-dev, v6.0'
|
13
16
|
|
14
17
|
s.files = `git ls-files`.split("\n")
|
15
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -19,20 +22,21 @@ Gem::Specification.new do |s|
|
|
19
22
|
s.add_development_dependency "guard"
|
20
23
|
s.add_development_dependency "guard-bundler"
|
21
24
|
s.add_development_dependency "guard-rspec"
|
22
|
-
s.add_development_dependency "
|
23
|
-
s.add_development_dependency "
|
24
|
-
s.add_development_dependency
|
25
|
-
s.add_development_dependency 'rails', '~> 3.2.13'
|
25
|
+
s.add_development_dependency "factory_girl_rails", ">= 4.2.1"
|
26
|
+
s.add_development_dependency "rspec-rails", '~> 3.1.0'
|
27
|
+
s.add_development_dependency 'rails', '>=3.1.12'
|
26
28
|
|
27
|
-
s.add_dependency 'activerecord'
|
29
|
+
s.add_dependency 'activerecord', '3.2.18'
|
28
30
|
s.add_dependency 'activerecord-postgres-hstore'
|
29
|
-
s.add_dependency 'dr-postgis_adapter', '0.8.
|
30
|
-
s.add_dependency '
|
31
|
-
s.add_dependency '
|
32
|
-
s.add_dependency 'activerecord-import', '~> 0.3.1'
|
33
|
-
s.add_dependency 'georuby-ext', "0.0.2"
|
31
|
+
s.add_dependency 'dr-postgis_adapter', '0.8.4'
|
32
|
+
s.add_dependency 'pg', '>= 0.15.1'
|
33
|
+
s.add_dependency 'georuby-ext', "0.0.5"
|
34
34
|
s.add_dependency 'nokogiri'
|
35
35
|
s.add_dependency 'saxerator'
|
36
|
-
s.add_dependency 'shortest_path', '0.0.
|
37
|
-
s.add_dependency 'enumerize', '0.
|
36
|
+
s.add_dependency 'shortest_path', '0.0.4'
|
37
|
+
s.add_dependency 'enumerize', '0.7.0'
|
38
|
+
s.add_dependency "pbf_parser", '~> 0.0.6'
|
39
|
+
s.add_dependency "leveldb-native", '~> 0.6'
|
40
|
+
s.add_dependency "snappy"
|
41
|
+
s.add_dependency 'postgres-copy', '~> 0.6.O'
|
38
42
|
end
|
@@ -14,8 +14,8 @@ class ActiveRoad::AccessLink
|
|
14
14
|
|
15
15
|
alias_method :to_s, :name
|
16
16
|
|
17
|
-
def self.from(location
|
18
|
-
ActiveRoad::AccessPoint.from(location
|
17
|
+
def self.from(location)
|
18
|
+
ActiveRoad::AccessPoint.from(location).collect do |access_point|
|
19
19
|
new :departure => location, :arrival => access_point
|
20
20
|
end
|
21
21
|
end
|
@@ -33,8 +33,8 @@ class ActiveRoad::AccessLink
|
|
33
33
|
|
34
34
|
delegate :access_to_road?, :to => :arrival
|
35
35
|
|
36
|
-
def paths
|
37
|
-
arrival.respond_to?(:paths) ? arrival.paths
|
36
|
+
def paths
|
37
|
+
arrival.respond_to?(:paths) ? arrival.paths : [arrival]
|
38
38
|
end
|
39
39
|
|
40
40
|
def access_to_road?(road)
|
@@ -13,19 +13,15 @@ class ActiveRoad::AccessPoint
|
|
13
13
|
end
|
14
14
|
|
15
15
|
# Find access points from a location
|
16
|
-
def self.from(location
|
17
|
-
|
18
|
-
|
19
|
-
physical_roads_filtered.nearest_to(location, 100).collect do |physical_road|
|
16
|
+
def self.from(location)
|
17
|
+
ActiveRoad::PhysicalRoad.nearest_to(location).collect do |physical_road|
|
20
18
|
new :location => location, :physical_road => physical_road
|
21
19
|
end
|
22
20
|
end
|
23
21
|
|
24
22
|
# Find access points to go to a location
|
25
|
-
def self.to(location
|
26
|
-
|
27
|
-
|
28
|
-
physical_roads_filtered.nearest_to(location, 100).collect do |physical_road|
|
23
|
+
def self.to(location)
|
24
|
+
ActiveRoad::PhysicalRoad.nearest_to(location).collect do |physical_road|
|
29
25
|
new :location => location, :physical_road => physical_road, :exit => true
|
30
26
|
end
|
31
27
|
end
|
@@ -41,7 +37,7 @@ class ActiveRoad::AccessPoint
|
|
41
37
|
alias_method :geometry, :point_on_road
|
42
38
|
|
43
39
|
def access_to_road?(road)
|
44
|
-
physical_road == road
|
40
|
+
physical_road.id == road.id
|
45
41
|
end
|
46
42
|
|
47
43
|
def name
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ActiveRoad
|
2
|
+
class Boundary < ActiveRoad::Base
|
3
|
+
#set_table_name :boundaries
|
4
|
+
attr_accessible :objectid, :geometry, :name, :admin_level, :postal_code, :insee_code
|
5
|
+
acts_as_geom :geometry => :multi_polygon
|
6
|
+
|
7
|
+
# Return linear rings which delimit multi polygon area
|
8
|
+
def self.all_uniq_borders
|
9
|
+
borders = self.all.collect(&:geometry).collect(&:polygons).flatten(1).collect(&:rings).flatten(1).uniq
|
10
|
+
GeoRuby::SimpleFeatures::MultiLineString.from_line_strings(borders)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Return linear rings which delimit multi polygon area
|
14
|
+
def borders
|
15
|
+
geometry.polygons.collect(&:rings).flatten
|
16
|
+
end
|
17
|
+
|
18
|
+
def intersection(other)
|
19
|
+
postgis_calculate(:intersection, [self, other])
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
def difference(other)
|
24
|
+
postgis_calculate(:difference, [self, other])
|
25
|
+
end
|
26
|
+
|
27
|
+
def sym_difference(other)
|
28
|
+
postgis_calculate(:symDifference, [self, other])
|
29
|
+
end
|
30
|
+
|
31
|
+
# Contains not take object equals on a boundary border!!
|
32
|
+
def self.first_contains(other)
|
33
|
+
where("ST_Contains(geometry, ST_GeomFromEWKT(E'#{other.as_hex_ewkb}'))").first
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.all_intersect(other)
|
37
|
+
where("ST_Intersects(geometry, ST_GeomFromEWKT(E'#{other.as_hex_ewkb}'))")
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
@@ -1,6 +1,4 @@
|
|
1
1
|
# A junction is a connection between 1 to n physical roads
|
2
|
-
require "activerecord-postgres-hstore"
|
3
|
-
|
4
2
|
module ActiveRoad
|
5
3
|
class Junction < ActiveRoad::Base
|
6
4
|
serialize :tags, ActiveRecord::Coders::Hstore
|
@@ -11,30 +9,18 @@ module ActiveRoad
|
|
11
9
|
has_and_belongs_to_many :physical_roads, :class_name => "ActiveRoad::PhysicalRoad",:uniq => true
|
12
10
|
has_many :junction_conditionnal_costs, :class_name => "ActiveRoad::JunctionConditionnalCost"
|
13
11
|
|
14
|
-
%w[max_speed, max_slope].each do |key|
|
15
|
-
attr_accessible key
|
16
|
-
scope "has_#{key}", lambda { |value| where("properties @> hstore(?, ?)", key, value) }
|
17
|
-
define_method(key) do
|
18
|
-
properties && properties[key]
|
19
|
-
end
|
20
|
-
|
21
|
-
define_method("#{key}=") do |value|
|
22
|
-
self.properties = (properties || {}).merge(key => value)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
12
|
def location_on_road(road)
|
27
13
|
(@location_on_road ||= {})[road.id] ||= road.locate_point(geometry)
|
28
14
|
end
|
29
15
|
|
30
|
-
def paths
|
31
|
-
|
16
|
+
def paths
|
17
|
+
physical_roads.includes(:junctions, :physical_road_conditionnal_costs).collect do |physical_road|
|
32
18
|
ActiveRoad::Path.all self, (physical_road.junctions - [self]), physical_road
|
33
19
|
end.flatten
|
34
20
|
end
|
35
21
|
|
36
22
|
def access_to_road?(road)
|
37
|
-
physical_roads.include? road
|
23
|
+
physical_roads.pluck(:id).include? road.id
|
38
24
|
end
|
39
25
|
|
40
26
|
def to_geometry
|
@@ -42,7 +28,7 @@ module ActiveRoad
|
|
42
28
|
end
|
43
29
|
|
44
30
|
def to_s
|
45
|
-
"Junction @#{geometry.
|
31
|
+
"Junction @#{geometry.lng},#{geometry.lat}"
|
46
32
|
end
|
47
33
|
|
48
34
|
def name
|
@@ -1,5 +1,6 @@
|
|
1
1
|
module ActiveRoad
|
2
2
|
class JunctionConditionnalCost < ActiveRoad::Base
|
3
|
+
attr_accessible :tags, :cost, :start_physical_road, :end_physical_road
|
3
4
|
|
4
5
|
belongs_to :junction
|
5
6
|
belongs_to :start_physical_road, :class_name => 'ActiveRoad::PhysicalRoad', :foreign_key => 'start_physical_road_id'
|
@@ -7,6 +8,7 @@ module ActiveRoad
|
|
7
8
|
|
8
9
|
validates_presence_of :junction_id
|
9
10
|
validates_presence_of :tags
|
11
|
+
validates_uniqueness_of :tags
|
10
12
|
validates_presence_of :cost
|
11
13
|
|
12
14
|
end
|
@@ -1,13 +1,14 @@
|
|
1
1
|
module ActiveRoad
|
2
2
|
class LogicalRoad < ActiveRoad::Base
|
3
3
|
extend ActiveSupport::Memoizable
|
4
|
-
attr_accessible :objectid, :name
|
5
|
-
|
6
|
-
validates_uniqueness_of :objectid
|
4
|
+
attr_accessible :objectid, :name, :boundary_id
|
7
5
|
|
8
6
|
has_many :physical_roads, :class_name => "ActiveRoad::PhysicalRoad", :inverse_of => :logical_road
|
9
|
-
|
10
7
|
has_many :numbers, :through => :physical_roads, :class_name => "ActiveRoad::StreetNumber"
|
8
|
+
belongs_to :boundary, :class_name => "ActiveRoad::Boundary"
|
9
|
+
|
10
|
+
#validates_uniqueness_of :objectid
|
11
|
+
#validates :boundary, presence: true
|
11
12
|
|
12
13
|
def geometry
|
13
14
|
GeoRuby::SimpleFeatures::MultiLineString.from_line_strings physical_roads.map(&:geometry)
|
@@ -0,0 +1,293 @@
|
|
1
|
+
module ActiveRoad
|
2
|
+
module OsmPbfImporter
|
3
|
+
|
4
|
+
@@relation_required_tags_keys = ["boundary", "admin_level"]
|
5
|
+
@@relation_selected_tags_keys = ["boundary", "admin_level", "ref:INSEE", "name", "addr:postcode", "type"]
|
6
|
+
mattr_reader :relation_required_tags_keys
|
7
|
+
mattr_reader :relation_selected_tags_keys
|
8
|
+
|
9
|
+
@@way_required_tags_keys = ["highway", "railway", "boundary", "admin_level", "addr:housenumber"]
|
10
|
+
@@way_for_physical_road_required_tags_keys = ["highway", "railway"]
|
11
|
+
@@way_for_boundary_required_tags_keys = ["boundary", "admin_level"]
|
12
|
+
@@way_for_street_number_required_tags_keys = ["addr:housenumber"]
|
13
|
+
@@way_selected_tags_keys = [ "name", "maxspeed", "oneway", "boundary", "admin_level", "addr:housenumber" ]
|
14
|
+
# Add first_node_id and last_node_id
|
15
|
+
@@way_optionnal_tags_keys = ["highway", "maxspeed", "bridge", "tunnel", "toll", "cycleway", "cycleway-right", "cycleway-left", "cycleway-both", "oneway:bicycle", "oneway", "bicycle", "segregated", "foot", "lanes", "lanes:forward", "lanes:forward:bus", "busway:right", "busway:left", "oneway_bus", "boundary", "admin_level", "access", "construction", "junction", "motor_vehicle", "psv", "bus", "addr:city", "addr:country", "addr:state", "addr:street"]
|
16
|
+
mattr_reader :way_required_tags_keys
|
17
|
+
mattr_reader :way_for_physical_road_required_tags_keys
|
18
|
+
mattr_reader :way_for_boundary_required_tags_keys
|
19
|
+
mattr_reader :way_for_street_number_required_tags_keys
|
20
|
+
mattr_reader :way_selected_tags_keys
|
21
|
+
mattr_reader :way_optionnal_tags_keys
|
22
|
+
|
23
|
+
@@nodes_selected_tags_keys = [ "addr:housenumber", "addr:city", "addr:postcode", "addr:street" ]
|
24
|
+
mattr_reader :nodes_selected_tags_keys
|
25
|
+
|
26
|
+
@@pg_batch_size = 10000 # Not Rails.logger.debug a high value because postgres failed to allocate memory
|
27
|
+
mattr_reader :pg_batch_size
|
28
|
+
|
29
|
+
def self.included(base)
|
30
|
+
base.extend(ClassMethods)
|
31
|
+
end
|
32
|
+
|
33
|
+
module ClassMethods
|
34
|
+
end
|
35
|
+
|
36
|
+
def pedestrian?(tags)
|
37
|
+
highway_tag_values = %w{pedestrian footway path steps}
|
38
|
+
if tags["highway"].present? && highway_tag_values.include?(tags["highway"])
|
39
|
+
true
|
40
|
+
else
|
41
|
+
false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# http://wiki.openstreetmap.org/wiki/FR:Cycleway
|
46
|
+
# http://wiki.openstreetmap.org/wiki/FR:Bicycle
|
47
|
+
def bike?(tags)
|
48
|
+
highway_tag_values = %w{cycleway}
|
49
|
+
bike_tags_keys = ["cycleway:left", "cycleway:right", "cycleway", "cycleway:left"]
|
50
|
+
|
51
|
+
if (tags["highway"].present? && highway_tag_values.include?(tags["highway"])) || (bike_tags_keys & tags.keys).present?
|
52
|
+
true
|
53
|
+
else
|
54
|
+
false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# http://wiki.openstreetmap.org/wiki/Key:railway
|
59
|
+
def train?(tags)
|
60
|
+
railway_tag_values = %w{rail tram funicular light_rail subway}
|
61
|
+
if tags["railway"].present? && railway_tag_values.include?(tags["railway"])
|
62
|
+
true
|
63
|
+
else
|
64
|
+
false
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# http://wiki.openstreetmap.org/wiki/FR:France_roads_tagging
|
69
|
+
def car?(tags)
|
70
|
+
highway_tag_values = %w{motorway trunk trunk_link primary secondary tertiary motorway_link primary_link unclassified service road residential track}
|
71
|
+
if tags["highway"].present? && highway_tag_values.include?(tags["highway"])
|
72
|
+
true
|
73
|
+
else
|
74
|
+
false
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def required_way?(required_tags, tags)
|
79
|
+
required_tags.each do |require_tag_key|
|
80
|
+
if tags.keys.include?(require_tag_key)
|
81
|
+
return true
|
82
|
+
end
|
83
|
+
end
|
84
|
+
return false
|
85
|
+
end
|
86
|
+
|
87
|
+
def required_relation?(tags)
|
88
|
+
@@relation_required_tags_keys.each do |require_tag_key|
|
89
|
+
if tags.keys.include?(require_tag_key)
|
90
|
+
return true
|
91
|
+
end
|
92
|
+
end
|
93
|
+
return false
|
94
|
+
end
|
95
|
+
|
96
|
+
# Return an hash with tag_key => tag_value for osm attributes
|
97
|
+
def selected_tags(tags, selected_tags_keys)
|
98
|
+
{}.tap do |selected_tags|
|
99
|
+
tags.each do |key, value|
|
100
|
+
if selected_tags_keys.include?(key)
|
101
|
+
selected_tags[key] = value
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
# def extract_tag_value(tag_value)
|
108
|
+
# case tag_value
|
109
|
+
# when "yes" : 1
|
110
|
+
# when "no" : 0
|
111
|
+
# when /[0-9].+/i tag_value.to_f
|
112
|
+
# else 0
|
113
|
+
# end
|
114
|
+
# end
|
115
|
+
|
116
|
+
def physical_road_conditionnal_costs(way)
|
117
|
+
[].tap do |prcc|
|
118
|
+
prcc << [ "car", Float::MAX] if !way.car
|
119
|
+
prcc << [ "pedestrian", Float::MAX] if !way.pedestrian
|
120
|
+
prcc << [ "bike", Float::MAX] if !way.bike
|
121
|
+
prcc << [ "train", Float::MAX] if !way.train
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def extract_relation_polygon(outer_geometries, inner_geometries = [])
|
126
|
+
outer_rings = join_ways(outer_geometries)
|
127
|
+
inner_rings = join_ways(inner_geometries)
|
128
|
+
|
129
|
+
# TODO : Fix the case where many outer rings with many inner rings
|
130
|
+
polygons = [].tap do |polygons|
|
131
|
+
outer_rings.each { |outer_ring|
|
132
|
+
polygons << GeoRuby::SimpleFeatures::Polygon.from_linear_rings( [outer_ring] + inner_rings )
|
133
|
+
}
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def join_ways(ways)
|
138
|
+
closed_ways = []
|
139
|
+
endpoints_to_ways = EndpointToWayMap.new
|
140
|
+
for way in ways
|
141
|
+
if way.closed?
|
142
|
+
closed_ways << way
|
143
|
+
next
|
144
|
+
end
|
145
|
+
|
146
|
+
# Are there any existing ways we can join this to?
|
147
|
+
to_join_to = endpoints_to_ways.get_from_either_end(way)
|
148
|
+
if to_join_to.present?
|
149
|
+
joined = way
|
150
|
+
for existing_way in to_join_to
|
151
|
+
joined = join_way(joined, existing_way)
|
152
|
+
endpoints_to_ways.remove_way(existing_way)
|
153
|
+
if joined.closed?
|
154
|
+
closed_ways << joined
|
155
|
+
break
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
if !joined.closed?
|
160
|
+
endpoints_to_ways.add_way(joined)
|
161
|
+
end
|
162
|
+
else
|
163
|
+
endpoints_to_ways.add_way(way)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
if endpoints_to_ways.number_of_endpoints != 0
|
168
|
+
raise StandardError, "Unclosed boundaries"
|
169
|
+
end
|
170
|
+
|
171
|
+
closed_ways
|
172
|
+
end
|
173
|
+
|
174
|
+
def join_way(way, other)
|
175
|
+
if way.closed?
|
176
|
+
raise StandardError, "Trying to join a closed way to another"
|
177
|
+
end
|
178
|
+
if other.closed?
|
179
|
+
raise StandardError, "Trying to join a way to a closed way"
|
180
|
+
end
|
181
|
+
|
182
|
+
if way.points.first == other.points.first
|
183
|
+
new_points = other.reverse.points[0..-2] + way.points
|
184
|
+
elsif way.points.first == other.points.last
|
185
|
+
new_points = other.points[0..-2] + way.points
|
186
|
+
elsif way.points.last == other.points.first
|
187
|
+
new_points = way.points[0..-2] + other.points
|
188
|
+
elsif way.points.last == other.points.last
|
189
|
+
new_points = way.points[0..-2] + other.reverse.points
|
190
|
+
else
|
191
|
+
raise StandardError, "Trying to join two ways with no end point in common"
|
192
|
+
end
|
193
|
+
|
194
|
+
GeoRuby::SimpleFeatures::LineString.from_points(new_points)
|
195
|
+
end
|
196
|
+
|
197
|
+
class EndpointToWayMap
|
198
|
+
attr_accessor :endpoints
|
199
|
+
|
200
|
+
def initialize
|
201
|
+
@endpoints = {}
|
202
|
+
end
|
203
|
+
|
204
|
+
def add_way(way)
|
205
|
+
if get_from_either_end(way).present?
|
206
|
+
raise StandardError, "Call to add_way would overwrite existing way(s)"
|
207
|
+
end
|
208
|
+
self.endpoints[way.points.first] = way
|
209
|
+
self.endpoints[way.points.last] = way
|
210
|
+
end
|
211
|
+
|
212
|
+
def remove_way(way)
|
213
|
+
endpoints.delete(way.points.first)
|
214
|
+
endpoints.delete(way.points.last)
|
215
|
+
end
|
216
|
+
|
217
|
+
def get_from_either_end(way)
|
218
|
+
[].tap do |selected_end_points|
|
219
|
+
selected_end_points << endpoints[way.points.first] if endpoints.include?(way.points.first)
|
220
|
+
selected_end_points << endpoints[way.points.last] if endpoints.include?(way.points.last)
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
def number_of_endpoints
|
225
|
+
return endpoints.size
|
226
|
+
end
|
227
|
+
|
228
|
+
end
|
229
|
+
|
230
|
+
class Node
|
231
|
+
attr_accessor :id, :lon, :lat, :ways, :end_of_way, :addr_housenumber, :tags
|
232
|
+
|
233
|
+
def initialize(id, lon, lat, addr_housenumber = "", ways = [], end_of_way = false, tags = {} )
|
234
|
+
@id = id
|
235
|
+
@lon = lon
|
236
|
+
@lat = lat
|
237
|
+
@addr_housenumber = addr_housenumber
|
238
|
+
@ways = ways
|
239
|
+
@end_of_way = end_of_way
|
240
|
+
@tags = tags
|
241
|
+
end
|
242
|
+
|
243
|
+
def add_way(id)
|
244
|
+
@ways << id
|
245
|
+
end
|
246
|
+
|
247
|
+
def marshal_dump
|
248
|
+
[@id, @lon, @lat, @addr_housenumber, @ways, @end_of_way, @tags]
|
249
|
+
end
|
250
|
+
|
251
|
+
def marshal_load array
|
252
|
+
@id, @lon, @lat, @addr_housenumber, @ways, @end_of_way, @tags = array
|
253
|
+
end
|
254
|
+
|
255
|
+
def used?
|
256
|
+
( ways.present? && ways.size > 1 ) || end_of_way
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
class Way
|
261
|
+
attr_accessor :id, :nodes, :car, :bike, :train, :pedestrian, :name, :maxspeed, :oneway, :boundary, :admin_level, :addr_housenumber, :options
|
262
|
+
|
263
|
+
def initialize(id, nodes = [], car = false, bike = false, train = false, pedestrian = false, name = "", maxspeed = 0, oneway = false, boundary = "", admin_level = "", addr_housenumber = "", options = {})
|
264
|
+
@id = id
|
265
|
+
@nodes = nodes
|
266
|
+
@car = car
|
267
|
+
@bike = bike
|
268
|
+
@train = train
|
269
|
+
@pedestrian = pedestrian
|
270
|
+
@name = name
|
271
|
+
@maxspeed = maxspeed
|
272
|
+
@oneway = oneway
|
273
|
+
@boundary = boundary
|
274
|
+
@admin_level = admin_level
|
275
|
+
@addr_housenumber = addr_housenumber
|
276
|
+
@options = options
|
277
|
+
end
|
278
|
+
|
279
|
+
def add_node(id)
|
280
|
+
@nodes << id
|
281
|
+
end
|
282
|
+
|
283
|
+
def marshal_dump
|
284
|
+
[@id, @nodes, @car, @bike, @train, @pedestrian, @name, @maxspeed, @oneway, @boundary, @admin_level, @addr_housenumber, @options]
|
285
|
+
end
|
286
|
+
|
287
|
+
def marshal_load array
|
288
|
+
@id, @nodes, @car, @bike, @train, @pedestrian, @name, @maxspeed, @oneway, @boundary, @admin_level, @addr_housenumber, @options = array
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
end
|
293
|
+
end
|