hatch.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366
  1. use std::fmt::Debug;
  2. use crate::{
  3. array_of::ArrayOf,
  4. field_of::FieldOf,
  5. types::{Field, Coordinate, F64, U32},
  6. };
  7. use binrw::{binrw, BinRead, BinWrite};
  8. use diff::Diff;
  9. use modular_bitfield::{
  10. bitfield,
  11. specifiers::{B1, B18},
  12. };
  13. use serde::{Deserialize, Serialize};
  14. use super::{line::Lines, Object, ObjectCore, Translate};
  15. #[bitfield(bits = 32)]
  16. #[derive(BinRead, BinWrite, Copy, Clone, Debug, Default, Diff, PartialEq)]
  17. #[diff(attr(
  18. #[derive(Debug, PartialEq)]
  19. ))]
  20. #[br(map = Self::from_bytes)]
  21. #[bw(map = |&x| Self::into_bytes(x))]
  22. pub struct HatchFlag {
  23. pub all_calc: B1,
  24. pub follow_edge_once: B1,
  25. pub continuous_pattern: B1, // Hatch type 3 when combined with bidirectional_pattern
  26. pub bidirectional_pattern: B1, // Hatch type 1
  27. pub ring_pattern: B1, // Hatch type 2
  28. #[skip]
  29. __: B1,
  30. pub auto_rotate_hatch_angle: B1,
  31. pub average_distribute_line: B1,
  32. #[skip]
  33. __: B1,
  34. pub gong_pattern: B1, // Hatch type 4 when combined with bidirectional_pattern
  35. pub cross_hatch: B1,
  36. pub background_pattern: B1, // Hatch type 5, must set all_calc as well
  37. pub fill_pattern: B1, // Hatch type 6 when combined with continuous_pattern and bidirectional_pattern
  38. pub zigzag_pattern: B1, // Hatch type 7
  39. #[skip]
  40. __: B18,
  41. }
  42. #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
  43. pub enum HatchPattern {
  44. Directional,
  45. Bidirectional,
  46. Ring,
  47. Continuous,
  48. Gong,
  49. Background,
  50. Fill,
  51. Zigzag,
  52. }
  53. impl From<HatchPattern> for HatchFlag {
  54. fn from(value: HatchPattern) -> Self {
  55. let mut ret = Self::new();
  56. match value {
  57. HatchPattern::Directional => (),
  58. HatchPattern::Bidirectional => ret.set_bidirectional_pattern(1),
  59. HatchPattern::Ring => ret.set_ring_pattern(1),
  60. HatchPattern::Continuous => {
  61. ret.set_bidirectional_pattern(1);
  62. ret.set_continuous_pattern(1);
  63. }
  64. HatchPattern::Gong => {
  65. ret.set_bidirectional_pattern(1);
  66. ret.set_gong_pattern(1);
  67. }
  68. HatchPattern::Background => {
  69. ret.set_background_pattern(1);
  70. ret.set_all_calc(1);
  71. }
  72. HatchPattern::Fill => ret.set_fill_pattern(1),
  73. HatchPattern::Zigzag => ret.set_zigzag_pattern(1),
  74. }
  75. ret
  76. }
  77. }
  78. #[cfg_attr(feature = "default-debug", derive(Debug))]
  79. #[derive(BinRead, BinWrite, Clone, Diff, PartialEq)]
  80. #[diff(attr(
  81. #[derive(Debug, PartialEq)]
  82. ))]
  83. #[brw(magic(46u32))] // Number of fields in this struct
  84. pub struct LegacyHatchSetting {
  85. pub mark_contour: U32,
  86. pub hatch_0_enable: U32,
  87. pub hatch_0_pen: U32,
  88. pub hatch_0_flags: FieldOf<HatchFlag>,
  89. pub hatch_0_edge_offset: F64,
  90. pub hatch_0_line_spacing: F64,
  91. pub hatch_0_start_offset: F64,
  92. pub hatch_0_end_offset: F64,
  93. pub hatch_0_angle: F64,
  94. pub hatch_1_enable: U32,
  95. pub hatch_1_pen: U32,
  96. pub hatch_1_flags: FieldOf<HatchFlag>,
  97. pub hatch_1_edge_offset: F64,
  98. pub hatch_1_line_spacing: F64,
  99. pub hatch_1_start_offset: F64,
  100. pub hatch_1_end_offset: F64,
  101. pub hatch_1_angle: F64,
  102. pub any_hatch_enabled: U32,
  103. pub hatch_0_rotate_angle: F64,
  104. pub hatch_1_rotate_angle: F64,
  105. pub hatch_2_enable: U32,
  106. pub hatch_2_pen: U32,
  107. pub hatch_2_flags: FieldOf<HatchFlag>,
  108. pub hatch_2_edge_offset: F64,
  109. pub hatch_2_line_spacing: F64,
  110. pub hatch_2_start_offset: F64,
  111. pub hatch_2_end_offset: F64,
  112. pub hatch_2_angle: F64,
  113. pub hatch_2_rotate_angle: F64,
  114. pub hatch_0_line_reduction: F64,
  115. pub hatch_1_line_reduction: F64,
  116. pub hatch_2_line_reduction: F64,
  117. pub hatch_0_loop_count: U32,
  118. pub hatch_1_loop_count: U32,
  119. pub hatch_2_loop_count: U32,
  120. pub hatch_0_loop_distance: F64,
  121. pub hatch_1_loop_distance: F64,
  122. pub hatch_2_loop_distance: F64,
  123. pub _unknown_1: [Field; 3],
  124. pub contour_priority: U32,
  125. pub hatch_0_count: U32,
  126. pub hatch_1_count: U32,
  127. pub hatch_2_count: U32,
  128. }
  129. // Custom Debug implementation to only print known fields
  130. #[cfg(not(feature = "default-debug"))]
  131. impl Debug for LegacyHatchSetting {
  132. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  133. f.debug_struct("LegacyHatchSetting")
  134. .field("mark_contour", &self.mark_contour)
  135. .field("hatch_0_enable", &self.hatch_0_enable)
  136. .field("hatch_0_pen", &self.hatch_0_pen)
  137. .field("hatch_0_flags", &self.hatch_0_flags)
  138. .field("hatch_0_edge_offset", &self.hatch_0_edge_offset)
  139. .field("hatch_0_line_spacing", &self.hatch_0_line_spacing)
  140. .field("hatch_0_start_offset", &self.hatch_0_start_offset)
  141. .field("hatch_0_end_offset", &self.hatch_0_end_offset)
  142. .field("hatch_0_angle", &self.hatch_0_angle)
  143. .field("hatch_1_enable", &self.hatch_1_enable)
  144. .field("hatch_1_pen", &self.hatch_1_pen)
  145. .field("hatch_1_flags", &self.hatch_1_flags)
  146. .field("hatch_1_edge_offset", &self.hatch_1_edge_offset)
  147. .field("hatch_1_line_spacing", &self.hatch_1_line_spacing)
  148. .field("hatch_1_start_offset", &self.hatch_1_start_offset)
  149. .field("hatch_1_end_offset", &self.hatch_1_end_offset)
  150. .field("hatch_1_angle", &self.hatch_1_angle)
  151. .field("any_hatch_enabled", &self.any_hatch_enabled)
  152. .field("hatch_0_auto_rotate_angle", &self.hatch_0_rotate_angle)
  153. .field("hatch_1_auto_rotate_angle", &self.hatch_1_rotate_angle)
  154. .field("hatch_2_enable", &self.hatch_2_enable)
  155. .field("hatch_2_pen", &self.hatch_2_pen)
  156. .field("hatch_2_flags", &self.hatch_2_flags)
  157. .field("hatch_2_edge_offset", &self.hatch_2_edge_offset)
  158. .field("hatch_2_line_spacing", &self.hatch_2_line_spacing)
  159. .field("hatch_2_start_offset", &self.hatch_2_start_offset)
  160. .field("hatch_2_end_offset", &self.hatch_2_end_offset)
  161. .field("hatch_2_angle", &self.hatch_2_angle)
  162. .field("hatch_2_auto_rotate_angle", &self.hatch_2_rotate_angle)
  163. .field("hatch_0_line_reduction", &self.hatch_0_line_reduction)
  164. .field("hatch_1_line_reduction", &self.hatch_1_line_reduction)
  165. .field("hatch_2_line_reduction", &self.hatch_2_line_reduction)
  166. .field("hatch_0_loop_count", &self.hatch_0_loop_count)
  167. .field("hatch_1_loop_count", &self.hatch_1_loop_count)
  168. .field("hatch_2_loop_count", &self.hatch_2_loop_count)
  169. .field("hatch_0_loop_distance", &self.hatch_0_loop_distance)
  170. .field("hatch_1_loop_distance", &self.hatch_1_loop_distance)
  171. .field("hatch_2_loop_distance", &self.hatch_2_loop_distance)
  172. .field("contour_priority", &self.contour_priority)
  173. .field("hatch_0_count", &self.hatch_0_count)
  174. .field("hatch_1_count", &self.hatch_1_count)
  175. .field("hatch_2_count", &self.hatch_2_count)
  176. .finish()
  177. }
  178. }
  179. #[cfg_attr(feature = "default-debug", derive(Debug))]
  180. #[derive(BinRead, BinWrite, Clone, Diff, PartialEq)]
  181. #[diff(attr(
  182. #[derive(Debug, PartialEq)]
  183. ))]
  184. #[brw(magic(15u32))] // Number of fields in this struct
  185. pub struct HatchSetting {
  186. pub count: U32,
  187. pub enabled: U32,
  188. pub pen: U32,
  189. pub flags: FieldOf<HatchFlag>,
  190. pub edge_offset: F64,
  191. pub line_spacing: F64,
  192. pub start_offset: F64,
  193. pub end_offset: F64,
  194. pub angle: F64,
  195. pub rotate_angle: F64,
  196. pub line_reduction: F64,
  197. pub loop_distance: F64,
  198. pub loop_count: U32,
  199. pub _unknown_1: [Field; 2],
  200. }
  201. // Custom Debug implementation to only print known fields
  202. #[cfg(not(feature = "default-debug"))]
  203. impl Debug for HatchSetting {
  204. fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
  205. f.debug_struct("HatchSettings")
  206. .field("count", &self.count)
  207. .field("enabled", &self.enabled)
  208. .field("pen", &self.pen)
  209. .field("flags", &self.flags)
  210. .field("edge_offset", &self.edge_offset)
  211. .field("line_spacing", &self.line_spacing)
  212. .field("start_offset", &self.start_offset)
  213. .field("end_offset", &self.end_offset)
  214. .field("angle", &self.angle)
  215. .field("auto_rotate_angle", &self.rotate_angle)
  216. .field("line_reduction", &self.line_reduction)
  217. .field("loop_distance", &self.loop_distance)
  218. .field("loop_count", &self.loop_count)
  219. .finish()
  220. }
  221. }
  222. impl Default for HatchSetting {
  223. fn default() -> Self {
  224. Self {
  225. count: 1.into(),
  226. enabled: false.into(),
  227. pen: 0.into(),
  228. flags: HatchFlag::new().into(),
  229. edge_offset: 0.0.into(),
  230. line_spacing: 1.0.into(),
  231. start_offset: 0.0.into(),
  232. end_offset: 0.0.into(),
  233. angle: 0.0.into(),
  234. rotate_angle: 10.0.into(),
  235. line_reduction: 0.0.into(),
  236. loop_distance: 0.5.into(),
  237. loop_count: 0.into(),
  238. _unknown_1: [vec![0, 0, 0, 0, 0, 0, 0, 0].into(), vec![0, 0, 0, 0].into()].into(),
  239. }
  240. }
  241. }
  242. impl From<Vec<HatchSetting>> for LegacyHatchSetting {
  243. fn from(value: Vec<HatchSetting>) -> Self {
  244. LegacyHatchSetting {
  245. mark_contour: false.into(),
  246. hatch_0_enable: value.get(0).map(|x| x.enabled).unwrap_or_default(),
  247. hatch_0_pen: value.get(0).map(|x| x.pen).unwrap_or_default(),
  248. hatch_0_flags: value.get(0).map(|x| x.flags).unwrap_or_default(),
  249. hatch_0_edge_offset: value.get(0).map(|x| x.edge_offset).unwrap_or_default(),
  250. hatch_0_line_spacing: value.get(0).map(|x| x.line_spacing).unwrap_or_default(),
  251. hatch_0_start_offset: value.get(0).map(|x| x.start_offset).unwrap_or_default(),
  252. hatch_0_end_offset: value.get(0).map(|x| x.end_offset).unwrap_or_default(),
  253. hatch_0_angle: value.get(0).map(|x| x.angle).unwrap_or_default(),
  254. hatch_1_enable: value.get(1).map(|x| x.enabled).unwrap_or_default(),
  255. hatch_1_pen: value.get(1).map(|x| x.pen).unwrap_or_default(),
  256. hatch_1_flags: value.get(1).map(|x| x.flags).unwrap_or_default(),
  257. hatch_1_edge_offset: value.get(1).map(|x| x.edge_offset).unwrap_or_default(),
  258. hatch_1_line_spacing: value.get(1).map(|x| x.line_spacing).unwrap_or_default(),
  259. hatch_1_start_offset: value.get(1).map(|x| x.start_offset).unwrap_or_default(),
  260. hatch_1_end_offset: value.get(1).map(|x| x.end_offset).unwrap_or_default(),
  261. hatch_1_angle: value.get(1).map(|x| x.angle).unwrap_or_default(),
  262. any_hatch_enabled: value.iter().any(|x| x.enabled.into()).into(),
  263. hatch_0_rotate_angle: value.get(0).map(|x| x.rotate_angle).unwrap_or_default(),
  264. hatch_1_rotate_angle: value.get(1).map(|x| x.rotate_angle).unwrap_or_default(),
  265. hatch_2_enable: value.get(2).map(|x| x.enabled).unwrap_or_default(),
  266. hatch_2_pen: value.get(2).map(|x| x.pen).unwrap_or_default(),
  267. hatch_2_flags: value.get(2).map(|x| x.flags).unwrap_or_default(),
  268. hatch_2_edge_offset: value.get(2).map(|x| x.edge_offset).unwrap_or_default(),
  269. hatch_2_line_spacing: value.get(2).map(|x| x.line_spacing).unwrap_or_default(),
  270. hatch_2_start_offset: value.get(2).map(|x| x.start_offset).unwrap_or_default(),
  271. hatch_2_end_offset: value.get(2).map(|x| x.end_offset).unwrap_or_default(),
  272. hatch_2_angle: value.get(2).map(|x| x.angle).unwrap_or_default(),
  273. hatch_2_rotate_angle: value.get(2).map(|x| x.rotate_angle).unwrap_or_default(),
  274. hatch_0_line_reduction: value.get(0).map(|x| x.line_reduction).unwrap_or_default(),
  275. hatch_1_line_reduction: value.get(1).map(|x| x.line_reduction).unwrap_or_default(),
  276. hatch_2_line_reduction: value.get(2).map(|x| x.line_reduction).unwrap_or_default(),
  277. hatch_0_loop_count: value.get(0).map(|x| x.loop_count).unwrap_or_default(),
  278. hatch_1_loop_count: value.get(1).map(|x| x.loop_count).unwrap_or_default(),
  279. hatch_2_loop_count: value.get(2).map(|x| x.loop_count).unwrap_or_default(),
  280. hatch_0_loop_distance: value.get(0).map(|x| x.loop_distance).unwrap_or_default(),
  281. hatch_1_loop_distance: value.get(1).map(|x| x.loop_distance).unwrap_or_default(),
  282. hatch_2_loop_distance: value.get(2).map(|x| x.loop_distance).unwrap_or_default(),
  283. _unknown_1: [
  284. vec![0, 0, 0, 0, 0, 0, 0, 0].into(),
  285. vec![0, 0, 0, 0, 0, 0, 0, 0].into(),
  286. vec![0, 0, 0, 0, 0, 0, 0, 0].into(),
  287. ]
  288. .into(),
  289. contour_priority: false.into(),
  290. hatch_0_count: value.get(0).map(|x| x.count).unwrap_or_default(),
  291. hatch_1_count: value.get(1).map(|x| x.count).unwrap_or_default(),
  292. hatch_2_count: value.get(2).map(|x| x.count).unwrap_or_default(),
  293. }
  294. }
  295. }
  296. #[derive(BinRead, BinWrite, Clone, Debug, Diff, PartialEq)]
  297. #[diff(attr(
  298. #[derive(Debug, PartialEq)]
  299. ))]
  300. pub struct HatchLine {
  301. pub lines: ArrayOf<Lines>,
  302. }
  303. #[derive(BinRead, BinWrite, Clone, Debug, Diff, PartialEq)]
  304. #[diff(attr(
  305. #[derive(Debug, PartialEq)]
  306. ))]
  307. #[brw(magic(16_u32))] // ObjectType::HatchLine
  308. pub struct HatchLines {
  309. pub core: ObjectCore, // HatchType::HatchLine
  310. pub hatch_line: ArrayOf<HatchLine>,
  311. }
  312. #[derive(BinRead, BinWrite, Clone, Debug, Diff, PartialEq)]
  313. #[diff(attr(
  314. #[derive(Debug, PartialEq)]
  315. ))]
  316. pub struct Hatches {
  317. pub core: ObjectCore, // HatchType::HatchLine
  318. pub hatch_lines: ArrayOf<HatchLines>,
  319. }
  320. #[binrw]
  321. #[derive(Clone, Debug, Diff, PartialEq)]
  322. #[diff(attr(
  323. #[derive(Debug, PartialEq)]
  324. ))]
  325. pub struct Hatch {
  326. pub core: ObjectCore,
  327. pub outline: ArrayOf<Object>,
  328. pub legacy_setting: LegacyHatchSetting,
  329. #[br(temp)]
  330. #[bw(try_calc(u32::try_from(hatch_settings.len()).unwrap().try_into()))]
  331. pub num_settings: U32,
  332. #[br(count = num_settings.value)]
  333. pub hatch_settings: Vec<HatchSetting>,
  334. #[brw(if(legacy_setting.any_hatch_enabled.value == 1))]
  335. pub hatches: Option<Hatches>,
  336. }
  337. impl Translate for Hatch {
  338. fn move_absolute(&mut self, origin: Option<Coordinate>, z: Option<f64>) {
  339. self.outline.iter_mut().for_each(|x| x.move_absolute(origin, z));
  340. self.core.move_absolute(origin, z);
  341. }
  342. fn move_relative(&mut self, delta: Option<Coordinate>, z: Option<f64>) {
  343. self.outline.iter_mut().for_each(|x| x.move_relative(delta, z));
  344. self.core.move_relative(delta, z);
  345. }
  346. }