dxfscan 0.1.0

Binary DXF parser with typed entity data and lookup indices
Documentation
// SPDX-License-Identifier: ISC
use crate::value::GroupValue;
use alloc::vec::Vec;

/// A single vertex within an [`LwPolyline`].
#[derive(Debug, Clone, Copy, Default)]
pub struct LwPolylineVertex {
    /// X coordinate.
    pub x: f64,
    /// Y coordinate.
    pub y: f64,
    /// Bulge factor.
    ///
    /// The tangent of one quarter of the arc's included angle for the
    /// segment starting at this vertex. Zero means a straight segment.
    /// Positive values produce counter-clockwise arcs; negative values
    /// produce clockwise arcs. A bulge of 1.0 is a semicircle.
    pub bulge: f64,
    /// Starting width for this segment.
    ///
    /// Zero means use the polyline's `constant_width`.
    pub start_width: f64,
    /// Ending width for this segment.
    ///
    /// Zero means use the polyline's `constant_width`.
    pub end_width: f64,
}

/// An LWPOLYLINE (lightweight polyline) entity.
#[derive(Debug, Clone, Default)]
pub struct LwPolyline {
    /// Vertex list.
    pub vertices: Vec<LwPolylineVertex>,
    /// Polyline flags.
    ///
    /// `0b1` = closed.
    pub flags: i16,
    /// Constant width for all segments.
    ///
    /// Overridden by per-vertex `start_width`/`end_width` when nonzero.
    pub constant_width: f64,
    /// Elevation in the OCS Z direction.
    pub elevation: f64,
    /// Extrusion thickness.
    pub thickness: f64,
    /// In-progress vertex being accumulated.
    current: Option<LwPolylineVertex>,
}

impl LwPolyline {
    /// Returns `true` if the closed flag (`0b1`) is set.
    pub fn is_closed(&self) -> bool {
        self.flags & 1 != 0
    }

    pub(crate) fn feed(&mut self, code: u16, val: &GroupValue) {
        match code {
            10 => {
                if let Some(v) = self.current.take() {
                    self.vertices.push(v);
                }
                self.current = Some(LwPolylineVertex {
                    x: val.as_f64().unwrap_or(0.0),
                    ..Default::default()
                });
            }
            20 => {
                if let Some(ref mut v) = self.current {
                    v.y = val.as_f64().unwrap_or(0.0);
                }
            }
            40 => {
                if let Some(ref mut v) = self.current {
                    v.start_width = val.as_f64().unwrap_or(0.0);
                }
            }
            41 => {
                if let Some(ref mut v) = self.current {
                    v.end_width = val.as_f64().unwrap_or(0.0);
                }
            }
            42 => {
                if let Some(ref mut v) = self.current {
                    v.bulge = val.as_f64().unwrap_or(0.0);
                }
            }
            70 => {
                if let Some(v) = val.as_i16() {
                    self.flags = v;
                }
            }
            _ => {
                if let Some(v) = val.as_f64() {
                    match code {
                        38 => self.elevation = v,
                        39 => self.thickness = v,
                        43 => self.constant_width = v,
                        _ => {}
                    }
                }
            }
        }
    }

    /// Flushes the in-progress vertex. Called by the scanner after the last pair.
    pub(crate) fn finish(&mut self) {
        if let Some(v) = self.current.take() {
            self.vertices.push(v);
        }
    }
}