active_road 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (118) hide show
  1. data/.gitignore +9 -0
  2. data/.rvmrc +1 -0
  3. data/.travis.yml +11 -0
  4. data/Gemfile +14 -0
  5. data/Guardfile +26 -0
  6. data/LICENSE.txt +19 -0
  7. data/README.md +37 -0
  8. data/Rakefile +46 -0
  9. data/active_road.gemspec +38 -0
  10. data/app/models/active_road/access_link.rb +44 -0
  11. data/app/models/active_road/access_point.rb +65 -0
  12. data/app/models/active_road/base.rb +5 -0
  13. data/app/models/active_road/junction.rb +52 -0
  14. data/app/models/active_road/junction_conditionnal_cost.rb +13 -0
  15. data/app/models/active_road/logical_road.rb +41 -0
  16. data/app/models/active_road/path.rb +85 -0
  17. data/app/models/active_road/physical_road.rb +65 -0
  18. data/app/models/active_road/physical_road_conditionnal_cost.rb +10 -0
  19. data/app/models/active_road/physical_road_filter.rb +41 -0
  20. data/app/models/active_road/street_number.rb +81 -0
  21. data/app/models/active_road/terra_import.rb +148 -0
  22. data/config/database.yml +20 -0
  23. data/config/database.yml.ci +12 -0
  24. data/config/routes.rb +2 -0
  25. data/db/init.sql +6 -0
  26. data/db/migrate/20110914160756_create_street_numbers.rb +18 -0
  27. data/db/migrate/20120201114800_create_physical_roads.rb +17 -0
  28. data/db/migrate/20120201162800_create_logical_roads.rb +16 -0
  29. data/db/migrate/20120203154500_create_junctions.rb +25 -0
  30. data/db/migrate/20120401083409_create_physical_roads_spatial_index.rb +9 -0
  31. data/db/migrate/20120419093427_add_kind_to_physical_roads.rb +10 -0
  32. data/db/migrate/20121010125851_create_junction_conditionnal_costs.rb +13 -0
  33. data/db/migrate/20121011124923_create_physical_road_conditionnal_costs.rb +13 -0
  34. data/db/migrate/20121012134251_add_start_end_ref_to_junction_conditionnal_cost.rb +6 -0
  35. data/db/migrate/20121012134440_add_tags_junction.rb +5 -0
  36. data/db/migrate/20121012134457_add_tags_physical_road.rb +5 -0
  37. data/db/migrate/20121106095002_add_objectid_to_street_number.rb +5 -0
  38. data/db/migrate/20130419155438_add_length_and_minimum_width_to_physical_road.rb +6 -0
  39. data/db/migrate/20130507162801_setup_hstore.rb +9 -0
  40. data/db/migrate/20130509075631_change_tags_type_for_physical_road.rb +10 -0
  41. data/db/migrate/20130509081745_index_physical_roads_tags.rb +9 -0
  42. data/db/migrate/20130513134422_change_tags_type_for_junction.rb +10 -0
  43. data/db/migrate/20130513134511_index_junctions_tags.rb +9 -0
  44. data/db/migrate/20130607114951_change_length_name_for_physical_road.rb +11 -0
  45. data/db/migrate/20130801151637_add_constraints_to_physical_roads.rb +37 -0
  46. data/db/migrate/20130809155019_add_height_and_waiting_constraint_to_junction.rb +6 -0
  47. data/db/migrate/20130812143049_fix_waiting_constraint_type_for_junction.rb +11 -0
  48. data/lib/active_road.rb +19 -0
  49. data/lib/active_road/engine.rb +13 -0
  50. data/lib/active_road/migration.rb +15 -0
  51. data/lib/active_road/shortest_path.rb +2 -0
  52. data/lib/active_road/shortest_path/finder.rb +172 -0
  53. data/lib/active_road/version.rb +3 -0
  54. data/lib/tasks/activeroad_tasks.rake +4 -0
  55. data/log/.gitignore +0 -0
  56. data/script/console +2 -0
  57. data/script/import-tiger-numbers +201 -0
  58. data/script/rails +9 -0
  59. data/spec/dummy/README.rdoc +261 -0
  60. data/spec/dummy/Rakefile +6 -0
  61. data/spec/dummy/app/assets/javascripts/application.js +15 -0
  62. data/spec/dummy/app/assets/stylesheets/application.css +13 -0
  63. data/spec/dummy/app/controllers/application_controller.rb +3 -0
  64. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  65. data/spec/dummy/app/mailers/.gitkeep +0 -0
  66. data/spec/dummy/app/models/.gitkeep +0 -0
  67. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  68. data/spec/dummy/config.ru +4 -0
  69. data/spec/dummy/config/application.rb +56 -0
  70. data/spec/dummy/config/boot.rb +10 -0
  71. data/spec/dummy/config/database.yml +20 -0
  72. data/spec/dummy/config/environment.rb +5 -0
  73. data/spec/dummy/config/environments/development.rb +37 -0
  74. data/spec/dummy/config/environments/production.rb +67 -0
  75. data/spec/dummy/config/environments/test.rb +37 -0
  76. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  77. data/spec/dummy/config/initializers/inflections.rb +15 -0
  78. data/spec/dummy/config/initializers/mime_types.rb +5 -0
  79. data/spec/dummy/config/initializers/secret_token.rb +7 -0
  80. data/spec/dummy/config/initializers/session_store.rb +8 -0
  81. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  82. data/spec/dummy/config/locales/en.yml +5 -0
  83. data/spec/dummy/config/routes.rb +4 -0
  84. data/spec/dummy/db/schema.rb +87 -0
  85. data/spec/dummy/db/structure.sql +10250 -0
  86. data/spec/dummy/lib/assets/.gitkeep +0 -0
  87. data/spec/dummy/log/.gitkeep +0 -0
  88. data/spec/dummy/public/404.html +26 -0
  89. data/spec/dummy/public/422.html +26 -0
  90. data/spec/dummy/public/500.html +25 -0
  91. data/spec/dummy/public/favicon.ico +0 -0
  92. data/spec/dummy/script/rails +6 -0
  93. data/spec/factories/junction.rb +18 -0
  94. data/spec/factories/junction_conditionnal_cost.rb +13 -0
  95. data/spec/factories/logical_road.rb +8 -0
  96. data/spec/factories/physical_road.rb +9 -0
  97. data/spec/factories/physical_road_conditionnal_cost.rb +9 -0
  98. data/spec/factories/street_number.rb +11 -0
  99. data/spec/fixtures/terra.xml +1772 -0
  100. data/spec/fixtures/terra_minimal.xml +28 -0
  101. data/spec/fixtures/trajectory_arc.xml +10 -0
  102. data/spec/fixtures/trajectory_node.xml +11 -0
  103. data/spec/lib/active_road/shortest_path/finder_spec.rb +157 -0
  104. data/spec/models/active_road/access_point_spec.rb +36 -0
  105. data/spec/models/active_road/junction_conditionnal_cost_spec.rb +28 -0
  106. data/spec/models/active_road/junction_spec.rb +25 -0
  107. data/spec/models/active_road/logical_road_spec.rb +46 -0
  108. data/spec/models/active_road/path_spec.rb +7 -0
  109. data/spec/models/active_road/physical_road_conditionnal_cost_spec.rb +19 -0
  110. data/spec/models/active_road/physical_road_filter_spec.rb +85 -0
  111. data/spec/models/active_road/physical_road_spec.rb +17 -0
  112. data/spec/models/active_road/street_number_spec.rb +78 -0
  113. data/spec/models/active_road/terra_import_spec.rb +113 -0
  114. data/spec/spec_helper.rb +46 -0
  115. data/spec/support/georuby_ext.rb +15 -0
  116. data/travis/before_install.sh +10 -0
  117. data/travis/before_script.sh +9 -0
  118. metadata +460 -0
