use crate::io::dwg::dwg_stream_readers::merged_reader::DwgMergedReader;
use crate::objects::{
DgnLineStyleData, DgnLsComponentData, DgnLsComponentType, DgnLsCompoundComponent,
DgnLsCompoundEntry, DgnLsInternalComponent, DgnLsPhaseMode, DgnLsPointComponent, DgnLsStroke,
DgnLsStrokePattern, DgnLsSymbolComponent, DgnLsSymbolReference,
};
use crate::types::Handle;
const MAX_COMPONENT_ITEMS: i32 = 100_000;
pub fn read_dgn_line_style_data(
reader: &mut DwgMergedReader,
dxf_name: &str,
) -> Option<DgnLineStyleData> {
let description = reader.read_variable_text();
let version = reader.read_bit_long();
let component_type = reader.read_bit_long();
let component_uid = read_uid(reader);
if dxf_name.eq_ignore_ascii_case("LSDEFINITION") {
return Some(DgnLineStyleData::Definition {
description,
version,
style_number: component_type,
component_uid,
is_continuous: reader.read_bit(),
unit_definition: reader.read_bit_double(),
unit_scale: reader.read_bit_double(),
units_type: reader.read_bit_long(),
is_element: reader.read_bit(),
is_physical: reader.read_bit(),
is_scale_independent: reader.read_bit(),
is_snappable: reader.read_bit(),
root_component: Handle::from(reader.read_handle()),
properties: Vec::new(),
});
}
let kind = DgnLsComponentType::from_code(component_type)?;
let scale = reader.read_bit_double();
let property_flags = read_byte(reader);
let component = match kind {
DgnLsComponentType::Symbol => DgnLsComponentData::Symbol(DgnLsSymbolComponent {
stored_unit_scale: reader.read_bit_double(),
unit_scale: reader.read_bit_double(),
has_unit_scale: reader.read_bit(),
is_3d: reader.read_bit(),
block: Handle::from(reader.read_handle()),
}),
DgnLsComponentType::Compound => {
let count = safe_count(reader.read_bit_long());
let offsets = (0..count)
.map(|_| reader.read_bit_double())
.collect::<Vec<_>>();
let entries = offsets
.into_iter()
.map(|offset| DgnLsCompoundEntry {
component: Handle::from(reader.read_handle()),
offset,
})
.collect();
DgnLsComponentData::Compound(DgnLsCompoundComponent { entries })
}
DgnLsComponentType::Stroke => DgnLsComponentData::Stroke(read_stroke_pattern(reader)),
DgnLsComponentType::Point => {
let count = safe_count(reader.read_bit_long());
let mut symbols = Vec::with_capacity(count as usize);
for _ in 0..count {
symbols.push(DgnLsSymbolReference {
symbol_component: Handle::NULL,
partial_strokes: reader.read_bit(),
clip_partial: reader.read_bit(),
allow_stretch: reader.read_bit(),
partial_projected: reader.read_bit(),
use_symbol_color: reader.read_bit(),
use_symbol_lineweight: reader.read_bit(),
justify: reader.read_bit_long(),
rotation_type: reader.read_bit_long(),
vertex_mask: reader.read_bit_long(),
x_offset: reader.read_bit_double(),
y_offset: reader.read_bit_double(),
angle: reader.read_bit_double(),
stroke_number: reader.read_bit_long(),
});
}
let stroke_component = Handle::from(reader.read_handle());
for symbol in &mut symbols {
symbol.symbol_component = Handle::from(reader.read_handle());
}
DgnLsComponentData::Point(DgnLsPointComponent {
stroke_component,
symbols,
})
}
DgnLsComponentType::Internal => {
let pattern = read_stroke_pattern(reader);
DgnLsComponentData::Internal(DgnLsInternalComponent {
pattern,
internal_version: reader.read_bit_long(),
hardware_style: reader.read_bit_long(),
is_hardware_style: reader.read_bit(),
line_code: reader.read_bit_long(),
})
}
};
Some(DgnLineStyleData::Component {
kind,
description,
version,
component_uid,
scale,
property_flags,
component,
properties: Vec::new(),
})
}
fn read_uid(reader: &mut DwgMergedReader) -> [u8; 16] {
let bytes = reader.read_bytes(16);
let mut uid = [0; 16];
uid[..bytes.len().min(16)].copy_from_slice(&bytes[..bytes.len().min(16)]);
uid
}
fn read_byte(reader: &mut DwgMergedReader) -> u8 {
reader.read_bytes(1).first().copied().unwrap_or(0)
}
fn safe_count(value: i32) -> i32 {
value.clamp(0, MAX_COMPONENT_ITEMS)
}
fn read_stroke_pattern(reader: &mut DwgMergedReader) -> DgnLsStrokePattern {
let has_iteration_limit = reader.read_bit();
let is_single_segment = reader.read_bit();
let iteration_limit = reader.read_bit_long();
let auto_phase = reader.read_bit_double();
let phase = reader.read_bit_double();
let phase_mode =
DgnLsPhaseMode::from_code(((reader.read_bit() as u8) << 1) | reader.read_bit() as u8);
let count = safe_count(reader.read_bit_long());
let mut strokes = Vec::with_capacity(count as usize);
for _ in 0..count {
strokes.push(DgnLsStroke {
is_dash: reader.read_bit(),
bypass_corner: reader.read_bit(),
can_be_scaled: reader.read_bit(),
invert_at_origin: reader.read_bit(),
invert_at_end: reader.read_bit(),
length: reader.read_bit_double(),
start_width: reader.read_bit_double(),
end_width: reader.read_bit_double(),
width_mode: reader.read_bit_long(),
cap_mode: reader.read_bit_long(),
});
}
DgnLsStrokePattern {
has_iteration_limit,
is_single_segment,
iteration_limit,
auto_phase,
phase,
phase_mode,
strokes,
}
}