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