org.opentripplanner.visualizer.GraphVisualizer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of otp Show documentation
Show all versions of otp Show documentation
The OpenTripPlanner multimodal journey planning system
package org.opentripplanner.visualizer;
import javassist.Modifier;
import org.locationtech.jts.geom.Coordinate;
import org.opentripplanner.graph_builder.DataImportIssue;
import org.opentripplanner.routing.algorithm.astar.TraverseVisitor;
import org.opentripplanner.routing.core.BicycleOptimizeType;
import org.opentripplanner.routing.api.request.RoutingRequest;
import org.opentripplanner.routing.core.State;
import org.opentripplanner.routing.core.TraverseModeSet;
import org.opentripplanner.routing.edgetype.StreetEdge;
import org.opentripplanner.routing.graph.Edge;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.graph.Vertex;
import org.opentripplanner.routing.impl.GraphPathFinder;
import org.opentripplanner.routing.spt.DominanceFunction;
import org.opentripplanner.routing.spt.GraphPath;
import org.opentripplanner.routing.spt.ShortestPathTree;
import org.opentripplanner.routing.vertextype.IntersectionVertex;
import org.opentripplanner.standalone.server.Router;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.lang.reflect.Field;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
* Exit on window close.
*
*/
class ExitListener extends WindowAdapter {
public void windowClosing(WindowEvent event) {
System.exit(0);
}
}
/**
* DisplayVertex holds a vertex, but has a toString value that's a little more useful.
*/
class DisplayVertex {
public Vertex vertex;
public DisplayVertex(Vertex v) {
vertex = v;
}
public String toString() {
String label = vertex.getLabel();
if (label.contains("osm node")) {
label = vertex.getName();
}
return label;
}
}
/**
* This is a ListModel that holds Edges. It gets its edges from a PatternBoard/PatternAlight, hence the iterable.
*/
class EdgeListModel extends AbstractListModel {
private static final long serialVersionUID = 1L;
private ArrayList edges;
EdgeListModel(Iterable edges) {
this.edges = new ArrayList();
for (Edge e : edges) {
this.edges.add(e);
}
}
public int getSize() {
return edges.size();
}
public Edge getElementAt(int index) {
return edges.get(index);
}
}
/**
* A list of vertices where the internal container is exposed.
*/
class VertexList extends AbstractListModel {
private static final long serialVersionUID = 1L;
public List selected;
VertexList(List selected) {
this.selected = selected;
}
public int getSize() {
return selected.size();
}
public DisplayVertex getElementAt(int index) {
return new DisplayVertex(selected.get(index));
}
};
/**
* A simple visualizer for graphs. It shows (using ShowGraph) a map of the graph, intersections and
* TransitStops only, and allows a user to select stops, examine incoming and outgoing edges, and
* examine trip patterns. It's meant mainly for debugging, so it's totally OK if it develops (say)
* a bunch of weird buttons designed to debug specific cases.
*/
public class GraphVisualizer extends JFrame implements VertexSelectionListener {
private final class ComparePathStatesClickListener implements ListSelectionListener {
private JList outputList;
ComparePathStatesClickListener(JList outputList){
this.outputList = outputList;
}
@Override
public void valueChanged(ListSelectionEvent e) {
@SuppressWarnings("unchecked")
JList theList = (JList)e.getSource();
State st = (State)theList.getSelectedValue();
if(st==null){
return;
}
DefaultListModel stateListModel = new DefaultListModel();
stateListModel.addElement( "weight:"+st.getWeight() );
stateListModel.addElement( "weightdelta:"+st.getWeightDelta() );
stateListModel.addElement( "bikeRenting:"+st.isBikeRenting() );
stateListModel.addElement( "carParked:"+st.isCarParked() );
stateListModel.addElement( "walkDistance:"+st.getWalkDistance() );
stateListModel.addElement( "elapsedTime:"+st.getElapsedTimeSeconds() );
outputList.setModel( stateListModel );
lastStateClicked = st;
}
}
private final class OnPopupMenuClickListener implements ActionListener {
private final class DiffListCellRenderer extends DefaultListCellRenderer {
private final int diverge;
private final int converge;
private DiffListCellRenderer(int diverge, int converge) {
this.diverge = diverge;
this.converge = converge;
}
@Override
public Component getListCellRendererComponent(JList> list, Object value, int index,
boolean isSelected, boolean cellHasFocus) {
Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
if(isSelected){
return c;
}
if(index <= diverge){
c.setBackground(new Color(196,201,255));
}
if(index >= converge){
c.setBackground(new Color(255,196,196));
}
return c;
}
}
private int[] diffPaths() {
if(firstComparePath == null || secondComparePath == null) {
int[] failboat = {-2,-2};
return failboat;
}
int l1 = firstComparePath.states.size();
int l2 = secondComparePath.states.size();
int minlen = l1 < l2 ? l1 : l2;
int divergence=-1;
int convergence=-1;
// find divergence
for(int i=0; i pathModel = new DefaultListModel();
for( State st : firstComparePath.states ){
pathModel.addElement( st );
}
firstComparePathStates.setModel( pathModel );
}
if(secondComparePath != null){
DefaultListModel pathModel = new DefaultListModel();
for( State st : secondComparePath.states ){
pathModel.addElement( st );
}
secondComparePathStates.setModel( pathModel );
}
int[] diff = diffPaths();
final int diverge = diff[0];
final int converge = diff[1];
if(diff[0]>=0){
firstComparePathStates.setCellRenderer(new DiffListCellRenderer(diverge,firstComparePath.states.size()-converge-1));
secondComparePathStates.setCellRenderer(new DiffListCellRenderer(diverge,secondComparePath.states.size()-converge-1));
}
}
}
class PathPrinter{
GraphPath gp;
PathPrinter(GraphPath gp){
this.gp=gp;
}
public String toString(){
SimpleDateFormat shortDateFormat = new SimpleDateFormat("HH:mm:ss z");
String startTime = shortDateFormat.format(new Date(gp.getStartTime()*1000));
String endTime = shortDateFormat.format(new Date(gp.getEndTime()*1000));
return "Path ("+startTime+"-"+endTime+") weight:"+gp.getWeight()+" dur:"+(gp.getDuration()/60.0)+" walk:"+gp.getWalkDistance();
}
}
private static final long serialVersionUID = 1L;
private static final Logger LOG = LoggerFactory.getLogger(GraphVisualizer.class);
private JPanel leftPanel;
/* The Processing applet that actually displays the graph. */
private ShowGraph showGraph;
/* The set of callbacks that display search progress on the showGraph Processing applet. */
public TraverseVisitor traverseVisitor;
public JList nearbyVertices;
private JList outgoingEdges;
private JList incomingEdges;
private JTextField sourceVertex;
private JTextField sinkVertex;
private JCheckBox walkCheckBox;
private JCheckBox bikeCheckBox;
private JCheckBox trainCheckBox;
private JCheckBox busCheckBox;
private JCheckBox ferryCheckBox;
private JCheckBox transitCheckBox;
private JCheckBox carCheckBox;
private JTextField searchDate;
private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z");
private JTextField boardingPenaltyField;
private DefaultListModel issueMatchesModel;
private JList issueMatches;
private DefaultListModel metadataModel;
private HashSet closed;
private Vertex tracingVertex;
private HashSet open;
private HashSet seen;
private JList metadataList;
/* The router we are visualizing. */
private final Router router;
/* The graph from the router we are visualizing, note that it will not be updated if the router reloads. */
private final Graph graph;
private JRadioButton opQuick;
private JRadioButton opSafe;
private JRadioButton opFlat;
private JRadioButton opGreenways;
private ButtonGroup optimizeTypeGrp;
private JTextField maxWalkField;
private JTextField walkSpeed;
private JTextField bikeSpeed;
private JTextField heuristicWeight;
private JCheckBox softWalkLimiting;
private JTextField softWalkPenalty;
private JTextField softWalkOverageRate;
private JCheckBox arriveByCheckBox;
private JLabel searchTimeElapsedLabel;
private JCheckBox dontUseGraphicalCallbackCheckBox;
private JTextField nPaths;
private JList pathsList;
private JList pathStates;
private JCheckBox showTransitCheckbox;
private JCheckBox showStreetsCheckbox;
private JCheckBox showMultistateVerticesCheckbox;
private JCheckBox showHighlightedCheckbox;
private JCheckBox showSPTCheckbox;
private ShortestPathTree spt;
private JTextField sptFlattening;
private JTextField sptThickness;
private JPopupMenu popup;
private GraphPath firstComparePath;
private GraphPath secondComparePath;
private JList firstComparePathStates;
private JList secondComparePathStates;
private JList secondStateData;
private JList firstStateData;
protected State lastStateClicked=null;
private JCheckBox longDistanceModeCheckbox;
public GraphVisualizer(Router router) {
super();
LOG.info("Starting up graph visualizer...");
setTitle("GraphVisualizer");
this.router = router;
this.graph = router.graph;
init();
}
public void run () {
this.setVisible(true);
}
public void init() {
final JTabbedPane tabbedPane = new JTabbedPane();
final Container mainTab = makeMainTab();
Container prefsPanel = makePrefsPanel();
Container diffTab = makeDiffTab();
tabbedPane.addTab("Main", null, mainTab,
"Pretty much everything");
tabbedPane.addTab("Prefs", null, prefsPanel,
"Routing preferences");
tabbedPane.addTab("Diff", null, diffTab, "multistate path diffs");
//Add the tabbed pane to this panel.
add(tabbedPane);
//The following line enables to use scrolling tabs.
tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
// startup the graphical pane; ensure closing works; draw the window
showGraph.init();
addWindowListener(new ExitListener());
pack();
// make sure the showGraph quits drawing when we switch tabs
tabbedPane.addChangeListener(new ChangeListener(){
@Override
public void stateChanged(ChangeEvent e) {
if( tabbedPane.getSelectedComponent().equals(mainTab) ){
showGraph.loop();
} else{
showGraph.noLoop();
}
}
});
}
private Container makeDiffTab() {
JPanel pane = new JPanel();
pane.setLayout(new GridLayout(0, 2));
firstStateData = new JList();
secondStateData = new JList();
// a place to list the states of the first path
firstComparePathStates = new JList();
JScrollPane stScrollPane = new JScrollPane(firstComparePathStates);
stScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
pane.add(stScrollPane);
firstComparePathStates.addListSelectionListener(new ComparePathStatesClickListener(firstStateData));
// a place to list the states of the second path
secondComparePathStates = new JList();
stScrollPane = new JScrollPane(secondComparePathStates);
stScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
pane.add(stScrollPane);
secondComparePathStates.addListSelectionListener(new ComparePathStatesClickListener(secondStateData));
// a place to list details of a state selected from the first path
stScrollPane = new JScrollPane(firstStateData);
stScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
pane.add(stScrollPane);
// a place to list details of a state selected from the second path
stScrollPane = new JScrollPane(secondStateData);
stScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
pane.add(stScrollPane);
// A button that executes the 'dominates' function between the two states
// this is useful only if you have a breakpoint set up
JButton dominateButton = new JButton();
dominateButton.setText("dominates");
dominateButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
State s1 = firstComparePathStates.getSelectedValue();
State s2 = secondComparePathStates.getSelectedValue();
DominanceFunction pareto = new DominanceFunction.Pareto();
System.out.println("s1 dominates s2:" + pareto.betterOrEqualAndComparable(s1, s2));
System.out.println("s2 dominates s1:" + pareto.betterOrEqualAndComparable(s2, s1));
}
});
pane.add(dominateButton);
// A button that executes the 'traverse' function leading to the last clicked state
// in either window. Also only useful if you set a breakpoint.
JButton traverseButton = new JButton();
traverseButton.setText("traverse");
traverseButton.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
if(lastStateClicked==null){
return;
}
Edge backEdge = lastStateClicked.getBackEdge();
State backState = lastStateClicked.getBackState();
backEdge.traverse(backState);
}
});
pane.add(traverseButton);
return pane;
}
private Container makeMainTab() {
Container pane = new JPanel();
pane.setLayout(new BorderLayout());
// init center graphical panel
showGraph = new ShowGraph(this, getGraph());
pane.add(showGraph, BorderLayout.CENTER);
traverseVisitor = new VisualTraverseVisitor(showGraph);
// init left panel
leftPanel = new JPanel();
leftPanel.setLayout(new BorderLayout());
pane.add(leftPanel, BorderLayout.LINE_START);
initRoutingSubpanel();
initVertexInfoSubpanel();
initControlButtons();
// init right panel
initRightPanel(pane);
return pane;
}
private JComponent makePrefsPanel() {
JPanel pane = new JPanel();
pane.setLayout(new GridLayout(0, 2));
// 4 rows (7 elements): transport mode options
walkCheckBox = new JCheckBox("walk");
walkCheckBox.setSelected(true);
pane.add(walkCheckBox);
bikeCheckBox = new JCheckBox("bike");
pane.add(bikeCheckBox);
trainCheckBox = new JCheckBox("trainish");
pane.add(trainCheckBox);
busCheckBox = new JCheckBox("busish");
pane.add(busCheckBox);
ferryCheckBox = new JCheckBox("ferry");
pane.add(ferryCheckBox);
transitCheckBox = new JCheckBox("transit");
transitCheckBox.setSelected(true);
pane.add(transitCheckBox);
carCheckBox = new JCheckBox("car");
pane.add(carCheckBox);
// GridLayout does not support empty cells, so a dummy label is used to fix the layout.
JLabel dummyLabel = new JLabel("");
pane.add(dummyLabel);
// row: arrive by?
JLabel arriveByLabel = new JLabel("Arrive by?:");
pane.add(arriveByLabel);
arriveByCheckBox = new JCheckBox("arrive by");
pane.add(arriveByCheckBox);
// row: boarding penalty
JLabel boardPenaltyLabel = new JLabel("Boarding penalty (min):");
pane.add(boardPenaltyLabel);
boardingPenaltyField = new JTextField("5");
pane.add(boardingPenaltyField);
// row: max walk
JLabel maxWalkLabel = new JLabel("Maximum walk (meters):");
pane.add(maxWalkLabel);
maxWalkField = new JTextField("5000");
pane.add(maxWalkField);
// row: walk speed
JLabel walkSpeedLabel = new JLabel("Walk speed (m/s):");
pane.add(walkSpeedLabel);
walkSpeed = new JTextField("1.33");
pane.add(walkSpeed);
// row: bike speed
JLabel bikeSpeedLabel = new JLabel("Bike speed (m/s):");
pane.add(bikeSpeedLabel);
bikeSpeed = new JTextField("5.0");
pane.add(bikeSpeed);
// row: heuristic weight
JLabel heuristicWeightLabel = new JLabel("Heuristic weight:");
pane.add(heuristicWeightLabel);
heuristicWeight = new JTextField("1.0");
pane.add(heuristicWeight);
// row: soft walk?
JLabel softWalkLimitLabel = new JLabel("Soft walk-limit?:");
pane.add(softWalkLimitLabel);
softWalkLimiting = new JCheckBox("soft walk-limiting");
pane.add(softWalkLimiting);
// row: soft walk-limit penalty
JLabel softWalkLimitPenaltyLabel = new JLabel("Soft walk-limiting penalty:");
pane.add(softWalkLimitPenaltyLabel);
softWalkPenalty = new JTextField("60.0");
pane.add(softWalkPenalty);
// row: soft walk-limit overage
JLabel softWalkLimitOverageLabel = new JLabel("Soft walk-limiting overage:");
pane.add(softWalkLimitOverageLabel);
softWalkOverageRate = new JTextField("5.0");
pane.add(softWalkOverageRate);
// row: nPaths
JLabel nPathsLabel = new JLabel("nPaths:");
pane.add(nPathsLabel);
nPaths = new JTextField("1");
pane.add(nPaths);
// viz preferences
ItemListener onChangeVizPrefs = new ItemListener() {
@Override
public void itemStateChanged(ItemEvent e) {
showGraph.setShowTransit(showTransitCheckbox.isSelected());
showGraph.setShowStreets(showStreetsCheckbox.isSelected());
showGraph.setShowMultistateVertices(showMultistateVerticesCheckbox.isSelected());
showGraph.setShowHightlights(showHighlightedCheckbox.isSelected());
showGraph.setShowSPT(showSPTCheckbox.isSelected());
showGraph.redraw();
}
};
showTransitCheckbox = new JCheckBox("show transit");
showTransitCheckbox.setSelected(true);
showTransitCheckbox.addItemListener(onChangeVizPrefs);
pane.add(showTransitCheckbox);
showStreetsCheckbox = new JCheckBox("show streets");
showStreetsCheckbox.setSelected(true);
showStreetsCheckbox.addItemListener(onChangeVizPrefs);
pane.add(showStreetsCheckbox);
showHighlightedCheckbox = new JCheckBox("show highlighted");
showHighlightedCheckbox.setSelected(true);
showHighlightedCheckbox.addItemListener(onChangeVizPrefs);
pane.add(showHighlightedCheckbox);
showSPTCheckbox = new JCheckBox("show SPT");
showSPTCheckbox.setSelected(true);
showSPTCheckbox.addItemListener(onChangeVizPrefs);
pane.add(showSPTCheckbox);
showMultistateVerticesCheckbox = new JCheckBox("show multistate vertices");
showMultistateVerticesCheckbox.setSelected(true);
showMultistateVerticesCheckbox.addItemListener(onChangeVizPrefs);
pane.add(showMultistateVerticesCheckbox);
// GridLayout does not support empty cells, so a dummy label is used to fix the layout.
JLabel dummyLabel2 = new JLabel("");
pane.add(dummyLabel2);
// row: SPT flattening
JLabel sptFlatteningLabel = new JLabel("SPT flattening:");
pane.add(sptFlatteningLabel);
sptFlattening = new JTextField("0.3");
pane.add(sptFlattening);
// row: SPT thickness
JLabel sptThicknessLabel = new JLabel("SPT thickness:");
pane.add(sptThicknessLabel);
sptThickness = new JTextField("0.1");
pane.add(sptThickness);
// radio buttons: optimize type
JLabel optimizeTypeLabel = new JLabel("Optimize type:");
pane.add(optimizeTypeLabel);
opQuick = new JRadioButton("Quick");
opQuick.setSelected(true);
opSafe = new JRadioButton("Safe");
opFlat = new JRadioButton("Flat");
opGreenways = new JRadioButton("Greenways");
optimizeTypeGrp = new ButtonGroup();
optimizeTypeGrp.add(opQuick);
optimizeTypeGrp.add(opSafe);
optimizeTypeGrp.add(opFlat);
optimizeTypeGrp.add(opGreenways);
JPanel optimizeTypePane = new JPanel();
optimizeTypePane.add(opQuick);
optimizeTypePane.add(opSafe);
optimizeTypePane.add(opFlat);
optimizeTypePane.add(opGreenways);
pane.add(optimizeTypePane);
return pane;
}
BicycleOptimizeType getSelectedOptimizeType(){
if(opQuick.isSelected()){
return BicycleOptimizeType.QUICK;
}
if(opSafe.isSelected()){
return BicycleOptimizeType.SAFE;
}
if(opFlat.isSelected()){
return BicycleOptimizeType.FLAT;
}
if(opGreenways.isSelected()){
return BicycleOptimizeType.GREENWAYS;
}
return BicycleOptimizeType.QUICK;
}
protected JComponent makeTextPanel(String text) {
JPanel panel = new JPanel(false);
JLabel filler = new JLabel(text);
filler.setHorizontalAlignment(JLabel.CENTER);
panel.setLayout(new GridLayout(1, 1));
panel.add(filler);
return panel;
}
private void initRightPanel(Container pane) {
/* right panel holds trip pattern and stop metadata */
JPanel rightPanel = new JPanel();
rightPanel.setLayout(new BorderLayout());
pane.add(rightPanel, BorderLayout.LINE_END);
JTabbedPane rightPanelTabs = new JTabbedPane();
rightPanel.add(rightPanelTabs, BorderLayout.LINE_END);
// a place to print out the details of a path
pathStates = new JList();
JScrollPane stScrollPane = new JScrollPane(pathStates);
stScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
rightPanelTabs.addTab("path states", stScrollPane);
// when you select a path component state, it prints the backedge's metadata
pathStates.addListSelectionListener(new ListSelectionListener(){
@Override
public void valueChanged(ListSelectionEvent e) {
outgoingEdges.clearSelection();
incomingEdges.clearSelection();
@SuppressWarnings("unchecked")
JList theList = (JList)e.getSource();
State st = (State)theList.getSelectedValue();
Edge edge = st.getBackEdge();
reactToEdgeSelection( edge, false );
}
});
metadataList = new JList();
metadataModel = new DefaultListModel();
metadataList.setModel(metadataModel);
JScrollPane mdScrollPane = new JScrollPane(metadataList);
mdScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
rightPanelTabs.addTab("metadata", mdScrollPane);
// This is where matched issues from an issue search go
issueMatches = new JList<>();
issueMatches.addListSelectionListener(e -> {
@SuppressWarnings("unchecked")
JList theList = (JList) e.getSource();
DataImportIssue issue = theList.getSelectedValue();
if (issue == null) {
return;
}
showGraph.drawIssue(issue);
});
issueMatchesModel = new DefaultListModel();
issueMatches.setModel(issueMatchesModel);
JScrollPane imScrollPane = new JScrollPane(issueMatches);
imScrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
rightPanelTabs.addTab("issues", imScrollPane);
Dimension size = new Dimension(200, 1600);
imScrollPane.setMaximumSize(size);
imScrollPane.setPreferredSize(size);
stScrollPane.setMaximumSize(size);
stScrollPane.setPreferredSize(size);
mdScrollPane.setMaximumSize(size);
mdScrollPane.setPreferredSize(size);
rightPanelTabs.setMaximumSize(size);
rightPanel.setMaximumSize(size);
}
private void initControlButtons() {
/* buttons at bottom */
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(0, 3));
leftPanel.add(buttonPanel, BorderLayout.PAGE_END);
JButton zoomDefaultButton = new JButton("Zoom to default");
zoomDefaultButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showGraph.zoomToDefault();
}
});
buttonPanel.add(zoomDefaultButton);
final JFrame frame = this;
JButton zoomToNodeButton = new JButton("Zoom to node");
zoomToNodeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String nodeName = (String) JOptionPane.showInputDialog(frame, "Node id",
JOptionPane.PLAIN_MESSAGE);
Vertex v = getGraph().getVertex(nodeName);
if (v == null) {
System.out.println("no such node " + nodeName);
} else {
showGraph.zoomToVertex(v);
}
}
});
buttonPanel.add(zoomToNodeButton);
JButton zoomToLocationButton = new JButton("Zoom to location");
zoomToLocationButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String result = JOptionPane.showInputDialog("Enter the location (lat lon)");
if (result == null || result.length() == 0)
return;
String[] tokens = result.split("[\\s,]+");
double lat = Double.parseDouble(tokens[0]);
double lon = Double.parseDouble(tokens[1]);
Coordinate c = new Coordinate(lon, lat);
showGraph.zoomToLocation(c);
}
});
buttonPanel.add(zoomToLocationButton);
JButton zoomOutButton = new JButton("Zoom out");
zoomOutButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showGraph.zoomOut();
}
});
buttonPanel.add(zoomOutButton);
JButton routeButton2 = new JButton("Route");
routeButton2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// String initialFrom = "";
// Object selected = nearbyVertices.getSelectedValue();
// if (selected != null) {
// initialFrom = selected.toString();
// }
// RouteDialog dlg = new RouteDialog(frame, initialFrom); // modal
String from = sourceVertex.getText();
String to = sinkVertex.getText();
route(from, to);
}
});
buttonPanel.add(routeButton2);
JButton findButton = new JButton("Find node");
findButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String nodeName = (String) JOptionPane.showInputDialog(frame, "Node id",
JOptionPane.PLAIN_MESSAGE);
Vertex v = getGraph().getVertex(nodeName);
if (v == null) {
System.out.println("no such node " + nodeName);
} else {
showGraph.highlightVertex(v);
ArrayList l = new ArrayList();
l.add(v);
verticesSelected(l);
}
}
});
buttonPanel.add(findButton);
JButton findEdgeButton = new JButton("Find edge");
findEdgeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String edgeName = (String) JOptionPane.showInputDialog(frame, "Edge name like",
JOptionPane.PLAIN_MESSAGE);
for (Vertex gv : getGraph().getVertices()) {
for (Edge edge : gv.getOutgoing()) {
if (edge.getName() != null && edge.getName().contains(edgeName)) {
showGraph.highlightVertex(gv);
ArrayList l = new ArrayList();
l.add(gv);
verticesSelected(l);
}
}
}
}
});
buttonPanel.add(findEdgeButton);
JButton checkButton = new JButton("Check graph");
checkButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
checkGraph();
}
});
buttonPanel.add(checkButton);
JButton traceButton = new JButton("Trace");
traceButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
trace();
}
});
buttonPanel.add(traceButton);
JButton findEdgeByIdButton = new JButton("Find edge ID");
findEdgeByIdButton.addActionListener(e -> {
throw new UnsupportedOperationException("Edges no longer have integer IDs.");
});
buttonPanel.add(findEdgeByIdButton);
JButton snapButton = new JButton("Snap location");
snapButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
LOG.error("StreetIndex.getClosestPointOnStreet no longer exists.");
}
});
buttonPanel.add(snapButton);
}
private void getMetadata(Object selected) {
Class> c = selected.getClass();
Field[] fields;
while (c != null && c != Object.class) {
metadataModel.addElement("Class:" + c);
fields = c.getDeclaredFields();
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
int modifiers = field.getModifiers();
if ((modifiers & Modifier.STATIC) != 0) {
continue;
}
field.setAccessible(true);
String name = field.getName();
String value = "(unknown -- see console for stack trace)";
try {
value = "" + field.get(selected);
} catch (IllegalArgumentException e1) {
LOG.error("IllegalArgumentException", e1);
} catch (IllegalAccessException e1) {
LOG.error("IllegalAccessException", e1);
}
metadataModel.addElement(name + ": " + value);
}
c = c.getSuperclass();
}
}
private void reactToEdgeSelection(Edge selected, boolean outgoing){
if (selected == null) {
return;
}
showGraph.highlightEdge(selected);
/* for turns, highlight the outgoing street's ends */
if (selected instanceof StreetEdge) {
List vertices = new ArrayList();
List edges = new ArrayList();
Vertex tov = selected.getToVertex();
for (Edge og : tov.getOutgoing()) {
if (og instanceof StreetEdge) {
edges.add(og);
vertices.add(og.getToVertex());
break;
}
}
Vertex fromv = selected.getFromVertex();
for (Edge ic : fromv.getIncoming()) {
if (ic instanceof StreetEdge) {
edges.add(ic);
vertices.add(ic.getFromVertex());
break;
}
}
// showGraph.setHighlightedVertices(vertices);
showGraph.setHighlightedEdges(edges);
}
/* add the connected vertices to the list of vertices */
VertexList nearbyModel = (VertexList) nearbyVertices.getModel();
List vertices = nearbyModel.selected;
Vertex v;
if (outgoing) {
v = selected.getToVertex();
} else {
v = selected.getFromVertex();
}
if (!vertices.contains(v)) {
vertices.add(v);
nearbyModel = new VertexList(vertices);
nearbyVertices.setModel(nearbyModel); // this should just be an event, but for
// some reason, JList doesn't implement
// the right event.
}
/* set up metadata tab */
metadataModel.clear();
getMetadata(selected);
// fromv
Vertex fromv = selected.getFromVertex();
getMetadata(fromv);
if (selected instanceof StreetEdge) {
//TODO ElevationProfileSegment do not exist anymore
//getMetadata(((StreetEdge) selected).getElevationProfileSegment());
}
metadataList.revalidate();
}
private void initVertexInfoSubpanel() {
JPanel vertexDataPanel = new JPanel();
vertexDataPanel.setLayout(new BoxLayout(vertexDataPanel, BoxLayout.PAGE_AXIS));
vertexDataPanel.setPreferredSize(new Dimension(300, 600));
leftPanel.add(vertexDataPanel, BorderLayout.CENTER);
// nearby vertices
JLabel nvLabel = new JLabel("Vertices");
vertexDataPanel.add(nvLabel);
nearbyVertices = new JList();
nearbyVertices.setVisibleRowCount(4);
JScrollPane nvScrollPane = new JScrollPane(nearbyVertices);
vertexDataPanel.add(nvScrollPane);
nearbyVertices.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
outgoingEdges.removeAll();
incomingEdges.removeAll();
DisplayVertex selected = (DisplayVertex) nearbyVertices.getSelectedValue();
if (selected != null) {
Vertex nowSelected = selected.vertex;
showGraph.highlightVertex(nowSelected);
outgoingEdges.setModel(new EdgeListModel(nowSelected.getOutgoing()));
incomingEdges.setModel(new EdgeListModel(nowSelected.getIncoming()));
}
}
});
// listener useful for both incoming and outgoing edge list panes
// when a different edge is selected, change up the pattern pane and list of nearby nodes
ListSelectionListener edgeChanged = new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
@SuppressWarnings("unchecked")
JList edgeList = (JList) e.getSource();
Edge selected = (Edge) edgeList.getSelectedValue();
boolean outgoing = (edgeList==outgoingEdges);
reactToEdgeSelection( selected, outgoing );
}
};
// outgoing edges
JLabel ogeLabel = new JLabel("Outgoing edges");
vertexDataPanel.add(ogeLabel);
outgoingEdges = new JList();
outgoingEdges.setVisibleRowCount(4);
JScrollPane ogeScrollPane = new JScrollPane(outgoingEdges);
vertexDataPanel.add(ogeScrollPane);
outgoingEdges.addListSelectionListener(edgeChanged);
// incoming edges
JLabel iceLabel = new JLabel("Incoming edges");
vertexDataPanel.add(iceLabel);
incomingEdges = new JList();
JScrollPane iceScrollPane = new JScrollPane(incomingEdges);
vertexDataPanel.add(iceScrollPane);
incomingEdges.addListSelectionListener(edgeChanged);
// paths list
JLabel pathsLabel = new JLabel("Paths");
vertexDataPanel.add(pathsLabel);
pathsList = new JList();
popup = new JPopupMenu();
JMenuItem compareMenuItem = new JMenuItem("compare");
compareMenuItem.addActionListener(new OnPopupMenuClickListener());
popup.add(compareMenuItem);
// make paths list right-clickable
pathsList.addMouseListener(new MouseListener(){
@Override
public void mouseClicked(MouseEvent e) {
if( SwingUtilities.isRightMouseButton(e) ){
@SuppressWarnings("unchecked")
JList list = (JList)e.getSource();
int row = list.locationToIndex(e.getPoint());
list.setSelectedIndex(row);
popup.show(list, e.getX(), e.getY());
}
}
@Override
public void mousePressed(MouseEvent e) {}
@Override
public void mouseReleased(MouseEvent e) {}
@Override
public void mouseEntered(MouseEvent e) {}
@Override
public void mouseExited(MouseEvent e) {}
});
pathsList.addListSelectionListener(new ListSelectionListener(){
@Override
public void valueChanged(ListSelectionEvent ev) {
PathPrinter pp = ((PathPrinter) pathsList.getSelectedValue());
if(pp==null){
return;
}
GraphPath path = pp.gp;
DefaultListModel pathModel = new DefaultListModel();
for( State st : path.states ){
pathModel.addElement( st );
}
pathStates.setModel( pathModel );
showGraph.highlightGraphPath(path);
}
});
JScrollPane pathsScrollPane = new JScrollPane(pathsList);
vertexDataPanel.add(pathsScrollPane);
}
private void initRoutingSubpanel() {
/* ROUTING SUBPANEL */
JPanel routingPanel = new JPanel();
routingPanel.setLayout(new GridLayout(0, 2));
leftPanel.add(routingPanel, BorderLayout.NORTH);
// row: source vertex
JButton setSourceVertexButton = new JButton("set source");
setSourceVertexButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Object selected = nearbyVertices.getSelectedValue();
if (selected != null) {
sourceVertex.setText(selected.toString());
}
}
});
routingPanel.add(setSourceVertexButton);
sourceVertex = new JTextField();
routingPanel.add(sourceVertex);
// row: sink vertex
JButton setSinkVertexButton = new JButton("set sink");
setSinkVertexButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Object selected = nearbyVertices.getSelectedValue();
if (selected != null) {
sinkVertex.setText(selected.toString());
}
}
});
routingPanel.add(setSinkVertexButton);
sinkVertex = new JTextField();
routingPanel.add(sinkVertex);
// row: set date
JButton resetSearchDateButton = new JButton("now ->");
resetSearchDateButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
searchDate.setText(dateFormat.format(new Date()));
}
});
routingPanel.add(resetSearchDateButton);
searchDate = new JTextField();
searchDate.setText(dateFormat.format(new Date()));
routingPanel.add(searchDate);
// row: launch, continue, and clear path search
JButton routeButton = new JButton("path search");
routeButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String from = sourceVertex.getText();
String to = sinkVertex.getText();
route(from, to);
}
});
routingPanel.add(routeButton);
JButton continueButton = new JButton("continue");
continueButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
//TODO continue search
}
});
routingPanel.add(continueButton);
JButton clearRouteButton = new JButton("clear path");
clearRouteButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
showGraph.highlightGraphPath(null);
showGraph.clearHighlights();
showGraph.resetSPT();
}
});
routingPanel.add(clearRouteButton);
//label: search time elapsed
searchTimeElapsedLabel = new JLabel("search time elapsed:");
routingPanel.add(searchTimeElapsedLabel);
//option: don't use graphical callback. useful for doing a quick profile
dontUseGraphicalCallbackCheckBox = new JCheckBox("no graphics");
routingPanel.add(dontUseGraphicalCallbackCheckBox);
}
protected void trace() {
DisplayVertex selected = (DisplayVertex) nearbyVertices.getSelectedValue();
if (selected == null) {
return;
}
Vertex v = selected.vertex;
if (tracingVertex != v) {
tracingVertex = v;
closed = new HashSet();
open = new HashSet();
open.add(v);
seen = new HashSet();
}
HashSet newOpen = new HashSet();
for (Vertex v2 : open) {
closed.add(v2);
for (Edge e : v2.getOutgoing()) {
Vertex target = e.getToVertex();
if (closed.contains(target)) {
continue;
}
newOpen.add(target);
}
}
seen.addAll(newOpen);
open = newOpen;
showGraph.setHighlightedVertices(seen);
}
protected void traceOld() {
HashSet seenVertices = new HashSet();
DisplayVertex selected = (DisplayVertex) nearbyVertices.getSelectedValue();
if (selected == null) {
System.out.println("no vertex selected");
return;
}
Vertex v = selected.vertex;
System.out.println("initial vertex: " + v);
Queue toExplore = new LinkedList();
toExplore.add(v);
seenVertices.add(v);
while (!toExplore.isEmpty()) {
Vertex src = toExplore.poll();
for (Edge e : src.getOutgoing()) {
Vertex tov = e.getToVertex();
if (!seenVertices.contains(tov)) {
seenVertices.add(tov);
toExplore.add(tov);
}
}
}
showGraph.setHighlightedVertices(seenVertices);
}
protected void checkGraph() {
HashSet seenVertices = new HashSet();
Collection allVertices = getGraph().getVertices();
Vertex v = allVertices.iterator().next();
System.out.println("initial vertex: " + v);
Queue toExplore = new LinkedList();
toExplore.add(v);
seenVertices.add(v);
while (!toExplore.isEmpty()) {
Vertex src = toExplore.poll();
for (Edge e : src.getOutgoing()) {
Vertex tov = e.getToVertex();
if (!seenVertices.contains(tov)) {
seenVertices.add(tov);
toExplore.add(tov);
}
}
}
System.out.println("After investigation, visited " + seenVertices.size() + " of "
+ allVertices.size());
/* now, let's find an unvisited vertex */
for (Vertex u : allVertices) {
if (!seenVertices.contains(u)) {
System.out.println("unvisited vertex" + u);
break;
}
}
}
protected void route(String from, String to) {
Date when;
// Year + 1900
try {
when = dateFormat.parse(searchDate.getText());
} catch (ParseException e) {
searchDate.setText("Format: " + dateFormat.toPattern());
return;
}
TraverseModeSet modeSet = new TraverseModeSet();
modeSet.setWalk(walkCheckBox.isSelected());
modeSet.setBicycle(bikeCheckBox.isSelected());
modeSet.setFerry(ferryCheckBox.isSelected());
modeSet.setRail(trainCheckBox.isSelected());
modeSet.setTram(trainCheckBox.isSelected());
modeSet.setSubway(trainCheckBox.isSelected());
modeSet.setFunicular(trainCheckBox.isSelected());
modeSet.setGondola(trainCheckBox.isSelected());
modeSet.setBus(busCheckBox.isSelected());
modeSet.setCableCar(busCheckBox.isSelected());
modeSet.setCar(carCheckBox.isSelected());
// must set generic transit mode last, and only when it is checked
// otherwise 'false' will clear trainish and busish
if (transitCheckBox.isSelected())
modeSet.setTransit(true);
RoutingRequest options = new RoutingRequest(modeSet);
options.setArriveBy(arriveByCheckBox.isSelected());
options.setWalkBoardCost(Integer.parseInt(boardingPenaltyField.getText()) * 60); // override low 2-4 minute values
// TODO LG Add ui element for bike board cost (for now bike = 2 * walk)
options.setBikeBoardCost(Integer.parseInt(boardingPenaltyField.getText()) * 60 * 2);
// there should be a ui element for walk distance and optimize type
options.setOptimize( getSelectedOptimizeType() );
options.setMaxWalkDistance(Integer.parseInt(maxWalkField.getText()));
options.setDateTime(when);
options.setFromString(from);
options.setToString(to);
options.walkSpeed = Float.parseFloat(walkSpeed.getText());
options.bikeSpeed = Float.parseFloat(bikeSpeed.getText());
options.numItineraries = 1;
System.out.println("--------");
System.out.println("Path from " + from + " to " + to + " at " + when);
System.out.println("\tModes: " + modeSet);
System.out.println("\tOptions: " + options);
options.numItineraries = ( Integer.parseInt( this.nPaths.getText() ) );
// apply callback if the options call for it
// if( dontUseGraphicalCallbackCheckBox.isSelected() ){
// TODO perhaps avoid using a GraphPathFinder and go one level down the call chain directly to a GenericAStar
// TODO perhaps instead of giving the pathservice a callback, we can just put the visitor in the routing request
GraphPathFinder finder = new GraphPathFinder(router);
long t0 = System.currentTimeMillis();
// TODO: check options properly intialized (AMB)
List paths = finder.graphPathFinderEntryPoint(options);
long dt = System.currentTimeMillis() - t0;
searchTimeElapsedLabel.setText( "search time elapsed: "+dt+"ms" );
// grab the spt from the visitor
// TODO somehow yank the SPT out of the depths of the call stack... but there multiple SPTs here.
// This is why we should probably just use AStar directly.
/*
spt = vis.spt;
showGraph.setSPT(spt);
System.out.println( "got spt:"+spt );
*/
if (paths == null) {
System.out.println("no path");
showGraph.highlightGraphPath(null);
return;
}
// now's a convenient time to set graphical SPT weights
showGraph.simpleSPT.setWeights();
showPathsInPanel(paths);
// now's a good time to set showGraph's SPT drawing weights
showGraph.setSPTFlattening( Float.parseFloat(sptFlattening.getText()) );
showGraph.setSPTThickness( Float.parseFloat(sptThickness.getText()) );
showGraph.redraw();
options.cleanup();
}
private void showPathsInPanel(List paths) {
// show paths in a list panel
DefaultListModel data = new DefaultListModel();
for(GraphPath gp : paths ){
data.addElement( new PathPrinter(gp) );
}
pathsList.setModel(data);
}
public void verticesSelected(final List selected) {
// sort vertices by name
Collections.sort(selected, new Comparator() {
@Override
public int compare(Vertex arg0, Vertex arg1) {
return arg0.getLabel().compareTo(arg1.getLabel());
}
});
ListModel data = new VertexList(selected);
nearbyVertices.setModel(data);
// pick out an intersection vertex and find the path
// if the spt is already available
Vertex target=null;
for(Vertex vv : selected){
if( vv instanceof IntersectionVertex ){
target = vv;
break;
}
}
if(target!=null && spt!=null){
List paths = spt.getPaths(target,true);
showPathsInPanel( paths );
}
}
public Graph getGraph() {
return graph;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy