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