class Arcgis_Vrps

Public Class Methods

new(client_id, client_secret) click to toggle source
# getOutputRoutes("jf163f4d4f7874fd69b4f6f90e2d5d9aa")
# getOutputOrders("jf163f4d4f7874fd69b4f6f90e2d5d9aa")

end

# File lib/arcgis_vrps.rb, line 31
def initialize(client_id, client_secret)
        auth = Auth.new(client_id, client_secret)
        @token = auth.generateToken
        
        # puts
        # puts "Token generated #{@token}"
        # puts
        
end

Public Instance Methods

getJobStatus() click to toggle source
# File lib/arcgis_vrps.rb, line 157
def getJobStatus
        url = "https://logistics.arcgis.com/arcgis/rest/services/World/VehicleRoutingProblem/GPServer/SolveVehicleRoutingProblem/jobs/"+@jobId
        escaped_url = URI.encode(url)
        uri = URI.parse(escaped_url)
        req = Net::HTTP::Post.new(uri.to_s)
         
        req.set_form_data(
                token: @token,
                returnMessages: true,
                f: 'json'
        )
        
        http = Net::HTTP.new(uri.hostname, uri.port)
        http.use_ssl = true
                 
        res = http.request(req)

        status = JSON.parse(res.body)['jobStatus']


        if status == "esriJobSucceeded"
                return res.body
        elsif status == "esriJobFailed"
                raise "\nJob failed with the following message stack:\n #{res.body}"
        else
                return false
        end
end
getOutputOrders(jobId) click to toggle source
# File lib/arcgis_vrps.rb, line 218
def getOutputOrders(jobId)
        unless jobId.nil?
                @jobId = jobId
        end

        url = 'https://logistics.arcgis.com/arcgis/rest/services/World/VehicleRoutingProblem/GPServer/SolveVehicleRoutingProblem/jobs/'+@jobId+'/results/out_stops'
        escaped_url = URI.encode(url)
        uri = URI.parse(escaped_url)
        req = Net::HTTP::Post.new(uri.to_s)
         
        req.set_form_data(
                token: @token,
                f: 'json'
        )
        
        http = Net::HTTP.new(uri.hostname, uri.port)
        http.use_ssl = true
                 
        res = http.request(req)

        # We return the entire string is because it have meta data about the geometry type, spatial reference, etc
        ordersFeatures = JSON.parse(res.body)
        # ordersFeatures = JSON.parse(res.body)["value"]["features"]

        # puts " ================================================== "
        # puts "ordersFeatures"
        # puts ordersFeatures
        # puts " ================================================== "

        if ordersFeatures.nil?
                ordersFeatures = res.body
        end

        return ordersFeatures
end
getOutputRoutes(jobId) click to toggle source
# File lib/arcgis_vrps.rb, line 186
def getOutputRoutes(jobId)
        unless jobId.nil?
                @jobId = jobId
        end

        url = 'https://logistics.arcgis.com/arcgis/rest/services/World/VehicleRoutingProblem/GPServer/SolveVehicleRoutingProblem/jobs/'+@jobId+'/results/out_routes'
        escaped_url = URI.encode(url)
        uri = URI.parse(escaped_url)
        req = Net::HTTP::Post.new(uri.to_s)
         
        req.set_form_data(
                token: @token,
                f: 'json'
        )
        
        http = Net::HTTP.new(uri.hostname, uri.port)
        http.use_ssl = true
                 
        res = http.request(req)

        # We return the entire string is because it have meta data about the geometry type, spatial reference, etc
        routesFeatures = JSON.parse(res.body)
        # JSON.parse(res.body)["value"]["features"]["geometry"]["paths"] will return an array of coordinates in the following format: [longitude, latitude]
        # routesFeatures = JSON.parse(res.body)["value"]["features"]

        if routesFeatures.nil?
                routesFeatures = res.body
        end

        return routesFeatures
end
getToken() click to toggle source
# File lib/arcgis_vrps.rb, line 41
def getToken 
        return @token
end
loadSampleData(loadFromFile) click to toggle source
# File lib/arcgis_vrps.rb, line 254
def loadSampleData(loadFromFile)
        @loadData = Data_Load.new()

        if loadFromFile
                @loadData.getCoordinateFromMapSynq()
                @loadData.writeCoordinateToFile()
        end
