1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
use crate::Design;
use std::io::Write;

impl<StrandLabel, DomainLabel> Design<StrandLabel, DomainLabel> {
    /// Output a design in Cadnano format.
    pub fn to_cadnano<W: Write>(&self, w: W) -> Result<(), failure::Error> {
        let mut vstrands = Vec::new();

        let mut max_x = 0;
        let mut min_x = 0;
        let mut max_y = 0;
        for s in self.strands.iter() {
            for dom in s.domains.iter() {
                if dom.helix < 0 {
                    continue;
                }
                max_x = max_x.max(dom.start).max(dom.end - 1);
                min_x = min_x.min(dom.start).min(dom.end - 1);
                max_y = max_y.max(dom.helix as usize);
            }
        }

        max_x -= min_x;
        let max_x = ((1 + max_x / 32) * 32) as usize;

        let mut odd_num = 1;
        let mut even_num = 0;
        let mut helices = Vec::new();
        for (i, _h) in self.helices.iter().enumerate().take(max_y + 1) {
            let num;
            if i % 2 == 0 {
                num = odd_num;
                odd_num += 2;
            } else {
                num = even_num;
                even_num += 2;
            };
            helices.push(num);
            vstrands.push(cadnano_format::VStrand {
                col: 1,
                loop_: vec![0; max_x],
                num: num as isize,
                row: (max_y - i) as isize,
                scaf: vec![(-1, -1, -1, -1); max_x],
                scaf_loop: vec![0; max_x],
                skip: vec![0; max_x],
                stap: vec![(-1, -1, -1, -1); max_x],
                stap_loop: vec![0; max_x],
                stap_colors: vec![],
            })
        }

        for s in self.strands.iter() {
            let mut prev: Option<(usize, usize)> = None;
            for (ndom, dom) in s.domains.iter().enumerate() {
                let x_range = if dom.end < dom.start {
                    (dom.end + 1)..(dom.start + 1)
                } else {
                    dom.start..dom.end
                };
                for x_ in x_range {
                    let is_scaf = (dom.helix % 2 == 0) ^ (dom.end < dom.start);
                    let x = (x_ - min_x) as usize;

                    let mut result: (isize, isize, isize, isize) = (-1, -1, -1, -1);

                    if let Some((ref prev_helix, ref prev_x)) = prev {
                        result.0 = helices[*prev_helix] as isize;
                        result.1 = *prev_x as isize;
                    }
                    if x_ < dom.end - 1 {
                        result.2 = dom.helix as isize;
                        result.3 = (x + 1) as isize;
                    } else if ndom + 1 < s.domains.len() {
                        result.2 = s.domains[ndom + 1].helix as isize;
                        result.3 = s.domains[ndom + 1].start - min_x;
                    }
                    prev = Some((dom.helix as usize, x));
                    // if is_scaf {
                    std::mem::swap(&mut result.0, &mut result.2);
                    std::mem::swap(&mut result.1, &mut result.3);
                    // }

                    if is_scaf {
                        vstrands[dom.helix as usize].scaf[x] = result;
                    } else {
                        vstrands[dom.helix as usize].stap[x] = result;
                    }
                }
            }
        }

        for st in self.strands.iter() {
            if !st.domains.is_empty() {
                let ref dom = st.domains[0];
                let is_scaf = (dom.helix % 2 == 0) ^ (dom.end <= dom.start);
                if !is_scaf {
                    let color = st.color.unwrap_or_else(|| st.default_color());
                    vstrands[dom.helix as usize]
                        .stap_colors
                        .push((dom.start - min_x, color as isize));
                }
            }
        }

        let nano = cadnano_format::Cadnano {
            name: "name".to_string(),
            vstrands,
        };

        Ok(serde_json::to_writer(w, &nano).unwrap())
    }
}