1 package org.djutils.math.functions;
2
3 import java.util.Objects;
4
5 import org.djutils.exceptions.Throw;
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 record Interval<T extends Comparable<T>>(double low, boolean lowInclusive, double high, boolean highInclusive, T payload)
26 implements Comparable<Interval<?>>
27 {
28
29
30
31
32
33
34
35
36 Interval(final double low, final boolean lowInclusive, final double high, final boolean highInclusive, final T payload)
37 {
38 Throw.when(low > high, IllegalArgumentException.class, "low may not be higher than high");
39 Throw.when(low == high && (!lowInclusive) && (!highInclusive), IllegalArgumentException.class,
40 "zero width interval must include at least one of its boundaries");
41 this.low = low;
42 this.lowInclusive = lowInclusive;
43 this.high = high;
44 this.highInclusive = highInclusive;
45 this.payload = payload;
46 }
47
48
49
50
51
52
53
54 public boolean covers(final Interval<?> other)
55 {
56 if (this.low > other.low || this.high < other.high)
57 {
58 return false;
59 }
60 if (this.low == other.low && (!this.lowInclusive) && other.lowInclusive)
61 {
62 return false;
63 }
64 if (this.high == other.high && (!this.highInclusive) && other.highInclusive)
65 {
66 return false;
67 }
68 return true;
69 }
70
71
72
73
74
75
76
77 public boolean disjunct(final Interval<?> other)
78 {
79 if (this.high < other.low || this.low > other.high)
80 {
81 return true;
82 }
83 if (this.high == other.low && ((!this.highInclusive) || (!other.lowInclusive)))
84 {
85 return true;
86 }
87 if (this.low == other.high && ((!this.lowInclusive) || (!other.highInclusive)))
88 {
89 return true;
90 }
91 return false;
92 }
93
94 @SuppressWarnings("unchecked")
95 @Override
96 public int compareTo(final Interval<?> other)
97 {
98
99 if (this.low < other.low || this.low == other.low && this.lowInclusive && (!other.lowInclusive))
100 {
101 return -1;
102 }
103 if (this.low > other.low || this.low == other.low && other.lowInclusive && (!this.lowInclusive))
104 {
105 return 1;
106 }
107
108 if (this.high < other.high || this.high == other.high && (!this.highInclusive) && other.highInclusive)
109 {
110 return -1;
111 }
112 if (this.high > other.high || this.high == other.high && this.highInclusive && (!other.highInclusive))
113 {
114 return 1;
115 }
116
117 if (this.payload != null)
118 {
119 if (other.payload == null)
120 {
121 return -1;
122 }
123 return this.payload.compareTo((T) other.payload);
124 }
125 if (other.payload != null)
126 {
127 return 1;
128 }
129 return 0;
130 }
131
132
133
134
135
136
137 public boolean covers(final double x)
138 {
139 return ((this.low < x || (this.low == x && this.lowInclusive))
140 && (this.high > x || (this.high == x && this.highInclusive)));
141 }
142
143
144
145
146
147
148
149
150 public Interval<T> intersection(final Interval<?> other)
151 {
152 if (this.disjunct(other))
153 {
154 return null;
155 }
156 if (other.covers(this))
157 {
158 return this;
159 }
160 if (this.covers(other))
161 {
162 return new Interval<T>(other.low, other.lowInclusive, other.high, other.highInclusive, this.payload);
163 }
164 boolean includeLow = this.low > other.low && this.lowInclusive || this.low < other.low && other.lowInclusive
165 || this.low == other.low && this.lowInclusive && other.lowInclusive;
166 boolean includeHigh = this.high < other.high && this.highInclusive || this.high > other.high && other.highInclusive
167 || this.high == other.high && this.highInclusive && other.highInclusive;
168 return new Interval<T>(Math.max(this.low, other.low), includeLow, Math.min(this.high, other.high), includeHigh,
169 this.payload);
170 }
171
172 @Override
173 public String toString()
174 {
175 return (this.lowInclusive ? "[" : "(") + this.low + ", " + this.high + (this.highInclusive ? "]" : ")") + "\u2192"
176 + this.payload;
177 }
178
179 @Override
180 public int hashCode()
181 {
182 return Objects.hash(this.high, this.highInclusive, this.low, this.lowInclusive, this.payload);
183 }
184
185 @SuppressWarnings("checkstyle:needbraces")
186 @Override
187 public boolean equals(final Object obj)
188 {
189 if (this == obj)
190 return true;
191 if (obj == null)
192 return false;
193 if (getClass() != obj.getClass())
194 return false;
195 Interval<?> other = (Interval<?>) obj;
196 return Double.doubleToLongBits(this.high) == Double.doubleToLongBits(other.high)
197 && this.highInclusive == other.highInclusive
198 && Double.doubleToLongBits(this.low) == Double.doubleToLongBits(other.low)
199 && this.lowInclusive == other.lowInclusive && Objects.equals(this.payload, other.payload);
200 }
201
202 }