1 package org.opentrafficsim.kpi.sampling;
2
3 import java.io.Serializable;
4 import java.util.Iterator;
5 import java.util.LinkedHashSet;
6 import java.util.Set;
7
8 import org.djunits.value.vdouble.scalar.Length;
9 import org.djutils.exceptions.Throw;
10 import org.djutils.immutablecollections.ImmutableIterator;
11 import org.opentrafficsim.kpi.interfaces.LaneData;
12 import org.opentrafficsim.kpi.interfaces.LinkData;
13 import org.opentrafficsim.kpi.sampling.CrossSection.LanePosition;
14
15 /**
16 * A cross sections contains locations on lanes that together make up a cross section. It is not required that this is on a
17 * single road, i.e. the cross section may be any section in space.
18 * <p>
19 * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
20 * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
21 * </p>
22 * @author <a href="https://github.com/averbraeck">Alexander Verbraeck</a>
23 * @author <a href="https://github.com/peter-knoppers">Peter Knoppers</a>
24 * @author <a href="https://github.com/wjschakel">Wouter Schakel</a>
25 */
26 public class CrossSection implements Serializable, Iterable<LanePosition>
27 {
28
29 /** */
30 private static final long serialVersionUID = 20160929L;
31
32 /** Set of lane locations. */
33 private final Set<LanePosition> lanePositions;
34
35 /**
36 * Constructor with set of lane positions.
37 * @param lanePositions set of lane locations
38 */
39 public CrossSection(final Set<LanePosition> lanePositions)
40 {
41 Throw.whenNull(lanePositions, "Lane positions may not be null.");
42 this.lanePositions = new LinkedHashSet<>(lanePositions);
43 }
44
45 /**
46 * Constructor with link and fraction. Note that the fraction is used with the length of each lane. For curved links this
47 * fraction may not point to locations on the lane that are perfectly laterally adjacent. GTUs can thus possibly change lane
48 * at these gaps and be missed.
49 * @param link link
50 * @param fraction fraction on link
51 */
52 public CrossSection(final LinkData<?> link, final double fraction)
53 {
54 Throw.whenNull(link, "Link lane positions may not be null.");
55 this.lanePositions = new LinkedHashSet<>();
56 for (LaneData<?> lane : link.getLanes())
57 {
58 LanePosition lanePosition = new LanePosition(lane, lane.getLength().times(fraction));
59 this.lanePositions.add(lanePosition);
60 }
61 }
62
63 /**
64 * Returns the number of lane positions.
65 * @return number of directed lane positions
66 */
67 public final int size()
68 {
69 return this.lanePositions.size();
70 }
71
72 /**
73 * Returns a safe copy of the lane positions.
74 * @return safe copy of lane positions
75 */
76 public final Set<LanePosition> getLanePositions()
77 {
78 return new LinkedHashSet<>(this.lanePositions);
79 }
80
81 /**
82 * Returns an iterator over the lane positions.
83 * @return iterator over lane positions
84 */
85 @Override
86 public final Iterator<LanePosition> iterator()
87 {
88 return new ImmutableIterator<>(this.lanePositions.iterator());
89 }
90
91 @Override
92 public String toString()
93 {
94 return "CrossSection [lanePositions=" + this.lanePositions + "]";
95 }
96
97 /**
98 * Position on a lane.
99 * @param lane lane
100 * @param position position
101 */
102 @SuppressWarnings("javadoc") // @param's present but warning still given, bug?
103 public record LanePosition(LaneData<?> lane, Length position)
104 {
105 /**
106 * Construct a new LanePosition.
107 */
108 public LanePosition
109 {
110 Throw.whenNull(lane, "lane is null");
111 Throw.whenNull(position, "position is null");
112 }
113 }
114
115 }