@@ -0,0 +1,85 @@
1
+ # A path is a link between differents objects :
2
+ # - Departure
3
+ # - Arrival
4
+ class ActiveRoad::Path
5
+
6
+ attr_accessor :departure, :arrival, :physical_road
7
+ alias_method :road, :physical_road
8
+
9
+ def initialize(attributes = {})
10
+ attributes.each do |k, v|
11
+ send("#{k}=", v)
12
+ end
13
+ end
14
+
15
+ def name
16
+ "Path : #{departure} -> #{arrival}"
17
+ end
18
+
19
+ def locations_on_road
20
+ [departure, arrival].collect do |endpoint|
21
+ location =
22
+ if GeoRuby::SimpleFeatures::Point === endpoint
23
+ road.locate_point endpoint
24
+ else
25
+ endpoint.location_on_road road
26
+ end
27
+ location = [0, [location, 1].min].max
28
+ end
29
+ end
30
+
31
+ def length_in_meter
32
+ length_on_road * road.length_in_meter
33
+ end
34
+
35
+ def length_on_road
36
+ begin_on_road, end_on_road = locations_on_road.sort
37
+ end_on_road - begin_on_road
38
+ end
39
+
40
+ def self.all(departure, arrivals, physical_road)
41
+ Array(arrivals).collect do |arrival|
42
+ new :departure => departure, :arrival => arrival, :physical_road => physical_road
43
+ end
44
+ end
45
+
46
+ delegate :access_to_road?, :to => :arrival
47
+
48
+ def paths(tags = {})
49
+ arrival.paths(tags) - [reverse]
50
+ end
51
+
52
+ def reverse
53
+ self.class.new :departure => arrival, :arrival => departure, :physical_road => physical_road
54
+ end
55
+
56
+ def geometry_without_cache
57
+ sorted_locations_on_road = locations_on_road.sort
58
+ reverse = (sorted_locations_on_road != locations_on_road)
59
+ geometry = road.line_substring *sorted_locations_on_road
60
+ geometry = geometry.reverse if reverse
61
+ geometry
62
+ end
63
+
64
+ def geometry_with_cache
65
+ @geometry ||= geometry_without_cache
66
+ end
67
+ alias_method :geometry, :geometry_with_cache
68
+ alias_method :to_geometry, :geometry
69
+
70
+ def to_s
71
+ name
72
+ end
73
+
74
+ def ==(other)
75
+ [:departure, :arrival, :physical_road].all? do |attribute|
76
+ other.respond_to?(attribute) and send(attribute) == other.send(attribute)
77
+ end
78
+ end
79
+ alias_method :eql?, :==
80
+
81
+ def hash
82
+ [departure, arrival, physical_road].hash
83
+ end
84
+
85
+ end
@@ -0,0 +1,65 @@
1
+ require "activerecord-postgres-hstore"
2
+ require "enumerize"
3
+
4
+ module ActiveRoad
5
+ class PhysicalRoad < ActiveRoad::Base
6
+ extend Enumerize
7
+ extend ActiveModel::Naming
8
+
9
+ serialize :tags, ActiveRecord::Coders::Hstore
10
+
11
+ attr_accessible :objectid, :tags, :geometry, :logical_road_id, :length_in_meter, :minimum_width, :covering, :transport_mode, :slope, :cant, :physical_road_type
12
+
13
+ # TODO : Pass covering in array mode???
14
+ enumerize :covering, :in => [:slippery_gravel, :gravel, :asphalt_road, :asphalt_road_damaged, :pavement, :irregular_pavement, :slippery_pavement]
15
+ enumerize :transport_mode, :in => [:pedestrian, :bike]
16
+
17
+ enumerize :minimum_width, :in => [:wide, :enlarged, :narrow, :cramped], :default => :wide
18
+ enumerize :slope, :in => [:flat, :medium, :significant, :steep], :default => :flat
19
+ enumerize :cant, :in => [:flat, :medium, :significant, :steep], :default => :flat
20
+ enumerize :physical_road_type, :in => [:path_link, :stairs, :crossing], :default => :path_link
21
+
22
+ validates_uniqueness_of :objectid
23
+
24
+ has_many :numbers, :class_name => "ActiveRoad::StreetNumber", :inverse_of => :physical_road
25
+ belongs_to :logical_road, :class_name => "ActiveRoad::LogicalRoad"
26
+ has_and_belongs_to_many :junctions, :uniq => true
27
+ has_many :physical_road_conditionnal_costs
28
+
29
+ acts_as_geom :geometry => :line_string
30
+ delegate :locate_point, :interpolate_point, :to => :geometry
31
+
32
+ before_validation :update_length_in_meter
33
+
34
+ def update_length_in_meter
35
+ if ( geometry )
36
+ spherical_factory = ::RGeo::Geographic.spherical_factory
37
+ self.update_attribute :length_in_meter, spherical_factory.line_string(geometry.points.collect(&:to_rgeo)).length
38
+ end
39
+ end
40
+
41
+ def name
42
+ logical_road.try(:name) or objectid
43
+ end
44
+
45
+ alias_method :to_s, :name
46
+
47
+ def self.nearest_to(location, distance = 100)
48
+ with_in(location, distance).closest_to(location)
49
+ end
50
+
51
+ def self.closest_to(location)
52
+ location_as_text = location.to_ewkt(false)
53
+ order("ST_Distance(geometry, GeomFromText('#{location_as_text}', 4326))")
54
+ end
55
+
56
+ def self.with_in(location, distance = 100)
57
+ # FIXME why ST_DWithin doesn't use meters ??
58
+ distance = distance / 1000.0
59
+
60
+ location_as_text = location.to_ewkt(false)
61
+ where "ST_DWithin(ST_GeomFromText(?, 4326), geometry, ?)", location_as_text, distance
62
+ end
63
+
64
+ end
65
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveRoad
2
+ class PhysicalRoadConditionnalCost < ActiveRoad::Base
3
+ belongs_to :physical_road
4
+
5
+ validates_presence_of :physical_road_id
6
+ validates_presence_of :tags
7
+ validates_presence_of :cost
8
+
9
+ end
10
+ end
@@ -0,0 +1,41 @@
1
+ # Filter Physical Road by :
2
+ # - constraints
3
+ class ActiveRoad::PhysicalRoadFilter
4
+ attr_accessor :relation, :constraints
5
+
6
+ def initialize(constraints = {}, relation = ActiveRoad::PhysicalRoad.scoped )
7
+ @relation, @constraints = relation, constraints
8
+ end
9
+
10
+ # Must define an sql request with forbidden tags
11
+ def sql_request
12
+ sql_request = ""
13
+ constraints.each do |key, value|
14
+ if !( (constraints.keys.first.present? && constraints.keys.first == key) )
15
+ sql_request += " AND "
16
+ end
17
+
18
+ sql_request += "(tags -> '#{new_key}')::int > :#{key}"
19
+
20
+ # if key.to_s.include? "min_"
21
+ # new_key = key.to_s.gsub("min_", "")
22
+ # sql_request += "(tags -> '#{new_key}')::int > :#{key}"
23
+ # elsif key.to_s.include? "max_"
24
+ # new_key = key.to_s.gsub("max_", "")
25
+ # sql_request += "(tags -> '#{new_key}')::int < :#{key}"
26
+ # else
27
+ # sql_request += "tags -> '#{key}' != :#{key}"
28
+ # end
29
+ end
30
+ sql_request
31
+ end
32
+
33
+ def filter
34
+ if constraints.present?
35
+ @relation = @relation.where(constraints)
36
+ else
37
+ @relation
38
+ end
39
+ end
40
+
41
+ end
@@ -0,0 +1,81 @@
1
+ class ActiveRoad::StreetNumber < ActiveRoad::Base
2
+ attr_accessible :objectid, :number, :geometry, :physical_road_id, :location_on_road
3
+
4
+ validates_uniqueness_of :objectid
5
+ validates_presence_of :number, :stored_geometry
6
+
7
+ belongs_to :physical_road, :class_name => "ActiveRoad::PhysicalRoad"
8
+ def road
9
+ @road or physical_road
10
+ end
11
+ def road=(road)
12
+ @road ||= road
13
+ end
14
+
15
+ before_validation :compute_locate_on_road, :on => :create
16
+
17
+ def stored_geometry
18
+ read_attribute :geometry
19
+ end
20
+
21
+ def geometry
22
+ stored_geometry or computed_geometry
23
+ end
24
+
25
+ def computed_geometry
26
+ road.at computed_location_on_road
27
+ end
28
+
29
+ def location_on_road
30
+ stored_location_on_road or computed_location_on_road
31
+ end
32
+
33
+ def stored_location_on_road
34
+ read_attribute :location_on_road
35
+ end
36
+
37
+ def compute_locate_on_road
38
+ if stored_location_on_road.nil? and stored_geometry
39
+ self.location_on_road = road.geometry.locate_point(stored_geometry)
40
+ end
41
+ end
42
+
43
+ # TODO rename into estimated_location_on_road
44
+ def computed_location_on_road
45
+ if previous and self.next
46
+ number_ratio = (number.to_i - previous.number.to_i) / (self.next.number.to_i - previous.number.to_i).to_f
47
+ previous.location_on_road + number_ratio * (self.next.location_on_road - previous.location_on_road)
48
+ end
49
+ end
50
+
51
+ def previous
52
+ @previous ||= road.numbers.find :first, :conditions => ["number < ?", number], :limit => 1, :order => "number desc"
53
+ end
54
+
55
+ def next
56
+ @next ||= road.numbers.find :first, :conditions => ["number > ?", number], :limit => 1, :order => "number"
57
+ end
58
+
59
+ def number
60
+ Number.new read_attribute(:number)
61
+ end
62
+
63
+ class Number < String
64
+
65
+ alias_method :numeric_value, :to_i
66
+
67
+ def suffix
68
+ gsub(/^[0-9]+/,'')
69
+ end
70
+
71
+ def +(value)
72
+ self.class.new "#{numeric_value+value}#{suffix}"
73
+ end
74
+
75
+ def -(value)
76
+ self.class.new "#{numeric_value-value}#{suffix}"
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,148 @@
1
+ module ActiveRoad
2
+ class TerraImport
3
+ attr_reader :parser
4
+
5
+ def initialize(xml_file)
6
+ @parser = ::Saxerator.parser(File.new(xml_file))
7
+ end
8
+
9
+ def extract
10
+ parser.for_tag(:LogicalRoad).each do |logical_road|
11
+ LogicalRoadXml.new(logical_road).import
12
+ end
13
+
14
+ parser.for_tag(:TrajectoryArc).each do |physical_road|
15
+ TrajectoryArcXml.new(physical_road).import
16
+ end
17
+
18
+ parser.for_tag(:TrajectoryNode).each do |junction|
19
+ TrajectoryNodeXml.new(junction).import
20
+ end
21
+
22
+ parser.for_tag(:StreetNumber).each do |street_number|
23
+ StreetNumberXml.new(street_number).import
24
+ end
25
+
26
+ end
27
+
28
+ class ElementXml
29
+ attr_reader :xml
30
+
31
+ def initialize(xml)
32
+ @xml = xml
33
+ end
34
+
35
+ def objectid
36
+ xml['ObjectId']
37
+ end
38
+
39
+ def geometry
40
+ GeoRuby::SimpleFeatures::Geometry.from_ewkt( xml['Geometry'] )
41
+ end
42
+
43
+ end
44
+
45
+ class LogicalRoadXml < ElementXml
46
+
47
+ def name
48
+ xml['Name']
49
+ end
50
+
51
+ def import
52
+ ActiveRoad::LogicalRoad.create :name => name, :objectid => objectid
53
+ end
54
+
55
+ end
56
+
57
+ class TrajectoryArcXml < ElementXml
58
+
59
+ def logical_road
60
+ ActiveRoad::LogicalRoad.find_by_objectid( logical_road_id )
61
+ end
62
+
63
+ def logical_road_id
64
+ xml['LogicalRoadRef']
65
+ end
66
+
67
+ def minimum_width
68
+ xml['MinimumWidth']
69
+ end
70
+
71
+ def length
72
+ xml['Length']
73
+ end
74
+
75
+ def tags
76
+ {}
77
+ end
78
+
79
+ def import
80
+ ActiveRoad::PhysicalRoad.create(:geometry => geometry, :tags => tags, :logical_road_id => logical_road_id, :objectid => objectid, :minimum_with => minimum_width, :length_in_meter => length) if (geometry) #&& logical_road)
81
+ end
82
+
83
+ end
84
+
85
+ class TrajectoryNodeXml < ElementXml
86
+
87
+ def tags
88
+ {} #xml['Tags'].to_s
89
+ end
90
+
91
+ # def height
92
+ # xml['Height'] || 0
93
+ # end
94
+
95
+ # def physical_road
96
+ # ActiveRoad::PhysicalRoad.find_by_objectid( physical_road_id )
97
+ # end
98
+
99
+ # def physical_road_id
100
+ # xml['PhysicalRoadRef']
101
+ # end
102
+
103
+ def physical_roads
104
+ physical_roads = []
105
+ if(xml['TrajectoryArcRef'].class == Saxerator::Builder::StringElement)
106
+ physical_roads << ActiveRoad::PhysicalRoad.find_by_objectid( xml['TrajectoryArcRef'].to_s )
107
+ else
108
+ xml['TrajectoryArcRef'].each do |trajectory_arc_ref|
109
+ physical_road = ActiveRoad::PhysicalRoad.find_by_objectid( trajectory_arc_ref.to_s )
110
+ physical_roads << physical_road if physical_road.present?
111
+ end
112
+ end
113
+ physical_roads
114
+ end
115
+
116
+ def import
117
+ junction = ActiveRoad::Junction.create :objectid => objectid, :tags => tags, :geometry => geometry
118
+ junction.physical_roads << physical_roads
119
+ end
120
+
121
+ end
122
+
123
+ class StreetNumberXml < ElementXml
124
+ # TODO : Fix location_on_road value
125
+ def physical_road
126
+ ActiveRoad::PhysicalRoad.find_by_objectid( physical_road_ref )
127
+ end
128
+
129
+ def physical_road_ref
130
+ xml['TrajectoryArcRef']
131
+ end
132
+
133
+ def number
134
+ xml['Number']
135
+ end
136
+
137
+ def location_on_road
138
+ xml['LocationOnRoad'] || 0
139
+ end
140
+
141
+ def import
142
+ ActiveRoad::StreetNumber.create(:number => number , :objectid => objectid, :geometry => geometry, :location_on_road => location_on_road)#, :physical_road_id => physical_road.id)
143
+ end
144
+
145
+ end
146
+
147
+ end
148
+ end
@@ -0,0 +1,20 @@
1
+ development:
2
+ adapter: postgresql
3
+ database: roads
4
+ username: roads
5
+ password: roads0
6
+ template: template_postgis
7
+
8
+ test:
9
+ adapter: postgresql
10
+ database: roads_test
11
+ username: roads
12
+ password: roads0
13
+ template: template_postgis
14
+
15
+ osm:
16
+ adapter: postgresql
17
+ database: osm
18
+ username: osm
19
+ password: osm
20
+ host: osm.dbx2.dryade.priv