1use core::{
2 cmp::{max, min},
3 convert::Infallible,
4};
5
6use embedded_graphics::{
7 pixelcolor::BinaryColor,
8 prelude::{Dimensions, DrawTarget, Point, Size},
9 primitives::Rectangle,
10 Pixel,
11};
12
13#[derive(Clone)]
17pub struct BinaryBuffer<const L: usize> {
18 size: Size,
19 bytes_per_row: usize,
20 data: [u8; L],
22}
23
24pub const fn binary_buffer_length(size: Size) -> usize {
26 (size.width as usize / 8) * size.height as usize
27}
28
29impl<const L: usize> BinaryBuffer<L> {
30 pub fn new(dimensions: Size) -> Self {
42 debug_assert_eq!(
43 dimensions.width % 8,
44 0,
45 "Width must be a multiple of 8 for binary packing."
46 );
47 debug_assert_eq!(
48 binary_buffer_length(dimensions),
49 L,
50 "Size must match given dimensions"
51 );
52 Self {
53 bytes_per_row: dimensions.width as usize / 8,
54 size: dimensions,
55 data: [0; L],
56 }
57 }
58
59 pub fn data(&self) -> &[u8] {
61 &self.data
62 }
63}
64
65impl<const L: usize> Dimensions for BinaryBuffer<L> {
66 fn bounding_box(&self) -> Rectangle {
67 Rectangle::new(Point::zero(), self.size)
68 }
69}
70
71impl<const L: usize> DrawTarget for BinaryBuffer<L> {
72 type Color = BinaryColor;
73
74 type Error = Infallible;
75
76 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
77 where
78 I: IntoIterator<Item = Pixel<Self::Color>>,
79 {
80 for Pixel(point, color) in pixels.into_iter() {
82 if point.x < 0
83 || point.x >= self.size.width as i32
84 || point.y < 0
85 || point.y >= self.size.height as i32
86 {
87 continue; }
89
90 let byte_index = (point.x as usize) / 8 + (point.y as usize * self.bytes_per_row);
91 let bit_index = (point.x as usize) % 8;
92
93 if color == BinaryColor::On {
94 self.data[byte_index] |= 0x80 >> bit_index;
95 } else {
96 self.data[byte_index] &= !(0x80 >> bit_index);
97 }
98 }
99 Ok(())
100 }
101
102 fn fill_contiguous<I>(&mut self, area: &Rectangle, colors: I) -> Result<(), Self::Error>
103 where
104 I: IntoIterator<Item = Self::Color>,
105 {
106 let drawable_area = self.bounding_box().intersection(area);
108 if drawable_area.size.width == 0 || drawable_area.size.height == 0 {
109 return Ok(()); }
111
112 let y_start = area.top_left.y;
113 let y_end = area.top_left.y + area.size.height as i32;
114 let x_start = area.top_left.x;
115 let x_end = area.top_left.x + area.size.width as i32;
116
117 let mut colors_iter = colors.into_iter();
118 let mut byte_index = max(y_start, 0) as usize * self.bytes_per_row;
120 let row_start_byte_offset = max(x_start, 0) as usize / 8;
121 let row_end_byte_offset =
122 self.bytes_per_row - (min(x_end, self.size.width as i32) as usize / 8);
123 for y in y_start..y_end {
124 if y < 0 || y >= self.size.height as i32 {
125 for _ in x_start..x_end {
127 colors_iter.next();
128 }
129 continue;
130 }
131
132 byte_index += row_start_byte_offset;
133 let mut bit_index = (max(x_start, 0) as usize) % 8;
134
135 for x in x_start..x_end {
137 if x < 0 || x >= self.size.width as i32 {
138 colors_iter.next();
140 continue;
141 }
142
143 let Some(color) = colors_iter.next() else {
145 return Ok(());
146 };
147
148 if color == BinaryColor::On {
149 self.data[byte_index] |= 0x80 >> bit_index;
150 } else {
151 self.data[byte_index] &= !(0x80 >> bit_index);
152 }
153
154 bit_index += 1;
155 if bit_index == 8 {
156 byte_index += 1;
158 bit_index = 0;
159 }
160 }
161
162 byte_index += row_end_byte_offset;
163 }
164
165 Ok(())
166 }
167
168 fn fill_solid(&mut self, area: &Rectangle, color: Self::Color) -> Result<(), Self::Error> {
169 let drawable_area = self.bounding_box().intersection(area);
171 if drawable_area.size.width == 0 || drawable_area.size.height == 0 {
172 return Ok(()); }
174
175 let y_start = drawable_area.top_left.y;
176 let y_end = drawable_area.top_left.y + drawable_area.size.height as i32;
177 let x_start = drawable_area.top_left.x;
178 let x_end = drawable_area.top_left.x + drawable_area.size.width as i32;
179
180 let x_full_bytes_start = min(x_start + x_start % 8, x_end);
181 let x_full_bytes_end = max(x_end - (x_end % 8), x_start);
182 let num_full_bytes_per_row = (x_full_bytes_end - x_full_bytes_start) / 8;
183
184 let mut byte_index = y_start as usize * self.bytes_per_row;
185 let row_start_byte_offset = x_start as usize / 8;
186 let row_end_byte_offset = self.bytes_per_row - (x_end as usize / 8);
187 for _y in y_start..y_end {
188 byte_index += row_start_byte_offset;
189 let mut bit_index = (x_start as usize) % 8;
190
191 macro_rules! set_next_bit {
192 () => {
193 if color == BinaryColor::On {
194 self.data[byte_index] |= 0x80 >> bit_index;
195 } else {
196 self.data[byte_index] &= !(0x80 >> bit_index);
197 }
198 bit_index += 1;
199 if bit_index == 8 {
200 byte_index += 1;
202 bit_index = 0;
203 }
204 };
205 }
206
207 if num_full_bytes_per_row == 0 {
208 for _x in x_start..x_end {
209 set_next_bit!();
210 }
211 } else {
212 for _x in x_start..x_full_bytes_start {
213 set_next_bit!();
214 }
215
216 for _ in 0..num_full_bytes_per_row {
218 if color == BinaryColor::On {
219 self.data[byte_index] = 0xFF;
220 } else {
221 self.data[byte_index] = 0x00;
222 }
223 byte_index += 1;
224 }
225
226 bit_index = x_full_bytes_end as usize % 8;
228 for _x in x_full_bytes_end..x_end {
229 set_next_bit!();
230 }
231 }
232
233 byte_index += row_end_byte_offset;
234 }
235
236 Ok(())
237 }
238}
239
240pub trait Rotation {
241 fn inverse(&self) -> Self;
243
244 fn rotate_size(&self, size: Size) -> Size;
246
247 fn rotate_point(&self, point: Point, bounds: Size) -> Point;
249
250 fn rotate_rectangle(&self, rectangle: Rectangle, bounds: Size) -> Rectangle;
252}
253
254#[derive(Clone, Copy, Debug, PartialEq, Eq)]
256pub enum Rotate {
257 R90,
258 R180,
259 R270,
260}
261
262impl Rotation for Rotate {
263 fn inverse(&self) -> Self {
264 match self {
265 Rotate::R90 => Rotate::R270,
266 Rotate::R180 => Rotate::R180,
267 Rotate::R270 => Rotate::R90,
268 }
269 }
270
271 fn rotate_size(&self, size: Size) -> Size {
272 match self {
273 Rotate::R90 | Rotate::R270 => Size::new(size.height, size.width),
274 Rotate::R180 => size,
275 }
276 }
277
278 fn rotate_point(&self, point: Point, source_bounds: Size) -> Point {
279 match self {
280 Rotate::R90 => Point::new(source_bounds.height as i32 - point.y - 1, point.x),
281 Rotate::R180 => Point::new(
282 source_bounds.width as i32 - point.x - 1,
283 source_bounds.height as i32 - point.y - 1,
284 ),
285 Rotate::R270 => Point::new(point.y, source_bounds.width as i32 - point.x - 1),
286 }
287 }
288
289 fn rotate_rectangle(&self, rectangle: Rectangle, source_bounds: Size) -> Rectangle {
290 match self {
291 Rotate::R90 => {
292 let old_bottom_left =
293 rectangle.top_left + Point::new(0, rectangle.size.height as i32 - 1);
294 let new_top_left = self.rotate_point(old_bottom_left, source_bounds);
295 Rectangle::new(new_top_left, self.rotate_size(rectangle.size))
296 }
297 Rotate::R180 => {
298 let old_bottom_right = rectangle.top_left + rectangle.size - Point::new(1, 1);
299 let new_top_left = self.rotate_point(old_bottom_right, source_bounds);
300 Rectangle::new(new_top_left, self.rotate_size(rectangle.size))
301 }
302 Rotate::R270 => {
303 let old_top_right =
304 rectangle.top_left + Point::new(rectangle.size.width as i32 - 1, 0);
305 let new_top_left = self.rotate_point(old_top_right, source_bounds);
306 Rectangle::new(new_top_left, self.rotate_size(rectangle.size))
307 }
308 }
309 }
310}
311
312#[derive(Clone)]
313pub struct RotatedBuffer<B: DrawTarget, R: Rotation> {
326 buffer: B,
327 rotation: R,
328}
329
330impl<B: DrawTarget, R: Rotation> RotatedBuffer<B, R> {
331 pub fn new(buffer: B, rotation: R) -> Self {
332 Self { buffer, rotation }
333 }
334
335 pub fn inner(&self) -> &B {
337 &self.buffer
338 }
339}
340
341impl<B: DrawTarget, R: Rotation> Dimensions for RotatedBuffer<B, R> {
342 fn bounding_box(&self) -> Rectangle {
343 let internal = self.buffer.bounding_box();
344 self.rotation
345 .inverse()
346 .rotate_rectangle(internal, internal.size)
347 }
348}
349
350impl<B: DrawTarget, R: Rotation> DrawTarget for RotatedBuffer<B, R> {
351 type Color = B::Color;
352 type Error = B::Error;
353
354 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
355 where
356 I: IntoIterator<Item = Pixel<Self::Color>>,
357 {
358 let source_bounds = self
359 .rotation
360 .inverse()
361 .rotate_size(self.buffer.bounding_box().size);
362 let rotated_pixels = pixels.into_iter().map(|Pixel(point, color)| {
363 let rotated_point = self.rotation.rotate_point(point, source_bounds);
364 Pixel(rotated_point, color)
365 });
366 self.buffer.draw_iter(rotated_pixels)
367 }
368}
369
370#[cfg(test)]
371mod tests {
372 use super::*;
373 use embedded_graphics::pixelcolor::BinaryColor;
374
375 #[test]
376 fn test_binary_buffer_draw_iter_singles() {
377 const SIZE: Size = Size::new(16, 4);
378 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
379 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
380
381 buffer
383 .draw_iter([Pixel(Point::new(0, 0), BinaryColor::On)])
384 .unwrap();
385 assert_eq!(buffer.data[0], 0b10000000);
386
387 buffer
389 .draw_iter([Pixel(Point::new(10, 2), BinaryColor::On)])
390 .unwrap();
391 assert_eq!(buffer.data[5], 0b00100000);
392
393 buffer
395 .draw_iter([Pixel(Point::new(15, 3), BinaryColor::On)])
396 .unwrap();
397 assert_eq!(buffer.data[7], 0b1);
398 }
399
400 #[test]
401 fn test_binary_buffer_draw_iter_multiple() {
402 const SIZE: Size = Size::new(16, 4);
403 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
404 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
405
406 buffer
408 .draw_iter([
409 Pixel(Point::new(1, 0), BinaryColor::On),
410 Pixel(Point::new(2, 0), BinaryColor::On),
411 Pixel(Point::new(3, 0), BinaryColor::On),
412 Pixel(Point::new(2, 0), BinaryColor::Off),
413 Pixel(Point::new(1, 1), BinaryColor::On),
414 ])
415 .unwrap();
416
417 assert_eq!(buffer.data[0], 0b01010000);
418 assert_eq!(buffer.data[2], 0b01000000);
419 }
420
421 #[test]
422 fn test_binary_buffer_draw_iter_out_of_bounds() {
423 const SIZE: Size = Size::new(16, 4);
424 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
425 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
426 let previous_data = buffer.data;
427
428 buffer
430 .draw_iter([
431 Pixel(Point::new(-1, 0), BinaryColor::On),
432 Pixel(Point::new(0, -1), BinaryColor::On),
433 Pixel(Point::new(16, 0), BinaryColor::On),
434 Pixel(Point::new(0, 4), BinaryColor::On),
435 ])
436 .unwrap();
437
438 assert_eq!(
439 buffer.data, previous_data,
440 "Data should not change when drawing out-of-bounds pixels."
441 );
442 }
443
444 #[cfg(debug_assertions)]
445 #[test]
446 #[should_panic]
447 fn test_binary_buffer_must_have_aligned_width() {
448 let _ = BinaryBuffer::<16>::new(Size::new(10, 10));
449 }
450
451 #[cfg(debug_assertions)]
452 #[test]
453 #[should_panic]
454 fn test_binary_buffer_size_must_match_dimensions() {
455 let _ = BinaryBuffer::<16>::new(Size::new(16, 10));
456 }
457
458 #[test]
459 fn test_binary_buffer_fill_continguous() {
460 const SIZE: Size = Size::new(24, 8);
462 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
463 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
464
465 buffer
467 .fill_contiguous(
468 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
469 [BinaryColor::On; 8 * 8],
470 )
471 .unwrap();
472 buffer
473 .fill_contiguous(
474 &Rectangle::new(Point::new(6, 2), Size::new(12, 4)),
476 [BinaryColor::On; 12 * 4],
477 )
478 .unwrap();
479 buffer
480 .fill_contiguous(
481 &Rectangle::new(Point::new(20, 4), Size::new(8, 8)),
483 [BinaryColor::On; 8 * 8],
484 )
485 .unwrap();
486
487 #[rustfmt::skip]
488 let expected: [u8; 3 * 8] = [
489 0b11110000, 0b00000000, 0b00000000,
490 0b11110000, 0b00000000, 0b00000000,
491 0b11110011, 0b11111111, 0b11000000,
492 0b11110011, 0b11111111, 0b11000000,
493 0b00000011, 0b11111111, 0b11001111,
494 0b00000011, 0b11111111, 0b11001111,
495 0b00000000, 0b00000000, 0b00001111,
496 0b00000000, 0b00000000, 0b00001111,
497 ];
498 assert_eq!(buffer.data(), &expected);
499 }
500
501 #[test]
502 fn test_binary_buffer_fill_solid() {
503 const SIZE: Size = Size::new(24, 8);
505 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
506 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
507
508 buffer
510 .fill_solid(
511 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
512 BinaryColor::On,
513 )
514 .unwrap();
515 buffer
516 .fill_solid(
517 &Rectangle::new(Point::new(6, 2), Size::new(12, 4)),
519 BinaryColor::On,
520 )
521 .unwrap();
522 buffer
523 .fill_solid(
524 &Rectangle::new(Point::new(20, 4), Size::new(8, 8)),
526 BinaryColor::On,
527 )
528 .unwrap();
529
530 #[rustfmt::skip]
531 let expected: [u8; 3 * 8] = [
532 0b11110000, 0b00000000, 0b00000000,
533 0b11110000, 0b00000000, 0b00000000,
534 0b11110011, 0b11111111, 0b11000000,
535 0b11110011, 0b11111111, 0b11000000,
536 0b00000011, 0b11111111, 0b11001111,
537 0b00000011, 0b11111111, 0b11001111,
538 0b00000000, 0b00000000, 0b00001111,
539 0b00000000, 0b00000000, 0b00001111,
540 ];
541 assert_eq!(buffer.data(), &expected);
542 }
543
544 #[test]
545 fn test_rotated_buffer_bounds() {
546 const SIZE: Size = Size::new(8, 24);
547 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
548
549 let mut rotated_buffer =
550 RotatedBuffer::new(BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE), Rotate::R90);
551 assert_eq!(
552 rotated_buffer.bounding_box(),
553 Rectangle::new(Point::new(0, 0), Size::new(24, 8))
554 );
555
556 rotated_buffer =
557 RotatedBuffer::new(BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE), Rotate::R180);
558 assert_eq!(
559 rotated_buffer.bounding_box(),
560 Rectangle::new(Point::new(0, 0), Size::new(8, 24))
561 );
562
563 rotated_buffer =
564 RotatedBuffer::new(BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE), Rotate::R270);
565 assert_eq!(
566 rotated_buffer.bounding_box(),
567 Rectangle::new(Point::new(0, 0), Size::new(24, 8))
568 );
569 }
570
571 #[test]
572 fn test_rotated_buffer_draw_iter() {
573 const SIZE: Size = Size::new(8, 4);
574 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
575
576 let mut rotated_buffer =
577 RotatedBuffer::new(BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE), Rotate::R90);
578 rotated_buffer
579 .draw_iter([
580 Pixel(Point::new(-1, -1), BinaryColor::On), Pixel(Point::new(0, 0), BinaryColor::On),
582 Pixel(Point::new(1, 1), BinaryColor::On),
583 Pixel(Point::new(2, 2), BinaryColor::On),
584 ])
585 .unwrap();
586 #[rustfmt::skip]
587 let expected: [u8; 4] = [
588 0b00000001,
589 0b00000010,
590 0b00000100,
591 0b00000000,
592 ];
593 assert_eq!(rotated_buffer.inner().data(), &expected);
594
595 rotated_buffer =
596 RotatedBuffer::new(BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE), Rotate::R180);
597 rotated_buffer
598 .draw_iter([
599 Pixel(Point::new(-1, -1), BinaryColor::On), Pixel(Point::new(0, 0), BinaryColor::On),
601 Pixel(Point::new(1, 1), BinaryColor::On),
602 Pixel(Point::new(2, 2), BinaryColor::On),
603 ])
604 .unwrap();
605 #[rustfmt::skip]
606 let expected: [u8; 4] = [
607 0b00000000,
608 0b00000100,
609 0b00000010,
610 0b00000001,
611 ];
612 assert_eq!(rotated_buffer.inner().data(), &expected);
613
614 rotated_buffer =
615 RotatedBuffer::new(BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE), Rotate::R270);
616 rotated_buffer
617 .draw_iter([
618 Pixel(Point::new(-1, -1), BinaryColor::On), Pixel(Point::new(0, 0), BinaryColor::On),
620 Pixel(Point::new(1, 1), BinaryColor::On),
621 Pixel(Point::new(2, 2), BinaryColor::On),
622 ])
623 .unwrap();
624 #[rustfmt::skip]
625 let expected: [u8; 4] = [
626 0b00000000,
627 0b00100000,
628 0b01000000,
629 0b10000000,
630 ];
631 assert_eq!(rotated_buffer.inner().data(), &expected);
632 }
633
634 #[test]
635 fn test_rotated_buffer_fill_contiguous() {
636 const SIZE: Size = Size::new(8, 6);
638 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
639 let buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
640
641 let mut rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::R90);
642 rotated_buffer
643 .fill_contiguous(
644 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
645 [BinaryColor::On; 8 * 8],
646 )
647 .unwrap();
648
649 #[rustfmt::skip]
650 let expected: [u8; 6] = [
651 0b00001111,
652 0b00001111,
653 0b00001111,
654 0b00001111,
655 0b00000000,
656 0b00000000,
657 ];
658 assert_eq!(rotated_buffer.inner().data(), &expected);
659
660 rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::R180);
661 rotated_buffer
662 .fill_contiguous(
663 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
664 [BinaryColor::On; 8 * 8],
665 )
666 .unwrap();
667
668 #[rustfmt::skip]
669 let expected: [u8; 6] = [
670 0b00000000,
671 0b00000000,
672 0b00001111,
673 0b00001111,
674 0b00001111,
675 0b00001111,
676 ];
677 assert_eq!(rotated_buffer.inner().data(), &expected);
678
679 rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::R270);
680 rotated_buffer
681 .fill_contiguous(
682 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
683 [BinaryColor::On; 8 * 8],
684 )
685 .unwrap();
686
687 #[rustfmt::skip]
688 let expected: [u8; 6] = [
689 0b00000000,
690 0b00000000,
691 0b11110000,
692 0b11110000,
693 0b11110000,
694 0b11110000,
695 ];
696 assert_eq!(rotated_buffer.inner().data(), &expected);
697 }
698
699 #[test]
700 fn test_rotated_buffer_fill_solid() {
701 const SIZE: Size = Size::new(8, 6);
703 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
704 let buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
705
706 let mut rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::R90);
707 rotated_buffer
708 .fill_solid(
709 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
710 BinaryColor::On,
711 )
712 .unwrap();
713
714 #[rustfmt::skip]
715 let expected: [u8; 6] = [
716 0b00001111,
717 0b00001111,
718 0b00001111,
719 0b00001111,
720 0b00000000,
721 0b00000000,
722 ];
723 assert_eq!(rotated_buffer.inner().data(), &expected);
724
725 rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::R180);
726 rotated_buffer
727 .fill_solid(
728 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
729 BinaryColor::On,
730 )
731 .unwrap();
732
733 #[rustfmt::skip]
734 let expected: [u8; 6] = [
735 0b00000000,
736 0b00000000,
737 0b00001111,
738 0b00001111,
739 0b00001111,
740 0b00001111,
741 ];
742 assert_eq!(rotated_buffer.inner().data(), &expected);
743
744 rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::R270);
745 rotated_buffer
746 .fill_solid(
747 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
748 BinaryColor::On,
749 )
750 .unwrap();
751
752 #[rustfmt::skip]
753 let expected: [u8; 6] = [
754 0b00000000,
755 0b00000000,
756 0b11110000,
757 0b11110000,
758 0b11110000,
759 0b11110000,
760 ];
761 assert_eq!(rotated_buffer.inner().data(), &expected);
762 }
763
764 #[test]
765 fn test_rotate_near_corner() {
766 let mut r = Rotate::R90;
767 assert_eq!(
769 Point::new(18, 1),
770 r.rotate_point(Point::new(1, 1), Size::new(10, 20))
771 );
772 r = Rotate::R180;
773 assert_eq!(
775 Point::new(8, 18),
776 r.rotate_point(Point::new(1, 1), Size::new(10, 20))
777 );
778 r = Rotate::R270;
779 assert_eq!(
781 Point::new(1, 8),
782 r.rotate_point(Point::new(1, 1), Size::new(10, 20))
783 );
784 }
785
786 #[test]
787 fn test_rotate_centre() {
788 let mut r = Rotate::R90;
789 assert_eq!(
790 Point::new(2, 2),
791 r.rotate_point(Point::new(2, 2), Size::new(5, 5))
792 );
793 r = Rotate::R180;
794 assert_eq!(
795 Point::new(2, 2),
796 r.rotate_point(Point::new(2, 2), Size::new(5, 5))
797 );
798 r = Rotate::R270;
799 assert_eq!(
800 Point::new(2, 2),
801 r.rotate_point(Point::new(2, 2), Size::new(5, 5))
802 );
803 }
804
805 #[test]
806 fn test_rotate_size() {
807 let mut r = Rotate::R90;
808 assert_eq!(Size::new(5, 10), r.rotate_size(Size::new(10, 5)));
809 r = Rotate::R180;
810 assert_eq!(Size::new(10, 5), r.rotate_size(Size::new(10, 5)));
811 r = Rotate::R270;
812 assert_eq!(Size::new(5, 10), r.rotate_size(Size::new(10, 5)));
813 }
814
815 #[test]
816 fn test_rotate_rectangle() {
817 let mut r = Rotate::R90;
818 let rect = Rectangle::new(Point::new(1, 1), Size::new(3, 2));
819 let _dest_bounds = Size::new(8, 4);
821 let mut source_bounds = Size::new(4, 8);
822 let rotated = r.rotate_rectangle(rect, source_bounds);
823 assert_eq!(rotated.top_left, Point::new(5, 1));
826 assert_eq!(rotated.size, Size::new(2, 3));
827
828 r = Rotate::R180;
829 source_bounds = Size::new(8, 4);
830 let rotated = r.rotate_rectangle(rect, source_bounds);
831 assert_eq!(rotated.top_left, Point::new(4, 1));
834 assert_eq!(rotated.size, Size::new(3, 2));
835
836 r = Rotate::R270;
837 source_bounds = Size::new(4, 8);
838 let rotated = r.rotate_rectangle(rect, source_bounds);
839 assert_eq!(rotated.top_left, Point::new(1, 0));
842 assert_eq!(rotated.size, Size::new(2, 3));
843 }
844}