// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.graphview.core.graph;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import org.openstreetmap.josm.plugins.graphview.core.transition.Restriction;
import org.openstreetmap.josm.plugins.graphview.core.transition.Segment;
import org.openstreetmap.josm.plugins.graphview.core.transition.SegmentNode;
/**
* group of nodes that will be evaluated independently from other groups
*/
public class JunctionEvaluationGroup extends EvaluationGroup {
private final Set<SegmentNode> segmentNodes;
protected List<Segment> inboundSegments;
protected List<Segment> outboundSegments;
/**
* @param segmentNodes set of SegmentNodes, must not be modified
* after being used as constructor parameter; != null
*/
public JunctionEvaluationGroup(Set<SegmentNode> segmentNodes) {
assert segmentNodes != null;
this.segmentNodes = segmentNodes;
}
/**
* returns all segments that can be used to enter this group.
* {@link #evaluate(Iterable)} needs be called before this method.
*
* @return segment collection; != null
*/
public Collection<Segment> getInboundSegments() {
if (!evaluated) {
throw new IllegalStateException(tr("Group not yet evaluated"));
}
return inboundSegments;
}
/**
* returns all segments that can be used to leave this group.
* {@link #evaluate(Iterable)} needs be called before this method.
*
* @return segment collection; != null
*/
public Collection<Segment> getOutboundSegments() {
if (!evaluated) {
throw new IllegalStateException(tr("Group not yet evaluated"));
}
return outboundSegments;
}
/**
* returns a segment sequence that runs from an inbound to an outbound
* segment or null if no connection is possible.
* {@link EvaluationGroup#evaluate(Collection)} needs be called before this method.
*
* @param inboundSegment start of the potential sequence;
* must be inbound segment; != null
* @param outboundSegment target of the potential sequence;
* must be outbound segment; != null
* @return sequence of segments or null
*/
public List<Segment> getSegmentSequence(Segment inboundSegment, Segment outboundSegment) {
assert inboundSegment != null && inboundSegments.contains(inboundSegment);
assert outboundSegment != null && outboundSegments.contains(outboundSegment);
if (!evaluated) {
throw new IllegalStateException(tr("Group not yet evaluated"));
}
int inboundIndex = inboundSegments.indexOf(inboundSegment);
int outboundIndex = outboundSegments.indexOf(outboundSegment);
return segmentSequences[inboundIndex][outboundIndex];
}
@Override
protected void evaluateImpl(final Collection<Restriction> restrictions) {
assert restrictions != null;
/* find inbound and outbound segments. An inbound segment is a segment whose target
* is in the set and whose start node isn't (analogous for outbound segments) */
inboundSegments = new ArrayList<>();
outboundSegments = new ArrayList<>();
for (SegmentNode segmentNode : segmentNodes) {
for (Segment segment : segmentNode.getInboundSegments()) {
if (!segmentNodes.contains(segment.getNode1())) {
inboundSegments.add(segment);
}
}
for (Segment segment : segmentNode.getOutboundSegments()) {
if (!segmentNodes.contains(segment.getNode2())) {
outboundSegments.add(segment);
}
}
}
/* find segment sequences from inbound to outbound segments */
@SuppressWarnings("unchecked") //cannot create generic array without cast
List<Segment>[][] sequenceArray = new List[inboundSegments.size()][outboundSegments.size()];
for (int inboundIndex = 0; inboundIndex < inboundSegments.size(); inboundIndex++) {
for (int outboundIndex = 0; outboundIndex < outboundSegments.size(); outboundIndex++) {
List<Segment> sequence =
findSegmentSequence(inboundSegments.get(inboundIndex),
outboundSegments.get(outboundIndex), restrictions);
sequenceArray[inboundIndex][outboundIndex] = sequence;
}
}
segmentSequences = sequenceArray;
}
@Override
protected boolean isUsableNode(SegmentNode node) {
return segmentNodes.contains(node);
}
@Override
protected boolean isUsableSegment(Segment segment) {
return segmentNodes.contains(segment.getNode1())
&& segmentNodes.contains(segment.getNode2());
}
@Override
public String toString() {
return "JunctionEG " + segmentNodes;
}
}