// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.JunctionChecker.converting;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.Channel;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.ChannelDiGraph;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.OSMGraph;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.OSMNode;
import org.openstreetmap.josm.plugins.JunctionChecker.datastructure.OSMWay;
/**
* erstellt einen ChannelDigraphen aus einem OSMGraphen
* @author Jörg Possin
*/
public class ChannelDigraphBuilder {
private final ChannelDiGraph digraph;
private final OSMGraph osmgraph;
private final OSMWay[] osmways;
private Channel newChannel = new Channel();
private final NodesConnectionProducer ncp;
// Variable wird für die IDs der neu erstellten Ways benötigt, die
// Hinrichtung bekommt den des ursprungs-Way, die Rückrichtung
// eine fiktive negative (OSM-XML-Standard für neue, noch nicht in der DB
// gespeicherte Entities)
private int newid = 1;
private TurnRestrictionChecker trchecker;
Channel backChannel;
public ChannelDigraphBuilder(OSMGraph osmgraph) {
//Nodesbeziehungen erstellen
ncp = new NodesConnectionProducer(osmgraph);
ncp.produceNodesConnections();
digraph = new ChannelDiGraph();
this.osmways = osmgraph.getWays();
digraph.setBbbottom(osmgraph.getBbbottom());
digraph.setBbleft(osmgraph.getBbleft());
digraph.setBbright(osmgraph.getBbright());
digraph.setBbtop(osmgraph.getBbtop());
this.osmgraph = osmgraph;
}
private void setNewWayID(Channel channel) {
channel.setNewid(newid);
newid++;
}
/**
* Hilfemethode zur Erstellung eines Channels
* @param fromNode fromNode des zu erstellenden Channels
* @param toNode toNode des zu erstellnenden Channels
* @param way ein zu dem Channel gehörender Way
*/
private Channel createChannel(OSMNode fromNode, OSMNode toNode, OSMWay way) {
newChannel = new Channel();
newChannel.setFromNode(fromNode);
newChannel.setToNode(toNode);
setNewWayID(newChannel);
digraph.addChannel(newChannel);
fromNode.addOutgoingChannel(newChannel);
newChannel.addWay(way);
return newChannel;
}
private void createBackChannel(OSMNode fromNode, OSMNode toNode, OSMWay way, Channel channel) {
backChannel = new Channel();
backChannel = createChannel(fromNode, toNode, way);
backChannel.setBackChannelID(channel.getNewid());
channel.setBackChannelID(backChannel.getNewid());
}
/**
* erzeugt den Digraphen
*/
private void buildChannels(OSMWay way, boolean oneway) {
Channel tempChannel = new Channel();
OSMNode lastUsedNode = way.getFromNode();
OSMNode[] nodes = way.getNodes();
/*
* log.debug("Way mit ID " + way.getId() + " , startnode: " +
* way.getFromNode().getId() + " , EndNode: " + way.getToNode().getId()
* + " wird bearbeitet.");
*/
// alle Knoten eines ways durchgehen
for (int i = 1; i < nodes.length; i++) {
// nur wenn der aktuelle Knoten mehr als einen Vorgänger/Nachfolger
// hat, wird in die if-Abfrage gesprungen und ein neuer Channel mit
//mit dem aktuell betrachtetem Node als Endnode erzeugt
if (nodes[i].getPredNodeList().size() > 1 || nodes[i].getSuccNodeList().size() > 1) {
tempChannel = createChannel(lastUsedNode, nodes[i], way);
// bei Nichteinbahnstraße wird Channel in die andere Richtung
// erzeugt
if (oneway == false) {
createBackChannel(nodes[i], lastUsedNode, way, tempChannel);
}
lastUsedNode = nodes[i];
// wenn der betrachtete Knoten keine Nachfolger hat, ist ein
// Straßenende erreicht. Auch in diesem Fall muß ein Channel erzeugt werden
} else if (nodes[i].getSuccNodeList().size() == 0) {
tempChannel = createChannel(lastUsedNode, nodes[i], way);
// Rückrichtung wird nur erzeugt, wenn der OSM-Way keine Einbahnstraße ist
if (oneway == false) {
createBackChannel(nodes[i], lastUsedNode, way, tempChannel);
}
// eine Straße besteht aus 2 Ways, obwohl eigentlich eine reicht
// tritt z.b. bei einer brücke auf, brücke wird neuer channel
//TODO: kann an dieser stelle das erzeugen von pseudo-channels verhindert werden?
// Idee: speichern eines flags, um diese erzeugten Channels zu markieren. aus diesen informationen
// später den CHannel löschen!!!
} else if (i == nodes.length - 1
&& nodes[i].getSuccNodeList().size() == 1) {
// damit ist ein Channel gefunden, und wird mit Werten gefüllt
tempChannel = createChannel(lastUsedNode, nodes[i], way);
// bei Nichteinbahnstraße wird Channel in die andere Richtung
// erzeugt
if (oneway == false) {
createBackChannel(nodes[i], lastUsedNode, way, tempChannel);
}
lastUsedNode = nodes[i];
}
}
}
/**
* baut den ChannelDigraph
*/
public void buildChannelDigraph() {
// alle Wege eines OSMGraphen durchgehen
for (int i = 0; i < osmways.length; i++) {
buildChannels(osmways[i], osmways[i].isOneWay());
}
trchecker = new TurnRestrictionChecker(osmgraph, digraph);
trchecker.createLeadsTo();
PseudoChannelRemover pcr = new PseudoChannelRemover(digraph); //überflüssige Channels entfernen
pcr.removePseudoChannels();
}
public ChannelDiGraph getDigraph() {
return digraph;
}
public void setNewid(int newid) {
this.newid = newid;
}
public int getNewid() {
return newid;
}
}