ninoxe 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|