end
mockCase1(numberOfVehicles) click to toggle source
# File lib/arcgis_vrps.rb, line 263
def mockCase1(numberOfVehicles) # Routes without any start & end time (Basic routing)

        puts "Setting up orders"

        @loadData.getCoordinateFromFile()
        coordinate = @loadData.coordinateArrayFromFile

        ord = Orders.new()

        i = 0
        coordinate.each do |coor|
                store_name = "Store_"+i.to_s

                orderAttributeObj = ord.getBasicOrderAttributeObj(store_name)
                ord.addOrders(coor[0], coor[1], orderAttributeObj)

                if i == 50
                        break
                end

                i += 1
        end
        
        ordersObj = ord.getOrderObj(nil)

        puts "Setting up depots"

        dep = Depots.new()
        deportAttributeObj = dep.getDepotAttributeObj("depot_1")
        dep.addDepots(103.848427, 1.277751, deportAttributeObj)
        depotsObj = dep.getDepotObj(nil)
        
        puts "Setting up routes"

        route = Routes.new()
        
        startDateTime = (Time.now.to_f * 1000).to_i

        for i in 1..numberOfVehicles
                truck_name = "Truck_#{i}"
                route.addRoutes(truck_name, "depot_1", startDateTime, startDateTime)
        end
        
        routesObj = route.getRouteObj()

        begin
                contents = submitJob(ordersObj, depotsObj, routesObj, nil)

                writeToFile("Mock Case 1 - #{numberOfVehicles}.json", contents)
        rescue Exception => e  
                puts
                puts e
                puts
        end
end
mockCase2(numberOfVehicles) click to toggle source
# File lib/arcgis_vrps.rb, line 319
def mockCase2(numberOfVehicles) # 9 locations with set times that vehicles must reach (no overlapping time)
        
        puts "Setting up orders"

        @loadData.getCoordinateFromFile()
        coordinate = @loadData.coordinateArrayFromFile

        ord = Orders.new()

        i = 0

        minutesInSeconds = 1800000 # 30 minutes in milliseconds
        timeWindowStart1 = 1441933200000 # Default date time: 11th Sept 2015, 9:00:00 AM in milliseconds
        timeWindowEnd1 = timeWindowStart1 + minutesInSeconds # Add 30 minutes every run

        coordinate.each do |coor|
                store_name = "Store_"+i.to_s
                serviceTime = 30

                if i < 9 && i >= 0
                        if i < 5 && i >= 1 # Can reach later than the set time here
                                timeWindowStart1 += (minutesInSeconds*2) # Add 1 hour every run
                                timeWindowEnd1 = timeWindowStart1 + minutesInSeconds # Add 30 minutes every run
                                maxViolationTime1 = nil
                        elsif i < 9 && i >= 5 # Can reach later than the set time based on the x minute set by MaxViolationTime1
                                timeWindowStart1 += (minutesInSeconds*2) # Add 1 hour every run
                                timeWindowEnd1 = timeWindowStart1 + minutesInSeconds # Add 30 minutes every run
                                maxViolationTime1 = 0
                        end
                        orderAttributeObj = ord.getOrderAttributeObj(store_name, serviceTime, timeWindowStart1, timeWindowEnd1, maxViolationTime1)
                elsif i >= 9
                        timeWindowStart1 = nil
                        timeWindowEnd1 = nil
                        maxViolationTime1 = nil
                        orderAttributeObj = ord.getBasicOrderAttributeObj(store_name)
                end          

                ord.addOrders(coor[0], coor[1], orderAttributeObj)

                if i == 49
                        break 
                end

                i += 1
        end
        
        ordersObj = ord.getOrderObj(nil)

        puts "Setting up depots"

        dep = Depots.new()
        deportAttributeObj = dep.getDepotAttributeObj("depot_1")
        dep.addDepots(103.848427, 1.277751, deportAttributeObj)
        depotsObj = dep.getDepotObj(nil)
        
        puts "Setting up routes"

        route = Routes.new()
        
        startDateTime = 1441933200000
        for i in 1..numberOfVehicles
                truck_name = "Truck_#{i}"
                route.addRoutes(truck_name, "depot_1", startDateTime, startDateTime)
        end
        
        routesObj = route.getRouteObj()

        # puts
        # puts ordersObj.to_json
        # puts
        # puts depotsObj.to_json
        # puts
        # puts routesObj.to_json
        # puts

        begin
                contents = submitJob(ordersObj, depotsObj, routesObj, nil)

                writeToFile("Mock Case 2 - #{numberOfVehicles}.json", contents)
        rescue Exception => e  
                puts
                puts e
                puts
        end
