mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
vis
This commit is contained in:
parent
9c857962d6
commit
b702c8015b
2 changed files with 394 additions and 57 deletions
|
|
@ -24,14 +24,15 @@ import jsprit.core.algorithm.recreate.listener.BeforeJobInsertionListener;
|
||||||
import jsprit.core.algorithm.recreate.listener.InsertionEndsListener;
|
import jsprit.core.algorithm.recreate.listener.InsertionEndsListener;
|
||||||
import jsprit.core.algorithm.recreate.listener.InsertionStartsListener;
|
import jsprit.core.algorithm.recreate.listener.InsertionStartsListener;
|
||||||
import jsprit.core.algorithm.ruin.listener.RuinListener;
|
import jsprit.core.algorithm.ruin.listener.RuinListener;
|
||||||
|
import jsprit.core.problem.AbstractActivity;
|
||||||
import jsprit.core.problem.VehicleRoutingProblem;
|
import jsprit.core.problem.VehicleRoutingProblem;
|
||||||
import jsprit.core.problem.job.Job;
|
import jsprit.core.problem.job.*;
|
||||||
import jsprit.core.problem.job.Service;
|
|
||||||
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||||
import jsprit.core.problem.vehicle.Vehicle;
|
import jsprit.core.problem.vehicle.Vehicle;
|
||||||
import jsprit.core.problem.vehicle.VehicleImpl;
|
import jsprit.core.problem.vehicle.VehicleImpl;
|
||||||
|
import jsprit.core.util.Coordinate;
|
||||||
import jsprit.core.util.Solutions;
|
import jsprit.core.util.Solutions;
|
||||||
import org.graphstream.graph.Edge;
|
import org.graphstream.graph.Edge;
|
||||||
import org.graphstream.graph.Graph;
|
import org.graphstream.graph.Graph;
|
||||||
|
|
@ -43,11 +44,19 @@ import java.io.File;
|
||||||
import java.io.FileWriter;
|
import java.io.FileWriter;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
|
||||||
public class AlgorithmEventRecorder implements RuinListener, IterationStartsListener, InsertionStartsListener, BeforeJobInsertionListener, InsertionEndsListener, AlgorithmEndsListener {
|
public class AlgorithmEventRecorder implements RuinListener, IterationStartsListener, InsertionStartsListener, BeforeJobInsertionListener, InsertionEndsListener, AlgorithmEndsListener {
|
||||||
|
|
||||||
|
private boolean renderShipments = false;
|
||||||
|
|
||||||
|
public static void writeSolution(VehicleRoutingProblem vrp, VehicleRoutingProblemSolution solution, File outfile){
|
||||||
|
AlgorithmEventRecorder rec = new AlgorithmEventRecorder(vrp,outfile);
|
||||||
|
rec.initialiseGraph(vrp);
|
||||||
|
rec.addRoutes(solution.getRoutes());
|
||||||
|
rec.finish();
|
||||||
|
}
|
||||||
|
|
||||||
public static enum RecordPolicy {
|
public static enum RecordPolicy {
|
||||||
RECORD_AND_WRITE
|
RECORD_AND_WRITE
|
||||||
|
|
@ -75,7 +84,10 @@ public class AlgorithmEventRecorder implements RuinListener, IterationStartsList
|
||||||
|
|
||||||
private int currentIteration = 0;
|
private int currentIteration = 0;
|
||||||
|
|
||||||
|
private VehicleRoutingProblem vrp;
|
||||||
|
|
||||||
public AlgorithmEventRecorder(VehicleRoutingProblem vrp, File outfile) {
|
public AlgorithmEventRecorder(VehicleRoutingProblem vrp, File outfile) {
|
||||||
|
this.vrp = vrp;
|
||||||
graph = new MultiGraph("g");
|
graph = new MultiGraph("g");
|
||||||
try {
|
try {
|
||||||
writer = new FileWriter(outfile);
|
writer = new FileWriter(outfile);
|
||||||
|
|
@ -88,6 +100,11 @@ public class AlgorithmEventRecorder implements RuinListener, IterationStartsList
|
||||||
initialiseGraph(vrp);
|
initialiseGraph(vrp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AlgorithmEventRecorder(VehicleRoutingProblem vrp, File outfile, boolean renderShipments) {
|
||||||
|
this.renderShipments = renderShipments;
|
||||||
|
new AlgorithmEventRecorder(vrp,outfile);
|
||||||
|
}
|
||||||
|
|
||||||
public void setRecordingRange(int startIteration, int endIteration){
|
public void setRecordingRange(int startIteration, int endIteration){
|
||||||
this.start_recording_at = startIteration;
|
this.start_recording_at = startIteration;
|
||||||
this.end_recording_at = endIteration;
|
this.end_recording_at = endIteration;
|
||||||
|
|
@ -114,23 +131,41 @@ public class AlgorithmEventRecorder implements RuinListener, IterationStartsList
|
||||||
public void ruinStarts(Collection<VehicleRoute> routes) {
|
public void ruinStarts(Collection<VehicleRoute> routes) {
|
||||||
if(!record()) return;
|
if(!record()) return;
|
||||||
fileSink.stepBegins(graph.getId(),0,BEFORE_RUIN_RENDER_SOLUTION);
|
fileSink.stepBegins(graph.getId(),0,BEFORE_RUIN_RENDER_SOLUTION);
|
||||||
recordRoutes(routes);
|
addRoutes(routes);
|
||||||
fileSink.stepBegins(graph.getId(),0,RUIN);
|
fileSink.stepBegins(graph.getId(),0,RUIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void recordRoutes(Collection<VehicleRoute> routes) {
|
private void addRoutes(Collection<VehicleRoute> routes) {
|
||||||
for(VehicleRoute route : routes){
|
for(VehicleRoute route : routes){
|
||||||
String prevNode = makeStartId(route.getVehicle());
|
String prevNode = makeStartId(route.getVehicle());
|
||||||
for(TourActivity act : route.getActivities()){
|
for(TourActivity act : route.getActivities()){
|
||||||
String actNode = ((TourActivity.JobActivity)act).getJob().getId();
|
String actNodeId = getNodeId(act);
|
||||||
addEdge(prevNode+"_"+actNode,prevNode,actNode);
|
addEdge(prevNode+"_"+actNodeId,prevNode,actNodeId);
|
||||||
prevNode = actNode;
|
prevNode = actNodeId;
|
||||||
}
|
}
|
||||||
String lastNode = makeEndId(route.getVehicle());
|
if(route.getVehicle().isReturnToDepot()) {
|
||||||
addEdge(prevNode+"_"+lastNode,prevNode,lastNode);
|
String lastNode = makeEndId(route.getVehicle());
|
||||||
|
addEdge(prevNode+"_"+lastNode,prevNode,lastNode);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getNodeId(TourActivity act) {
|
||||||
|
String nodeId = null;
|
||||||
|
if(act instanceof TourActivity.JobActivity){
|
||||||
|
Job job = ((TourActivity.JobActivity) act).getJob();
|
||||||
|
if(job instanceof Service){
|
||||||
|
nodeId = job.getId();
|
||||||
|
}
|
||||||
|
else if(job instanceof Shipment){
|
||||||
|
if(act.getName().equals("pickupShipment")) nodeId = getFromNodeId((Shipment) job);
|
||||||
|
else nodeId = getToNodeId((Shipment) job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nodeId;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean record() {
|
private boolean record() {
|
||||||
return currentIteration >= start_recording_at && currentIteration <= end_recording_at;
|
return currentIteration >= start_recording_at && currentIteration <= end_recording_at;
|
||||||
}
|
}
|
||||||
|
|
@ -143,19 +178,99 @@ public class AlgorithmEventRecorder implements RuinListener, IterationStartsList
|
||||||
@Override
|
@Override
|
||||||
public void removed(Job job, VehicleRoute fromRoute) {
|
public void removed(Job job, VehicleRoute fromRoute) {
|
||||||
if(!record()) return;
|
if(!record()) return;
|
||||||
|
if(job instanceof Service) removeService(job, fromRoute);
|
||||||
|
else if(job instanceof Shipment) removeShipment(job,fromRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeShipment(Job job, VehicleRoute fromRoute) {
|
||||||
|
Shipment shipment = (Shipment)job;
|
||||||
|
String fromNodeId = getFromNodeId(shipment);
|
||||||
|
String toNodeId = getToNodeId(shipment);
|
||||||
|
// removeNodeAndBelongingEdges(fromNodeId,fromRoute);
|
||||||
|
// removeNodeAndBelongingEdges(toNodeId,fromRoute);
|
||||||
|
|
||||||
|
Edge enteringToNode = getEnteringEdge(toNodeId);
|
||||||
|
if(enteringToNode.getNode0().getId().equals(fromNodeId)){
|
||||||
|
markRemoved(graph.getNode(fromNodeId));
|
||||||
|
markRemoved(graph.getNode(toNodeId));
|
||||||
|
// i -> from -> to -> j: rem(i,from), rem(from,to), rem(to,j), add(i,j)
|
||||||
|
Edge enteringFromNode = getEnteringEdge(fromNodeId);
|
||||||
|
removeEdge(enteringFromNode.getId());
|
||||||
|
removeEdge(enteringToNode.getId());
|
||||||
|
if(graph.getNode(toNodeId).getLeavingEdgeSet().isEmpty()){
|
||||||
|
if(fromRoute.getVehicle().isReturnToDepot()) throw new IllegalStateException("leaving edge is missing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Edge leavingToNode = getLeavingEdge(toNodeId);
|
||||||
|
removeEdge(leavingToNode.getId());
|
||||||
|
Node from = enteringFromNode.getNode0();
|
||||||
|
Node to = leavingToNode.getNode1();
|
||||||
|
if(!fromRoute.getActivities().isEmpty()){
|
||||||
|
addEdge(makeEdgeId(from,to),from.getId(),to.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
removeNodeAndBelongingEdges(fromNodeId,fromRoute);
|
||||||
|
removeNodeAndBelongingEdges(toNodeId,fromRoute);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Edge getLeavingEdge(String toNodeId) {
|
||||||
|
Collection<Edge> edges = graph.getNode(toNodeId).getLeavingEdgeSet();
|
||||||
|
if(edges.size()==1) return edges.iterator().next();
|
||||||
|
else{
|
||||||
|
for(Edge e : edges){
|
||||||
|
if(e.getId().startsWith("shipment")){ continue; }
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Edge getEnteringEdge(String toNodeId) {
|
||||||
|
Collection<Edge> enteringEdges = graph.getNode(toNodeId).getEnteringEdgeSet();
|
||||||
|
if(enteringEdges.size()==1) return enteringEdges.iterator().next();
|
||||||
|
else{
|
||||||
|
for(Edge e : enteringEdges){
|
||||||
|
if(e.getId().startsWith("shipment")){ continue; }
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getToNodeId(Shipment shipment) {
|
||||||
|
return shipment.getId() + "_delivery";
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getFromNodeId(Shipment shipment) {
|
||||||
|
return shipment.getId() + "_pickup";
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeService(Job job, VehicleRoute fromRoute) {
|
||||||
String nodeId = job.getId();
|
String nodeId = job.getId();
|
||||||
|
removeNodeAndBelongingEdges(nodeId, fromRoute);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeNodeAndBelongingEdges(String nodeId, VehicleRoute fromRoute) {
|
||||||
Node node = graph.getNode(nodeId);
|
Node node = graph.getNode(nodeId);
|
||||||
markRemoved(node);
|
markRemoved(node);
|
||||||
Edge entering = node.getEnteringEdge(0);
|
Edge entering = getEnteringEdge(nodeId);
|
||||||
removeEdge(entering.getId());
|
removeEdge(entering.getId());
|
||||||
Edge leaving = node.getLeavingEdge(0);
|
|
||||||
|
if(node.getLeavingEdgeSet().isEmpty()){
|
||||||
|
if(fromRoute.getVehicle().isReturnToDepot()) throw new IllegalStateException("leaving edge is missing");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Edge leaving = getLeavingEdge(nodeId);
|
||||||
removeEdge((leaving.getId()));
|
removeEdge((leaving.getId()));
|
||||||
Node from = entering.getNode0();
|
Node from = entering.getNode0();
|
||||||
Node to = leaving.getNode1();
|
Node to = leaving.getNode1();
|
||||||
if(!fromRoute.getActivities().isEmpty()){
|
if(!fromRoute.getActivities().isEmpty()){
|
||||||
addEdge(makeEdgeId(from,to),from.getId(),to.getId());
|
addEdge(makeEdgeId(from,to),from.getId(),to.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markRemoved(Node node) {
|
private void markRemoved(Node node) {
|
||||||
|
|
@ -170,7 +285,11 @@ public class AlgorithmEventRecorder implements RuinListener, IterationStartsList
|
||||||
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||||
VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions);
|
VehicleRoutingProblemSolution solution = Solutions.bestOf(solutions);
|
||||||
fileSink.stepBegins(graph.getId(),0,BEFORE_RUIN_RENDER_SOLUTION);
|
fileSink.stepBegins(graph.getId(),0,BEFORE_RUIN_RENDER_SOLUTION);
|
||||||
recordRoutes(solution.getRoutes());
|
addRoutes(solution.getRoutes());
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void finish() {
|
||||||
try {
|
try {
|
||||||
fileSink.end();
|
fileSink.end();
|
||||||
writer.close();
|
writer.close();
|
||||||
|
|
@ -189,10 +308,50 @@ public class AlgorithmEventRecorder implements RuinListener, IterationStartsList
|
||||||
addVehicle(vehicle);
|
addVehicle(vehicle);
|
||||||
}
|
}
|
||||||
for(Job job : problem.getJobs().values()){
|
for(Job job : problem.getJobs().values()){
|
||||||
Service service = (Service)job;
|
addJob(job);
|
||||||
addService(service);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addJob(Job job) {
|
||||||
|
if(job instanceof Service){
|
||||||
|
Service service = (Service)job;
|
||||||
|
addNode(service.getId(), service.getCoord());
|
||||||
|
markService(service);
|
||||||
|
}
|
||||||
|
else if(job instanceof Shipment){
|
||||||
|
Shipment shipment = (Shipment)job;
|
||||||
|
String fromNodeId = getFromNodeId(shipment);
|
||||||
|
addNode(fromNodeId, shipment.getPickupCoord());
|
||||||
|
String toNodeId = getToNodeId(shipment);
|
||||||
|
addNode(toNodeId,shipment.getDeliveryCoord());
|
||||||
|
markShipment(shipment);
|
||||||
|
if(renderShipments) {
|
||||||
|
Edge e = graph.addEdge("shipment_" + fromNodeId + "_" + toNodeId, fromNodeId, toNodeId, true);
|
||||||
|
e.addAttribute("ui.class", "shipment");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markShipment(Shipment shipment) {
|
||||||
|
markPickup(getFromNodeId(shipment));
|
||||||
|
markDelivery(getToNodeId(shipment));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markService(Service service) {
|
||||||
|
if(service instanceof Pickup){
|
||||||
|
markPickup(service.getId());
|
||||||
|
}
|
||||||
|
else if(service instanceof Delivery){
|
||||||
|
markDelivery(service.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markPickup(String id) {
|
||||||
|
graph.getNode(id).addAttribute("ui.class","pickup");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markDelivery(String id) {
|
||||||
|
graph.getNode(id).addAttribute("ui.class","delivery");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addVehicle(Vehicle vehicle) {
|
private void addVehicle(Vehicle vehicle) {
|
||||||
|
|
@ -220,25 +379,31 @@ public class AlgorithmEventRecorder implements RuinListener, IterationStartsList
|
||||||
return vehicle.getId() + "_end";
|
return vehicle.getId() + "_end";
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addService(Service service) {
|
private void addNode(String nodeId, Coordinate nodeCoord) {
|
||||||
Node serviceNode = graph.addNode(service.getId());
|
Node node = graph.addNode(nodeId);
|
||||||
serviceNode.addAttribute("x", service.getCoord().getX());
|
node.addAttribute("x", nodeCoord.getX());
|
||||||
serviceNode.addAttribute("y", service.getCoord().getY());
|
node.addAttribute("y", nodeCoord.getY());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
if(!record()) return;
|
if(!record()) return;
|
||||||
fileSink.stepBegins(graph.getId(),0,CLEAR_SOLUTION);
|
fileSink.stepBegins(graph.getId(),0,CLEAR_SOLUTION);
|
||||||
|
removeRoutes(vehicleRoutes);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeRoutes(Collection<VehicleRoute> vehicleRoutes) {
|
||||||
for(VehicleRoute route : vehicleRoutes){
|
for(VehicleRoute route : vehicleRoutes){
|
||||||
String prevNode = makeStartId(route.getVehicle());
|
String prevNode = makeStartId(route.getVehicle());
|
||||||
for(TourActivity act : route.getActivities()){
|
for(TourActivity act : route.getActivities()){
|
||||||
String actNode = ((TourActivity.JobActivity)act).getJob().getId();
|
String actNode = getNodeId(act);
|
||||||
removeEdge(prevNode + "_" + actNode);
|
removeEdge(prevNode + "_" + actNode);
|
||||||
prevNode = actNode;
|
prevNode = actNode;
|
||||||
}
|
}
|
||||||
String lastNode = makeEndId(route.getVehicle());
|
if(route.getVehicle().isReturnToDepot()) {
|
||||||
removeEdge(prevNode + "_" + lastNode);
|
String lastNode = makeEndId(route.getVehicle());
|
||||||
|
removeEdge(prevNode + "_" + lastNode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,6 +411,66 @@ public class AlgorithmEventRecorder implements RuinListener, IterationStartsList
|
||||||
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route) {
|
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route) {
|
||||||
if(!record()) return;
|
if(!record()) return;
|
||||||
markInserted(job);
|
markInserted(job);
|
||||||
|
handleVehicleSwitch(data, route);
|
||||||
|
insertJob(job, data, route);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertJob(Job job, InsertionData data, VehicleRoute route) {
|
||||||
|
if(job instanceof Service) insertService(job,data,route);
|
||||||
|
else if(job instanceof Shipment) insertShipment(job,data,route);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertShipment(Job job, InsertionData data, VehicleRoute route) {
|
||||||
|
String fromNodeId = getFromNodeId((Shipment) job);
|
||||||
|
String toNodeId = getToNodeId((Shipment) job);
|
||||||
|
insertNode(toNodeId,data.getDeliveryInsertionIndex(),data,route);
|
||||||
|
|
||||||
|
List<AbstractActivity> del = vrp.getActivities(job);
|
||||||
|
VehicleRoute copied = VehicleRoute.copyOf(route);
|
||||||
|
copied.getTourActivities().addActivity(data.getDeliveryInsertionIndex(),del.get(1));
|
||||||
|
|
||||||
|
insertNode(fromNodeId, data.getPickupInsertionIndex(), data, copied);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertService(Job job, InsertionData data, VehicleRoute route) {
|
||||||
|
insertNode(job.getId(), data.getDeliveryInsertionIndex(), data, route);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void insertNode(String nodeId, int insertionIndex, InsertionData data, VehicleRoute route) {
|
||||||
|
// VehicleRoute copied = VehicleRoute.copyOf(route);
|
||||||
|
|
||||||
|
String node_i;
|
||||||
|
|
||||||
|
if(isFirst(insertionIndex,route)) {
|
||||||
|
node_i = makeStartId(data.getSelectedVehicle());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TourActivity.JobActivity jobActivity = (TourActivity.JobActivity) route.getActivities().get(insertionIndex - 1);
|
||||||
|
node_i = getNodeId(jobActivity);
|
||||||
|
}
|
||||||
|
String node_k = nodeId;
|
||||||
|
String edgeId_1 = node_i + "_" + node_k;
|
||||||
|
String node_j;
|
||||||
|
if(isLast(insertionIndex,route)) {
|
||||||
|
node_j = makeEndId(data.getSelectedVehicle());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TourActivity.JobActivity jobActivity = (TourActivity.JobActivity) route.getActivities().get(insertionIndex);
|
||||||
|
node_j = getNodeId(jobActivity);
|
||||||
|
}
|
||||||
|
String edgeId_2 = node_k + "_" + node_j;
|
||||||
|
|
||||||
|
addEdge(edgeId_1, node_i, node_k);
|
||||||
|
|
||||||
|
if(!(isLast(insertionIndex,route) && !data.getSelectedVehicle().isReturnToDepot())) {
|
||||||
|
addEdge(edgeId_2, node_k, node_j);
|
||||||
|
if (!route.getActivities().isEmpty()) {
|
||||||
|
removeEdge(node_i + "_" + node_j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleVehicleSwitch(InsertionData data, VehicleRoute route) {
|
||||||
boolean vehicleSwitch = false;
|
boolean vehicleSwitch = false;
|
||||||
if(!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
if(!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||||
if (!route.getVehicle().getId().equals(data.getSelectedVehicle().getId())) {
|
if (!route.getVehicle().getId().equals(data.getSelectedVehicle().getId())) {
|
||||||
|
|
@ -258,56 +483,55 @@ public class AlgorithmEventRecorder implements RuinListener, IterationStartsList
|
||||||
String oldEnd = makeEndId(route.getVehicle());
|
String oldEnd = makeEndId(route.getVehicle());
|
||||||
String lastAct = ((TourActivity.JobActivity)route.getActivities().get(route.getActivities().size()-1)).getJob().getId();
|
String lastAct = ((TourActivity.JobActivity)route.getActivities().get(route.getActivities().size()-1)).getJob().getId();
|
||||||
removeEdge(oldStart + "_" + firstAct);
|
removeEdge(oldStart + "_" + firstAct);
|
||||||
removeEdge(lastAct + "_" + oldEnd);
|
|
||||||
|
if(route.getVehicle().isReturnToDepot()) {
|
||||||
|
removeEdge(lastAct + "_" + oldEnd);
|
||||||
|
}
|
||||||
|
|
||||||
String newStart = makeStartId(data.getSelectedVehicle());
|
String newStart = makeStartId(data.getSelectedVehicle());
|
||||||
String newEnd = makeEndId(data.getSelectedVehicle());
|
String newEnd = makeEndId(data.getSelectedVehicle());
|
||||||
addEdge(newStart + "_" + firstAct,newStart,firstAct);
|
addEdge(newStart + "_" + firstAct,newStart,firstAct);
|
||||||
addEdge(lastAct + "_" + newEnd, lastAct,newEnd);
|
|
||||||
}
|
|
||||||
String node_i;
|
|
||||||
|
|
||||||
if(isFirst(data,route)) {
|
if(data.getSelectedVehicle().isReturnToDepot()) {
|
||||||
node_i = makeStartId(data.getSelectedVehicle());
|
addEdge(lastAct + "_" + newEnd, lastAct, newEnd);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
node_i = ((TourActivity.JobActivity)route.getActivities().get(data.getDeliveryInsertionIndex()-1)).getJob().getId();
|
|
||||||
}
|
|
||||||
String node_k = job.getId();
|
|
||||||
String edgeId_1 = node_i + "_" + node_k;
|
|
||||||
String node_j;
|
|
||||||
if(isLast(data,route)) {
|
|
||||||
node_j = makeEndId(data.getSelectedVehicle());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
node_j = ((TourActivity.JobActivity)route.getActivities().get(data.getDeliveryInsertionIndex())).getJob().getId();
|
|
||||||
}
|
|
||||||
String edgeId_2 = node_k + "_" + node_j;
|
|
||||||
|
|
||||||
addEdge(edgeId_1, node_i, node_k);
|
|
||||||
addEdge(edgeId_2, node_k, node_j);
|
|
||||||
if(!route.getActivities().isEmpty()){
|
|
||||||
removeEdge(node_i + "_" + node_j);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void markInserted(Job job) {
|
private void markInserted(Job job) {
|
||||||
graph.getNode(job.getId()).removeAttribute("ui.class");
|
if(job instanceof Service){
|
||||||
|
markService((Service) job);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
markShipment((Shipment)job);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeEdge(String edgeId) {
|
private void removeEdge(String edgeId) {
|
||||||
|
markEdgeRemoved(edgeId);
|
||||||
graph.removeEdge(edgeId);
|
graph.removeEdge(edgeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isFirst(InsertionData data, VehicleRoute route) {
|
private void markEdgeRemoved(String edgeId) {
|
||||||
return data.getDeliveryInsertionIndex() == 0;
|
graph.getEdge(edgeId).addAttribute("ui.class","removed");
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isLast(InsertionData data, VehicleRoute route) {
|
private boolean isFirst(int index, VehicleRoute route) {
|
||||||
return data.getDeliveryInsertionIndex() == route.getActivities().size();
|
return index == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isLast(int index, VehicleRoute route) {
|
||||||
|
return index == route.getActivities().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addEdge(String edgeId, String fromNode, String toNode) {
|
private void addEdge(String edgeId, String fromNode, String toNode) {
|
||||||
graph.addEdge(edgeId,fromNode,toNode,true);
|
graph.addEdge(edgeId,fromNode,toNode,true);
|
||||||
|
markEdgeInserted(edgeId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void markEdgeInserted(String edgeId) {
|
||||||
|
graph.getEdge(edgeId).addAttribute("ui.class","inserted");
|
||||||
|
graph.getEdge(edgeId).removeAttribute("ui.class");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -33,16 +33,95 @@ import org.graphstream.graph.Edge;
|
||||||
import org.graphstream.graph.Graph;
|
import org.graphstream.graph.Graph;
|
||||||
import org.graphstream.graph.Node;
|
import org.graphstream.graph.Node;
|
||||||
import org.graphstream.graph.implementations.MultiGraph;
|
import org.graphstream.graph.implementations.MultiGraph;
|
||||||
|
import org.graphstream.stream.Sink;
|
||||||
|
import org.graphstream.stream.file.FileSinkImages;
|
||||||
import org.graphstream.ui.swingViewer.View;
|
import org.graphstream.ui.swingViewer.View;
|
||||||
import org.graphstream.ui.swingViewer.Viewer;
|
import org.graphstream.ui.swingViewer.Viewer;
|
||||||
|
|
||||||
import javax.swing.*;
|
import javax.swing.*;
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
|
||||||
public class GraphStreamViewer {
|
public class GraphStreamViewer {
|
||||||
|
|
||||||
|
private static class EmptySink implements Sink {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void graphAttributeAdded(String sourceId, long timeId, String attribute, Object value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void graphAttributeChanged(String sourceId, long timeId, String attribute, Object oldValue, Object newValue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void graphAttributeRemoved(String sourceId, long timeId, String attribute) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nodeAttributeAdded(String sourceId, long timeId, String nodeId, String attribute, Object value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nodeAttributeChanged(String sourceId, long timeId, String nodeId, String attribute, Object oldValue, Object newValue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nodeAttributeRemoved(String sourceId, long timeId, String nodeId, String attribute) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void edgeAttributeAdded(String sourceId, long timeId, String edgeId, String attribute, Object value) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void edgeAttributeChanged(String sourceId, long timeId, String edgeId, String attribute, Object oldValue, Object newValue) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void edgeAttributeRemoved(String sourceId, long timeId, String edgeId, String attribute) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nodeAdded(String sourceId, long timeId, String nodeId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void nodeRemoved(String sourceId, long timeId, String nodeId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void edgeAdded(String sourceId, long timeId, String edgeId, String fromNodeId, String toNodeId, boolean directed) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void edgeRemoved(String sourceId, long timeId, String edgeId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void graphCleared(String sourceId, long timeId) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void stepBegins(String sourceId, long timeId, double step) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static Graph createMultiGraph(String name, String style){
|
public static Graph createMultiGraph(String name, String style){
|
||||||
Graph g = new MultiGraph(name);
|
Graph g = new MultiGraph(name);
|
||||||
|
|
@ -143,6 +222,12 @@ public class GraphStreamViewer {
|
||||||
|
|
||||||
private double scaling = 1.0;
|
private double scaling = 1.0;
|
||||||
|
|
||||||
|
private boolean createImageByEvent = false;
|
||||||
|
|
||||||
|
private File imageDirectory;
|
||||||
|
|
||||||
|
Sink fsi = new EmptySink();
|
||||||
|
|
||||||
public GraphStreamViewer(VehicleRoutingProblem vrp) {
|
public GraphStreamViewer(VehicleRoutingProblem vrp) {
|
||||||
super();
|
super();
|
||||||
this.vrp = vrp;
|
this.vrp = vrp;
|
||||||
|
|
@ -159,6 +244,12 @@ public class GraphStreamViewer {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public GraphStreamViewer createImagesByEvent(boolean createImanges, File outDirectory){
|
||||||
|
createImageByEvent = true;
|
||||||
|
imageDirectory = outDirectory;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public GraphStreamViewer setRenderDelay(long ms){
|
public GraphStreamViewer setRenderDelay(long ms){
|
||||||
this.renderDelay_in_ms=ms;
|
this.renderDelay_in_ms=ms;
|
||||||
return this;
|
return this;
|
||||||
|
|
@ -204,7 +295,21 @@ public class GraphStreamViewer {
|
||||||
|
|
||||||
JFrame jframe = createJFrame(view,scaling);
|
JFrame jframe = createJFrame(view,scaling);
|
||||||
|
|
||||||
render(g,view);
|
Sink fsi;
|
||||||
|
if(createImageByEvent){
|
||||||
|
FileSinkImages.OutputPolicy outputPolicy = FileSinkImages.OutputPolicy.BY_ELEMENT_EVENT;
|
||||||
|
String prefix = "screenshot_";
|
||||||
|
FileSinkImages.OutputType type = FileSinkImages.OutputType.PNG;
|
||||||
|
FileSinkImages.Resolution resolution = FileSinkImages.Resolutions.HD720;
|
||||||
|
fsi = new FileSinkImages( type, resolution );
|
||||||
|
((FileSinkImages)fsi).setStyleSheet(STYLESHEET);
|
||||||
|
((FileSinkImages)fsi).setOutputPolicy(outputPolicy);
|
||||||
|
((FileSinkImages)fsi).setLayoutPolicy(FileSinkImages.LayoutPolicy.NO_LAYOUT);
|
||||||
|
((FileSinkImages)fsi).setQuality(FileSinkImages.Quality.HIGH);
|
||||||
|
((FileSinkImages)fsi).setRenderer(FileSinkImages.RendererType.SCALA);
|
||||||
|
}
|
||||||
|
|
||||||
|
render(g, view);
|
||||||
}
|
}
|
||||||
|
|
||||||
private JFrame createJFrame(View view, double scaling) {
|
private JFrame createJFrame(View view, double scaling) {
|
||||||
|
|
@ -254,8 +359,7 @@ public class GraphStreamViewer {
|
||||||
private void render(Graph g, View view) {
|
private void render(Graph g, View view) {
|
||||||
if(center != null){
|
if(center != null){
|
||||||
view.resizeFrame(view.getWidth(), view.getHeight());
|
view.resizeFrame(view.getWidth(), view.getHeight());
|
||||||
view.getCamera().setViewCenter(center.x, center.y, 0);
|
alignCamera(view);
|
||||||
view.getCamera().setViewPercent(zoomFactor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for(Vehicle vehicle : vrp.getVehicles()){
|
for(Vehicle vehicle : vrp.getVehicles()){
|
||||||
|
|
@ -284,7 +388,16 @@ public class GraphStreamViewer {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private JLabel createEmptyLabel() {
|
private void alignCamera(View view) {
|
||||||
|
view.getCamera().setViewCenter(center.x, center.y, 0);
|
||||||
|
view.getCamera().setViewPercent(zoomFactor);
|
||||||
|
if(fsi instanceof FileSinkImages){
|
||||||
|
((FileSinkImages) fsi).setViewCenter(center.x, center.y);
|
||||||
|
((FileSinkImages) fsi).setViewPercent(zoomFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private JLabel createEmptyLabel() {
|
||||||
JLabel emptyLabel1 = new JLabel();
|
JLabel emptyLabel1 = new JLabel();
|
||||||
emptyLabel1.setPreferredSize(new Dimension((int)(40*scaling),(int)(25*scaling)));
|
emptyLabel1.setPreferredSize(new Dimension((int)(40*scaling),(int)(25*scaling)));
|
||||||
return emptyLabel1;
|
return emptyLabel1;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue