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, }