qr_encode/qr_encoder/
config.rs

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, // for now - should be its own sub-type.
39    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
127// NOTE FOR MATT FOR TOMORROW ABOUT ISSUE WITH VERSIONS 4, 5 and 6 NOT WORKING -> CHECK THE ERROR ENCODING PROCESS FOR GROUPS THE ISSUE MIGHT BE THERE!
128
129fn 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        // codewords
183        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        // panic!("VERSION BINARY {:018b}", bit_string);
260
261        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                // new row, so reset again
473                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                // tally up and reset
487                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                // tally up and reset
507                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        // total modules
530        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        // TODO!
562        // let content_length = self.get_content_length();
563        // println!("{:?} CL: {}", self.codeword_properties, content_length);
564        // let data_length = self.data.len();
565
566        // if data_length + 2 > self.codeword_properties.ecc_codeword_count {
567        //     // data content is too large for the version size, so change the version to match.
568        //     // TODO
569        // } else if data_length + 2 < self.codeword_properties.ecc_codeword_count {
570        //     // TODO: if someone wants to use version 20 when the data is only 4 bytes...
571
572        // }
573    }
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        // for (idx, byte) in codewords.iter().enumerate() {
581        //     if let Some(data_byte) = data.get(idx + 2) {
582        //         println!("{:b} original", 112 << 4);
583        //     }
584        //     println!("{:b} byte #: {} ", idx, byte);
585        // }
586    }
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            /*
646                what am I doing...
647
648                1. if there's a 16 bit integer, it needs to be broken up|
649                2. the first half of the 16 bit integer is used first
650                3. cast it to an 8 bit integer
651                4. bitwise operation normally with the mode byte
652                
653            */
654
655            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        // pad the end of the message codewords, alternating between 17 and 236, until it fills the allotted amount for the version
672
673
674        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        // this can be refactored so it just iterates going from 0 to max-index
699        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        // x == y Upper left
834        // x < y Upper Right
835        // x > y Lower Left
836        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            // upper left
842            start_x = 7;
843            end_y = 7;
844        } else if x > y {
845            // lower left
846            start_x = row_len - 8;
847            end_x = row_len;
848            end_y = 7;
849        } else {
850            // upper right
851            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 last_column = self.size - 7;
941        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![]; //numbers.iter().map(|n| (*n, *n)).collect();
992        let xnumbers: Vec<usize> = numbers.iter().cloned().collect();
993        for n in numbers {
994            for xn in xnumbers.iter() { // can I use the same vec inside its iteration?
995                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        // center cell
1034        plot_points.push(PlotPoint { point: Point(x, y), color: Color { r: 0, g: 0, b: 0 } });
1035        plot_points
1036    }
1037}