LaneStructureAnimation.java

  1. package org.opentrafficsim.draw.lane;

  2. import java.awt.BasicStroke;
  3. import java.awt.Color;
  4. import java.awt.Graphics2D;
  5. import java.awt.geom.Path2D;
  6. import java.awt.image.ImageObserver;
  7. import java.lang.reflect.Field;
  8. import java.rmi.RemoteException;
  9. import java.util.LinkedHashSet;
  10. import java.util.Set;

  11. import javax.naming.NamingException;

  12. import org.djutils.exceptions.Try;
  13. import org.opentrafficsim.core.geometry.OTSLine3D;
  14. import org.opentrafficsim.core.geometry.OTSPoint3D;
  15. import org.opentrafficsim.core.gtu.GTU;
  16. import org.opentrafficsim.road.gtu.lane.perception.LaneStructureRecord;
  17. import org.opentrafficsim.road.gtu.lane.perception.RollingLaneStructure;
  18. import org.opentrafficsim.road.gtu.lane.perception.RollingLaneStructureRecord;
  19. import org.opentrafficsim.road.gtu.lane.perception.RollingLaneStructureRecord.RecordLink;

  20. import nl.tudelft.simulation.dsol.animation.D2.Renderable2D;
  21. import nl.tudelft.simulation.language.d3.DirectedPoint;

  22. /**
  23.  * LaneStructureAnimation.java. <br>
  24.  * <br>
  25.  * Copyright (c) 2003-2020 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
  26.  * for project information <a href="https://www.simulation.tudelft.nl/" target="_blank">www.simulation.tudelft.nl</a>. The
  27.  * source code and binary code of this software is proprietary information of Delft University of Technology.
  28.  * @author <a href="https://www.tudelft.nl/averbraeck" target="_blank">Alexander Verbraeck</a>
  29.  */
  30. public class LaneStructureAnimation extends Renderable2D<LaneStructureLocatable>
  31. {
  32.     /** Destroyed. */
  33.     private boolean isDestroyed = false;

  34.     /**
  35.      * @param source LaneStructureLocatable; dummy locatable
  36.      * @throws NamingException on naming exception
  37.      * @throws RemoteException on remote exception
  38.      */
  39.     LaneStructureAnimation(final LaneStructureLocatable source) throws NamingException, RemoteException
  40.     {
  41.         super(source, source.getGtu().getSimulator());
  42.         this.setFlip(false);
  43.         this.setRotate(false);
  44.     }

  45.     /** {@inheritDoc} */
  46.     @Override
  47.     public void paint(final Graphics2D graphics, final ImageObserver observer) throws RemoteException
  48.     {
  49.         if (!this.isDestroyed)
  50.         {
  51.             if (getSource().getGtu().isDestroyed())
  52.             {
  53.                 this.isDestroyed = true;
  54.                 Try.execute(() -> destroy(), "Exception during deletion of LaneStructureAnimation.");
  55.                 return;
  56.             }
  57.             else
  58.             {
  59.                 LaneStructureRecord rt = getSource().getRollingLaneStructure().getRootRecord();
  60.                 if (rt != null)
  61.                 {
  62.                     paintRecord(rt, graphics);
  63.                 }
  64.             }
  65.         }
  66.     }

  67.     /**
  68.      * @param lsr LaneStructureRecord; record
  69.      * @param graphics Graphics2D; graphics
  70.      */
  71.     @SuppressWarnings({"unchecked"})
  72.     private void paintRecord(final LaneStructureRecord lsr, final Graphics2D graphics)
  73.     {
  74.         // line
  75.         DirectedPoint loc = Try.assign(() -> getSource().getLocation(), "Unable to return location.");
  76.         graphics.setStroke(new BasicStroke(
  77.                 getSource().getRollingLaneStructure().animationAccess.getCrossSectionRecords().containsValue(lsr) ? 1.0f
  78.                         : 0.5f));
  79.         graphics.setColor(
  80.                 getSource().getRollingLaneStructure().animationAccess.getCrossSectionRecords().containsValue(lsr) ? Color.PINK
  81.                         : getSource().getRollingLaneStructure().animationAccess.getUpstreamEdge().contains(lsr) ? Color.MAGENTA
  82.                                 : getSource().getRollingLaneStructure().animationAccess.getDownstreamEdge().contains(lsr)
  83.                                         ? Color.GREEN : Color.CYAN);
  84.         OTSLine3D line = Try.assign(() -> lsr.getLane().getCenterLine().extractFractional(0.1, 0.9),
  85.                 "Exception while painting LaneStructures");
  86.         Path2D.Double path = new Path2D.Double();
  87.         boolean start = true;
  88.         for (OTSPoint3D point : line.getPoints())
  89.         {
  90.             if (start)
  91.             {
  92.                 path.moveTo(point.x - loc.x, -(point.y - loc.y));
  93.                 start = false;
  94.             }
  95.             else
  96.             {
  97.                 path.lineTo(point.x - loc.x, -(point.y - loc.y));
  98.             }
  99.         }
  100.         graphics.draw(path);
  101.         // connection
  102.         Field sourceField = Try.assign(() -> RollingLaneStructureRecord.class.getDeclaredField("source"),
  103.                 "Exception while painting LaneStructure");
  104.         sourceField.setAccessible(true);
  105.         LaneStructureRecord src =
  106.                 Try.assign(() -> (LaneStructureRecord) sourceField.get(lsr), "Exception while painting LaneStructure");
  107.         if (src != null)
  108.         {
  109.             Field sourceLinkField = Try.assign(() -> RollingLaneStructureRecord.class.getDeclaredField("sourceLink"),
  110.                     "Exception while painting LaneStructure");
  111.             sourceLinkField.setAccessible(true);
  112.             RecordLink link = (RecordLink) Try.assign(() -> sourceLinkField.get(lsr), "Exception while painting LaneStructure");
  113.             float f1 = link.equals(RecordLink.DOWN) ? 0.9f : link.equals(RecordLink.UP) ? 0.1f : 0.5f;
  114.             float f2 = link.equals(RecordLink.DOWN) ? 0.0f : link.equals(RecordLink.UP) ? 1.0f : 0.5f;
  115.             f1 = src.getDirection().isPlus() ? f1 : 1.0f - f1;
  116.             f2 = lsr.getDirection().isPlus() ? f2 : 1.0f - f2;
  117.             float f3 = f1;
  118.             float f4 = f2;
  119.             DirectedPoint p1 = Try.assign(() -> src.getLane().getCenterLine().getLocationFraction(f3),
  120.                     "Exception while painting LaneStructure");
  121.             DirectedPoint p2 = Try.assign(() -> line.getLocationFraction(f4), "Exception while painting LaneStructure");
  122.             path = new Path2D.Double();
  123.             path.moveTo(p1.x - loc.x, -(p1.y - loc.y));
  124.             path.lineTo(p2.x - loc.x, -(p2.y - loc.y));
  125.             graphics.setStroke(
  126.                     new BasicStroke(0.15f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[] {.3f, 1.2f}, 0f));
  127.             graphics.setColor(Color.DARK_GRAY);
  128.             graphics.draw(path);
  129.         }
  130.         // left/right
  131.         paintLateralConnection(lsr, lsr.getLeft(), Color.RED, graphics, loc);
  132.         paintLateralConnection(lsr, lsr.getRight(), Color.BLUE, graphics, loc);
  133.         // recursion to depending records
  134.         Field dependentField = Try.assign(() -> RollingLaneStructureRecord.class.getDeclaredField("dependentRecords"),
  135.                 "Exception while painting LaneStructure");
  136.         dependentField.setAccessible(true);
  137.         Set<LaneStructureRecord> dependables =
  138.                 (Set<LaneStructureRecord>) Try.assign(() -> dependentField.get(lsr), "Exception while painting LaneStructure");
  139.         if (dependables != null)
  140.         {
  141.             for (LaneStructureRecord dependable : new LinkedHashSet<>(dependables)) // concurrency
  142.             {
  143.                 paintRecord(dependable, graphics);
  144.             }
  145.         }
  146.     }

  147.     /**
  148.      * Paint the connection to a lateral record.
  149.      * @param main LaneStructureRecord; main record
  150.      * @param adj LaneStructureRecord; adjacent record, can be {@code null}
  151.      * @param color Color; color
  152.      * @param graphics Graphics2D; graphics
  153.      * @param loc DirectedPoint; location
  154.      */
  155.     private void paintLateralConnection(final LaneStructureRecord main, final LaneStructureRecord adj, final Color color,
  156.             final Graphics2D graphics, final DirectedPoint loc)
  157.     {
  158.         if (adj == null)
  159.         {
  160.             return;
  161.         }
  162.         float f1 = main.getDirection().isPlus() ? 0.45f : 0.55f;
  163.         float f2 = adj.getDirection().isPlus() ? 0.55f : 0.45f;
  164.         DirectedPoint p1 = Try.assign(() -> main.getLane().getCenterLine().getLocationFraction(f1),
  165.                 "Exception while painting LaneStructure");
  166.         DirectedPoint p2 = Try.assign(() -> adj.getLane().getCenterLine().getLocationFraction(f2),
  167.                 "Exception while painting LaneStructure");
  168.         Path2D.Double path = new Path2D.Double();
  169.         path.moveTo(p1.x - loc.x, -(p1.y - loc.y));
  170.         path.lineTo(p2.x - loc.x, -(p2.y - loc.y));
  171.         graphics.setStroke(
  172.                 new BasicStroke(0.05f, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER, 10f, new float[] {.15f, 0.6f}, 0f));
  173.         graphics.setColor(color);
  174.         graphics.draw(path);
  175.     }

  176.     /**
  177.      * Enables visualization of this lane structure. This is purely for debugging purposes.
  178.      * @param rollingLaneStructure RollingLaneStructure; the lane structure to visualize
  179.      * @param gtu GTU; GTU to animate the LaneStructure of
  180.      */
  181.     public static final void visualize(final RollingLaneStructure rollingLaneStructure, final GTU gtu)
  182.     {
  183.         Try.execute(() -> new LaneStructureAnimation(new LaneStructureLocatable(rollingLaneStructure, gtu)),
  184.                 "Could not create animation.");
  185.     }

  186. }