object.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374
  1. use std::path::PathBuf;
  2. use ezcad::{
  3. array_of::ArrayOf,
  4. layer::Layer,
  5. objects::{
  6. circle::Circle,
  7. hatch::{Hatch, HatchFlag, HatchPattern, HatchSetting, Hatches},
  8. rectangle::Rectangle,
  9. Object, ObjectCore, Translate,
  10. },
  11. pen::Pen,
  12. types::{Coordinate, ObjectType},
  13. };
  14. use log::{debug, error, warn};
  15. use rand::{seq::SliceRandom, thread_rng};
  16. use serde::{Deserialize, Serialize};
  17. use super::pen::PatternField;
  18. #[derive(Debug, Serialize, Deserialize)]
  19. #[serde(rename_all = "PascalCase")]
  20. pub struct DeleteObjects {
  21. layer: usize,
  22. object: Option<usize>,
  23. }
  24. impl DeleteObjects {
  25. pub fn delete(&self, layers: &mut ArrayOf<Layer>) {
  26. debug!(
  27. "Deleting layer #{} {}",
  28. match &self.object {
  29. Some(object) => format!("object #{}", object),
  30. None => format!("all objects"),
  31. },
  32. self.layer,
  33. );
  34. let layer: &mut Layer = layers.get_mut(self.layer).expect("Invalid layer index");
  35. match self.object {
  36. Some(index) => {
  37. assert!(index < layer.objects.len(), "Invalid object index");
  38. layer.objects.remove(index);
  39. }
  40. None => layer.objects.clear(),
  41. }
  42. }
  43. }
  44. #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
  45. #[serde(rename_all = "PascalCase")]
  46. pub struct HatchConfig {
  47. line_spacing: f64,
  48. pen: Option<u32>,
  49. count: Option<u32>,
  50. edge_offset: Option<f64>,
  51. start_offset: Option<f64>,
  52. end_offset: Option<f64>,
  53. angle: Option<f64>,
  54. rotate_angle: Option<f64>,
  55. line_reduction: Option<f64>,
  56. loop_distance: Option<f64>,
  57. loop_count: Option<u32>,
  58. pattern: Option<HatchPattern>,
  59. follow_edge_once: Option<bool>,
  60. cross_hatch: Option<bool>,
  61. }
  62. impl From<HatchConfig> for HatchSetting {
  63. fn from(value: HatchConfig) -> Self {
  64. let mut flags: HatchFlag = match value.pattern {
  65. Some(pattern) => pattern.into(),
  66. None => HatchPattern::Directional.into(),
  67. };
  68. value
  69. .follow_edge_once
  70. .map(|x| flags.set_follow_edge_once(x.into()));
  71. value.cross_hatch.map(|x| flags.set_cross_hatch(x.into()));
  72. if value.start_offset.is_none() && value.end_offset.is_none() {
  73. flags.set_average_distribute_line(1);
  74. }
  75. let mut ret = Self::default();
  76. *ret.line_spacing = value.line_spacing;
  77. value.pen.map(|x| *ret.pen = x.into());
  78. value.count.map(|x| *ret.count = x.into());
  79. value.edge_offset.map(|x| *ret.edge_offset = x.into());
  80. value.start_offset.map(|x| *ret.start_offset = x.into());
  81. value.end_offset.map(|x| *ret.end_offset = x.into());
  82. value.angle.map(|x| *ret.angle = x.into());
  83. value.rotate_angle.map(|x| *ret.rotate_angle = x.into());
  84. value.line_reduction.map(|x| *ret.line_reduction = x.into());
  85. value.loop_distance.map(|x| *ret.loop_distance = x.into());
  86. value.loop_count.map(|x| *ret.loop_count = x.into());
  87. *ret.flags = flags;
  88. *ret.enabled = true.into();
  89. ret
  90. }
  91. }
  92. #[derive(Debug, Serialize, Deserialize)]
  93. #[serde(rename_all = "PascalCase")]
  94. pub struct ArrayConfig {
  95. columns: usize,
  96. rows: usize,
  97. spacing: f64,
  98. randomize_order: bool,
  99. starting_pen: usize,
  100. pattern_x: Option<PatternField>,
  101. pattern_y: Option<PatternField>,
  102. }
  103. #[derive(Debug, Serialize, Deserialize, strum::Display)]
  104. #[serde(rename_all = "PascalCase")]
  105. pub enum InputObject {
  106. #[serde(rename_all = "PascalCase")]
  107. Rectangle {
  108. width: f64,
  109. height: f64,
  110. round_corner: Option<f64>,
  111. },
  112. #[serde(rename_all = "PascalCase")]
  113. Circle { radius: f64 },
  114. #[serde(rename_all = "PascalCase")]
  115. Import { path: PathBuf },
  116. #[serde(rename_all = "PascalCase")]
  117. Existing { layer: usize, object: usize },
  118. }
  119. impl InputObject {
  120. fn new(&self, layers: &ArrayOf<Layer>) -> Object {
  121. match self {
  122. InputObject::Rectangle {
  123. width,
  124. height,
  125. round_corner,
  126. } => Object::Rectangle(Rectangle {
  127. drawn_corner_a: Coordinate::from((-width / 2.0, -height / 2.0)).into(),
  128. drawn_corner_b: Coordinate::from((width / 2.0, height / 2.0)).into(),
  129. round_bottom_left: round_corner.unwrap_or(0.0).into(),
  130. round_bottom_right: round_corner.unwrap_or(0.0).into(),
  131. round_top_left: round_corner.unwrap_or(0.0).into(),
  132. round_top_right: round_corner.unwrap_or(0.0).into(),
  133. ..Default::default()
  134. }),
  135. InputObject::Circle { radius } => Object::Circle(Circle {
  136. radius: (*radius).into(),
  137. ..Default::default()
  138. }),
  139. InputObject::Import { path } => Object::read_from_file(path),
  140. InputObject::Existing { layer, object } => {
  141. let layer: &Layer = layers.get(*layer).expect("Invalid layer index");
  142. layer
  143. .objects
  144. .get(*object)
  145. .expect("Invalid object index")
  146. .clone()
  147. }
  148. }
  149. }
  150. }
  151. #[derive(Debug, Serialize, Deserialize)]
  152. #[serde(rename_all = "PascalCase")]
  153. pub struct ObjectOperation {
  154. input: InputObject,
  155. z: Option<f64>,
  156. origin: Option<Coordinate>,
  157. pen: Option<u32>,
  158. layer: Option<usize>,
  159. array: Option<ArrayConfig>,
  160. hatch: Option<HatchConfig>,
  161. export: Option<PathBuf>,
  162. replace_object: Option<usize>,
  163. }
  164. impl ObjectOperation {
  165. pub fn process(&self, pens: &mut Vec<Pen>, layers: &mut ArrayOf<Layer>) {
  166. debug!("Begin processing of object {:?}", self.input);
  167. let mut object: Object = self.input.new(layers);
  168. // Process basic transformation
  169. if self.origin.is_some() || self.z.is_some() {
  170. debug!(
  171. "Translating object to origin {:?} and Z {:?}",
  172. self.origin, self.z
  173. );
  174. object.move_absolute(self.origin, self.z);
  175. }
  176. self.pen.map(|pen| {
  177. if self.array.is_some() {
  178. warn!("Ignoring pen setting as values will be overridden by array setting");
  179. } else {
  180. assert!(pen < pens.len().try_into().unwrap(), "Invalid pen index");
  181. debug!("Setting object pen to #{}", pen);
  182. object.set_pen(pen);
  183. }
  184. });
  185. // Process conversion to hatch object
  186. let object = self.hatch.as_ref().map_or(object.clone(), |hatch| {
  187. if hatch.pen.is_some() && self.array.is_some() {
  188. warn!("Ignoring hatch pen setting as values will be overridden by array setting");
  189. }
  190. let hatch_setting: HatchSetting = (*hatch).into();
  191. match object {
  192. Object::Curve(_) | Object::Point(_) => {
  193. error!("Points, lines, and curves cannot be hatched");
  194. object
  195. }
  196. Object::Rectangle(_)
  197. | Object::Circle(_)
  198. | Object::Ellipse(_)
  199. | Object::Polygon(_) => {
  200. debug!("Converting to hatch object");
  201. // Build new hatch object (no hatch lines)
  202. Object::Hatch(Hatch {
  203. core: ObjectCore {
  204. origin: object.core().origin,
  205. z: object.core().z,
  206. ..ObjectCore::default(ObjectType::Hatch)
  207. },
  208. outline: vec![object].into(),
  209. legacy_setting: vec![hatch_setting.clone()].into(),
  210. _unknown_1: vec![0; 960].into(),
  211. hatch_settings: vec![hatch_setting.clone()].into(),
  212. hatches: Some(Hatches {
  213. core: ObjectCore::default(ObjectType::HatchLine),
  214. hatch_lines: vec![].into(),
  215. }),
  216. })
  217. }
  218. Object::Hatch(hatch) => {
  219. debug!("Modifying existing hatch settings");
  220. // Modify existing hatch (delete existing hatch lines)
  221. Object::Hatch(Hatch {
  222. legacy_setting: vec![hatch_setting.clone()].into(),
  223. hatch_settings: vec![hatch_setting.clone()].into(),
  224. hatches: Some(Hatches {
  225. core: ObjectCore::default(ObjectType::HatchLine),
  226. hatch_lines: vec![].into(),
  227. }),
  228. ..hatch
  229. })
  230. }
  231. }
  232. });
  233. // Process array generation of object
  234. let new_objects = self.array.as_ref().map_or_else(
  235. || vec![object.clone()],
  236. |array| {
  237. let mut new_obj: Vec<Object> = vec![];
  238. let bottom_left: Coordinate = Coordinate {
  239. x: (array.columns - 1) as f64 * array.spacing / -2.0,
  240. y: (array.rows - 1) as f64 * array.spacing / -2.0,
  241. };
  242. // Generate objects
  243. for y in 0..array.rows {
  244. for x in 0..array.columns {
  245. let delta: Coordinate = bottom_left
  246. + Coordinate {
  247. x: array.spacing * x as f64,
  248. y: array.spacing * y as f64,
  249. };
  250. let pen: usize = array.starting_pen + y * array.columns + x;
  251. let mut object: Object = object.clone();
  252. object.move_relative(Some(delta), None);
  253. object.set_pen(pen.try_into().unwrap());
  254. debug!(
  255. "Adding new object at {} with pen #{}",
  256. object.core().origin,
  257. pen
  258. );
  259. new_obj.push(object);
  260. }
  261. }
  262. // Generate pens
  263. match &array.pattern_y {
  264. None => {
  265. if let Some(pattern_x) = &array.pattern_x {
  266. pattern_x.pattern(
  267. &mut pens
  268. .iter_mut()
  269. .enumerate()
  270. .skip(array.starting_pen)
  271. .take(array.columns * array.rows),
  272. );
  273. }
  274. }
  275. Some(pattern_y) => {
  276. for x in 0..array.columns {
  277. pattern_y.pattern(
  278. &mut pens
  279. .iter_mut()
  280. .enumerate()
  281. .skip(x + array.starting_pen)
  282. .step_by(array.columns)
  283. .take(array.rows),
  284. );
  285. }
  286. if let Some(pattern_x) = &array.pattern_x {
  287. for y in 0..array.rows {
  288. pattern_x.pattern(
  289. &mut pens
  290. .iter_mut()
  291. .enumerate()
  292. .skip(array.starting_pen)
  293. .skip(y * array.columns)
  294. .take(array.columns),
  295. )
  296. }
  297. }
  298. }
  299. }
  300. if array.randomize_order {
  301. debug!("Randomizing draw order of array objects");
  302. new_obj.shuffle(&mut thread_rng());
  303. }
  304. new_obj
  305. },
  306. );
  307. let layer_id: usize = self.layer.unwrap_or(0);
  308. let layer: &mut Layer = layers.get_mut(layer_id).expect("Invalid layer index");
  309. // Either export the object, replace an existing object, or append if neither
  310. if let Some(path) = &self.export {
  311. if new_objects.len() > 1 {
  312. warn!(
  313. "Exporting only object #0 from layer #{} in list of objects",
  314. layer_id
  315. );
  316. } else {
  317. debug!(
  318. "Exporting object {} in layer #{} to '{}'",
  319. new_objects[0],
  320. layer_id,
  321. path.to_string_lossy()
  322. );
  323. }
  324. new_objects[0].write_to_file(path);
  325. } else if let Some(object) = self.replace_object {
  326. assert!(object < layer.objects.len(), "Invalid object index");
  327. debug!(
  328. "Replacing object #{} in layer #{} with new objects",
  329. object, layer_id
  330. );
  331. layer.objects.splice(object..=object, new_objects);
  332. } else {
  333. debug!("Extending layer #{} with new objects", layer_id);
  334. layer.objects.extend(new_objects);
  335. }
  336. }
  337. }