View Javadoc
1   package org.opentrafficsim.editor.extensions.map;
2   
3   import org.djunits.value.vdouble.scalar.Direction;
4   import org.djutils.draw.bounds.Bounds2d;
5   import org.djutils.draw.line.Polygon2d;
6   import org.djutils.draw.point.DirectedPoint2d;
7   import org.djutils.draw.point.Point2d;
8   import org.djutils.event.Event;
9   import org.djutils.event.EventListener;
10  import org.djutils.event.reference.ReferenceType;
11  import org.opentrafficsim.animation.network.NodeAnimation.NodeData;
12  import org.opentrafficsim.base.geometry.OtsShape;
13  import org.opentrafficsim.editor.OtsEditor;
14  import org.opentrafficsim.editor.XsdPaths;
15  import org.opentrafficsim.editor.XsdTreeNode;
16  import org.opentrafficsim.editor.extensions.Adapters;
17  
18  /**
19   * NodeData for the editor Map.
20   * <p>
21   * Copyright (c) 2023-2026 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
22   * BSD-style license. See <a href="https://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
23   * </p>
24   * @author Wouter Schakel
25   */
26  public class MapNodeData extends MapData implements NodeData, EventListener
27  {
28  
29      /** Bounds. */
30      private static final Bounds2d BOUNDS = new Bounds2d(2.0, 2.0);
31  
32      /** String attribute. */
33      private String id = "";
34  
35      /** Coordinate attribute. */
36      private Point2d coordinate = null;
37  
38      /** Direction attribute. */
39      private Direction direction = null;
40  
41      /** Location. */
42      private DirectedPoint2d location = new DirectedPoint2d(0.0, 0.0, 0.0);
43  
44      /** Absolute contour. */
45      private Polygon2d absoluteContour;
46  
47      /** Relative contour. */
48      private Polygon2d relativeContour;
49  
50      /**
51       * Constructor.
52       * @param map map.
53       * @param nodeNode node Ots.Network.Node.
54       * @param editor editor.
55       */
56      public MapNodeData(final EditorMap map, final XsdTreeNode nodeNode, final OtsEditor editor)
57      {
58          super(map, nodeNode, editor);
59          getNode().addListener(this, XsdTreeNode.ATTRIBUTE_CHANGED, ReferenceType.WEAK);
60          // for when node is duplicated, set data immediately
61          if (getNode().isActive())
62          {
63              notify(new Event(XsdTreeNode.ATTRIBUTE_CHANGED, new Object[] {getNode(), "Id", null}));
64              notify(new Event(XsdTreeNode.ATTRIBUTE_CHANGED, new Object[] {getNode(), "Coordinate", null}));
65              if (!isCentroid())
66              {
67                  notify(new Event(XsdTreeNode.ATTRIBUTE_CHANGED, new Object[] {getNode(), "Direction", null}));
68              }
69          }
70          this.absoluteContour = OtsShape.boundsAsAbsoluteContour(this);
71          this.relativeContour =
72                  new Polygon2d(0.0, OtsShape.toRelativeTransform(this.location).transform(this.absoluteContour.iterator()));
73      }
74  
75      @Override
76      public Bounds2d getRelativeBounds()
77      {
78          return BOUNDS;
79      }
80  
81      @Override
82      public Polygon2d getAbsoluteContour()
83      {
84          return this.absoluteContour;
85      }
86  
87      @Override
88      public Polygon2d getRelativeContour()
89      {
90          return this.relativeContour;
91      }
92  
93      @Override
94      public String getId()
95      {
96          return this.id;
97      }
98  
99      @Override
100     public void destroy()
101     {
102         super.destroy();
103         getNode().removeListener(this, XsdTreeNode.ATTRIBUTE_CHANGED);
104     }
105 
106     @Override
107     public DirectedPoint2d getLocation()
108     {
109         return this.location;
110     }
111 
112     @Override
113     public boolean isCentroid()
114     {
115         return getNode().getNodeName().equals("Centroid");
116     }
117 
118     @Override
119     public void notify(final Event event)
120     {
121         String attribute = (String) ((Object[]) event.getContent())[1];
122         String value = getNode().getAttributeValueOrDefault(attribute);
123         if ("Id".equals(attribute))
124         {
125             this.id = value == null ? "" : value;
126             return;
127         }
128         else if ("Coordinate".equals(attribute))
129         {
130             setValue((v) -> this.coordinate = v, Adapters.get(Point2d.class), getNode(), "Coordinate");
131         }
132         else if ("Direction".equals(attribute))
133         {
134             setValue((v) -> this.direction = v, Adapters.get(Direction.class), getNode(), "Direction");
135         }
136         else
137         {
138             return;
139         }
140         setLocation();
141     }
142 
143     @Override
144     public void evalChanged()
145     {
146         this.id = getNode().getId() == null ? "" : getNode().getId();
147         setValue((v) -> this.coordinate = v, Adapters.get(Point2d.class), getNode(), "Coordinate");
148         XsdTreeNode node = getNode();
149         if (node != null && node.getPathString().equals(XsdPaths.NODE)) // Centroids have no direction
150         {
151             setValue((v) -> this.direction = v, Adapters.get(Direction.class), node, "Direction");
152         }
153         setLocation();
154     }
155 
156     /**
157      * Set the location from the coordinate and direction. Notify when invalid or valid.
158      */
159     private void setLocation()
160     {
161         if (this.coordinate == null)
162         {
163             setInvalid();
164             return;
165         }
166         this.location = new DirectedPoint2d(this.coordinate, this.direction == null ? 0.0 : this.direction.si);
167         this.absoluteContour = OtsShape.boundsAsAbsoluteContour(this);
168         this.relativeContour =
169                 new Polygon2d(0.0, OtsShape.toRelativeTransform(this.location).transform(this.absoluteContour.iterator()));
170         setValid();
171     }
172 
173     @Override
174     public String toString()
175     {
176         return "Node " + this.id;
177     }
178 
179 }