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;
260
261 fn rotate_rectangle(&self, rectangle: Rectangle, bounds: Size) -> Rectangle;
263}
264
265#[derive(Clone, Copy, Debug, PartialEq, Eq)]
267pub enum Rotate {
268 Degrees90,
269 Degrees180,
270 Degrees270,
271}
272
273impl Rotation for Rotate {
274 fn inverse(&self) -> Self {
275 match self {
276 Rotate::Degrees90 => Rotate::Degrees270,
277 Rotate::Degrees180 => Rotate::Degrees180,
278 Rotate::Degrees270 => Rotate::Degrees90,
279 }
280 }
281
282 fn rotate_size(&self, size: Size) -> Size {
283 match self {
284 Rotate::Degrees90 | Rotate::Degrees270 => Size::new(size.height, size.width),
285 Rotate::Degrees180 => size,
286 }
287 }
288
289 fn rotate_point(&self, point: Point, source_bounds: Size) -> Point {
290 match self {
291 Rotate::Degrees90 => Point::new(source_bounds.height as i32 - point.y - 1, point.x),
292 Rotate::Degrees180 => Point::new(
293 source_bounds.width as i32 - point.x - 1,
294 source_bounds.height as i32 - point.y - 1,
295 ),
296 Rotate::Degrees270 => Point::new(point.y, source_bounds.width as i32 - point.x - 1),
297 }
298 }
299
300 fn rotate_rectangle(&self, rectangle: Rectangle, source_bounds: Size) -> Rectangle {
301 match self {
302 Rotate::Degrees90 => {
303 let old_bottom_left =
304 rectangle.top_left + Point::new(0, rectangle.size.height as i32 - 1);
305 let new_top_left = self.rotate_point(old_bottom_left, source_bounds);
306 Rectangle::new(new_top_left, self.rotate_size(rectangle.size))
307 }
308 Rotate::Degrees180 => {
309 let old_bottom_right = rectangle.top_left + rectangle.size - Point::new(1, 1);
310 let new_top_left = self.rotate_point(old_bottom_right, source_bounds);
311 Rectangle::new(new_top_left, self.rotate_size(rectangle.size))
312 }
313 Rotate::Degrees270 => {
314 let old_top_right =
315 rectangle.top_left + Point::new(rectangle.size.width as i32 - 1, 0);
316 let new_top_left = self.rotate_point(old_top_right, source_bounds);
317 Rectangle::new(new_top_left, self.rotate_size(rectangle.size))
318 }
319 }
320 }
321}
322
323pub struct RotatedBuffer<B: DrawTarget, R: Rotation> {
336 bounds: Rectangle,
337 buffer: B,
338 rotation: R,
339}
340
341impl<B: DrawTarget, R: Rotation> RotatedBuffer<B, R> {
342 pub fn new(buffer: B, rotation: R) -> Self {
343 let inverse_rotation = rotation.inverse();
344 let inner_bounds = buffer.bounding_box();
345 let bounds = inverse_rotation.rotate_rectangle(inner_bounds, inner_bounds.size);
346 Self {
347 bounds,
348 buffer,
349 rotation,
350 }
351 }
352
353 pub fn inner(&mut self) -> &B {
355 &self.buffer
356 }
357
358 pub fn take_inner(self) -> B {
360 self.buffer
361 }
362}
363
364impl<B: DrawTarget, R: Rotation> Dimensions for RotatedBuffer<B, R> {
365 fn bounding_box(&self) -> Rectangle {
366 self.bounds
367 }
368}
369
370impl<B: DrawTarget, R: Rotation> DrawTarget for RotatedBuffer<B, R> {
371 type Color = B::Color;
372 type Error = B::Error;
373
374 fn draw_iter<I>(&mut self, pixels: I) -> Result<(), Self::Error>
375 where
376 I: IntoIterator<Item = Pixel<Self::Color>>,
377 {
378 let rotated_pixels = pixels.into_iter().map(|Pixel(point, color)| {
379 let rotated_point = self.rotation.rotate_point(point, self.bounds.size);
380 Pixel(rotated_point, color)
381 });
382 self.buffer.draw_iter(rotated_pixels)
383 }
384}
385
386#[cfg(test)]
387mod tests {
388 use super::*;
389 use embedded_graphics::pixelcolor::BinaryColor;
390
391 #[test]
392 fn test_binary_buffer_draw_iter_singles() {
393 const SIZE: Size = Size::new(16, 4);
394 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
395 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
396
397 buffer
399 .draw_iter([Pixel(Point::new(0, 0), BinaryColor::On)])
400 .unwrap();
401 assert_eq!(buffer.data[0], 0b10000000);
402
403 buffer
405 .draw_iter([Pixel(Point::new(10, 2), BinaryColor::On)])
406 .unwrap();
407 assert_eq!(buffer.data[5], 0b00100000);
408
409 buffer
411 .draw_iter([Pixel(Point::new(15, 3), BinaryColor::On)])
412 .unwrap();
413 assert_eq!(buffer.data[7], 0b1);
414 }
415
416 #[test]
417 fn test_binary_buffer_draw_iter_multiple() {
418 const SIZE: Size = Size::new(16, 4);
419 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
420 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
421
422 buffer
424 .draw_iter([
425 Pixel(Point::new(1, 0), BinaryColor::On),
426 Pixel(Point::new(2, 0), BinaryColor::On),
427 Pixel(Point::new(3, 0), BinaryColor::On),
428 Pixel(Point::new(2, 0), BinaryColor::Off),
429 Pixel(Point::new(1, 1), BinaryColor::On),
430 ])
431 .unwrap();
432
433 assert_eq!(buffer.data[0], 0b01010000);
434 assert_eq!(buffer.data[2], 0b01000000);
435 }
436
437 #[test]
438 fn test_binary_buffer_draw_iter_out_of_bounds() {
439 const SIZE: Size = Size::new(16, 4);
440 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
441 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
442 let previous_data = buffer.data;
443
444 buffer
446 .draw_iter([
447 Pixel(Point::new(-1, 0), BinaryColor::On),
448 Pixel(Point::new(0, -1), BinaryColor::On),
449 Pixel(Point::new(16, 0), BinaryColor::On),
450 Pixel(Point::new(0, 4), BinaryColor::On),
451 ])
452 .unwrap();
453
454 assert_eq!(
455 buffer.data, previous_data,
456 "Data should not change when drawing out-of-bounds pixels."
457 );
458 }
459
460 #[cfg(debug_assertions)]
461 #[test]
462 #[should_panic]
463 fn test_binary_buffer_must_have_aligned_width() {
464 let _ = BinaryBuffer::<16>::new(Size::new(10, 10));
465 }
466
467 #[cfg(debug_assertions)]
468 #[test]
469 #[should_panic]
470 fn test_binary_buffer_size_must_match_dimensions() {
471 let _ = BinaryBuffer::<16>::new(Size::new(16, 10));
472 }
473
474 #[test]
475 fn test_binary_buffer_fill_continguous() {
476 const SIZE: Size = Size::new(24, 8);
478 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
479 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
480
481 buffer
483 .fill_contiguous(
484 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
485 [BinaryColor::On; 8 * 8],
486 )
487 .unwrap();
488 buffer
489 .fill_contiguous(
490 &Rectangle::new(Point::new(6, 2), Size::new(12, 4)),
492 [BinaryColor::On; 12 * 4],
493 )
494 .unwrap();
495 buffer
496 .fill_contiguous(
497 &Rectangle::new(Point::new(20, 4), Size::new(8, 8)),
499 [BinaryColor::On; 8 * 8],
500 )
501 .unwrap();
502
503 #[rustfmt::skip]
504 let expected: [u8; 3 * 8] = [
505 0b11110000, 0b00000000, 0b00000000,
506 0b11110000, 0b00000000, 0b00000000,
507 0b11110011, 0b11111111, 0b11000000,
508 0b11110011, 0b11111111, 0b11000000,
509 0b00000011, 0b11111111, 0b11001111,
510 0b00000011, 0b11111111, 0b11001111,
511 0b00000000, 0b00000000, 0b00001111,
512 0b00000000, 0b00000000, 0b00001111,
513 ];
514 assert_eq!(buffer.data(), &expected);
515 }
516
517 #[test]
518 fn test_binary_buffer_fill_solid() {
519 const SIZE: Size = Size::new(24, 8);
521 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
522 let mut buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
523
524 buffer
526 .fill_solid(
527 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
528 BinaryColor::On,
529 )
530 .unwrap();
531 buffer
532 .fill_solid(
533 &Rectangle::new(Point::new(6, 2), Size::new(12, 4)),
535 BinaryColor::On,
536 )
537 .unwrap();
538 buffer
539 .fill_solid(
540 &Rectangle::new(Point::new(20, 4), Size::new(8, 8)),
542 BinaryColor::On,
543 )
544 .unwrap();
545
546 #[rustfmt::skip]
547 let expected: [u8; 3 * 8] = [
548 0b11110000, 0b00000000, 0b00000000,
549 0b11110000, 0b00000000, 0b00000000,
550 0b11110011, 0b11111111, 0b11000000,
551 0b11110011, 0b11111111, 0b11000000,
552 0b00000011, 0b11111111, 0b11001111,
553 0b00000011, 0b11111111, 0b11001111,
554 0b00000000, 0b00000000, 0b00001111,
555 0b00000000, 0b00000000, 0b00001111,
556 ];
557 assert_eq!(buffer.data(), &expected);
558 }
559
560 #[test]
561 fn test_rotated_buffer_bounds() {
562 const SIZE: Size = Size::new(8, 24);
563 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
564
565 let mut rotated_buffer = RotatedBuffer::new(
566 BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE),
567 Rotate::Degrees90,
568 );
569 assert_eq!(
570 rotated_buffer.bounding_box(),
571 Rectangle::new(Point::new(0, 0), Size::new(24, 8))
572 );
573
574 rotated_buffer = RotatedBuffer::new(
575 BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE),
576 Rotate::Degrees180,
577 );
578 assert_eq!(
579 rotated_buffer.bounding_box(),
580 Rectangle::new(Point::new(0, 0), Size::new(8, 24))
581 );
582
583 rotated_buffer = RotatedBuffer::new(
584 BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE),
585 Rotate::Degrees270,
586 );
587 assert_eq!(
588 rotated_buffer.bounding_box(),
589 Rectangle::new(Point::new(0, 0), Size::new(24, 8))
590 );
591 }
592
593 #[test]
594 fn test_rotated_buffer_draw_iter() {
595 const SIZE: Size = Size::new(8, 4);
596 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
597
598 let mut rotated_buffer = RotatedBuffer::new(
599 BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE),
600 Rotate::Degrees90,
601 );
602 rotated_buffer
603 .draw_iter([
604 Pixel(Point::new(-1, -1), BinaryColor::On), Pixel(Point::new(0, 0), BinaryColor::On),
606 Pixel(Point::new(1, 1), BinaryColor::On),
607 Pixel(Point::new(2, 2), BinaryColor::On),
608 ])
609 .unwrap();
610 #[rustfmt::skip]
611 let expected: [u8; 4] = [
612 0b00000001,
613 0b00000010,
614 0b00000100,
615 0b00000000,
616 ];
617 assert_eq!(rotated_buffer.inner().data(), &expected);
618
619 rotated_buffer = RotatedBuffer::new(
620 BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE),
621 Rotate::Degrees180,
622 );
623 rotated_buffer
624 .draw_iter([
625 Pixel(Point::new(-1, -1), BinaryColor::On), Pixel(Point::new(0, 0), BinaryColor::On),
627 Pixel(Point::new(1, 1), BinaryColor::On),
628 Pixel(Point::new(2, 2), BinaryColor::On),
629 ])
630 .unwrap();
631 #[rustfmt::skip]
632 let expected: [u8; 4] = [
633 0b00000000,
634 0b00000100,
635 0b00000010,
636 0b00000001,
637 ];
638 assert_eq!(rotated_buffer.inner().data(), &expected);
639
640 rotated_buffer = RotatedBuffer::new(
641 BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE),
642 Rotate::Degrees270,
643 );
644 rotated_buffer
645 .draw_iter([
646 Pixel(Point::new(-1, -1), BinaryColor::On), Pixel(Point::new(0, 0), BinaryColor::On),
648 Pixel(Point::new(1, 1), BinaryColor::On),
649 Pixel(Point::new(2, 2), BinaryColor::On),
650 ])
651 .unwrap();
652 #[rustfmt::skip]
653 let expected: [u8; 4] = [
654 0b00000000,
655 0b00100000,
656 0b01000000,
657 0b10000000,
658 ];
659 assert_eq!(rotated_buffer.inner().data(), &expected);
660 }
661
662 #[test]
663 fn test_rotated_buffer_fill_contiguous() {
664 const SIZE: Size = Size::new(8, 6);
666 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
667 let buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
668
669 let mut rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::Degrees90);
670 rotated_buffer
671 .fill_contiguous(
672 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
673 [BinaryColor::On; 8 * 8],
674 )
675 .unwrap();
676
677 #[rustfmt::skip]
678 let expected: [u8; 6] = [
679 0b00001111,
680 0b00001111,
681 0b00001111,
682 0b00001111,
683 0b00000000,
684 0b00000000,
685 ];
686 assert_eq!(rotated_buffer.inner().data(), &expected);
687
688 rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::Degrees180);
689 rotated_buffer
690 .fill_contiguous(
691 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
692 [BinaryColor::On; 8 * 8],
693 )
694 .unwrap();
695
696 #[rustfmt::skip]
697 let expected: [u8; 6] = [
698 0b00000000,
699 0b00000000,
700 0b00001111,
701 0b00001111,
702 0b00001111,
703 0b00001111,
704 ];
705 assert_eq!(rotated_buffer.inner().data(), &expected);
706
707 rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::Degrees270);
708 rotated_buffer
709 .fill_contiguous(
710 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
711 [BinaryColor::On; 8 * 8],
712 )
713 .unwrap();
714
715 #[rustfmt::skip]
716 let expected: [u8; 6] = [
717 0b00000000,
718 0b00000000,
719 0b11110000,
720 0b11110000,
721 0b11110000,
722 0b11110000,
723 ];
724 assert_eq!(rotated_buffer.inner().data(), &expected);
725 }
726
727 #[test]
728 fn test_rotated_buffer_fill_solid() {
729 const SIZE: Size = Size::new(8, 6);
731 const BUFFER_LENGTH: usize = binary_buffer_length(SIZE);
732 let buffer = BinaryBuffer::<{ BUFFER_LENGTH }>::new(SIZE);
733
734 let mut rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::Degrees90);
735 rotated_buffer
736 .fill_solid(
737 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
738 BinaryColor::On,
739 )
740 .unwrap();
741
742 #[rustfmt::skip]
743 let expected: [u8; 6] = [
744 0b00001111,
745 0b00001111,
746 0b00001111,
747 0b00001111,
748 0b00000000,
749 0b00000000,
750 ];
751 assert_eq!(rotated_buffer.inner().data(), &expected);
752
753 rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::Degrees180);
754 rotated_buffer
755 .fill_solid(
756 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
757 BinaryColor::On,
758 )
759 .unwrap();
760
761 #[rustfmt::skip]
762 let expected: [u8; 6] = [
763 0b00000000,
764 0b00000000,
765 0b00001111,
766 0b00001111,
767 0b00001111,
768 0b00001111,
769 ];
770 assert_eq!(rotated_buffer.inner().data(), &expected);
771
772 rotated_buffer = RotatedBuffer::new(buffer.clone(), Rotate::Degrees270);
773 rotated_buffer
774 .fill_solid(
775 &Rectangle::new(Point::new(-4, -4), Size::new(8, 8)),
776 BinaryColor::On,
777 )
778 .unwrap();
779
780 #[rustfmt::skip]
781 let expected: [u8; 6] = [
782 0b00000000,
783 0b00000000,
784 0b11110000,
785 0b11110000,
786 0b11110000,
787 0b11110000,
788 ];
789 assert_eq!(rotated_buffer.inner().data(), &expected);
790 }
791
792 #[test]
793 fn test_rotate_near_corner() {
794 let mut r = Rotate::Degrees90;
795 assert_eq!(
797 Point::new(18, 1),
798 r.rotate_point(Point::new(1, 1), Size::new(10, 20))
799 );
800 r = Rotate::Degrees180;
801 assert_eq!(
803 Point::new(8, 18),
804 r.rotate_point(Point::new(1, 1), Size::new(10, 20))
805 );
806 r = Rotate::Degrees270;
807 assert_eq!(
809 Point::new(1, 8),
810 r.rotate_point(Point::new(1, 1), Size::new(10, 20))
811 );
812 }
813
814 #[test]
815 fn test_rotate_centre() {
816 let mut r = Rotate::Degrees90;
817 assert_eq!(
818 Point::new(2, 2),
819 r.rotate_point(Point::new(2, 2), Size::new(5, 5))
820 );
821 r = Rotate::Degrees180;
822 assert_eq!(
823 Point::new(2, 2),
824 r.rotate_point(Point::new(2, 2), Size::new(5, 5))
825 );
826 r = Rotate::Degrees270;
827 assert_eq!(
828 Point::new(2, 2),
829 r.rotate_point(Point::new(2, 2), Size::new(5, 5))
830 );
831 }
832
833 #[test]
834 fn test_rotate_size() {
835 let mut r = Rotate::Degrees90;
836 assert_eq!(Size::new(5, 10), r.rotate_size(Size::new(10, 5)));
837 r = Rotate::Degrees180;
838 assert_eq!(Size::new(10, 5), r.rotate_size(Size::new(10, 5)));
839 r = Rotate::Degrees270;
840 assert_eq!(Size::new(5, 10), r.rotate_size(Size::new(10, 5)));
841 }
842
843 #[test]
844 fn test_rotate_rectangle() {
845 let mut r = Rotate::Degrees90;
846 let rect = Rectangle::new(Point::new(1, 1), Size::new(3, 2));
847 let _dest_bounds = Size::new(8, 4);
849 let mut source_bounds = Size::new(4, 8);
850 let rotated = r.rotate_rectangle(rect, source_bounds);
851 assert_eq!(rotated.top_left, Point::new(5, 1));
854 assert_eq!(rotated.size, Size::new(2, 3));
855
856 r = Rotate::Degrees180;
857 source_bounds = Size::new(8, 4);
858 let rotated = r.rotate_rectangle(rect, source_bounds);
859 assert_eq!(rotated.top_left, Point::new(4, 1));
862 assert_eq!(rotated.size, Size::new(3, 2));
863
864 r = Rotate::Degrees270;
865 source_bounds = Size::new(4, 8);
866 let rotated = r.rotate_rectangle(rect, source_bounds);
867 assert_eq!(rotated.top_left, Point::new(1, 0));
870 assert_eq!(rotated.size, Size::new(2, 3));
871 }
872}