123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484 |
- use std::fmt::{Debug, Display};
- use crate::{
- array_of::ArrayOf,
- field_of::FieldOf,
- types::{Coordinate, Field, 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, strum::Display)]
- pub enum HatchPattern {
- Directional,
- Bidirectional,
- Ring,
- Continuous,
- Gong,
- Background,
- Fill,
- Zigzag,
- }
- impl From<HatchPattern> 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
- }
- }
- impl From<HatchFlag> for HatchPattern {
- fn from(value: HatchFlag) -> Self {
- if value.ring_pattern() != 0 {
- HatchPattern::Ring
- } else if value.background_pattern() != 0 {
- HatchPattern::Background
- } else if value.fill_pattern() != 0 {
- HatchPattern::Fill
- } else if value.zigzag_pattern() != 0 {
- HatchPattern::Zigzag
- } else if value.gong_pattern() != 0 {
- HatchPattern::Gong
- } else if value.bidirectional_pattern() != 0 {
- if value.continuous_pattern() != 0 {
- HatchPattern::Continuous
- } else {
- HatchPattern::Bidirectional
- }
- } else {
- HatchPattern::Directional
- }
- }
- }
- #[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
- #[brw(magic(47u32))] // 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<HatchFlag>,
- 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<HatchFlag>,
- 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<HatchFlag>,
- 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<HatchFlag>,
- 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<Vec<HatchSetting>> for LegacyHatchSetting {
- fn from(value: Vec<HatchSetting>) -> 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<Lines>,
- }
- #[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<HatchLine>,
- }
- #[derive(BinRead, BinWrite, Clone, Debug, Diff, PartialEq)]
- #[diff(attr(
- #[derive(Debug, PartialEq)]
- ))]
- pub struct Hatches {
- pub core: ObjectCore, // HatchType::HatchLine
- pub hatch_lines: ArrayOf<HatchLines>,
- }
- impl Hatches {
- pub fn set_pen(&mut self, pen: u32) {
- // Ignore self.core.pen
- self.hatch_lines.iter_mut().for_each(|x| {
- // Ignore HatchLines.core.pen
- x.hatch_line.iter_mut().for_each(|x| {
- x.lines.iter_mut().for_each(|x| {
- x.core.pen = pen.into();
- })
- })
- });
- }
- }
- #[binrw]
- #[derive(Clone, Debug, Diff, PartialEq)]
- #[diff(attr(
- #[derive(Debug, PartialEq)]
- ))]
- pub struct Hatch {
- pub core: ObjectCore,
- pub outline: ArrayOf<Object>,
- pub legacy_setting: LegacyHatchSetting,
- #[br(temp)]
- #[bw(try_calc(u32::try_from(hatch_settings.len()).unwrap().try_into()))]
- pub num_settings: U32,
- pub _unknown_1: Field,
- #[br(count = num_settings.value)]
- pub hatch_settings: Vec<HatchSetting>,
- #[brw(if(legacy_setting.any_hatch_enabled.value == 1))]
- pub hatches: Option<Hatches>,
- }
- impl Display for Hatch {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{}", self.core)?;
- for object in self.outline.iter() {
- write!(f, "\nOutline: {}", object)?;
- }
- write!(
- f,
- "\nMark Contour: {}, Contour Priority: {}",
- *self.legacy_setting.mark_contour != 0,
- *self.legacy_setting.contour_priority != 0
- )?;
- for (index, setting) in self.hatch_settings.iter().enumerate() {
- if setting.enabled.into() {
- write!(
- f,
- "\nHatch #{}: All Calc: {}, Follow Edge Once: {}, Cross Hatch: {}, Pattern: {}, Angle: {:.2}, Pen: {}, Count: {}, Line Space: {:.2}, Avg Distribte Line: {}",
- index,
- setting.flags.all_calc() != 0,
- setting.flags.follow_edge_once() != 0,
- setting.flags.cross_hatch() != 0,
- HatchPattern::from(*setting.flags),
- *setting.angle,
- *setting.pen,
- *setting.count,
- *setting.line_spacing,
- setting.flags.average_distribute_line() != 0,
- )?;
- write!(
- f,
- "\n Edge Offset: {:.2}, Start Offset: {:.2}, End Offset: {:.2}, Line Reduction: {:.2}, Loop Count: {}, Loop Distance: {:.2}, Auto Rotate: {}, Auto Rotate Angle: {:.2}",
- *setting.edge_offset,
- *setting.start_offset,
- *setting.end_offset,
- *setting.line_reduction,
- *setting.loop_count,
- *setting.loop_distance,
- setting.flags.auto_rotate_hatch_angle() != 0,
- *setting.rotate_angle,
- )?;
- }
- }
- Ok(())
- }
- }
- impl Translate for Hatch {
- fn move_absolute(&mut self, origin: Option<Coordinate>, z: Option<f64>) {
- self.outline
- .iter_mut()
- .for_each(|x| x.move_absolute(origin, z));
- origin.map(|origin| {
- let delta: Coordinate = origin - *self.core.origin;
- self.hatches.iter_mut().for_each(|x| {
- // Ignore Hatches.core.origin
- x.hatch_lines.iter_mut().for_each(|x| {
- // Ignore HatchLines.core.origin
- x.hatch_line.iter_mut().for_each(|x| {
- x.lines
- .iter_mut()
- .for_each(|x| x.move_relative(Some(delta), None));
- })
- })
- });
- });
- self.core.move_absolute(origin, z);
- }
- fn move_relative(&mut self, delta: Option<Coordinate>, z: Option<f64>) {
- self.outline
- .iter_mut()
- .for_each(|x| x.move_relative(delta, z));
- delta.map(|delta| {
- self.hatches.iter_mut().for_each(|x| {
- // Ignore Hatches.core.origin
- x.hatch_lines.iter_mut().for_each(|x| {
- // Ignore HatchLines.core.origin
- x.hatch_line.iter_mut().for_each(|x| {
- x.lines
- .iter_mut()
- .for_each(|x| x.move_relative(Some(delta), None));
- })
- })
- });
- });
- self.core.move_relative(delta, z);
- }
- }
|