end
mockCase3(numberOfVehicles) click to toggle source
# File lib/arcgis_vrps.rb, line 405
def mockCase3(numberOfVehicles) # 8 locations with set times that vehicles must reach (with overlapping time)
        
        puts "Setting up orders"

        @loadData.getCoordinateFromFile()
        coordinate = @loadData.coordinateArrayFromFile

        ord = Orders.new()

        i = 0

        minutesInSeconds = 1800000 # 30 minutes in milliseconds
        timeWindowStart1 = 1441933200000 # Default date time: 11th Sept 2015, 9:00:00 AM in milliseconds
        timeWindowEnd1 = timeWindowStart1 + minutesInSeconds # Add 30 minutes every run

        countThree = 0
        countFive = 0

        coordinate.each do |coor|
                store_name = "Store_"+i.to_s
                serviceTime = 30

                if ((i%3 == 0 || i%5 == 0) && (countThree < 4 || countFive < 4))
                        if timeWindowStart1.nil? || timeWindowStart1 >= 1441944000000
                                timeWindowStart1 = 1441933200000
                        end

                        if i%3 == 0 && countThree < 4
                                timeWindowStart1 += (minutesInSeconds*2) # Add 1 hour every run
                                timeWindowEnd1 = timeWindowStart1 + minutesInSeconds # Add 30 minutes every run
                                maxViolationTime1 = nil
                                countThree += 1
                        elsif i%5 == 0 && countFive < 4
                                timeWindowStart1 += (minutesInSeconds*2) # Add 1 hour every run
                                timeWindowEnd1 = timeWindowStart1 + minutesInSeconds # Add 30 minutes every run
                                maxViolationTime1 = 0
                                countFive += 1
                        end
                        orderAttributeObj = ord.getOrderAttributeObj(store_name, serviceTime, timeWindowStart1, timeWindowEnd1, maxViolationTime1)
                else
                        timeWindowStart1 = nil
                        timeWindowEnd1 = nil
                        maxViolationTime1 = nil
                        orderAttributeObj = ord.getBasicOrderAttributeObj(store_name)
                end          

                ord.addOrders(coor[0], coor[1], orderAttributeObj)

                if i == 49
                        break 
                end

                i += 1
        end
        
        ordersObj = ord.getOrderObj(nil)

        puts "Setting up depots"

        dep = Depots.new()
        deportAttributeObj = dep.getDepotAttributeObj("depot_1")
        dep.addDepots(103.848427, 1.277751, deportAttributeObj)
        depotsObj = dep.getDepotObj(nil)
        
        puts "Setting up routes"

        route = Routes.new()
        
        startDateTime = 1441933200000
        for i in 1..numberOfVehicles
                truck_name = "Truck_#{i}"
                route.addRoutes(truck_name, "depot_1", startDateTime, startDateTime)
        end
        
        routesObj = route.getRouteObj()

        # puts
        # puts ordersObj.to_json
        # puts
        # puts depotsObj.to_json
        # puts
        # puts routesObj.to_json
        # puts

        begin
                contents = submitJob(ordersObj, depotsObj, routesObj, nil)

                writeToFile("Mock Case 3 - #{numberOfVehicles}.json", contents)
        rescue Exception => e  
                puts
                puts e
                puts
        end   
end
mockCase4(numberOfVehicles) click to toggle source
# File lib/arcgis_vrps.rb, line 500
def mockCase4(numberOfVehicles) # Same as use case 3 but with more overlapping times than routes available
        
        puts "Setting up orders"

        @loadData.getCoordinateFromFile()
        coordinate = @loadData.coordinateArrayFromFile

        ord = Orders.new()

        i = 0

        minutesInSeconds = 1800000 # 30 minutes in milliseconds
        timeWindowStart1 = 1441933200000 # Default date time: 11th Sept 2015, 9:00:00 AM in milliseconds
        timeWindowEnd1 = timeWindowStart1 + minutesInSeconds # Add 30 minutes every run

        countThree = 0
        countFive = 0

        coordinate.each do |coor|
                store_name = "Store_"+i.to_s
                serviceTime = 30

                if i < 6
                        # This if block is to set 3 with MaxViolationTime1 and 3 without
                        # if i < 3 && i >= 0
                        #   maxViolationTime1 = nil
                        # elsif i < 6 && i >= 3
                        #   maxViolationTime1 = 0
                        # end
                        maxViolationTime1 = 0 # This is to set all 6 with MaxViolationTime1
                        orderAttributeObj = ord.getOrderAttributeObj(store_name, serviceTime, timeWindowStart1, timeWindowEnd1, maxViolationTime1)
                else
                        timeWindowStart1 = nil
                        timeWindowEnd1 = nil
                        maxViolationTime1 = nil
                        orderAttributeObj = ord.getBasicOrderAttributeObj(store_name)
                end          

                ord.addOrders(coor[0], coor[1], orderAttributeObj)

                if i == 49
                        break 
                end

                i += 1
        end
        
        ordersObj = ord.getOrderObj(nil)

        puts "Setting up depots"

        dep = Depots.new()
        deportAttributeObj = dep.getDepotAttributeObj("depot_1")
        dep.addDepots(103.848427, 1.277751, deportAttributeObj)
        depotsObj = dep.getDepotObj(nil)
        
        puts "Setting up routes"

        route = Routes.new()
        
        startDateTime = 1441933200000
        for i in 1..numberOfVehicles
                truck_name = "Truck_#{i}"
                route.addRoutes(truck_name, "depot_1", startDateTime, startDateTime)
        end
        
        routesObj = route.getRouteObj()

        # puts
        # puts ordersObj.to_json
        # puts
        # puts depotsObj.to_json
        # puts
        # puts routesObj.to_json
        # puts

        begin
                contents = submitJob(ordersObj, depotsObj, routesObj, nil)

                writeToFile("Mock Case 4 - location - 6.json", contents)
        rescue Exception => e  
                puts
                puts e
                puts
        end   
