1
0
Fork 0
mirror of https://github.com/graphhopper/jsprit.git synced 2020-01-24 07:45:05 +01:00

Merge branch 'routes-with-specified-start-and-end' into

access-egress-costs-merged-with-routes-with-spec-start-end

Conflicts:
	jsprit-core/src/test/java/jsprit/core/algorithm/recreate/TestCalculatesServiceInsertion.java
	jsprit-examples/src/main/java/jsprit/examples/MultipleDepotExampleWithPenaltyVehicles.java
	jsprit-examples/src/main/java/jsprit/examples/SolomonExample.java
	jsprit-examples/src/main/java/jsprit/examples/SolomonOpenExample.java
This commit is contained in:
oblonski 2014-02-11 05:39:06 +01:00
commit 6dbcd7431a
75 changed files with 4281 additions and 525 deletions

View file

@ -86,9 +86,15 @@ class InsertionFactory {
String weight = config.getString("considerFixedCosts[@weight]");
if(weight == null) weight = config.getString("considerFixedCost[@weight]");
if(weight != null) fixedCostWeight = Double.parseDouble(weight);
else log.warn("parameter considerFixedCosts[@weight] is missing. by default, it is 0.5.");
else throw new IllegalStateException("fixedCostsParameter 'weight' must be set, e.g. <considerFixedCosts weight=1.0>true</considerFixedCosts>.\n" +
"this has to be changed in algorithm-config-xml-file.");
iBuilder.considerFixedCosts(fixedCostWeight);
}
else if(val.equals("false")){
}
else throw new IllegalStateException("considerFixedCosts must either be true or false, i.e. <considerFixedCosts weight=1.0>true</considerFixedCosts> or \n<considerFixedCosts weight=1.0>false</considerFixedCosts>. " +
"if latter, you can also omit the tag. this has to be changed in algorithm-config-xml-file");
}
String timeSliceString = config.getString("experimental[@timeSlice]");
String neighbors = config.getString("experimental[@neighboringSlices]");

View file

