kpt_lib 0.1.1

Keyboard plate prototyping
Documentation
use crate::geometry::primitives::*;
use crate::config::model::Layout;
use cgmath::Point2;
use dxf::entities::*;
use ply_rs::ply::{
    Addable, DefaultElement, ElementDef, Encoding, Ply, Property, PropertyDef, PropertyType,
    ScalarType,
};
use ply_rs::writer::Writer;
use spade::delaunay::ConstrainedDelaunayTriangulation;
use spade::kernels::FloatKernel;
use std::fs::File;
use std::io::Write;

pub type Cdt = ConstrainedDelaunayTriangulation<Point2<f64>, FloatKernel>;

pub trait PlyExport {
    fn new() -> Self;
    fn create_vertex_header(&mut self);
    fn create_triangle_header(&mut self);
    fn write_to_file(&mut self, name: String);
    fn add_enconding(&mut self, encoding: Encoding);
    fn add_comment(&mut self, comment: String);
}

pub trait PlyImport {
    fn import(&mut self, keyboard: &Layout, geometry: &Vec<Polyline>);
}

#[derive(Debug)]
pub struct PlyObject {
    pub object: Ply<DefaultElement>,
}

impl PlyExport for PlyObject {
    fn new() -> Self {
        Self {
            object: Ply::<DefaultElement>::new(),
        }
    }
    fn create_vertex_header(&mut self) {
        let mut point_element = ElementDef::new("vertex".to_string());
        let p = PropertyDef::new("x".to_string(), PropertyType::Scalar(ScalarType::Float));
        point_element.properties.add(p);
        let p = PropertyDef::new("y".to_string(), PropertyType::Scalar(ScalarType::Float));
        point_element.properties.add(p);
        let p = PropertyDef::new("z".to_string(), PropertyType::Scalar(ScalarType::Float));
        point_element.properties.add(p);
        self.object.header.elements.add(point_element);
    }
    fn create_triangle_header(&mut self) {
        let mut face_element = ElementDef::new("face".to_string());
        let p = PropertyDef::new(
            "vertex_index".to_string(),
            PropertyType::List(ScalarType::UChar, ScalarType::Int),
        );
        face_element.properties.add(p);
        self.object.header.elements.add(face_element);
    }
    fn write_to_file(&mut self, name: String) {
        let mut buf = Vec::<u8>::new();
        let w = Writer::new();
        w.write_ply(&mut buf, &mut self.object).unwrap();
        let mut file = File::create(format!("{}.ply", name)).unwrap();
        file.write_all(&buf).unwrap();
    }
    fn add_enconding(&mut self, encoding: Encoding) {
        self.object.header.encoding = encoding;
    }
    fn add_comment(&mut self, comment: String) {
        self.object.header.comments.push(comment);
    }
}

