package org.opentrafficsim.road.gtu.lane.perception; import java.io.Serializable; import org.djutils.exceptions.Throw; import org.opentrafficsim.core.network.LateralDirectionality; /** * Defines a lane relative to the current lane. *

* 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 May 2, 2016
* @author Wouter Schakel */ public class RelativeLane implements Comparable, Serializable { /** */ private static final long serialVersionUID = 20160502L; /** Second left lane. */ public static final RelativeLane SECOND_LEFT = new RelativeLane(LateralDirectionality.LEFT, 2); /** Left lane. */ public static final RelativeLane LEFT = new RelativeLane(LateralDirectionality.LEFT, 1); /** Current lane. */ public static final RelativeLane CURRENT = new RelativeLane(LateralDirectionality.NONE, 0); /** right lane. */ public static final RelativeLane RIGHT = new RelativeLane(LateralDirectionality.RIGHT, 1); /** Second right lane. */ public static final RelativeLane SECOND_RIGHT = new RelativeLane(LateralDirectionality.RIGHT, 2); /** * Rank, summarizes both the lateral directionality and the number of lanes. Is zero for CURRENT, otherwise equal to number * of lanes for RIGHT, negative number of lanes for LEFT. */ private final int rank; /** * Private constructor. * @param rank int; the rank */ private RelativeLane(final int rank) { this.rank = rank; } /** * Constructor. * @param lat LateralDirectionality; lateral direction (use {@code null} for the current lane) * @param numLanes int; number of lanes in the lateral direction (not important for the current lane) * @throws IllegalArgumentException if numLanes is not at least 1, except if {@code lat == null} (current lane) * @throws IllegalArgumentException if numLanes is not 0 if {@code lat == null} (current lane) */ public RelativeLane(final LateralDirectionality lat, final int numLanes) { Throw.whenNull(lat, "Lateral directionality may not be null."); Throw.when(lat.isNone() && numLanes != 0, IllegalArgumentException.class, "Number of lanes must be zero if the lateral directionality is NONE."); Throw.when((!lat.isNone()) && numLanes <= 0, IllegalArgumentException.class, "Relative lane with %d lanes in %s direction is not allowed, use values > 0.", numLanes, lat); this.rank = lat.isLeft() ? -numLanes : numLanes; } /** * Returns the lateral direction. * @return LateralDirectionality; the lateral direction */ public final LateralDirectionality getLateralDirectionality() { // return this.lat; return this.rank == 0 ? LateralDirectionality.NONE : this.rank < 0 ? LateralDirectionality.LEFT : LateralDirectionality.RIGHT; } /** * Returns the number of lanes in the lateral direction. * @return int; number of lanes in the lateral direction */ public final int getNumLanes() { return Math.abs(this.rank); } /** * Returns whether the second left lane is referred to. * @return whether the second left lane is referred to */ public final boolean isSecondLeft() { return this.equals(SECOND_LEFT); } /** * Returns whether the left lane is referred to. * @return whether the left lane is referred to */ public final boolean isLeft() { return this.equals(LEFT); } /** * Returns whether the current lane is referred to. * @return whether the current lane is referred to */ public final boolean isCurrent() { return this.equals(CURRENT); } /** * Returns whether the right lane is referred to. * @return whether the right lane is referred to */ public final boolean isRight() { return this.equals(RIGHT); } /** * Returns whether the second right lane is referred to. * @return whether the second right lane is referred to */ public final boolean isSecondRight() { return this.equals(SECOND_RIGHT); } /** * Returns the left hand relative lane of this relative lane. * @return left hand relative lane of this relative lane. */ public final RelativeLane getLeft() { return this.add(LEFT); } /** * Returns the right hand relative lane of this relative lane. * @return right hand relative lane of this relative lane. */ public final RelativeLane getRight() { return this.add(RIGHT); } /** * Returns the relative lane relative to this lane, for example "the left lane" of "the 3rd right lane" is "the 2nd right * lane". * @param relativeLane RelativeLane; relative lane to get of this lane * @return relative lane relative to this lane */ public final RelativeLane add(final RelativeLane relativeLane) { return new RelativeLane(this.rank + relativeLane.rank); } /** {@inheritDoc} */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + this.rank; return result; } /** {@inheritDoc} */ @Override public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } RelativeLane other = (RelativeLane) obj; if (this.rank != other.rank) // relative lane is uniquely defined by the rank { return false; } return true; } /** {@inheritDoc} */ @Override public final String toString() { if (this.equals(CURRENT)) { return "RelativeLane [CURRENT]"; } return new StringBuilder("RelativeLane [").append(getLateralDirectionality()).append(", ").append(getNumLanes()) .append("]").toString(); } /** {@inheritDoc} */ @Override public final int compareTo(final RelativeLane rel) { return this.rank - rel.rank; } }