Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions app/controllers/midways_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -88,16 +88,24 @@ def create
#accesses the venue type and any keywords the user wants
@midway.venue_type = params[:midway][:venue_type].downcase
@midway.keyword = params[:midway][:keyword].downcase
@midway.choice = params[:midway][:choice].downcase

#assigns the midpoint
midpoint_service = MidpointService.new(addresses: participants_locations, time_option: time_option, future_datetime: future_datetime)
midpoint_coordinates = midpoint_service.calculate[0]
if @midway.choice == "efficient"
results = midpoint_service.calculate_efficient
midpoint_coordinates = results[0]
durations = results[1]
else
results = midpoint_service.calculate_equal
midpoint_coordinates = results[0]
durations = results[1]
end
@midpoint = "#{midpoint_coordinates[:lat]},#{midpoint_coordinates[:lng]}"
@midway.midpoint = @midpoint
@midway.save!

#assigns a duration to each Midway Participant
durations = midpoint_service.calculate[1]
participants.each_with_index do |participant, index|
participant.duration_to_midpoint = durations[index]
participant.save!
Expand Down Expand Up @@ -229,7 +237,7 @@ def show
private

def midway_params
params.require(:midway).permit(:friends, :time_option, :future_time, :future_date, :future_datetime, :venue_type, :venue, :keyword)
params.require(:midway).permit(:friends, :time_option, :future_time, :future_date, :future_datetime, :venue_type, :venue, :keyword, :choice)
end

def venue_params
Expand Down
132 changes: 126 additions & 6 deletions app/services/midpoint_service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ def initialize(attributes = {})
@midpoint = { lat: 0, lng: 0 }
end

def calculate
def calculate_efficient

# find the average lat and long of all user locations (set this to variable D) - this is the first attempt at the midpoint (based purely off geographical equidistance)

Expand All @@ -33,7 +33,8 @@ def calculate
p address_query

candidates = []
5.times do
user_candidates = []
3.times do

url = "https://api.distancematrix.ai/maps/api/distancematrix/json?units=imperial&origins=#{address_query}&destinations=#{@midpoint[:lat]},#{@midpoint[:lng]}&transit_mode=subway&mode=transit&#{url_time}&key=#{ENV["DISTANCE_MATRIX_KEY"]}"

Expand All @@ -48,6 +49,7 @@ def calculate
durations = @addresses.map { |address| address[:duration] }
max_duration = durations.max
md_index = durations.index(max_duration)
min_duration = durations.min

durations_text = @addresses.map { |address| address[:duration_text] }

Expand All @@ -57,28 +59,146 @@ def calculate
percentage = avg / max_duration
@midpoint[:lat] = lerp(@addresses[md_index][:lat], @midpoint[:lat], percentage)
@midpoint[:lng] = lerp(@addresses[md_index][:lng], @midpoint[:lng], percentage)
min_duration = durations.min

# stores as candidate_duration the discrepancy between the largest/smallest travel time

candidate_duration = (max_duration - min_duration).abs
candidates.push([@midpoint, candidate_duration, durations_text])
candidates.push([@midpoint, candidate_duration, durations_text, avg])
end

# also puts as candidate midpoints the home locations of each of the users

@addresses.each do |address|
url = "https://api.distancematrix.ai/maps/api/distancematrix/json?units=imperial&origins=#{address_query}&destinations=#{address[:lat]},#{address[:lng]}&transit_mode=subway&mode=transit&#{url_time}&key=#{ENV["DISTANCE_MATRIX_KEY"]}"

@matrix = JSON.parse(open(url).read, symbolize_names: true)

@addresses.each_with_index do |address, index|
address[:duration] = @matrix[:rows][index+1][:elements][0][:duration][:value]
address[:duration_text] = @matrix[:rows][index+1][:elements][0][:duration][:text]
end

# determines the longest route between a user and @midpoint
durations = @addresses.map { |address| address[:duration] }
max_duration = durations.max
md_index = durations.index(max_duration)
min_duration = durations.min
durations_text = @addresses.map { |address| address[:duration_text] }
avg = (durations.sum / durations.count).to_f

candidate_duration = (max_duration - min_duration).abs
user_candidates.push([address, candidate_duration, durations_text, avg])
end

# of the 5 attempts, selects the midpoint with the smallest discrepancy (candidate_duration)
# of all the 5 attempts, selects the midpoint with the smallest discrepancy (candidate_duration)
# returns the chosen midpoint

candidate_durations = candidates.map { |candidate| candidate[1] }
minimum_candidate_duration = candidate_durations.min
mcd_index = candidate_durations.index(minimum_candidate_duration)
candidate_midpoints = candidates.map { |candidate| candidate[0] }
@midpoint = candidate_midpoints[mcd_index]
p "Candidates:"
p candidates
p candidate_durations
p "_________"
# p candidate_durations
p "User Candidates"
p user_candidates
p "_________"
p @midpoint

# then it checks that this midpoint does not have an average duration greater than any of the user locations
# if it does it reassigns

