1extern crate reed_solomon;
2
3use std::ops::{BitXorAssign};
4use std::fmt::{Binary, Debug};
5use self::reed_solomon::{Encoder, Buffer};
6
7use qr_encoder::cell::{
8 Cell,
9 Point,
10 CellType,
11 Color,
12 PlotPoint
13};
14use qr_encoder::qr::QR;
15use qr_encoder::util::{CodeWord, get_indices_for_dimensions};
16
17
18pub enum ECLevel {
19 Low,
20 Medium,
21 Q,
22 High,
23}
24
25pub enum EncodingMode {
26 Numeric,
27 AlphaNumeric,
28 Byte,
29 Japanese
30}
31
32pub struct QRConfig {
33 pub version: usize,
34 pub data: Vec<u8>,
35 pub codewords: Vec<u8>,
36 pub codeword_properties: CodeWord,
37 pub mask: usize,
38 pub encoding: u8, pub encoding_mode: EncodingMode,
40 pub debug_mode: bool,
41 pub requires_alignment: bool,
42 pub finder_points: [(usize, usize); 3],
43 pub size: usize,
44 pub err_correction_level: ECLevel
45}
46
47const ECC_FORMAT_MASK: u16 = 21522;
48const GEN_POLY_VERSION: u32 = 7973;
49const GEN_POLY_FORMAT: u16 = 1335;
50
51
52
53fn assign_bit_from_codeword(index: usize, body: &mut Vec<Cell>, dark: bool) -> isize {
54 let cell = body.get_mut(index).unwrap();
55 match cell.module_type {
56 CellType::None => {
57 if dark {
58 cell.value = 1;
59 cell.color = Color { r: 0, b: 0, g: 0 };
60 } else {
61 cell.value = 0;
62 cell.color = Color { r: 255, g: 255, b: 255 };
63 };
64 cell.module_type = CellType::Message;
65
66 -1
67 },
68 _ => 0
69 }
70}
71
72fn zig_zag_points(canvas_size: usize) -> Vec<usize> {
73 let mut col = canvas_size - 1;
74 let mut row = canvas_size - 1;
75 let mut indices = vec![];
76 let mut inc = -1;
77 while col != 0 {
78 if col == 6 {
79 col -= 1;
80 continue;
81 }
82 for c in 0..2 {
83 let index = (row * canvas_size) + col - c;
84 indices.push(index);
85 }
86
87 if row == 0 && inc == -1 {
88 inc = 1;
89 col -= 2;
90 } else if row == canvas_size - 1 && inc == 1 {
91 inc = -1;
92 if col == 1 {
93 col -= 1;
94 } else {
95 col -= 2;
96 }
97 } else {
98 row = (row as isize + inc) as usize;
99 }
100 }
101
102 indices
103}
104
105pub fn ecc_format_u32(data: u32, gen_poly: u32) -> u32 {
106 let (limit, mut format_str) = (19, data << 12);
107
108 while format_str.leading_zeros() <= limit {
109 let diff = gen_poly.leading_zeros() - format_str.leading_zeros();
110 format_str ^= gen_poly << diff as usize;
111 }
112
113 (data << 12) | format_str
114}
115
116pub fn ecc_format_u16(data: u16, gen_poly: u16, gen_mask: u16) -> u16 {
117 let (limit, mut format_str) = (5, data << 10);
118
119 while format_str.leading_zeros() <= limit {
120 let diff = gen_poly.leading_zeros() - format_str.leading_zeros();
121 format_str ^= gen_poly << diff as usize;
122 }
123
124 ((data << 10) | format_str) ^ gen_mask
125}
126
127fn interleave_blocks(blocks: &[Buffer], block_size: usize, ecc_block_size: usize) -> Vec<u8> {
130 let mut data: Vec<u8> = vec![];
131 for i in 0..block_size {
132 for block in blocks {
133 if let Some(cw) = block.data().get(i) {
134 data.push(*cw);
135 } else {
136 println!("bleh: {}, block_size: {}", i, block_size);
137 }
138 }
139 }
140
141 for i in 0..ecc_block_size {
142 for block in blocks {
143 if let Some(cw) = block.ecc().get(i) {
144 data.push(*cw);
145 } else {
146 panic!("ADLKJSDLFKJD ECC {}", i);
147 }
148 }
149 }
150
151 data
152}
153
154pub struct CellTrack(pub Vec<usize>, pub Vec<usize>, pub Vec<usize>);
155
156impl QRConfig {
157 pub fn gen_qr_code(&mut self) -> (QR, CellTrack) {
158 self.translate_data();
159 self.encode_error_correction_codewords();
160
161 let mut canvas: QR = QR {
162 body: self.create_body()
163 };
164
165 canvas.setup(&self);
166
167 let tracker = self.process_data(&mut canvas);
168 self.post_process_data(&mut canvas);
169
170 (canvas, tracker)
171 }
172
173 fn process_data(&self, canvas: &mut QR) -> CellTrack {
174 let mut bit_index = 7;
175 let mut codeword_index = 0usize;
176 let mut bit_order = vec![];
177 let mut cw_order = vec![];
178 let mut point_order = vec![];
179 let pathing = zig_zag_points(self.size);
180 let pathing_iter = &mut pathing.iter();
181
182 while codeword_index < self.codewords.len() {
184 let cw = self.codewords[codeword_index];
185 bit_order.push(bit_index as usize);
186 cw_order.push(codeword_index as usize);
187 let idx = pathing_iter.next().unwrap();
188 point_order.push(*idx as usize);
189 bit_index += assign_bit_from_codeword(*idx, &mut canvas.body, (cw >> bit_index) & 1 == 1);
190
191 if bit_index == -1 {
192 bit_index = 7;
193 codeword_index += 1;
194 }
195 }
196
197 let mut remainder_bits = self.get_remainder_bit_length();
198 while remainder_bits > 0 {
199 let i = pathing_iter.next().unwrap();
200 remainder_bits += assign_bit_from_codeword(*i, &mut canvas.body, false);
201 }
202
203 CellTrack(bit_order, cw_order, point_order)
204 }
205
206 fn post_process_data(&self, canvas: &mut QR) {
207 let body = &mut canvas.body;
208 let mut best = 0;
209 let mut best_pattern = 0;
210 for pattern in 0..7 {
211 let mut copy = &mut body.clone();
212 self.apply_mask_pattern(&mut copy, pattern);
213 let score = self.eval_penalty_scores(copy);
214 if best == 0 || score < best {
215 best = score;
216 best_pattern = pattern;
217 }
218 }
219
220 self.apply_mask_pattern(body, best_pattern);
221 self.encode_format_areas(body, best_pattern as u8);
222
223 if self.version >= 7 {
224 self.apply_version_information(body);
225 }
226 }
227
228 pub fn get_ecc_length(&self) -> usize {
229 self.codeword_properties.ecc_codeword_count
230 }
231
232 pub fn get_remainder_bit_length(&self) -> isize {
233 match self.version {
234 2...6 => 7,
235 14...20 | 28...34 => 3,
236 _ => 0
237 }
238 }
239
240 pub fn get_mask_pattern(&self, n: usize) -> Box<Fn(usize, usize) -> bool> {
241 match n {
242 0 => Box::new(move |row: usize, col: usize| (row + col) % 2 == 0),
243 1 => Box::new(move |row: usize, _: usize| row % 2 == 0),
244 2 => Box::new(move |_: usize, col: usize| col % 3 == 0),
245 3 => Box::new(move |row: usize, col: usize| (row + col) % 3 == 0),
246 4 => Box::new(move |row: usize, col: usize| ((row / 2) + (col / 3)) % 2 == 0),
247 5 => Box::new(move |row: usize, col: usize| ((row * col) % 2) + ((row * col) % 3) == 0),
248 6 => Box::new(move |row: usize, col: usize| (((row * col) % 2) + ((row * col) % 3) ) % 2 == 0),
249 _ => Box::new(move |row: usize, col: usize| (((row + col) % 2) + ((row * col) % 3) ) % 2 == 0)
250 }
251 }
252
253 pub fn apply_version_information(&self, body: &mut Vec<Cell>) {
254 let canvas_size = self.size as isize;
255 let origin = (canvas_size - 12) as isize;
256 let bit_string = ecc_format_u32(self.version as u32, GEN_POLY_VERSION);
257 let upper_right_indices = get_indices_for_dimensions(origin, 1, canvas_size - 3);
258 let lower_left_indices = get_indices_for_dimensions(origin * canvas_size, canvas_size, (-canvas_size * 3) + 1);
259 for (bit_pos, i) in upper_right_indices.iter().enumerate() {
262 let is_bit = ((bit_string >> bit_pos) & 1) > 0;
263 let color: Color = if is_bit {
264 Color { r: 0, b: 0, g: 0 }
265 } else {
266 Color { r: 255, b: 255, g: 255 }
267 };
268
269 match body.get_mut(*i) {
270 Some(c) => c.color = color,
271 None => {}
272 }
273 }
274
275 for (bit_index, idx) in lower_left_indices.iter().enumerate() {
276 let is_bit = (bit_string & (1 << bit_index)) > 0;
277 let color: Color = if is_bit {
278 Color { r: 0, b: 0, g: 0 }
279 } else {
280 Color { r: 255, b: 255, g: 255 }
281 };
282 match body.get_mut(*idx) {
283 Some(c) => c.color = color,
284 None => {}
285 }
286 }
287 }
288
289 pub fn encode_format_areas(&self, body: &mut Vec<Cell>, pattern: u8) {
290 let ec_level: u8 = match self.err_correction_level {
291 ECLevel::Low => 1,
292 ECLevel::Medium => 0,
293 ECLevel::Q => 3,
294 _ => 2
295 };
296
297 let data = (ec_level << 3) | pattern;
298 let format_str = ecc_format_u16(data as u16, GEN_POLY_FORMAT, ECC_FORMAT_MASK);
299
300 let mut bit_position = 14;
301
302 let mut x = 8;
303 let mut y = 0;
304
305 while y != self.size {
306 let bit = format_str & (1 << bit_position);
307 let color: Color = if bit == 0 {
308 Color { r: 255, g: 255, b: 255 }
309 } else {
310 Color { r: 0, g: 0, b: 0 }
311 };
312
313 let idx = (x * self.size) + y;
314 let cell = body.get_mut(idx).unwrap();
315 match cell.module_type {
316 CellType::Format => cell.color = color,
317 CellType::Timing => {
318 if x == 8 {
319 y += 1;
320 } else {
321 x -= 1;
322 }
323 continue;
324 },
325 CellType::DarkModule => {
326 x = 8;
327 y = self.size - 8;
328 continue;
329 }
330 _ => panic!("What is this? {:?}", cell)
331 }
332
333 if x == 8 && (y < 8 || y >= self.size - 8) {
334 y += 1;
335 } else if y == 8 && x > 0 {
336 x -= 1;
337 } else if x == 0 && y == 8 {
338 x = self.size - 1;
339 }
340
341 if bit_position == 0 {
342 bit_position = 14;
343 } else {
344 bit_position -= 1;
345 }
346 }
347 }
348
349 pub fn apply_mask_pattern(&self, body: &mut Vec<Cell>, n: usize) {
350 let pattern = self.get_mask_pattern(n);
351
352 for cell in body {
353 match cell.module_type {
354 CellType::Message => {
355 let flip_module = pattern(cell.point.0, cell.point.1);
356 if flip_module && cell.is_black() {
357 cell.color = Color { r: 255, g: 255, b: 255 };
358 } else if flip_module {
359 cell.color = Color { r: 0, g: 0, b: 0 };
360 }
361 },
362 _ => {}
363 }
364 }
365 }
366
367 pub fn eval_penalty_scores(&self, body: &Vec<Cell>) -> usize {
368 let one = self.penalty_score_eval_one(body);
369 let two = self.penalty_score_eval_two(body);
370 let three = self.penalty_score_eval_three(body);
371 let four = self.penalty_score_eval_four(body);
372 let total = one + two + three + four;
373
374 total
375 }
376
377 pub fn penalty_score_eval_two(&self, body: &Vec<Cell>) -> usize {
378 let mut penalty_total = 0;
379 let canvas_size = self.size;
380
381 let adjacent_coords = [
382 canvas_size,
383 canvas_size + 1,
384 1
385 ];
386
387 for x in 0..(canvas_size - 1) {
388 for y in 0..(canvas_size - 1) {
389 let idx = (x * canvas_size) + y;
390 let is_black = body[idx].is_black();
391 let square = adjacent_coords.into_iter()
392 .map(|&i| body[i + idx].is_black())
393 .all(|p| p == is_black);
394
395 if square {
396 penalty_total += 3;
397 }
398 }
399 }
400
401 penalty_total
402 }
403
404
405 fn check_column(&self, body: &Vec<Cell>, column: isize) -> usize {
406 let mut subtotal = 0;
407 let pattern_mask: u16 = 0b00001011101;
408 let reverse_mask: u16 = 0b10111010000;
409 let remap_pattern: u16 = 0b11111111111;
410 let mut current_pattern = 0;
411 for row in 0..self.size {
412 let idx = (row * self.size) + column as usize;
413 let cell = &body[idx];
414
415 if cell.is_black() {
416 current_pattern = ((current_pattern << 1) ^ 1) & remap_pattern;
417 } else {
418 current_pattern = (current_pattern << 1) & remap_pattern;
419 }
420
421 if row >= 9 && current_pattern == pattern_mask || current_pattern == reverse_mask {
422 subtotal += 40;
423 }
424 }
425
426 subtotal
427 }
428
429 fn check_row(&self, body: &Vec<Cell>, row: isize) -> usize {
430 let mut subtotal = 0;
431 let pattern_mask: u16 = 0b00001011101;
432 let reverse_mask: u16 = 0b10111010000;
433 let remap_pattern: u16 = 0b11111111111;
434 let mut current_pattern = 0;
435 for column in 0..self.size {
436 let idx = ((row as usize) * self.size) + column as usize;
437 let cell = &body[idx];
438
439 if cell.is_black() {
440 current_pattern = ((current_pattern << 1) ^ 1) & remap_pattern;
441 } else {
442 current_pattern = (current_pattern << 1) & remap_pattern;
443 }
444
445 if column >= 9 && current_pattern == pattern_mask || current_pattern == reverse_mask {
446 subtotal += 40;
447 }
448 }
449
450 subtotal
451 }
452
453 pub fn penalty_score_eval_three(&self, body: &Vec<Cell>) -> usize {
454 let mut penalty_total = 0;
455
456 for i in 0..self.size {
457 penalty_total += self.check_column(body, i as isize);
458 penalty_total += self.check_row(body, i as isize);
459 }
460 penalty_total
461 }
462
463 pub fn penalty_score_eval_one(&self, body: &Vec<Cell>) -> usize {
464 let canvas_size = self.size;
465 let mut current_row = 0;
466 let mut consecutive_same_color = 1;
467 let mut tracking_black = false;
468 let mut penalty_total = 0;
469
470 for cell in body {
471 if cell.point.0 != current_row {
472 if consecutive_same_color >= 5 {
474 penalty_total += consecutive_same_color - 2;
475 }
476 consecutive_same_color = 1;
477 tracking_black = cell.is_black();
478 current_row = cell.point.0;
479 continue;
480 }
481 let is_black = cell.is_black();
482
483 if (tracking_black && is_black) || (!tracking_black && !is_black) {
484 consecutive_same_color += 1;
485 } else if (tracking_black && !is_black) || (!tracking_black && is_black) {
486 if consecutive_same_color >= 5 {
488 penalty_total += consecutive_same_color - 2;
489 }
490
491 consecutive_same_color = 1;
492 tracking_black = is_black;
493 }
494 }
495
496 let cell_count = body.len();
497 let mut idx = 0;
498
499 while idx < cell_count {
500 let cell = &body[idx];
501 let is_black = cell.is_black();
502
503 if (tracking_black && is_black) || (!tracking_black && !is_black) {
504 consecutive_same_color += 1;
505 } else if (tracking_black && !is_black) || (!tracking_black && is_black) {
506 if consecutive_same_color >= 5 {
508 penalty_total += consecutive_same_color - 2;
509 }
510
511 consecutive_same_color = 1;
512 tracking_black = is_black;
513 }
514
515 if cell.point.1 == (canvas_size - 1) && cell.point.0 == (canvas_size - 1) {
516 break;
517 } else if cell.point.0 == canvas_size - 1 {
518 idx = cell.point.1 + 1;
519 consecutive_same_color = 1;
520 } else {
521 idx += canvas_size;
522 }
523 }
524
525 penalty_total
526 }
527
528 pub fn penalty_score_eval_four(&self, body: &Vec<Cell>) -> usize {
529 let total_modules = body.len() as f64;
531 let black_modules: f64 = body.iter()
532 .fold(0.0, |acc, ref c| {
533 if c.is_black() {
534 acc + 1.0
535 } else {
536 acc
537 }
538 });
539
540 let black_percentage = ((black_modules / total_modules) * 100.0).round() as usize;
541 let remainder = black_percentage % 5;
542
543 let prev_mul = black_percentage - remainder;
544 let next_mul = prev_mul + 5;
545
546 let prev_abs = (50 - prev_mul as isize).abs();
547 let next_abs = (50 - next_mul as isize).abs();
548
549 let prev_div = prev_abs / 5;
550 let next_div = next_abs / 5;
551
552
553 if prev_div < next_div {
554 (prev_div * 10) as usize
555 } else {
556 (next_div * 10) as usize
557 }
558 }
559
560 pub fn verify_version(&mut self) {
561 }
574
575 pub fn debug_data(&self) {
576 let ref data = self.data;
577 let ref codewords = self.codewords;
578 println!("data {}, codewords {}", data.len(), codewords.len());
579 println!("cw: {:?}", self.codeword_properties);
580 }
587
588 pub fn encode_error_correction_codewords(&mut self) {
589 let ecc_len = self.codeword_properties.ecc_codeword_count;
590 let ecc_per_block = ecc_len / self.codeword_properties.block_count;
591 let encoder = Encoder::new(ecc_per_block);
592 let (group_one, group_two) = self.codeword_properties.get_data_cw_total_for_groups();
593 let data_codewords = &mut self.codewords;
594 let mid_point = group_one.blocks * group_one.codewords_per_block;
595 let mut blocks: Vec<Buffer> = vec![];
596 let mut data_section: Vec<u8> = vec![];
597
598 {
599 let (first_group_data, second_group_data) = data_codewords.split_at(mid_point);
600 for data_block in first_group_data.chunks(group_one.codewords_per_block) {
601 let buffer = encoder.encode(data_block);
602 blocks.push(buffer);
603 }
604
605 if group_two.blocks > 0 {
606 for data_block in second_group_data.chunks(group_two.codewords_per_block) {
607 let buffer = encoder.encode(data_block);
608 blocks.push(buffer);
609 }
610 }
611
612 let codeword_max = if group_one.codewords_per_block > group_two.codewords_per_block {
613 group_one.codewords_per_block
614 } else {
615 group_two.codewords_per_block
616 };
617
618 let mut interleaved_data = interleave_blocks(&blocks[..], codeword_max, ecc_per_block);
619 data_section.append(&mut interleaved_data);
620 }
621
622 *data_codewords = data_section;
623 }
624
625
626 pub fn translate_data(&mut self) {
627 let data_cw_length = self.codeword_properties.get_data_codeword_length();
628 let data_length = self.data.len() as u16;
629 let encoding = self.encoding;
630 let copied_data = self.data.clone();
631 {
632 let codewords = &mut self.codewords;
633 let mut first_byte = encoding << 4;
634 let mut second_byte: u8 = data_length as u8;
635
636 if self.version > 9 {
637 second_byte = (data_length >> 8) as u8;
638 codewords.push(first_byte | (second_byte >> 4));
639 first_byte = second_byte << 4;
640 second_byte = data_length as u8;
641 } else {
642 second_byte = data_length as u8;
643 }
644
645 let mut index = 0;
656
657 loop {
658 codewords.push(first_byte | (second_byte >> 4));
659 first_byte = second_byte << 4;
660
661 if let Some(byte) = copied_data.get(index) {
662 second_byte = *byte;
663 index += 1;
664 } else {
665 codewords.push(second_byte << 4);
666 break;
667 }
668 }
669 }
670
671 let mut swap = false;
675 let mut n = 0;
676 while self.codewords.len() < data_cw_length {
677 n += 1;
678 if swap {
679 self.codewords.push(17u8);
680 } else {
681 self.codewords.push(236u8);
682 }
683
684 swap = !swap;
685 }
686
687 if self.debug_mode {
688 println!("THIS IS HOW MANY PADDED BYTES ARE ADDED BEFORE INTERLEAVING {}", n);
689
690 println!("after translate {}", self.codewords.len());
691 for (idx, cw) in self.codewords.iter().enumerate() {
692 println!("Codeword {}: {:08b}", idx, cw);
693 }
694 }
695 }
696
697 pub fn create_body(&self) -> Vec<Cell> {
698 let mut rows: Vec<Cell> = vec![];
700 let row_len = self.size;
701 for x in 0..row_len {
702 for y in 0..row_len {
703 let cell = Cell {
704 point: Point(x as usize, y as usize),
705 value: 0,
706 color: Color { r: 255, g: 255, b: 255 },
707 module_type: CellType::None
708 };
709 rows.push(cell);
710 }
711 }
712 rows
713 }
714
715 pub fn get_content_length(&self) -> usize {
716 let modifier = match self.version {
717 1...10 => 0,
718 11...27 => 2,
719 _ => 4
720 };
721 match self.encoding {
722 1 => 10 + modifier,
723 2 => 9 + modifier,
724 8 => 12 + modifier,
725 _ => {
726 if self.version < 10 {
727 8
728 } else {
729 16
730 }
731 }
732 }
733 }
734
735 pub fn apply_version_information_areas(&self, body: &mut Vec<Cell>) {
736 let mut x = self.size - 11;
737 let mut y = 0;
738 let mut blocks = 6 * 3;
739 while blocks > 0 {
740 let indices: [usize; 2] = [
741 x * self.size + y,
742 y * self.size + x
743 ];
744 for index in indices.into_iter() {
745 match body.get_mut(*index) {
746 Some(cell) => {
747 cell.module_type = CellType::VersionInformation;
748 cell.color = Color { r: 200, g: 200, b: 123 };
749 },
750 None => {}
751 }
752
753 }
754
755 if y < 5 {
756 y += 1;
757 } else {
758 y = 0;
759 x += 1;
760 }
761 blocks -= 1;
762 }
763 }
764
765 pub fn apply_reserve_format_areas(&self, body: &mut Vec<Cell>) {
766 let mut vertical: Point<usize> = Point(0, 8);
767 let mut horizontal: Point<usize> = Point(8, 0);
768
769 while horizontal.1 < self.size {
770 let idx = (horizontal.0 * self.size) + horizontal.1;
771 match body.get_mut(idx) {
772 Some(cell) => {
773 cell.module_type = CellType::Format;
774 cell.color = Color { r: 10, g: 140, b: 230 };
775 },
776 None => {}
777 }
778
779 if horizontal.1 > 7 && horizontal.1 < self.size - 8 {
780 horizontal = Point(8, self.size - 8);
781 } else {
782 horizontal = Point(8, horizontal.1 + 1);
783 }
784 }
785
786 while vertical.0 < self.size {
787 let idx = (vertical.0 * self.size) + vertical.1;
788 match body.get_mut(idx) {
789 Some(cell) => {
790 cell.module_type = CellType::Format;
791 cell.color = Color { r: 10, g: 140, b: 230 };
792 },
793 None => {}
794 }
795
796 if vertical.0 > 7 && vertical.0 < self.size - 8 {
797 vertical = Point(self.size - 8, 8);
798 } else {
799 vertical = Point(vertical.0 + 1, 8);
800 }
801 }
802
803 }
804
805 pub fn apply_dark_module(&self, body: &mut Vec<Cell>) {
806 let dark_module_coord: Point<usize> = Point((4 * self.version) + 9, 8);
807 let idx = (dark_module_coord.0 * self.size) + dark_module_coord.1;
808 match body.get_mut(idx) {
809 Some(cell) => {
810 cell.module_type = CellType::DarkModule;
811 cell.color = Color { r: 0, g: 0, b: 0 };
812 },
813 None => {}
814 }
815 }
816
817 pub fn apply_alignment_patterns(&self, body: &mut Vec<Cell>, points: &Vec<PlotPoint>) {
818 for plot_point in points {
819 let idx = (plot_point.point.0 * self.size) + plot_point.point.1;
820 match body.get_mut(idx) {
821 Some(cell) => {
822 cell.module_type = CellType::Alignment;
823 cell.color = plot_point.color
824 },
825 None => {}
826 }
827 }
828 }
829
830 pub fn apply_separators(&self, body: &mut Vec<Cell>, alignment_point: (usize, usize)) {
831 let row_len = self.size;
832 let (mut x, mut y) = alignment_point;
833 let mut start_x = 0;
837 let mut start_y = 0;
838 let mut end_x = 0;
839 let mut end_y = 0;
840 if x == y {
841 start_x = 7;
843 end_y = 7;
844 } else if x > y {
845 start_x = row_len - 8;
847 end_x = row_len;
848 end_y = 7;
849 } else {
850 start_y = row_len - 8;
852 end_y = row_len;
853 end_x = 7;
854 }
855 x = start_x;
856 y = start_y;
857 loop {
858 let pt: Point<usize> = Point(x, y);
859 let idx = (pt.0 * self.size) + pt.1;
860 match body.get_mut(idx) {
861 Some(c) => {
862 c.module_type = CellType::Separator;
863 c.color = Color { r: 255, g: 255, b: 255 };
864 },
865 None => panic!("dunno idx {} x: {} y: {}", idx, x, y)
866 }
867
868 if start_x == end_y && y < end_y {
869 y += 1;
870 } else if end_y == y && x > end_x {
871 x -= 1;
872 } else if end_x > x && start_y > x {
873 x += 1;
874 } else if end_x == x && end_y - 1 > y {
875 y += 1;
876 } else if end_y > y && start_x > y {
877 y += 1;
878 } else if (end_x > 0 && end_x - 1 > x) && end_y == y {
879 x += 1;
880 } else {
881 break;
882 }
883 }
884 }
885
886 pub fn apply_finder_patterns(&self, body: &mut Vec<Cell>, alignment_point: Point<usize>) {
887 for plot_point in self.plot_spiral(&alignment_point, 6, 0) {
888 let idx = (plot_point.point.0 * self.size) + plot_point.point.1;
889 match body.get_mut(idx) {
890 Some(cell) => {
891 cell.module_type = CellType::Finder;
892 cell.color = plot_point.color
893 },
894 None => {}
895 }
896 }
897 }
898
899 pub fn apply_timer_patterns(&self, body: &mut Vec<Cell>) {
900 let (mut x, mut y) = (6, self.size - 8);
901 loop {
902 if x >= self.size - 7 {
903 break;
904 }
905 let pt: Point<usize> = Point(x, y);
906 let idx = (pt.0 * self.size) + pt.1;
907 match body.get_mut(idx) {
908 Some(cell) => {
909 match cell.module_type {
910 CellType::None | CellType::Format => {
911 let direction = if y > x {
912 y
913 } else {
914 x
915 };
916 cell.module_type = CellType::Timing;
917 if direction % 2 == 0 {
918 cell.color = Color { r: 0, g: 0, b: 0 };
919 }
920 },
921 _ => {}
922 }
923 },
924 None => {}
925 }
926 if y > x {
927 y -= 1;
928 } else if y == 7 {
929 y = 6;
930 x = 8;
931 } else {
932 x += 1;
933 }
934 }
935 }
936
937 pub fn get_alignment_points(&self, body: &Vec<Cell>) -> Vec<PlotPoint> {
938 let mut pts: Vec<usize> = vec![6];
939 let mut n = 6;
940 let version_bracket = match self.version {
942 1 => 0,
943 2...6 => 1,
944 7...13 => 2,
945 14...21 => 3,
946 22...28 => 4,
947 29...36 => 5,
948 37...41 => 6,
949 _ => 0
950 };
951
952
953
954 let modifier = if version_bracket == 1 {
955 self.size - 13
956 } else {
957 (self.size - 12) / version_bracket
958 };
959
960 for _ in 0..version_bracket {
961 n += modifier;
962 pts.push(n);
963 }
964
965 let pts: Vec<PlotPoint> = self.get_point_combinations(pts)
966 .into_iter()
967 .filter(|pt| {
968 let idx = (pt.0 * self.size) + pt.1;
969 let cell_ref = body.get(idx);
970 if cell_ref.is_none() {
971 return false
972 }
973
974 let cell = cell_ref.unwrap();
975 let result = match cell.module_type {
976 CellType::None => true,
977 _ => false
978 };
979
980 result
981 })
982 .flat_map(|pt| {
983 self.plot_spiral(&pt, 4, 2)
984 })
985 .collect();
986
987 pts
988 }
989
990 pub fn get_point_combinations(&self, numbers: Vec<usize>) -> Vec<Point<usize>> {
991 let mut pairs: Vec<Point<usize>> = vec![]; let xnumbers: Vec<usize> = numbers.iter().cloned().collect();
993 for n in numbers {
994 for xn in xnumbers.iter() { pairs.push(Point(n, *xn));
996 }
997 }
998 pairs
999 }
1000
1001 pub fn plot_spiral(&self, origin_pt: &Point<usize>, size: usize, diff: usize) -> Vec<PlotPoint> {
1002 let mut plot_points: Vec<PlotPoint> = vec![];
1003 let mut max = size;
1004 let mut depth = 0;
1005 let (mut x, mut y) = (origin_pt.0 - diff, origin_pt.1 - diff);
1006 while max > 1 {
1007 let mut cell_steps = max * 4;
1008 let color = match depth % 2 {
1009 0 => Color { r: 0, g: 0, b: 0 },
1010 _ => Color { r: 255, g: 255, b: 255 },
1011 };
1012 while cell_steps > 0 {
1013 let plot_point = PlotPoint { point: Point(x, y), color: color };
1014 plot_points.push(plot_point);
1015 if cell_steps > 3 * max {
1016 y += 1;
1017 } else if cell_steps > 2 * max {
1018 x += 1;
1019 } else if cell_steps > max {
1020 y -= 1;
1021 } else {
1022 x -= 1;
1023 }
1024
1025 cell_steps -= 1;
1026
1027 }
1028 depth += 1;
1029 max -= 2;
1030 x += 1;
1031 y += 1;
1032 }
1033 plot_points.push(PlotPoint { point: Point(x, y), color: Color { r: 0, g: 0, b: 0 } });
1035 plot_points
1036 }
1037}