* @return An {@link ArraysObject} using the specified output time unit.
*/
public static ArraysObject toSingleVehicleArrays(GlobalStateObject state,
Unit<Duration> outputTimeUnit) {
final UnitConverter timeConverter = state.timeUnit
.getConverterTo(outputTimeUnit);
final VehicleStateObject v = state.vehicles.iterator().next();
// we check all vehicles in case this method is used in other contexts
final ImmutableSet.Builder<ParcelDTO> cargoBuilder = ImmutableSet.builder();
for (final VehicleStateObject vs : state.vehicles) {
cargoBuilder.addAll(vs.contents);
}
final Set<ParcelDTO> inCargo = cargoBuilder.build();
// there are always two locations: the current vehicle location and
// the depot
final int numLocations = 2 + (state.availableParcels.size() * 2)
+ inCargo.size();
final int[] releaseDates = new int[numLocations];
final int[] dueDates = new int[numLocations];
final int[][] servicePairs = new int[state.availableParcels.size()][2];
final int[] serviceTimes = new int[numLocations];
// we need to create two mappings:
// parceldto -> pickup index / deliver index
// index -> parceldto
final ImmutableMap.Builder<ParcelDTO, ParcelIndexObj> parcel2indexBuilder = ImmutableMap
.builder();
final ImmutableMap.Builder<Integer, ParcelIndexObj> index2parcelBuilder = ImmutableMap
.builder();
// we wrap the points in PointWrapper to avoid problems with (possibly)
// duplicates in the points
final ImmutableList.Builder<Point> points = ImmutableList.builder();
points.add(v.location);
int index = 1;
int spIndex = 0;
for (final ParcelDTO p : state.availableParcels) {
serviceTimes[index] = DoubleMath.roundToInt(
timeConverter.convert(p.pickupDuration), RoundingMode.CEILING);
// add pickup location and time window
points.add(p.pickupLocation);
final int deliveryIndex = index + state.availableParcels.size();
final ParcelIndexObj pio = new ParcelIndexObj(p, index, deliveryIndex);
parcel2indexBuilder.put(p, pio);
index2parcelBuilder.put(index, pio);
index2parcelBuilder.put(deliveryIndex, pio);
final int[] tw = convertTW(p.pickupTimeWindow, state.time, timeConverter);
releaseDates[index] = tw[0];
dueDates[index] = tw[1];
checkState(releaseDates[index] <= dueDates[index]);
// link the pair with its delivery location (see next loop)
servicePairs[spIndex++] = new int[] { index, deliveryIndex };
index++;
}
checkState(spIndex == state.availableParcels.size(), "%s %s",
state.availableParcels.size(), spIndex);
final List<ParcelDTO> deliveries = new ImmutableList.Builder<ParcelDTO>()
.addAll(state.availableParcels).addAll(inCargo).build();
for (final ParcelDTO p : deliveries) {
serviceTimes[index] = DoubleMath.roundToInt(
timeConverter.convert(p.deliveryDuration), RoundingMode.CEILING);
points.add(p.destinationLocation);
if (inCargo.contains(p)) {
final ParcelIndexObj pio = new ParcelIndexObj(p, -1, index);
parcel2indexBuilder.put(p, pio);