@ -481,9 +481,6 @@ public class VehicleRoutingAlgorithms {
@Override
public void finish() {
if(firstAct){
assert vehicle.getLocationId() == end.getLocationId() : "route end and last activity are not equal even route is open. this should not be.";
}
firstAct = true;
}

View file

@ -39,7 +39,7 @@ class AdditionalAccessEgressCalculator {
Driver newDriver = insertionContext.getNewDriver();
double newVehicleDepartureTime = insertionContext.getNewDepTime();
if(!currentRoute.isEmpty()){
double accessTransportCostNew = routingCosts.getTransportCost(newVehicle.getLocationId(), currentRoute.getActivities().get(0).getLocationId(), newVehicleDepartureTime, newDriver, newVehicle);
double accessTransportCostNew = routingCosts.getTransportCost(newVehicle.getStartLocationId(), currentRoute.getActivities().get(0).getLocationId(), newVehicleDepartureTime, newDriver, newVehicle);
double accessTransportCostOld = routingCosts.getTransportCost(currentRoute.getStart().getLocationId(), currentRoute.getActivities().get(0).getLocationId(), currentRoute.getDepartureTime(), currentRoute.getDriver(), currentRoute.getVehicle());
delta_access = accessTransportCostNew - accessTransportCostOld;
@ -48,7 +48,7 @@ class AdditionalAccessEgressCalculator {
TourActivity lastActivityBeforeEndOfRoute = currentRoute.getActivities().get(currentRoute.getActivities().size()-1);
double lastActivityEndTimeWithOldVehicleAndDepartureTime = lastActivityBeforeEndOfRoute.getEndTime();
double lastActivityEndTimeEstimationWithNewVehicleAndNewDepartureTime = Math.max(0.0, lastActivityEndTimeWithOldVehicleAndDepartureTime + (newVehicleDepartureTime - currentRoute.getDepartureTime()));
double egressTransportCostNew = routingCosts.getTransportCost(lastActivityBeforeEndOfRoute.getLocationId(), newVehicle.getLocationId() , lastActivityEndTimeEstimationWithNewVehicleAndNewDepartureTime, newDriver, newVehicle);
double egressTransportCostNew = routingCosts.getTransportCost(lastActivityBeforeEndOfRoute.getLocationId(), newVehicle.getEndLocationId() , lastActivityEndTimeEstimationWithNewVehicleAndNewDepartureTime, newDriver, newVehicle);
double egressTransportCostOld = routingCosts.getTransportCost(lastActivityBeforeEndOfRoute.getLocationId(), currentRoute.getEnd().getLocationId(), lastActivityEndTimeWithOldVehicleAndDepartureTime, currentRoute.getDriver(), currentRoute.getVehicle());
delta_egress = egressTransportCostNew - egressTransportCostOld;

View file

@ -60,13 +60,13 @@ class Inserter {
@Override
public void handleJobInsertion(Job job, InsertionData iData, VehicleRoute route) {
if(job instanceof Service){
route.setVehicleAndDepartureTime(iData.getSelectedVehicle(),iData.getVehicleDepartureTime());
if(!iData.getSelectedVehicle().isReturnToDepot()){
if(iData.getDeliveryInsertionIndex()>=route.getTourActivities().getActivities().size()){
setEndLocation(route,(Service)job);
}
}
route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), this.activityFactory.createActivity((Service)job));
route.setDepartureTime(iData.getVehicleDepartureTime());
}
else delegator.handleJobInsertion(job, iData, route);
}
@ -92,6 +92,7 @@ class Inserter {
if(job instanceof Shipment){
TourActivity pickupShipment = this.activityFactory.createPickup((Shipment)job);
TourActivity deliverShipment = this.activityFactory.createDelivery((Shipment)job);
route.setVehicleAndDepartureTime(iData.getSelectedVehicle(),iData.getVehicleDepartureTime());
if(!iData.getSelectedVehicle().isReturnToDepot()){
if(iData.getDeliveryInsertionIndex()>=route.getActivities().size()){
setEndLocation(route,(Shipment)job);
@ -99,7 +100,6 @@ class Inserter {
}
route.getTourActivities().addActivity(iData.getDeliveryInsertionIndex(), deliverShipment);
route.getTourActivities().addActivity(iData.getPickupInsertionIndex(), pickupShipment);
route.setDepartureTime(iData.getVehicleDepartureTime());
}
else delegator.handleJobInsertion(job, iData, route);
}
@ -132,8 +132,7 @@ class Inserter {
if(job == null) throw new IllegalStateException("cannot insert null-job");
if(!(vehicleRoute.getVehicle().getId().toString().equals(insertionData.getSelectedVehicle().getId().toString()))){
insertionListeners.informVehicleSwitched(vehicleRoute, vehicleRoute.getVehicle(), insertionData.getSelectedVehicle());
// log.debug("vehicle switched from " + vehicleRoute.getVehicle().getId() + " to " + insertionData.getSelectedVehicle().getId());
vehicleRoute.setVehicle(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
vehicleRoute.setVehicleAndDepartureTime(insertionData.getSelectedVehicle(), insertionData.getVehicleDepartureTime());
}
jobInsertionHandler.handleJobInsertion(job, insertionData, vehicleRoute);
insertionListeners.informJobInserted(job, vehicleRoute, insertionData.getInsertionCost(), insertionData.getAdditionalTime());

View file

@ -110,9 +110,9 @@ final class ServiceInsertionCalculator implements JobInsertionCostsCalculator{
TourActivity deliveryAct2Insert = activityFactory.createActivity(service);
Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
Start start = Start.newInstance(newVehicle.getStartLocationId(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE);
start.setEndTime(newVehicleDepartureTime);
End end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
End end = End.newInstance(newVehicle.getEndLocationId(), 0.0, newVehicle.getLatestArrival());
TourActivity prevAct = start;
double prevActStartTime = newVehicleDepartureTime;

View file

@ -314,22 +314,22 @@ final class ServiceInsertionOnRouteLevelCalculator implements JobInsertionCostsC
*/
private void initialiseStartAndEnd(final Vehicle newVehicle, double newVehicleDepartureTime) {
if(start == null){
start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
start = Start.newInstance(newVehicle.getStartLocationId(), newVehicle.getEarliestDeparture(), Double.MAX_VALUE);
start.setEndTime(newVehicleDepartureTime);
}
else{
start.setLocationId(newVehicle.getLocationId());
start.setLocationId(newVehicle.getStartLocationId());
start.setTheoreticalEarliestOperationStartTime(newVehicle.getEarliestDeparture());
start.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
start.setTheoreticalLatestOperationStartTime(Double.MAX_VALUE);
start.setEndTime(newVehicleDepartureTime);
}
if(end == null){
end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
end = End.newInstance(newVehicle.getEndLocationId(), 0.0, newVehicle.getLatestArrival());
}
else{
end.setLocationId(newVehicle.getLocationId());
end.setTheoreticalEarliestOperationStartTime(newVehicleDepartureTime);
end.setLocationId(newVehicle.getEndLocationId());
end.setTheoreticalEarliestOperationStartTime(0.0);
end.setTheoreticalLatestOperationStartTime(newVehicle.getLatestArrival());
}
}

View file

@ -111,10 +111,10 @@ final class ShipmentInsertionCalculator implements JobInsertionCostsCalculator{
int pickupInsertionIndex = InsertionData.NO_INDEX;
int deliveryInsertionIndex = InsertionData.NO_INDEX;
Start start = Start.newInstance(newVehicle.getLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
Start start = Start.newInstance(newVehicle.getStartLocationId(), newVehicle.getEarliestDeparture(), newVehicle.getLatestArrival());
start.setEndTime(newVehicleDepartureTime);
End end = End.newInstance(newVehicle.getLocationId(), 0.0, newVehicle.getLatestArrival());
End end = End.newInstance(newVehicle.getEndLocationId(), 0.0, newVehicle.getLatestArrival());
TourActivity prevAct = start;
double prevActEndTime = newVehicleDepartureTime;

View file

@ -85,7 +85,7 @@ final class VehicleTypeDependentJobInsertionCalculator implements JobInsertionCo
if(!(selectedVehicle instanceof NoVehicle)) {
relevantVehicles.add(selectedVehicle);
if(vehicleSwitchAllowed){
relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle.getType().getTypeId(),selectedVehicle.getLocationId()));
relevantVehicles.addAll(fleetManager.getAvailableVehicles(selectedVehicle));
}
}
else{ //if no vehicle has been assigned, i.e. it is an empty route

View file

@ -327,7 +327,11 @@ public class VehicleRoutingProblem {
if(!vehicleTypes.contains(vehicle.getType())){
vehicleTypes.add(vehicle.getType());
}
coordinates.put(vehicle.getLocationId(), vehicle.getCoord());
String startLocationId = vehicle.getStartLocationId();
coordinates.put(startLocationId, vehicle.getStartLocationCoordinate());
if(!vehicle.getEndLocationId().equals(startLocationId)){
coordinates.put(vehicle.getEndLocationId(), vehicle.getEndLocationCoordinate());
}
return this;
}
@ -373,7 +377,7 @@ public class VehicleRoutingProblem {
Set<LocTypeKey> locTypeKeys = new HashSet<LocTypeKey>();
List<Vehicle> uniqueVehicles = new ArrayList<Vehicle>();
for(Vehicle v : vehicles){
LocTypeKey key = new LocTypeKey(v.getLocationId(),v.getType().getTypeId());
LocTypeKey key = new LocTypeKey(v.getStartLocationId(),v.getType().getTypeId());
if(!locTypeKeys.contains(key)){
uniqueVehicles.add(v);
locTypeKeys.add(key);
@ -390,9 +394,10 @@ public class VehicleRoutingProblem {
.setFixedCost(fixed)
.build();
PenaltyVehicleType penType = new PenaltyVehicleType(t,penaltyFactor);
String vehicleId = "penaltyVehicle_" + v.getLocationId() + "_" + t.getTypeId();
String vehicleId = "penaltyVehicle_" + v.getStartLocationId() + "_" + t.getTypeId();
Vehicle penVehicle = VehicleImpl.Builder.newInstance(vehicleId).setEarliestStart(v.getEarliestDeparture())
.setLatestArrival(v.getLatestArrival()).setLocationCoord(v.getCoord()).setLocationId(v.getLocationId())
.setLatestArrival(v.getLatestArrival()).setStartLocationCoordinate(v.getStartLocationCoordinate()).setStartLocationId(v.getStartLocationId())
.setEndLocationId(v.getEndLocationId()).setEndLocationCoordinate(v.getEndLocationCoordinate())
.setReturnToDepot(v.isReturnToDepot()).setType(penType).build();
addVehicle(penVehicle);
}

View file

@ -492,20 +492,45 @@ public class VrpXMLReader{
if(type == null) throw new IllegalStateException("vehicleType with typeId " + typeId + " is missing.");
builder.setType(type);
String locationId = vehicleConfig.getString("location.id");
if(locationId == null) {
locationId = vehicleConfig.getString("startLocation.id");
}
if(locationId == null) throw new IllegalStateException("location.id is missing.");
builder.setLocationId(locationId);
builder.setStartLocationId(locationId);
String coordX = vehicleConfig.getString("location.coord[@x]");
String coordY = vehicleConfig.getString("location.coord[@y]");
if(coordX == null || coordY == null) {
coordX = vehicleConfig.getString("startLocation.coord[@x]");
coordY = vehicleConfig.getString("startLocation.coord[@y]");
}
if(coordX == null || coordY == null) {
if(!doNotWarnAgain) {
logger.warn("location.coord is missing. will not warn you again.");
doNotWarnAgain = true;
}
}
else{
Coordinate coordinate = Coordinate.newInstance(Double.parseDouble(coordX), Double.parseDouble(coordY));
builder.setStartLocationCoordinate(coordinate);
}
String endLocationId = vehicleConfig.getString("endLocation.id");
if(endLocationId != null) builder.setEndLocationId(endLocationId);
String endCoordX = vehicleConfig.getString("endLocation.coord[@x]");
String endCoordY = vehicleConfig.getString("endLocation.coord[@y]");
if(endCoordX == null || endCoordY == null) {
if(!doNotWarnAgain) {
logger.warn("location.coord is missing. do not warn you again.");
logger.warn("endLocation.coord is missing. will not warn you again.");
doNotWarnAgain = true;
}
}
else{
Coordinate coordinate = Coordinate.newInstance(Double.parseDouble(coordX), Double.parseDouble(coordY));
builder.setLocationCoord(coordinate);
Coordinate coordinate = Coordinate.newInstance(Double.parseDouble(endCoordX), Double.parseDouble(endCoordY));
builder.setEndLocationCoordinate(coordinate);
}
String start = vehicleConfig.getString("timeSchedule.start");
String end = vehicleConfig.getString("timeSchedule.end");
if(start != null) builder.setEarliestStart(Double.parseDouble(start));

View file

@ -236,10 +236,15 @@ public class VrpXMLWriter {
}
xmlConfig.setProperty(vehiclePathString + "("+counter+").id", vehicle.getId());
xmlConfig.setProperty(vehiclePathString + "("+counter+").typeId", vehicle.getType().getTypeId());
xmlConfig.setProperty(vehiclePathString + "("+counter+").location.id", vehicle.getLocationId());
if(vehicle.getCoord() != null){
xmlConfig.setProperty(vehiclePathString + "("+counter+").location.coord[@x]", vehicle.getCoord().getX());
xmlConfig.setProperty(vehiclePathString + "("+counter+").location.coord[@y]", vehicle.getCoord().getY());
xmlConfig.setProperty(vehiclePathString + "("+counter+").startLocation.id", vehicle.getStartLocationId());
if(vehicle.getStartLocationCoordinate() != null){
xmlConfig.setProperty(vehiclePathString + "("+counter+").startLocation.coord[@x]", vehicle.getStartLocationCoordinate().getX());
xmlConfig.setProperty(vehiclePathString + "("+counter+").startLocation.coord[@y]", vehicle.getStartLocationCoordinate().getY());
}
xmlConfig.setProperty(vehiclePathString + "("+counter+").endLocation.id", vehicle.getEndLocationId());
if(vehicle.getEndLocationCoordinate() != null){
xmlConfig.setProperty(vehiclePathString + "("+counter+").endLocation.coord[@x]", vehicle.getEndLocationCoordinate().getX());
xmlConfig.setProperty(vehiclePathString + "("+counter+").endLocation.coord[@y]", vehicle.getEndLocationCoordinate().getY());
}
xmlConfig.setProperty(vehiclePathString + "("+counter+").timeSchedule.start", vehicle.getEarliestDeparture());
xmlConfig.setProperty(vehiclePathString + "("+counter+").timeSchedule.end", vehicle.getLatestArrival());

View file

@ -64,8 +64,10 @@ public class VehicleRoute {
* @param tour
* @param driver
* @param vehicle
* @return
* @return VehicleRoute
* @deprecated use VehicleRoute.Builder instead
*/
@Deprecated
public static VehicleRoute newInstance(TourActivities tour, Driver driver, Vehicle vehicle) {
return new VehicleRoute(tour,driver,vehicle);
}
@ -78,7 +80,7 @@ public class VehicleRoute {
* @return
*/
public static VehicleRoute emptyRoute() {
return new VehicleRoute(TourActivities.emptyTour(), DriverImpl.noDriver(), VehicleImpl.createNoVehicle());
return Builder.newInstance(VehicleImpl.createNoVehicle(), DriverImpl.noDriver()).build();
}
/**
@ -92,11 +94,19 @@ public class VehicleRoute {
/**
* Returns new instance of this builder.
*
* <p><b>Construction-settings of vehicleRoute:</b>
* <p>startLocation == vehicle.getStartLocationId()
* <p>endLocation == vehicle.getEndLocationId()
* <p>departureTime == vehicle.getEarliestDepartureTime()
* <p>latestStart == Double.MAX_VALUE
* <p>earliestEnd == 0.0
*
* @param vehicle
* @param driver
* @return this builder
*/
public static Builder newInstance(Vehicle vehicle, Driver driver){
if(vehicle == null || driver == null) throw new IllegalArgumentException("null arguments not accepted. ini emptyRoute with VehicleImpl.createNoVehicle() and DriverImpl.noDriver()");
return new Builder(vehicle,driver);
}
@ -141,9 +151,11 @@ public class VehicleRoute {
/**
* Constructs the route-builder.
*
* <p>Default startLocation is vehicle.getLocationId()<br>
* Default departureTime is vehicle.getEarliestDeparture()<br>
* Default endLocation is either vehicle.getLocationId() or (if !vehicle.isReturnToDepot()) last specified activityLocation
* <p>startLocation == vehicle.getStartLocationId()
* <p>endLocation == vehicle.getEndLocationId()
* <p>departureTime == vehicle.getEarliestDepartureTime()
* <p>latestStart == Double.MAX_VALUE
* <p>earliestEnd == 0.0
* @param vehicle
* @param driver
*/
@ -151,18 +163,22 @@ public class VehicleRoute {
super();
this.vehicle = vehicle;
this.driver = driver;
start = Start.newInstance(vehicle.getLocationId(), vehicle.getEarliestDeparture(), vehicle.getLatestArrival());
start = Start.newInstance(vehicle.getStartLocationId(), vehicle.getEarliestDeparture(), Double.MAX_VALUE);
start.setEndTime(vehicle.getEarliestDeparture());
end = End.newInstance(vehicle.getLocationId(), vehicle.getEarliestDeparture(), vehicle.getLatestArrival());
end = End.newInstance(vehicle.getEndLocationId(), 0.0, vehicle.getLatestArrival());
}
/**
* Sets the departure-time of the route, i.e. which is the time the vehicle departs from start-location.
*
* <p><b>Note</b> that departureTime cannot be lower than earliestDepartureTime of vehicle.
*
* @param departureTime
* @return
* @return builder
* @throws IllegalArgumentException if departureTime < vehicle.getEarliestDeparture()
*/
public Builder setDepartureTime(double departureTime){
if(departureTime < start.getEndTime()) throw new IllegalArgumentException("departureTime < vehicle.getEarliestDepartureTime(). this must not be.");
start.setEndTime(departureTime);
return this;
}
@ -172,8 +188,10 @@ public class VehicleRoute {
*
* @param endTime
* @return this builder
* @throws IllegalArgumentException if endTime > vehicle.getLatestArrival()
*/
public Builder setRouteEndArrivalTime(double endTime){
if(endTime > vehicle.getLatestArrival()) throw new IllegalArgumentException("endTime > vehicle.getLatestArrival(). this must not be.");
end.setArrTime(endTime);
return this;
}
@ -306,6 +324,11 @@ public class VehicleRoute {
private End end;
/**
* Copy constructor copying a route.
*
* @param route
*/
private VehicleRoute(VehicleRoute route){
this.start = Start.copyOf(route.getStart());
this.end = End.copyOf(route.getEnd());
@ -314,6 +337,7 @@ public class VehicleRoute {
this.driver = route.getDriver();
}
@Deprecated
private VehicleRoute(TourActivities tour, Driver driver, Vehicle vehicle) {
super();
verify(tour, driver, vehicle);
@ -323,7 +347,11 @@ public class VehicleRoute {
setStartAndEnd(vehicle, vehicle.getEarliestDeparture());
}
/**
* Constructs route.
*
* @param builder
*/
private VehicleRoute(Builder builder){
this.tourActivities = builder.tourActivities;
this.vehicle = builder.vehicle;
@ -332,6 +360,14 @@ public class VehicleRoute {
this.end = builder.end;
}
/**
*
* @param tour
* @param driver
* @param vehicle
* @deprecated verification is a task of VehicleRoute.Builder
*/
@Deprecated
private void verify(TourActivities tour, Driver driver, Vehicle vehicle) {
if(tour == null || driver == null || vehicle == null) throw new IllegalStateException("null is not allowed for tour, driver or vehicle. use emptyRoute. use Tour.emptyTour, DriverImpl.noDriver() and VehicleImpl.noVehicle() instead." +
"\n\tor make it easier and use VehicleRoute.emptyRoute()");
@ -349,6 +385,11 @@ public class VehicleRoute {
return Collections.unmodifiableList(tourActivities.getActivities());
}
/**
* Returns TourActivities.
*
* @return {@link TourActivities}
*/
public TourActivities getTourActivities() {
return tourActivities;
}
@ -372,19 +413,42 @@ public class VehicleRoute {
}
/**
* Sets the vehicle and its departureTime.
* Sets the vehicle and its departureTime from <code>vehicle.getStartLocationId()</code>.
*
* <p>This implies the following:<br>
* if start and end are null, new start and end activities are created.<br>
* <p>startActivity is initialized with the location of the specified vehicle. the time-window of this activity is initialized
* as follows: [time-window.start = vehicle.getEarliestDeparture()][time-window.end = vehicle.getLatestArrival()]
* <p>endActivity is initialized with the location of the specified vehicle as well. time-window of this activity:[time-window.start = vehicle.getEarliestDeparture()][time-window.end = vehicle.getLatestArrival()]
* <p>start.endTime is set to the specified departureTime
* <p>Note that start end end-locations are always initialized with the location of the specified vehicle. (this will change soon, then there will be start and end location of vehicle which can be different, 23.01.14)
* <p>startActivity is initialized with the start-location of the specified vehicle (<code>vehicle.getStartLocationId()</code>). the time-window of this activity is initialized
* such that [<code>startActivity.getTheoreticalEarliestOperationStartTime()</code> = <code>vehicle.getEarliestDeparture()</code>][<code>startActivity.getTheoreticalLatestOperationStartTime()</code> = <code>vehicle.getLatestArrival()</code>]
* <p>endActivity is initialized with the end-location of the specified vehicle (<code>vehicle.getEndLocationId()</code>). The time-window of the
* endActivity is initialized such that [<code>endActivity.getTheoreticalEarliestOperationStartTime()</code> = <code>vehicle.getEarliestDeparture()</code>][<code>endActivity.getTheoreticalLatestOperationStartTime()</code> = <code>vehicle.getLatestArrival()</code>]
* <p>startActivity.endTime (<code>startActivity.getEndTime()</code>) is set to max{<code>vehicle.getEarliestDeparture()</code>, <code>vehicleDepTime</code>}.
* thus, <code>vehicle.getEarliestDeparture()</code> is a physical constraint that has to be met.
*
* @param vehicle
* @param vehicleDepTime
*/
public void setVehicleAndDepartureTime(Vehicle vehicle, double vehicleDepTime){
this.vehicle = vehicle;
setStartAndEnd(vehicle, vehicleDepTime);
}
/**
* Sets the vehicle and its departureTime from <code>vehicle.getStartLocationId()</code>.
*
* <p>This implies the following:<br>
* if start and end are null, new start and end activities are created.<br>
* <p>startActivity is initialized with the start-location of the specified vehicle (<code>vehicle.getStartLocationId()</code>). the time-window of this activity is initialized
* such that [<code>startActivity.getTheoreticalEarliestOperationStartTime()</code> = <code>vehicle.getEarliestDeparture()</code>][<code>startActivity.getTheoreticalLatestOperationStartTime()</code> = <code>vehicle.getLatestArrival()</code>]
* <p>endActivity is initialized with the end-location of the specified vehicle (<code>vehicle.getEndLocationId()</code>). The time-window of the
* endActivity is initialized such that [<code>endActivity.getTheoreticalEarliestOperationStartTime()</code> = <code>vehicle.getEarliestDeparture()</code>][<code>endActivity.getTheoreticalLatestOperationStartTime()</code> = <code>vehicle.getLatestArrival()</code>]
* <p>startActivity.endTime (<code>startActivity.getEndTime()</code>) is set to max{<code>vehicle.getEarliestDeparture()</code>, <code>vehicleDepTime</code>}.
* thus, <code>vehicle.getEarliestDeparture()</code> is a physical constraint that has to be met.
*
* @param vehicle
* @param vehicleDepTime
* @deprecated use .setVehicleAndDepartureTime(Vehicle vehicle, double vehicleDepTime) instead
*/
@Deprecated
public void setVehicle(Vehicle vehicle, double vehicleDepTime){
this.vehicle = vehicle;
setStartAndEnd(vehicle, vehicleDepTime);
@ -393,14 +457,14 @@ public class VehicleRoute {
private void setStartAndEnd(Vehicle vehicle, double vehicleDepTime) {
if(!(vehicle instanceof NoVehicle)){
if(start == null && end == null){
start = Start.newInstance(vehicle.getLocationId(), vehicle.getEarliestDeparture(), vehicle.getLatestArrival());
end = End.newInstance(vehicle.getLocationId(), vehicle.getEarliestDeparture(), vehicle.getLatestArrival());
start = Start.newInstance(vehicle.getStartLocationId(), vehicle.getEarliestDeparture(), vehicle.getLatestArrival());
end = End.newInstance(vehicle.getEndLocationId(), vehicle.getEarliestDeparture(), vehicle.getLatestArrival());
}
start.setEndTime(vehicleDepTime);
start.setEndTime(Math.max(vehicleDepTime, vehicle.getEarliestDeparture()));
start.setTheoreticalEarliestOperationStartTime(vehicle.getEarliestDeparture());
start.setTheoreticalLatestOperationStartTime(vehicle.getLatestArrival());
start.setLocationId(vehicle.getLocationId());
end.setLocationId(vehicle.getLocationId());
start.setLocationId(vehicle.getStartLocationId());
end.setLocationId(vehicle.getEndLocationId());
end.setTheoreticalEarliestOperationStartTime(vehicle.getEarliestDeparture());
end.setTheoreticalLatestOperationStartTime(vehicle.getLatestArrival());
}
@ -411,14 +475,17 @@ public class VehicleRoute {
* Sets departureTime of this route, i.e. the time the vehicle departs from its start-location.
*
* @param vehicleDepTime
* @deprecated use .setVehicleAndDepartureTime(...) instead (vehicle requires departureTime and the other way around, and earliestDepartureTime
* of a vehicle is a physical constraint of the vehicle and cannot be broken. Using this method might break this constraint.)
*/
@Deprecated
public void setDepartureTime(double vehicleDepTime){
if(start == null) throw new IllegalStateException("cannot set departureTime without having a vehicle on this route. use setVehicle(vehicle,departureTime) instead.");
start.setEndTime(vehicleDepTime);
}
/**
* Returns the departureTime of this vehicle.
* Returns the departureTime of this vehicle in this route.
*
* @return departureTime
* @throws IllegalStateException if start is null
@ -431,7 +498,7 @@ public class VehicleRoute {
/**
* Returns tour if tour-activity-sequence is empty, i.e. to activity on the tour yet.
*
* @return
* @return true if route is empty
*/
public boolean isEmpty() {
return tourActivities.isEmpty();

View file

@ -45,7 +45,7 @@ class InfiniteVehicles implements VehicleFleetManager{
private void extractTypes(Collection<Vehicle> vehicles) {
for(Vehicle v : vehicles){
VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(),v.getLocationId());
VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocationId(),v.getEndLocationId());
types.put(typeKey,v);
sortedTypes.add(typeKey);
@ -79,10 +79,26 @@ class InfiniteVehicles implements VehicleFleetManager{
return types.values();
}
/**
* @deprecated use getAvailableVehicles(Vehicle withoutThisType) instead
*/
@Override
@Deprecated
public Collection<Vehicle> getAvailableVehicles(String withoutThisType, String locationId) {
Collection<Vehicle> vehicles = new ArrayList<Vehicle>();
VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType,locationId);
VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType, locationId,locationId);
for(VehicleTypeKey key : types.keySet()){
if(!key.equals(thisKey)){
vehicles.add(types.get(key));
}
}
return vehicles;
}
@Override
public Collection<Vehicle> getAvailableVehicles(Vehicle withoutThisType) {
Collection<Vehicle> vehicles = new ArrayList<Vehicle>();
VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocationId(), withoutThisType.getEndLocationId());
for(VehicleTypeKey key : types.keySet()){
if(!key.equals(thisKey)){
vehicles.add(types.get(key));

View file

@ -47,7 +47,9 @@ public interface Vehicle {
* <p> Consequently, it should be the end-location of this vehicle, if returnToDepot is true.
*
* @return location-id of this vehicle
* @deprecated use getStartLocationId() instead
*/
@Deprecated
public abstract String getLocationId();
/**
@ -56,7 +58,9 @@ public interface Vehicle {
* <p> Consequently, it should be the coordinate of the end-location, if returnToDepot is true.
*
* @return coordinate of this vehicle
* @deprecated use getStartLocationCoordinate() instead
*/
@Deprecated
public abstract Coordinate getCoord();
/**
@ -86,5 +90,25 @@ public interface Vehicle {
* @return true if isReturnToDepot
*/
public abstract boolean isReturnToDepot();
/**
* Returns the start-locationId of this vehicle.
*/
public abstract String getStartLocationId();
/**
* Returns the start-locationCoord of this vehicle.
*/
public abstract Coordinate getStartLocationCoordinate();
/**
* Returns the end-locationId of this vehicle.
*
*/
public abstract String getEndLocationId();
/**
* Returns the end-locationCoord of this vehicle.
*/
public abstract Coordinate getEndLocationCoordinate();
}

View file

@ -31,6 +31,16 @@ public interface VehicleFleetManager {
public abstract Collection<Vehicle> getAvailableVehicles();
/**
*
* @param withoutThisType
* @param locationId
* @return
* @deprecated use .getAvailableVehicles(Vehicle without) instead. this might ignore withoutType and returns all available vehicles
*/
@Deprecated
public Collection<Vehicle> getAvailableVehicles(String withoutThisType, String locationId);
public Collection<Vehicle> getAvailableVehicles(Vehicle withoutThisType);
}

View file

@ -132,11 +132,11 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
}
String typeId = v.getType().getTypeId();
if(v.getType() instanceof PenaltyVehicleType){
VehicleTypeKey typeKey = new VehicleTypeKey(typeId,v.getLocationId());
VehicleTypeKey typeKey = new VehicleTypeKey(typeId, v.getStartLocationId(), v.getEndLocationId());
penaltyVehicles.put(typeKey, v);
}
else{
VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(),v.getLocationId());
VehicleTypeKey typeKey = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocationId(), v.getEndLocationId());
if(!typeMapOfAvailableVehicles.containsKey(typeKey)){
typeMapOfAvailableVehicles.put(typeKey, new TypeContainer(typeKey));
}
@ -147,7 +147,7 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
private void removeVehicle(Vehicle v){
//it might be better to introduce a class PenaltyVehicle
if(!(v.getType() instanceof PenaltyVehicleType)){
VehicleTypeKey key = new VehicleTypeKey(v.getType().getTypeId(),v.getLocationId());
VehicleTypeKey key = new VehicleTypeKey(v.getType().getTypeId(), v.getStartLocationId(), v.getEndLocationId());
if(typeMapOfAvailableVehicles.containsKey(key)){
typeMapOfAvailableVehicles.get(key).remove(v);
}
@ -186,11 +186,13 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
* @param typeId to specify the typeId that should not be the returned collection
* @param locationId to specify the locationId that should not be in the returned collection
* @return collection of available vehicles without the vehicles that have the typeId 'withoutThisType' AND the locationId 'withThisLocation'.
* @deprecated use .getAvailableVehicles(Vehicle without) instead - this might ignore withoutThisType and returns all available vehicles
*/
@Override
@Deprecated
public Collection<Vehicle> getAvailableVehicles(String withoutThisType, String withThisLocationId) {
List<Vehicle> vehicles = new ArrayList<Vehicle>();
VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType,withThisLocationId);
VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType, withThisLocationId, withThisLocationId);
for(VehicleTypeKey key : typeMapOfAvailableVehicles.keySet()){
if(key.equals(thisKey)) continue;
if(!typeMapOfAvailableVehicles.get(key).isEmpty()){
@ -207,6 +209,24 @@ class VehicleFleetManagerImpl implements VehicleFleetManager {
@Override
public Collection<Vehicle> getAvailableVehicles(Vehicle withoutThisType) {
List<Vehicle> vehicles = new ArrayList<Vehicle>();
VehicleTypeKey thisKey = new VehicleTypeKey(withoutThisType.getType().getTypeId(), withoutThisType.getStartLocationId(), withoutThisType.getEndLocationId());
for(VehicleTypeKey key : typeMapOfAvailableVehicles.keySet()){
if(key.equals(thisKey)) continue;
if(!typeMapOfAvailableVehicles.get(key).isEmpty()){
vehicles.add(typeMapOfAvailableVehicles.get(key).getVehicle());
}
else{
if(penaltyVehicles.containsKey(key)){
vehicles.add(penaltyVehicles.get(key));
}
}
}
return vehicles;
}
/* (non-Javadoc)
* @see org.matsim.contrib.freight.vrp.basics.VehicleFleetManager#lock(org.matsim.contrib.freight.vrp.basics.Vehicle)
*/

View file

@ -79,6 +79,12 @@ public class VehicleImpl implements Vehicle {
private double earliestStart = 0.0;
private double latestArrival = Double.MAX_VALUE;
private String startLocationId;
private Coordinate startLocationCoord;
private String endLocationId;
private Coordinate endLocationCoord;
private boolean returnToDepot = true;
private VehicleType type = VehicleTypeImpl.Builder.newInstance("default", 0).build();
@ -109,6 +115,12 @@ public class VehicleImpl implements Vehicle {
/**
* Sets the flag whether the vehicle must return to depot or not.
*
* <p>If returnToDepot is true, the vehicle must return to specified end-location. If you
* omit specifying the end-location, vehicle returns to start-location (that must to be set). If
* you specify it, it returns to specified end-location.
*
* <p>If returnToDepot is false, the end-location of the vehicle is endogenous.
*
* @param returnToDepot
* @return this builder
*/
@ -124,9 +136,12 @@ public class VehicleImpl implements Vehicle {
*
* @param id
* @return this builder
* @deprecated use setStartLocationId(..) instead
*/
@Deprecated
public Builder setLocationId(String id){
this.locationId = id;
this.startLocationId = id;
return this;
}
@ -137,9 +152,60 @@ public class VehicleImpl implements Vehicle {
*
* @param coord
* @return this builder
* @deprecated use setStartLocationCoordinate(...) instead
*/
@Deprecated
public Builder setLocationCoord(Coordinate coord){
this.locationCoord = coord;
this.startLocationCoord = coord;
return this;
}
/**
* Sets the start-location of this vehicle.
*
* @param startLocationId
* @return this builder
* @throws IllegalArgumentException if startLocationId is null
*/
public Builder setStartLocationId(String startLocationId){
if(startLocationId == null) throw new IllegalArgumentException("startLocationId cannot be null");
this.startLocationId = startLocationId;
this.locationId = startLocationId;
return this;
}
/**
* Sets the start-coordinate of this vehicle.
*
* @param coord
* @return this builder
*/
public Builder setStartLocationCoordinate(Coordinate coord){
this.startLocationCoord = coord;
this.locationCoord = coord;
return this;
}
/**
* Sets the end-locationId of this vehicle.
*
* @param endLocationId
* @return this builder
*/
public Builder setEndLocationId(String endLocationId){
this.endLocationId = endLocationId;
return this;
}
/**
* Sets the end-coordinate of this vehicle.
*
* @param coord
* @return this builder
*/
public Builder setEndLocationCoordinate(Coordinate coord){
this.endLocationCoord = coord;
return this;
}
@ -171,13 +237,33 @@ public class VehicleImpl implements Vehicle {
* <p>if {@link VehicleType} is not set, default vehicle-type is set with id="default" and
* capacity=0
*
* <p>if startLocationId || locationId is null (=> startLocationCoordinate || locationCoordinate must be set) then startLocationId=startLocationCoordinate.toString()
* and locationId=locationCoordinate.toString() [coord.toString() --> [x=x_val][y=y_val])
* <p>if endLocationId is null and endLocationCoordinate is set then endLocationId=endLocationCoordinate.toString()
* <p>if endLocationId==null AND endLocationCoordinate==null then endLocationId=startLocationId AND endLocationCoord=startLocationCoord
* Thus endLocationId can never be null even returnToDepot is false.
*
* @return vehicle
* @throw IllegalStateException if both locationId and locationCoord is not set
* @throws IllegalStateException if both locationId and locationCoord is not set or (endLocationCoord!=null AND returnToDepot=false)
* or (endLocationId!=null AND returnToDepot=false)
*/
public VehicleImpl build(){
if(locationId == null && locationCoord != null) locationId = locationCoord.toString();
if((locationId == null && locationCoord == null) && (startLocationId == null && startLocationCoord == null)){
throw new IllegalStateException("vehicle requires startLocation. but neither locationId nor locationCoord nor startLocationId nor startLocationCoord has been set");
}
if(locationId == null && locationCoord != null) {
locationId = locationCoord.toString();
startLocationId = locationCoord.toString();
}
if(locationId == null && locationCoord == null) throw new IllegalStateException("locationId and locationCoord is missing.");
if(locationCoord == null) log.warn("locationCoord for vehicle " + id + " is missing.");
if(endLocationId == null && endLocationCoord != null) endLocationId = endLocationCoord.toString();
if(endLocationId == null && endLocationCoord == null) {
endLocationId = startLocationId;
endLocationCoord = startLocationCoord;
}
if( !startLocationId.equals(endLocationId) && returnToDepot == false) throw new IllegalStateException("this must not be. you specified both endLocationId and open-routes. this is contradictory. <br>" +
"if you set endLocation, returnToDepot must be true. if returnToDepot is false, endLocationCoord must not be specified.");
return new VehicleImpl(this);
}
@ -216,6 +302,14 @@ public class VehicleImpl implements Vehicle {
private final boolean returnToDepot;
private final Coordinate endLocationCoord;
private final String endLocationId;
private final Coordinate startLocationCoord;
private final String startLocationId;
private VehicleImpl(Builder builder){
id = builder.id;
type = builder.type;
@ -224,6 +318,10 @@ public class VehicleImpl implements Vehicle {
earliestDeparture = builder.earliestStart;
latestArrival = builder.latestArrival;
returnToDepot = builder.returnToDepot;
startLocationId = builder.startLocationId;
startLocationCoord = builder.startLocationCoord;
endLocationId = builder.endLocationId;
endLocationCoord = builder.endLocationCoord;
}
/**
@ -236,6 +334,10 @@ public class VehicleImpl implements Vehicle {
return "[id="+id+"][type="+type+"][locationId="+locationId+"][coord=" + coord + "][isReturnToDepot=" + isReturnToDepot() + "]";
}
/**
* @deprecated use getStartLocationCoordinate() instead
*/
@Deprecated
public Coordinate getCoord() {
return coord;
}
@ -250,6 +352,10 @@ public class VehicleImpl implements Vehicle {
return latestArrival;
}
/**
* @deprecated use getStartLocationId() instead
*/
@Deprecated
@Override
public String getLocationId() {
return locationId;
@ -273,5 +379,25 @@ public class VehicleImpl implements Vehicle {
public boolean isReturnToDepot() {
return returnToDepot;
}
@Override
public String getStartLocationId() {
return this.startLocationId;
}
@Override
public Coordinate getStartLocationCoordinate() {
return this.startLocationCoord;
}
@Override
public String getEndLocationId() {
return this.endLocationId;
}
@Override
public Coordinate getEndLocationCoordinate() {
return this.endLocationCoord;
}
}

View file

@ -1,26 +1,45 @@
package jsprit.core.problem.vehicle;
/**
* Key to identify different vehicles
*
* <p>Two vehicles are equal if they share the same type and location.
* <p>Note that earliestStart and latestArrival are ignored by this key (this might change in future)
*
* @author stefan
*
*/
class VehicleTypeKey {
public final String type;
public final String locationId;
public final String startLocationId;
public final String endLocationId;
VehicleTypeKey(String typeId, String locationId) {
VehicleTypeKey(String typeId, String startLocationId, String endLocationId) {
super();
this.type = typeId;
this.locationId = locationId;
this.startLocationId = startLocationId;
this.endLocationId = endLocationId;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((locationId == null) ? 0 : locationId.hashCode());
+ ((endLocationId == null) ? 0 : endLocationId.hashCode());
result = prime * result
+ ((startLocationId == null) ? 0 : startLocationId.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
@ -30,10 +49,15 @@ class VehicleTypeKey {
if (getClass() != obj.getClass())
return false;
VehicleTypeKey other = (VehicleTypeKey) obj;
if (locationId == null) {
if (other.locationId != null)
if (endLocationId == null) {
if (other.endLocationId != null)
return false;
} else if (!locationId.equals(other.locationId))
} else if (!endLocationId.equals(other.endLocationId))
return false;
if (startLocationId == null) {
if (other.startLocationId != null)
return false;
} else if (!startLocationId.equals(other.startLocationId))
return false;
if (type == null) {
if (other.type != null)
@ -43,6 +67,6 @@ class VehicleTypeKey {
return true;
}
}

View file

@ -62,7 +62,7 @@ public class NeighborhoodImpl implements Neighborhood{
for(Service i : services){
Set<String> neigh = new HashSet<String>();
for(Vehicle v : vehicles){
double dist2depot = EuclideanDistanceCalculator.calculateDistance(v.getCoord(), i.getCoord());
double dist2depot = EuclideanDistanceCalculator.calculateDistance(v.getStartLocationCoordinate(), i.getCoord());
if(dist2depot <= threshold){
neighborsToAll.add(((Service)i).getLocationId());
}
@ -80,7 +80,7 @@ public class NeighborhoodImpl implements Neighborhood{
private void makeNeighborsToAll(Collection<Vehicle> vehicles) {
for(Vehicle v : vehicles){
neighborsToAll.add(v.getLocationId());
neighborsToAll.add(v.getStartLocationId());
}
}

View file

@ -21,15 +21,21 @@ import java.util.Collection;
import jsprit.core.algorithm.VehicleRoutingAlgorithm;
import jsprit.core.algorithm.listener.AlgorithmStartsListener;
import jsprit.core.problem.VehicleRoutingProblem;
import jsprit.core.problem.driver.DriverImpl;
import jsprit.core.problem.job.Job;
import jsprit.core.problem.job.Service;
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
import jsprit.core.problem.vehicle.Vehicle;
import org.apache.log4j.Logger;
/**
* Verifies whether vrp can be solved.
*
* <p>Checks<br>
* - capacities, i.e. whether all job at least fit into the biggest vehicle
*
* @author stefan
*
*/
public class VrpVerifier implements AlgorithmStartsListener{
private static Logger log = Logger.getLogger(VrpVerifier.class);
@ -47,26 +53,26 @@ public class VrpVerifier implements AlgorithmStartsListener{
}
}
log.info("ok");
log.info("check vehicles can manage shuttle tours ...");
for(Job j : problem.getJobs().values()){
Service s = (Service)j;
boolean jobCanBeRoutedWithinTimeWindow = false;
for(Vehicle v : problem.getVehicles()){
double transportTime = problem.getTransportCosts().getTransportTime(v.getLocationId(), s.getLocationId(), v.getEarliestDeparture(), DriverImpl.noDriver(), v);
if(transportTime+v.getEarliestDeparture() < s.getTimeWindow().getEnd()){
jobCanBeRoutedWithinTimeWindow = true;
break;
}
else{
log.warn("vehicle " + v + " needs " + transportTime + " time-units to get to " + s.getLocationId() + ". latestOperationStartTime however is " + s.getTimeWindow().getEnd());
}
}
if(!jobCanBeRoutedWithinTimeWindow){
throw new IllegalStateException("no vehicle is able to cover the distance from depot to " + s.getLocationId() + " to meet the time-window " + s.getTimeWindow() + ".");
}
}
log.info("ok");
// log.info("check vehicles can manage shuttle tours ...");
// for(Job j : problem.getJobs().values()){
// Service s = (Service)j;
// boolean jobCanBeRoutedWithinTimeWindow = false;
// for(Vehicle v : problem.getVehicles()){
// double transportTime = problem.getTransportCosts().getTransportTime(v.getStartLocationId(), s.getLocationId(), v.getEarliestDeparture(), DriverImpl.noDriver(), v);
// if(transportTime+v.getEarliestDeparture() < s.getTimeWindow().getEnd()){
// jobCanBeRoutedWithinTimeWindow = true;
// break;
// }
// else{
// log.warn("vehicle " + v + " needs " + transportTime + " time-units to get to " + s.getLocationId() + ". latestOperationStartTime however is " + s.getTimeWindow().getEnd());
// }
//
// }
// if(!jobCanBeRoutedWithinTimeWindow){
// throw new IllegalStateException("no vehicle is able to cover the distance from depot to " + s.getLocationId() + " to meet the time-window " + s.getTimeWindow() + ".");
// }
// }
// log.info("ok");
log.info("verifying done");
}

View file

@ -226,7 +226,8 @@
<xs:extension base="xs:string">
<xs:attribute name="weight" type="xs:double"/>
</xs:extension>
</xs:simpleContent>
</xs:simpleContent>
</xs:complexType>
</xs:element>
<xs:element name="allowVehicleSwitch" type="xs:boolean" minOccurs="0" maxOccurs="1"/>

View file

@ -37,18 +37,29 @@
<xs:complexType>
<xs:all>
<xs:element name="id" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="location">
<xs:element name="location" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="id" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="coord" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="x" type="xs:decimal" use="required"/>
<xs:attribute name="y" type="xs:decimal" use="required"/>
</xs:complexType>
</xs:element>
<xs:element name="coord" type="coordType" minOccurs="0" maxOccurs="1"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="startLocation" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="id" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="coord" type="coordType" minOccurs="0" maxOccurs="1"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="endLocation" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:all>
<xs:element name="id" type="xs:string" minOccurs="0" maxOccurs="1"/>
<xs:element name="coord" type="coordType" minOccurs="0" maxOccurs="1"/>
</xs:all>
</xs:complexType>
</xs:element>
<xs:element name="typeId" type="xs:string" minOccurs="1" maxOccurs="1"/>