using System; using System.Collections.Generic; using System.Linq; using System.Text; using HeuristicLab.Persistence.Default.CompositeSerializers.Storable; using HeuristicLab.Common; using HeuristicLab.PDPSimulation.DomainModel; using HeuristicLab.PDPSimulation.DistanceMeasures; namespace HeuristicLab.PDPSimulation { public enum VehicleAction { Wait, Pickup, Deliver, Park, Invalid } [StorableClass] public class MoveVehicleAction: PDAction { [Storable] double sourceX; public double SourceX { get { return sourceX; } } [Storable] double sourceY; public double SourceY { get { return sourceY; } } [Storable] double targetX; public double TargetX { get { return targetX; } } [Storable] double targetY; public double TargetY { get { return targetY; } } [Storable] VehicleAction action; [Storable] Order order; [Storable] double serviceTime; [Storable] bool interruptable; [Storable] bool completed; [Storable] DistanceMeasure distMeasure; [Storable] bool diversionAllowed; public MoveVehicleAction( Guid vehicleId, double targetX, double targetY, VehicleAction action, Order order, bool diversionAllowed, DistanceMeasure distMeasure) : base(vehicleId) { this.targetX = targetX; this.targetY = targetY; this.action = action; this.order = order; this.serviceTime = 0; this.completed = false; this.diversionAllowed = diversionAllowed; this.interruptable = diversionAllowed; this.distMeasure = distMeasure; this.sourceX = -1; this.sourceY = -1; } [StorableConstructor] protected MoveVehicleAction(bool deserializing) : base(deserializing) { } protected MoveVehicleAction(MoveVehicleAction original, Cloner cloner) : base(original, cloner) { this.targetX = original.targetX; this.sourceX = original.sourceX; this.targetY = original.targetY; this.sourceY = original.sourceY; this.action = original.action; this.order = cloner.Clone(original.order); this.serviceTime = original.serviceTime; this.completed = original.completed; this.interruptable = original.interruptable; this.distMeasure = cloner.Clone(original.distMeasure); this.diversionAllowed = original.diversionAllowed; } public override IDeepCloneable Clone(Cloner cloner) { return new MoveVehicleAction(this, cloner); } protected override bool ActionInterruptable() { return interruptable; } public override bool ActionCompleted() { return completed; } protected override double Perform(BaseObject baseObject, double simulationTime, double tickTime, List changes) { Vehicle vehicle = baseObject as Vehicle; lock (vehicle) { if ((action == VehicleAction.Pickup && (order.OrderState != OrderState.Waiting && order.OrderState != OrderState.PickingUp)) || (action == VehicleAction.Deliver && ((order.OrderState != OrderState.PickedUp && order.OrderState != OrderState.Delivering) || !vehicle.PickedUpOrders.Contains(order.Id))) || (order != null && (order.Vehicle != Guid.Empty && order.Vehicle != vehicle.Id))) { if (vehicle.VehicleState != VehicleState.InvalidAction) { vehicle.InvalidActions++; vehicle.VehicleState = VehicleState.InvalidAction; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); } if (diversionAllowed) vehicle.ReadyTime = simulationTime; interruptable = diversionAllowed; completed = diversionAllowed; if (diversionAllowed) return simulationTime; else { if (order != null) { changes.Add(new PDChange() { ChangeType = SimulationStateChange.OrderFailed, BaseObject = order }); order = null; action = VehicleAction.Invalid; } } } if (sourceX == -1) { sourceX = vehicle.PositionX; sourceY = vehicle.PositionY; } vehicle.TargetPositionX = targetX; vehicle.TargetPositionY = targetY; vehicle.CurrentAction = action; if (order == null) vehicle.CurrentOrder = Guid.Empty; else { if (!diversionAllowed) order.Vehicle = vehicle.Id; vehicle.CurrentOrder = order.Id; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); } if (action == VehicleAction.Wait || action == VehicleAction.Park) if (diversionAllowed) vehicle.ReadyTime = simulationTime; double tx, ty, length; distMeasure.Move(sourceX, sourceY, vehicle.PositionX, vehicle.PositionY, targetX, targetY, tickTime, vehicle.MoveInfo, out tx, out ty, out length); if (!diversionAllowed) { double time = simulationTime; time += distMeasure.GetDistance(sourceX, sourceY, vehicle.PositionX, vehicle.PositionY, targetX, targetY); if (action == VehicleAction.Pickup) { if (time < order.PickupReadyTime) time = order.PickupReadyTime; time += order.PickupServiceTime - serviceTime; } else if (action == VehicleAction.Deliver) { if (time < order.DeliveryReadyTime) time = order.DeliveryReadyTime; time += order.DeliveryServiceTime - serviceTime; } vehicle.ReadyTime = time; } vehicle.PositionX = tx; vehicle.PositionY = ty; if (length > 0) { vehicle.Distance += length; tickTime -= length; simulationTime += length; if (vehicle.VehicleState != VehicleState.Moving) { vehicle.VehicleState = VehicleState.Moving; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); } changes.Add( new PDChange() { ChangeType = SimulationStateChange.VehicleMoved, BaseObject = baseObject }); } if (vehicle.PositionX == targetX && vehicle.PositionY == targetY) { if (action == VehicleAction.Pickup) { if (order.Vehicle != Guid.Empty && order.Vehicle != vehicle.Id) throw new Exception("Order already assigned"); if (simulationTime < order.PickupReadyTime) { if (vehicle.VehicleState != VehicleState.Waiting) { if (diversionAllowed) vehicle.ReadyTime = simulationTime; vehicle.VehicleState = VehicleState.Waiting; interruptable = diversionAllowed; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); } double waitTime = Math.Min(tickTime, order.PickupReadyTime - simulationTime); simulationTime += waitTime; tickTime -= waitTime; } //pickup if (simulationTime >= order.PickupReadyTime && tickTime > 0) { if (vehicle.VehicleState != VehicleState.Servicing) { if (diversionAllowed) { vehicle.ReadyTime = simulationTime; vehicle.ReadyTime += order.PickupServiceTime; } vehicle.VehicleState = VehicleState.Servicing; interruptable = false; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); } if (order.OrderState != OrderState.PickingUp) { order.Vehicle = vehicle.Id; order.OrderState = OrderState.PickingUp; changes.Add(new PDChange() { ChangeType = SimulationStateChange.OrderState, BaseObject = order }); } if (serviceTime == 0 && simulationTime > order.PickupDueTime) { order.Tardiness += simulationTime - order.PickupDueTime; } double service = Math.Min(tickTime, order.PickupServiceTime - serviceTime); serviceTime += service; simulationTime += service; tickTime -= service; //load if (serviceTime == order.PickupServiceTime) { vehicle.Capacity -= order.Demand; if (vehicle.Capacity < 0) { vehicle.Overload = -vehicle.Capacity; vehicle.Capacity = 0; } vehicle.PickedUpOrders.Add(order.Id); order.Vehicle = vehicle.Id; order.OrderState = OrderState.PickedUp; changes.Add(new PDChange() { ChangeType = SimulationStateChange.OrderState, BaseObject = order }); vehicle.VehicleState = VehicleState.Waiting; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); completed = true; } } } else if (action == VehicleAction.Deliver) { if (order.Vehicle != Guid.Empty && order.Vehicle != vehicle.Id) throw new Exception("Order already assigned"); if (simulationTime < order.DeliveryReadyTime) { if (vehicle.VehicleState != VehicleState.Waiting) { if (diversionAllowed) vehicle.ReadyTime = simulationTime; vehicle.VehicleState = VehicleState.Waiting; interruptable = diversionAllowed; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); } double waitTime = Math.Min(tickTime, order.DeliveryReadyTime - simulationTime); simulationTime += waitTime; tickTime -= waitTime; } //deliver if (simulationTime >= order.DeliveryReadyTime && tickTime > 0) { if (vehicle.VehicleState != VehicleState.Servicing) { if (diversionAllowed) { vehicle.ReadyTime = simulationTime; vehicle.ReadyTime += order.DeliveryServiceTime; } vehicle.VehicleState = VehicleState.Servicing; interruptable = false; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); } if (order.OrderState != OrderState.Delivering) { order.OrderState = OrderState.Delivering; changes.Add(new PDChange() { ChangeType = SimulationStateChange.OrderState, BaseObject = order }); } if (serviceTime == 0 && simulationTime > order.DeliveryDueTime) { order.Tardiness += simulationTime - order.DeliveryDueTime; } double service = Math.Min(tickTime, order.DeliveryServiceTime - serviceTime); serviceTime += service; simulationTime += service; tickTime -= service; //load if (serviceTime == order.DeliveryServiceTime) { vehicle.Capacity += order.Demand; vehicle.PickedUpOrders.Remove(order.Id); order.OrderState = OrderState.Delivered; changes.Add(new PDChange() { ChangeType = SimulationStateChange.OrderState, BaseObject = order }); vehicle.VehicleState = VehicleState.Waiting; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); completed = true; } } } else if (action == VehicleAction.Park) { completed = true; if (vehicle.VehicleState != VehicleState.Parked) { vehicle.VehicleState = VehicleState.Parked; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); if (vehicle.PositionX == vehicle.DepotX && vehicle.PositionY == vehicle.DepotY) { if (simulationTime > vehicle.DueTime) { vehicle.Tardiness = simulationTime - vehicle.DueTime; } } } } else if (action == VehicleAction.Wait) { completed = true; if (vehicle.VehicleState != VehicleState.Waiting) { vehicle.VehicleState = VehicleState.Waiting; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); } } else if (action == VehicleAction.Invalid) { completed = true; if (vehicle.VehicleState != VehicleState.InvalidAction) { vehicle.VehicleState = VehicleState.InvalidAction; changes.Add(new PDChange() { ChangeType = SimulationStateChange.VehicleState, BaseObject = baseObject }); } } } return simulationTime; } } } }