LinkParser.java
package org.opentrafficsim.road.network.factory.xml.network;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Predicate;
import org.djunits.unit.SpeedUnit;
import org.djunits.value.AngleUtil;
import org.djunits.value.vdouble.scalar.Direction;
import org.djunits.value.vdouble.scalar.Length;
import org.djunits.value.vdouble.scalar.Speed;
import org.djutils.logger.CategoryLogger;
import org.djutils.reflection.ClassUtil;
import org.opentrafficsim.base.logger.Cat;
import org.opentrafficsim.core.compatibility.Compatible;
import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
import org.opentrafficsim.core.geometry.Bezier;
import org.opentrafficsim.core.geometry.OTSGeometryException;
import org.opentrafficsim.core.geometry.OTSLine3D;
import org.opentrafficsim.core.geometry.OTSPoint3D;
import org.opentrafficsim.core.gtu.GTUType;
import org.opentrafficsim.core.gtu.RelativePosition;
import org.opentrafficsim.core.network.LinkType;
import org.opentrafficsim.core.network.LongitudinalDirectionality;
import org.opentrafficsim.core.network.NetworkException;
import org.opentrafficsim.core.network.Node;
import org.opentrafficsim.core.network.OTSNetwork;
import org.opentrafficsim.core.network.factory.xml.units.SpeedUnits;
import org.opentrafficsim.road.network.factory.xml.XmlParserException;
import org.opentrafficsim.road.network.lane.CrossSectionElement;
import org.opentrafficsim.road.network.lane.CrossSectionLink;
import org.opentrafficsim.road.network.lane.CrossSectionLink.Priority;
import org.opentrafficsim.road.network.lane.Lane;
import org.opentrafficsim.road.network.lane.LaneType;
import org.opentrafficsim.road.network.lane.NoTrafficLane;
import org.opentrafficsim.road.network.lane.Shoulder;
import org.opentrafficsim.road.network.lane.Stripe;
import org.opentrafficsim.road.network.lane.Stripe.Permeable;
import org.opentrafficsim.road.network.lane.changing.LaneKeepingPolicy;
import org.opentrafficsim.road.network.lane.changing.OvertakingConditions;
import org.opentrafficsim.road.network.lane.object.sensor.SinkSensor;
import org.opentrafficsim.xml.bindings.types.ArcDirection;
import org.opentrafficsim.xml.generated.CROSSSECTIONELEMENT;
import org.opentrafficsim.xml.generated.CSELANE;
import org.opentrafficsim.xml.generated.CSENOTRAFFICLANE;
import org.opentrafficsim.xml.generated.CSESHOULDER;
import org.opentrafficsim.xml.generated.CSESTRIPE;
import org.opentrafficsim.xml.generated.LINK;
import org.opentrafficsim.xml.generated.LINK.LANEOVERRIDE;
import org.opentrafficsim.xml.generated.NETWORK;
import org.opentrafficsim.xml.generated.ROADLAYOUT;
import org.opentrafficsim.xml.generated.TRAFFICLIGHTTYPE;
import nl.tudelft.simulation.dsol.simulators.DEVSSimulatorInterface;
import nl.tudelft.simulation.language.d3.DirectedPoint;
/**
* LinkParser parses the LINK tags in the XML network.. <br>
* <br>
* Copyright (c) 2003-2018 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
* for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
* source code and binary code of this software is proprietary information of Delft University of Technology.
* @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
*/
public final class LinkParser
{
/** */
public LinkParser()
{
// utility class
}
/**
* Build the links with the correct design line.
* @param otsNetwork the network to insert the parsed objects in
* @param network the NETWORK tag
* @param nodeDirections a map of the node ids and their default directions
* @param simulator the simulator
* @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
* @throws OTSGeometryException when the design line is invalid
*/
static void parseLinks(final OTSNetwork otsNetwork, final NETWORK network, Map<String, Direction> nodeDirections,
OTSSimulatorInterface simulator) throws NetworkException, OTSGeometryException
{
for (LINK xmlLink : network.getLINK())
{
Node startNode = otsNetwork.getNode(xmlLink.getNODESTART().getNAME());
Node endNode = otsNetwork.getNode(xmlLink.getNODEEND().getNAME());
double startDirection =
nodeDirections.containsKey(startNode.getId()) ? nodeDirections.get(startNode.getId()).getInUnit() : 0.0;
double endDirection =
nodeDirections.containsKey(endNode.getId()) ? nodeDirections.get(endNode.getId()).getInUnit() : 0.0;
OTSPoint3D startPoint = new OTSPoint3D(startNode.getPoint());
OTSPoint3D endPoint = new OTSPoint3D(endNode.getPoint());
if (!xmlLink.getOFFSETSTART().eq0())
{
// shift the start point perpendicular to the node direction or read from tag
double offset = xmlLink.getOFFSETSTART().si;
startPoint = new OTSPoint3D(startPoint.x + offset * Math.cos(startDirection + Math.PI / 2.0),
startPoint.y + offset * Math.sin(startDirection + Math.PI / 2.0), startPoint.z);
CategoryLogger.filter(Cat.PARSER).debug("fc = " + startNode.getPoint() + ", sa = " + startDirection + ", so = "
+ offset + ", sp = " + startPoint);
}
if (!xmlLink.getOFFSETEND().eq0())
{
// shift the end point perpendicular to the node direction or read from tag
double offset = xmlLink.getOFFSETEND().si;
endPoint = new OTSPoint3D(endPoint.x + offset * Math.cos(endDirection + Math.PI / 2.0),
endPoint.y + offset * Math.sin(endDirection + Math.PI / 2.0), endPoint.z);
CategoryLogger.filter(Cat.PARSER).debug(
"tc = " + endNode.getPoint() + ", ea = " + endDirection + ", eo = " + offset + ", ep = " + endPoint);
}
OTSPoint3D[] coordinates = null;
if (xmlLink.getSTRAIGHT() != null)
{
coordinates = new OTSPoint3D[2];
coordinates[0] = startPoint;
coordinates[1] = endPoint;
}
else if (xmlLink.getPOLYLINE() != null)
{
int intermediatePoints = xmlLink.getPOLYLINE().getINTERMEDIATEPOINTS().size();
coordinates = new OTSPoint3D[intermediatePoints + 2];
coordinates[0] = startPoint;
coordinates[intermediatePoints + 1] = endPoint;
for (int p = 0; p < intermediatePoints; p++)
{
coordinates[p + 1] = new OTSPoint3D(xmlLink.getPOLYLINE().getINTERMEDIATEPOINTS().get(p));
}
}
else if (xmlLink.getARC() != null)
{
// calculate the center position
double radiusSI = xmlLink.getARC().getRADIUS().getSI();
double offsetStart = 0.0;
if (xmlLink.getOFFSETSTART() != null)
{
offsetStart = xmlLink.getOFFSETSTART().si;
}
double offsetEnd = 0.0;
if (xmlLink.getOFFSETEND() != null)
{
offsetEnd = xmlLink.getOFFSETEND().si;
}
List<OTSPoint3D> centerList = OTSPoint3D.circleIntersections(startNode.getPoint(), radiusSI + offsetStart,
endNode.getPoint(), radiusSI + offsetEnd);
OTSPoint3D center =
(xmlLink.getARC().getDIRECTION().equals(ArcDirection.RIGHT)) ? centerList.get(0) : centerList.get(1);
// calculate start angle and end angle
double sa = Math.atan2(startNode.getPoint().y - center.y, startNode.getPoint().x - center.x);
double ea = Math.atan2(endNode.getPoint().y - center.y, endNode.getPoint().x - center.x);
if (xmlLink.getARC().getDIRECTION().equals(ArcDirection.RIGHT))
{
// right -> negative direction, ea should be less than sa
ea = (sa < ea) ? ea + Math.PI * 2.0 : ea;
}
else
{
// left -> positive direction, sa should be less than ea
ea = (ea < sa) ? ea + Math.PI * 2.0 : ea;
}
// TODO: user defined #points
int points = (AngleUtil.normalize(ea - sa) <= Math.PI / 2.0) ? 64 : 128;
coordinates = new OTSPoint3D[points];
coordinates[0] = new OTSPoint3D(startNode.getPoint().x + Math.cos(sa) * offsetStart,
startNode.getPoint().y + Math.sin(sa) * offsetStart, startNode.getPoint().z);
coordinates[coordinates.length - 1] = new OTSPoint3D(endNode.getPoint().x + Math.cos(ea) * offsetEnd,
endNode.getPoint().y + Math.sin(ea) * offsetEnd, endNode.getPoint().z);
double angleStep = Math.abs((ea - sa)) / points;
double slopeStep = (endNode.getPoint().z - startNode.getPoint().z) / points;
if (xmlLink.getARC().getDIRECTION().equals(ArcDirection.RIGHT))
{
for (int p = 1; p < points - 1; p++)
{
double dRad = offsetStart + (offsetEnd - offsetStart) * p / points;
coordinates[p] = new OTSPoint3D(center.x + (radiusSI + dRad) * Math.cos(sa - angleStep * p),
center.y + (radiusSI + dRad) * Math.sin(sa - angleStep * p),
startNode.getPoint().z + slopeStep * p);
}
}
else
{
for (int p = 1; p < points - 1; p++)
{
double dRad = offsetStart + (offsetEnd - offsetStart) * p / points;
coordinates[p] = new OTSPoint3D(center.x + (radiusSI + dRad) * Math.cos(sa + angleStep * p),
center.y + (radiusSI + dRad) * Math.sin(sa + angleStep * p),
startNode.getPoint().z + slopeStep * p);
}
}
}
else if (xmlLink.getBEZIER() != null)
{
// TODO: user defined #points
coordinates = Bezier
.cubic(128, new DirectedPoint(startPoint.x, startPoint.y, startPoint.z, 0, 0, startDirection),
new DirectedPoint(endPoint.x, endPoint.y, endPoint.z, 0, 0, endDirection), 1.0, false)
.getPoints();
// TODO: Bezier shape factor and weighted factor
}
else if (xmlLink.getCLOTHOID() != null)
{
// TODO: user defined #points
// TODO: Clothoid parsing
}
else
{
throw new NetworkException("Making link, but link " + xmlLink.getNAME()
+ " has no filled straight, arc, bezier, polyline, or clothoid definition");
}
OTSLine3D designLine = OTSLine3D.createAndCleanOTSLine3D(coordinates);
// TODO: Directionality has to be added later when the lanes and their direction are known.
LaneKeepingPolicy laneKeepingPolicy = LaneKeepingPolicy.valueOf(xmlLink.getLANEKEEPING().name());
CrossSectionLink link = new CrossSectionLink(otsNetwork, xmlLink.getNAME(), startNode, endNode, LinkType.FREEWAY,
designLine, simulator, laneKeepingPolicy);
if (xmlLink.getPRIORITY() != null)
{
Priority priority = Priority.valueOf(xmlLink.getPRIORITY());
link.setPriority(priority);
}
// TODO: rotationstart and rotationend of a link, or leave out of xsd?
// TODO: networkAnimation.addDrawingInfoBase(link, new DrawingInfoLine<CrossSectionLink>(Color.BLACK, 0.5f));
}
}
/**
* Build the links with the correct design line.
* @param otsNetwork the network to insert the parsed objects in
* @param network the NETWORK tag
* @param simulator the simulator
* @throws NetworkException when the objects cannot be inserted into the network due to inconsistencies
* @throws OTSGeometryException when the design line is invalid
* @throws XmlParserException when the stripe type cannot be recognized
*/
static void applyRoadTypes(final OTSNetwork otsNetwork, final NETWORK network, OTSSimulatorInterface simulator)
throws NetworkException, OTSGeometryException, XmlParserException
{
for (LINK xmlLink : network.getLINK())
{
CrossSectionLink csl = (CrossSectionLink) otsNetwork.getLink(xmlLink.getNAME());
List<CrossSectionElement> cseList = new ArrayList<>();
Map<String, Lane> lanes = new HashMap<>();
// TODO: Map<GTUType, LongitudinalDirectionality> linkDirections = new HashMap<>();
System.out.println(xmlLink.getNAME());
// CROSSSECTIONELEMENT
// XXX: does not work! Simplify the network.xsd...
ROADLAYOUT roadlayout = Parser.findObject(network.getDEFINITIONS(), ROADLAYOUT.class, new Predicate<ROADLAYOUT>()
{
@Override
public boolean test(ROADLAYOUT t)
{
return t.getNAME().equals(xmlLink.getROADLAYOUT());
}
});
for (CROSSSECTIONELEMENT cse : roadlayout.getLANEOrNOTRAFFICLANEOrSHOULDER())
{
LANEOVERRIDE laneOverride = null;
for (LANEOVERRIDE lo : xmlLink.getLANEOVERRIDE())
{
if (lo.getLANE().equals(cse.getNAME()))
laneOverride = lo;
}
Length startOffset = cse.getOFFSET() != null ? cse.getOFFSET() : xmlLink.getOFFSETSTART();
Length endOffset = cse.getOFFSET() != null ? cse.getOFFSET() : xmlLink.getOFFSETEND();
if (cse instanceof CSESTRIPE)
{
makeStripe(csl, startOffset, endOffset, cse, cseList);
}
else if (cse instanceof CSELANE)
{
CSELANE cseLane = (CSELANE) cse;
LongitudinalDirectionality direction = LongitudinalDirectionality.valueOf(cseLane.getDIRECTION().name());
// TODO: The LaneType should be defined in the XML...
// TODO: how to handle cseLane.getSPEEDLIMIT()? GTUType specific...
Lane lane = new Lane(csl, cseLane.getNAME(), startOffset, endOffset, cseLane.getWIDTH(), cseLane.getWIDTH(),
LaneType.FREEWAY, new Speed(100.0, SpeedUnit.KM_PER_HOUR),
parseOvertakingConditions(cseLane.getOVERTAKING()));
cseList.add(lane);
lanes.put(lane.getId(), lane);
// TODO: deal with cse.getCOLOR() where the laneOverrideTag can also have a color
}
else if (cse instanceof CSENOTRAFFICLANE)
{
Lane lane = new NoTrafficLane(csl, cse.getNAME(), startOffset, endOffset, cse.getWIDTH(), cse.getWIDTH());
cseList.add(lane);
// TODO: deal with cse.getCOLOR() where the laneOverrideTag can also have a color
}
else if (cse instanceof CSESHOULDER)
{
Shoulder shoulder =
new Shoulder(csl, cse.getNAME(), startOffset, endOffset, cse.getWIDTH(), cse.getWIDTH());
cseList.add(shoulder);
// TODO: deal with cse.getCOLOR() where the laneOverrideTag can also have a color
}
}
// SINK
for (LINK.SINK sink : xmlLink.getSINK())
{
if (!lanes.containsKey(sink.getLANE()))
throw new NetworkException(
"LINK: " + xmlLink.getNAME() + ", Sink on Lane " + sink.getLANE() + " - Lane not found");
Lane lane = lanes.get(sink.getLANE());
Length position = Transformer.parseLengthBeginEnd(sink.getPOSITION(), lane.getLength());
new SinkSensor(lane, position, simulator);
}
// TRAFFICLIGHT
for (TRAFFICLIGHTTYPE trafficLight : xmlLink.getTRAFFICLIGHT())
{
if (!lanes.containsKey(trafficLight.getLANE()))
throw new NetworkException("LINK: " + xmlLink.getNAME() + ", TrafficLight with id " + trafficLight.getNAME()
+ " on Lane " + trafficLight.getLANE() + " - Lane not found");
Lane lane = lanes.get(trafficLight.getLANE());
Length position = Transformer.parseLengthBeginEnd(trafficLight.getPOSITION(), lane.getLength());
try
{
Constructor<?> trafficLightConstructor = ClassUtil.resolveConstructor(trafficLight.getCLASS(),
new Class[] {String.class, Lane.class, Length.class, DEVSSimulatorInterface.TimeDoubleUnit.class});
trafficLightConstructor.newInstance(new Object[] {trafficLight.getNAME(), lane, position, simulator});
}
catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException exception)
{
throw new NetworkException("TRAFFICLIGHT: CLASS NAME " + trafficLight.getCLASS().getName()
+ " for traffic light " + trafficLight.getNAME() + " on lane " + lane.toString()
+ " -- class not found or constructor not right", exception);
}
}
// GENERATOR
for (LINK.GENERATOR generator : xmlLink.getGENERATOR())
{
if (!lanes.containsKey(generator.getLANE()))
throw new NetworkException(
"LINK: " + xmlLink.getNAME() + ", Generator on Lane " + generator.getLANE() + " - Lane not found");
Lane lane = lanes.get(generator.getLANE());
Length position = Transformer.parseLengthBeginEnd(generator.getPOSITION(), lane.getLength());
// TODO: makeGenerator(generator, xmlLink, simulator);
}
// TODO: LISTGENERATOR
// SENSOR
for (LINK.SENSOR sensor : xmlLink.getSENSOR())
{
if (!lanes.containsKey(sensor.getLANE()))
throw new NetworkException("LINK: " + xmlLink.getNAME() + ", Sensor with id " + sensor.getNAME()
+ " on Lane " + sensor.getLANE() + " - Lane not found");
Lane lane = lanes.get(sensor.getLANE());
Length position = Transformer.parseLengthBeginEnd(sensor.getPOSITION(), lane.getLength());
try
{
Constructor<?> sensorConstructor = ClassUtil.resolveConstructor(sensor.getCLASS(),
new Class[] {String.class, Lane.class, Length.class, RelativePosition.TYPE.class,
DEVSSimulatorInterface.TimeDoubleUnit.class, Compatible.class});
sensorConstructor.newInstance(new Object[] {sensor.getNAME(), lane, position,
Transformer.parseTriggerPosition(sensor.getTRIGGER()), simulator, Compatible.EVERYTHING});
}
catch (NoSuchMethodException | InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException exception)
{
throw new NetworkException(
"SENSOR: CLASS NAME " + sensor.getCLASS().getName() + " for sensor " + sensor.getNAME()
+ " on lane " + lane.toString() + " -- class not found or constructor not right",
exception);
}
}
// FILL
for (LINK.FILL fill : xmlLink.getFILL())
{
if (!lanes.containsKey(fill.getLANE()))
throw new NetworkException(
"LINK: " + xmlLink.getNAME() + ", Fill on Lane " + fill.getLANE() + " - Lane not found");
Lane lane = lanes.get(fill.getLANE());
// TODO: parseFill(fill, xmlLink, simulator);
}
}
}
/**
* Parse a stripe on a road.
* @param csl the CrossSectionLine
* @param startOffset the offset of the start node
* @param endOffset the offset of the end node
* @param cse the CROSSECTIONELEMENT tag in the XML file
* @param cseList the list of CrossSectionElements to which the stripes should be added
* @throws OTSGeometryException when creation of the center line or contour geometry fails
* @throws NetworkException when id of the stripe not unique
* @throws XmlParserException when the stripe type cannot be recognized
*/
private static void makeStripe(final CrossSectionLink csl, final Length startOffset, final Length endOffset,
final CROSSSECTIONELEMENT cse, final List<CrossSectionElement> cseList)
throws OTSGeometryException, NetworkException, XmlParserException
{
switch (((CSESTRIPE) cse).getTYPE())
{
case BLOCKED:
case DASHED:
Stripe dashedLine = new Stripe(csl, startOffset, endOffset, cse.getWIDTH());
dashedLine.addPermeability(GTUType.VEHICLE, Permeable.BOTH);
// TODO: parser.networkAnimation.addDrawingInfoBase(dashedLine,
// TODO: new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.DASHED));
cseList.add(dashedLine);
break;
case DOUBLE:
Stripe doubleLine = new Stripe(csl, startOffset, endOffset, cse.getWIDTH());
// TODO: parser.networkAnimation.addDrawingInfoBase(doubleLine,
// TODO: new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.DOUBLE));
cseList.add(doubleLine);
break;
case LEFTONLY:
Stripe leftOnlyLine = new Stripe(csl, startOffset, endOffset, cse.getWIDTH());
leftOnlyLine.addPermeability(GTUType.VEHICLE, Permeable.LEFT); // TODO correct?
// TODO: parser.networkAnimation.addDrawingInfoBase(leftOnlyLine,
// TODO: new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.LEFTONLY));
cseList.add(leftOnlyLine);
break;
case RIGHTONLY:
Stripe rightOnlyLine = new Stripe(csl, startOffset, endOffset, cse.getWIDTH());
rightOnlyLine.addPermeability(GTUType.VEHICLE, Permeable.RIGHT); // TODO correct?
// TODO: parser.networkAnimation.addDrawingInfoBase(rightOnlyLine,
// TODO: new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.RIGHTONLY));
cseList.add(rightOnlyLine);
break;
case SOLID:
Stripe solidLine = new Stripe(csl, startOffset, endOffset, cse.getWIDTH());
// TODO: parser.networkAnimation.addDrawingInfoBase(solidLine,
// TODO: new DrawingInfoStripe<Stripe>(Color.BLACK, 0.5f, StripeType.SOLID));
cseList.add(solidLine);
break;
default:
throw new XmlParserException("Unknown Stripe type: " + ((CSESTRIPE) cse).getTYPE().toString());
}
}
/**
* @param ocStr String; the overtaking conditions string.
* @return the overtaking conditions.
* @throws NetworkException in case of unknown overtaking conditions.
*/
private static OvertakingConditions parseOvertakingConditions(String ocStr) throws NetworkException
{
if (ocStr.equals("LEFTONLY"))
{
return new OvertakingConditions.LeftOnly();
}
else if (ocStr.equals("RIGHTONLY"))
{
return new OvertakingConditions.RightOnly();
}
else if (ocStr.equals("LEFTANDRIGHT"))
{
return new OvertakingConditions.LeftAndRight();
}
else if (ocStr.equals("NONE"))
{
return new OvertakingConditions.None();
}
else if (ocStr.equals("SAMELANERIGHT"))
{
return new OvertakingConditions.SameLaneRight();
}
else if (ocStr.equals("SAMELANELEFT"))
{
return new OvertakingConditions.SameLaneLeft();
}
else if (ocStr.equals("SAMELANEBOTH"))
{
return new OvertakingConditions.SameLaneBoth();
}
else if (ocStr.startsWith("LEFTALWAYS RIGHTSPEED"))
{
int lb = ocStr.indexOf('(');
int rb = ocStr.indexOf(')');
if (lb == -1 || rb == -1 || rb - lb < 3)
{
throw new NetworkException("Speed in overtaking conditions string: '" + ocStr + "' not coded right");
}
Speed speed = SpeedUnits.parseSpeed(ocStr.substring(lb + 1, rb));
return new OvertakingConditions.LeftAlwaysRightSpeed(speed);
}
else if (ocStr.startsWith("RIGHTALWAYS LEFTSPEED"))
{
int lb = ocStr.indexOf('(');
int rb = ocStr.indexOf(')');
if (lb == -1 || rb == -1 || rb - lb < 3)
{
throw new NetworkException("Speed in overtaking conditions string: '" + ocStr + "' not coded right");
}
Speed speed = SpeedUnits.parseSpeed(ocStr.substring(lb + 1, rb));
return new OvertakingConditions.RightAlwaysLeftSpeed(speed);
}
// TODO SETs and JAM
/*-
else if (ocStr.startsWith("LEFTSET"))
{
int lset1 = ocStr.indexOf('[') + 1;
int rset1 = ocStr.indexOf(']', lset1);
int lset2 = ocStr.indexOf('[', ocStr.indexOf("OVERTAKE")) + 1;
int rset2 = ocStr.indexOf(']', lset2);
if (lset1 == -1 || rset1 == -1 || rset1 - lset1 < 3 || lset2 == -1 || rset2 == -1 || rset2 - lset2 < 3)
{
throw new NetworkException("Sets in overtaking conditions string: '" + ocStr + "' not coded right");
}
Set<GTUType> overtakingGTUs = parseGTUTypeSet(ocStr.substring(lset1, rset1));
Set<GTUType> overtakenGTUs = parseGTUTypeSet(ocStr.substring(lset2, rset2));
if (ocStr.contains("RIGHTSPEED"))
{
int i = ocStr.indexOf("RIGHTSPEED");
int lb = ocStr.indexOf('(', i);
int rb = ocStr.indexOf(')', i);
if (lb == -1 || rb == -1 || rb - lb < 3)
{
throw new NetworkException("Speed in overtaking conditions string: '" + ocStr + "' not coded right");
}
Speed speed = SpeedUnits.parseSpeed(ocStr.substring(lb + 1, rb));
return new OvertakingConditions.LeftSetRightSpeed(overtakingGTUs, overtakenGTUs, speed);
}
return new OvertakingConditions.LeftSet(overtakingGTUs, overtakenGTUs);
}
else if (ocStr.startsWith("RIGHTSET"))
{
int lset1 = ocStr.indexOf('[') + 1;
int rset1 = ocStr.indexOf(']', lset1);
int lset2 = ocStr.indexOf('[', ocStr.indexOf("OVERTAKE")) + 1;
int rset2 = ocStr.indexOf(']', lset2);
if (lset1 == -1 || rset1 == -1 || rset1 - lset1 < 3 || lset2 == -1 || rset2 == -1 || rset2 - lset2 < 3)
{
throw new NetworkException("Sets in overtaking conditions string: '" + ocStr + "' not coded right");
}
Set<GTUType> overtakingGTUs = parseGTUTypeSet(ocStr.substring(lset1, rset1));
Set<GTUType> overtakenGTUs = parseGTUTypeSet(ocStr.substring(lset2, rset2));
if (ocStr.contains("LEFTSPEED"))
{
int i = ocStr.indexOf("LEFTSPEED");
int lb = ocStr.indexOf('(', i);
int rb = ocStr.indexOf(')', i);
if (lb == -1 || rb == -1 || rb - lb < 3)
{
throw new NetworkException("Speed in overtaking conditions string: '" + ocStr + "' not coded right");
}
Speed speed = SpeedUnits.parseSpeed(ocStr.substring(lb + 1, rb));
return new OvertakingConditions.RightSetLeftSpeed(overtakingGTUs, overtakenGTUs, speed);
}
return new OvertakingConditions.RightSet(overtakingGTUs, overtakenGTUs);
}
*/
throw new NetworkException("Unknown overtaking conditions string: " + ocStr);
}
}