All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.opentrafficsim.road.gtu.lane.perception.AbstractPerceptionReiterable Maven / Gradle / Ivy

The newest version!
package org.opentrafficsim.road.gtu.lane.perception;

import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.function.Supplier;

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.LaneBasedGtu;
import org.opentrafficsim.road.gtu.lane.perception.headway.Headway;

/**
 * This class uses a single primary iterator which a subclass defines, and makes sure that all elements are only looked up and
 * created once. It does so by storing the elements in a linked list. All calls to {@code iterator()} return an iterator which
 * iterates over the linked list. If an iterator runs to the end of the linked list, the primary iterator is requested to add an
 * element if it has one.
 * 

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

* @author Alexander Verbraeck * @author Peter Knoppers * @author Wouter Schakel * @param headway type * @param underlying object type */ public abstract class AbstractPerceptionReiterable implements PerceptionCollectable { /** First entry. */ private SecondaryIteratorEntry first; /** Last entry generated by the primary iterator. */ private SecondaryIteratorEntry last; /** Primary iterator. */ private Iterator primaryIterator; /** Perceiving GTU. */ private final LaneBasedGtu gtu; /** * Constructor. * @param perceivingGtu LaneBasedGtu; perceiving GTU */ protected AbstractPerceptionReiterable(final LaneBasedGtu perceivingGtu) { this.gtu = perceivingGtu; } /** * Returns the GTU. * @return LaneBasedGtu; GTU */ protected LaneBasedGtu getGtu() { return this.gtu; } /** * Returns the primary iterator. * @return Iterator; primary iterator */ final Iterator getPrimaryIterator() { if (this.primaryIterator == null) { this.primaryIterator = primaryIterator(); } return this.primaryIterator; } /** * Returns the primary iterator. This method is called once by AbstractPerceptionReiterable. * @return Iterator; primary iterator */ protected abstract Iterator primaryIterator(); /** * Returns a perceived version of the underlying object. * @param perceivingGtu LaneBasedGtu; perceiving GTU * @param object U; underlying object * @param distance Length; distance to the object * @return H; perceived version of the underlying object * @throws GtuException on exception * @throws ParameterException on invalid parameter value or missing parameter */ protected abstract H perceive(LaneBasedGtu perceivingGtu, U object, Length distance) throws GtuException, ParameterException; /** {@inheritDoc} */ @Override public final synchronized H first() { assureFirst(); if (this.first == null) { return null; } return this.first.getValue(); } /** * Assures a first SecondaryIteratorEntry is present, if the primary iterator has any elements. */ private synchronized void assureFirst() { if (this.first == null && getPrimaryIterator().hasNext()) { addNext(getPrimaryIterator().next()); } } /** * Adds an iterator entry to the internal linked list. * @param next PrimaryIteratorEntry; next object */ @SuppressWarnings("synthetic-access") final void addNext(final PrimaryIteratorEntry next) { SecondaryIteratorEntry entry = new SecondaryIteratorEntry(next.object, next.distance); if (AbstractPerceptionReiterable.this.last == null) { AbstractPerceptionReiterable.this.first = entry; AbstractPerceptionReiterable.this.last = entry; } else { AbstractPerceptionReiterable.this.last.next = entry; AbstractPerceptionReiterable.this.last = entry; } } /** {@inheritDoc} */ @Override public final boolean isEmpty() { return first() == null; } /** {@inheritDoc} */ @Override public final Iterator iterator() { return new PerceptionIterator(); } /** {@inheritDoc} */ @Override public final C collect(final Supplier identity, final PerceptionAccumulator accumulator, final PerceptionFinalizer finalizer) { Intermediate intermediate = new Intermediate<>(identity.get()); assureFirst(); if (this.first != null) { SecondaryIteratorEntry lastReturned = null; SecondaryIteratorEntry next = this.first; next = assureNext(next, lastReturned); while (next != null && !intermediate.isStop()) { intermediate = accumulator.accumulate(intermediate, next.object, next.distance); intermediate.step(); lastReturned = next; next = lastReturned.next; next = assureNext(next, lastReturned); } } return finalizer.collect(intermediate.getObject()); } /** {@inheritDoc} */ @Override public Iterator underlying() { assureFirst(); SecondaryIteratorEntry firstInContext = this.first; return new Iterator() { /** Last returned iterator entry. */ private SecondaryIteratorEntry lastReturned = null; /** Next iterator entry. */ private SecondaryIteratorEntry next = firstInContext; /** {@inheritDoc} */ @Override public boolean hasNext() { this.next = assureNext(this.next, this.lastReturned); return this.next != null; } /** {@inheritDoc} */ @Override public U next() { // this.next = assureNext(this.next, this.lastReturned); // if (this.next == null) // { // throw new NoSuchElementException(); // } // this.lastReturned = this.next; // this.next = this.lastReturned.next; // return this.lastReturned.object; this.lastReturned = this.next; this.next = this.lastReturned.next; this.next = assureNext(this.next, this.lastReturned); return this.lastReturned.object; } }; } /** {@inheritDoc} */ @Override public Iterator> underlyingWithDistance() { assureFirst(); SecondaryIteratorEntry firstInContext = this.first; return new Iterator>() { /** Last returned iterator entry. */ private SecondaryIteratorEntry lastReturned = null; /** Next iterator entry. */ private SecondaryIteratorEntry next = firstInContext; /** {@inheritDoc} */ @Override public boolean hasNext() { this.next = assureNext(this.next, this.lastReturned); return this.next != null; } /** {@inheritDoc} */ @Override public UnderlyingDistance next() { this.lastReturned = this.next; this.next = this.lastReturned.next; this.next = assureNext(this.next, this.lastReturned); return new UnderlyingDistance<>(this.lastReturned.object, this.lastReturned.distance); } }; } /** * This iterator is returned to callers of the {@code iterator()} method. Multiple instances may be returned which use the * same linked list of {@code SecondaryIteratorEntry}. Whenever an iterator runs to the end of this list, the primary * iterator is requested to find the next object, if it has a next object. *

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

* @author Alexander Verbraeck * @author Peter Knoppers * @author Wouter Schakel */ public class PerceptionIterator implements Iterator { /** Last returned entry. */ private SecondaryIteratorEntry lastReturned; /** Next entry. */ private SecondaryIteratorEntry next; /** Constructor. */ PerceptionIterator() { this.next = AbstractPerceptionReiterable.this.first; } /** {@inheritDoc} */ @Override public boolean hasNext() { this.next = assureNext(this.next, this.lastReturned); return this.next != null; } /** {@inheritDoc} */ @Override public H next() { this.next = assureNext(this.next, this.lastReturned); if (this.next == null) { throw new NoSuchElementException(); } this.lastReturned = this.next; this.next = this.lastReturned.next; return this.lastReturned.getValue(); } } /** * Helper method that assures that a next entry is available, if the primary iterator has a next value. This method may be * used by any process that derives from the primary iterator. * @param next SecondaryIteratorEntry; currently known next entry * @param lastReturned SecondaryIteratorEntry; entry of last returned object or value * @return IteratorEntry; next entry */ synchronized SecondaryIteratorEntry assureNext(final SecondaryIteratorEntry next, final SecondaryIteratorEntry lastReturned) { if (next != null) { return next; } if (lastReturned != null) { if (lastReturned.next == null) { if (getPrimaryIterator().hasNext()) { addNext(getPrimaryIterator().next()); } } return lastReturned.next; } if (getPrimaryIterator().hasNext()) { addNext(getPrimaryIterator().next()); } return AbstractPerceptionReiterable.this.first; } /** * Class for {@code primaryIterator()} to return, implemented in subclasses. *

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

* @author Alexander Verbraeck * @author Peter Knoppers * @author Wouter Schakel */ protected class PrimaryIteratorEntry implements Comparable { /** Object. */ private final U object; /** Distance to the object. */ private final Length distance; /** * Constructor. * @param object U; object * @param distance Length; distance */ public PrimaryIteratorEntry(final U object, final Length distance) { this.object = object; this.distance = distance; } /** {@inheritDoc} */ @Override public int compareTo(final PrimaryIteratorEntry o) { return this.distance.compareTo(o.distance); } /** * Returns the object. * @return U; object */ protected U getObject() { return this.object; } } /** * Entries that make up a linked list of values for secondary iterators to iterate over. *

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

* @author Alexander Verbraeck * @author Peter Knoppers * @author Wouter Schakel */ private class SecondaryIteratorEntry { /** Value. */ private final U object; /** Distance to object. */ private final Length distance; /** Value. */ private H value; /** Next entry. */ private SecondaryIteratorEntry next; /** * Constructor. * @param object U; object * @param distance Length; distance to object */ SecondaryIteratorEntry(final U object, final Length distance) { this.object = object; this.distance = distance; } /** * Returns the perceived version of the object. * @return H; perceived version of the object */ H getValue() { if (this.value == null) { /*- this.value = Try.assign(() -> perceive(AbstractPerceptionReiterable.this.getGtu(), this.object, this.distance), "Exception during perception of object."); */ try { this.value = perceive(AbstractPerceptionReiterable.this.getGtu(), this.object, this.distance); } catch (Exception e) { e.printStackTrace(); } } return this.value; } } }