aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruno Perles2015-12-16 10:02:29 +0100
committerBruno Perles2015-12-16 10:02:29 +0100
commit013f4fa8fe9bb08f3ed1d15f905ca2a8437d6aa7 (patch)
tree426b9c17167c10547da2222517cbd4433ae554fe
parent2590606c5912a85b8cb1aaa40c57dab67d75e7f7 (diff)
downloadchouette-core-013f4fa8fe9bb08f3ed1d15f905ca2a8437d6aa7.tar.bz2
Add route_sections for traces
-rw-r--r--Gemfile6
-rw-r--r--Gemfile.lock29
-rw-r--r--app/assets/images/icons/edit-disabled.pngbin0 -> 333 bytes
-rw-r--r--app/assets/javascripts/route_section.js.coffee58
-rw-r--r--app/assets/stylesheets/main/route_sections.css.scss68
-rw-r--r--app/assets/stylesheets/main/routes.scss24
-rw-r--r--app/assets/stylesheets/modules/icons.scss5
-rw-r--r--app/controllers/route_sections_controller.rb70
-rw-r--r--app/controllers/route_sections_selectors_controller.rb42
-rw-r--r--app/controllers/routes_controller.rb2
-rw-r--r--app/controllers/stop_areas_controller.rb2
-rw-r--r--app/helpers/breadcrumb_helper.rb11
-rw-r--r--app/helpers/route_section_selectors_helper.rb23
-rw-r--r--app/maps/design/route_section_selector_style_map.rb73
-rw-r--r--app/maps/design/route_section_style_map.rb66
-rw-r--r--app/maps/route_section_map.rb67
-rw-r--r--app/maps/route_section_selector_map.rb118
-rw-r--r--app/models/referential.rb4
-rw-r--r--app/models/route_section_search.rb34
-rw-r--r--app/models/route_sections_selector.rb99
-rw-r--r--app/views/journey_patterns/show.html.erb4
-rw-r--r--app/views/referentials/_counts.html.erb4
-rw-r--r--app/views/route_sections/_form.html.erb24
-rw-r--r--app/views/route_sections/edit.html.erb4
-rw-r--r--app/views/route_sections/index.html.erb56
-rw-r--r--app/views/route_sections/new.html.erb3
-rw-r--r--app/views/route_sections/show.html.erb28
-rw-r--r--app/views/route_sections/show.kml.erb8
-rw-r--r--app/views/route_sections_selectors/_selection.js.erb28
-rw-r--r--app/views/route_sections_selectors/edit.html.erb48
-rw-r--r--app/views/shared/_header.erb4
-rw-r--r--config/database.yml6
-rw-r--r--config/database.yml.travis6
-rw-r--r--config/initializers/apartment.rb2
-rw-r--r--config/initializers/route_section.rb3
-rw-r--r--config/locales/referentials.fr.yml1
-rw-r--r--config/locales/route_sections.en.yml47
-rw-r--r--config/locales/route_sections.fr.yml47
-rw-r--r--config/routes.rb9
-rw-r--r--db/migrate/20150529134410_create_route_sections.ninoxe_engine.rb18
-rw-r--r--db/migrate/20150922103725_add_distance_to_route_sections.ninoxe_engine.rb8
-rw-r--r--db/migrate/20151111210749_add_no_processing_to_route_sections.ninoxe_engine.rb8
-rw-r--r--db/migrate/20151203132113_create_journey_pattern_sections.ninoxe_engine.rb16
-rw-r--r--db/schema.rb120
-rw-r--r--lib/osrm_route_section_processor.rb36
-rw-r--r--lib/tasks/route_sections.rake17
-rw-r--r--spec/controllers/routes_controller_spec.rb10
-rw-r--r--spec/models/route_sections_selector_spec.rb43
-rw-r--r--spec/support/fake_iev_server.rb15
-rw-r--r--spec/support/referential.rb8
50 files changed, 1339 insertions, 93 deletions
diff --git a/Gemfile b/Gemfile
index ff52cb1f3..c0558eeaf 100644
--- a/Gemfile
+++ b/Gemfile
@@ -52,6 +52,9 @@ platforms :ruby do
gem 'sqlite3'
end
+gem 'activerecord-postgis-adapter'
+gem 'polylines'
+
# Authentication
gem 'devise', '~> 3.4.0'
gem 'devise-encryptable'
@@ -112,7 +115,8 @@ group :development do
gem 'guard'
gem 'guard-rspec'
gem 'rails-erd'
- gem 'meta_request'
+ # MetaRequest is incompatible with rgeo-activerecord
+ # gem 'meta_request'
gem 'letter_opener'
gem 'quiet_assets', '~> 1.0'
gem 'simplecov', '~> 0.10.0'
diff --git a/Gemfile.lock b/Gemfile.lock
index d439cef61..175b2e760 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -44,6 +44,9 @@ GEM
activerecord-jdbcpostgresql-adapter (1.3.15)
activerecord-jdbc-adapter (~> 1.3.15)
jdbc-postgres (>= 9.1)
+ activerecord-postgis-adapter (2.2.2)
+ activerecord (>= 4.0.0, < 4.2.0)
+ rgeo-activerecord (~> 1.2)
activesupport (4.1.10)
i18n (~> 0.6, >= 0.6.9)
json (~> 1.7, >= 1.7.7)
@@ -76,7 +79,6 @@ GEM
builder (3.2.2)
calendar_helper (0.2.5)
open4
- callsite (0.0.11)
capistrano (2.13.5)
highline
net-scp (>= 1.0.0)
@@ -106,7 +108,7 @@ GEM
coffee-script-source (1.9.1)
daemons (1.1.9)
database_cleaner (1.4.1)
- dbf (3.0.1)
+ dbf (3.0.0)
debug_inspector (0.0.2)
deep_cloneable (2.0.2)
activerecord (>= 3.1.0, < 5.0.0)
@@ -219,9 +221,9 @@ GEM
launchy (2.4.3-java)
addressable (~> 2.3)
spoon (~> 0.0.1)
- letter_opener (1.3.0)
+ letter_opener (1.4.1)
launchy (~> 2.2)
- libv8 (3.16.14.7)
+ libv8 (3.16.14.11)
listen (2.8.6)
celluloid (>= 0.15.2)
rb-fsevent (>= 0.9.3)
@@ -230,10 +232,6 @@ GEM
mail (2.6.3)
mime-types (>= 1.16, < 3)
map_layers (0.0.4)
- meta_request (0.3.4)
- callsite (~> 0.0, >= 0.0.11)
- rack-contrib (~> 1.1)
- railties (>= 3.0.0, < 5.0.0)
method_source (0.8.2)
mime-types (2.4.3)
mimemagic (0.3.0)
@@ -268,6 +266,7 @@ GEM
websocket-driver (>= 0.2.0)
polyamorous (1.1.0)
activerecord (>= 3.0)
+ polylines (0.3.0)
pry (0.10.1)
coderay (~> 1.1.0)
method_source (~> 0.8.1)
@@ -277,15 +276,13 @@ GEM
method_source (~> 0.8.1)
slop (~> 3.4)
spoon (~> 0.0)
- pry-rails (0.3.3)
+ pry-rails (0.3.4)
pry (>= 0.9.10)
quiet_assets (1.1.0)
railties (>= 3.1, < 5.0)
rabl (0.11.6)
activesupport (>= 2.3.14)
- rack (1.5.5)
- rack-contrib (1.2.0)
- rack (>= 0.9.1)
+ rack (1.5.3)
rack-test (0.6.3)
rack (>= 1.0)
rails (4.1.10)
@@ -355,10 +352,13 @@ GEM
ffi (>= 0.5.0)
rdoc (4.2.0)
json (~> 1.4)
- ref (1.0.5)
+ ref (2.0.0)
responders (1.1.2)
railties (>= 3.2, < 4.2)
rgeo (0.4.0)
+ rgeo-activerecord (1.2.0)
+ activerecord (~> 4.0)
+ rgeo (~> 0.3)
roo (1.13.2)
nokogiri
rubyzip
@@ -481,6 +481,7 @@ DEPENDENCIES
RedCloth
SyslogLogger
activerecord-jdbcpostgresql-adapter (~> 1.3.3)
+ activerecord-postgis-adapter
acts_as_list (~> 0.6.0)
acts_as_tree (~> 2.1.0)
apartment (~> 1.0.0)
@@ -522,12 +523,12 @@ DEPENDENCIES
launchy
letter_opener
map_layers (= 0.0.4)
- meta_request
mimemagic
newrelic_rpm
ninoxe!
pg
poltergeist
+ polylines
pry-rails
quiet_assets (~> 1.0)
rabl
diff --git a/app/assets/images/icons/edit-disabled.png b/app/assets/images/icons/edit-disabled.png
new file mode 100644
index 000000000..aaefed65c
--- /dev/null
+++ b/app/assets/images/icons/edit-disabled.png
Binary files differ
diff --git a/app/assets/javascripts/route_section.js.coffee b/app/assets/javascripts/route_section.js.coffee
new file mode 100644
index 000000000..f2e494c0c
--- /dev/null
+++ b/app/assets/javascripts/route_section.js.coffee
@@ -0,0 +1,58 @@
+class @RouteSectionMap
+ @onSelectedFeature: (feature) ->
+ route_section_id = feature.data.id
+
+ routeSectionOption = $("option[value=#{route_section_id}]")
+ routeSectionOption.parent().val route_section_id
+
+ $('#map-selection').show()
+ $('#empty-map-selection').hide()
+
+ selectionUrl = location.pathname.replace /edit$/, "selection"
+ $.ajax(url: selectionUrl, method: 'POST', data: { route_section_id: route_section_id }, dataType: 'html').done (data) ->
+ $('#map-selection div').replaceWith(data)
+
+ @onUnselectedFeature: (feature) ->
+ $('#map-selection').hide()
+ $('#empty-map-selection').show()
+
+jQuery ->
+ if $("#map.route_section").length > 0 and user_geometry?
+ projWGS84 = new OpenLayers.Projection("EPSG:4326")
+ proj900913 = new OpenLayers.Projection("EPSG:900913")
+ wtk_format = new OpenLayers.Format.WKT()
+
+ user_geometry.events.on({
+ afterfeaturemodified: (event) ->
+ wgs84_geometry = event.feature.geometry.transform(proj900913, projWGS84)
+ wgs84_feature = new OpenLayers.Feature.Vector(wgs84_geometry)
+ ewtk = "SRID=4326;#{wtk_format.write(wgs84_feature)}"
+
+ $('#route_section_editable_geometry').val(ewtk)
+ return
+ })
+
+ $('#new_route_sections_selector select').on 'change', ->
+ new_route_section_id = $(this).val()
+
+ edit_link = $(this).closest("tr").find("a.edit-route-section")
+
+ # Save edit link to play with it
+ unless edit_link.data("href-pattern")?
+ edit_link.data "href-pattern", edit_link.attr('href').replace(new RegExp("/route_sections/([0-9]+)/edit"), "/route_sections/:id/edit")
+
+ if !!new_route_section_id
+ edit_link.removeClass "disabled"
+ edit_link.attr 'href', edit_link.data("href-pattern").replace(/:id/, new_route_section_id)
+ else
+ edit_link.addClass "disabled"
+ edit_link.attr 'href', '#'
+
+ $('form.route_section').find('button[type="submit"]').on 'click', (e) ->
+ e.preventDefault();
+ if typeof modify_feature != 'undefined'
+ modify_feature.deactivate()
+ $('form.route_section').submit()
+ return
+
+ return
diff --git a/app/assets/stylesheets/main/route_sections.css.scss b/app/assets/stylesheets/main/route_sections.css.scss
new file mode 100644
index 000000000..cc1c85abc
--- /dev/null
+++ b/app/assets/stylesheets/main/route_sections.css.scss
@@ -0,0 +1,68 @@
+#workspace.route_sections_selectors.edit {
+ td.route_section {
+ .input {
+ padding: 0;
+ margin: 0;
+
+ select {
+ width: 100%;
+ }
+ }
+ }
+
+ a.edit-route-section {
+ background: url(image-path('icons/edit.png')) no-repeat 0% 50%;
+ text-indent: -9999px;
+ display: inline-block;
+ width: 16px;
+ height: 16px;
+
+ margin-right: 8px;
+
+ &.disabled {
+ background-image: url(image-path('icons/edit-disabled.png'));
+ }
+ }
+
+ #map-selection {
+ position: relative;
+ span {
+ display: inline-block;
+ }
+ .departure, .arrival {
+ width: 25%;
+ }
+ .actions {
+ width: 25%;
+ overflow: visible;
+ padding-left: 0;
+ position: absolute;
+ right: 0;
+ }
+ }
+}
+
+#workspace.route_sections.index {
+ th.distance, th.points {
+ text-align: center;
+ }
+
+ td.distance, td.points, td.actions {
+ text-align: center;
+ }
+}
+
+#workspace.route_sections.edit {
+ .formtastic {
+ .input .label {
+ width: 40%;
+ }
+ .actions {
+ padding-left: 19%;
+ }
+ }
+ #map {
+ width: 600px;
+ heigth: 600px;
+ }
+}
diff --git a/app/assets/stylesheets/main/routes.scss b/app/assets/stylesheets/main/routes.scss
index 7714c13a3..44703c7e5 100644
--- a/app/assets/stylesheets/main/routes.scss
+++ b/app/assets/stylesheets/main/routes.scss
@@ -3,7 +3,7 @@
// You can use Sass (SCSS) here: http://sass-lang.com/
#workspace.lines.show
-{
+{
}
#workspace.routes.edit, #workspace.routes.new, #workspace.routes.create, #workspace.routes.update
@@ -11,13 +11,13 @@
#route_color{ width: 100px;
color: white;
font-weight: bold;}
-
+
#stop_points .nested-fields {
ol {
margin-left: 25%;
- .handle { margin-left: 5px;}
+ .handle { margin-left: 5px;}
- .search_stop_area {
+ .search_stop_area {
margin-bottom: 0px !important;
}
@@ -31,7 +31,7 @@
#stop_points .links {
margin: 10px 0 15px 25%;
- }
+ }
}
#workspace.routes.edit_boarding_alighting{
@@ -39,10 +39,18 @@
.stop_area{
padding-top: 7px;
}
-
+
}
#workspace.routes.show
-{
-}
+{
+}
+.large-map {
+ width: 100%;
+ height: 600px;
+ #map {
+ width: 100%;
+ height: 100%;
+ }
+}
diff --git a/app/assets/stylesheets/modules/icons.scss b/app/assets/stylesheets/modules/icons.scss
index 001e511d1..3c42c3bd6 100644
--- a/app/assets/stylesheets/modules/icons.scss
+++ b/app/assets/stylesheets/modules/icons.scss
@@ -5,6 +5,11 @@ a:before {
vertical-align: middle;
}
+a.view:before { // fa-eye
+ content: "\f06e";
+ color: $brand-success;
+}
+
a.add:before { // fa-plus-circle
content: "\f055";
color: $brand-success;
diff --git a/app/controllers/route_sections_controller.rb b/app/controllers/route_sections_controller.rb
new file mode 100644
index 000000000..64cb8c65c
--- /dev/null
+++ b/app/controllers/route_sections_controller.rb
@@ -0,0 +1,70 @@
+class RouteSectionsController < ChouetteController
+
+ defaults :resource_class => Chouette::RouteSection
+
+ respond_to :html
+ respond_to :kml, :only => :show
+
+ belongs_to :referential
+
+ before_action :save_return_to_path, only: [:edit, :create_to_edit]
+ before_action ->(controller) { build_breadcrumb controller.action_name }
+
+ helper_method :search
+
+ def index
+ index!
+ end
+
+ def new
+ @stop_areas = referential.stop_areas.with_geometry.order :name
+ new!
+ end
+
+ def show
+ @map = RouteSectionMap.new(resource).with_helpers(self)
+ show!
+ end
+
+ def edit
+ @map = RouteSectionMap.new(resource, true).with_helpers(self)
+ edit!
+ end
+
+ def update
+ update! { session.delete(:return_to) }
+ end
+
+ def create
+ create! { session.delete(:return_to) }
+ end
+
+ def create_to_edit
+ route_section = Chouette::RouteSection.create(route_section_params)
+ redirect_to edit_referential_route_section_path(referential, route_section)
+ end
+
+ protected
+
+ def save_return_to_path
+ session[:return_to] = params[:return_to] if params[:return_to]
+ end
+
+ def collection
+ # if q = params[:q]
+ # @route_sections ||= Chouette::RouteSection.joins(:departure, :arrival).where(departure: {name: "#{q}"}).or.where(arrival: {name: "#{q}"})
+ # end
+ @route_sections ||= search.collection.includes(:departure, :arrival).paginate page: params[:page]
+ end
+
+ def search
+ @search ||= RouteSectionSearch.new(params[:route_section_search])
+ end
+
+ private
+
+ def route_section_params
+ params.require(:route_section).permit(:departure_id, :arrival_id, :editable_geometry, :no_processing)
+ end
+
+end
diff --git a/app/controllers/route_sections_selectors_controller.rb b/app/controllers/route_sections_selectors_controller.rb
new file mode 100644
index 000000000..05a399ae8
--- /dev/null
+++ b/app/controllers/route_sections_selectors_controller.rb
@@ -0,0 +1,42 @@
+class RouteSectionsSelectorsController < ChouetteController
+
+ # singleton option makes association_chain crazy
+ #defaults singleton: true
+
+ respond_to :html, only: [ :edit, :update ]
+ respond_to :js, only: :section
+
+ belongs_to :referential do
+ belongs_to :line, :parent_class => Chouette::Line do
+ belongs_to :route, :parent_class => Chouette::Route do
+ belongs_to :journey_pattern, parent_class: Chouette::JourneyPattern
+ end
+ end
+ end
+
+ def edit
+ @map = RouteSectionSelectorMap.new(resource).with_helpers(self)
+ end
+
+ def selection
+ parent
+
+ @route_section = referential.route_sections.find params[:route_section_id].to_i
+ render partial: 'selection', format: 'js'
+ end
+
+ private
+
+ def resource
+ @route_sections_selector ||= RouteSectionsSelector.new parent
+ end
+
+ def build_resource
+ @route_sections_selector ||= RouteSectionsSelector.new parent, *resource_params
+ end
+
+ def route_section_selector_params
+ params.require(:route_section_selector).permit()
+ end
+
+end
diff --git a/app/controllers/routes_controller.rb b/app/controllers/routes_controller.rb
index 6dfaf3dd0..59c129867 100644
--- a/app/controllers/routes_controller.rb
+++ b/app/controllers/routes_controller.rb
@@ -75,7 +75,7 @@ class RoutesController < ChouetteController
end
private
-
+
def route_params
params.require(:route).permit( :direction_code, :wayback_code, :line_id, :objectid, :object_version, :creation_time, :creator_id, :name, :comment, :opposite_route_id, :published_name, :number, :direction, :wayback, { stop_points_attributes: [ :id, :_destroy, :position, :stop_area_id, :for_boarding, :for_alighting ] } )
end
diff --git a/app/controllers/stop_areas_controller.rb b/app/controllers/stop_areas_controller.rb
index 9321ac9ae..dbbadb80c 100644
--- a/app/controllers/stop_areas_controller.rb
+++ b/app/controllers/stop_areas_controller.rb
@@ -137,6 +137,6 @@ class StopAreasController < ChouetteController
def stop_area_params
params.require(:stop_area).permit( :routing_stop_ids, :routing_line_ids, :children_ids, :stop_area_type, :parent_id, :objectid, :object_version, :creation_time, :creator_id, :name, :comment, :area_type, :registration_number, :nearest_topic_name, :fare_code, :longitude, :latitude, :long_lat_type, :country_code, :street_name, :zip_code, :city_name, :mobility_restricted_suitability, :stairs_availability, :lift_availability, :int_user_needs, :coordinates, :url, :time_zone )
- end
+ end
end
diff --git a/app/helpers/breadcrumb_helper.rb b/app/helpers/breadcrumb_helper.rb
index 52da8b887..69494321b 100644
--- a/app/helpers/breadcrumb_helper.rb
+++ b/app/helpers/breadcrumb_helper.rb
@@ -1,6 +1,7 @@
module BreadcrumbHelper
- def build_breadcrumb(action)
+ def build_breadcrumb(action)
+ action = action.to_sym
case resource_class.to_s
when "Chouette::Network"
network_breadcrumb action
@@ -30,6 +31,8 @@ module BreadcrumbHelper
connection_link_breadcrumb action
when "Chouette::TimeTable"
time_table_breadcrumb action
+ when "Chouette::RouteSection"
+ route_section_breadcrumb action
when "Chouette::Timeband"
timeband_breadcrumb action
when "StopAreaCopy"
@@ -106,6 +109,12 @@ module BreadcrumbHelper
add_breadcrumb breadcrumb_label(@time_table), referential_time_table_path(@referential, @time_table),:title => breadcrumb_tooltip(@time_table) if action == :edit
end
+ def route_section_breadcrumb(action)
+ referential_breadcrumb
+ add_breadcrumb Chouette::RouteSection.model_name.human.pluralize, referential_route_sections_path(@referential)
+ add_breadcrumb breadcrumb_label(resource), referential_route_section_path(@referential, resource),:title => breadcrumb_tooltip(resource) if action.in?([:show, :edit])
+ end
+
def timeband_breadcrumb(action)
referential_breadcrumb
add_breadcrumb Chouette::Timeband.model_name.human(:count => 2), referential_timebands_path(@referential) unless action == :index
diff --git a/app/helpers/route_section_selectors_helper.rb b/app/helpers/route_section_selectors_helper.rb
new file mode 100644
index 000000000..1be30066b
--- /dev/null
+++ b/app/helpers/route_section_selectors_helper.rb
@@ -0,0 +1,23 @@
+module RouteSectionSelectorsHelper
+
+ def link_to_edit_route_section(route_section)
+ classes = [ 'edit-route-section' ]
+ link ='#'
+
+ if route_section.present?
+ return_to = edit_referential_line_route_journey_pattern_route_sections_selector_path(@referential, @line, @route, @journey_pattern)
+ link = edit_referential_route_section_path(@referential, route_section, return_to: return_to)
+ else
+ classes << 'disabled'
+ end
+
+ link_to "Edit", link, class: classes, title: t('route_sections_selectors.edit.route_section.edit')
+ end
+
+ def link_to_create_route_section(departure, arrival)
+ return_to = edit_referential_line_route_journey_pattern_route_sections_selector_path(@referential, @line, @route, @journey_pattern)
+ link_to t('route_sections_selectors.edit.route_section.new'),
+ create_to_edit_referential_route_sections_path(@referential, route_section: {departure_id:departure.id, arrival_id: arrival.id}, return_to: return_to)
+ end
+
+end
diff --git a/app/maps/design/route_section_selector_style_map.rb b/app/maps/design/route_section_selector_style_map.rb
new file mode 100644
index 000000000..12f192ec8
--- /dev/null
+++ b/app/maps/design/route_section_selector_style_map.rb
@@ -0,0 +1,73 @@
+class Design::RouteSectionSelectorStyleMap < Design::GenericStyleMap
+ attr_accessor :style
+
+ def initialize(helpers, options = {})
+ @helpers = helpers
+ @style = options[:style].present? ? default_style.merge(options[:style]) : default_style
+ end
+
+ def select_style
+ {
+ fillColor: "blue",
+ graphicName: "square",
+ rotation: 90,
+ strokeColor: "#00dd00",
+ pointRadius: 15,
+ graphicZIndex: 100
+ }
+ end
+
+ def highlight_style
+ {
+ fillColor: "orange",
+ graphicName: "square",
+ rotation: 90,
+ strokeColor: "#dd0000",
+ pointRadius: 15,
+ graphicZIndex: 200
+ }
+ end
+
+ def default_style
+ {
+ label: "${label}",
+ fontColor: "black",
+ fontSize: "11px",
+ fontWeight: "bold",
+ labelAlign: "ct",
+ labelXOffset: 0,
+ labelYOffset: -15,
+ strokeColor: "#0000dd",
+ strokeOpacity: 1,
+ strokeWidth: 3,
+ strokeLineCap: "round",
+ strokeDashstyle: "solid",
+ externalGraphic: @helpers.assets_path_patch( "map/${positionType}.png"),
+ graphicWidth: 12,
+ graphicHeight: 12,
+ graphicOpacity: 1,
+ graphicXOffset: -6,
+ graphicYOffset: -6,
+ display: true,
+ fillColor: "red",
+ graphicName: "square",
+ rotation: 90,
+ graphicZIndex: 10
+ }
+ end
+
+ def context
+ {
+ label: :" function(feature) {if(feature.layer.map.getZoom() > 13) { return feature.attributes.name;} else {return '';}} ",
+ positionType: :" function(feature) { if (feature.attributes.iconCode != undefined) {return feature.attributes.iconCode;} else { return '';} } "
+ }
+ end
+
+ def style_map
+ OpenLayers::StyleMap.new(
+ default: OpenLayers::Style.new(style, { context: context}),
+ select: OpenLayers::Style.new(style.merge(select_style), { context: context }),
+ highlight: OpenLayers::Style.new(style.merge( highlight_style), { context: context }))
+ end
+
+end
diff --git a/app/maps/design/route_section_style_map.rb b/app/maps/design/route_section_style_map.rb
new file mode 100644
index 000000000..2c94bb3a0
--- /dev/null
+++ b/app/maps/design/route_section_style_map.rb
@@ -0,0 +1,66 @@
+class Design::RouteSectionStyleMap < Design::GenericStyleMap
+ attr_accessor :style
+
+ def initialize(helpers, options = {})
+ @helpers= helpers
+ @style = options[:style].present? ? default_style.merge(options[:style]) : default_style
+ end
+
+ def select_style
+ {
+ fillColor:"blue",
+ graphicName:"circle",
+ rotation:90,
+ :strokeColor => "red",
+ pointerEvents: "visiblePainted"
+ }
+ end
+
+ def highlight_style
+ {
+ fillColor:"lightblue",
+ graphicName:"circle",
+ rotation:90,
+ :strokeColor => "#dd0000"
+ }
+ end
+
+ def default_style
+
+ {
+ :fontColor => "black",
+ :fontSize => "11px",
+ :fontWeight => "bold",
+ :labelAlign => "cm",
+ :labelXOffset => 0,
+ :labelYOffset => -15,
+ :strokeColor => "green",
+ :strokeOpacity => 1,
+ :strokeWidth => 2,
+ :strokeLineCap => "round",
+ :strokeLineJoin => "round",
+ :strokeDashstyle => "solid",
+ :lineCap => "round",
+ :lineJoin => "round",
+ :dashstyle => "solid",
+ :graphicWidth => 12,
+ :graphicHeight => 12,
+ :graphicOpacity => 1,
+ :graphicXOffset => -6,
+ :graphicYOffset => -6,
+ :display => true,
+ fillOpacity: 0.5,
+ fillColor: "lightblue",
+ graphicName: "circle",
+ pointRadius: 6,
+ pointerEvents: "visiblePainted",
+ rotation: 90
+ }
+
+ end
+
+ def style_map
+ OpenLayers::StyleMap.new(:default => OpenLayers::Style.new(style), :select => OpenLayers::Style.new(style.merge( select_style)), :highlight => OpenLayers::Style.new(style.merge( highlight_style)))
+ end
+
+end
diff --git a/app/maps/route_section_map.rb b/app/maps/route_section_map.rb
new file mode 100644
index 000000000..cfa40d481
--- /dev/null
+++ b/app/maps/route_section_map.rb
@@ -0,0 +1,67 @@
+class RouteSectionMap < ApplicationMap
+
+ attr_reader :route_section
+
+ attr_accessor :editable
+ alias_method :editable?, :editable
+
+ def initialize(route_section, editable = false)
+ @route_section = route_section
+ @editable = editable
+ end
+
+ def customize_map(map, page)
+ # layers order seems to matter for ModifyFeature control
+ route_section.stop_areas.each do |stop_area|
+ layer = "stop_area_#{stop_area.id}".to_sym
+ page.assign layer.to_s, kml_layer(stop_area, :styleMap => Design::StopAreasStyleMap.new(helpers).style_map)
+ page << map.add_layer(layer)
+ page << map.add_control( hover_control_display_name(layer) )
+ end
+
+ geometry_options = {}.tap do |options|
+ options[:mode] = :editable if editable?
+ end
+ geometry_uneditable_kml_layer = kml_layer(route_section, :styleMap => Design::RouteSectionSelectorStyleMap.new(helpers).style_map)
+ page << map.add_layer(geometry_uneditable_kml_layer)
+
+ if route_section.input_geometry
+ geometry_editable_layer = kml_layer(route_section, geometry_options, {}) # , :styleMap => Design::LineStyleMap.new(style: nil).style_map)
+ else
+ points = route_section.stop_areas.map{|point| OpenLayers::Geometry::Point.new(point.longitude, point.latitude).transform("EPSG:4326", "EPSG:900913")}
+ geometry_editable_layer = OpenLayers::Layer::Vector.new("user_geometry", {:projection => projection("EPSG:4326"), :styleMap => Design::RouteSectionStyleMap.new(helpers).style_map})
+ #geometry_editable_layer = OpenLayers::Layer::Vector.new("user_geometry", {:projection => projection("EPSG:4326")})
+ geometry_editable_features = OpenLayers::Feature::Vector.new(OpenLayers::Geometry::LineString.new(points))
+ page.assign :geometry_editable_features, geometry_editable_features
+ end
+
+ if editable
+ page.assign :user_geometry, geometry_editable_layer
+
+ page << "user_geometry.addFeatures([geometry_editable_features])" if geometry_editable_features
+
+ page << map.add_layer(:user_geometry)
+
+ page.assign :modify_feature, OpenLayers::Control::ModifyFeature.new(:user_geometry, autoActivate: true)
+ page << map.add_control( :modify_feature )
+ else
+ page << map.add_layer(geometry_editable_layer)
+ end
+
+ page << map.zoom_to_extent(bounds.to_google.to_openlayers) if bounds
+ end
+
+ def bounds
+ @bounds ||=
+ if route_section.geometry.present?
+ route_section.geometry.bounds
+ elsif route_section.stop_areas.present?
+ GeoRuby::SimpleFeatures::Point.bounds route_section.stop_areas.collect(&:geometry)
+ end
+ end
+
+ def ready?
+ bounds.present?
+ end
+
+end
diff --git a/app/maps/route_section_selector_map.rb b/app/maps/route_section_selector_map.rb
new file mode 100644
index 000000000..425a6750a
--- /dev/null
+++ b/app/maps/route_section_selector_map.rb
@@ -0,0 +1,118 @@
+class RouteSectionSelectorMap < ApplicationMap
+
+ attr_reader :route_section_selector, :style
+
+ def initialize(route_section_selector, style = nil)
+ @route_section_selector = route_section_selector
+ @style = nil
+ end
+
+ def customize_map(map, page)
+ layer = kml_layer([route_section_selector.itinerary.referential, route_section_selector.itinerary.route.line, route_section_selector.itinerary.route, route_section_selector.itinerary],
+ { rendererOptions: { zIndexing: true }, styleMap: Design::JourneyPatternStyleMap.new(helpers).style_map })
+ page.assign 'journeyPatternLayer', layer
+
+ page << map.add_layer(:journeyPatternLayer)
+ page << map.add_control(hover_control_display_name(:journeyPatternLayer))
+
+ route_section_geometry = OpenLayers::Layer::Vector.new('Route Section Geometry',
+ { projection: projection('EPSG:900913'),
+ rendererOptions: { zIndexing: true },
+ styleMap: Design::RouteSectionSelectorStyleMap.new(helpers).style_map})
+
+ route_section_layer_points = []
+ route_section_selector.sections.reject{|s| s.candidates.length==0}.each do |section|
+ section.candidates.each do |candidate|
+ geometry = candidate.processed_geometry
+ route_section_layer_points << ["#{candidate.id}"] + clean_route_section_line(geometry)
+ end
+ end
+
+ page.assign :route_section_layer_points, route_section_layer_points
+ page << <<EOF
+ var route_section_layers;
+ route_section_layers = route_section_layer_points.map(function(elt, index) {
+ var route_section_id = elt[0];
+ elt.splice(0, 1);
+ var points = elt.map( function(e,i) {
+ return OpenLayers.Projection.transform(new OpenLayers.Geometry.Point(e[0], e[1]), "EPSG:4326", "EPSG:900913" );
+ })
+ return new OpenLayers.Feature.Vector(new OpenLayers.Geometry.LineString(points), {id: route_section_id, name: ""});
+ })
+EOF
+ page.assign :route_section_geometry, route_section_geometry
+ page << 'route_section_geometry.addFeatures(route_section_layers)'
+ page << map.add_layer(:route_section_geometry)
+
+ page << <<EOF
+ function selected(feature) {
+ RouteSectionMap.onSelectedFeature(feature);
+ }
+ function unselected(feature) {
+ RouteSectionMap.onUnselectedFeature(feature);
+ }
+
+ highlightControl = new OpenLayers.Control.SelectFeature([route_section_geometry],
+ {
+ clickout: true,
+ toggle: false,
+ multiple:false,
+ hover:true,
+ highlightOnly:true,
+ eventListeners:{
+ featurehighlighted: function (event) {
+ event.feature.layer.drawFeature(
+ event.feature,
+ 'highlight'
+ );
+ },
+ featureunhighlighted: function (event) {
+ event.feature.layer.drawFeature(
+ event.feature,
+ 'default'
+ );
+ }
+ }
+ }
+ );
+ selectControl = new OpenLayers.Control.SelectFeature([route_section_geometry],
+ {
+ onSelect:selected,
+ onUnselect:unselected
+ }
+ );
+ map.addControl(highlightControl);
+ map.addControl(selectControl);
+ highlightControl.activate();
+ selectControl.activate();
+EOF
+
+ #page.assign :select_feature, OpenLayers::Control::SelectFeature.new(:route_section_geometry, {onSelect: selected, onUnselect: unselected})
+ #page << map.add_control( :select_feature )
+
+
+ page << map.zoom_to_extent(bounds.to_google.to_openlayers) if bounds
+
+ end
+
+ def clean_route_section_line(line)
+ point_array = line.to_s.scan(/\d+[.]\d+\s\d+[.]\d+/)
+ proj = OpenLayers::Projection.new('proj')
+
+ point_array.map do |point|
+ point = point.scan(/\d+[.]\d+/)
+ lat = point[0].to_f
+ lng = point[1].to_f
+ [lat, lng]
+ end
+
+ end
+
+ def ready?
+ bounds.present?
+ end
+
+ def bounds
+ @bounds ||= GeoRuby::SimpleFeatures::Point.bounds(route_section_selector.itinerary.route.stop_areas.collect(&:geometry).compact)
+ end
+end
diff --git a/app/models/referential.rb b/app/models/referential.rb
index e32c956fb..d537246e5 100644
--- a/app/models/referential.rb
+++ b/app/models/referential.rb
@@ -91,6 +91,10 @@ class Referential < ActiveRecord::Base
Chouette::VehicleJourney.all
end
+ def route_sections
+ Chouette::RouteSection.all
+ end
+
after_initialize :define_default_attributes
def define_default_attributes
diff --git a/app/models/route_section_search.rb b/app/models/route_section_search.rb
new file mode 100644
index 000000000..a03eb894d
--- /dev/null
+++ b/app/models/route_section_search.rb
@@ -0,0 +1,34 @@
+class RouteSectionSearch
+ include ActiveModel::Conversion
+ extend ActiveModel::Naming
+
+ attr_accessor :departure_name, :arrival_name, :line_id
+ attr_accessor :scope
+
+ def scope
+ scope ||= Chouette::RouteSection
+ end
+
+ def initialize(attributes = {})
+ attributes.each { |k,v| send "#{k}=", v } if attributes
+ end
+
+ def collection()
+ Rails.logger.debug "Search RouteSections with #{inspect}"
+ collection = scope
+
+ [:departure, :arrival].each do |endpoint|
+ endpoint_name = send "#{endpoint}_name"
+ collection = collection.by_endpoint_name(endpoint, endpoint_name) if endpoint_name.present?
+ end
+
+ collection = collection.by_line_id(line_id) if line_id.present?
+
+ collection
+ end
+
+ def persisted?
+ false
+ end
+
+end
diff --git a/app/models/route_sections_selector.rb b/app/models/route_sections_selector.rb
new file mode 100644
index 000000000..ba8a2cc9a
--- /dev/null
+++ b/app/models/route_sections_selector.rb
@@ -0,0 +1,99 @@
+class RouteSectionsSelector
+ extend ActiveModel::Naming
+ include ActiveModel::Conversion
+
+ include ActiveModel::Validations
+
+ attr_reader :itinerary
+
+ def initialize(route_or_journey_pattern, attributes = {})
+ @itinerary = route_or_journey_pattern
+
+ self.attributes = attributes
+ end
+
+ def attributes=(attributes)
+ attributes.each { |k,v| send "#{k}=", v }
+ end
+
+ def update_attributes(attributes)
+ self.attributes = attributes
+ save
+ end
+
+ # def persisted?
+ # false
+ # end
+
+ delegate :stop_points, to: :itinerary
+
+ def route_sections
+ @route_sections ||= itinerary.route_sections.to_a
+ end
+
+ def sections
+ @sections ||= create_sections
+ end
+
+ def create_sections
+ [].tap do |sections|
+ stop_points.each_cons(2).each_with_index do |(departure, arrival), index|
+ sections << Section.new(departure.stop_area, arrival.stop_area, route_sections[index])
+ end
+ end
+ end
+
+ def sections_attributes=(attributes)
+ # Process the attributes hash
+ attributes.each do |index, section_attributes|
+ sections[index.to_i].attributes = section_attributes
+ end
+ end
+
+ def save
+ itinerary.update_attribute :route_section_ids, sections.map(&:route_section_id)
+ end
+
+ class Section
+ extend ActiveModel::Translation
+
+ attr_accessor :departure, :arrival, :route_section_id
+
+ def initialize(departure, arrival, route_section = nil)
+ @departure, @arrival = departure, arrival
+
+ self.route_section = route_section
+ end
+
+ def route_section=(route_section)
+ @route_section = route_section
+ @route_section_id = route_section.respond_to?(:id) ? route_section.id : nil
+ end
+
+ def route_section
+ @route_section ||= candidates.find_by id: route_section_id
+ end
+
+ def persisted?
+ false
+ end
+
+ def candidates
+ @candidates ||= Chouette::RouteSection.where(departure: departure, arrival: arrival)
+ end
+
+ def create_candidate
+ Chouette::RouteSection.create(departure: departure, arrival: arrival)
+ end
+
+ def attributes=(attributes)
+ attributes.each { |k,v| send "#{k}=", v }
+ end
+
+ def valid?
+ route_section.present?
+ end
+
+ end
+
+end
diff --git a/app/views/journey_patterns/show.html.erb b/app/views/journey_patterns/show.html.erb
index dc9e852fa..3a2b18ea1 100644
--- a/app/views/journey_patterns/show.html.erb
+++ b/app/views/journey_patterns/show.html.erb
@@ -34,9 +34,9 @@
<ul class="actions">
<li><%= link_to t('journey_patterns.actions.new'), new_referential_line_route_journey_pattern_path(@referential, @line, @route), :class => "add" %></li>
<li><%= link_to t('journey_patterns.actions.edit'), edit_referential_line_route_journey_pattern_path(@referential, @line, @route, @journey_pattern), :class => "edit" %></li>
- <li><%= link_to t('journey_patterns.actions.destroy'), referential_line_route_journey_pattern_path(@referential, @line, @route, @journey_pattern), :method => :delete, :data => {:confirm => t('journey_patterns.actions.destroy_confirm')}, :class => "remove" %></li>
+ <li><%= link_to t('journey_patterns.actions.destroy'), referential_line_route_journey_pattern_path(@referential, @line, @route, @journey_pattern), :method => :delete, :data => {:confirm => t('journey_patterns.actions.destroy_confirm')}, :class => "remove" %></li>
+ <li><%= link_to t('journey_patterns.actions.edit_route_sections'), edit_referential_line_route_journey_pattern_route_sections_selector_path(@referential, @line, @route, @journey_pattern), class: 'edit' %></li>
<li><%= link_to t('journey_patterns.journey_pattern.vehicle_journey_at_stops'), referential_line_route_vehicle_journeys_path(@referential, @line, @route, :q => {:journey_pattern_id_eq => @journey_pattern.id}), :class => "clock" %></li>
</ul>
<%= creation_tag(@journey_pattern) %>
<% end %>
-
diff --git a/app/views/referentials/_counts.html.erb b/app/views/referentials/_counts.html.erb
index 3ade4e945..20078429b 100644
--- a/app/views/referentials/_counts.html.erb
+++ b/app/views/referentials/_counts.html.erb
@@ -32,6 +32,10 @@
<%= Referential.human_attribute_name("connection_links") %>
</li>
<li class="list-group-item">
+ <span class="badge"><%= @referential.route_sections.size %></span>
+ <%= link_to Referential.human_attribute_name("route_sections"), referential_route_sections_path(@referential) %>
+ </li>
+ <li class="list-group-item">
<span class="badge"><%= @referential.stop_areas.size %></span>
<%= Referential.human_attribute_name("stop_areas") %>
</li>
diff --git a/app/views/route_sections/_form.html.erb b/app/views/route_sections/_form.html.erb
new file mode 100644
index 000000000..28a1dd47a
--- /dev/null
+++ b/app/views/route_sections/_form.html.erb
@@ -0,0 +1,24 @@
+<%= semantic_form_for [@referential, @route_section] do |form| %>
+ <%= form.inputs do %>
+ <% if @route_section.new_record? %>
+ <%= form.input :departure, as: :select, collection: @stop_areas, include_blank: false %>
+ <%= form.input :arrival, as: :select, collection: @stop_areas, include_blank: false %>
+ <% else %>
+ <li class="input optional">
+ <label class="label"><%= @route_section.human_attribute_name("departure") %></label>
+ <%= @route_section.departure.name %>
+ </li>
+ <li class="input optional">
+ <label class="label"><%= @route_section.human_attribute_name("arrival") %></label>
+ <%= @route_section.arrival.name %>
+ </li>
+ <%= form.input :editable_geometry, as: :hidden %>
+ <% end %>
+
+ <%= form.input :no_processing, label: t('.no_processing'), as: :select, collection: { t('.standard_processor') => false, t('.no_processor') => true }, include_blank: false %>
+ <% end %>
+ <%= form.actions do %>
+ <%= form.action :submit, :as => :button, label: t('.submit') %>
+ <%= form.action :cancel, :as => :link %>
+ <% end %>
+<% end %>
diff --git a/app/views/route_sections/edit.html.erb b/app/views/route_sections/edit.html.erb
new file mode 100644
index 000000000..80b7bde4a
--- /dev/null
+++ b/app/views/route_sections/edit.html.erb
@@ -0,0 +1,4 @@
+<%= title_tag t('route_sections.edit.title') %>
+
+<%= @map.to_html %>
+<%= render "form" %>
diff --git a/app/views/route_sections/index.html.erb b/app/views/route_sections/index.html.erb
new file mode 100644
index 000000000..5d7bef989
--- /dev/null
+++ b/app/views/route_sections/index.html.erb
@@ -0,0 +1,56 @@
+<%= title_tag t('.title') %>
+
+<%= form_for search, url: referential_route_sections_path(@referential), method: :get, class: "form-inline" do |form| %>
+ <div class="panel panel-default">
+ <div class="panel-heading">
+ <div class="col-md-6">
+ <%= form.text_field :departure_name, class: 'form-control', placeholder: Chouette::RouteSection.human_attribute_name(:departure) %>
+ </div>
+
+ <div class="input-group col-md-6">
+ <%= form.text_field :arrival_name, class: 'form-control', placeholder: Chouette::RouteSection.human_attribute_name(:arrival) %>
+ <div class="input-group-btn">
+ <button class="btn btn-default" type="submit"><i class="fa fa-search"></i></button>
+ </div>
+ </div>
+ </div>
+
+ <div class="panel-body">
+ <div class="col-md-4">
+ <%= form.select :line_id, @referential.lines.order(:name).pluck(:name, :id), { include_blank: t('.all_lines')}, class: 'form-control' %>
+ </div>
+ </div>
+ </div>
+<% end %>
+
+<table class="table table-hover table-striped">
+ <thead>
+ <tr>
+ <th><%= Chouette::RouteSection.human_attribute_name :departure %></th>
+ <th><%= Chouette::RouteSection.human_attribute_name :arrival %></th>
+ <th class="distance"><%= Chouette::RouteSection.human_attribute_name :distance %></th>
+ <th class="points"><%= Chouette::RouteSection.human_attribute_name :points %></th>
+ <th class="actions"></th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @route_sections.each do |route_section| %>
+ <tr>
+ <td><%= route_section.departure.name %> <%= link_to content_tag(:i, "", class: "fa fa-external-link"), referential_stop_area_path(@referential, route_section.departure) %></td>
+ <td><%= route_section.arrival.name %> <%= link_to content_tag(:i, "", class: "fa fa-external-link"), referential_stop_area_path(@referential, route_section.arrival) %></td>
+ <td class="distance"><%= route_section.distance.to_i if route_section.distance %></td>
+ <td class="points"><%= route_section.via_count if route_section.via_count > 0 %></td>
+ <td class="actions">
+ <%= link_to t('.actions.show'), referential_route_section_path(@referential, route_section), class: "view" %>
+ <%= link_to t('.actions.edit'), edit_referential_route_section_path(@referential, route_section), class: "edit" %>
+ <%= link_to t('.actions.destroy'), referential_route_section_path(@referential, route_section), method: :delete, data: { confirm: t('route_sections.actions.destroy_confirm') }, class: "remove" %>
+ </td>
+ </tr>
+ <% end %>
+ </tbody>
+
+</table>
+
+<div class="pagination">
+ <%= will_paginate @route_sections, :container => false, renderer: RemoteBootstrapPaginationLinkRenderer %>
+</div>
diff --git a/app/views/route_sections/new.html.erb b/app/views/route_sections/new.html.erb
new file mode 100644
index 000000000..1ff3c74d0
--- /dev/null
+++ b/app/views/route_sections/new.html.erb
@@ -0,0 +1,3 @@
+<%= title_tag t('route_sections.new.title') %>
+
+<%= render "form" %>
diff --git a/app/views/route_sections/show.html.erb b/app/views/route_sections/show.html.erb
new file mode 100644
index 000000000..61c7c8149
--- /dev/null
+++ b/app/views/route_sections/show.html.erb
@@ -0,0 +1,28 @@
+<%= title_tag t('.title') %>
+
+<div class="route_section">
+ <%= @map.to_html %>
+
+ <div class="summary">
+ <p>
+ <label><%= @route_section.human_attribute_name("departure") %>: </label>
+ <%= @route_section.departure.name %>
+ </p>
+ <p>
+ <label><%= @route_section.human_attribute_name("arrival") %>: </label>
+ <%= @route_section.arrival.name %>
+ </p>
+ <p>
+ <label><%= @route_section.human_attribute_name("distance") %>: </label>
+ <%= "#{@route_section.distance.round}m" if @route_section.distance %>
+ </p>
+ </div>
+</div>
+
+<% content_for :sidebar do %>
+<ul class="actions">
+ <li><%= link_to t('route_sections.actions.edit'), edit_referential_route_section_path(@referential, @route_section), :class => "edit" %></li>
+ <li><%= link_to t('route_sections.actions.destroy'), referential_route_section_path(@referential, @route_section), :method => :delete, :data => {:confirm => t('route_sections.actions.destroy_confirm')}, :class => "remove" %></li>
+</ul>
+ <%= creation_tag(@route_section) %>
+<% end %>
diff --git a/app/views/route_sections/show.kml.erb b/app/views/route_sections/show.kml.erb
new file mode 100644
index 000000000..0d41f0fdb
--- /dev/null
+++ b/app/views/route_sections/show.kml.erb
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<kml xmlns="http://www.opengis.net/kml/2.2">
+ <Document>
+ <Placemark id="route-section-<%= @route_section.id %>">
+ <%= @route_section.geometry(params[:mode]).kml_representation.html_safe %>
+ </Placemark>
+ </Document>
+</kml>
diff --git a/app/views/route_sections_selectors/_selection.js.erb b/app/views/route_sections_selectors/_selection.js.erb
new file mode 100644
index 000000000..70d03cf75
--- /dev/null
+++ b/app/views/route_sections_selectors/_selection.js.erb
@@ -0,0 +1,28 @@
+<div>
+ <span class="departure">
+ <label><%= @route_section.human_attribute_name("departure") %>:</label>
+ <%= link_to @route_section.departure.name, referential_stop_area_path(@referential, @route_section.departure) %>
+ </span>
+
+ <span class="arrival">
+ <label><%= @route_section.human_attribute_name("arrival") %>:</label>
+ <%= link_to @route_section.arrival.name, referential_stop_area_path(@referential, @route_section.arrival) %>
+ </span>
+
+ <span class="distance">
+ <label><%= @route_section.human_attribute_name("distance") %>:</label>
+ <%= "#{@route_section.distance.to_i} m" if @route_section.distance > 0 %>
+ </span>
+
+ <% if @route_section.via_count > 0 %>
+ <span class="via_count">
+ <label><%= @route_section.human_attribute_name("via_count") %>:</label>
+ <%= @route_section.via_count if @route_section.via_count > 0 %>
+ </span>
+ <% end %>
+
+ <span class="actions">
+ <%= link_to_edit_route_section @route_section %>
+ <%= link_to_create_route_section @route_section.departure, @route_section.arrival %>
+ </span>
+</div>
diff --git a/app/views/route_sections_selectors/edit.html.erb b/app/views/route_sections_selectors/edit.html.erb
new file mode 100644
index 000000000..0cd58d9c1
--- /dev/null
+++ b/app/views/route_sections_selectors/edit.html.erb
@@ -0,0 +1,48 @@
+<%= title_tag t('.title', journey_pattern: journey_name(@journey_pattern)) %>
+
+<div class = "large-map">
+ <%= @map.to_html %>
+</div>
+
+<%= semantic_form_for resource, url: referential_line_route_journey_pattern_route_sections_selector_path(@referential, @line, @route, @journey_pattern), method: :put do |form| %>
+
+<h3><%= t('.selection.title') %></h3>
+
+<div id="map-selection" style="display: none">
+ <div>
+ </div>
+</div>
+
+<div id="empty-map-selection">
+ <%= t('.no_selection') %>
+</div>
+
+<h3><%= t('.form.title') %></h3>
+
+<table class="table table-hover table-striped">
+ <tbody>
+ <%= form.fields_for :sections do |section_form| %>
+ <tr>
+ <td><%= link_to section_form.object.departure.name, referential_stop_area_path(@referential, section_form.object.departure) %></td>
+ <td class="route_section">
+ <% if section_form.object.candidates.present? %>
+ <%= section_form.input :route_section_id, as: :select, label: false, collection: section_form.object.candidates, include_blank: t('.no_selection') %>
+ <% else %>
+ <%= t('.no_candidate') %>
+ <% end %>
+ </td>
+ <td class="action">
+ <%= link_to_edit_route_section section_form.object.route_section %>
+ <%= link_to_create_route_section section_form.object.departure, section_form.object.arrival %>
+ </td>
+ </tr>
+ <% end %>
+ </tbody>
+</table>
+
+<%= form.actions do %>
+ <%= form.action :submit, as: :button, label: t('.submit') %>
+ <%= form.action :cancel, as: :link, url: referential_line_route_journey_pattern_path(@referential, @line, @route, @journey_pattern) %>
+<% end %>
+
+<% end %>
diff --git a/app/views/shared/_header.erb b/app/views/shared/_header.erb
index 1e8a63fba..9d53d807f 100644
--- a/app/views/shared/_header.erb
+++ b/app/views/shared/_header.erb
@@ -65,6 +65,10 @@
<span class="badge pull-right"><%= @referential.time_tables.size %></span><%= Referential.human_attribute_name("time_tables") %>
<% end %>
</li>
+ <li><%= link_to referential_route_sections_path(@referential) do %>
+ <span class="badge pull-right"><%= @referential.route_sections.size %></span><%= Referential.human_attribute_name("route_sections") %>
+ <% end %>
+ </li>
<li><%= link_to referential_timebands_path(@referential) do %>
<span class="badge pull-right"><%= @referential.timebands.size %></span><%= Referential.human_attribute_name("timebands") %>
<% end %>
diff --git a/config/database.yml b/config/database.yml
index 08d265760..81951d183 100644
--- a/config/database.yml
+++ b/config/database.yml
@@ -1,12 +1,12 @@
default: &default
- adapter: postgresql
+ adapter: postgis
encoding: unicode
- pool: 5
port: 5432
host: localhost
- schema_search_path: "public"
+ schema_search_path: 'public,shared_extensions'
username: chouette
password: chouette
+ postgis_schema: 'shared_extensions'
development:
<<: *default
diff --git a/config/database.yml.travis b/config/database.yml.travis
index c554142f5..dc35cfcb2 100644
--- a/config/database.yml.travis
+++ b/config/database.yml.travis
@@ -1,11 +1,11 @@
default: &default
- adapter: postgresql
+ adapter: postgis
encoding: unicode
- pool: 5
port: 5432
host: localhost
- schema_search_path: "public"
+ schema_search_path: 'public,shared_extensions'
username: postgres
+ postgis_schema: 'shared_extensions'
development:
<<: *default
diff --git a/config/initializers/apartment.rb b/config/initializers/apartment.rb
index b87a9fd67..31649f3e2 100644
--- a/config/initializers/apartment.rb
+++ b/config/initializers/apartment.rb
@@ -26,7 +26,7 @@ Apartment.configure do |config|
#config.use_sql = true
# configure persistent schemas (E.g. hstore )
- # config.persistent_schemas = %w{ hstore }
+ config.persistent_schemas = %w{ shared_extensions }
# add the Rails environment to database names?
# config.prepend_environment = true
diff --git a/config/initializers/route_section.rb b/config/initializers/route_section.rb
new file mode 100644
index 000000000..dadea36ee
--- /dev/null
+++ b/config/initializers/route_section.rb
@@ -0,0 +1,3 @@
+Rails.application.config.to_prepare do
+ Chouette::RouteSection.processor = OsrmRouteSectionProcessor.new
+end
diff --git a/config/locales/referentials.fr.yml b/config/locales/referentials.fr.yml
index bb328a430..7a1d26956 100644
--- a/config/locales/referentials.fr.yml
+++ b/config/locales/referentials.fr.yml
@@ -57,6 +57,7 @@ fr:
access_points: "points d'accès"
time_tables: "Calendriers"
connection_links: "Correspondances"
+ route_sections: "Sections de parcours"
quays: "quais"
boarding_positions: "points d'embarquement"
commercial_stops: "arrêts commerciaux"
diff --git a/config/locales/route_sections.en.yml b/config/locales/route_sections.en.yml
new file mode 100644
index 000000000..f799432f0
--- /dev/null
+++ b/config/locales/route_sections.en.yml
@@ -0,0 +1,47 @@
+en:
+ route_sections:
+ new:
+ title: "Add a new section"
+ show:
+ title: "Show this section"
+ edit:
+ title: "Edit this section"
+ form:
+ no_processing: "Geometry processing"
+ standard_processor: "Standard"
+ no_processor: "No treatment"
+ submit: "Submit"
+ index:
+ title: "Sections course"
+ all_lines: "All lines"
+ actions:
+ show: "Show"
+ edit: "Edit"
+ destroy: "Delete"
+ destroy_confirm: "Are you sure you want to delete this route section?"
+ actions:
+ edit: "Edit this section"
+ destroy: "Delete this section"
+ destroy_confirm: "Are you sure you want to delete this route section?"
+ route_sections_selectors:
+ edit:
+ title: "Changing the course of the mission %{journey_pattern}"
+ route_section:
+ edit: "Edit this section"
+ new: "Add alternative"
+ no_candidate: "No known path"
+ no_selection: "No selection"
+ selection:
+ title: "Selected section"
+ form:
+ title: "Full course"
+ submit: "Change the route"
+ activerecord:
+ models:
+ route_section: "Section course"
+ attributes:
+ route_section:
+ departure: "Departure point"
+ arrival: "Arrival point"
+ points: "Via"
+ distance: "Distance"
diff --git a/config/locales/route_sections.fr.yml b/config/locales/route_sections.fr.yml
new file mode 100644
index 000000000..65bead733
--- /dev/null
+++ b/config/locales/route_sections.fr.yml
@@ -0,0 +1,47 @@
+fr:
+ route_sections:
+ new:
+ title: "Ajouter une section"
+ show:
+ title: "Détails d'une Section de parcours"
+ edit:
+ title: "Modifier une Section de parcours"
+ form:
+ no_processing: "Traitement de la géométrie"
+ standard_processor: "Standard"
+ no_processor: "Pas de traitement"
+ submit: "Valider"
+ index:
+ title: "Sections de parcours"
+ all_lines: "Tous les lignes"
+ actions:
+ show: "Voir"
+ edit: "Modifier"
+ destroy: "Supprimer"
+ destroy_confirm: "Etes vous sûr de vouloir supprimer cette section de parcours ?"
+ actions:
+ edit: "Modifier cette section"
+ destroy: "Supprimer cette section"
+ destroy_confirm: "Etes vous sûr de vouloir supprimer cette section de parcours ?"
+ route_sections_selectors:
+ edit:
+ title: "Modification du parcours de la mission %{journey_pattern}"
+ route_section:
+ edit: "Modifier cette section"
+ new: "Ajouter une alternative"
+ no_candidate: "Aucun parcours connu"
+ no_selection: "Aucune selection"
+ selection:
+ title: "Section sélectionnée"
+ form:
+ title: "Parcours complet"
+ submit: "Modifier le parcours"
+ activerecord:
+ models:
+ route_section: "Section du parcours"
+ attributes:
+ route_section:
+ departure: "Arrêt de départ"
+ arrival: "Arrêt d'arrivée"
+ points: "Via"
+ distance: "Distance"
diff --git a/config/routes.rb b/config/routes.rb
index 8f41615d9..5f899292a 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -46,6 +46,7 @@ ChouetteIhm::Application.routes.draw do
resources :api_keys
resources :autocomplete_stop_areas
resources :autocomplete_time_tables
+ resources :autocomplete_route_sections
resources :autocomplete_timebands
resources :group_of_lines do
collection do
@@ -70,6 +71,9 @@ ChouetteIhm::Application.routes.draw do
member do
get 'new_vehicle_journey'
end
+ resource :route_sections_selector, path: 'sections' do
+ post 'selection'
+ end
end
resources :vehicle_journeys, :vehicle_journey_frequencies do
get 'select_journey_pattern', :on => :member
@@ -164,6 +168,11 @@ ChouetteIhm::Application.routes.draw do
end
resources :clean_ups
+ resources :route_sections do
+ collection do
+ get 'create_to_edit'
+ end
+ end
end
root :to => "referentials#index"
diff --git a/db/migrate/20150529134410_create_route_sections.ninoxe_engine.rb b/db/migrate/20150529134410_create_route_sections.ninoxe_engine.rb
new file mode 100644
index 000000000..8e288c8ab
--- /dev/null
+++ b/db/migrate/20150529134410_create_route_sections.ninoxe_engine.rb
@@ -0,0 +1,18 @@
+class CreateRouteSections < ActiveRecord::Migration
+ def change
+ create_table :route_sections do |t|
+ t.belongs_to :departure, limit: 8
+ t.belongs_to :arrival, limit: 8
+
+ t.line_string :input_geometry, srid: 4326
+ t.line_string :processed_geometry, srid: 4326
+
+ t.string :objectid, null: false
+ t.integer :object_version
+ t.datetime :creation_time
+ t.string :creator_id
+ end
+ add_foreign_key :route_sections, :stop_areas, column: :departure_id, dependent: :delete
+ add_foreign_key :route_sections, :stop_areas, column: :arrival_id, dependent: :delete
+ end
+end
diff --git a/db/migrate/20150922103725_add_distance_to_route_sections.ninoxe_engine.rb b/db/migrate/20150922103725_add_distance_to_route_sections.ninoxe_engine.rb
new file mode 100644
index 000000000..321248039
--- /dev/null
+++ b/db/migrate/20150922103725_add_distance_to_route_sections.ninoxe_engine.rb
@@ -0,0 +1,8 @@
+# This migration comes from ninoxe_engine (originally 20150921100000)
+class AddDistanceToRouteSections < ActiveRecord::Migration
+
+ def change
+ add_column "route_sections", "distance", "float"
+ end
+
+end
diff --git a/db/migrate/20151111210749_add_no_processing_to_route_sections.ninoxe_engine.rb b/db/migrate/20151111210749_add_no_processing_to_route_sections.ninoxe_engine.rb
new file mode 100644
index 000000000..d5665fb6a
--- /dev/null
+++ b/db/migrate/20151111210749_add_no_processing_to_route_sections.ninoxe_engine.rb
@@ -0,0 +1,8 @@
+# This migration comes from ninoxe_engine (originally 2015110517100832)
+class AddNoProcessingToRouteSections < ActiveRecord::Migration
+
+ def change
+ add_column :route_sections, :no_processing, :boolean
+ end
+
+end
diff --git a/db/migrate/20151203132113_create_journey_pattern_sections.ninoxe_engine.rb b/db/migrate/20151203132113_create_journey_pattern_sections.ninoxe_engine.rb
new file mode 100644
index 000000000..254e64567
--- /dev/null
+++ b/db/migrate/20151203132113_create_journey_pattern_sections.ninoxe_engine.rb
@@ -0,0 +1,16 @@
+# This migration comes from ninoxe_engine (originally 20151203131606)
+class CreateJourneyPatternSections < ActiveRecord::Migration
+ def change
+ create_table :journey_pattern_sections do |t|
+ t.references :journey_pattern, null: false, index: true, limit: 8
+ t.references :route_section, null: false, index: true, limit: 8
+ t.integer :rank, null: false
+ t.foreign_key :journey_patterns, dependent: :delete
+ t.foreign_key :route_sections, dependent: :delete
+
+ t.timestamps
+ end
+ add_index :journey_pattern_sections, [:journey_pattern_id, :route_section_id, :rank],
+ unique: true, name: 'index_jps_on_journey_pattern_id_and_route_section_id_and_rank'
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index d47122199..ac3a1dd2e 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,10 +11,11 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20151124145300) do
+ActiveRecord::Schema.define(version: 20151203132113) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
+ enable_extension "postgis"
create_table "access_links", force: true do |t|
t.integer "access_point_id", limit: 8
@@ -38,7 +39,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "link_orientation"
end
- add_index "access_links", ["objectid"], name: "access_links_objectid_key", unique: true, using: :btree
+ add_index "access_links", ["objectid"], :name => "access_links_objectid_key", :unique => true
create_table "access_points", force: true do |t|
t.string "objectid"
@@ -64,7 +65,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "city_name"
end
- add_index "access_points", ["objectid"], name: "access_points_objectid_key", unique: true, using: :btree
+ add_index "access_points", ["objectid"], :name => "access_points_objectid_key", :unique => true
create_table "api_keys", force: true do |t|
t.integer "referential_id"
@@ -92,8 +93,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "time_zone"
end
- add_index "companies", ["objectid"], name: "companies_objectid_key", unique: true, using: :btree
- add_index "companies", ["registration_number"], name: "companies_registration_number_key", using: :btree
+ add_index "companies", ["objectid"], :name => "companies_objectid_key", :unique => true
+ add_index "companies", ["registration_number"], :name => "companies_registration_number_key"
create_table "connection_links", force: true do |t|
t.integer "departure_id", limit: 8
@@ -116,7 +117,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.integer "int_user_needs"
end
- add_index "connection_links", ["objectid"], name: "connection_links_objectid_key", unique: true, using: :btree
+ add_index "connection_links", ["objectid"], :name => "connection_links_objectid_key", :unique => true
create_table "delayed_jobs", force: true do |t|
t.integer "priority", default: 0
@@ -132,7 +133,20 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.datetime "updated_at"
end
- add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority", using: :btree
+ add_index "delayed_jobs", ["priority", "run_at"], :name => "delayed_jobs_priority"
+
+ create_table "exports", force: true do |t|
+ t.integer "referential_id", limit: 8
+ t.string "status"
+ t.string "type"
+ t.string "options"
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ t.string "references_type"
+ t.string "reference_ids"
+ end
+
+ add_index "exports", ["referential_id"], :name => "index_exports_on_referential_id"
create_table "facilities", force: true do |t|
t.integer "stop_area_id", limit: 8
@@ -158,7 +172,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "contained_in"
end
- add_index "facilities", ["objectid"], name: "facilities_objectid_key", unique: true, using: :btree
+ add_index "facilities", ["objectid"], :name => "facilities_objectid_key", :unique => true
create_table "facilities_features", id: false, force: true do |t|
t.integer "facility_id", limit: 8
@@ -188,7 +202,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "registration_number"
end
- add_index "group_of_lines", ["objectid"], name: "group_of_lines_objectid_key", unique: true, using: :btree
+ add_index "group_of_lines", ["objectid"], :name => "group_of_lines_objectid_key", :unique => true
create_table "group_of_lines_lines", id: false, force: true do |t|
t.integer "group_of_line_id", limit: 8
@@ -206,8 +220,20 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.integer "timeband_id"
end
- add_index "journey_frequencies", ["timeband_id"], name: "index_journey_frequencies_on_timeband_id", using: :btree
- add_index "journey_frequencies", ["vehicle_journey_id"], name: "index_journey_frequencies_on_vehicle_journey_id", using: :btree
+ add_index "journey_frequencies", ["timeband_id"], :name => "index_journey_frequencies_on_timeband_id"
+ add_index "journey_frequencies", ["vehicle_journey_id"], :name => "index_journey_frequencies_on_vehicle_journey_id"
+
+ create_table "journey_pattern_sections", force: true do |t|
+ t.integer "journey_pattern_id", limit: 8, null: false
+ t.integer "route_section_id", limit: 8, null: false
+ t.integer "rank", null: false
+ t.datetime "created_at"
+ t.datetime "updated_at"
+ end
+
+ add_index "journey_pattern_sections", ["journey_pattern_id", "route_section_id", "rank"], :name => "index_jps_on_journey_pattern_id_and_route_section_id_and_rank", :unique => true
+ add_index "journey_pattern_sections", ["journey_pattern_id"], :name => "index_journey_pattern_sections_on_journey_pattern_id"
+ add_index "journey_pattern_sections", ["route_section_id"], :name => "index_journey_pattern_sections_on_route_section_id"
create_table "journey_patterns", force: true do |t|
t.integer "route_id", limit: 8
@@ -223,14 +249,14 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.integer "arrival_stop_point_id", limit: 8
end
- add_index "journey_patterns", ["objectid"], name: "journey_patterns_objectid_key", unique: true, using: :btree
+ add_index "journey_patterns", ["objectid"], :name => "journey_patterns_objectid_key", :unique => true
create_table "journey_patterns_stop_points", id: false, force: true do |t|
t.integer "journey_pattern_id", limit: 8
t.integer "stop_point_id", limit: 8
end
- add_index "journey_patterns_stop_points", ["journey_pattern_id"], name: "index_journey_pattern_id_on_journey_patterns_stop_points", using: :btree
+ add_index "journey_patterns_stop_points", ["journey_pattern_id"], :name => "index_journey_pattern_id_on_journey_patterns_stop_points"
create_table "lines", force: true do |t|
t.integer "network_id", limit: 8
@@ -254,8 +280,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "stable_id"
end
- add_index "lines", ["objectid"], name: "lines_objectid_key", unique: true, using: :btree
- add_index "lines", ["registration_number"], name: "lines_registration_number_key", using: :btree
+ add_index "lines", ["objectid"], :name => "lines_objectid_key", :unique => true
+ add_index "lines", ["registration_number"], :name => "lines_registration_number_key"
create_table "networks", force: true do |t|
t.string "objectid", null: false
@@ -272,8 +298,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "comment"
end
- add_index "networks", ["objectid"], name: "networks_objectid_key", unique: true, using: :btree
- add_index "networks", ["registration_number"], name: "networks_registration_number_key", using: :btree
+ add_index "networks", ["objectid"], :name => "networks_objectid_key", :unique => true
+ add_index "networks", ["registration_number"], :name => "networks_registration_number_key"
create_table "organisations", force: true do |t|
t.string "name"
@@ -295,7 +321,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.decimal "link_distance", precision: 19, scale: 2
end
- add_index "pt_links", ["objectid"], name: "pt_links_objectid_key", unique: true, using: :btree
+ add_index "pt_links", ["objectid"], :name => "pt_links_objectid_key", :unique => true
create_table "referentials", force: true do |t|
t.string "name"
@@ -313,6 +339,19 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "data_format"
end
+ create_table "route_sections", force: true do |t|
+ t.integer "departure_id", limit: 8
+ t.integer "arrival_id", limit: 8
+ t.string "objectid", null: false
+ t.integer "object_version"
+ t.datetime "creation_time"
+ t.string "creator_id"
+ t.spatial "input_geometry", limit: {:srid=>4326, :type=>"line_string"}
+ t.spatial "processed_geometry", limit: {:srid=>4326, :type=>"line_string"}
+ t.float "distance"
+ t.boolean "no_processing"
+ end
+
create_table "routes", force: true do |t|
t.integer "line_id", limit: 8
t.string "objectid", null: false
@@ -328,7 +367,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "wayback"
end
- add_index "routes", ["objectid"], name: "routes_objectid_key", unique: true, using: :btree
+ add_index "routes", ["objectid"], :name => "routes_objectid_key", :unique => true
create_table "routing_constraints_lines", id: false, force: true do |t|
t.integer "stop_area_id", limit: 8
@@ -370,8 +409,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "time_zone"
end
- add_index "stop_areas", ["objectid"], name: "stop_areas_objectid_key", unique: true, using: :btree
- add_index "stop_areas", ["parent_id"], name: "index_stop_areas_on_parent_id", using: :btree
+ add_index "stop_areas", ["objectid"], :name => "stop_areas_objectid_key", :unique => true
+ add_index "stop_areas", ["parent_id"], :name => "index_stop_areas_on_parent_id"
create_table "stop_areas_stop_areas", id: false, force: true do |t|
t.integer "child_id", limit: 8
@@ -390,7 +429,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "for_alighting"
end
- add_index "stop_points", ["objectid"], name: "stop_points_objectid_key", unique: true, using: :btree
+ add_index "stop_points", ["objectid"], :name => "stop_points_objectid_key", :unique => true
create_table "taggings", force: true do |t|
t.integer "tag_id"
@@ -402,15 +441,15 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.datetime "created_at"
end
- add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], name: "taggings_idx", unique: true, using: :btree
- add_index "taggings", ["taggable_id", "taggable_type", "context"], name: "index_taggings_on_taggable_id_and_taggable_type_and_context", using: :btree
+ add_index "taggings", ["tag_id", "taggable_id", "taggable_type", "context", "tagger_id", "tagger_type"], :name => "taggings_idx", :unique => true
+ add_index "taggings", ["taggable_id", "taggable_type", "context"], :name => "index_taggings_on_taggable_id_and_taggable_type_and_context"
create_table "tags", force: true do |t|
t.string "name"
t.integer "taggings_count", default: 0
end
- add_index "tags", ["name"], name: "index_tags_on_name", unique: true, using: :btree
+ add_index "tags", ["name"], :name => "index_tags_on_name", :unique => true
create_table "time_table_dates", force: true do |t|
t.integer "time_table_id", limit: 8, null: false
@@ -419,7 +458,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.boolean "in_out"
end
- add_index "time_table_dates", ["time_table_id"], name: "index_time_table_dates_on_time_table_id", using: :btree
+ add_index "time_table_dates", ["time_table_id"], :name => "index_time_table_dates_on_time_table_id"
create_table "time_table_periods", force: true do |t|
t.integer "time_table_id", limit: 8, null: false
@@ -428,7 +467,7 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.integer "position", null: false
end
- add_index "time_table_periods", ["time_table_id"], name: "index_time_table_periods_on_time_table_id", using: :btree
+ add_index "time_table_periods", ["time_table_id"], :name => "index_time_table_periods_on_time_table_id"
create_table "time_tables", force: true do |t|
t.string "objectid", null: false
@@ -442,15 +481,15 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.date "end_date"
end
- add_index "time_tables", ["objectid"], name: "time_tables_objectid_key", unique: true, using: :btree
+ add_index "time_tables", ["objectid"], :name => "time_tables_objectid_key", :unique => true
create_table "time_tables_vehicle_journeys", id: false, force: true do |t|
t.integer "time_table_id", limit: 8
t.integer "vehicle_journey_id", limit: 8
end
- add_index "time_tables_vehicle_journeys", ["time_table_id"], name: "index_time_tables_vehicle_journeys_on_time_table_id", using: :btree
- add_index "time_tables_vehicle_journeys", ["vehicle_journey_id"], name: "index_time_tables_vehicle_journeys_on_vehicle_journey_id", using: :btree
+ add_index "time_tables_vehicle_journeys", ["time_table_id"], :name => "index_time_tables_vehicle_journeys_on_time_table_id"
+ add_index "time_tables_vehicle_journeys", ["vehicle_journey_id"], :name => "index_time_tables_vehicle_journeys_on_vehicle_journey_id"
create_table "timebands", force: true do |t|
t.string "objectid", null: false
@@ -496,9 +535,9 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.datetime "invitation_created_at"
end
- add_index "users", ["email"], name: "index_users_on_email", unique: true, using: :btree
- add_index "users", ["invitation_token"], name: "index_users_on_invitation_token", unique: true, using: :btree
- add_index "users", ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, using: :btree
+ add_index "users", ["email"], :name => "index_users_on_email", :unique => true
+ add_index "users", ["invitation_token"], :name => "index_users_on_invitation_token", :unique => true
+ add_index "users", ["reset_password_token"], :name => "index_users_on_reset_password_token", :unique => true
create_table "vehicle_journey_at_stops", force: true do |t|
t.integer "vehicle_journey_id", limit: 8
@@ -511,8 +550,8 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.string "for_alighting"
end
- add_index "vehicle_journey_at_stops", ["stop_point_id"], name: "index_vehicle_journey_at_stops_on_stop_pointid", using: :btree
- add_index "vehicle_journey_at_stops", ["vehicle_journey_id"], name: "index_vehicle_journey_at_stops_on_vehicle_journey_id", using: :btree
+ add_index "vehicle_journey_at_stops", ["stop_point_id"], :name => "index_vehicle_journey_at_stops_on_stop_pointid"
+ add_index "vehicle_journey_at_stops", ["vehicle_journey_id"], :name => "index_vehicle_journey_at_stops_on_vehicle_journey_id"
create_table "vehicle_journeys", force: true do |t|
t.integer "route_id", limit: 8
@@ -535,9 +574,10 @@ ActiveRecord::Schema.define(version: 20151124145300) do
t.integer "journey_category", default: 0, null: false
end
- add_index "vehicle_journeys", ["objectid"], name: "vehicle_journeys_objectid_key", unique: true, using: :btree
- add_index "vehicle_journeys", ["route_id"], name: "index_vehicle_journeys_on_route_id", using: :btree
+ add_index "vehicle_journeys", ["objectid"], :name => "vehicle_journeys_objectid_key", :unique => true
+ add_index "vehicle_journeys", ["route_id"], :name => "index_vehicle_journeys_on_route_id"
+ Foreigner.load
add_foreign_key "access_links", "access_points", name: "aclk_acpt_fkey", dependent: :delete
add_foreign_key "access_links", "stop_areas", name: "aclk_area_fkey", dependent: :delete
@@ -549,6 +589,9 @@ ActiveRecord::Schema.define(version: 20151124145300) do
add_foreign_key "group_of_lines_lines", "group_of_lines", name: "groupofline_group_fkey", dependent: :delete
add_foreign_key "group_of_lines_lines", "lines", name: "groupofline_line_fkey", dependent: :delete
+ add_foreign_key "journey_pattern_sections", "journey_patterns", name: "journey_pattern_sections_journey_pattern_id_fk", dependent: :delete
+ add_foreign_key "journey_pattern_sections", "route_sections", name: "journey_pattern_sections_route_section_id_fk", dependent: :delete
+
add_foreign_key "journey_patterns", "routes", name: "jp_route_fkey", dependent: :delete
add_foreign_key "journey_patterns", "stop_points", name: "arrival_point_fkey", column: "arrival_stop_point_id", dependent: :nullify
add_foreign_key "journey_patterns", "stop_points", name: "departure_point_fkey", column: "departure_stop_point_id", dependent: :nullify
@@ -559,6 +602,9 @@ ActiveRecord::Schema.define(version: 20151124145300) do
add_foreign_key "lines", "companies", name: "line_company_fkey", dependent: :nullify
add_foreign_key "lines", "networks", name: "line_ptnetwork_fkey", dependent: :nullify
+ add_foreign_key "route_sections", "stop_areas", name: "route_sections_arrival_id_fk", column: "arrival_id", dependent: :delete
+ add_foreign_key "route_sections", "stop_areas", name: "route_sections_departure_id_fk", column: "departure_id", dependent: :delete
+
add_foreign_key "routes", "lines", name: "route_line_fkey", dependent: :delete
add_foreign_key "routes", "routes", name: "route_opposite_route_fkey", column: "opposite_route_id", dependent: :nullify
diff --git a/lib/osrm_route_section_processor.rb b/lib/osrm_route_section_processor.rb
new file mode 100644
index 000000000..102c53966
--- /dev/null
+++ b/lib/osrm_route_section_processor.rb
@@ -0,0 +1,36 @@
+require 'open-uri'
+
+class OsrmRouteSectionProcessor
+
+ def call(route_section)
+ points_string = (route_section.input_geometry || route_section.default_geometry).points.map do |point|
+ "loc=#{point.y.to_f},#{point.x.to_f}"
+ end.join
+
+ Rails.logger.info "Invoke router.project-osrm.org for RouteSection StopArea:#{route_section.departure.id} -> StopArea:#{route_section.arrival.id}"
+
+ response = open "http://router.project-osrm.org/viaroute?#{points_string}instructions=false"
+ geometry = JSON.parse(response.read.to_s)['route_geometry']
+
+ if geometry
+ decoded_geometry = Polylines::Decoder.decode_polyline(geometry, 1e6).map do |point|
+ GeoRuby::SimpleFeatures::Point.from_x_y(point[1], point[0], 4326)
+ end
+
+ GeoRuby::SimpleFeatures::LineString.from_points(decoded_geometry).try(:to_rgeo) if decoded_geometry.many?
+ end
+ rescue OpenURI::HTTPError => e
+ Rails.logger.error "router.project-osrm.org failed: #{e}"
+ nil
+ end
+
+ def self.create_all
+ Chouette::JourneyPattern.find_each do |journey_pattern|
+ selector = RouteSectionsSelector.new(journey_pattern)
+ selector.sections.each do |section|
+ section.create_candidate unless section.candidates.present?
+ end
+ end
+ end
+
+end
diff --git a/lib/tasks/route_sections.rake b/lib/tasks/route_sections.rake
new file mode 100644
index 000000000..d48ddbba4
--- /dev/null
+++ b/lib/tasks/route_sections.rake
@@ -0,0 +1,17 @@
+namespace :route_sections do
+
+ def find_referential(id_or_slug)
+ if id_or_slug.to_s =~ /\A\d+\Z/
+ Referential.find id_or_slug.to_i
+ else
+ Referential.find_by slug: id_or_slug
+ end
+ end
+
+ desc "Generate all RouteSections for a given Referential"
+ task :create_all, [:referential] => [:environment] do |t, args|
+ find_referential(args[:referential]).switch
+ OsrmRouteSectionProcessor.create_all
+ end
+
+end
diff --git a/spec/controllers/routes_controller_spec.rb b/spec/controllers/routes_controller_spec.rb
index a813056c3..de6d16c8b 100644
--- a/spec/controllers/routes_controller_spec.rb
+++ b/spec/controllers/routes_controller_spec.rb
@@ -37,7 +37,7 @@ describe RoutesController, :type => :controller do
it_behaves_like "line and referential linked"
it_behaves_like "redirected to referential_line_path(referential,line)"
end
-
+
describe "POST /create" do
before(:each) do
post :create, :line_id => route.line_id,
@@ -48,7 +48,7 @@ describe RoutesController, :type => :controller do
it_behaves_like "line and referential linked"
it_behaves_like "redirected to referential_line_path(referential,line)"
end
-
+
describe "PUT /update" do
before(:each) do
put :update, :id => route.id, :line_id => route.line_id,
@@ -59,10 +59,10 @@ describe RoutesController, :type => :controller do
it_behaves_like "route, line and referential linked"
it_behaves_like "redirected to referential_line_path(referential,line)"
end
-
+
describe "GET /show" do
before(:each) do
- get :show, :id => route.id,
+ get :show, :id => route.id,
:line_id => route.line_id,
:referential_id => referential.id
end
@@ -78,6 +78,6 @@ describe RoutesController, :type => :controller do
# expect(assigns[:stop_points]).to eq(route.stop_points.paginate(:page => nil))
#end
end
-
+
end
diff --git a/spec/models/route_sections_selector_spec.rb b/spec/models/route_sections_selector_spec.rb
new file mode 100644
index 000000000..a00945d42
--- /dev/null
+++ b/spec/models/route_sections_selector_spec.rb
@@ -0,0 +1,43 @@
+require 'spec_helper'
+
+describe RouteSectionsSelector, :type => :model do
+
+ let(:stop_points) { create_list :stop_point, 5 }
+ let(:itinerary) { double stop_points: stop_points, route_sections: [] }
+
+ subject { RouteSectionsSelector.new itinerary }
+
+ describe "#sections" do
+
+ it "should create a Section between each StopPoint" do
+ expect(subject.sections.size).to eq(stop_points.size - 1)
+ end
+
+ end
+
+end
+
+describe RouteSectionsSelector::Section, :type => :model do
+
+ let(:departure) { create :stop_point }
+ let(:arrival) { create :stop_point }
+
+ subject { RouteSectionsSelector::Section.new departure, arrival }
+
+ let(:route_sections) do
+ create_list :route_section, 5,
+ departure: departure.stop_area,
+ arrival: arrival.stop_area
+ end
+
+ describe "#candidates" do
+ it "should return an empty array when no RouteSection exists" do
+ expect(subject.candidates).to be_empty
+ end
+
+ it "should return the RouteSections with the same departure/arrival StopAreas" do
+ expect(subject.candidates).to match_array(route_sections)
+ end
+ end
+
+end
diff --git a/spec/support/fake_iev_server.rb b/spec/support/fake_iev_server.rb
index c311fdc91..8cd002fae 100644
--- a/spec/support/fake_iev_server.rb
+++ b/spec/support/fake_iev_server.rb
@@ -10,17 +10,11 @@ end
# Importer
############
# get list
-fixture_request :get,
- "http://#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs?action=importer",
- 'scheduled_jobs.json'
+fixture_request :get, "#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs?action=importer", 'scheduled_jobs.json'
# get element
-fixture_request :get,
- "http://#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs/1?action=importer",
- 'scheduled_job.json'
+fixture_request :get, "#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs/1?action=importer", 'scheduled_job.json'
# post element
-fixture_request :post,
- "http://#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs/",
- 'scheduled_job.json'
+fixture_request :post, "#{Rails.application.secrets.api_endpoint}referentials/test/scheduled_jobs/", 'scheduled_job.json'
# Optionnels
# delete element
@@ -36,6 +30,3 @@ fixture_request :post,
############
# Validation
############
-
-
-
diff --git a/spec/support/referential.rb b/spec/support/referential.rb
index d77a05f41..8c468eb53 100644
--- a/spec/support/referential.rb
+++ b/spec/support/referential.rb
@@ -12,7 +12,7 @@ module ReferentialHelper
end
module ClassMethods
-
+
def assign_referential
before(:each) do
assign :referential, referential
@@ -34,7 +34,7 @@ RSpec.configure do |config|
config.before(:suite) do
# Clean all tables to start
- DatabaseCleaner.clean_with :truncation
+ DatabaseCleaner.clean_with :truncation, except: %w[spatial_ref_sys]
# Truncating doesn't drop schemas, ensure we're clean here, first *may not* exist
Apartment::Tenant.drop('first') rescue nil
# Create the default tenant for our tests
@@ -49,7 +49,7 @@ RSpec.configure do |config|
end
config.before(:each, :js => true) do
- DatabaseCleaner.strategy = :truncation
+ DatabaseCleaner.strategy = :truncation, { except: %w[spatial_ref_sys] }
end
config.before(:each) do
@@ -61,6 +61,6 @@ RSpec.configure do |config|
Apartment::Tenant.reset
# Rollback transaction
DatabaseCleaner.clean
- end
+ end
end