SplitColorer.java

  1. package org.opentrafficsim.road.gtu.colorer;

  2. import java.awt.Color;
  3. import java.util.ArrayList;
  4. import java.util.List;
  5. import java.util.Set;

  6. import org.opentrafficsim.core.animation.gtu.colorer.GTUColorer;
  7. import org.opentrafficsim.core.geometry.OTSGeometryException;
  8. import org.opentrafficsim.core.geometry.OTSPoint3D;
  9. import org.opentrafficsim.core.gtu.GTU;
  10. import org.opentrafficsim.core.gtu.GTUException;
  11. import org.opentrafficsim.core.network.Link;
  12. import org.opentrafficsim.core.network.LinkDirection;
  13. import org.opentrafficsim.core.network.NetworkException;
  14. import org.opentrafficsim.core.network.route.Route;
  15. import org.opentrafficsim.road.gtu.lane.LaneBasedGTU;
  16. import org.opentrafficsim.road.network.lane.DirectedLanePosition;

  17. /**
  18.  * <p>
  19.  * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
  20.  * BSD-style license. See <a href="http://opentrafficsim.org/node/13">OpenTrafficSim License</a>.
  21.  * <p>
  22.  * @version $Revision$, $LastChangedDate$, by $Author$, initial version 14 apr. 2017 <br>
  23.  * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
  24.  * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
  25.  * @author <a href="http://www.transport.citg.tudelft.nl">Wouter Schakel</a>
  26.  */

  27. public class SplitColorer implements GTUColorer
  28. {

  29.     /** Left color. */
  30.     static final Color LEFT = Color.GREEN;

  31.     /** Other color. */
  32.     static final Color OTHER = Color.BLUE;

  33.     /** Right color. */
  34.     static final Color RIGHT = Color.RED;

  35.     /** Unknown color. */
  36.     static final Color UNKNOWN = Color.WHITE;

  37.     /** The legend. */
  38.     private static final List<LegendEntry> LEGEND;

  39.     static
  40.     {
  41.         LEGEND = new ArrayList<>(4);
  42.         LEGEND.add(new LegendEntry(LEFT, "Left", "Left"));
  43.         LEGEND.add(new LegendEntry(RIGHT, "Right", "Right"));
  44.         LEGEND.add(new LegendEntry(OTHER, "Other", "Other"));
  45.         LEGEND.add(new LegendEntry(UNKNOWN, "Unknown", "Unknown"));
  46.     }

  47.     /** {@inheritDoc} */
  48.     @Override
  49.     public final Color getColor(final GTU gtu)
  50.     {
  51.         if (!(gtu instanceof LaneBasedGTU))
  52.         {
  53.             return UNKNOWN;
  54.         }
  55.         LaneBasedGTU laneGtu = (LaneBasedGTU) gtu;
  56.         DirectedLanePosition refPos;
  57.         try
  58.         {
  59.             refPos = laneGtu.getReferencePosition();

  60.         }
  61.         catch (GTUException exception)
  62.         {
  63.             return UNKNOWN;
  64.         }
  65.         LinkDirection linkDir = refPos.getLinkDirection();
  66.         Route route = laneGtu.getStrategicalPlanner().getRoute();
  67.         if (route == null)
  68.         {
  69.             return UNKNOWN;
  70.         }

  71.         // get all links we can go in to
  72.         Set<Link> nextLinks;
  73.         Link preLink;
  74.         do
  75.         {
  76.             try
  77.             {
  78.                 preLink = linkDir.getLink();
  79.                 nextLinks = linkDir.getNodeTo().nextLinks(gtu.getGTUType(), linkDir.getLink());
  80.                 if (!nextLinks.isEmpty())
  81.                 {
  82.                     linkDir = laneGtu.getStrategicalPlanner().nextLinkDirection(preLink, linkDir.getDirection(),
  83.                             gtu.getGTUType());
  84.                 }
  85.             }
  86.             catch (NetworkException exception)
  87.             {
  88.                 // System.err.println("Network exception while defining split color for GTU.");
  89.                 return UNKNOWN;
  90.             }
  91.         }
  92.         while (nextLinks.size() == 1);

  93.         // dead end
  94.         if (nextLinks.isEmpty())
  95.         {
  96.             return UNKNOWN;
  97.         }

  98.         // split, sort next links
  99.         try
  100.         {
  101.             double preAngle =
  102.                     linkDir.getDirection().isPlus() ? linkDir.getLink().getDesignLine().getLocationFraction(1.0).getRotZ()
  103.                             : linkDir.getLink().getDesignLine().getLocationFraction(0.0).getRotZ() - Math.PI;
  104.             OTSPoint3D pre = linkDir.getDirection().isPlus() ? linkDir.getLink().getDesignLine().getLast()
  105.                     : linkDir.getLink().getDesignLine().getFirst();
  106.             List<Double> angles = new ArrayList<>();
  107.             List<Link> links = new ArrayList<>();
  108.             for (Link nextLink : nextLinks)
  109.             {
  110.                 double angle = getAngle(pre, nextLink.getStartNode().equals(linkDir.getNodeFrom())
  111.                         ? nextLink.getDesignLine().get(1) : nextLink.getDesignLine().get(nextLink.getDesignLine().size() - 2));
  112.                 angle -= preAngle; // difference with from
  113.                 while (angle < -Math.PI)
  114.                 {
  115.                     angle += Math.PI * 2;
  116.                 }
  117.                 while (angle > Math.PI)
  118.                 {
  119.                     angle -= Math.PI * 2;
  120.                 }
  121.                 if (angles.isEmpty() || angle < angles.get(0))
  122.                 {
  123.                     angles.add(0, angle);
  124.                     links.add(0, nextLink);
  125.                 }
  126.                 else if (angle > angles.get(angles.size() - 1))
  127.                 {
  128.                     angles.add(angle);
  129.                     links.add(nextLink);
  130.                 }
  131.                 else
  132.                 {
  133.                     for (double a : angles)
  134.                     {
  135.                         if (a > angle)
  136.                         {
  137.                             int index = angles.indexOf(angle);
  138.                             angles.add(index, angle);
  139.                             links.add(index, nextLink);
  140.                         }
  141.                     }
  142.                 }
  143.             }
  144.             int index = links.indexOf(linkDir.getLink());
  145.             if (index == 0)
  146.             {
  147.                 return RIGHT;
  148.             }
  149.             else if (index == links.size() - 1)
  150.             {
  151.                 return LEFT;
  152.             }
  153.             return OTHER;
  154.         }
  155.         catch (OTSGeometryException exception)
  156.         {
  157.             // should not happen as the fractions are 0.0 and 1.0
  158.             throw new RuntimeException("Angle could not be calculated.", exception);
  159.         }
  160.     }

  161.     /**
  162.      * Returns the angle between two points.
  163.      * @param from OTSPoint3D; from point
  164.      * @param to OTSPoint3D; to point
  165.      * @return angle between two points
  166.      */
  167.     private double getAngle(final OTSPoint3D from, final OTSPoint3D to)
  168.     {
  169.         return Math.atan2(to.x - from.x, to.y - from.y);
  170.     }

  171.     /** {@inheritDoc} */
  172.     @Override
  173.     public final List<LegendEntry> getLegend()
  174.     {
  175.         return LEGEND;
  176.     }

  177.     /** {@inheritDoc} */
  178.     @Override
  179.     public final String toString()
  180.     {
  181.         return "Split";
  182.     }

  183. }