impl PlyImport for PlyObject {
    fn import(&mut self, keyboard: &Layout, geometry: &Vec<Polyline>) {
        let mut cdt = Cdt::new();

        for pl in geometry {
            for vtx in 0..pl.vertices.len() {
                if vtx + 1 < pl.vertices.len() {
                    let a = cdt.insert(Point2::new(
                        pl.vertices[vtx].location.x,
                        pl.vertices[vtx].location.y,
                    ));
                    let b = cdt.insert(Point2::new(
                        pl.vertices[vtx + 1].location.x,
                        pl.vertices[vtx + 1].location.y,
                    ));
                    cdt.add_constraint(a, b);
                }
            }
        }

        let mut points = Vec::new();
        let mut triangles = Vec::new();
        let mut original_triangles: Vec<TriangleIndex> = Vec::new();
        self.add_enconding(Encoding::Ascii);
        self.create_vertex_header();

        for tr in cdt.vertices() {
            let mut point = DefaultElement::new();
            point.insert("x".to_string(), Property::Float(tr.x as f32));
            point.insert("y".to_string(), Property::Float(tr.y as f32));
            point.insert("z".to_string(), Property::Float(0.));
            points.push(point);
        }
        for tr in cdt.vertices() {
            let mut point = DefaultElement::new();
            point.insert("x".to_string(), Property::Float(tr.x as f32));
            point.insert("y".to_string(), Property::Float(tr.y as f32));
            point.insert(
                "z".to_string(),
                Property::Float(keyboard.options.plate_height as f32),
            );
            points.push(point);
        }

        let points_len = points.len();
        self.object.payload.insert("vertex".to_string(), points);
        self.object.make_consistent().unwrap();

        for tr in cdt.triangles() {
            let mut triangle = DefaultElement::new();
            let trngl = tr.as_triangle();
            let mut pip = false;

            let point_avg_x = (trngl[0][0] + trngl[1][0] + trngl[2][0]) / 3.;
            let point_avg_y = (trngl[0][1] + trngl[1][1] + trngl[2][1]) / 3.;

            for pl in geometry {
                if pl.vertices.len() > 5 {
                    if point_in_polygon(pl.vertices.to_vec(), point_avg_x, point_avg_y) {
                        pip = true;
                        break;
                    }
                }
            }
            if pip == false {
                triangle.insert(
                    "vertex_index".to_string(),
                    Property::ListInt(vec![
                        trngl[0].fix() as i32,
                        trngl[1].fix() as i32,
                        trngl[2].fix() as i32,
                    ]),
                );
                triangles.push(triangle);
                original_triangles.push(TriangleIndex {
                    a: VertexIndex {
                        v: trngl[0].fix() as i32,
                        x: trngl[0][0] as f32,
                        y: trngl[0][1] as f32,
                        z: 0.,
                    },
                    b: VertexIndex {
                        v: trngl[1].fix() as i32,
                        x: trngl[1][0] as f32,
                        y: trngl[1][1] as f32,
                        z: 0.,
                    },
                    c: VertexIndex {
                        v: trngl[2].fix() as i32,
                        x: trngl[2][0] as f32,
                        y: trngl[2][1] as f32,
                        z: 0.,
                    },
                })
            }
        }

        for tr in &original_triangles {
            let mut triangle = DefaultElement::new();

            triangle.insert(
                "vertex_index".to_string(),
                Property::ListInt(vec![
                    tr.a.v + (points_len / 2) as i32,
                    tr.b.v + (points_len / 2) as i32,
                    tr.c.v + (points_len / 2) as i32,
                ]),
            );
            triangles.push(triangle);
        }

        for pl in geometry {
            for vtx in 0..pl.vertices.len() {
                if vtx + 1 < pl.vertices.len() {
                    let mut find_first = -1;

                    for ort in original_triangles.to_vec() {
                        find_first = ort.search(
                            pl.vertices[vtx].location.x as f32,
                            pl.vertices[vtx].location.y as f32,
                        );

                        if find_first != -1 {
                            break;
                        }
                    }

                    let mut find_second = -1;

                    for ort in original_triangles.to_vec() {
                        find_second = ort.search(
                            pl.vertices[vtx + 1].location.x as f32,
                            pl.vertices[vtx + 1].location.y as f32,
                        );
                        if find_second != -1 {
                            break;
                        }
                    }

                    if find_first != -1 && find_second != -1 {
                        let mut triangle_a = DefaultElement::new();

                        triangle_a.insert(
                            "vertex_index".to_string(),
                            Property::ListInt(vec![
                                find_first + (points_len / 2) as i32,
                                find_first,
                                find_second,
                            ]),
                        );
                        triangles.push(triangle_a);

                        let mut triangle_b = DefaultElement::new();

                        triangle_b.insert(
                            "vertex_index".to_string(),
                            Property::ListInt(vec![
                                find_first + (points_len / 2) as i32,
                                find_second,
                                find_second + (points_len / 2) as i32,
                            ]),
                        );
                        triangles.push(triangle_b);
                    }
                }
            }
        }

        
        self.create_triangle_header();
        self.object.payload.insert("face".to_string(), triangles);
        self.object.make_consistent().unwrap();
    }
}