1 package org.opentrafficsim.road.network.animation;
2
3 import java.awt.Color;
4 import java.awt.Graphics2D;
5 import java.awt.image.ImageObserver;
6 import java.io.Serializable;
7 import java.rmi.RemoteException;
8 import java.util.ArrayList;
9 import java.util.Arrays;
10
11 import javax.naming.NamingException;
12
13 import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
14
15 import org.opentrafficsim.core.dsol.OTSSimulatorInterface;
16 import org.opentrafficsim.core.geometry.OTSGeometryException;
17 import org.opentrafficsim.core.geometry.OTSLine3D;
18 import org.opentrafficsim.core.geometry.OTSPoint3D;
19 import org.opentrafficsim.core.network.animation.PaintPolygons;
20 import org.opentrafficsim.road.network.lane.Stripe;
21
22 import com.vividsolutions.jts.geom.Coordinate;
23 import com.vividsolutions.jts.geom.Geometry;
24 import com.vividsolutions.jts.linearref.LengthIndexedLine;
25 import com.vividsolutions.jts.operation.buffer.BufferParameters;
26
27
28
29
30
31
32
33
34
35
36
37 public class StripeAnimation extends Renderable2D implements Serializable
38 {
39
40 private static final long serialVersionUID = 20141017L;
41
42
43 private final TYPE type;
44
45
46 private final OTSLine3D line;
47
48
49 private static final int QUADRANTSEGMENTS = 8;
50
51
52
53
54
55
56
57
58
59
60
61
62 private ArrayList<OTSPoint3D> makeDashes(final LengthIndexedLine center, final double width,
63 final double startOffset, final double[] onOffLengths)
64 {
65 double period = 0;
66 for (double length : onOffLengths)
67 {
68 if (length < 0)
69 {
70 throw new Error("Bad pattern - on or off length is < 0");
71 }
72 period += length;
73 }
74 if (period <= 0)
75 {
76 throw new Error("Bad pattern - repeat period length is 0");
77 }
78 double length = center.getEndIndex();
79 double position = -startOffset;
80 int phase = 0;
81 ArrayList<OTSPoint3D> result = new ArrayList<>();
82 while (position < length)
83 {
84 double nextBoundary = position + onOffLengths[phase++ % onOffLengths.length];
85 if (nextBoundary > 0)
86 {
87 if (position < 0)
88 {
89 position = 0;
90 }
91 double endPosition = nextBoundary;
92 if (endPosition > length)
93 {
94 endPosition = length;
95 }
96 Coordinate[] oneDash =
97 center.extractLine(position, endPosition)
98 .buffer(width / 2, QUADRANTSEGMENTS, BufferParameters.CAP_FLAT).getCoordinates();
99 for (int i = 0; i < oneDash.length; i++)
100 {
101 result.add(new OTSPoint3D(oneDash[i]));
102 }
103 result.add(PaintPolygons.NEWPATH);
104 }
105 position = nextBoundary + onOffLengths[phase++ % onOffLengths.length];
106 }
107 return result;
108 }
109
110
111
112
113
114
115
116
117 private ArrayList<OTSPoint3D> makePoints(final Stripe stripe, final TYPE stripeType) throws NamingException
118 {
119 switch (this.type)
120 {
121 case DASHED:
122 return makeDashes(new LengthIndexedLine(stripe.getCenterLine().getLineString()), 0.2, 0, new double[]{
123 3, 9});
124
125 case DOUBLE:
126 {
127 OTSLine3D centerLine = stripe.getCenterLine();
128 Coordinate[] leftLine =
129 centerLine.offsetLine(0.2).getLineString().buffer(0.1, QUADRANTSEGMENTS, BufferParameters.CAP_FLAT)
130 .getCoordinates();
131 Coordinate[] rightLine =
132 centerLine.offsetLine(-0.2).getLineString()
133 .buffer(0.1, QUADRANTSEGMENTS, BufferParameters.CAP_FLAT).getCoordinates();
134 ArrayList<OTSPoint3D> result = new ArrayList<OTSPoint3D>(leftLine.length + rightLine.length);
135 for (int i = 0; i < leftLine.length; i++)
136 {
137 result.add(new OTSPoint3D(leftLine[i]));
138 }
139 for (int i = 0; i < rightLine.length; i++)
140 {
141 result.add(new OTSPoint3D(rightLine[i]));
142 }
143 return result;
144 }
145
146 case LEFTONLY:
147 {
148 OTSLine3D centerLine = stripe.getCenterLine();
149 Geometry rightDesignLine = centerLine.offsetLine(-0.2).getLineString();
150 ArrayList<OTSPoint3D> result =
151 makeDashes(new LengthIndexedLine(rightDesignLine), 0.2, 0, new double[]{3, 9});
152 Geometry leftDesignLine =
153 centerLine.offsetLine(0.2).getLineString().buffer(0.1, QUADRANTSEGMENTS, BufferParameters.CAP_FLAT);
154 Coordinate[] leftCoordinates =
155 leftDesignLine.buffer(0.1, QUADRANTSEGMENTS, BufferParameters.CAP_FLAT).getCoordinates();
156 for (int i = 0; i < leftCoordinates.length; i++)
157 {
158 result.add(new OTSPoint3D(leftCoordinates[i]));
159 }
160 result.add(PaintPolygons.NEWPATH);
161 return result;
162 }
163
164 case RIGHTONLY:
165 {
166 OTSLine3D centerLine = stripe.getCenterLine();
167 Geometry leftDesignLine = centerLine.offsetLine(0.2).getLineString();
168 ArrayList<OTSPoint3D> result =
169 makeDashes(new LengthIndexedLine(leftDesignLine), 0.2, 0, new double[]{3, 9});
170 Geometry rightDesignLine =
171 centerLine.offsetLine(-0.2).getLineString()
172 .buffer(0.1, QUADRANTSEGMENTS, BufferParameters.CAP_FLAT);
173 Coordinate[] rightCoordinates =
174 rightDesignLine.buffer(0.1, QUADRANTSEGMENTS, BufferParameters.CAP_FLAT).getCoordinates();
175 for (int i = 0; i < rightCoordinates.length; i++)
176 {
177 result.add(new OTSPoint3D(rightCoordinates[i]));
178 }
179 result.add(PaintPolygons.NEWPATH);
180 return result;
181 }
182
183 case SOLID:
184 return new ArrayList<OTSPoint3D>(Arrays.asList(stripe.getContour().getPoints()));
185
186 default:
187 throw new NamingException("Unsupported stripe type: " + stripeType);
188 }
189
190 }
191
192
193
194
195
196
197
198
199
200 public StripeAnimation(final Stripe source, final OTSSimulatorInterface simulator, final TYPE type)
201 throws NamingException, RemoteException, OTSGeometryException
202 {
203 super(source, simulator);
204 this.type = type;
205 this.line = new OTSLine3D(makePoints(source, type));
206 }
207
208
209 @Override
210 public final void paint(final Graphics2D graphics, final ImageObserver observer)
211 {
212 PaintPolygons.paintMultiPolygon(graphics, Color.WHITE, ((Stripe) getSource()).getLocation(), this.line, true);
213 }
214
215
216
217
218
219
220
221
222 public enum TYPE
223 {
224
225 SOLID,
226
227
228 LEFTONLY,
229
230
231 RIGHTONLY,
232
233
234 DASHED,
235
236
237 DOUBLE
238 }
239
240
241 @Override
242 public final String toString()
243 {
244 return "StripeAnimation [source = " + getSource().toString() + ", type=" + this.type + ", line=" + this.line + "]";
245 }
246 }