dxfscan 0.1.0

Binary DXF parser with typed entity data and lookup indices
Documentation
// SPDX-License-Identifier: ISC
use super::MText;
use crate::point::Point3;
use crate::value::GroupValue;

/// An ATTRIB (block attribute value) entity.
#[derive(Debug, Clone, Default)]
pub struct Attrib<'a> {
    /// Attribute text value.
    pub value: &'a [u8],
    /// Embedded MTEXT sub-entity.
    ///
    /// Present when the attribute uses MTEXT for its display text
    /// (indicated by an AcDbMText subclass marker). When set, `value`
    /// is typically empty and the rendered text comes from here instead.
    pub mtext: Option<MText<'a>>,
    /// Tag name.
    pub tag: &'a [u8],
    /// Insertion point.
    pub location: Point3,
    /// Second alignment point.
    ///
    /// Used for all non-default justifications. When `h_justify` or
    /// `v_justify` is nonzero, this point (not `location`) determines
    /// the text's actual position.
    pub second_alignment_point: Point3,
    /// Text height.
    pub height: f64,
    /// Extrusion thickness.
    pub thickness: f64,
    /// Rotation angle in degrees.
    pub rotation: f64,
    /// Text style name.
    pub style_name: &'a [u8],
    /// Horizontal text justification.
    ///
    /// | Value | Meaning |
    /// |------:|---------|
    /// |     0 | Left    |
    /// |     1 | Center  |
    /// |     2 | Right   |
    /// |     3 | Aligned |
    /// |     4 | Middle  |
    /// |     5 | Fit     |
    pub h_justify: i16,
    /// Vertical text justification.
    ///
    /// | Value | Meaning  |
    /// |------:|----------|
    /// |     0 | Baseline |
    /// |     1 | Bottom   |
    /// |     2 | Middle   |
    /// |     3 | Top      |
    pub v_justify: i16,
    /// Relative X scale factor.
    ///
    /// Defaults to 1.0.
    pub width_factor: f64,
    /// Oblique angle in degrees.
    pub oblique_angle: f64,
    /// Text generation flags.
    ///
    /// `0b10` = backward (mirrored in X),
    /// `0b100` = upside down (mirrored in Y).
    pub text_generation_flags: i16,
    /// Attribute flags.
    ///
    /// `0b1` = invisible.
    pub flags: i16,
    /// Whether we're inside the embedded AcDbMText subclass.
    in_mtext: bool,
}

impl<'a> Attrib<'a> {
    pub(crate) fn feed(&mut self, code: u16, val: &GroupValue<'a>) {
        if code == 100 {
            if let Some(s) = val.as_str_bytes()
                && s == b"AcDbMText"
            {
                self.in_mtext = true;
                self.mtext = Some(MText::default());
            }
            return;
        }

        if self.in_mtext {
            if let Some(ref mut mt) = self.mtext {
                mt.feed(code, val);
            }
            return;
        }

        match code {
            1 => {
                if let Some(s) = val.as_str_bytes() {
                    self.value = s;
                }
            }
            2 => {
                if let Some(s) = val.as_str_bytes() {
                    self.tag = s;
                }
            }
            7 => {
                if let Some(s) = val.as_str_bytes() {
                    self.style_name = s;
                }
            }
            70 => {
                if let Some(v) = val.as_i16() {
                    self.flags = v;
                }
            }
            71 => {
                if let Some(v) = val.as_i16() {
                    self.text_generation_flags = v;
                }
            }
            72 => {
                if let Some(v) = val.as_i16() {
                    self.h_justify = v;
                }
            }
            74 => {
                if let Some(v) = val.as_i16() {
                    self.v_justify = v;
                }
            }
            _ => {
                if let Some(v) = val.as_f64() {
                    match code {
                        10 => self.location.x = v,
                        20 => self.location.y = v,
                        30 => self.location.z = v,
                        11 => self.second_alignment_point.x = v,
                        21 => self.second_alignment_point.y = v,
                        31 => self.second_alignment_point.z = v,
                        39 => self.thickness = v,
                        40 => self.height = v,
                        41 => self.width_factor = v,
                        50 => self.rotation = v,
                        51 => self.oblique_angle = v,
                        _ => {}
                    }
                }
            }
        }
    }
}