93
93
*/
94
94
@ FunctionalInterface
95
95
public interface LEDPattern {
96
+ /** A functional interface for index mapping functions. */
97
+ @ FunctionalInterface
98
+ interface IndexMapper {
99
+ /**
100
+ * Maps the index.
101
+ *
102
+ * @param bufLen Length of the buffer
103
+ * @param index The index to map
104
+ */
105
+ int apply (int bufLen , int index );
106
+ }
107
+
96
108
/**
97
109
* Writes the pattern to an LED buffer. Dynamic animations should be called periodically (such as
98
110
* with a command or with a periodic method) to refresh the buffer over time.
@@ -130,19 +142,12 @@ default <T extends LEDReader & LEDWriter> void applyTo(T readWriter) {
130
142
}
131
143
132
144
/**
133
- * Creates a pattern that displays this one in reverse. Scrolling patterns will scroll in the
134
- * opposite direction (but at the same speed). It will treat the end of an LED strip as the start,
135
- * and the start of the strip as the end. This can be useful for making ping-pong patterns that
136
- * travel from one end of an LED strip to the other, then reverse direction and move back to the
137
- * start. This can also be useful when working with LED strips connected in a serpentine pattern
138
- * (where the start of one strip is connected to the end of the previous one); however, consider
139
- * using a {@link AddressableLEDBufferView#reversed() reversed view} of the overall buffer for
140
- * that segment rather than reversing patterns.
145
+ * Creates a pattern with remapped indices.
141
146
*
142
- * @return the reverse pattern
143
- * @see AddressableLEDBufferView#reversed()
147
+ * @param indexMapper the index mapper
148
+ * @return the mapped pattern
144
149
*/
145
- default LEDPattern reversed ( ) {
150
+ default LEDPattern mapIndex ( IndexMapper indexMapper ) {
146
151
return (reader , writer ) -> {
147
152
int bufLen = reader .getLength ();
148
153
applyTo (
@@ -154,23 +159,40 @@ public int getLength() {
154
159
155
160
@ Override
156
161
public int getRed (int index ) {
157
- return reader .getRed (getLength () - 1 - index );
162
+ return reader .getRed (indexMapper . apply ( bufLen , index ) );
158
163
}
159
164
160
165
@ Override
161
166
public int getGreen (int index ) {
162
- return reader .getGreen (getLength () - 1 - index );
167
+ return reader .getGreen (indexMapper . apply ( bufLen , index ) );
163
168
}
164
169
165
170
@ Override
166
171
public int getBlue (int index ) {
167
- return reader .getBlue (getLength () - 1 - index );
172
+ return reader .getBlue (indexMapper . apply ( bufLen , index ) );
168
173
}
169
174
},
170
- (i , r , g , b ) -> writer .setRGB ((bufLen - 1 ) - i , r , g , b ));
175
+ (i , r , g , b ) -> writer .setRGB (indexMapper . apply (bufLen , i ) , r , g , b ));
171
176
};
172
177
}
173
178
179
+ /**
180
+ * Creates a pattern that displays this one in reverse. Scrolling patterns will scroll in the
181
+ * opposite direction (but at the same speed). It will treat the end of an LED strip as the start,
182
+ * and the start of the strip as the end. This can be useful for making ping-pong patterns that
183
+ * travel from one end of an LED strip to the other, then reverse direction and move back to the
184
+ * start. This can also be useful when working with LED strips connected in a serpentine pattern
185
+ * (where the start of one strip is connected to the end of the previous one); however, consider
186
+ * using a {@link AddressableLEDBufferView#reversed() reversed view} of the overall buffer for
187
+ * that segment rather than reversing patterns.
188
+ *
189
+ * @return the reverse pattern
190
+ * @see AddressableLEDBufferView#reversed()
191
+ */
192
+ default LEDPattern reversed () {
193
+ return mapIndex ((length , index ) -> length - 1 - index );
194
+ }
195
+
174
196
/**
175
197
* Creates a pattern that plays this one, but offset by a certain number of LEDs. The offset
176
198
* pattern will wrap around, if necessary.
@@ -179,15 +201,7 @@ public int getBlue(int index) {
179
201
* @return the offset pattern
180
202
*/
181
203
default LEDPattern offsetBy (int offset ) {
182
- return (reader , writer ) -> {
183
- int bufLen = reader .getLength ();
184
- applyTo (
185
- LEDReader .RemappedReader .offset (reader , offset ),
186
- (i , r , g , b ) -> {
187
- int shiftedIndex = Math .floorMod (i + offset , bufLen );
188
- writer .setRGB (shiftedIndex , r , g , b );
189
- });
190
- };
204
+ return mapIndex ((length , index ) -> Math .floorMod (index + offset , length ));
191
205
}
192
206
193
207
/**
@@ -211,23 +225,16 @@ default LEDPattern offsetBy(int offset) {
211
225
default LEDPattern scrollAtRelativeSpeed (Frequency velocity ) {
212
226
final double periodMicros = velocity .asPeriod ().in (Microseconds );
213
227
214
- return ( reader , writer ) -> {
215
- int bufLen = reader . getLength ();
216
- long now = WPIUtilJNI .now ();
228
+ return mapIndex (
229
+ ( bufLen , index ) -> {
230
+ long now = WPIUtilJNI .now ();
217
231
218
- // index should move by (buf.length) / (period)
219
- double t = (now % (long ) periodMicros ) / periodMicros ;
220
- int offset = (int ) (t * bufLen );
232
+ // index should move by (buf.length) / (period)
233
+ double t = (now % (long ) periodMicros ) / periodMicros ;
234
+ int offset = (int ) (t * bufLen );
221
235
222
- applyTo (
223
- LEDReader .RemappedReader .offset (reader , offset ),
224
- (i , r , g , b ) -> {
225
- // floorMod so if the offset is negative, we still get positive outputs
226
- int shiftedIndex = Math .floorMod (i + offset , bufLen );
227
-
228
- writer .setRGB (shiftedIndex , r , g , b );
229
- });
230
- };
236
+ return Math .floorMod (index + offset , bufLen );
237
+ });
231
238
}
232
239
233
240
/**
@@ -262,22 +269,16 @@ default LEDPattern scrollAtAbsoluteSpeed(LinearVelocity velocity, Distance ledSp
262
269
var metersPerMicro = velocity .in (Meters .per (Microsecond ));
263
270
var microsPerLED = (int ) (ledSpacing .in (Meters ) / metersPerMicro );
264
271
265
- return (reader , writer ) -> {
266
- int bufLen = reader .getLength ();
267
- long now = WPIUtilJNI .now ();
268
-
269
- // every step in time that's a multiple of microsPerLED will increment the offset by 1
270
- var offset = (int ) (now / microsPerLED );
272
+ return mapIndex (
273
+ (bufLen , index ) -> {
274
+ long now = WPIUtilJNI .now ();
271
275
272
- applyTo (
273
- LEDReader .RemappedReader .offset (reader , offset ),
274
- (i , r , g , b ) -> {
275
- // floorMod so if the offset is negative, we still get positive outputs
276
- int shiftedIndex = Math .floorMod (i + offset , bufLen );
276
+ // every step in time that's a multiple of microsPerLED will increment the offset by 1
277
+ var offset = (int ) (now / microsPerLED );
277
278
278
- writer . setRGB ( shiftedIndex , r , g , b );
279
- } );
280
- } ;
279
+ // floorMod so if the offset is negative, we still get positive outputs
280
+ return Math . floorMod ( index + offset , bufLen );
281
+ }) ;
281
282
}
282
283
283
284
/**
0 commit comments