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