1   package org.opentrafficsim.draw.gtu;
2   
3   import java.awt.BasicStroke;
4   import java.awt.Color;
5   import java.awt.Graphics2D;
6   import java.awt.geom.Ellipse2D;
7   import java.awt.geom.Rectangle2D;
8   import java.awt.geom.RectangularShape;
9   import java.awt.image.ImageObserver;
10  import java.io.Serializable;
11  import java.rmi.RemoteException;
12  
13  import javax.naming.NamingException;
14  
15  import org.opentrafficsim.core.animation.gtu.colorer.DefaultSwitchableGTUColorer;
16  import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
17  import org.opentrafficsim.core.animation.gtu.colorer.IDGTUColorer;
18  import org.opentrafficsim.core.gtu.GTUType;
19  import org.opentrafficsim.draw.core.ClonableRenderable2DInterface;
20  import org.opentrafficsim.draw.core.TextAlignment;
21  import org.opentrafficsim.draw.core.TextAnimation;
22  import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
23  import org.opentrafficsim.road.gtu.lane.LaneBasedIndividualGTU;
24  
25  import nl.tudelft.simulation.dsol.animation.Locatable;
26  import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
27  import nl.tudelft.simulation.dsol.simulators.SimulatorInterface;
28  import nl.tudelft.simulation.language.d2.Angle;
29  import nl.tudelft.simulation.language.d3.DirectedPoint;
30  
31  
32  
33  
34  
35  
36  
37  
38  
39  
40  
41  
42  public class DefaultCarAnimation extends Renderable2D<LaneBasedGTU>
43          implements ClonableRenderable2DInterface<LaneBasedGTU>, Serializable
44  {
45      
46      private static final long serialVersionUID = 20150000L;
47  
48      
49      private GTUColorer gtuColorer = new DefaultSwitchableGTUColorer();
50  
51      
52      private Text text;
53  
54      
55      private boolean isDestroyed = false;
56  
57      
58      private final int hashCode;
59  
60      
61      private Rectangle2D.Double rectangle;
62  
63      
64      private Ellipse2D.Double frontIndicator;
65  
66      
67      private Rectangle2D.Double leftIndicator;
68  
69      
70      private Rectangle2D.Double rightIndicator;
71  
72      
73      private Rectangle2D.Double leftBrake;
74  
75      
76      private Rectangle2D.Double rightBrake;
77  
78      
79      private RectangularShape dot;
80  
81      
82  
83  
84  
85  
86  
87  
88      public DefaultCarAnimation(final LaneBasedGTU gtu, final SimulatorInterface.TimeDoubleUnit simulator)
89              throws NamingException, RemoteException
90      {
91          this(gtu, simulator, null);
92      }
93  
94      
95  
96  
97  
98  
99  
100 
101 
102     public DefaultCarAnimation(final LaneBasedGTU gtu, final SimulatorInterface.TimeDoubleUnit simulator,
103             final GTUColorer gtuColorer) throws NamingException, RemoteException
104     {
105         super(gtu, simulator);
106         this.hashCode = gtu.hashCode();
107         if (null == gtuColorer)
108         {
109             this.gtuColorer = new IDGTUColorer();
110         }
111         else
112         {
113             this.gtuColorer = gtuColorer;
114         }
115         this.text = new Text(gtu, gtu.getId(), 0.0f, 0.0f, TextAlignment.CENTER, Color.BLACK, simulator,
116                 new TextAnimation.ContrastToBackground()
117                 {
118 
119                     @Override
120                     public Color getBackgroundColor()
121                     {
122                         return gtuColorer.getColor(gtu);
123                     }
124                 });
125     }
126 
127     
128 
129 
130 
131     public final void setGTUColorer(final GTUColorer newGTUColorer)
132     {
133         this.gtuColorer = newGTUColorer;
134     }
135 
136     
137     @Override
138     public final void paint(final Graphics2D graphics, final ImageObserver observer)
139     {
140         final LaneBasedGTU gtu = getSource();
141         if (gtu.isDestroyed())
142         {
143             if (!this.isDestroyed)
144             {
145                 try
146                 {
147                     destroy();
148                 }
149                 catch (Exception e)
150                 {
151                     System.err.println("Error while destroying GTU " + gtu.getId());
152                     e.printStackTrace();
153                 }
154             }
155             return;
156         }
157 
158         if (this.rectangle == null)
159         {
160             
161             
162             final double length = gtu.getLength().si;
163             final double lFront = gtu.getFront().getDx().si;
164             final double lRear = gtu.getRear().getDx().si;
165             final double width = gtu.getWidth().si;
166             final double w2 = width / 2;
167             final double w4 = width / 4;
168             this.rectangle = new Rectangle2D.Double(lRear, -w2, length, width);
169             this.frontIndicator = new Ellipse2D.Double(lFront - w2 - w4, -w4, w2, w2);
170             this.leftIndicator = new Rectangle2D.Double(lFront - w4, -w2, w4, w4);
171             this.rightIndicator = new Rectangle2D.Double(lFront - w4, w2 - w4, w4, w4);
172             this.leftBrake = new Rectangle2D.Double(lRear, w2 - w4, w4, w4);
173             this.rightBrake = new Rectangle2D.Double(lRear, -w2, w4, w4);
174             this.dot = gtu.getGTUType().isOfType(gtu.getPerceivableContext().getGtuType(GTUType.DEFAULTS.TRUCK))
175                     ? new Rectangle2D.Double(0, 0, 0, 0) : new Ellipse2D.Double(0, 0, 0, 0);
176         }
177 
178         double scale = graphics.getTransform().getDeterminant();
179         
180         
181         if (scale > 1)
182         {
183             Color color = this.gtuColorer.getColor(gtu);
184             graphics.setColor(color);
185             BasicStroke saveStroke = (BasicStroke) graphics.getStroke();
186             graphics.setStroke(new BasicStroke(0.05f)); 
187             graphics.fill(this.rectangle);
188 
189             graphics.setColor(Color.WHITE);
190             graphics.fill(this.frontIndicator);
191             
192             if (color.equals(Color.WHITE))
193             {
194                 
195                 graphics.setColor(Color.BLACK);
196                 graphics.draw(this.frontIndicator);
197             }
198 
199             
200             graphics.setColor(Color.YELLOW);
201             if (gtu.getTurnIndicatorStatus() != null && gtu.getTurnIndicatorStatus().isLeftOrBoth())
202             {
203                 graphics.fill(this.leftIndicator);
204                 if (color.equals(Color.YELLOW))
205                 {
206                     graphics.setColor(Color.BLACK);
207                     graphics.draw(this.leftIndicator);
208                 }
209             }
210             if (gtu.getTurnIndicatorStatus() != null && gtu.getTurnIndicatorStatus().isRightOrBoth())
211             {
212                 graphics.fill(this.rightIndicator);
213                 if (color.equals(Color.YELLOW))
214                 {
215                     graphics.setColor(Color.BLACK);
216                     graphics.draw(this.rightIndicator);
217                 }
218             }
219 
220             
221             if (gtu.isBrakingLightsOn())
222             {
223                 graphics.setColor(Color.RED);
224                 graphics.fill(this.leftBrake);
225                 graphics.fill(this.rightBrake);
226                 if (color.equals(Color.RED))
227                 {
228                     graphics.setColor(Color.BLACK);
229                     graphics.draw(this.leftBrake);
230                     graphics.draw(this.rightBrake);
231                 }
232             }
233             graphics.setStroke(saveStroke);
234         }
235         else
236         {
237             
238             graphics.setColor(this.gtuColorer.getColor(gtu));
239             double w = 7.0 / Math.sqrt(scale);
240             double x = -w / 2.0;
241             this.dot.setFrame(x, x, w, w);
242             graphics.fill(this.dot);
243         }
244     }
245 
246     
247     @Override
248     public final void destroy() throws NamingException
249     {
250         this.isDestroyed = true;
251         super.destroy();
252         this.text.destroy();
253     }
254 
255     
256     @Override
257     @SuppressWarnings("checkstyle:designforextension")
258     public ClonableRenderable2DInterface<LaneBasedGTU> clone(final LaneBasedGTU newSource,
259             final SimulatorInterface.TimeDoubleUnit newSimulator) throws NamingException, RemoteException
260     {
261         
262         return new DefaultCarAnimation(newSource, newSimulator, this.gtuColorer);
263     }
264 
265     
266     @Override
267     public final String toString()
268     {
269         return super.toString(); 
270     }
271 
272     
273     @Override
274     public int hashCode()
275     {
276         return this.hashCode;
277     }
278 
279     
280     @Override
281     public boolean equals(final Object object)
282     {
283         
284         return super.equals(object);
285     }
286 
287     
288 
289 
290 
291 
292 
293 
294 
295 
296 
297 
298 
299 
300     public class Text extends TextAnimation
301     {
302         
303         private static final long serialVersionUID = 20161211L;
304 
305         
306         private boolean isTextDestroyed = false;
307 
308         
309 
310 
311 
312 
313 
314 
315 
316 
317 
318 
319         public Text(final Locatable source, final String text, final float dx, final float dy,
320                 final TextAlignment textAlignment, final Color color, final SimulatorInterface.TimeDoubleUnit simulator)
321                 throws RemoteException, NamingException
322         {
323             super(source, text, dx, dy, textAlignment, color, 1.0f, 12.0f, 50f, simulator, TextAnimation.RENDERWHEN1);
324         }
325 
326         
327 
328 
329 
330 
331 
332 
333 
334 
335 
336 
337 
338         @SuppressWarnings("parameternumber")
339         public Text(final Locatable source, final String text, final float dx, final float dy,
340                 final TextAlignment textAlignment, final Color color, final SimulatorInterface.TimeDoubleUnit simulator,
341                 final TextAnimation.ContrastToBackground background) throws RemoteException, NamingException
342         {
343             super(source, text, dx, dy, textAlignment, color, 1.0f, 12.0f, 50f, simulator, background, RENDERWHEN1);
344         }
345 
346         
347         @Override
348         public final void paint(final Graphics2D graphics, final ImageObserver observer) throws RemoteException
349         {
350             final LaneBasedIndividualGTU car = (LaneBasedIndividualGTU) getSource();
351 
352             if (car.isDestroyed())
353             {
354                 if (!this.isTextDestroyed)
355                 {
356                     try
357                     {
358                         destroy();
359                     }
360                     catch (Exception e)
361                     {
362                         System.err.println("Error while destroying text animation of GTU " + car.getId());
363                     }
364                     this.isTextDestroyed = true;
365                 }
366                 return;
367             }
368 
369             super.paint(graphics, observer);
370         }
371 
372         
373         @Override
374         @SuppressWarnings("checkstyle:designforextension")
375         public DirectedPoint getLocation() throws RemoteException
376         {
377             
378             DirectedPoint p = ((LaneBasedIndividualGTU) getSource()).getLocation();
379             double a = Angle.normalizePi(p.getRotZ());
380             if (a > Math.PI / 2.0 || a < -0.99 * Math.PI / 2.0)
381             {
382                 a += Math.PI;
383             }
384             return new DirectedPoint(p.x, p.y, Double.MAX_VALUE, 0.0, 0.0, a);
385         }
386 
387         
388         @Override
389         @SuppressWarnings("checkstyle:designforextension")
390         public TextAnimation clone(final Locatable newSource, final SimulatorInterface.TimeDoubleUnit newSimulator)
391                 throws RemoteException, NamingException
392         {
393             return new Text(newSource, getText(), getDx(), getDy(), getTextAlignment(), getColor(), newSimulator);
394         }
395 
396         
397         @Override
398         public final String toString()
399         {
400             return "Text [isTextDestroyed=" + this.isTextDestroyed + "]";
401         }
402 
403     }
404 
405 }