use crate::error::{Lib3mfError, Result};
use crate::model::{Polygon, Segment, Slice, SliceRef, SliceStack, Vertex2D};
use crate::writer::xml_writer::XmlWriter;
use std::io::Write;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum SliceMode {
#[default]
PreserveOriginal,
Inline,
External,
}
pub struct SliceWriteOptions {
pub slice_mode: SliceMode,
pub strict: bool,
}
impl Default for SliceWriteOptions {
fn default() -> Self {
Self {
slice_mode: SliceMode::PreserveOriginal,
strict: false,
}
}
}
pub fn write_slice_stack<W: Write>(
writer: &mut XmlWriter<W>,
stack: &SliceStack,
opts: &SliceWriteOptions,
) -> Result<()> {
match opts.slice_mode {
SliceMode::PreserveOriginal => {}
SliceMode::Inline => {
return Err(Lib3mfError::Validation(
"SliceMode::Inline is not yet implemented".to_string(),
));
}
SliceMode::External => {
return Err(Lib3mfError::Validation(
"SliceMode::External is not yet implemented".to_string(),
));
}
}
if stack.slices.is_empty() && stack.refs.is_empty() {
eprintln!(
"Warning: slice stack id={} has no slices and no slicerefs",
stack.id.0
);
if opts.strict {
return Err(Lib3mfError::Validation(format!(
"Empty slice stack id={}",
stack.id.0
)));
}
}
writer
.start_element("slicestack")
.attr("id", &stack.id.0.to_string())
.attr("zbottom", &stack.z_bottom.to_string())
.write_start()?;
for slice in &stack.slices {
write_slice(writer, slice)?;
}
for sref in &stack.refs {
write_sliceref(writer, sref)?;
}
writer.end_element("slicestack")?;
Ok(())
}
fn write_slice<W: Write>(writer: &mut XmlWriter<W>, slice: &Slice) -> Result<()> {
if !slice.vertices.is_empty() && slice.polygons.is_empty() {
eprintln!(
"Warning: slice ztop={} has {} vertices but no polygons, skipping",
slice.z_top,
slice.vertices.len()
);
return Ok(());
}
writer
.start_element("slice")
.attr("ztop", &slice.z_top.to_string())
.write_start()?;
if !slice.vertices.is_empty() {
writer.start_element("vertices").write_start()?;
for v in &slice.vertices {
write_vertex(writer, v)?;
}
writer.end_element("vertices")?;
}
for polygon in &slice.polygons {
write_polygon(writer, polygon)?;
}
writer.end_element("slice")?;
Ok(())
}
fn write_vertex<W: Write>(writer: &mut XmlWriter<W>, v: &Vertex2D) -> Result<()> {
writer
.start_element("vertex")
.attr("x", &v.x.to_string())
.attr("y", &v.y.to_string())
.write_empty()?;
Ok(())
}
fn write_polygon<W: Write>(writer: &mut XmlWriter<W>, polygon: &Polygon) -> Result<()> {
if polygon.segments.is_empty() {
eprintln!(
"Warning: polygon start={} has zero segments (degenerate)",
polygon.start_segment
);
}
writer
.start_element("polygon")
.attr("start", &polygon.start_segment.to_string())
.write_start()?;
for segment in &polygon.segments {
write_segment(writer, segment)?;
}
writer.end_element("polygon")?;
Ok(())
}
fn write_segment<W: Write>(writer: &mut XmlWriter<W>, segment: &Segment) -> Result<()> {
let mut elem = writer
.start_element("segment")
.attr("v2", &segment.v2.to_string());
if let Some(p1) = segment.p1 {
elem = elem.attr("p1", &p1.to_string());
}
if let Some(p2) = segment.p2 {
elem = elem.attr("p2", &p2.to_string());
}
if let Some(pid) = segment.pid {
elem = elem.attr("pid", &pid.0.to_string());
}
elem.write_empty()?;
Ok(())
}
fn write_sliceref<W: Write>(writer: &mut XmlWriter<W>, sref: &SliceRef) -> Result<()> {
writer
.start_element("sliceref")
.attr("slicestackid", &sref.slice_stack_id.0.to_string())
.attr("slicepath", &sref.slice_path)
.write_empty()?;
Ok(())
}