mod stream_writer;
mod text_writer;
mod binary_writer;
mod section_writer;
pub use stream_writer::{DxfStreamWriter, DxfStreamWriterExt, value_type_for_code};
pub use text_writer::DxfTextWriter;
pub use binary_writer::DxfBinaryWriter;
pub use section_writer::SectionWriter;
use crate::document::CadDocument;
use crate::entities::EntityType;
use crate::error::Result;
use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;
pub struct DxfWriter<'a> {
document: &'a CadDocument,
pub binary: bool,
}
impl<'a> DxfWriter<'a> {
pub fn new(document: &'a CadDocument) -> Self {
Self {
document,
binary: false,
}
}
pub fn new_binary(document: &'a CadDocument) -> Self {
Self {
document,
binary: true,
}
}
pub fn set_binary(&mut self, binary: bool) {
self.binary = binary;
}
pub fn write_to_file<P: AsRef<Path>>(&self, path: P) -> Result<()> {
let file = File::create(path)?;
let writer = BufWriter::new(file);
self.write_to_writer(writer)
}
pub fn write_to_writer<W: Write>(&self, writer: W) -> Result<()> {
if self.binary {
let mut stream_writer = DxfBinaryWriter::new(writer)?;
self.write_dxf(&mut stream_writer)?;
stream_writer.flush()?;
} else {
let mut stream_writer = DxfTextWriter::new(writer);
self.write_dxf(&mut stream_writer)?;
stream_writer.flush()?;
}
Ok(())
}
pub fn write_to_vec(&self) -> Result<Vec<u8>> {
let entity_count = self.document.entities().count();
let estimated = (entity_count + 64) * 512;
let mut buffer = Vec::with_capacity(estimated);
self.write_to_writer(&mut buffer)?;
Ok(buffer)
}
fn write_dxf<W: DxfStreamWriter>(&self, writer: &mut W) -> Result<()> {
let handle_start = compute_max_handle(&self.document);
let extra_handles = count_extra_handles(&self.document);
let handle_seed = handle_start + extra_handles + 1;
let mut section_writer = SectionWriter::new(writer, handle_start, handle_seed);
section_writer.set_version(self.document.version);
section_writer.build_valid_handles(&self.document);
section_writer.write_header(&self.document)?;
section_writer.write_classes(&self.document)?;
section_writer.write_tables(&self.document)?;
section_writer.write_blocks(&self.document)?;
section_writer.write_entities(&self.document)?;
section_writer.write_objects(&self.document)?;
section_writer.write_acdsdata()?;
writer.write_string(0, "EOF")?;
Ok(())
}
pub fn document(&self) -> &CadDocument {
&self.document
}
}
fn count_extra_handles(document: &CadDocument) -> u64 {
use crate::objects::ObjectType;
let mut count = 0u64;
for entity in document.entities() {
match entity {
EntityType::Polyline(polyline) => {
count += polyline.vertices.len() as u64 + 1;
}
EntityType::Polyline2D(polyline) => {
count += polyline.vertices.len() as u64 + 1;
}
EntityType::Polyline3D(polyline) => {
for vertex in &polyline.vertices {
if vertex.handle.is_null() {
count += 1;
}
}
count += 1;
}
EntityType::PolyfaceMesh(mesh) => {
for vertex in &mesh.vertices {
if vertex.common.handle.is_null() {
count += 1;
}
}
for face in &mesh.faces {
if face.common.handle.is_null() {
count += 1;
}
}
if mesh.seqend_handle.is_none() {
count += 1;
}
}
EntityType::PolygonMesh(mesh) => {
for vertex in &mesh.vertices {
if vertex.common.handle.is_null() {
count += 1;
}
}
count += 1;
}
EntityType::Insert(insert) => {
if insert.has_attributes() {
count += 1;
}
}
_ => {}
}
}
for obj in document.objects.values() {
if let ObjectType::SortEntitiesTable(table) = obj {
count += table.len() as u64;
}
}
count
}
fn compute_max_handle(document: &CadDocument) -> u64 {
let mut max = document.next_handle();
for entity in document.entities() {
let h = entity.common().handle.value();
if h >= max { max = h + 1; }
}
for (handle, _) in &document.objects {
let h = handle.value();
if h >= max { max = h + 1; }
}
for br in document.block_records.iter() {
let h = br.handle.value();
if h >= max { max = h + 1; }
for eh in &br.entity_handles {
let h = eh.value();
if h >= max { max = h + 1; }
}
}
for r in document.layers.iter() { let h = r.handle.value(); if h >= max { max = h + 1; } }
for r in document.line_types.iter() { let h = r.handle.value(); if h >= max { max = h + 1; } }
for r in document.text_styles.iter() { let h = r.handle.value(); if h >= max { max = h + 1; } }
for r in document.dim_styles.iter() { let h = r.handle.value(); if h >= max { max = h + 1; } }
for r in document.app_ids.iter() { let h = r.handle.value(); if h >= max { max = h + 1; } }
for r in document.views.iter() { let h = r.handle.value(); if h >= max { max = h + 1; } }
for r in document.vports.iter() { let h = r.handle.value(); if h >= max { max = h + 1; } }
for r in document.ucss.iter() { let h = r.handle.value(); if h >= max { max = h + 1; } }
max
}
pub fn write_dxf<P: AsRef<Path>>(document: &CadDocument, path: P) -> Result<()> {
let writer = DxfWriter::new(document);
writer.write_to_file(path)
}
pub fn write_binary_dxf<P: AsRef<Path>>(document: &CadDocument, path: P) -> Result<()> {
let writer = DxfWriter::new_binary(document);
writer.write_to_file(path)
}