1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// 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);
}
}
}