use crate::error::Result;
use crate::io::dxf::{DxfCode, GroupCodeValueType};
use crate::types::Vector3;
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum CodePairValue {
None,
Int(i64),
Double(f64),
Bool(bool),
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct DxfCodePair {
pub code: i32,
pub dxf_code: DxfCode,
pub value_string: String,
typed_value: CodePairValue,
}
impl DxfCodePair {
pub fn new(code: i32, value_string: String) -> Self {
let dxf_code = DxfCode::from_i32(code);
let value_type = GroupCodeValueType::from_code(dxf_code);
let typed_value = match value_type {
GroupCodeValueType::Int16 | GroupCodeValueType::Int32 | GroupCodeValueType::Int64 | GroupCodeValueType::Byte => {
match value_string.trim().parse::<i64>() {
Ok(v) => CodePairValue::Int(v),
Err(_) => CodePairValue::None,
}
}
GroupCodeValueType::Double => {
match value_string.trim().parse::<f64>() {
Ok(v) => CodePairValue::Double(v),
Err(_) => CodePairValue::None,
}
}
GroupCodeValueType::Bool => {
match value_string.trim().parse::<i32>() {
Ok(v) => CodePairValue::Bool(v != 0),
Err(_) => CodePairValue::None,
}
}
_ => CodePairValue::None,
};
Self {
code,
dxf_code,
value_string,
typed_value,
}
}
pub(crate) fn new_typed(code: i32, value_string: String, typed_value: CodePairValue) -> Self {
let dxf_code = DxfCode::from_i32(code);
Self {
code,
dxf_code,
value_string,
typed_value,
}
}
#[allow(dead_code)]
pub fn as_string(&self) -> &str {
&self.value_string
}
#[allow(dead_code)]
pub fn as_int(&self) -> Option<i64> {
match self.typed_value {
CodePairValue::Int(v) => Some(v),
_ => None,
}
}
pub fn as_i16(&self) -> Option<i16> {
match self.typed_value {
CodePairValue::Int(v) => i16::try_from(v).ok(),
_ => None,
}
}
#[allow(dead_code)]
pub fn as_i32(&self) -> Option<i32> {
match self.typed_value {
CodePairValue::Int(v) => i32::try_from(v).ok(),
_ => None,
}
}
pub fn as_double(&self) -> Option<f64> {
match self.typed_value {
CodePairValue::Double(v) => Some(v),
_ => None,
}
}
pub fn as_bool(&self) -> Option<bool> {
match self.typed_value {
CodePairValue::Bool(v) => Some(v),
_ => None,
}
}
#[allow(dead_code)]
pub fn as_handle(&self) -> Option<u64> {
u64::from_str_radix(self.value_string.trim(), 16).ok()
}
}
pub trait DxfStreamReader {
fn read_pair(&mut self) -> Result<Option<DxfCodePair>>;
#[allow(dead_code)]
fn peek_code(&mut self) -> Result<Option<i32>>;
fn push_back(&mut self, pair: DxfCodePair);
#[allow(dead_code)]
fn reset(&mut self) -> Result<()>;
fn set_encoding(&mut self, _encoding: &'static encoding_rs::Encoding) {
}
}
pub struct PointReader {
x: Option<f64>,
y: Option<f64>,
z: Option<f64>,
group: Option<usize>,
}
impl PointReader {
pub fn new() -> Self {
Self {
x: None,
y: None,
z: None,
group: None,
}
}
pub fn add_coordinate(&mut self, pair: &DxfCodePair) -> bool {
if let Some(axis) = GroupCodeValueType::coordinate_axis(pair.dxf_code) {
let coord_group = GroupCodeValueType::coordinate_group(pair.dxf_code);
if self.group.is_some() && self.group != coord_group {
return false;
}
self.group = coord_group;
if let Some(value) = pair.as_double() {
match axis {
0 => self.x = Some(value),
1 => self.y = Some(value),
2 => self.z = Some(value),
_ => return false,
}
return true;
}
}
false
}
#[allow(dead_code)]
pub fn is_complete(&self) -> bool {
self.x.is_some() && self.y.is_some()
}
pub fn get_point(&self) -> Option<Vector3> {
if let (Some(x), Some(y)) = (self.x, self.y) {
Some(Vector3::new(x, y, self.z.unwrap_or(0.0)))
} else {
None
}
}
#[allow(dead_code)]
pub fn reset(&mut self) {
self.x = None;
self.y = None;
self.z = None;
self.group = None;
}
}
impl Default for PointReader {
fn default() -> Self {
Self::new()
}
}