ninoxe 0.0.8
Sign up to get free protection for your applications and to get access to all the features.
- data/MIT-LICENSE +20 -0
- data/README.rdoc +3 -0
- data/Rakefile +49 -0
- data/app/assets/javascripts/ninoxe/application.js +15 -0
- data/app/assets/stylesheets/ninoxe/application.css +13 -0
- data/app/controllers/ninoxe/application_controller.rb +4 -0
- data/app/helpers/ninoxe/application_helper.rb +4 -0
- data/app/models/chouette/access_link.rb +63 -0
- data/app/models/chouette/access_point.rb +145 -0
- data/app/models/chouette/access_point_type.rb +50 -0
- data/app/models/chouette/active_record.rb +66 -0
- data/app/models/chouette/area_type.rb +56 -0
- data/app/models/chouette/chouette_structure.dump +3417 -0
- data/app/models/chouette/command.rb +93 -0
- data/app/models/chouette/command_line_support.rb +35 -0
- data/app/models/chouette/company.rb +19 -0
- data/app/models/chouette/connection_link.rb +43 -0
- data/app/models/chouette/connection_link_type.rb +51 -0
- data/app/models/chouette/direction.rb +60 -0
- data/app/models/chouette/exporter.rb +32 -0
- data/app/models/chouette/file_validator.rb +47 -0
- data/app/models/chouette/group_of_line.rb +30 -0
- data/app/models/chouette/journey_pattern.rb +63 -0
- data/app/models/chouette/line.rb +65 -0
- data/app/models/chouette/link_orientation_type.rb +49 -0
- data/app/models/chouette/loader.rb +110 -0
- data/app/models/chouette/network.rb +33 -0
- data/app/models/chouette/object_id.rb +36 -0
- data/app/models/chouette/pt_link.rb +39 -0
- data/app/models/chouette/route.rb +158 -0
- data/app/models/chouette/stop_area.rb +273 -0
- data/app/models/chouette/stop_point.rb +33 -0
- data/app/models/chouette/time_table.rb +146 -0
- data/app/models/chouette/time_table_date.rb +14 -0
- data/app/models/chouette/time_table_period.rb +26 -0
- data/app/models/chouette/time_table_vehicle_journey.rb +5 -0
- data/app/models/chouette/transport_mode.rb +71 -0
- data/app/models/chouette/trident_active_record.rb +97 -0
- data/app/models/chouette/vehicle_journey.rb +101 -0
- data/app/models/chouette/vehicle_journey_at_stop.rb +45 -0
- data/app/models/chouette/wayback.rb +50 -0
- data/app/views/layouts/ninoxe/application.html.erb +14 -0
- data/config/database.yml +9 -0
- data/config/database.yml.ci +14 -0
- data/config/database.yml.travis +9 -0
- data/config/locales/en.yml +15 -0
- data/config/locales/fr.yml +16 -0
- data/config/routes.rb +2 -0
- data/db/migrate/20120213131553_create_chouette_line.rb +26 -0
- data/db/migrate/20120214101458_create_chouette_company.rb +25 -0
- data/db/migrate/20120214101645_create_chouette_ptnetwork.rb +24 -0
- data/db/migrate/20120406144221_create_chouette_stop_area.rb +33 -0
- data/db/migrate/20120411144209_create_time_table.rb +38 -0
- data/db/migrate/20120425064403_create_chouette_route.rb +22 -0
- data/db/migrate/20120425123944_create_chouette_stop_point.rb +17 -0
- data/db/migrate/20120426114527_create_chouette_connection_link.rb +28 -0
- data/db/migrate/20120521073709_create_chouette_journey_pattern.rb +26 -0
- data/db/migrate/20120521073723_create_chouette_journey_pattern_stop_point.rb +14 -0
- data/db/migrate/20120521073740_create_chouette_time_slot.rb +22 -0
- data/db/migrate/20120521073746_create_chouette_vehicle_journey.rb +34 -0
- data/db/migrate/20120521073758_create_chouette_vehicle_journey_at_stop.rb +25 -0
- data/db/migrate/20120521073900_create_chouette_time_table_vehicle_journey.rb +16 -0
- data/db/migrate/20120521132304_create_chouette_access_point.rb +34 -0
- data/db/migrate/20120521132313_create_chouette_access_link.rb +33 -0
- data/db/migrate/20120521132429_create_chouette_facility.rb +34 -0
- data/db/migrate/20120521132502_create_chouette_facility_feature.rb +12 -0
- data/db/migrate/20120521132551_create_chouette_group_of_line.rb +18 -0
- data/db/migrate/20120521132600_create_chouette_group_of_line_line.rb +12 -0
- data/db/migrate/20120521132656_create_chouette_routing_constrains_line.rb +12 -0
- data/db/migrate/20120521132724_create_chouette_stoparea_stoparea.rb +12 -0
- data/db/migrate/20120531091529_create_chouette_pt_link.rb +21 -0
- data/db/migrate/20120926141405_add_id_to_time_table_date.rb +12 -0
- data/db/migrate/20120926141415_add_id_to_time_table_period.rb +12 -0
- data/db/migrate/20121024072219_add_fields_to_access_points.rb +12 -0
- data/lib/chouette_factories.rb +1 -0
- data/lib/factories/chouette_access_links.rb +11 -0
- data/lib/factories/chouette_access_points.rb +8 -0
- data/lib/factories/chouette_companies.rb +5 -0
- data/lib/factories/chouette_connection_links.rb +11 -0
- data/lib/factories/chouette_group_of_lines.rb +4 -0
- data/lib/factories/chouette_journey_pattern.rb +32 -0
- data/lib/factories/chouette_lines.rb +20 -0
- data/lib/factories/chouette_networks.rb +5 -0
- data/lib/factories/chouette_routes.rb +18 -0
- data/lib/factories/chouette_stop_areas.rb +8 -0
- data/lib/factories/chouette_stop_points.rb +7 -0
- data/lib/factories/chouette_time_table.rb +21 -0
- data/lib/factories/chouette_vehicle_journey.rb +50 -0
- data/lib/factories/chouette_vehicle_journey_at_stop.rb +5 -0
- data/lib/ninoxe/engine.rb +15 -0
- data/lib/ninoxe/version.rb +3 -0
- data/lib/ninoxe.rb +7 -0
- 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
|