pen.rs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352
  1. use std::path::PathBuf;
  2. use ezcad::{
  3. pen::Pen,
  4. types::{PulseWidth, Rgba},
  5. };
  6. use log::debug;
  7. use serde::{Deserialize, Serialize};
  8. use strum::IntoEnumIterator;
  9. const SPEED_MIN: f64 = 0.0;
  10. const SPEED_MAX: f64 = 100000.0;
  11. const POWER_MIN: f64 = 0.0;
  12. const POWER_MAX: f64 = 100.0;
  13. const FREQUENCY_MIN: u32 = 20_000;
  14. const FREQUENCY_MAX: u32 = 4_000_000;
  15. #[derive(Debug, Serialize, Deserialize)]
  16. #[serde(rename_all = "PascalCase")]
  17. pub struct Patch {
  18. color: Option<(u8, u8, u8)>,
  19. enabled: Option<bool>,
  20. loop_count: Option<u32>,
  21. speed: Option<f64>,
  22. power: Option<f64>,
  23. frequency: Option<u32>,
  24. pulse_width: Option<PulseWidth>,
  25. }
  26. impl Patch {
  27. fn patch(&self, pen: &mut Pen) {
  28. self.color.map(|color| {
  29. debug!("Patching pen color to {:?}", color);
  30. *pen.color = color.into()
  31. });
  32. self.enabled.map(|enabled| {
  33. debug!("Patching pen enablement to {}", enabled);
  34. *pen.disabled = !enabled as u32;
  35. });
  36. self.loop_count.map(|loop_count| {
  37. debug!("Patching pen loop count to {}", loop_count);
  38. assert!(loop_count > 0, "Pen loop count must be greater than zero");
  39. *pen.loop_count = loop_count;
  40. });
  41. self.speed.map(|speed| {
  42. debug!("Patching pen speed to {}", speed);
  43. assert!(
  44. speed > SPEED_MIN && speed <= SPEED_MAX,
  45. "Pen speed must be between {} and {}",
  46. SPEED_MIN,
  47. SPEED_MAX
  48. );
  49. *pen.speed = speed;
  50. });
  51. self.power.map(|power| {
  52. debug!("Patching pen power to {}", power);
  53. assert!(
  54. power > POWER_MIN && power <= POWER_MAX,
  55. "Pen power must be between {} and {}",
  56. POWER_MIN,
  57. POWER_MAX
  58. );
  59. *pen.power = power;
  60. });
  61. self.frequency.map(|frequency| {
  62. debug!("Patching pen frequency to {}", frequency);
  63. assert!(
  64. frequency >= FREQUENCY_MIN && frequency <= FREQUENCY_MAX,
  65. "Pen frequency must be between {} and {}",
  66. FREQUENCY_MIN,
  67. FREQUENCY_MAX
  68. );
  69. *pen.frequency = frequency;
  70. *pen.frequency_2 = frequency.try_into().unwrap();
  71. });
  72. self.pulse_width.map(|width| {
  73. let width: u32 = width.into();
  74. debug!("Patching pen pulse width to {}ns", width);
  75. *pen.pulse_width = width.into();
  76. *pen.pulse_width_2 = width.try_into().unwrap();
  77. });
  78. // Always enable custom settings for pen
  79. *pen.use_default = 0;
  80. }
  81. }
  82. #[derive(Debug, Serialize, Deserialize)]
  83. #[serde(rename_all = "PascalCase")]
  84. pub struct PatchPen {
  85. pen: usize,
  86. #[serde(flatten)]
  87. patch: Patch,
  88. }
  89. impl PatchPen {
  90. pub fn patch(&self, pens: &mut Vec<Pen>) {
  91. debug!("Patching pen #{}", self.pen);
  92. let pen: &mut Pen = pens.get_mut(self.pen).expect("Invalid pen index");
  93. self.patch.patch(pen);
  94. }
  95. }
  96. #[derive(Debug, Serialize, Deserialize)]
  97. #[serde(rename_all = "PascalCase")]
  98. pub struct ClonePen {
  99. from: usize,
  100. to: usize,
  101. inclusive: Option<bool>,
  102. patch: Option<Patch>,
  103. }
  104. impl ClonePen {
  105. pub fn clone(&self, pens: &mut Vec<Pen>) {
  106. debug!(
  107. "Cloning pen #{} to #{}{}",
  108. self.from,
  109. self.to,
  110. match self.inclusive {
  111. Some(true) => format!(" (inclusive)"),
  112. _ => format!(""),
  113. }
  114. );
  115. // Clone pen
  116. let src: Pen = pens.get(self.from).expect("Invalid pen index").clone();
  117. match self.inclusive {
  118. Some(true) => {
  119. assert!(
  120. self.to > self.from,
  121. "Target pen(s) must be greater than source pen"
  122. );
  123. // Clone pen (randomize color)
  124. for idx in (self.from..=self.to).skip(1) {
  125. let dst: &mut Pen = pens.get_mut(idx).expect("Invalid pen index");
  126. *dst = src.clone();
  127. *dst.color = Rgba::random().into();
  128. // Patch pen if needed
  129. self.patch.as_ref().map(|patch| {
  130. debug!("Patching pen #{}", idx);
  131. patch.patch(dst);
  132. });
  133. }
  134. }
  135. _ => {
  136. let dst: &mut Pen = pens.get_mut(self.to).expect("Invalid pen index");
  137. *dst = src;
  138. // Patch pen if needed
  139. self.patch.as_ref().map(|patch| {
  140. debug!("Patching pen #{}", self.to);
  141. patch.patch(dst);
  142. });
  143. }
  144. }
  145. }
  146. }
  147. #[derive(Debug, Serialize, Deserialize)]
  148. pub enum PatternField {
  149. Loops(i32),
  150. Speed(f64),
  151. Power(f64),
  152. Frequency(i32),
  153. PulseWidth(u32),
  154. }
  155. impl PatternField {
  156. pub fn pattern(&self, pens: &mut dyn Iterator<Item = (usize, &mut Pen)>) {
  157. // Obtain settings from source (first) pen
  158. let (src_idx, src) = pens.next().expect("Pattern must involve at least one pen");
  159. let mut setting: PatternField = match self {
  160. PatternField::Loops(_) => {
  161. debug!(
  162. "Initial loop count from pen #{} is {}",
  163. src_idx, *src.loop_count
  164. );
  165. PatternField::Loops((*src.loop_count).try_into().unwrap())
  166. }
  167. PatternField::Speed(_) => {
  168. debug!("Initial speed from pen #{} is {}", src_idx, *src.speed);
  169. PatternField::Speed(*src.speed)
  170. }
  171. PatternField::Power(_) => {
  172. debug!("Initial power from pen #{} is {}", src_idx, *src.power);
  173. PatternField::Power(*src.power)
  174. }
  175. PatternField::Frequency(_) => {
  176. debug!(
  177. "Initial frequency from pen #{} is {}",
  178. src_idx, *src.frequency
  179. );
  180. PatternField::Frequency((*src.frequency).try_into().unwrap())
  181. }
  182. PatternField::PulseWidth(_) => {
  183. debug!(
  184. "Initial pulse width from pen #{} is {}ns",
  185. src_idx, *src.pulse_width
  186. );
  187. PatternField::PulseWidth(*src.pulse_width)
  188. }
  189. };
  190. for (idx, dst) in pens {
  191. // Calculate new setting
  192. setting = match (setting, self) {
  193. (PatternField::Loops(prev), PatternField::Loops(incr)) => {
  194. let value: i32 = prev + incr;
  195. debug!("Patching loop count for pen #{} to {}", idx, value);
  196. assert!(value > 0, "Pen loop count must be greater than zero");
  197. PatternField::Loops(value)
  198. }
  199. (PatternField::Speed(prev), PatternField::Speed(incr)) => {
  200. let value: f64 = prev + incr;
  201. debug!("Patching speed for pen #{} to {}", idx, value);
  202. assert!(
  203. value > SPEED_MIN && value <= SPEED_MAX,
  204. "Pen speed must be between {} and {}",
  205. SPEED_MIN,
  206. SPEED_MAX
  207. );
  208. PatternField::Speed(value)
  209. }
  210. (PatternField::Power(prev), PatternField::Power(incr)) => {
  211. let value: f64 = prev + incr;
  212. debug!("Patching power for pen #{} to {}", idx, value);
  213. assert!(
  214. value > POWER_MIN && value <= POWER_MAX,
  215. "Pen power must be between {} and {}",
  216. POWER_MIN,
  217. POWER_MAX
  218. );
  219. PatternField::Power(value)
  220. }
  221. (PatternField::Frequency(prev), PatternField::Frequency(incr)) => {
  222. let value: i32 = prev + incr;
  223. debug!("Patching frequency for pen #{} to {}", idx, value);
  224. assert!(
  225. value >= FREQUENCY_MIN.try_into().unwrap()
  226. && value <= FREQUENCY_MAX.try_into().unwrap(),
  227. "Pen frequency must be between {} and {}",
  228. FREQUENCY_MIN,
  229. FREQUENCY_MAX
  230. );
  231. PatternField::Frequency(value)
  232. }
  233. (PatternField::PulseWidth(prev), PatternField::PulseWidth(incr)) => {
  234. let mut pw = PulseWidth::iter();
  235. let _ = pw
  236. .find(|x| u32::from(*x) == prev)
  237. .expect("Unknown pulse width");
  238. let mut pw = pw.skip((*incr - 1).try_into().unwrap());
  239. let next: u32 = pw.next().expect("Pulse width out of bounds").into();
  240. debug!("Patching pulse width for pen #{} to {}ns", idx, next);
  241. PatternField::PulseWidth(next)
  242. }
  243. _ => unreachable!(),
  244. };
  245. // Patch updated value
  246. match setting {
  247. PatternField::Loops(x) => *dst.loop_count = x.try_into().unwrap(),
  248. PatternField::Speed(x) => *dst.speed = x,
  249. PatternField::Power(x) => *dst.power = x,
  250. PatternField::Frequency(x) => {
  251. *dst.frequency = x.try_into().unwrap();
  252. *dst.frequency_2 = x.try_into().unwrap();
  253. }
  254. PatternField::PulseWidth(x) => {
  255. *dst.pulse_width = x;
  256. *dst.pulse_width_2 = x.try_into().unwrap();
  257. }
  258. }
  259. // Randomize pen color
  260. *dst.color = Rgba::random().into();
  261. // Always enable custom settings for pen
  262. *dst.use_default = 0;
  263. }
  264. }
  265. }
  266. #[derive(Debug, Serialize, Deserialize)]
  267. #[serde(rename_all = "PascalCase")]
  268. pub struct PatternPen {
  269. index: usize,
  270. count: usize,
  271. field: PatternField,
  272. }
  273. impl PatternPen {
  274. pub fn pattern(&self, pens: &mut Vec<Pen>) {
  275. debug!(
  276. "Patterning from pen #{} to #{}",
  277. self.index,
  278. self.index + self.count - 1
  279. );
  280. self.field.pattern(
  281. &mut pens
  282. .iter_mut()
  283. .enumerate()
  284. .skip(self.index)
  285. .take(self.count),
  286. )
  287. }
  288. }
  289. #[derive(Debug, Serialize, Deserialize)]
  290. #[serde(rename_all = "PascalCase")]
  291. pub struct ImportExportPen {
  292. index: usize,
  293. path: PathBuf,
  294. }
  295. impl ImportExportPen {
  296. pub fn export(&self, pens: &mut Vec<Pen>) {
  297. debug!(
  298. "Exporting pen #{} to '{}'",
  299. self.index,
  300. self.path.to_string_lossy()
  301. );
  302. let pen = pens.get(self.index).expect("Invalid pen index");
  303. pen.write_to_file(&self.path);
  304. }
  305. pub fn import(&self, pens: &mut Vec<Pen>) {
  306. debug!(
  307. "Importing pen #{} from '{}'",
  308. self.index,
  309. self.path.to_string_lossy()
  310. );
  311. let pen: Pen = Pen::read_from_file(&self.path);
  312. let dst: &mut Pen = pens.get_mut(self.index).expect("Invalid pen index");
  313. *dst = pen;
  314. }
  315. }