end
submitJob(ordersObj, depotsObj, routesObj, timer) click to toggle source
# File lib/arcgis_vrps.rb, line 45
def submitJob(ordersObj, depotsObj, routesObj, timer) # TODO: Check to decide whether to use synchronous or async

        puts "Submitting job"
        
        jobStatusNoOfCalls = 0

        t1 = Time.now.to_i

        url = "https://logistics.arcgis.com/arcgis/rest/services/World/VehicleRoutingProblem/GPServer/SolveVehicleRoutingProblem/submitJob"
        escaped_url = URI.encode(url)
        uri = URI.parse(escaped_url)
        req = Net::HTTP::Post.new(uri.to_s)
        
        # Expiration is set to 20160 minutes = 2 weeks
        req.set_form_data(
                orders: ordersObj.to_json,
                depots: depotsObj.to_json,
                routes: routesObj.to_json,
                # default_date: Time.now.to_f, # This must be in milliseconds
                default_date: 1453600108000,
                token: @token,
                f: 'json',
                time_units: 'Seconds',
                distance_units: 'Meters'
        )
        
        http = Net::HTTP.new(uri.hostname, uri.port)
        http.use_ssl = true
                 
        res = http.request(req)

        # print " ======================================================== "
        # print "req"
        # print ordersObj.to_json
        # print " ----- "
        # print depotsObj.to_json
        # print " ----- "
        # print routesObj.to_json
        # print " ----- "
        # print Time.now.to_i
        # print " ----- "
        # print @token
        # print " ======================================================== "


        @jobId = JSON.parse(res.body)['jobId']

        if @jobId.nil?
                raise "Error! #{res.body}"
        else
                puts "Received job ID: #{@jobId}"
                print "Getting job status..."

                if timer.nil?
                        timer = 1 # Timer of 500ms to constantly check for updates
                end

                start_time = Time.now
                end_time = start_time+timer

                completed = false

                begin
                        while completed == false
                                print "."
                                jobStatusNoOfCalls += 1
                                while Time.now < end_time
                                end

                                completed = getJobStatus()
                        end
                        print "Completed!\n" 
                        puts
                        # puts completed.to_s
                        # puts

                        t2 = Time.now.to_i

                        time_jobStatusIsComplete = t2-t1

                        puts "Time taken for job to be completed: #{time_jobStatusIsComplete}"
                        puts

                        routesReceived = getOutputRoutes(nil)
                        # routesReceived = "Routes received: \n #{routesReceived}"
                        ordersReceived = getOutputOrders(nil)
                        # ordersReceived = "Orders received: \n #{ordersReceived}"

                        t3 = Time.now.to_i

                        time_fullJobComplete = t3-t1

                        # extraContent = "Total time taken for getting routes and orders: #{time_fullJobComplete} \nNumber of calls to jobStatus: #{jobStatusNoOfCalls} \n\n"
                        
                        extraContent = {
                                :time_job_status_complete => time_jobStatusIsComplete,
                                :time_full_job_complete => time_fullJobComplete,
                                :no_of_job_status_call => jobStatusNoOfCalls
                        }

                        # puts extraContent
                        # puts

                        return extraContent, routesReceived, ordersReceived
                rescue Exception => e 
                        puts 
                        puts e
                        puts
                end
        end
end
writeCoordinateToFile() click to toggle source
# File lib/arcgis_vrps.rb, line 587
def writeCoordinateToFile
        @loadData.getCoordinateFromFile(true)
        coordinate = @loadData.coordinateArrayFromFile
        writeToFile("coordinateArray", coordinate.to_json);
end
writeToFile(filename, contents) click to toggle source
# File lib/arcgis_vrps.rb, line 593
def writeToFile(filename, contents)
        puts "Writing to file #{filename}"

        File.open("lib/test/sample_data/#{filename}", "w") do |file|
                if contents.kind_of?(Array)
                        contents.each do |content|
                                file.puts content
                                file.puts
                        end
                else
                        file.puts contents
                        file.puts
                end
        end

        puts "Done writing to file #{filename}"
        puts
end