ninoxe 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. data/MIT-LICENSE +20 -0
  2. data/README.rdoc +3 -0
  3. data/Rakefile +49 -0
  4. data/app/assets/javascripts/ninoxe/application.js +15 -0
  5. data/app/assets/stylesheets/ninoxe/application.css +13 -0
  6. data/app/controllers/ninoxe/application_controller.rb +4 -0
  7. data/app/helpers/ninoxe/application_helper.rb +4 -0
  8. data/app/models/chouette/access_link.rb +63 -0
  9. data/app/models/chouette/access_point.rb +145 -0
  10. data/app/models/chouette/access_point_type.rb +50 -0
  11. data/app/models/chouette/active_record.rb +66 -0
  12. data/app/models/chouette/area_type.rb +56 -0
  13. data/app/models/chouette/chouette_structure.dump +3417 -0
  14. data/app/models/chouette/command.rb +93 -0
  15. data/app/models/chouette/command_line_support.rb +35 -0
  16. data/app/models/chouette/company.rb +19 -0
  17. data/app/models/chouette/connection_link.rb +43 -0
  18. data/app/models/chouette/connection_link_type.rb +51 -0
  19. data/app/models/chouette/direction.rb +60 -0
  20. data/app/models/chouette/exporter.rb +32 -0
  21. data/app/models/chouette/file_validator.rb +47 -0
  22. data/app/models/chouette/group_of_line.rb +30 -0
  23. data/app/models/chouette/journey_pattern.rb +63 -0
  24. data/app/models/chouette/line.rb +65 -0
  25. data/app/models/chouette/link_orientation_type.rb +49 -0
  26. data/app/models/chouette/loader.rb +110 -0
  27. data/app/models/chouette/network.rb +33 -0
  28. data/app/models/chouette/object_id.rb +36 -0
  29. data/app/models/chouette/pt_link.rb +39 -0
  30. data/app/models/chouette/route.rb +158 -0
  31. data/app/models/chouette/stop_area.rb +273 -0
  32. data/app/models/chouette/stop_point.rb +33 -0
  33. data/app/models/chouette/time_table.rb +146 -0
  34. data/app/models/chouette/time_table_date.rb +14 -0
  35. data/app/models/chouette/time_table_period.rb +26 -0
  36. data/app/models/chouette/time_table_vehicle_journey.rb +5 -0
  37. data/app/models/chouette/transport_mode.rb +71 -0
  38. data/app/models/chouette/trident_active_record.rb +97 -0
  39. data/app/models/chouette/vehicle_journey.rb +101 -0
  40. data/app/models/chouette/vehicle_journey_at_stop.rb +45 -0
  41. data/app/models/chouette/wayback.rb +50 -0
  42. data/app/views/layouts/ninoxe/application.html.erb +14 -0
  43. data/config/database.yml +9 -0
  44. data/config/database.yml.ci +14 -0
  45. data/config/database.yml.travis +9 -0
  46. data/config/locales/en.yml +15 -0
  47. data/config/locales/fr.yml +16 -0
  48. data/config/routes.rb +2 -0
  49. data/db/migrate/20120213131553_create_chouette_line.rb +26 -0
  50. data/db/migrate/20120214101458_create_chouette_company.rb +25 -0
  51. data/db/migrate/20120214101645_create_chouette_ptnetwork.rb +24 -0
  52. data/db/migrate/20120406144221_create_chouette_stop_area.rb +33 -0
  53. data/db/migrate/20120411144209_create_time_table.rb +38 -0
  54. data/db/migrate/20120425064403_create_chouette_route.rb +22 -0
  55. data/db/migrate/20120425123944_create_chouette_stop_point.rb +17 -0
  56. data/db/migrate/20120426114527_create_chouette_connection_link.rb +28 -0
  57. data/db/migrate/20120521073709_create_chouette_journey_pattern.rb +26 -0
  58. data/db/migrate/20120521073723_create_chouette_journey_pattern_stop_point.rb +14 -0
  59. data/db/migrate/20120521073740_create_chouette_time_slot.rb +22 -0
  60. data/db/migrate/20120521073746_create_chouette_vehicle_journey.rb +34 -0
  61. data/db/migrate/20120521073758_create_chouette_vehicle_journey_at_stop.rb +25 -0
  62. data/db/migrate/20120521073900_create_chouette_time_table_vehicle_journey.rb +16 -0
  63. data/db/migrate/20120521132304_create_chouette_access_point.rb +34 -0
  64. data/db/migrate/20120521132313_create_chouette_access_link.rb +33 -0
  65. data/db/migrate/20120521132429_create_chouette_facility.rb +34 -0
  66. data/db/migrate/20120521132502_create_chouette_facility_feature.rb +12 -0
  67. data/db/migrate/20120521132551_create_chouette_group_of_line.rb +18 -0
  68. data/db/migrate/20120521132600_create_chouette_group_of_line_line.rb +12 -0
  69. data/db/migrate/20120521132656_create_chouette_routing_constrains_line.rb +12 -0
  70. data/db/migrate/20120521132724_create_chouette_stoparea_stoparea.rb +12 -0
  71. data/db/migrate/20120531091529_create_chouette_pt_link.rb +21 -0
  72. data/db/migrate/20120926141405_add_id_to_time_table_date.rb +12 -0
  73. data/db/migrate/20120926141415_add_id_to_time_table_period.rb +12 -0
  74. data/db/migrate/20121024072219_add_fields_to_access_points.rb +12 -0
  75. data/lib/chouette_factories.rb +1 -0
  76. data/lib/factories/chouette_access_links.rb +11 -0
  77. data/lib/factories/chouette_access_points.rb +8 -0
  78. data/lib/factories/chouette_companies.rb +5 -0
  79. data/lib/factories/chouette_connection_links.rb +11 -0
  80. data/lib/factories/chouette_group_of_lines.rb +4 -0
  81. data/lib/factories/chouette_journey_pattern.rb +32 -0
  82. data/lib/factories/chouette_lines.rb +20 -0
  83. data/lib/factories/chouette_networks.rb +5 -0
  84. data/lib/factories/chouette_routes.rb +18 -0
  85. data/lib/factories/chouette_stop_areas.rb +8 -0
  86. data/lib/factories/chouette_stop_points.rb +7 -0
  87. data/lib/factories/chouette_time_table.rb +21 -0
  88. data/lib/factories/chouette_vehicle_journey.rb +50 -0
  89. data/lib/factories/chouette_vehicle_journey_at_stop.rb +5 -0
  90. data/lib/ninoxe/engine.rb +15 -0
  91. data/lib/ninoxe/version.rb +3 -0
  92. data/lib/ninoxe.rb +7 -0
  93. metadata +251 -0
