diff options
| author | Bruno Perles | 2015-12-16 10:02:29 +0100 | 
|---|---|---|
| committer | Bruno Perles | 2015-12-16 10:02:29 +0100 | 
| commit | 013f4fa8fe9bb08f3ed1d15f905ca2a8437d6aa7 (patch) | |
| tree | 426b9c17167c10547da2222517cbd4433ae554fe | |
| parent | 2590606c5912a85b8cb1aaa40c57dab67d75e7f7 (diff) | |
| download | chouette-core-013f4fa8fe9bb08f3ed1d15f905ca2a8437d6aa7.tar.bz2 | |
Add route_sections for traces
50 files changed, 1339 insertions, 93 deletions
| @@ -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.pngBinary files differ new file mode 100644 index 000000000..aaefed65c --- /dev/null +++ b/app/assets/images/icons/edit-disabled.png 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 | 
