1 package org.opentrafficsim.draw.lane;
2
3 import java.awt.BasicStroke;
4 import java.awt.Color;
5 import java.awt.Graphics2D;
6 import java.awt.geom.Path2D;
7 import java.awt.image.ImageObserver;
8 import java.lang.reflect.Field;
9 import java.rmi.RemoteException;
10 import java.util.LinkedHashSet;
11 import java.util.Set;
12
13 import javax.naming.NamingException;
14
15 import org.djutils.exceptions.Try;
16 import org.opentrafficsim.core.geometry.OTSLine3D;
17 import org.opentrafficsim.core.geometry.OTSPoint3D;
18 import org.opentrafficsim.core.gtu.GTU;
19 import org.opentrafficsim.road.gtu.lane.perception.LaneStructureRecord;
20 import org.opentrafficsim.road.gtu.lane.perception.RollingLaneStructure;
21 import org.opentrafficsim.road.gtu.lane.perception.RollingLaneStructureRecord;
22 import org.opentrafficsim.road.gtu.lane.perception.RollingLaneStructureRecord.RecordLink;
23
24 import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
25 import nl.tudelft.simulation.language.d3.DirectedPoint;
26
27
28
29
30
31
32
33
34
35 public class LaneStructureAnimation extends Renderable2D<LaneStructureLocatable>
36 {
37
38 private boolean isDestroyed = false;
39
40
41
42
43
44
45 LaneStructureAnimation(final LaneStructureLocatable source) throws NamingException, RemoteException
46 {
47 super(source, source.getGtu().getSimulator());
48 this.setFlip(false);
49 this.setRotate(false);
50 }
51
52
53 @Override
54 public void paint(final Graphics2D graphics, final ImageObserver observer) throws RemoteException
55 {
56 if (!this.isDestroyed)
57 {
58 if (getSource().getGtu().isDestroyed())
59 {
60 this.isDestroyed = true;
61 Try.execute(() -> destroy(), "Exception during deletion of LaneStructureAnimation.");
62 return;
63 }
64 else
65 {
66 LaneStructureRecord rt = getSource().getRollingLaneStructure().getRootRecord();
67 if (rt != null)
68 {
69 paintRecord(rt, graphics);
70 }
71 }
72 }
73 }
74
75
76
77
78
79 @SuppressWarnings({ "unchecked" })
80 private void paintRecord(final LaneStructureRecord lsr, final Graphics2D graphics)
81 {
82
83 DirectedPoint loc = Try.assign(() -> getSource().getLocation(), "Unable to return location.");
84 graphics.setStroke(new BasicStroke(
85 getSource().getRollingLaneStructure().animationAccess.getCrossSectionRecords().containsValue(lsr) ? 1.0f
86 : 0.5f));
87 graphics.setColor(
88 getSource().getRollingLaneStructure().animationAccess.getCrossSectionRecords().containsValue(lsr) ? Color.PINK
89 : getSource().getRollingLaneStructure().animationAccess.getUpstreamEdge().contains(lsr) ? Color.MAGENTA
90 : getSource().getRollingLaneStructure().animationAccess.getDownstreamEdge().contains(lsr)
91 ? Color.GREEN : Color.CYAN);
92 OTSLine3D line = Try.assign(() -> lsr.getLane().getCenterLine().extractFractional(0.1, 0.9),
93 "Exception while painting LaneStructures");
94 Path2D.Double path = new Path2D.Double();
95 boolean start = true;
96 for (OTSPoint3D point : line.getPoints())
97 {
98 if (start)
99 {
100 path.moveTo(point.x - loc.x, -(point.y - loc.y));
101 start = false;
102 }
103 else
104 {
105 path.lineTo(point.x - loc.x, -(point.y - loc.y));
106 }
107 }
108 graphics.draw(path);
109
110 Field sourceField = Try.assign(() -> RollingLaneStructureRecord.class.getDeclaredField("source"),
111 "Exception while painting LaneStructure");
112 sourceField.setAccessible(true);
113 LaneStructureRecord src =
114 Try.assign(() -> (LaneStructureRecord) sourceField.get(lsr), "Exception while painting LaneStructure");
115 if (src != null)
116 {
117 Field sourceLinkField = Try.assign(() -> RollingLaneStructureRecord.class.getDeclaredField("sourceLink"),
118 "Exception while painting LaneStructure");
119 sourceLinkField.setAccessible(true);
120 RecordLink link = (RecordLink) Try.assign(() -> sourceLinkField.get(lsr), "Exception while painting LaneStructure");
121 float f1 = link.equals(RecordLink.DOWN) ? 0.9f : link.equals(RecordLink.UP) ? 0.1f : 0.5f;
122 float f2 = link.equals(RecordLink.DOWN) ? 0.0f : link.equals(RecordLink.UP) ? 1.0f : 0.5f;
123 f1 = src.getDirection().isPlus() ? f1 : 1.0f - f1;
124 f2 = lsr.getDirection().isPlus() ? f2 : 1.0f - f2;
125 float f3 = f1;
126 float f4 = f2;
127 DirectedPoint p1 = Try.assign(() -> src.getLane().getCenterLine().getLocationFraction(f3),
128 "Exception while painting LaneStructure");
129 DirectedPoint p2 = Try.assign(() -> line.getLocationFraction(f4), "Exception while painting LaneStructure");
130 path = new Path2D.Double();
131 path.moveTo(p1.x - loc.x, -(p1.y - loc.y));
132 path.lineTo(p2.x - loc.x, -(p2.y - loc.y));
133 graphics.setStroke(
134 new BasicStroke(0.15f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[] { .3f, 1.2f }, 0f));
135 graphics.setColor(Color.DARK_GRAY);
136 graphics.draw(path);
137 }
138
139 paintLateralConnection(lsr, lsr.getLeft(), Color.RED, graphics, loc);
140 paintLateralConnection(lsr, lsr.getRight(), Color.BLUE, graphics, loc);
141
142 Field dependentField = Try.assign(() -> RollingLaneStructureRecord.class.getDeclaredField("dependentRecords"),
143 "Exception while painting LaneStructure");
144 dependentField.setAccessible(true);
145 Set<LaneStructureRecord> dependables =
146 (Set<LaneStructureRecord>) Try.assign(() -> dependentField.get(lsr), "Exception while painting LaneStructure");
147 if (dependables != null)
148 {
149 for (LaneStructureRecord dependable : new LinkedHashSet<>(dependables))
150 {
151 paintRecord(dependable, graphics);
152 }
153 }
154 }
155
156
157
158
159
160
161
162
163
164 private void paintLateralConnection(final LaneStructureRecord main, final LaneStructureRecord adj, final Color color,
165 final Graphics2D graphics, final DirectedPoint loc)
166 {
167 if (adj == null)
168 {
169 return;
170 }
171 float f1 = main.getDirection().isPlus() ? 0.45f : 0.55f;
172 float f2 = adj.getDirection().isPlus() ? 0.55f : 0.45f;
173 DirectedPoint p1 = Try.assign(() -> main.getLane().getCenterLine().getLocationFraction(f1),
174 "Exception while painting LaneStructure");
175 DirectedPoint p2 = Try.assign(() -> adj.getLane().getCenterLine().getLocationFraction(f2),
176 "Exception while painting LaneStructure");
177 Path2D.Double path = new Path2D.Double();
178 path.moveTo(p1.x - loc.x, -(p1.y - loc.y));
179 path.lineTo(p2.x - loc.x, -(p2.y - loc.y));
180 graphics.setStroke(
181 new BasicStroke(0.05f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[] { .15f, 0.6f }, 0f));
182 graphics.setColor(color);
183 graphics.draw(path);
184 }
185
186
187
188
189
190
191 public static final void visualize(final RollingLaneStructure rollingLaneStructure, final GTU gtu)
192 {
193 Try.execute(() -> new LaneStructureAnimation(new LaneStructureLocatable(rollingLaneStructure, gtu)),
194 "Could not create animation.");
195 }
196
197 }