@@ -0,0 +1,110 @@
1
+ class Chouette::Loader
2
+
3
+ attr_reader :schema, :database, :user, :password, :host
4
+
5
+ def initialize(schema)
6
+ @schema = schema
7
+
8
+ Chouette::ActiveRecord.connection_pool.spec.config.tap do |config|
9
+ @database = config[:database]
10
+ @user = config[:username]
11
+ @password = config[:password]
12
+ @host = (config[:host] or "localhost")
13
+ end
14
+ end
15
+
16
+ # Load dump where datas are in schema 'chouette'
17
+ def load_dump(file)
18
+ logger.info "Load #{file} in schema #{schema}"
19
+ with_pg_password do
20
+ execute!("sed -e 's/ chouette/ \"#{schema}\"/' -e 's/ OWNER TO .*;/ OWNER TO #{user};/' #{file} | psql #{pg_options} --set ON_ERROR_ROLLBACK=1 --set ON_ERROR_STOP=1")
21
+ end
22
+ self
23
+ end
24
+
25
+ def self.chouette_command=(command)
26
+ Chouette::Command.command = command
27
+ end
28
+
29
+ class << self
30
+ deprecate :chouette_command= => "Use Chouette::Command.command ="
31
+ end
32
+
33
+ def chouette_command
34
+ @chouette_command ||= Chouette::Command.new(:schema => schema)
35
+ end
36
+
37
+ def import(file, options = {})
38
+ options = {
39
+ :format => :neptune
40
+ }.merge(options)
41
+
42
+ command_options = {
43
+ :c => "import",
44
+ :o => "line",
45
+ :format => options.delete(:format).to_s.upcase,
46
+ :input_file => File.expand_path(file),
47
+ :optimize_memory => true
48
+ }.merge(options)
49
+
50
+ logger.info "Import #{file} in schema #{schema}"
51
+ chouette_command.run! command_options
52
+ end
53
+
54
+ def backup(file)
55
+ logger.info "Backup schema #{schema} in #{file}"
56
+
57
+ with_pg_password do
58
+ execute!("pg_dump -n #{schema} -f #{file} #{pg_options}")
59
+ end
60
+
61
+ self
62
+ end
63
+
64
+ def pg_options
65
+ [].tap do |options|
66
+ options << "-U #{user}" if user
67
+ options << "-h #{host}" if host
68
+ options << database
69
+ end.join(" ")
70
+ end
71
+
72
+ def create
73
+ logger.info "Create schema #{schema}"
74
+ with_pg_password do
75
+ execute!("psql -c 'CREATE SCHEMA \"#{schema}\";' #{pg_options}")
76
+ end
77
+ self
78
+ end
79
+
80
+ def drop
81
+ logger.info "Drop schema #{schema}"
82
+ with_pg_password do
83
+ execute!("psql -c 'DROP SCHEMA \"#{schema}\" CASCADE;' #{pg_options}")
84
+ end
85
+ self
86
+ end
87
+
88
+ def with_pg_password(&block)
89
+ ENV['PGPASSWORD'] = password.to_s if password
90
+ begin
91
+ yield
92
+ ensure
93
+ ENV['PGPASSWORD'] = nil
94
+ end
95
+ end
96
+
97
+ @@binarisation_command = "binarisation"
98
+ cattr_accessor :binarisation_command
99
+
100
+ def binarize(period, target_directory)
101
+ # TODO check these computed daybefore/dayafter
102
+ day_before = Date.today - period.begin
103
+ day_after = period.end - period.begin
104
+
105
+ execute! "#{binarisation_command} --host=#{host} --dbname=#{database} --user=#{user} --password=#{password} --schema=#{schema} --daybefore=#{day_before} --dayafter=#{day_after} --targetdirectory=#{target_directory}"
106
+ end
107
+
108
+ include Chouette::CommandLineSupport
109
+
110
+ end
@@ -0,0 +1,33 @@
1
+ class Chouette::Network < Chouette::TridentActiveRecord
2
+ # FIXME http://jira.codehaus.org/browse/JRUBY-6358
3
+ set_primary_key :id
4
+
5
+ has_many :lines
6
+
7
+ validates_presence_of :registration_number
8
+ validates_uniqueness_of :registration_number
9
+ validates_format_of :registration_number, :with => %r{\A[0-9A-Za-z_-]+\Z}
10
+
11
+ validates_presence_of :name
12
+
13
+ attr_accessible :objectid, :object_version, :creation_time, :creator_id, :version_date, :description, :name
14
+ attr_accessible :registration_number, :source_name, :source_type, :source_identifier, :comment
15
+
16
+ def self.object_id_key
17
+ "GroupOfLine"
18
+ end
19
+
20
+ def self.nullable_attributes
21
+ [:source_name, :source_type, :source_identifier, :comment]
22
+ end
23
+
24
+ def commercial_stop_areas
25
+ Chouette::StopArea.joins(:children => [:stop_points => [:route => [:line => :network] ] ]).where(:networks => {:id => self.id}).uniq
26
+ end
27
+
28
+ def stop_areas
29
+ Chouette::StopArea.joins(:stop_points => [:route => [:line => :network] ]).where(:networks => {:id => self.id})
30
+ end
31
+
32
+ end
33
+
@@ -0,0 +1,36 @@
1
+ class Chouette::ObjectId < String
2
+
3
+ def valid?
4
+ parts.present?
5
+ end
6
+ alias_method :objectid?, :valid?
7
+
8
+ @@format = /^([0-9A-Za-z_]+):([A-Za-z]+):([0-9A-Za-z_-]+)$/
9
+ cattr_reader :format
10
+
11
+ def parts
12
+ match(format).try(:captures)
13
+ end
14
+
15
+ def system_id
16
+ parts.try(:first)
17
+ end
18
+
19
+ def object_type
20
+ parts.try(:second)
21
+ end
22
+
23
+ def local_id
24
+ parts.try(:third)
25
+ end
26
+
27
+ def self.create(system_id, object_type, local_id)
28
+ new [system_id, object_type, local_id].join(":")
29
+ end
30
+
31
+ def self.new(string)
32
+ string ||= ""
33
+ self === string ? string : super
34
+ end
35
+
36
+ end
@@ -0,0 +1,39 @@
1
+ require 'geokit'
2
+
3
+ class Chouette::PtLink < Chouette::ActiveRecord
4
+ # FIXME http://jira.codehaus.org/browse/JRUBY-6358
5
+ set_primary_key :id
6
+
7
+ attr_accessible :start_of_link_id, :end_of_link_id, :route_id, :objectid, :object_version, :creation_time, :creator_id, :name, :comment, :link_distance
8
+ include Geokit::Mappable
9
+
10
+
11
+ def geometry
12
+ the_geom
13
+ end
14
+
15
+ def self.import_csv
16
+ csv_file = Rails.root + "chouette_pt_links.csv"
17
+ if File.exists?( csv_file)
18
+ csv = CSV::Reader.parse(File.read(csv_file))
19
+
20
+ slug = csv.shift.first
21
+
22
+ Network::Base.find_by_slug( slug).tune_connection
23
+
24
+ csv.each do |row|
25
+ origin = Chouette::StopArea.find_by_objectid( row[0])
26
+ destination = Chouette::StopArea.find_by_objectid( row[1])
27
+
28
+ raise "unknown origin #{row[0]}" unless origin
29
+ raise "unknown destination #{row[1]}" unless destination
30
+
31
+ Chouette::PtLink.create( :departure_id => origin.id,
32
+ :arrival_id => destination.id,
33
+ :the_geom => GeoRuby::SimpleFeatures::Geometry.from_hex_ewkb( row[2]))
34
+ end
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,158 @@
1
+ class Chouette::Route < Chouette::TridentActiveRecord
2
+ # FIXME http://jira.codehaus.org/browse/JRUBY-6358
3
+ set_primary_key :id
4
+
5
+ attr_accessor :wayback_code
6
+ attr_accessor :direction_code
7
+
8
+ attr_accessible :direction_code, :wayback_code, :line_id, :objectid, :object_version, :creation_time, :creator_id, :name
9
+ attr_accessible :comment, :opposite_route_id, :published_name, :number, :direction, :wayback
10
+
11
+ def self.nullable_attributes
12
+ [:published_name, :comment, :number]
13
+ end
14
+
15
+ belongs_to :line
16
+
17
+ has_many :journey_patterns, :dependent => :destroy
18
+ has_many :vehicle_journeys, :dependent => :destroy do
19
+ def timeless
20
+ all( :conditions => ['vehicle_journeys.id NOT IN (?)', Chouette::VehicleJourneyAtStop.where( :stop_point_id => proxy_association.owner.journey_patterns.pluck( :departure_stop_point_id)).pluck(:vehicle_journey_id)] )
21
+ end
22
+ end
23
+ belongs_to :opposite_route, :class_name => 'Chouette::Route', :foreign_key => :opposite_route_id
24
+ has_many :stop_points, :order => 'position', :dependent => :destroy do
25
+ def find_by_stop_area(stop_area)
26
+ stop_area_ids = Integer === stop_area ? [stop_area] : (stop_area.children_in_depth + [stop_area]).map(&:id)
27
+ where( :stop_area_id => stop_area_ids).first or
28
+ raise ActiveRecord::RecordNotFound.new("Can't find a StopArea #{stop_area.inspect} in Route #{proxy_owner.id.inspect}'s StopPoints")
29
+ end
30
+
31
+ def between(departure, arrival)
32
+ between_positions = [departure, arrival].collect do |endpoint|
33
+ case endpoint
34
+ when Chouette::StopArea
35
+ find_by_stop_area(endpoint).position
36
+ when Chouette::StopPoint
37
+ endpoint.position
38
+ when Integer
39
+ endpoint
40
+ else
41
+ raise ActiveRecord::RecordNotFound.new("Can't determine position in route #{proxy_owner.id} with #{departure.inspect}")
42
+ end
43
+ end
44
+ where(" position between ? and ? ", between_positions.first, between_positions.last)
45
+ end
46
+ end
47
+ has_many :stop_areas, :through => :stop_points, :order => 'stop_points.position' do
48
+ def between(departure, arrival)
49
+ departure, arrival = [departure, arrival].collect do |endpoint|
50
+ String === endpoint ? Chouette::StopArea.find_by_objectid(endpoint) : endpoint
51
+ end
52
+ proxy_owner.stop_points.between(departure, arrival).includes(:stop_area).collect(&:stop_area)
53
+ end
54
+ end
55
+
56
+ validates_presence_of :name
57
+ validates_presence_of :line
58
+ validates_presence_of :direction_code
59
+ validates_presence_of :wayback_code
60
+
61
+ before_destroy :dereference_opposite_route
62
+
63
+ def dereference_opposite_route
64
+ self.line.routes.each do |r|
65
+ r.update_attributes( :opposite_route => nil) if r.opposite_route == self
66
+ end
67
+ end
68
+
69
+ def geometry
70
+ points = stop_areas.map(&:to_lat_lng).compact.map do |loc|
71
+ [loc.lng, loc.lat]
72
+ end
73
+ GeoRuby::SimpleFeatures::LineString.from_coordinates( points, 4326)
74
+ end
75
+
76
+ def time_tables
77
+ self.vehicle_journeys.joins(:time_tables).map(&:"time_tables").flatten.uniq
78
+ end
79
+
80
+ def sorted_vehicle_journeys
81
+ vehicle_journeys.includes( :vehicle_journey_at_stops, :journey_pattern).where( "vehicle_journey_at_stops.stop_point_id=journey_patterns.departure_stop_point_id").order( "vehicle_journey_at_stops.departure_time")
82
+ end
83
+
84
+ def self.direction_binding
85
+ { "A" => "straight_forward",
86
+ "R" => "backward",
87
+ "ClockWise" => "clock_wise",
88
+ "CounterClockWise" => "counter_clock_wise",
89
+ "North" => "north",
90
+ "NorthWest" => "north_west",
91
+ "West" => "west",
92
+ "SouthWest" => "south_west",
93
+ "South" => "south",
94
+ "SouthEast" => "south_east",
95
+ "East" => "east",
96
+ "NorthEast" => "north_east"}
97
+ end
98
+ def direction_code
99
+ return nil if self.class.direction_binding[direction].nil?
100
+ Chouette::Direction.new( self.class.direction_binding[direction])
101
+ end
102
+ def direction_code=(direction_code)
103
+ self.direction = nil
104
+ self.class.direction_binding.each do |k,v|
105
+ self.direction = k if v==direction_code
106
+ end
107
+ end
108
+ @@directions = nil
109
+ def self.directions
110
+ @@directions ||= Chouette::Direction.all
111
+ end
112
+ def self.wayback_binding
113
+ { "A" => "straight_forward", "R" => "backward"}
114
+ end
115
+ def wayback_code
116
+ return nil if self.class.wayback_binding[wayback].nil?
117
+ Chouette::Wayback.new( self.class.wayback_binding[wayback])
118
+ end
119
+ def wayback_code=(wayback_code)
120
+ self.wayback = nil
121
+ self.class.wayback_binding.each do |k,v|
122
+ self.wayback = k if v==wayback_code
123
+ end
124
+ end
125
+ @@waybacks = nil
126
+ def self.waybacks
127
+ @@waybacks ||= Chouette::Wayback.all
128
+ end
129
+
130
+ def stop_point_permutation?( stop_point_ids)
131
+ stop_points.map(&:id).map(&:to_s).sort == stop_point_ids.map(&:to_s).sort
132
+ end
133
+
134
+ def reorder!( stop_point_ids)
135
+ return false unless stop_point_permutation?( stop_point_ids)
136
+
137
+ stop_area_id_by_stop_point_id = {}
138
+ stop_points.each do |sp|
139
+ stop_area_id_by_stop_point_id.merge!( sp.id => sp.stop_area_id)
140
+ end
141
+
142
+ reordered_stop_area_ids = []
143
+ stop_point_ids.each do |stop_point_id|
144
+ reordered_stop_area_ids << stop_area_id_by_stop_point_id[ stop_point_id.to_i]
145
+ end
146
+
147
+ stop_points.each_with_index do |sp, index|
148
+ if sp.stop_area_id.to_s != reordered_stop_area_ids[ index].to_s
149
+ #result = sp.update_attributes( :stop_area_id => reordered_stop_area_ids[ index])
150
+ sp.stop_area_id = reordered_stop_area_ids[ index]
151
+ result = sp.save!
152
+ end
153
+ end
154
+
155
+ return true
156
+ end
157
+ end
158
+
@@ -0,0 +1,273 @@
1
+ require 'geokit'
2
+ require 'geo_ruby'
3
+
4
+ class Chouette::StopArea < Chouette::TridentActiveRecord
5
+ # FIXME http://jira.codehaus.org/browse/JRUBY-6358
6
+ set_primary_key :id
7
+ include Geokit::Mappable
8
+ has_many :stop_points, :dependent => :destroy
9
+ has_many :access_points, :dependent => :destroy
10
+ has_many :access_links, :dependent => :destroy
11
+ has_and_belongs_to_many :routing_lines, :class_name => 'Chouette::Line', :foreign_key => "stop_area_id", :association_foreign_key => "line_id", :join_table => "routing_constraints_lines", :order => "lines.number"
12
+ has_and_belongs_to_many :routing_stops, :class_name => 'Chouette::StopArea', :foreign_key => "parent_id", :association_foreign_key => "child_id", :join_table => "stop_areas_stop_areas", :order => "stop_areas.name"
13
+
14
+ acts_as_tree :foreign_key => 'parent_id',:order => "name"
15
+
16
+ attr_accessor :stop_area_type
17
+ attr_accessor :children_ids
18
+
19
+ attr_accessible :routing_stop_ids, :routing_line_ids, :children_ids, :stop_area_type, :parent_id, :objectid
20
+ attr_accessible :object_version, :creation_time, :creator_id, :name, :comment, :area_type, :registration_number
21
+ attr_accessible :nearest_topic_name, :fare_code, :longitude, :latitude, :long_lat_type, :x, :y, :projection_type
22
+ attr_accessible :country_code, :street_name
23
+
24
+ # workaround of ruby 1.8 private method y block attribute y reading access
25
+ def y
26
+ read_attribute :y
27
+ end
28
+
29
+ validates_uniqueness_of :registration_number, :allow_nil => true, :allow_blank => true
30
+ validates_format_of :registration_number, :with => %r{\A[0-9A-Za-z_-]+\Z}, :allow_blank => true
31
+ validates_presence_of :name
32
+ validates_presence_of :area_type
33
+
34
+ validates_presence_of :latitude, :if => :longitude
35
+ validates_presence_of :longitude, :if => :latitude
36
+ validates_numericality_of :latitude, :less_than_or_equal_to => 90, :greater_than_or_equal_to => -90, :allow_nil => true
37
+ validates_numericality_of :longitude, :less_than_or_equal_to => 180, :greater_than_or_equal_to => -180, :allow_nil => true
38
+
39
+ validates_presence_of :x, :if => :y
40
+ validates_presence_of :y, :if => :x
41
+ validates_numericality_of :x, :allow_nil => true
42
+ validates_numericality_of :y, :allow_nil => true
43
+
44
+ def self.nullable_attributes
45
+ [:registration_number, :street_name, :country_code, :fare_code, :nearest_topic_name, :comment, :projection_type, :long_lat_type]
46
+ end
47
+
48
+ after_update :clean_invalid_access_links
49
+
50
+ def children_in_depth
51
+ return [] if self.children.empty?
52
+
53
+ self.children + self.children.map do |child|
54
+ child.children_in_depth
55
+ end.flatten.compact
56
+ end
57
+
58
+ def possible_children
59
+ case area_type
60
+ when "BoardingPosition" then []
61
+ when "Quay" then []
62
+ when "CommercialStopPoint" then Chouette::StopArea.where(:area_type => ['Quay', 'BoardingPosition']) - [self]
63
+ when "StopPlace" then Chouette::StopArea.where(:area_type => ['StopPlace', 'CommercialStopPoint']) - [self]
64
+ when "ITL" then Chouette::StopArea.where(:area_type => ['Quay', 'BoardingPosition', 'StopPlace', 'CommercialStopPoint'])
65
+ end
66
+
67
+ end
68
+
69
+ def possible_parents
70
+ case area_type
71
+ when "BoardingPosition" then Chouette::StopArea.where(:area_type => "CommercialStopPoint") - [self]
72
+ when "Quay" then Chouette::StopArea.where(:area_type => "CommercialStopPoint") - [self]
73
+ when "CommercialStopPoint" then Chouette::StopArea.where(:area_type => "StopPlace") - [self]
74
+ when "StopPlace" then Chouette::StopArea.where(:area_type => "StopPlace") - [self]
75
+ end
76
+ end
77
+
78
+ def lines
79
+ if (area_type == 'CommercialStopPoint')
80
+ self.children.collect(&:stop_points).flatten.collect(&:route).flatten.collect(&:line).flatten.uniq
81
+ else
82
+ self.stop_points.collect(&:route).flatten.collect(&:line).flatten.uniq
83
+ end
84
+ end
85
+
86
+ def routes
87
+ self.stop_points.collect(&:route).flatten.uniq
88
+ end
89
+
90
+ def self.commercial
91
+ where :area_type => "CommercialStopPoint"
92
+ end
93
+
94
+ def to_lat_lng
95
+ Geokit::LatLng.new(latitude, longitude) if latitude and longitude
96
+ end
97
+
98
+ def geometry
99
+ GeoRuby::SimpleFeatures::Point.from_lon_lat(longitude, latitude, 4326) if latitude and longitude
100
+ end
101
+
102
+ def geometry=(geometry)
103
+ geometry = geometry.to_wgs84
104
+ self.latitude, self.longitude, self.long_lat_type = geometry.lat, geometry.lng, "WGS84"
105
+ end
106
+
107
+ def position
108
+ geometry
109
+ end
110
+
111
+ def position=(position)
112
+ position = nil if String === position && position == ""
113
+ position = Geokit::LatLng.normalize(position), 4326 if String === position
114
+ self.latitude = position.lat
115
+ self.longitude = position.lng
116
+ end
117
+
118
+ def default_position
119
+ # for first StopArea ... the bounds is nil :(
120
+ Chouette::StopArea.bounds and Chouette::StopArea.bounds.center
121
+ end
122
+
123
+ def self.near(origin, distance = 0.3)
124
+ origin = origin.to_lat_lng
125
+
126
+ lat_degree_units = units_per_latitude_degree(:kms)
127
+ lng_degree_units = units_per_longitude_degree(origin.lat, :kms)
128
+
129
+ where "SQRT(POW(#{lat_degree_units}*(#{origin.lat}-latitude),2)+POW(#{lng_degree_units}*(#{origin.lng}-longitude),2)) <= #{distance}"
130
+ end
131
+
132
+ def self.bounds
133
+ # Give something like :
134
+ # [["113.5292500000000000", "22.1127580000000000", "113.5819330000000000", "22.2157050000000000"]]
135
+ min_and_max = connection.select_rows("select min(longitude) as min_lon, min(latitude) as min_lat, max(longitude) as max_lon, max(latitude) as max_lat from #{table_name} where latitude is not null and longitude is not null").first
136
+ return nil unless min_and_max
137
+
138
+ # Ignore [nil, nil, nil, nil]
139
+ min_and_max.compact!
140
+ return nil unless min_and_max.size == 4
141
+
142
+ min_and_max.collect! { |n| n.to_f }
143
+
144
+ # We need something like :
145
+ # [[113.5292500000000000, 22.1127580000000000], [113.5819330000000000, 22.2157050000000000]]
146
+ coordinates = min_and_max.each_slice(2).to_a
147
+ GeoRuby::SimpleFeatures::Envelope.from_coordinates coordinates
148
+ end
149
+
150
+ def stop_area_type
151
+ area_type && Chouette::AreaType.new(area_type.underscore)
152
+ end
153
+
154
+ def stop_area_type=(stop_area_type)
155
+ self.area_type = (stop_area_type ? stop_area_type.camelcase : nil)
156
+ if self.area_type == 'Itl'
157
+ self.area_type = 'ITL'
158
+ end
159
+ end
160
+
161
+ @@stop_area_types = nil
162
+ def self.stop_area_types
163
+ @@stop_area_types ||= Chouette::AreaType.all.select do |stop_area_type|
164
+ stop_area_type.to_i >= 0
165
+ end
166
+ end
167
+
168
+ def children_ids=(children_ids)
169
+ children = children_ids.split(',').uniq
170
+ # remove unset children
171
+ self.children.each do |child|
172
+ if (! children.include? child.id)
173
+ child.update_attribute :parent_id, nil
174
+ end
175
+ end
176
+ # add new children
177
+ Chouette::StopArea.find(children).each do |child|
178
+ child.update_attribute :parent_id, self.id
179
+ end
180
+ end
181
+
182
+ def routing_stop_ids=(routing_stop_ids)
183
+ stops = routing_stop_ids.split(',').uniq
184
+ self.routing_stops.clear
185
+ Chouette::StopArea.find(stops).each do |stop|
186
+ self.routing_stops << stop
187
+ end
188
+ end
189
+
190
+ def routing_line_ids=(routing_line_ids)
191
+ lines = routing_line_ids.split(',').uniq
192
+ self.routing_lines.clear
193
+ Chouette::Line.find(lines).each do |line|
194
+ self.routing_lines << line
195
+ end
196
+ end
197
+
198
+ def self.without_geometry
199
+ where("latitude is null or longitude is null")
200
+ end
201
+
202
+ def self.with_geometry
203
+ where("latitude is not null and longitude is not null")
204
+ end
205
+
206
+ def self.default_geometry!
207
+ count = 0
208
+ scoped.find_each do |stop_area|
209
+ Chouette::StopArea.unscoped do
210
+ count += 1 if stop_area.default_geometry!
211
+ end
212
+ end
213
+ count
214
+ end
215
+
216
+ def default_geometry!
217
+ new_geometry = default_geometry
218
+ update_attribute :geometry, new_geometry if new_geometry
219
+ end
220
+
221
+ def default_geometry
222
+ children_geometries = children.with_geometry.map(&:geometry).uniq
223
+ GeoRuby::SimpleFeatures::Point.centroid children_geometries if children_geometries.present?
224
+ end
225
+
226
+ def generic_access_link_matrix
227
+ matrix = Array.new
228
+ access_points.each do |access_point|
229
+ matrix += access_point.generic_access_link_matrix
230
+ end
231
+ matrix
232
+ end
233
+
234
+ def detail_access_link_matrix
235
+ matrix = Array.new
236
+ access_points.each do |access_point|
237
+ matrix += access_point.detail_access_link_matrix
238
+ end
239
+ matrix
240
+ end
241
+
242
+ def children_at_base
243
+ list = Array.new
244
+ children_in_depth.each do |child|
245
+ if child.area_type == 'Quay' || child.area_type == 'BoardingPosition'
246
+ list << child
247
+ end
248
+ end
249
+ list
250
+ end
251
+
252
+ def parents
253
+ list = Array.new
254
+ if !parent.nil?
255
+ list << parent
256
+ list += parent.parents
257
+ end
258
+ list
259
+ end
260
+
261
+ def clean_invalid_access_links
262
+ stop_parents = parents
263
+ access_links.each do |link|
264
+ unless stop_parents.include? link.access_point.stop_area
265
+ link.delete
266
+ end
267
+ end
268
+ children.each do |child|
269
+ child.clean_invalid_access_links
270
+ end
271
+ end
272
+
273
+ end
@@ -0,0 +1,33 @@
1
+ class Chouette::StopPoint < Chouette::TridentActiveRecord
2
+ # FIXME http://jira.codehaus.org/browse/JRUBY-6358
3
+ set_primary_key :id
4
+
5
+ belongs_to :stop_area
6
+ belongs_to :route
7
+ acts_as_list :scope => 'route_id = \'#{route.id}\'',:top_of_list => 0
8
+
9
+ attr_accessible :route_id, :stop_area_id, :objectid, :object_version, :creation_time, :creator_id, :position
10
+
11
+ has_many :vehicle_journey_at_stops, :dependent => :destroy
12
+ has_many :vehicle_journeys, :through => :vehicle_journey_at_stops, :uniq => true
13
+
14
+ before_destroy :remove_dependent_journey_pattern_stop_points
15
+
16
+ validates_presence_of :stop_area
17
+ validates_presence_of :route
18
+
19
+ scope :default_order, order("position")
20
+
21
+ def self.area_candidates
22
+ Chouette::StopArea.where( :area_type => ['Quay', 'BoardingPosition'])
23
+ end
24
+
25
+ def remove_dependent_journey_pattern_stop_points
26
+ route.journey_patterns.each do |jp|
27
+ if jp.stop_point_ids.include?( id)
28
+ jp.stop_point_ids = jp.stop_point_ids - [id]
29
+ end
30
+ end
31
+ end
32
+
33
+ end