polygon-offsetting 0.1.5

polygon offsetting crate
Documentation
use crate::Offset;

use std::path::Path;
use std::fs::File;
use std::io::Write;

#[derive(Debug, Default)]
pub struct Segm {
    p1: (f64, f64),
    p2: (f64, f64)
}

pub fn draw_svg_offset(
    initial_contour: &Vec<(f64, f64)>,
    offset: &mut Offset,
    dir_path: String,
    filename: String) -> Result <(), Box<dyn std::error::Error>>
{
    let mut segments: Vec<Segm> = Vec::new();
    let mut segms: Vec<Segm> = Vec::new();

    for i in 1..initial_contour.len() {
        let mut sgmt: Segm = Segm::default();

        sgmt.p1.0 = initial_contour[i - 1].0;
        sgmt.p1.1 = initial_contour[i - 1].1;
        if i == initial_contour.len() { 
            sgmt.p2.0 = initial_contour[0].0;
            sgmt.p2.1 = initial_contour[0].1;
            segms.push(sgmt);
            break ;
        }
        sgmt.p2.0 = initial_contour[i].0;
        sgmt.p2.1 = initial_contour[i].1;
        segms.push(sgmt);
    }

    let contour_offset = offset.contour.clone();
    for i in 1..contour_offset.len() {
        let mut sgmt: Segm = Segm::default();

        sgmt.p1.0 = contour_offset[i - 1].0;
        sgmt.p1.1 = contour_offset[i - 1].1;
        if i == contour_offset.len() { 
            sgmt.p2.0 = contour_offset[0].0;
            sgmt.p2.1 = contour_offset[0].1;
            segms.push(sgmt);
            break ;
        }
        sgmt.p2.0 = contour_offset[i].0;
        sgmt.p2.1 = contour_offset[i].1;
        segms.push(sgmt);
    }

    segments.append(&mut segms);

    let mut x_min1 = 0.;
    let mut y_min1 = 0.;
    for i in 0..segments.len() {
        if i == 0 {
            x_min1 = segments[i].p1.0;
            y_min1 = segments[i].p1.1;
        } else {
            if segments[i].p1.0 < x_min1 { x_min1 = segments[i].p1.0; }
            if segments[i].p2.0 < x_min1 { x_min1 = segments[i].p2.0; }
            if segments[i].p1.1 < y_min1 { y_min1 = segments[i].p1.1; }
            if segments[i].p2.1 < y_min1 { y_min1 = segments[i].p2.1; }
        }
    }
    segments.iter_mut().for_each(|p| {
        p.p1.0 -= x_min1;
        p.p2.0 -= x_min1;
        p.p1.1 -= y_min1;
        p.p2.1 -= y_min1;

    });

    let mut max_x: f64 = std::f64::NEG_INFINITY;
    let mut max_y: f64 = std::f64::NEG_INFINITY;
    segments.iter().for_each(|segment| {
        let p = &segment.p1;
        if max_x < p.0 { max_x = p.0 }
        if max_y < p.1 { max_x = p.1 }

        let p = &segment.p2;
        if max_x < p.0 { max_x = p.0 }
        if max_y < p.1 { max_y = p.1 }
    });

    let resize_width =  max_x / 1800.0;
    let resize_height = max_y / 850.0;
    let resize = if resize_width > resize_height { resize_width } else { resize_height };
    segments.iter_mut().for_each(|s| {
        s.p1.0 = s.p1.0 / resize;
        s.p1.1 = s.p1.1 / resize;
        s.p2.0 = s.p2.0 / resize;
        s.p2.1 = s.p2.1 / resize;
    });

    let mut viewbox = vec![
        std::f64::INFINITY,
        std::f64::INFINITY,  
        std::f64::NEG_INFINITY,
        std::f64::NEG_INFINITY
    ];

    segments.iter().for_each(|segment| {
        let p = &segment.p1;
        if viewbox[0] > p.0 { viewbox[0] = p.0 }
        if viewbox[1] > p.1 { viewbox[1] = p.1 }
        if viewbox[2] < p.0 { viewbox[2] = p.0 }
        if viewbox[3] < p.1 { viewbox[3] = p.1 }

        let p = &segment.p2;
        if viewbox[0] > p.0 { viewbox[0] = p.0 }
        if viewbox[1] > p.1 { viewbox[1] = p.1 }
        if viewbox[2] < p.0 { viewbox[2] = p.0 }
        if viewbox[3] < p.1 { viewbox[3] = p.1 }
    });

    let mut txt = format!(
        "<?xml version='1.0' encoding='UTF-8' standalone='no'?>
            <svg xmlns='http://www.w3.org/2000/svg' viewBox='{} {} {} {}' id='export' style='background-color:white'>\n", 
        viewbox[0] - 50., viewbox[1] - 50. , viewbox[2] + 100., viewbox[3] + 100. ).to_string();

    let mut i: usize = 0;
    segments.iter().for_each(|segment| {
        let p1 = segment.p1;
        let p2 = segment.p2;
        
        let mut path = "M ".to_string();
        
        path = format!("{} {} {} ", path, p1.0, (viewbox[3] - viewbox[1]) - (p1.1 - viewbox[1]));
        path = format!("{} {} {} ", path, p2.0, (viewbox[3] - viewbox[1]) - (p2.1 - viewbox[1]));
        
        
        let color = "#000000";
        let width = 1.;

        txt = format!("{}<path style='fill:none;stroke-width:{};stroke:{};' d='{}' id='{}' />\n", txt, width, color, path, 0);
        i += 1;
    });

    txt = format!("{}</svg>", txt);
    let env_path = std::env::current_dir().unwrap().to_str().unwrap().to_string();
    let dir =  env_path.clone() + &dir_path;

    if !(Path::new(&dir_path).exists()) {
        std::fs::create_dir_all(&dir)?;
    }
    let mut file = File::create(format!("{}.svg", dir.clone() + &filename)).map_err(|e| { 
        print!("Error on creating offset svg: {:?}", dir.clone() + &filename);
        e 
    })?;
    file.write_all(txt.as_bytes()).unwrap();
    
    Ok(())
}