diff options
| -rw-r--r-- | lib/tom_tom.rb | 4 | ||||
| -rw-r--r-- | lib/tom_tom/matrix.rb | 89 | ||||
| -rw-r--r-- | spec/fixtures/tom_tom_matrix.json | 123 | ||||
| -rw-r--r-- | spec/lib/tom_tom/matrix_spec.rb | 127 | 
4 files changed, 343 insertions, 0 deletions
| diff --git a/lib/tom_tom.rb b/lib/tom_tom.rb index a1a2bda43..fcebcc7ac 100644 --- a/lib/tom_tom.rb +++ b/lib/tom_tom.rb @@ -19,4 +19,8 @@ module TomTom    def self.batch(way_costs)      TomTom::Batch.new(@connection).batch(way_costs)    end + +  def self.matrix(way_costs) +    TomTom::Matrix.new(@connection).matrix(way_costs) +  end  end diff --git a/lib/tom_tom/matrix.rb b/lib/tom_tom/matrix.rb new file mode 100644 index 000000000..985055dae --- /dev/null +++ b/lib/tom_tom/matrix.rb @@ -0,0 +1,89 @@ +module TomTom +  class Matrix +    def initialize(connection) +      @connection = connection +    end + +    def matrix(way_costs) +      points = points_from_way_costs(way_costs) +      points = points_as_params(points) + +      response = @connection.post do |req| +        req.url '/routing/1/matrix/json' +        req.headers['Content-Type'] = 'application/json' + +        req.params[:routeType] = 'shortest' +        req.params[:travelMode] = 'bus' + +        req.body = { +          origins: points, +          destinations: points +        }.to_json +      end + +      extract_costs_to_way_costs!( +        way_costs, +        points, +        JSON.parse(response.body) +      ) +    end + +    def points_from_way_costs(way_costs) +      points = Set.new + +      way_costs.each do |way_cost| +        points.add(way_cost.departure) +        points.add(way_cost.arrival) +      end + +      points +    end + +    def points_as_params(points) +      points.map do |latlng| +        { +          point: { +            latitude: latlng.lat, +            longitude: latlng.lng +          } +        } +      end +    end + +    # TODO: We actually need to create new WayCost objects to hold the new dot connections given to us by the matrix API. +    def extract_costs_to_way_costs!(way_costs, points, matrix_json) +      way_costs = [] + +      # `row` and `column` order is the same as `points` +      matrix_json['matrix'].each_with_index do |row, row_i| +        row.each_with_index do |column, column_i| +          next if column['statusCode'] != 200 + +          distance = column['response']['routeSummary']['lengthInMeters'] + +          # Ignore costs between a point and itself (e.g. from A to A) +          next if distance == 0 + +          departure = points[row_i] +          arrival = points[column_i] + +          way_costs << WayCost.new( +            departure: Geokit::LatLng.new( +              departure[:point][:latitude], +              departure[:point][:longitude] +            ), +            arrival: Geokit::LatLng.new( +              arrival[:point][:latitude], +              arrival[:point][:longitude] +            ), +            distance: distance, +            time: column['response']['routeSummary']['travelTimeInSeconds'] +            # id: 'TODO: figure out how to add combined stop IDs' +          ) +        end +      end + +      way_costs +    end +  end +end diff --git a/spec/fixtures/tom_tom_matrix.json b/spec/fixtures/tom_tom_matrix.json new file mode 100644 index 000000000..30048576c --- /dev/null +++ b/spec/fixtures/tom_tom_matrix.json @@ -0,0 +1,123 @@ +{ +  "formatVersion": "0.0.1", +  "matrix": [ +    [ +      { +        "statusCode": 200, +        "response": { +          "routeSummary": { +            "lengthInMeters": 0, +            "travelTimeInSeconds": 0, +            "trafficDelayInSeconds": 0, +            "departureTime": "2018-03-23T11:20:17+01:00", +            "arrivalTime": "2018-03-23T11:20:17+01:00" +          } +        } +      }, +      { +        "statusCode": 200, +        "response": { +          "routeSummary": { +            "lengthInMeters": 117947, +            "travelTimeInSeconds": 8356, +            "trafficDelayInSeconds": 0, +            "departureTime": "2018-03-23T11:20:17+01:00", +            "arrivalTime": "2018-03-23T13:39:32+01:00" +          } +        } +      }, +      { +        "statusCode": 200, +        "response": { +          "routeSummary": { +            "lengthInMeters": 999088, +            "travelTimeInSeconds": 62653, +            "trafficDelayInSeconds": 298, +            "departureTime": "2018-03-23T11:20:17+01:00", +            "arrivalTime": "2018-03-24T04:44:30+01:00" +          } +        } +      } +    ], +    [ +      { +        "statusCode": 200, +        "response": { +          "routeSummary": { +            "lengthInMeters": 117231, +            "travelTimeInSeconds": 9729, +            "trafficDelayInSeconds": 0, +            "departureTime": "2018-03-23T11:20:17+01:00", +            "arrivalTime": "2018-03-23T14:02:25+01:00" +          } +        } +      }, +      { +        "statusCode": 200, +        "response": { +          "routeSummary": { +            "lengthInMeters": 0, +            "travelTimeInSeconds": 0, +            "trafficDelayInSeconds": 0, +            "departureTime": "2018-03-23T11:20:17+01:00", +            "arrivalTime": "2018-03-23T11:20:17+01:00" +          } +        } +      }, +      { +        "statusCode": 200, +        "response": { +          "routeSummary": { +            "lengthInMeters": 1114635, +            "travelTimeInSeconds": 72079, +            "trafficDelayInSeconds": 298, +            "departureTime": "2018-03-23T11:20:18+01:00", +            "arrivalTime": "2018-03-24T07:21:36+01:00" +          } +        } +      } +    ], +    [ +      { +        "statusCode": 200, +        "response": { +          "routeSummary": { +            "lengthInMeters": 997232, +            "travelTimeInSeconds": 63245, +            "trafficDelayInSeconds": 179, +            "departureTime": "2018-03-23T11:20:18+01:00", +            "arrivalTime": "2018-03-24T04:54:23+01:00" +          } +        } +      }, +      { +        "statusCode": 200, +        "response": { +          "routeSummary": { +            "lengthInMeters": 1113108, +            "travelTimeInSeconds": 68485, +            "trafficDelayInSeconds": 52, +            "departureTime": "2018-03-23T11:20:18+01:00", +            "arrivalTime": "2018-03-24T06:21:43+01:00" +          } +        } +      }, +      { +        "statusCode": 200, +        "response": { +          "routeSummary": { +            "lengthInMeters": 344, +            "travelTimeInSeconds": 109, +            "trafficDelayInSeconds": 0, +            "departureTime": "2018-03-23T11:20:18+01:00", +            "arrivalTime": "2018-03-23T11:22:07+01:00" +          } +        } +      } +    ] +  ], +  "summary": { +    "successfulRoutes": 9, +    "totalRoutes": 9 +  } +} diff --git a/spec/lib/tom_tom/matrix_spec.rb b/spec/lib/tom_tom/matrix_spec.rb new file mode 100644 index 000000000..257bbd5fd --- /dev/null +++ b/spec/lib/tom_tom/matrix_spec.rb @@ -0,0 +1,127 @@ +RSpec.describe TomTom::Matrix do +  let(:matrix) { TomTom::Matrix.new(nil) } + +  describe "#points_from_way_costs" do +    it "extracts a set of lat/lng coordinates from a list of WayCosts" do +      way_costs = [ +        WayCost.new( +          departure: Geokit::LatLng.new(48.85086, 2.36143), +          arrival: Geokit::LatLng.new(47.91231, 1.87606) +        ), +        WayCost.new( +          departure: Geokit::LatLng.new(47.91231, 1.87606), +          arrival: Geokit::LatLng.new(52.50867, 13.42879) +        ) +      ] + +      expect( +        matrix.points_from_way_costs(way_costs) +      ).to eq(Set.new([ +        Geokit::LatLng.new(48.85086, 2.36143), +        Geokit::LatLng.new(47.91231, 1.87606), +        Geokit::LatLng.new(52.50867, 13.42879) +      ])) +    end +  end + +  describe "#points_as_params" do +    it "transforms a set of LatLng points into a hash for use by TomTom Matrix" do +      points = Set.new([ +        Geokit::LatLng.new(48.85086, 2.36143), +        Geokit::LatLng.new(47.91231, 1.87606), +        Geokit::LatLng.new(52.50867, 13.42879) +      ]) + +      expect( +        matrix.points_as_params(points) +      ).to eq([ +        { +          point: { +            latitude: 48.85086, +            longitude: 2.36143 +          }, +        }, +        { +          point: { +            latitude: 47.91231, +            longitude: 1.87606 +          }, +        }, +        { +          point: { +            latitude: 52.50867, +            longitude: 13.42879 +          }, +        } +      ]) +    end +  end + +  describe "#extract_costs_to_way_costs!" do +    it "puts distance & time costs in way_costs" do +      way_costs = [ +        WayCost.new( +          departure: Geokit::LatLng.new(48.85086, 2.36143), +          arrival: Geokit::LatLng.new(47.91231, 1.87606) +        ), +        WayCost.new( +          departure: Geokit::LatLng.new(47.91231, 1.87606), +          arrival: Geokit::LatLng.new(52.50867, 13.42879) +        ) +      ] + +      expected_way_costs = [ +        WayCost.new( +          departure: Geokit::LatLng.new(48.85086, 2.36143), +          arrival: Geokit::LatLng.new(47.91231, 1.87606), +          distance: 117947, +          time: 8356 +        ), +        WayCost.new( +          departure: Geokit::LatLng.new(48.85086, 2.36143), +          arrival: Geokit::LatLng.new(52.50867, 13.42879), +          distance: 999088, +          time: 62653 +        ), +        WayCost.new( +          departure: Geokit::LatLng.new(47.91231, 1.87606), +          arrival: Geokit::LatLng.new(48.85086, 2.36143), +          distance: 117231, +          time: 9729 +        ), +        WayCost.new( +          departure: Geokit::LatLng.new(47.91231, 1.87606), +          arrival: Geokit::LatLng.new(52.50867, 13.42879), +          distance: 1114635, +          time: 72079 +        ), +        WayCost.new( +          departure: Geokit::LatLng.new(52.50867, 13.42879), +          arrival: Geokit::LatLng.new(48.85086, 2.36143), +          distance: 997232, +          time: 63245 +        ), +        WayCost.new( +          departure: Geokit::LatLng.new(52.50867, 13.42879), +          arrival: Geokit::LatLng.new(47.91231, 1.87606), +          distance: 1113108, +          time: 68485 +        ), +        WayCost.new( +          departure: Geokit::LatLng.new(52.50867, 13.42879), +          arrival: Geokit::LatLng.new(52.50867, 13.42879), +          distance: 344, +          time: 109 +        ) +      ] + +      matrix_response = JSON.parse(read_fixture('tom_tom_matrix.json')) + +      points = matrix.points_as_params(matrix.points_from_way_costs(way_costs)) + +      expect( +        matrix.extract_costs_to_way_costs!(way_costs, points, matrix_response) +      ).to match_array(expected_way_costs) +    end +  end +end | 
