1 package org.djunits.quantity;
2
3 import org.djunits.quantity.Direction.Reference;
4 import org.djunits.quantity.def.AbsBasic;
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 AbsBasic<Direction, Angle, Reference>
18 {
19 /** */
20 private static final long serialVersionUID = 600L;
21
22 /**
23 * Instantiate a Direction quantity with a unit and a reference point.
24 * @param valueInUnit the angle value, expressed in a angle unit
25 * @param unit the angle unit in which the value is expressed, relative to the reference point
26 * @param reference the reference point of this direction
27 */
28 public Direction(final double valueInUnit, final Angle.Unit unit, final Reference reference)
29 {
30 super(new Angle(valueInUnit, unit), reference);
31 }
32
33 /**
34 * Instantiate a Direction instance based on an angle and a reference point.
35 * @param angle the angle, relative to the reference point
36 * @param reference the reference point of this direction
37 */
38 public Direction(final Angle angle, final Reference reference)
39 {
40 super(angle, reference);
41 }
42
43 /**
44 * Return a Direction instance based on an SI value and a reference point.
45 * @param si the angle si value, relative to the reference point
46 * @param reference the reference point of this direction
47 * @return the Direction instance based on an SI value
48 */
49 public static Direction ofSi(final double si, final Reference reference)
50 {
51 return new Direction(si, Angle.Unit.SI, reference);
52 }
53
54 @Override
55 public Direction instantiate(final Angle angle, final Reference reference)
56 {
57 return new Direction(angle, reference);
58 }
59
60 /**
61 * Returns a Direction representation of a textual representation of a value with a unit. The String representation that can
62 * be parsed is the double value in the unit, followed by a localized or English abbreviation of the unit. Spaces are
63 * allowed, but not required, between the value and the unit.
64 * @param text the textual representation to parse into a Direction
65 * @param reference the reference point of this direction
66 * @return the Scalar representation of the value in its unit
67 * @throws IllegalArgumentException when the text cannot be parsed
68 * @throws NullPointerException when the text argument is null
69 */
70 public static Direction valueOf(final String text, final Reference reference)
71 {
72 return new Direction(Quantity.valueOf(text, Angle.ZERO), reference);
73 }
74
75 /**
76 * Returns a Direction based on a value and the textual representation of the unit, which can be localized.
77 * @param valueInUnit the value, expressed in the unit as given by unitString
78 * @param unitString the textual representation of the unit
79 * @param reference the reference point of this direction
80 * @return the Scalar representation of the value in its unit
81 * @throws IllegalArgumentException when the unit cannot be parsed or is incorrect
82 * @throws NullPointerException when the unitString argument is null
83 */
84 public static Direction of(final double valueInUnit, final String unitString, final Reference reference)
85 {
86 return new Direction(Quantity.of(valueInUnit, unitString, Angle.ZERO), reference);
87 }
88
89 @Override
90 public Angle subtract(final Direction other)
91 {
92 var otherRef = other.relativeTo(getReference());
93 return Angle.ofSi(si() - otherRef.si()).setDisplayUnit(getDisplayUnit());
94 }
95
96 @Override
97 public Direction add(final Angle other)
98 {
99 return new Direction(Angle.ofSi(si() + other.si()).setDisplayUnit(getDisplayUnit()), getReference());
100 }
101
102 @Override
103 public Direction subtract(final Angle other)
104 {
105 return new Direction(Angle.ofSi(si() - other.si()).setDisplayUnit(getDisplayUnit()), getReference());
106 }
107
108 /**
109 * The reference class to define a reference point for the direction.
110 */
111 public static final class Reference extends AbstractReference<Reference, Direction, Angle>
112 {
113 /** East is zero. */
114 public static final Reference EAST = new Reference("EAST", "East = 0 degrees (counter-clockwise)", Angle.ZERO, null);
115
116 /** North is zero. */
117 public static final Reference NORTH =
118 new Reference("NORTH", "North = 0 degrees (counter-clockwise)", Angle.HALF_PI, EAST);
119
120 /**
121 * Define a new reference point for the direction.
122 * @param id the id
123 * @param name the name or explanation
124 * @param offset the offset w.r.t. the offsetReference
125 * @param offsetReference the reference to which the offset is relative
126 */
127 public Reference(final String id, final String name, final Angle offset, final Reference offsetReference)
128 {
129 super(id, name, offset, offsetReference);
130 }
131
132 /**
133 * Define a new reference point for the direction.
134 * @param id the id
135 * @param name the name or explanation
136 * @param offset the offset w.r.t. EAST
137 */
138 public Reference(final String id, final String name, final Angle offset)
139 {
140 this(id, name, offset, EAST);
141 }
142
143 /**
144 * Define a new reference point for the direction.
145 * @param id the id
146 * @param name the name or explanation
147 * @param offset the offset w.r.t. offsetReference
148 * @param offsetReference the reference to which the offset is relative
149 */
150 public static void add(final String id, final String name, final Angle offset, final Reference offsetReference)
151 {
152 new Reference(id, name, offset, offsetReference);
153 }
154
155 /**
156 * Define a new reference point for the direction.
157 * @param id the id
158 * @param name the name or explanation
159 * @param offset the offset w.r.t. EAST
160 */
161 public static void add(final String id, final String name, final Angle offset)
162 {
163 new Reference(id, name, offset);
164 }
165
166 /**
167 * Get a reference point for the direction, based on its id. Return null when the id could not be found.
168 * @param id the id
169 * @return the DirectionReference object
170 */
171 public static Reference get(final String id)
172 {
173 return AbstractReference.get(Direction.Reference.class, id);
174 }
175
176 @Override
177 public Direction instantiate(final Angle angle)
178 {
179 return new Direction(angle, this);
180 }
181 }
182 }