View Javadoc
1   package org.opentrafficsim.editor.extensions.map.edit;
2   
3   import java.awt.BasicStroke;
4   import java.awt.Color;
5   import java.awt.Graphics2D;
6   import java.awt.image.ImageObserver;
7   import java.util.function.Function;
8   import java.util.function.Supplier;
9   
10  import org.djutils.draw.line.PolyLine2d;
11  import org.djutils.draw.line.Polygon2d;
12  import org.djutils.draw.point.DirectedPoint2d;
13  import org.djutils.draw.point.Point2d;
14  import org.opentrafficsim.animation.DrawLevel;
15  import org.opentrafficsim.animation.PaintLine;
16  import org.opentrafficsim.base.geometry.OtsShape;
17  import org.opentrafficsim.editor.OtsEditorProperties;
18  import org.opentrafficsim.editor.extensions.map.EditorMap;
19  import org.opentrafficsim.editor.extensions.map.edit.HelperAnnotation.Helper;
20  
21  /**
22   * Annotations that helps provide context to a draggable annotation. For example snapping lines.
23   * <p>
24   * Copyright (c) 2026-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.<br>
25   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
26   * @author Wouter Schakel
27   */
28  public class HelperAnnotation extends MapAnnotation<Helper>
29  {
30  
31      /** Helper color. */
32      private static final Color HELPER_COLOR =
33              OtsEditorProperties.PROPERTIES_STORE.getColorOrDefault("map.helperColor", Color.LIGHT_GRAY.darker());
34  
35      /** Predicate for draggable. */
36      private Supplier<Boolean> predicate = () -> true;
37  
38      /**
39       * Constructor.
40       * @param source source
41       * @param map map
42       * @param scale whether to scale this annotation
43       */
44      public HelperAnnotation(final Helper source, final EditorMap map, final Scaling scale)
45      {
46          super(source, map);
47          setScale(scale == Scaling.SCALE);
48      }
49  
50      /**
51       * Set predicate. If the predicate is false, the draggable is not painted.
52       * @param predicate predicate
53       * @return this, for method chaining
54       */
55      public HelperAnnotation setPredicate(final Supplier<Boolean> predicate)
56      {
57          this.predicate = predicate;
58          return this;
59      }
60  
61      @Override
62      public void paint(final Graphics2D graphics, final ImageObserver observer)
63      {
64          if (!this.predicate.get())
65          {
66              return;
67          }
68          setRendering(graphics);
69          graphics.setStroke(new BasicStroke(px(1.5f), BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 10.0f,
70                  px(new float[] {3.0f, 6.0f}), 10.0f));
71          graphics.setColor(HELPER_COLOR);
72          graphics.draw(PaintLine.getPath(ZERO, getSource().getLine()));
73          resetRendering(graphics);
74      }
75  
76      /**
77       * Helper annotation data.
78       */
79      public static class Helper implements OtsShape
80      {
81  
82          /** Location (same as draggable being helped). */
83          private DirectedPoint2d location;
84  
85          /** Function to derive line from location. */
86          private final Function<? super Point2d, ? extends PolyLine2d> lineFunction;
87  
88          /** Line. */
89          private PolyLine2d line;
90  
91          /**
92           * Constructor.
93           * @param initialLocation initial location
94           * @param lineFunction function to derive line from location draggable location
95           */
96          public Helper(final Point2d initialLocation, final Function<? super Point2d, ? extends PolyLine2d> lineFunction)
97          {
98              this.location = new DirectedPoint2d(initialLocation, 0.0);
99              this.lineFunction = lineFunction;
100             this.line = this.lineFunction.apply(this.location);
101         }
102 
103         /**
104          * Sets the location (same as draggable being helped) and updates the line. Invoked by {@link DraggableAnnotation} when
105          * the draggable is moved or released.
106          * @param location location
107          */
108         public void setLocation(final Point2d location)
109         {
110             this.location = new DirectedPoint2d(location, 0.0);
111             this.line = this.lineFunction.apply(location);
112         }
113 
114         @Override
115         public double getZ()
116         {
117             return DrawLevel.SNAP.getZ();
118         }
119 
120         @Override
121         public DirectedPoint2d getLocation()
122         {
123             return this.location;
124         }
125 
126         /**
127          * Returns the line.
128          * @return line
129          */
130         public PolyLine2d getLine()
131         {
132             return this.line;
133         }
134 
135         @Override
136         public Polygon2d getRelativeContour()
137         {
138             if (this.line instanceof Polygon2d pol)
139             {
140                 return pol;
141             }
142             return new Polygon2d(this.line.getPointList());
143         }
144     }
145 
146     /**
147      * Scaling option.
148      */
149     public enum Scaling
150     {
151         /** Scale the annotation. */
152         SCALE,
153 
154         /** Do not scale the annotation. */
155         NO_SCALE;
156     }
157 
158 }