I'm working on a project that uses this example code at its core; using a custom distance/time matrix to solve the routing problem. The algorithm appears to work perfectly but I cannot find a way to view the outputs in a graph. Running just the example code without any modification results in:
2015-07-07 11:56:33,354 [main] WARN jsprit.analysis.toolbox.Plotter - cannot plot vrp, since coord is missing
This error makes sense. Nothing can be plotted because no locations are actually specified; we have only specified the relative distance/time between locations. I have to use a custom matrix because I'm working in lat/long and need the real road distance between points. However, as my problem scales up, it would be of great use to me simply to assign each location with its lat/long and to produce a graph treating these points as though they were cartesian coordinates. The catchment area isn't huge so it should still let me quickly see if a solution makes sense without having to do more elaborate plots. So my question is whether there's a simple way of getting jsprit to solve the problem using a custom distance/time matrix but assigning coordinates to the locations for the purpose of plotting? I can't seem to figure it out, thanks in advance.
EDIT: I have spent a long time working on this to no avail, even with the proposed changes from Stefan. I cannot find a way to do it without changing the base code and I don't want that to cause knock-on problems to what I already have working.
Building a location is fine, though it's slightly different than the proposed code:
Location.Builder.newInstance().setId("0").setCoordinate(Coordinate.newInstance(10.0, 10.0)).build();
The problem then comes that when I wish to make a Service, I am forced by the current code to define a new location (Location only accepts a newInstance):
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(Location.newInstance(6.0, 1.0)).build();
I cannot find an existing way to simply say that the Service is at a pre-defined location.
Moving on, I thought about adding the locations directly into VehicleRoutingProblem.Builder. Note that adding a location to the builder requires it to be defined as "addLocation(String LocationID, Coordinate coordinate), so it won't take pre-defined locations explicitly; they must be defined within the Builder. This looks like the following:
VehicleType type = VehicleTypeImpl.Builder.newInstance("type").addCapacityDimension(0, 5).setCostPerDistance(1).setCostPerTime(2).build();
VehicleImpl vehicle = VehicleImpl.Builder.newInstance("vehicle")
.setStartLocation(Location.newInstance("0")).setType(type).build();
Service s1 = Service.Builder.newInstance("1").addSizeDimension(0, 1).setLocation(Location.newInstance("1")).build();
Service s2 = Service.Builder.newInstance("2").addSizeDimension(0, 1).setLocation(Location.newInstance("2")).build();
Service s3 = Service.Builder.newInstance("3").addSizeDimension(0, 1).setLocation(Location.newInstance("3")).build();
//define a matrix-builder building an asymmetric matrix
VehicleRoutingTransportCostsMatrix.Builder costMatrixBuilder = VehicleRoutingTransportCostsMatrix.Builder.newInstance(true);
costMatrixBuilder.addTransportDistance("0", "1", 19.13);
costMatrixBuilder.addTransportDistance("0", "2", 18.56);
costMatrixBuilder.addTransportDistance("0", "3", 21.68);
costMatrixBuilder.addTransportDistance("1", "0", 15.91);
costMatrixBuilder.addTransportDistance("1", "2", 15.01);
costMatrixBuilder.addTransportDistance("1", "3", 11.45);
costMatrixBuilder.addTransportDistance("2", "0", 19.42);
costMatrixBuilder.addTransportDistance("2", "1", 12.54);
costMatrixBuilder.addTransportDistance("2", "3", 11.13);
costMatrixBuilder.addTransportDistance("3", "0", 25.75);
costMatrixBuilder.addTransportDistance("3", "1", 9.94);
costMatrixBuilder.addTransportDistance("3", "2", 11.24);
costMatrixBuilder.addTransportTime("0", "1", 12);
costMatrixBuilder.addTransportTime("0", "2", 11);
costMatrixBuilder.addTransportTime("0", "3", 15);
costMatrixBuilder.addTransportTime("1", "0", 10);
costMatrixBuilder.addTransportTime("1", "2", 10);
costMatrixBuilder.addTransportTime("1", "3", 10);
costMatrixBuilder.addTransportTime("2", "0", 15);
costMatrixBuilder.addTransportTime("2", "1", 9);
costMatrixBuilder.addTransportTime("2", "3", 10);
costMatrixBuilder.addTransportTime("3", "0", 17);
costMatrixBuilder.addTransportTime("3", "1", 13);
costMatrixBuilder.addTransportTime("3", "2", 10);
VehicleRoutingTransportCosts costMatrix = costMatrixBuilder.build();
VehicleRoutingProblem vrp = VehicleRoutingProblem.Builder.newInstance().setFleetSize(FleetSize.FINITE).setRoutingCost(costMatrix)
.addVehicle(vehicle).addJob(s1).addJob(s2).addJob(s3)
.addLocation("0", Coordinate.newInstance(1.0, 1.0)).addLocation("1", Coordinate.newInstance(9.0, 2.0))
.addLocation("2", Coordinate.newInstance(5.0, 4.0)).addLocation("3", Coordinate.newInstance(4.0, 8.0))
.addLocation("4", Coordinate.newInstance(3.0, 7.0)).build();`
That runs fine. But, it still won't plot because it doesn't make the association between the location indexes and the ability to plot them. However, I can confirm (as was requested) that the solver only uses the pre-defined costMatrix, so the printed answer is still correct.