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
114
115
116
117
//! # The main helix object
use std::f64::consts::PI;
/// A Helix struct
#[derive(Debug, Clone)]
pub struct Helix {
/// A Helix has a radius value, which should be positive
pub radius: f64,
/// The helical rise is the distance between subunits along the helix axis (i.e. z axis)
pub rise: f64,
/// The amount of subunits in a full turn of a helix. Can be decimal value.
pub frequency: f64,
/// The size of each subunit
pub unit_size: f64,
/// Translational offset along helix axis (i.e. z)
pub offset: f64,
/// Rotational offset of helix around helix axis (i.e. z)
pub rotation: f64,
/// Handedness (left- or righthanded) of the helix.
pub handedness: Handedness,
}
impl Helix {
/// Create a new Helix
///
/// Directly instantiating is also permitted, as it is more human readable, so may be
/// preferred for example code. When programmatically generating helices, it is best to use
/// the Helix::new() approach as it panics when it encounters invalid values.
/// # Examples
/// ```
/// use helixiser::helix::{Helix, Handedness};
/// let my_helix = Helix::new(0.1, 0.4, 12., 0.1, 5.6, 180., Handedness::Right);
/// let second = my_helix.clone();
/// ```
///
/// # Panics
///
/// The new function will panic if any of radius, rise, frequency, unit_size or offset are
/// smaller than or equal to zero.
pub fn new(radius: f64, rise: f64, frequency: f64, unit_size: f64, offset: f64, rotation: f64, handedness: Handedness) -> Helix {
assert!(radius > 0., "[Helix::new] radius value ({}) was smaller than or equal to zero", radius);
assert!(rise > 0., "[Helix::new] rise value ({}) was smaller than or equal to zero", rise);
assert!(frequency > 0., "[Helix::new] frequency value ({}) was smaller than or equal to zero", frequency);
assert!(unit_size > 0., "[Helix::new] unit size value ({}) was smaller than or equal to zero", unit_size);
assert!(offset >= 0., "[Helix::new] offset value ({}) was smaller than zero", offset);
Helix {
radius,
rise,
frequency,
unit_size,
offset,
rotation,
handedness,
}
}
/// Compute the pitch of the helix. This is the distance between the helix backbone along
/// the helix axis (i.e. z axis) after a full rotation. Does not need to be an integer
/// multiple of the rise. Is computed as `pitch` = `rise` * `frequency`.
///
/// # Examples
/// ```
/// use std::f64::consts::PI;
/// # use crate::helixiser::helix::{ Handedness, Helix };
///
/// let my_helix = Helix::new( 18.9, 0.55, 11.5, 0.1, 0., 0., Handedness::Right );
/// let myPitch = my_helix.pitch();
///
/// assert_eq!(myPitch, 11.5 * 0.55)
/// ```
pub fn pitch(&self) -> f64 {
self.rise * self.frequency
}
/// Convert the helix' rotation to radians insted of the default (degrees)
///
/// # Examples
/// ```
/// use std::f64::consts::PI;
/// # use crate::helixiser::helix::{ Handedness, Helix };
///
/// let my_helix = Helix::new ( 1.0, 0.34, 10., 0.18, 0., 90., Handedness::Right );
/// let rotation = my_helix.rotation_to_rad();
///
/// assert_eq!(rotation, PI/2f64)
/// ```
pub fn rotation_to_rad(&self) -> f64 {
self.rotation * PI / 180.
}
/// Determine the rotational offset between subunits. This is related only to the `frequency`
/// by: rotational offset = 2*Pi / frequency
///
/// # Examples
/// ```
/// use std::f64::consts::PI;
/// # use crate::helixiser::helix::{ Handedness, Helix };
///
/// let my_helix = Helix::new ( 2.0, 0.34, 8., 0.1, 0., 90., Handedness::Right );
/// let angle_per_subunit = my_helix.rad_per_subunit();
///
/// assert_eq!(angle_per_subunit, PI/4f64)
/// ```
pub fn rad_per_subunit(&self) -> f64 { 2f64 * PI / self.frequency }
}
/// An enum to specify the handedness of an object. Can be either left or right handed.
#[derive(Debug, Copy, Clone)]
pub enum Handedness {
Right,
Left,
}