1 package org.opentrafficsim.animation.network;
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.GeneralPath;
8 import java.awt.geom.Path2D;
9 import java.awt.image.ImageObserver;
10 import java.util.function.Supplier;
11
12 import org.djutils.base.Identifiable;
13 import org.djutils.draw.point.DirectedPoint2d;
14 import org.djutils.draw.point.Point2d;
15 import org.opentrafficsim.animation.DrawLevel;
16 import org.opentrafficsim.animation.OtsRenderableLabeled;
17 import org.opentrafficsim.animation.RenderableTextSource;
18 import org.opentrafficsim.animation.TextAlignment;
19 import org.opentrafficsim.animation.network.NodeAnimation.NodeData;
20 import org.opentrafficsim.animation.network.NodeAnimation.Text;
21 import org.opentrafficsim.base.geometry.OtsShape;
22
23 import nl.tudelft.simulation.naming.context.Contextualized;
24
25
26
27
28
29
30
31
32
33
34 public class NodeAnimation extends OtsRenderableLabeled<NodeData, Text>
35 {
36
37
38
39
40
41
42 public NodeAnimation(final NodeData node, final Contextualized contextualized)
43 {
44 super(node, contextualized);
45 setScaleY(false);
46 }
47
48 @Override
49 protected Text createText(final NodeData source, final Contextualized contextualized, final String prefix)
50 {
51 return new Text(source, source::getId, contextualized);
52 }
53
54 @Override
55 public boolean isScaleY()
56 {
57 return super.isScaleY();
58 }
59
60 @Override
61 public final void paint(final Graphics2D graphics, final ImageObserver observer)
62 {
63 setRendering(graphics);
64 double scale = Math.sqrt(graphics.getTransform().getDeterminant());
65 double factor = 4.0 / Math.min(scale, 4.0);
66 graphics.setColor(Color.BLACK);
67 graphics.setStroke(new BasicStroke((float) (factor * 0.5), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
68 graphics.draw(new Ellipse2D.Double(-0.5 * factor, -0.5 * factor, 1.0 * factor, 1.0 * factor));
69 if (!getSource().isCentroid())
70 {
71 double direction = getSource().getLocation().getDirZ();
72 if (!Double.isNaN(direction))
73 {
74 GeneralPath arrow = new GeneralPath(Path2D.WIND_EVEN_ODD, 3);
75 arrow.moveTo(0.7 * factor, -0.7 * factor);
76 arrow.lineTo(1.4 * factor, 0.0);
77 arrow.lineTo(0.7 * factor, 0.7 * factor);
78 graphics.setStroke(new BasicStroke((float) (factor * 0.25), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER));
79 graphics.draw(arrow);
80 }
81 }
82 resetRendering(graphics);
83 }
84
85 @Override
86 public final String toString()
87 {
88 return "NodeAnimation [node=" + super.getSource() + "]";
89 }
90
91
92
93
94 public static class Text extends RenderableTextSource<NodeData, Text>
95 {
96
97
98
99
100
101
102 @SuppressWarnings("checkstyle:parameternumber")
103 public Text(final NodeData source, final Supplier<String> text, final Contextualized contextualized)
104 {
105 super(source, text, 0.0f, 3.0f, TextAlignment.CENTER, Color.BLACK, contextualized,
106 RenderableTextSource.RENDERWHEN10);
107 setFlip(false);
108 setRotate(false);
109 }
110
111 @Override
112 public final String toString()
113 {
114 return "NodeAnimation.Text []";
115 }
116 }
117
118
119
120
121 public interface NodeData extends OtsShape, Identifiable
122 {
123 @Override
124 DirectedPoint2d getLocation();
125
126
127
128
129
130 boolean isCentroid();
131
132 @Override
133 default double signedDistance(final Point2d point)
134 {
135 return Math.hypot(point.x, point.y);
136 }
137
138 @Override
139 default boolean contains(final Point2d point)
140 {
141 return signedDistance(point) < WORLD_MARGIN_LINE;
142 }
143
144 @Override
145 default double getZ()
146 {
147 return DrawLevel.NODE.getZ();
148 }
149 }
150
151 }