mirror of
https://github.com/graphhopper/jsprit.git
synced 2020-01-24 07:45:05 +01:00
graph vis
This commit is contained in:
parent
6a1631fc9a
commit
006aa561cf
4 changed files with 425 additions and 54 deletions
|
|
@ -0,0 +1,27 @@
|
|||
package jsprit.analysis.toolbox;
|
||||
|
||||
import jsprit.core.algorithm.VehicleRoutingAlgorithm;
|
||||
import jsprit.core.algorithm.box.GreedySchrimpfFactory;
|
||||
import jsprit.core.problem.VehicleRoutingProblem;
|
||||
import jsprit.core.problem.io.VrpXMLReader;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Created by stefan on 14.11.14.
|
||||
*/
|
||||
public class AnotherGraphTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
VehicleRoutingProblem.Builder vrpBuilder = VehicleRoutingProblem.Builder.newInstance();
|
||||
new VrpXMLReader(vrpBuilder).read("/Users/stefan/Documents/git-repositories/jsprit/jsprit-examples/input/cordeau01.xml");
|
||||
VehicleRoutingProblem vrp = vrpBuilder.build();
|
||||
|
||||
// GraphStreamEventWriter eventWriter = new GraphStreamEventWriter(new File("output/events.txt"));
|
||||
VehicleRoutingAlgorithm vra = new GreedySchrimpfFactory().createAlgorithm(vrp);
|
||||
// vra.addListener(eventWriter);
|
||||
|
||||
vra.searchSolutions();
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,321 @@
|
|||
package jsprit.analysis.toolbox;
|
||||
|
||||
import jsprit.core.algorithm.listener.AlgorithmEndsListener;
|
||||
import jsprit.core.algorithm.recreate.InsertionData;
|
||||
import jsprit.core.algorithm.recreate.listener.BeforeJobInsertionListener;
|
||||
import jsprit.core.algorithm.recreate.listener.InsertionEndsListener;
|
||||
import jsprit.core.algorithm.ruin.listener.RuinListener;
|
||||
import jsprit.core.problem.VehicleRoutingProblem;
|
||||
import jsprit.core.problem.job.Job;
|
||||
import jsprit.core.problem.job.Service;
|
||||
import jsprit.core.problem.solution.VehicleRoutingProblemSolution;
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
import jsprit.core.problem.vehicle.Vehicle;
|
||||
import jsprit.core.problem.vehicle.VehicleImpl;
|
||||
import org.graphstream.graph.Edge;
|
||||
import org.graphstream.graph.Graph;
|
||||
import org.graphstream.graph.Node;
|
||||
import org.graphstream.graph.implementations.MultiGraph;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Created by stefan on 14.11.14.
|
||||
*/
|
||||
public class GraphStreamEventWriter implements RuinListener, BeforeJobInsertionListener, InsertionEndsListener, AlgorithmEndsListener {
|
||||
|
||||
|
||||
static class Edges {
|
||||
|
||||
String inEdgeId;
|
||||
|
||||
String outEdgeId;
|
||||
|
||||
Edges(String inEdgeId, String outEdgeId) {
|
||||
this.inEdgeId = inEdgeId;
|
||||
this.outEdgeId = outEdgeId;
|
||||
}
|
||||
}
|
||||
|
||||
private File outfile;
|
||||
|
||||
private FileWriter writer;
|
||||
|
||||
private Map<String,Edges> in_out_edges = new HashMap<String,Edges>();
|
||||
|
||||
private Graph graph;
|
||||
|
||||
private VehicleRoutingProblem vrp;
|
||||
|
||||
private boolean notInitialized = true;
|
||||
|
||||
public GraphStreamEventWriter(VehicleRoutingProblem vrp, File outfile) {
|
||||
this.outfile = outfile;
|
||||
this.vrp = vrp;
|
||||
graph = new MultiGraph("g");
|
||||
try {
|
||||
writer = new FileWriter(outfile);
|
||||
writeHead();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
initialiseGraph(vrp);
|
||||
}
|
||||
|
||||
public GraphStreamEventWriter(VehicleRoutingProblem vrp, VehicleRoutingProblemSolution initialSolution, File outfile) {
|
||||
this.outfile = outfile;
|
||||
this.vrp = vrp;
|
||||
graph = new MultiGraph("g");
|
||||
try {
|
||||
writer = new FileWriter(outfile);
|
||||
writeHead();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
initialiseGraph(vrp,initialSolution);
|
||||
}
|
||||
|
||||
private void initialiseGraph(VehicleRoutingProblem vrp, VehicleRoutingProblemSolution initialSolution) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ruinStarts(Collection<VehicleRoute> routes) {
|
||||
for(VehicleRoute route : routes){
|
||||
String prevNode = makeStartId(route.getVehicle());
|
||||
for(TourActivity act : route.getActivities()){
|
||||
String actNode = ((TourActivity.JobActivity)act).getJob().getId();
|
||||
addEdge(prevNode+"_"+actNode,prevNode,actNode);
|
||||
prevNode = actNode;
|
||||
}
|
||||
String lastNode = makeEndId(route.getVehicle());
|
||||
addEdge(prevNode+"_"+lastNode,prevNode,lastNode);
|
||||
}
|
||||
}
|
||||
|
||||
private void removeNode(Node node) {
|
||||
graph.removeNode(node);
|
||||
String eventString = "dn " + node.getId() + "\n";
|
||||
System.out.print(eventString);
|
||||
try {
|
||||
writer.write(eventString);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ruinEnds(Collection<VehicleRoute> routes, Collection<Job> unassignedJobs) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removed(Job job, VehicleRoute fromRoute) {
|
||||
System.out.println("remove job " + job.getId());
|
||||
String nodeId = job.getId();
|
||||
Node node = graph.getNode(nodeId);
|
||||
|
||||
markRemoved(node);
|
||||
|
||||
Edge entering = node.getEnteringEdge(0);
|
||||
removeEdge(entering.getId());
|
||||
Edge leaving = node.getLeavingEdge(0);
|
||||
removeEdge((leaving.getId()));
|
||||
Node from = entering.getNode0();
|
||||
Node to = leaving.getNode1();
|
||||
if(!fromRoute.getActivities().isEmpty()){
|
||||
addEdge(makeEdgeId(from,to),from.getId(),to.getId());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void markRemoved(Node node) {
|
||||
node.setAttribute("ui.class","removed");
|
||||
try {
|
||||
writer.write("cn " + node.getId() + " ui.class:removed\n");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String makeEdgeId(Node from, Node to) {
|
||||
return from.getId() + "_" + to.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informAlgorithmEnds(VehicleRoutingProblem problem, Collection<VehicleRoutingProblemSolution> solutions) {
|
||||
try {
|
||||
writer.close();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void writeHead() throws IOException {
|
||||
writer.write("DGS004\n");
|
||||
writer.write("null 0 0\n");
|
||||
}
|
||||
|
||||
private void initialiseGraph(VehicleRoutingProblem problem) {
|
||||
for(Vehicle vehicle : problem.getVehicles()){
|
||||
addVehicle(vehicle);
|
||||
}
|
||||
for(Job job : problem.getJobs().values()){
|
||||
Service service = (Service)job;
|
||||
addService(service);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void addVehicle(Vehicle vehicle) {
|
||||
try {
|
||||
String startId = makeStartId(vehicle);
|
||||
String startNodeEventString = "an " + startId + " x:" + vehicle.getStartLocationCoordinate().getX() + " y:"
|
||||
+ vehicle.getStartLocationCoordinate().getY() + " ui.class:depot\n";
|
||||
System.out.print(startNodeEventString);
|
||||
writer.write(startNodeEventString);
|
||||
graph.addNode(startId);
|
||||
String endId = makeEndId(vehicle);
|
||||
if(!startId.equals(endId)){
|
||||
String endNodeEventString = "an " + endId + " x:" + vehicle.getEndLocationCoordinate().getX() + " y:"
|
||||
+ vehicle.getEndLocationCoordinate().getY() + " ui.class:depot\n";
|
||||
System.out.print(endNodeEventString);
|
||||
writer.write( endNodeEventString);
|
||||
graph.addNode(endId);
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private String makeStartId(Vehicle vehicle) {
|
||||
return vehicle.getId() + "_start";
|
||||
}
|
||||
|
||||
private String makeEndId(Vehicle vehicle) {
|
||||
if(vehicle.getStartLocationId().equals(vehicle.getEndLocationId())) return makeStartId(vehicle);
|
||||
return vehicle.getId() + "_end";
|
||||
}
|
||||
|
||||
private void addService(Service service) {
|
||||
try {
|
||||
String eventString = "an " + service.getId() + " x:" + service.getCoord().getX() + " y:" + service.getCoord().getY() + "\n";
|
||||
System.out.print(eventString);
|
||||
writer.write(eventString);
|
||||
graph.addNode(service.getId());
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informInsertionEnds(Collection<VehicleRoute> vehicleRoutes) {
|
||||
for(VehicleRoute route : vehicleRoutes){
|
||||
String prevNode = makeStartId(route.getVehicle());
|
||||
for(TourActivity act : route.getActivities()){
|
||||
String actNode = ((TourActivity.JobActivity)act).getJob().getId();
|
||||
removeEdge(prevNode + "_" + actNode);
|
||||
prevNode = actNode;
|
||||
}
|
||||
String lastNode = makeEndId(route.getVehicle());
|
||||
removeEdge(prevNode + "_" + lastNode);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route) {
|
||||
System.out.println("insert job " + job.getId());
|
||||
markInserted(job);
|
||||
boolean vehicleSwitch = false;
|
||||
if(!(route.getVehicle() instanceof VehicleImpl.NoVehicle)) {
|
||||
if (!route.getVehicle().getId().equals(data.getSelectedVehicle().getId())) {
|
||||
vehicleSwitch = true;
|
||||
}
|
||||
}
|
||||
if(vehicleSwitch && !route.getActivities().isEmpty()){
|
||||
System.out.println("switch vehicle " + route.getVehicle().getId() + " --> " + data.getSelectedVehicle().getId());
|
||||
String oldStart = makeStartId(route.getVehicle());
|
||||
String firstAct = ((TourActivity.JobActivity)route.getActivities().get(0)).getJob().getId();
|
||||
String oldEnd = makeEndId(route.getVehicle());
|
||||
String lastAct = ((TourActivity.JobActivity)route.getActivities().get(route.getActivities().size()-1)).getJob().getId();
|
||||
removeEdge(oldStart + "_" + firstAct);
|
||||
removeEdge(lastAct + "_" + oldEnd);
|
||||
String newStart = makeStartId(data.getSelectedVehicle());
|
||||
String newEnd = makeEndId(data.getSelectedVehicle());
|
||||
addEdge(newStart + "_" + firstAct,newStart,firstAct);
|
||||
addEdge(lastAct + "_" + newEnd, lastAct,newEnd);
|
||||
}
|
||||
String node_i;
|
||||
|
||||
if(isFirst(data,route)) {
|
||||
node_i = makeStartId(data.getSelectedVehicle());
|
||||
}
|
||||
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) {
|
||||
graph.getNode(job.getId()).removeAttribute("ui.class");
|
||||
try {
|
||||
writer.write("cn " + job.getId() + " -ui.class\n");
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void removeEdge(String edgeId) {
|
||||
try {
|
||||
String eventString = "de " + edgeId + "\n";
|
||||
System.out.print(eventString);
|
||||
writer.write(eventString);
|
||||
graph.removeEdge(edgeId);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFirst(InsertionData data, VehicleRoute route) {
|
||||
return data.getDeliveryInsertionIndex() == 0;
|
||||
}
|
||||
|
||||
private boolean isLast(InsertionData data, VehicleRoute route) {
|
||||
return data.getDeliveryInsertionIndex() == route.getActivities().size();
|
||||
}
|
||||
|
||||
private void addEdge(String edgeId, String fromNode, String toNode) {
|
||||
try {
|
||||
String eventString = "ae " + edgeId + " " + fromNode + " > " + toNode + "\n";
|
||||
System.out.print(eventString);
|
||||
writer.write(eventString);
|
||||
graph.addEdge(edgeId,fromNode,toNode,true);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -27,7 +27,6 @@ import jsprit.core.problem.solution.route.activity.DeliveryActivity;
|
|||
import jsprit.core.problem.solution.route.activity.PickupActivity;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity;
|
||||
import jsprit.core.problem.solution.route.activity.TourActivity.JobActivity;
|
||||
import jsprit.core.problem.vehicle.PenaltyVehicleType;
|
||||
import jsprit.core.problem.vehicle.Vehicle;
|
||||
import jsprit.core.util.Time;
|
||||
import org.graphstream.graph.Edge;
|
||||
|
|
@ -44,7 +43,7 @@ import java.awt.*;
|
|||
|
||||
public class GraphStreamViewer {
|
||||
|
||||
protected static String styleSheet =
|
||||
public static String STYLESHEET =
|
||||
"node {" +
|
||||
" size: 10px, 10px;" +
|
||||
" fill-color: #6CC644;" +
|
||||
|
|
@ -79,6 +78,13 @@ public class GraphStreamViewer {
|
|||
" size: 10px, 10px;" +
|
||||
" shape: box;" +
|
||||
"}" +
|
||||
"node.removed {" +
|
||||
" fill-color: #BD2C00;" +
|
||||
" size: 10px, 10px;" +
|
||||
" stroke-mode: plain;" +
|
||||
" stroke-color: #333;" +
|
||||
" stroke-width: 2.0;" +
|
||||
"}" +
|
||||
|
||||
"edge {" +
|
||||
" fill-color: #333;" +
|
||||
|
|
@ -175,57 +181,72 @@ public class GraphStreamViewer {
|
|||
|
||||
public void display(){
|
||||
System.setProperty("org.graphstream.ui.renderer", "org.graphstream.ui.j2dviewer.J2DGraphRenderer");
|
||||
|
||||
JFrame jframe = new JFrame();
|
||||
|
||||
JPanel basicPanel = new JPanel();
|
||||
basicPanel.setLayout(new BoxLayout(basicPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
//result-panel
|
||||
JPanel resultPanel = createResultPanel();
|
||||
//graphstream-panel
|
||||
Graph g = new MultiGraph("g");
|
||||
g.addAttribute("ui.quality");
|
||||
g.addAttribute("ui.antialias");
|
||||
g.addAttribute("ui.stylesheet", styleSheet);
|
||||
|
||||
JPanel graphStreamPanel = new JPanel();
|
||||
graphStreamPanel.setPreferredSize(new Dimension((int)(800*scaling),(int)(460*scaling)));
|
||||
graphStreamPanel.setBackground(Color.WHITE);
|
||||
|
||||
JPanel graphStreamBackPanel = new JPanel();
|
||||
graphStreamBackPanel.setPreferredSize(new Dimension((int)(700*scaling),(int)(450*scaling)));
|
||||
graphStreamBackPanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
|
||||
graphStreamBackPanel.setBackground(Color.WHITE);
|
||||
|
||||
Viewer viewer = new Viewer(g,Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
|
||||
View view = viewer.addDefaultView(false);
|
||||
view.setPreferredSize(new Dimension((int)(698*scaling),(int)(440*scaling)));
|
||||
|
||||
graphStreamBackPanel.add(view);
|
||||
graphStreamPanel.add(graphStreamBackPanel);
|
||||
|
||||
//setup basicPanel
|
||||
basicPanel.add(resultPanel);
|
||||
basicPanel.add(graphStreamPanel);
|
||||
// basicPanel.add(legendPanel);
|
||||
|
||||
//put it together
|
||||
jframe.add(basicPanel);
|
||||
|
||||
//conf jframe
|
||||
jframe.setSize((int)(800*scaling),(int)(580*scaling));
|
||||
jframe.setLocationRelativeTo(null);
|
||||
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
jframe.setVisible(true);
|
||||
jframe.pack();
|
||||
jframe.setTitle("jsprit - GraphStream");
|
||||
|
||||
//start rendering graph
|
||||
render(g,view);
|
||||
Graph g = createMultiGraph("g");
|
||||
|
||||
View view = createEmbeddedView(g);
|
||||
|
||||
JFrame jframe = createJFrame(view);
|
||||
|
||||
render(g,view);
|
||||
}
|
||||
|
||||
private void render(Graph g, View view) {
|
||||
public JFrame createJFrame(View view) {
|
||||
JFrame jframe = new JFrame();
|
||||
JPanel basicPanel = new JPanel();
|
||||
basicPanel.setLayout(new BoxLayout(basicPanel, BoxLayout.Y_AXIS));
|
||||
|
||||
//result-panel
|
||||
JPanel resultPanel = createResultPanel();
|
||||
//graphstream-panel
|
||||
|
||||
|
||||
JPanel graphStreamPanel = new JPanel();
|
||||
graphStreamPanel.setPreferredSize(new Dimension((int)(800*scaling),(int)(460*scaling)));
|
||||
graphStreamPanel.setBackground(Color.WHITE);
|
||||
|
||||
JPanel graphStreamBackPanel = new JPanel();
|
||||
graphStreamBackPanel.setPreferredSize(new Dimension((int)(700*scaling),(int)(450*scaling)));
|
||||
graphStreamBackPanel.setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
|
||||
graphStreamBackPanel.setBackground(Color.WHITE);
|
||||
|
||||
graphStreamBackPanel.add(view);
|
||||
graphStreamPanel.add(graphStreamBackPanel);
|
||||
|
||||
//setup basicPanel
|
||||
basicPanel.add(resultPanel);
|
||||
basicPanel.add(graphStreamPanel);
|
||||
// basicPanel.add(legendPanel);
|
||||
|
||||
//put it together
|
||||
jframe.add(basicPanel);
|
||||
|
||||
//conf jframe
|
||||
jframe.setSize((int)(800*scaling),(int)(580*scaling));
|
||||
jframe.setLocationRelativeTo(null);
|
||||
jframe.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
|
||||
jframe.setVisible(true);
|
||||
jframe.pack();
|
||||
jframe.setTitle("jsprit - GraphStream");
|
||||
return jframe;
|
||||
}
|
||||
|
||||
public View createEmbeddedView(Graph g) {
|
||||
Viewer viewer = new Viewer(g,Viewer.ThreadingModel.GRAPH_IN_ANOTHER_THREAD);
|
||||
View view = viewer.addDefaultView(false);
|
||||
view.setPreferredSize(new Dimension((int)(698*scaling),(int)(440*scaling)));
|
||||
return view;
|
||||
}
|
||||
|
||||
public Graph createMultiGraph(String name) {
|
||||
Graph g = new MultiGraph(name);
|
||||
g.addAttribute("ui.quality");
|
||||
g.addAttribute("ui.antialias");
|
||||
g.addAttribute("ui.stylesheet", STYLESHEET);
|
||||
return g;
|
||||
}
|
||||
|
||||
private void render(Graph g, View view) {
|
||||
if(center != null){
|
||||
view.resizeFrame(view.getWidth(), view.getHeight());
|
||||
view.getCamera().setViewCenter(center.x, center.y, 0);
|
||||
|
|
@ -284,7 +305,10 @@ public class GraphStreamViewer {
|
|||
jobs.setFont(font);
|
||||
jobs.setPreferredSize(new Dimension((int)(40*scaling),(int)(25*scaling)));
|
||||
|
||||
JFormattedTextField nJobs = new JFormattedTextField(this.vrp.getJobs().values().size());
|
||||
int noJobs = 0;
|
||||
if(this.vrp != null) noJobs = this.vrp.getJobs().values().size();
|
||||
|
||||
JFormattedTextField nJobs = new JFormattedTextField(noJobs);
|
||||
nJobs.setFont(font);
|
||||
nJobs.setEditable(false);
|
||||
nJobs.setBorder(BorderFactory.createEmptyBorder());
|
||||
|
|
@ -393,8 +417,7 @@ public class GraphStreamViewer {
|
|||
|
||||
private void renderVehicle(Graph g, Vehicle vehicle, Label label) {
|
||||
String nodeId = makeId(vehicle.getId(),vehicle.getStartLocationId());
|
||||
if(vehicle.getType() instanceof PenaltyVehicleType) nodeId = makeId("pen_"+vehicle.getId(),vehicle.getStartLocationId());
|
||||
Node vehicleStart = g.addNode(nodeId);
|
||||
Node vehicleStart = g.addNode(nodeId);
|
||||
if(label.equals(Label.ID)) vehicleStart.addAttribute("ui.label", "depot");
|
||||
// if(label.equals(Label.ACTIVITY)) n.addAttribute("ui.label", "start");
|
||||
vehicleStart.addAttribute("x", vehicle.getStartLocationCoordinate().getX());
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ import jsprit.core.algorithm.recreate.InsertionData;
|
|||
import jsprit.core.problem.job.Job;
|
||||
import jsprit.core.problem.solution.route.VehicleRoute;
|
||||
|
||||
interface BeforeJobInsertionListener extends InsertionListener{
|
||||
public interface BeforeJobInsertionListener extends InsertionListener{
|
||||
|
||||
public void informBeforeJobInsertion(Job job, InsertionData data, VehicleRoute route);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue