package org.opentrafficsim.road.gtu.lane.perception; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import java.util.NoSuchElementException; import java.util.SortedMap; import java.util.TreeMap; import org.djunits.value.vdouble.scalar.Length; import org.opentrafficsim.base.parameters.ParameterException; import org.opentrafficsim.core.gtu.GtuException; import org.opentrafficsim.road.gtu.lane.InternalLaneBasedGtu; import org.opentrafficsim.road.gtu.lane.perception.headway.Headway; /** * Iterable class to search over multiple lanes. *

* Copyright (c) 2013-2021 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License. *

* @version $Revision$, $LastChangedDate$, by $Author$, initial version 20 feb. 2018
* @author Alexander Verbraeck * @author Peter Knoppers * @author Wouter Schakel * @param headway type * @param underlying headway type */ public class MultiLanePerceptionIterable extends AbstractPerceptionReiterable { /** Set of iterators per lane. */ private final Map> iterators = new LinkedHashMap<>(); /** Map of lane per object. */ private final Map laneMap = new LinkedHashMap<>(); /** Map of iterable per lane. */ private final Map> iterables = new LinkedHashMap<>(); /** * Constructor. * @param perceivingGtu InternalLaneBasedGtu; perceiving GTU */ public MultiLanePerceptionIterable(final InternalLaneBasedGtu perceivingGtu) { super(perceivingGtu); } /** * Adds an iterable for a lane. * @param lane RelativeLane; lane * @param iterable AbstractPerceptionReiterable<H, U>; iterable */ public void addIterable(final RelativeLane lane, final AbstractPerceptionReiterable iterable) { this.iterators.put(lane, iterable.getPrimaryIterator()); this.iterables.put(lane, iterable); } /** {@inheritDoc} */ @Override public Iterator primaryIterator() { return new MultiLaneIterator(); } /** * Iterator that returns the closest element from a set of lanes. *

* Copyright (c) 2013-2021 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. *
* BSD-style license. See OpenTrafficSim License. *

* @version $Revision$, $LastChangedDate$, by $Author$, initial version 21 feb. 2018
* @author Alexander Verbraeck * @author Peter Knoppers * @author Wouter Schakel */ private class MultiLaneIterator implements Iterator { /** Sorted elements per lane. */ private SortedMap elements; /** Constructor. */ MultiLaneIterator() { // } /** {@inheritDoc} */ @Override public boolean hasNext() { assureNext(); return !this.elements.isEmpty(); } /** {@inheritDoc} */ @SuppressWarnings("synthetic-access") @Override public PrimaryIteratorEntry next() { assureNext(); if (this.elements.isEmpty()) { throw new NoSuchElementException(); } // get and remove next PrimaryIteratorEntry next = this.elements.firstKey(); RelativeLane lane = this.elements.get(next); this.elements.remove(next); // prepare next Iterator laneIterator = MultiLanePerceptionIterable.this.iterators.get(lane); if (laneIterator != null) { if (laneIterator.hasNext()) { this.elements.put(laneIterator.next(), lane); } else { // remove it, it has no more elements to offer MultiLanePerceptionIterable.this.iterators.remove(lane); } } MultiLanePerceptionIterable.this.laneMap.put(next.getObject(), lane); return next; } /** * Starts the process. */ @SuppressWarnings("synthetic-access") public void assureNext() { if (this.elements == null) { this.elements = new TreeMap<>(); for (RelativeLane lane : MultiLanePerceptionIterable.this.iterators.keySet()) { Iterator laneIterator = MultiLanePerceptionIterable.this.iterators.get(lane); if (laneIterator.hasNext()) { this.elements.put(laneIterator.next(), lane); } } } } } /** {@inheritDoc} */ @Override public H perceive(final InternalLaneBasedGtu perceivingGtu, final U object, final Length distance) throws GtuException, ParameterException { return this.iterables.get(this.laneMap.get(object)).perceive(perceivingGtu, object, distance); } }