use std::fmt::Debug; use crate::{ array_of::ArrayOf, field_of::FieldOf, types::{Field, Coordinate, F64, U32}, }; use binrw::{binrw, BinRead, BinWrite}; use diff::Diff; use modular_bitfield::{ bitfield, specifiers::{B1, B18}, }; use serde::{Deserialize, Serialize}; use super::{line::Lines, Object, ObjectCore, Translate}; #[bitfield(bits = 32)] #[derive(BinRead, BinWrite, Copy, Clone, Debug, Default, Diff, PartialEq)] #[diff(attr( #[derive(Debug, PartialEq)] ))] #[br(map = Self::from_bytes)] #[bw(map = |&x| Self::into_bytes(x))] pub struct HatchFlag { pub all_calc: B1, pub follow_edge_once: B1, pub continuous_pattern: B1, // Hatch type 3 when combined with bidirectional_pattern pub bidirectional_pattern: B1, // Hatch type 1 pub ring_pattern: B1, // Hatch type 2 #[skip] __: B1, pub auto_rotate_hatch_angle: B1, pub average_distribute_line: B1, #[skip] __: B1, pub gong_pattern: B1, // Hatch type 4 when combined with bidirectional_pattern pub cross_hatch: B1, pub background_pattern: B1, // Hatch type 5, must set all_calc as well pub fill_pattern: B1, // Hatch type 6 when combined with continuous_pattern and bidirectional_pattern pub zigzag_pattern: B1, // Hatch type 7 #[skip] __: B18, } #[derive(Copy, Clone, Debug, Serialize, Deserialize)] pub enum HatchPattern { Directional, Bidirectional, Ring, Continuous, Gong, Background, Fill, Zigzag, } impl From for HatchFlag { fn from(value: HatchPattern) -> Self { let mut ret = Self::new(); match value { HatchPattern::Directional => (), HatchPattern::Bidirectional => ret.set_bidirectional_pattern(1), HatchPattern::Ring => ret.set_ring_pattern(1), HatchPattern::Continuous => { ret.set_bidirectional_pattern(1); ret.set_continuous_pattern(1); } HatchPattern::Gong => { ret.set_bidirectional_pattern(1); ret.set_gong_pattern(1); } HatchPattern::Background => { ret.set_background_pattern(1); ret.set_all_calc(1); } HatchPattern::Fill => ret.set_fill_pattern(1), HatchPattern::Zigzag => ret.set_zigzag_pattern(1), } ret } } #[cfg_attr(feature = "default-debug", derive(Debug))] #[derive(BinRead, BinWrite, Clone, Diff, PartialEq)] #[diff(attr( #[derive(Debug, PartialEq)] ))] #[brw(magic(46u32))] // Number of fields in this struct pub struct LegacyHatchSetting { pub mark_contour: U32, pub hatch_0_enable: U32, pub hatch_0_pen: U32, pub hatch_0_flags: FieldOf, pub hatch_0_edge_offset: F64, pub hatch_0_line_spacing: F64, pub hatch_0_start_offset: F64, pub hatch_0_end_offset: F64, pub hatch_0_angle: F64, pub hatch_1_enable: U32, pub hatch_1_pen: U32, pub hatch_1_flags: FieldOf, pub hatch_1_edge_offset: F64, pub hatch_1_line_spacing: F64, pub hatch_1_start_offset: F64, pub hatch_1_end_offset: F64, pub hatch_1_angle: F64, pub any_hatch_enabled: U32, pub hatch_0_rotate_angle: F64, pub hatch_1_rotate_angle: F64, pub hatch_2_enable: U32, pub hatch_2_pen: U32, pub hatch_2_flags: FieldOf, pub hatch_2_edge_offset: F64, pub hatch_2_line_spacing: F64, pub hatch_2_start_offset: F64, pub hatch_2_end_offset: F64, pub hatch_2_angle: F64, pub hatch_2_rotate_angle: F64, pub hatch_0_line_reduction: F64, pub hatch_1_line_reduction: F64, pub hatch_2_line_reduction: F64, pub hatch_0_loop_count: U32, pub hatch_1_loop_count: U32, pub hatch_2_loop_count: U32, pub hatch_0_loop_distance: F64, pub hatch_1_loop_distance: F64, pub hatch_2_loop_distance: F64, pub _unknown_1: [Field; 3], pub contour_priority: U32, pub hatch_0_count: U32, pub hatch_1_count: U32, pub hatch_2_count: U32, } // Custom Debug implementation to only print known fields #[cfg(not(feature = "default-debug"))] impl Debug for LegacyHatchSetting { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("LegacyHatchSetting") .field("mark_contour", &self.mark_contour) .field("hatch_0_enable", &self.hatch_0_enable) .field("hatch_0_pen", &self.hatch_0_pen) .field("hatch_0_flags", &self.hatch_0_flags) .field("hatch_0_edge_offset", &self.hatch_0_edge_offset) .field("hatch_0_line_spacing", &self.hatch_0_line_spacing) .field("hatch_0_start_offset", &self.hatch_0_start_offset) .field("hatch_0_end_offset", &self.hatch_0_end_offset) .field("hatch_0_angle", &self.hatch_0_angle) .field("hatch_1_enable", &self.hatch_1_enable) .field("hatch_1_pen", &self.hatch_1_pen) .field("hatch_1_flags", &self.hatch_1_flags) .field("hatch_1_edge_offset", &self.hatch_1_edge_offset) .field("hatch_1_line_spacing", &self.hatch_1_line_spacing) .field("hatch_1_start_offset", &self.hatch_1_start_offset) .field("hatch_1_end_offset", &self.hatch_1_end_offset) .field("hatch_1_angle", &self.hatch_1_angle) .field("any_hatch_enabled", &self.any_hatch_enabled) .field("hatch_0_auto_rotate_angle", &self.hatch_0_rotate_angle) .field("hatch_1_auto_rotate_angle", &self.hatch_1_rotate_angle) .field("hatch_2_enable", &self.hatch_2_enable) .field("hatch_2_pen", &self.hatch_2_pen) .field("hatch_2_flags", &self.hatch_2_flags) .field("hatch_2_edge_offset", &self.hatch_2_edge_offset) .field("hatch_2_line_spacing", &self.hatch_2_line_spacing) .field("hatch_2_start_offset", &self.hatch_2_start_offset) .field("hatch_2_end_offset", &self.hatch_2_end_offset) .field("hatch_2_angle", &self.hatch_2_angle) .field("hatch_2_auto_rotate_angle", &self.hatch_2_rotate_angle) .field("hatch_0_line_reduction", &self.hatch_0_line_reduction) .field("hatch_1_line_reduction", &self.hatch_1_line_reduction) .field("hatch_2_line_reduction", &self.hatch_2_line_reduction) .field("hatch_0_loop_count", &self.hatch_0_loop_count) .field("hatch_1_loop_count", &self.hatch_1_loop_count) .field("hatch_2_loop_count", &self.hatch_2_loop_count) .field("hatch_0_loop_distance", &self.hatch_0_loop_distance) .field("hatch_1_loop_distance", &self.hatch_1_loop_distance) .field("hatch_2_loop_distance", &self.hatch_2_loop_distance) .field("contour_priority", &self.contour_priority) .field("hatch_0_count", &self.hatch_0_count) .field("hatch_1_count", &self.hatch_1_count) .field("hatch_2_count", &self.hatch_2_count) .finish() } } #[cfg_attr(feature = "default-debug", derive(Debug))] #[derive(BinRead, BinWrite, Clone, Diff, PartialEq)] #[diff(attr( #[derive(Debug, PartialEq)] ))] #[brw(magic(15u32))] // Number of fields in this struct pub struct HatchSetting { pub count: U32, pub enabled: U32, pub pen: U32, pub flags: FieldOf, pub edge_offset: F64, pub line_spacing: F64, pub start_offset: F64, pub end_offset: F64, pub angle: F64, pub rotate_angle: F64, pub line_reduction: F64, pub loop_distance: F64, pub loop_count: U32, pub _unknown_1: [Field; 2], } // Custom Debug implementation to only print known fields #[cfg(not(feature = "default-debug"))] impl Debug for HatchSetting { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("HatchSettings") .field("count", &self.count) .field("enabled", &self.enabled) .field("pen", &self.pen) .field("flags", &self.flags) .field("edge_offset", &self.edge_offset) .field("line_spacing", &self.line_spacing) .field("start_offset", &self.start_offset) .field("end_offset", &self.end_offset) .field("angle", &self.angle) .field("auto_rotate_angle", &self.rotate_angle) .field("line_reduction", &self.line_reduction) .field("loop_distance", &self.loop_distance) .field("loop_count", &self.loop_count) .finish() } } impl Default for HatchSetting { fn default() -> Self { Self { count: 1.into(), enabled: false.into(), pen: 0.into(), flags: HatchFlag::new().into(), edge_offset: 0.0.into(), line_spacing: 1.0.into(), start_offset: 0.0.into(), end_offset: 0.0.into(), angle: 0.0.into(), rotate_angle: 10.0.into(), line_reduction: 0.0.into(), loop_distance: 0.5.into(), loop_count: 0.into(), _unknown_1: [vec![0, 0, 0, 0, 0, 0, 0, 0].into(), vec![0, 0, 0, 0].into()].into(), } } } impl From> for LegacyHatchSetting { fn from(value: Vec) -> Self { LegacyHatchSetting { mark_contour: false.into(), hatch_0_enable: value.get(0).map(|x| x.enabled).unwrap_or_default(), hatch_0_pen: value.get(0).map(|x| x.pen).unwrap_or_default(), hatch_0_flags: value.get(0).map(|x| x.flags).unwrap_or_default(), hatch_0_edge_offset: value.get(0).map(|x| x.edge_offset).unwrap_or_default(), hatch_0_line_spacing: value.get(0).map(|x| x.line_spacing).unwrap_or_default(), hatch_0_start_offset: value.get(0).map(|x| x.start_offset).unwrap_or_default(), hatch_0_end_offset: value.get(0).map(|x| x.end_offset).unwrap_or_default(), hatch_0_angle: value.get(0).map(|x| x.angle).unwrap_or_default(), hatch_1_enable: value.get(1).map(|x| x.enabled).unwrap_or_default(), hatch_1_pen: value.get(1).map(|x| x.pen).unwrap_or_default(), hatch_1_flags: value.get(1).map(|x| x.flags).unwrap_or_default(), hatch_1_edge_offset: value.get(1).map(|x| x.edge_offset).unwrap_or_default(), hatch_1_line_spacing: value.get(1).map(|x| x.line_spacing).unwrap_or_default(), hatch_1_start_offset: value.get(1).map(|x| x.start_offset).unwrap_or_default(), hatch_1_end_offset: value.get(1).map(|x| x.end_offset).unwrap_or_default(), hatch_1_angle: value.get(1).map(|x| x.angle).unwrap_or_default(), any_hatch_enabled: value.iter().any(|x| x.enabled.into()).into(), hatch_0_rotate_angle: value.get(0).map(|x| x.rotate_angle).unwrap_or_default(), hatch_1_rotate_angle: value.get(1).map(|x| x.rotate_angle).unwrap_or_default(), hatch_2_enable: value.get(2).map(|x| x.enabled).unwrap_or_default(), hatch_2_pen: value.get(2).map(|x| x.pen).unwrap_or_default(), hatch_2_flags: value.get(2).map(|x| x.flags).unwrap_or_default(), hatch_2_edge_offset: value.get(2).map(|x| x.edge_offset).unwrap_or_default(), hatch_2_line_spacing: value.get(2).map(|x| x.line_spacing).unwrap_or_default(), hatch_2_start_offset: value.get(2).map(|x| x.start_offset).unwrap_or_default(), hatch_2_end_offset: value.get(2).map(|x| x.end_offset).unwrap_or_default(), hatch_2_angle: value.get(2).map(|x| x.angle).unwrap_or_default(), hatch_2_rotate_angle: value.get(2).map(|x| x.rotate_angle).unwrap_or_default(), hatch_0_line_reduction: value.get(0).map(|x| x.line_reduction).unwrap_or_default(), hatch_1_line_reduction: value.get(1).map(|x| x.line_reduction).unwrap_or_default(), hatch_2_line_reduction: value.get(2).map(|x| x.line_reduction).unwrap_or_default(), hatch_0_loop_count: value.get(0).map(|x| x.loop_count).unwrap_or_default(), hatch_1_loop_count: value.get(1).map(|x| x.loop_count).unwrap_or_default(), hatch_2_loop_count: value.get(2).map(|x| x.loop_count).unwrap_or_default(), hatch_0_loop_distance: value.get(0).map(|x| x.loop_distance).unwrap_or_default(), hatch_1_loop_distance: value.get(1).map(|x| x.loop_distance).unwrap_or_default(), hatch_2_loop_distance: value.get(2).map(|x| x.loop_distance).unwrap_or_default(), _unknown_1: [ vec![0, 0, 0, 0, 0, 0, 0, 0].into(), vec![0, 0, 0, 0, 0, 0, 0, 0].into(), vec![0, 0, 0, 0, 0, 0, 0, 0].into(), ] .into(), contour_priority: false.into(), hatch_0_count: value.get(0).map(|x| x.count).unwrap_or_default(), hatch_1_count: value.get(1).map(|x| x.count).unwrap_or_default(), hatch_2_count: value.get(2).map(|x| x.count).unwrap_or_default(), } } } #[derive(BinRead, BinWrite, Clone, Debug, Diff, PartialEq)] #[diff(attr( #[derive(Debug, PartialEq)] ))] pub struct HatchLine { pub lines: ArrayOf, } #[derive(BinRead, BinWrite, Clone, Debug, Diff, PartialEq)] #[diff(attr( #[derive(Debug, PartialEq)] ))] #[brw(magic(16_u32))] // ObjectType::HatchLine pub struct HatchLines { pub core: ObjectCore, // HatchType::HatchLine pub hatch_line: ArrayOf, } #[derive(BinRead, BinWrite, Clone, Debug, Diff, PartialEq)] #[diff(attr( #[derive(Debug, PartialEq)] ))] pub struct Hatches { pub core: ObjectCore, // HatchType::HatchLine pub hatch_lines: ArrayOf, } #[binrw] #[derive(Clone, Debug, Diff, PartialEq)] #[diff(attr( #[derive(Debug, PartialEq)] ))] pub struct Hatch { pub core: ObjectCore, pub outline: ArrayOf, pub legacy_setting: LegacyHatchSetting, #[br(temp)] #[bw(try_calc(u32::try_from(hatch_settings.len()).unwrap().try_into()))] pub num_settings: U32, #[br(count = num_settings.value)] pub hatch_settings: Vec, #[brw(if(legacy_setting.any_hatch_enabled.value == 1))] pub hatches: Option, } impl Translate for Hatch { fn move_absolute(&mut self, origin: Option, z: Option) { self.outline.iter_mut().for_each(|x| x.move_absolute(origin, z)); self.core.move_absolute(origin, z); } fn move_relative(&mut self, delta: Option, z: Option) { self.outline.iter_mut().for_each(|x| x.move_relative(delta, z)); self.core.move_relative(delta, z); } }