1extern crate palette;
3extern crate serde;
4extern crate serde_json;
5#[macro_use]
6extern crate serde_derive;
7
8use palette::{Hsl, Srgb};
9use std::collections::HashMap;
10use std::collections::HashSet;
11mod cadnano;
12pub use cadnano::*;
13
14#[derive(Debug)]
15pub enum Error {
16 IO(std::io::Error),
17 Json(serde_json::Error),
18}
19
20impl std::convert::From<std::io::Error> for Error {
21 fn from(e: std::io::Error) -> Self {
22 Error::IO(e)
23 }
24}
25
26impl std::convert::From<serde_json::Error> for Error {
27 fn from(e: serde_json::Error) -> Self {
28 Error::Json(e)
29 }
30}
31
32pub fn color_rgb(y: usize, x: usize) -> Srgb {
33 Hsl::new(((y * 31 + x * 3) % 360) as f32, 1., 0.4).into()
34}
35
36pub fn color(y: usize, x: usize) -> isize {
37 let rgb = color_rgb(y, x);
38 let (r, g, b) = rgb.into_components();
39 let r = (r * 255.).round() as isize;
40 let g = (g * 255.).round() as isize;
41 let b = (b * 255.).round() as isize;
42 (((r << 8) | g) << 8) | b
43}
44
45#[derive(Debug)]
46pub struct Point {
47 pub helix: isize,
48 pub x: isize,
49}
50
51#[derive(Debug)]
52pub struct Strand {
53 pub path: Vec<Point>,
54}
55
56#[derive(Debug)]
57pub struct Strands {
58 pub scaffolds: Vec<Strand>,
59 pub staples: Vec<Strand>,
60 pub edits: Vec<(Point, isize)>,
61}
62
63
64pub enum Lattice {
65 Square,
66 Hexagonal,
67}
68
69impl Cadnano {
70
71 fn follow_scaffold(
72 &self,
73 points: &mut HashSet<(isize, isize)>,
74 nums: &HashMap<isize, usize>,
75 helix0: isize,
76 x0: isize,
77 ) -> Strand {
78 let mut path = Vec::new();
79 let (mut helix, mut x) = (helix0, x0);
80 while helix != -1 {
82 let (a, b, _, _) = self.vstrands[*nums.get(&helix).unwrap() as usize].scaf[x as usize];
83 let n = path.len();
84 if n < 2 {
85 path.push(Point { helix, x });
86 } else {
87 if path[n-1].helix == path[n-2].helix && path[n-1].helix == helix {
88 path.last_mut().unwrap().x = x
89 } else {
90 path.push(Point { helix, x });
91 }
92 }
93 points.remove(&(helix, x));
94 helix = a;
95 x = b;
96 }
97 path.reverse();
98 path.pop();
99 println!("scaffold reversed: {:?}", path);
100 helix = helix0;
101 x = x0;
102 while helix != -1 {
103 let (_, _, c, d) = self.vstrands[*nums.get(&helix).unwrap() as usize].scaf[x as usize];
104 let n = path.len();
105 if n < 2 {
106 path.push(Point { helix, x });
107 } else {
108 if path[n-1].helix == path[n-2].helix && path[n-1].helix == helix {
109 path.last_mut().unwrap().x = x
110 } else {
111 path.push(Point { helix, x });
112 }
113 }
114 points.remove(&(helix, x));
115 helix = c;
116 x = d;
117 }
118 Strand {
119 path
120 }
121 }
122
123 fn follow_staple(
124 &self,
125 points: &mut HashSet<(isize, isize)>,
126 nums: &HashMap<isize, usize>,
127 helix0: isize,
128 x0: isize,
129 ) -> Strand {
130 let mut path = Vec::new();
131 let (mut helix, mut x) = (helix0, x0);
132 while helix != -1 {
134 let (a, b, _, _) = self.vstrands[*nums.get(&helix).unwrap() as usize].stap[x as usize];
135 let n = path.len();
136 if n < 2 {
137 path.push(Point { helix, x });
138 } else {
139 if path[n-1].helix == path[n-2].helix && path[n-1].helix == helix {
140 path.last_mut().unwrap().x = x
141 } else {
142 path.push(Point { helix, x });
143 }
144 }
145 points.remove(&(helix, x));
146 helix = a;
147 x = b;
148 }
149 println!("reversed staple: {:?}", path);
150 path.reverse();
151 path.pop();
152 helix = helix0;
153 x = x0;
154 while helix != -1 {
155 let (_, _, c, d) = self.vstrands[*nums.get(&helix).unwrap() as usize].stap[x as usize];
156 let n = path.len();
157 if n < 2 {
158 path.push(Point { helix, x });
159 } else {
160 if path[n-1].helix == path[n-2].helix && path[n-1].helix == helix {
161 path.last_mut().unwrap().x = x
162 } else {
163 path.push(Point { helix, x });
164 }
165 }
166 points.remove(&(helix, x));
167 helix = c;
168 x = d;
169 }
170 Strand {
171 path
172 }
173 }
174
175 pub fn to_strands(&self) -> Strands {
176 let mut scaf_points = HashSet::new();
177 let mut stap_points = HashSet::new();
178 let mut nums = HashMap::new();
179 for (vs, vstrand) in self.vstrands.iter().enumerate() {
180 nums.insert(vstrand.num, vs);
181 for (x, st) in vstrand.scaf.iter().enumerate() {
182 if *st != (-1, -1, -1, -1) {
183 scaf_points.insert((vstrand.num, x as isize));
184 }
185 }
186 for (x, st) in vstrand.stap.iter().enumerate() {
187 if *st != (-1, -1, -1, -1) {
188 stap_points.insert((vstrand.num, x as isize));
189 }
190 }
191 }
192 let mut scaffolds = Vec::new();
193 loop {
194 let (num, x) = {
195 let mut it = scaf_points.iter();
196 if let Some(&(num, x)) = it.next() {
197 (num, x)
198 } else {
199 break
200 }
201 };
202 scaffolds.push(self.follow_scaffold(&mut scaf_points, &nums, num, x))
203 }
204 let mut staples = Vec::new();
205 loop {
206 let (num, x) = {
207 let mut it = stap_points.iter();
208 if let Some(&(num, x)) = it.next() {
209 (num, x)
210 } else {
211 break
212 }
213 };
214 staples.push(self.follow_staple(&mut stap_points, &nums, num, x))
215 }
216 let mut edits = Vec::new();
217 for (h, vs) in self.vstrands.iter().enumerate() {
218 for &x in vs.skip.iter().chain(vs.loop_.iter()) {
219 if x != 0 {
220 edits.push((
221 Point { helix: h as isize, x: x as isize },
222 x
223 ))
224 }
225 }
226 }
227 Strands {
228 scaffolds,
229 staples,
230 edits,
231 }
232 }
233
234 pub fn from_strands(
235 name: String,
236 lattice: Lattice,
237 scaffolds: &[Strand],
238 staples: &[Strand],
239 edits: &[(Point, isize)],
240 ) -> Cadnano {
241 let ref p0 = scaffolds[0].path[0];
242 let (min_x, max_x, min_y, max_y) = scaffolds
243 .iter().flat_map(|s| s.path.iter())
244 .chain(staples.iter().flat_map(|s| s.path.iter()))
245 .fold(
246 (p0.x, p0.x, p0.helix, p0.helix),
247 |(min_x, max_x, min_y, max_y), p| {
248 (
249 std::cmp::min(min_x, p.x),
250 std::cmp::max(max_x, p.x),
251 std::cmp::min(min_y, p.helix),
252 std::cmp::max(max_y, p.helix),
253 )
254 },
255 );
256 let min_x = min_x;
257 let columns = (max_x - min_x + 1) as usize;
258 let mut vstrands = Vec::new();
259
260 let columns = match lattice {
262 Lattice::Square => {
263 let mut cols = (columns / 32) * 32;
264 while cols % 21 == 0 || cols < columns {
265 cols += 32
266 }
267 cols
268 }
269 Lattice::Hexagonal => {
270 let mut cols = (columns / 21) * 21;
271 while cols % 32 == 0 || cols < columns {
272 cols += 21
273 }
274 cols
275 }
276 };
277 for y in min_y..=max_y {
278 let num = y - min_y;
280 let stap: Vec<(isize, isize, isize, isize)> = vec![(-1, -1, -1, -1); columns];
281 let scaf = stap.clone();
282
283 vstrands.push(VStrand {
284 stap_colors: vec![],
285 num,
286 scaf_loop: vec![],
287 stap,
288 skip: vec![0; columns as usize],
289 scaf,
290 stap_loop: vec![],
291 col: 1,
292 loop_: vec![0; columns as usize],
293 row: num as isize + 1,
294 })
295 }
296
297 for (is_scaffold, path) in
298 scaffolds.iter().map(|x| (true, x))
299 .chain(staples.iter().map(|x| (false, x)))
300 {
301 let (mut x0, mut y0): (isize, isize) = (-1, -1);
302 let it0 = path.path.iter().map(|p| Point {
303 helix: p.helix - min_y,
304 x: p.x - min_x,
305 });
306 let mut it1 = path.path.iter().map(|p| Point {
307 helix: p.helix - min_y,
308 x: p.x - min_x,
309 });
310 it1.next();
311 for (p0, p1) in it0.zip(it1) {
312 if p0.helix == p1.helix {
313 if p0.x < p1.x {
314 for x in p0.x..p1.x {
315 if is_scaffold {
316 vstrands[p0.helix as usize].scaf[x as usize] =
317 (y0, x0, p0.helix, x + 1);
318 } else {
319 vstrands[p0.helix as usize].stap[x as usize] =
320 (y0, x0, p0.helix, x + 1);
321 }
322 y0 = p0.helix;
323 x0 = x;
324 }
325 if is_scaffold {
326 vstrands[p1.helix as usize].scaf[p1.x as usize] = (y0, x0, -1, -1);
327 } else {
328 vstrands[p1.helix as usize].stap[p1.x as usize] = (y0, x0, -1, -1);
329 }
330 } else {
331 for x in ((p1.x + 1)..=p0.x).rev() {
332 if is_scaffold {
333 vstrands[p0.helix as usize].scaf[x as usize] =
334 (y0, x0, p1.helix, x - 1);
335 } else {
336 vstrands[p0.helix as usize].stap[x as usize] =
337 (y0, x0, p1.helix, x - 1);
338 }
339 y0 = p0.helix;
340 x0 = x;
341 }
342 if is_scaffold {
343 vstrands[p1.helix as usize].scaf[p1.x as usize] = (y0, x0, -1, -1);
344 } else {
345 vstrands[p1.helix as usize].stap[p1.x as usize] = (y0, x0, -1, -1);
346 }
347 }
348 } else {
349 if is_scaffold {
351 vstrands[p0.helix as usize].scaf[p0.x as usize] = (y0, x0, p1.helix, p1.x);
352 } else {
353 vstrands[p0.helix as usize].stap[p0.x as usize] = (y0, x0, p1.helix, p1.x);
354 }
355 x0 = p0.x;
356 y0 = p0.helix;
357 }
358 }
359 }
360
361 for &(ref p, ref n) in edits.iter() {
362 println!("{:?}", p);
363 if *n > 0 {
364 vstrands[p.helix as usize].loop_[p.x as usize] = *n
365 } else if *n < 0 {
366 vstrands[p.helix as usize].skip[p.x as usize] = *n
367 }
368 }
369 Cadnano { name, vstrands }
370 }
371}
372
373#[test]
374fn test_cad() {
375 let scaf = vec![Strand {
376 path: vec![
377 Point { x: 0, helix: 0 },
378 Point { x: 20, helix: 0 },
379 Point { x: 20, helix: 1 },
380 Point { x: 0, helix: 1 },
381 ],
382 }];
383 let staples = vec![Strand {
384 path: vec![
385 Point { x: 20, helix: 0 },
386 Point { x: 0, helix: 0 },
387 Point { x: 0, helix: 1 },
388 Point { x: 20, helix: 1 },
389 ],
390 }];
391 let cad = Cadnano::from_strands("blabla".to_string(), Lattice::Square, &scaf, &staples, &[(Point { x: 4, helix: 0 }, 1), (Point { x: 4, helix: 1 }, -1)]);
392 cad.to_file("/tmp/test.json").unwrap();
393 println!("{:?}", cad.to_strands());
394}