View Javadoc
1   package org.djunits.quantity;
2   
3   import org.djunits.quantity.Direction.Reference;
4   import org.djunits.quantity.def.AbsQuantity;
5   import org.djunits.quantity.def.AbstractReference;
6   import org.djunits.quantity.def.Quantity;
7   
8   /**
9    * Direction is the absolute equivalent of Angle, and can, e.g., represent an angle relative to a defined "zero" angle such as
10   * NORTH or EAST. The relative operations such as gt, lt, eq and ne are not available in the Direction class.
11   * <p>
12   * Copyright (c) 2025-2026 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See
13   * for project information <a href="https://djunits.org" target="_blank">https://djunits.org</a>. The DJUNITS project is
14   * distributed under a <a href="https://djunits.org/docs/license.html" target="_blank">three-clause BSD-style license</a>.
15   * @author Alexander Verbraeck
16   */
17  public class Direction extends AbsQuantity<Direction, Angle, Reference>
18  {
19      /** */
20      private static final long serialVersionUID = 600L;
21  
22      /**
23       * Instantiate a Direction quantity with an SI or base value, or a value expressed in a unit, and a reference point.
24       * @param value the angle value, either expressed in the SI unit, or in the provided unit, relative to the reference point
25       * @param unit the angle display unit or unit
26       * @param reference the reference point of this direction
27       * @param useSi when true, value is taken as the SI value; when false, value is expressed in the unit
28       */
29      public Direction(final double value, final Angle.Unit unit, final Reference reference, final boolean useSi)
30      {
31          super(new Angle(value, unit, useSi), reference);
32      }
33  
34      /**
35       * Instantiate a Direction instance based on an angle and a reference point.
36       * @param angle the angle, relative to the reference point
37       * @param reference the reference point of this direction
38       */
39      public Direction(final Angle angle, final Reference reference)
40      {
41          super(angle, reference);
42      }
43  
44      /**
45       * Return a Direction instance based on an SI value and a reference point.
46       * @param si the angle si value, relative to the reference point
47       * @param reference the reference point of this direction
48       * @return the Direction instance based on an SI value
49       */
50      public static Direction ofSi(final double si, final Reference reference)
51      {
52          return new Direction(si, Angle.Unit.SI, reference, true);
53      }
54  
55      @Override
56      public Direction instantiate(final Angle angle, final Reference reference)
57      {
58          return new Direction(angle, reference);
59      }
60  
61      /**
62       * Returns a Direction representation of a textual representation of a value with a unit. The String representation that can
63       * be parsed is the double value in the unit, followed by a localized or English abbreviation of the unit. Spaces are
64       * allowed, but not required, between the value and the unit.
65       * @param text the textual representation to parse into a Direction
66       * @param reference the reference point of this direction
67       * @return the Scalar representation of the value in its unit
68       * @throws IllegalArgumentException when the text cannot be parsed
69       * @throws NullPointerException when the text argument is null
70       */
71      public static Direction valueOf(final String text, final Reference reference)
72      {
73          return new Direction(Quantity.valueOf(text, Angle.ZERO), reference);
74      }
75  
76      /**
77       * Returns a Direction based on a value and the textual representation of the unit, which can be localized.
78       * @param valueInUnit the value, expressed in the unit as given by unitString
79       * @param unitString the textual representation of the unit
80       * @param reference the reference point of this direction
81       * @return the Scalar representation of the value in its unit
82       * @throws IllegalArgumentException when the unit cannot be parsed or is incorrect
83       * @throws NullPointerException when the unitString argument is null
84       */
85      public static Direction of(final double valueInUnit, final String unitString, final Reference reference)
86      {
87          return new Direction(Quantity.of(valueInUnit, unitString, Angle.ZERO), reference);
88      }
89  
90      @Override
91      public Angle subtract(final Direction other)
92      {
93          var otherRef = other.relativeTo(getReference());
94          return Angle.ofSi(si() - otherRef.si(), getQuantity().getDisplayUnit());
95      }
96  
97      @Override
98      public Direction add(final Angle other)
99      {
100         return new Direction(Angle.ofSi(si() + other.si(), getQuantity().getDisplayUnit()), getReference());
101     }
102 
103     @Override
104     public Direction subtract(final Angle other)
105     {
106         return new Direction(Angle.ofSi(si() - other.si(), getQuantity().getDisplayUnit()), getReference());
107     }
108 
109     /**
110      * The reference class to define a reference point for the direction.
111      */
112     public static final class Reference extends AbstractReference<Reference, Direction, Angle>
113     {
114         /** East is zero. */
115         public static final Reference EAST = new Reference("EAST", "East = 0 degrees (counter-clockwise)", Angle.ZERO, null);
116 
117         /** North is zero. */
118         public static final Reference NORTH =
119                 new Reference("NORTH", "North = 0 degrees (counter-clockwise)", Angle.HALF_PI, EAST);
120 
121         /**
122          * Define a new reference point for the direction.
123          * @param id the id
124          * @param name the name or explanation
125          * @param offset the offset w.r.t. the offsetReference
126          * @param offsetReference the reference to which the offset is relative
127          */
128         public Reference(final String id, final String name, final Angle offset, final Reference offsetReference)
129         {
130             super(id, name, offset, offsetReference);
131         }
132 
133         /**
134          * Define a new reference point for the direction.
135          * @param id the id
136          * @param name the name or explanation
137          * @param offset the offset w.r.t. EAST
138          */
139         public Reference(final String id, final String name, final Angle offset)
140         {
141             this(id, name, offset, EAST);
142         }
143 
144         /**
145          * Define a new reference point for the direction.
146          * @param id the id
147          * @param name the name or explanation
148          * @param offset the offset w.r.t. offsetReference
149          * @param offsetReference the reference to which the offset is relative
150          */
151         public static void add(final String id, final String name, final Angle offset, final Reference offsetReference)
152         {
153             new Reference(id, name, offset, offsetReference);
154         }
155 
156         /**
157          * Define a new reference point for the direction.
158          * @param id the id
159          * @param name the name or explanation
160          * @param offset the offset w.r.t. EAST
161          */
162         public static void add(final String id, final String name, final Angle offset)
163         {
164             new Reference(id, name, offset);
165         }
166 
167         /**
168          * Get a reference point for the direction, based on its id. Return null when the id could not be found.
169          * @param id the id
170          * @return the DirectionReference object
171          */
172         public static Reference get(final String id)
173         {
174             return AbstractReference.get(Direction.Reference.class, id);
175         }
176 
177         @Override
178         public Direction instantiate(final Angle angle)
179         {
180             return new Direction(angle, this);
181         }
182     }
183 }