GraphUtil.java

  1. package org.opentrafficsim.draw.graphs;

  2. import java.awt.Color;
  3. import java.awt.Paint;
  4. import java.util.LinkedHashMap;
  5. import java.util.List;
  6. import java.util.Map;

  7. import org.djunits.value.vdouble.scalar.Length;
  8. import org.djunits.value.vdouble.scalar.Time;
  9. import org.jfree.chart.ChartMouseEvent;
  10. import org.jfree.chart.ChartMouseListener;
  11. import org.jfree.chart.LegendItem;
  12. import org.jfree.chart.LegendItemCollection;
  13. import org.jfree.chart.entity.LegendItemEntity;
  14. import org.opentrafficsim.kpi.sampling.SamplingException;
  15. import org.opentrafficsim.kpi.sampling.Trajectory;

  16. /**
  17.  * Contains some static utilities.
  18.  * <p>
  19.  * Copyright (c) 2013-2020 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 15 okt. 2018 <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 final class GraphUtil
  28. {

  29.     /**
  30.      * Constructor.
  31.      */
  32.     private GraphUtil()
  33.     {
  34.         // no instances
  35.     }

  36.     /**
  37.      * Helper method for quick filtering of trajectories by checking if the time of the trajectory has overlap with the given
  38.      * time.
  39.      * @param trajectory Trajectory&lt;?&gt;; trajectory
  40.      * @param startTime Time; start time
  41.      * @param endTime Time; end time
  42.      * @return boolean; true if the trajectory should be considered for the given time
  43.      */
  44.     public static boolean considerTrajectory(final Trajectory<?> trajectory, final Time startTime, final Time endTime)
  45.     {
  46.         try
  47.         {
  48.             return trajectory.getT(0) < endTime.si && trajectory.getT(trajectory.size() - 1) > startTime.si;
  49.         }
  50.         catch (SamplingException exception)
  51.         {
  52.             throw new RuntimeException("Unexpected exception while checking whether the trajectory should be considered.",
  53.                     exception);
  54.         }
  55.     }

  56.     /**
  57.      * Helper method for quick filtering of trajectories by checking if the position of the trajectory has overlap with the
  58.      * given range.
  59.      * @param trajectory Trajectory&lt;?&gt;; trajectory
  60.      * @param startPosition Length; start position
  61.      * @param endPosition Length; end position
  62.      * @return boolean; true if the trajectory should be considered for the given time
  63.      */
  64.     public static boolean considerTrajectory(final Trajectory<?> trajectory, final Length startPosition,
  65.             final Length endPosition)
  66.     {
  67.         try
  68.         {
  69.             return trajectory.getX(0) < startPosition.si && trajectory.getX(trajectory.size() - 1) > endPosition.si;
  70.         }
  71.         catch (SamplingException exception)
  72.         {
  73.             throw new RuntimeException("Unexpected exception while checking whether the trajectory should be considered.",
  74.                     exception);
  75.         }
  76.     }

  77.     /**
  78.      * Ensures that the given capacity is available in the array. The array may become or may be longer than the required
  79.      * capacity. This method assumes that the array has non-zero length, and that the capacity required is at most 1 more than
  80.      * what the array can provide.
  81.      * @param data double[]; data array
  82.      * @param capacity int; required capacity
  83.      * @return double[]; array with at least the requested capacity
  84.      */
  85.     public static double[] ensureCapacity(final double[] data, final int capacity)
  86.     {
  87.         if (data.length < capacity)
  88.         {
  89.             double[] out = new double[data.length + (data.length >> 1)];
  90.             System.arraycopy(data, 0, out, 0, data.length);
  91.             return out;
  92.         }
  93.         return data;
  94.     }

  95.     /**
  96.      * Ensures that the given capacity is available in the array. The array may become or may be longer than the required
  97.      * capacity. This method assumes that the array has non-zero length, and that the capacity required is at most 1 more than
  98.      * what the array can provide.
  99.      * @param data float[]; data array
  100.      * @param capacity int; required capacity
  101.      * @return float[]; array with at least the requested capacity
  102.      */
  103.     public static float[] ensureCapacity(final float[] data, final int capacity)
  104.     {
  105.         if (data.length < capacity)
  106.         {
  107.             float[] out = new float[data.length + (data.length >> 1)];
  108.             System.arraycopy(data, 0, out, 0, data.length);
  109.             return out;
  110.         }
  111.         return data;
  112.     }

  113.     /**
  114.      * Ensures that the given capacity is available in the array. The array may become or may be longer than the required
  115.      * capacity. This method assumes that the array has non-zero length, and that the capacity required is at most 1 more than
  116.      * what the array can provide.
  117.      * @param data int[]; data array
  118.      * @param capacity int; required capacity
  119.      * @return int[]; array with at least the requested capacity
  120.      */
  121.     public static int[] ensureCapacity(final int[] data, final int capacity)
  122.     {
  123.         if (data.length < capacity)
  124.         {
  125.             int[] out = new int[data.length + (data.length >> 1)];
  126.             System.arraycopy(data, 0, out, 0, data.length);
  127.             return out;
  128.         }
  129.         return data;
  130.     }

  131.     /**
  132.      * Returns a chart listener that allows the series to be enabled and disabled by clicking on the respective legend item.
  133.      * @param legend LegendItemCollection; legend
  134.      * @param visibility List&lt;Boolean&gt;; visibility of each series; the listener will store visibility in this list, which
  135.      *            an {@code AbstractRenderer} can use in {@code isSeriesVisible(series)} to show or hide the series
  136.      * @param <K> underlying key type of the series
  137.      * @return ChartMouseListener; listener that will allow series to be enabled and disabled by clicking on the respective
  138.      *         legend item
  139.      */
  140.     @SuppressWarnings("unchecked")
  141.     public static <K> ChartMouseListener getToggleSeriesByLegendListener(final LegendItemCollection legend,
  142.             final List<Boolean> visibility)
  143.     {
  144.         Map<K, Paint> colors = new LinkedHashMap<>();
  145.         Map<K, Integer> series = new LinkedHashMap<>();
  146.         for (int i = 0; i < legend.getItemCount(); i++)
  147.         {
  148.             LegendItem legendItem = legend.get(i);
  149.             colors.put((K) legendItem.getSeriesKey(), legendItem.getFillPaint());
  150.             series.put((K) legendItem.getSeriesKey(), i);
  151.             legendItem.setToolTipText("Click to show/hide");
  152.         }
  153.         if (legend.getItemCount() < 2)
  154.         {
  155.             return null;
  156.         }
  157.         return new ChartMouseListener()
  158.         {
  159.             /** {@inheritDoc} */
  160.             @Override
  161.             public void chartMouseClicked(final ChartMouseEvent event)
  162.             {
  163.                 if (event.getEntity() instanceof LegendItemEntity)
  164.                 {
  165.                     K key = (K) ((LegendItemEntity) event.getEntity()).getSeriesKey();
  166.                     int s = series.get(key);
  167.                     boolean visible = !visibility.get(s);
  168.                     visibility.set(s, visible);
  169.                     legend.get(s).setLabelPaint(visible ? Color.BLACK : Color.LIGHT_GRAY);
  170.                     legend.get(s).setFillPaint(visible ? colors.get(key) : Color.LIGHT_GRAY);
  171.                 }
  172.             }

  173.             /** {@inheritDoc} */
  174.             @Override
  175.             public void chartMouseMoved(final ChartMouseEvent event)
  176.             {
  177.                 //
  178.             }
  179.         };
  180.     }
  181. }