candidate_averages = candidates.map { |candidate| candidate[3] }
midpoint_average = candidate_averages[mcd_index]
p midpoint_average
user_candidate_midpoints = user_candidates.map { |candidate| candidate[0] }
user_candidate_averages = user_candidates.map { |candidate| candidate[3] }
min_user_candidate_average = user_candidate_averages.min
p min_user_candidate_average
mucd_index = user_candidate_averages.index(min_user_candidate_average)
if midpoint_average > user_candidate_averages.min
@midpoint = user_candidate_midpoints[mucd_index]
user_candidate_durations_text = user_candidates.map { |candidate| candidate[2] }
@durations_text = user_candidate_durations_text[mucd_index]
else
candidate_durations_text = candidates.map { |candidate| candidate[2] }
@durations_text = candidate_durations_text[mcd_index]
end
p @midpoint

# p "Durations: #{@durations_text}"
return [@midpoint, @durations_text]
end

def calculate_equal

# find the average lat and long of all user locations (set this to variable D) - this is the first attempt at the midpoint (based purely off geographical equidistance)

lat_sum = @addresses.map { |address| address[:lat] }.sum
lng_sum = @addresses.map { |address| address[:lng] }.sum
@midpoint[:lat] = lat_sum / @addresses.count
@midpoint[:lng] = lng_sum / @addresses.count

# make the API calls to find the distances and duration between each user location and attempted midpoint

@condition = false
url_time = @time_option == 1 ? "arrival_time=#{@future_datetime}" : "departure_time=#{@future_datetime}"

address_query=""
@addresses.each do |address|
iaq = "|#{address[:lat]},#{address[:lng]}"
address_query = address_query + iaq
end
p address_query

candidates = []
user_candidates = []
3.times do

url = "https://api.distancematrix.ai/maps/api/distancematrix/json?units=imperial&origins=#{address_query}&destinations=#{@midpoint[:lat]},#{@midpoint[:lng]}&transit_mode=subway&mode=transit&#{url_time}&key=#{ENV["DISTANCE_MATRIX_KEY"]}"

@matrix = JSON.parse(open(url).read, symbolize_names: true)

@addresses.each_with_index do |address, index|
address[:duration] = @matrix[:rows][index+1][:elements][0][:duration][:value]
address[:duration_text] = @matrix[:rows][index+1][:elements][0][:duration][:text]
end

# determines the longest route between a user and @midpoint
durations = @addresses.map { |address| address[:duration] }
max_duration = durations.max
md_index = durations.index(max_duration)
min_duration = durations.min

durations_text = @addresses.map { |address| address[:duration_text] }

# reassigns the midpoint to a new location (skewed to be closer to the user who previously would have had to travel the longest)

avg = (durations.sum / durations.count).to_f
percentage = avg / max_duration
@midpoint[:lat] = lerp(@addresses[md_index][:lat], @midpoint[:lat], percentage)
@midpoint[:lng] = lerp(@addresses[md_index][:lng], @midpoint[:lng], percentage)

# stores as candidate_duration the discrepancy between the largest/smallest travel time

candidate_duration = (max_duration - min_duration).abs
candidates.push([@midpoint, candidate_duration, durations_text, avg])
end

# of all the 5 attempts, selects the midpoint with the smallest discrepancy (candidate_duration)
# returns the chosen midpoint

candidate_durations = candidates.map { |candidate| candidate[1] }
minimum_candidate_duration = candidate_durations.min
mcd_index = candidate_durations.index(minimum_candidate_duration)
candidate_midpoints = candidates.map { |candidate| candidate[0] }
@midpoint = candidate_midpoints[mcd_index]

candidate_durations_text = candidates.map { |candidate| candidate[2] }
@durations_text = candidate_durations_text[mcd_index]

# p "Durations: #{@durations_text}"
return [@midpoint, @durations_text]
end
Expand Down
5 changes: 5 additions & 0 deletions app/views/midways/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,11 @@
<label class="string" for="midway_keyword">What cuisine do you fancy? (Optional)</label>
<input class="form-control string required" placeholder="Italian, Indian, French..." type="text" name="midway[keyword]" id="midway_keyword">
</div>

<div class="form-group string required midway_choice">
<label class="string" for="midway_choice">How would you like us to calculate our Midawy? (Optional)</label>
<input class="form-control string required" placeholder="Efficient or Equal" type="text" name="midway[choice]" id="midway_choice">
</div>
<input type="submit" name="commit" value="Find our Midway" class="btn submit-button" id="submit-two" data-disable-with="Find our Midway">
<!-- <p><input placeholder="Username..." oninput="this.className = ''"></p>
<p><input placeholder="Password..." oninput="this.className = ''"></p> -->
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20201208162629_add_choice_to_midway.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddChoiceToMidway < ActiveRecord::Migration[6.0]
def change
add_column(:midways, :choice, :string)
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 2020_12_03_130053) do
ActiveRecord::Schema.define(version: 2020_12_08_162629) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -81,6 +81,7 @@
t.time "future_time"
t.date "future_date"
t.datetime "future_datetime"
t.string "choice"
t.index ["user_id"], name: "index_midways_on_user_id"
t.index ["venue_id"], name: "index_midways_on_venue_id"
end
Expand Down