diff --git a/Cargo.lock b/Cargo.lock index 0ee6322..82f682e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,3 +1,13 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "approx" version = "0.3.1" @@ -6,6 +16,16 @@ dependencies = [ "num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "atty" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "0.1.2" @@ -16,6 +36,11 @@ name = "bitflags" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "cgmath" version = "0.17.0" @@ -27,6 +52,20 @@ dependencies = [ "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "clap" +version = "2.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -44,7 +83,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "icosahedron" version = "0.1.0" dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -64,6 +106,11 @@ name = "num-traits" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "numtoa" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "proc-macro2" version = "0.4.27" @@ -184,6 +231,19 @@ dependencies = [ "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rustc_version" version = "0.2.3" @@ -238,6 +298,11 @@ dependencies = [ "serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "syn" version = "0.15.26" @@ -248,11 +313,40 @@ dependencies = [ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termion" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.3.6" @@ -273,15 +367,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" "checksum approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c57ff1a5b00753647aebbbcf4ea67fa1e711a65ea7a30eb90dbf07de2485aee" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" "checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" "checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1" +"checksum numtoa 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" @@ -295,6 +394,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "eb9e9b8cde282a9fe6a42dd4681319bfb63f121b8a8ee9439c6f4107e58a46f7" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" @@ -302,8 +403,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "9f301d728f2b94c9a7691c90f07b0b4e8a4517181d9461be94c04bddeb4bd850" "checksum serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)" = "beed18e6f5175aef3ba670e57c60ef3b1b74d250d962a26604bff4c80e970dd4" "checksum serde_json 1.0.38 (registry+https://github.com/rust-lang/crates.io-index)" = "27dce848e7467aa0e2fcaf0a413641499c0b745452aaca1194d24dedde9e13c9" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9" +"checksum termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a8fb22f7cde82c8220e5aeacb3258ed7ce996142c77cba193f203515e26c330" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 3c72edf..080d4bd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,18 @@ version = "0.1.0" authors = ["Tyler Hallada "] edition = "2018" +[lib] +name = "icosahedron" +path = "src/lib.rs" + +[[bin]] +name = "icosahedron" +path = "src/bin.rs" + [dependencies] +byteorder = "1.3.2" +clap = "2.33.0" cgmath = { version = "0.17.0", features = ["serde"] } +rand = "0.6.5" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" diff --git a/src/bin.rs b/src/bin.rs new file mode 100644 index 0000000..f71f814 --- /dev/null +++ b/src/bin.rs @@ -0,0 +1,169 @@ +#[macro_use] +extern crate clap; +extern crate byteorder; +extern crate icosahedron; + +use std::fs::{File, metadata}; +use std::io::{BufWriter, Write}; +use std::path::Path; + +use byteorder::{WriteBytesExt, LittleEndian}; +use icosahedron::{Polyhedron}; + +fn write_to_binary_file(polyhedron: Polyhedron, path: &Path) { + let bin_file = File::create(path).expect("Can't create file"); + let mut writer = BufWriter::new(bin_file); + let write_error_message = "Error encountered while writing to binary file"; + writer.write_u32::(polyhedron.positions.len() as u32) + .expect(write_error_message); + writer.write_u32::(polyhedron.cells.len() as u32) + .expect(write_error_message); + for position in polyhedron.positions.iter() { + writer.write_f32::(position.0.x).expect(write_error_message); + writer.write_f32::(position.0.y).expect(write_error_message); + writer.write_f32::(position.0.z).expect(write_error_message); + } + for normal in polyhedron.normals.iter() { + writer.write_f32::(normal.0.x).expect(write_error_message); + writer.write_f32::(normal.0.y).expect(write_error_message); + writer.write_f32::(normal.0.z).expect(write_error_message); + } + for color in polyhedron.colors.iter() { + writer.write_f32::(color.0.x).expect(write_error_message); + writer.write_f32::(color.0.y).expect(write_error_message); + writer.write_f32::(color.0.z).expect(write_error_message); + } + for cell in polyhedron.cells.iter() { + writer.write_u32::(cell.a as u32).expect(write_error_message); + writer.write_u32::(cell.b as u32).expect(write_error_message); + writer.write_u32::(cell.c as u32).expect(write_error_message); + } +} + +fn write_to_json_file(polyhedron: Polyhedron, path: &Path) { + let mut json_file = File::create(path).expect("Can't create file"); + let json = serde_json::to_string(&polyhedron).expect("Problem serializing"); + json_file.write_all(json.as_bytes()).expect("Can't write to file"); +} + +fn generate_files(dir: &str, format: Format, truncated: bool, colored: bool, + param_list: Vec<(f32, u32)>) { + let mesh_type = if truncated { + "hexsphere" + } else { + "icosahedron" + }; + + for param in param_list { + println!( + "Generating {} with radius {} and detail {}...", + mesh_type, param.0, param.1 + ); + + + let polyhedron = if truncated { + let mut hexsphere = Polyhedron::new_truncated_isocahedron(param.0, param.1); + hexsphere.compute_triangle_normals(); + hexsphere + } else { + let mut icosahedron = Polyhedron::new_isocahedron(param.0, param.1); + icosahedron.compute_triangle_normals(); + icosahedron + }; + + let colored_polyhedron = if colored { + let mut colored = Polyhedron::new(); + colored.unique_vertices(polyhedron); + colored.assign_random_face_colors(); + colored + } else { + polyhedron + }; + + println!("triangles: {}", colored_polyhedron.cells.len()); + println!("vertices: {}", colored_polyhedron.positions.len()); + + let filename = Path::new(dir).join( + format!("{}_r{}_d{}.{}", mesh_type, param.0, param.1, format.extension()) + ); + match format { + Format::Bin => write_to_binary_file(colored_polyhedron, &filename), + Format::Json => write_to_json_file(colored_polyhedron, &filename), + }; + } +} + +arg_enum!{ + #[derive(Debug)] + enum Format { + Json, + Bin, + } +} + +impl Format { + fn extension(&self) -> String { + match self { + Format::Bin => "bin".to_string(), + Format::Json => "json".to_string(), + } + } +} + +fn main() { + let dir_exists = |path: String| { + let path_clone = path.clone(); + match metadata(path) { + Ok(metadata) => { + if metadata.is_dir() { + Ok(()) + } else { + Err(String::from(format!("Output '{}' is not a directory", &path_clone))) + } + } + Err(_) => Err(String::from(format!("Directory '{}' doesn't exist", &path_clone))) + } + }; + + let matches = clap_app!(icosahedron => + (version: "1.0") + (author: "Tyler Hallada ") + (about: "Generates 3D icosahedra meshes") + (@arg truncated: -t --truncated "Generate truncated icosahedra (hexspheres).") + (@arg colored: -c --colored "Assigns a random color to every face \ + (increases vertices count).") + (@arg detail: -d --detail +takes_value default_value("7") + "Maximum detail level to generate. \ + Each level multiplies the number of triangles by 4.") + (@arg radius: -r --radius +takes_value default_value("1.0") + "Radius of the polyhedron,") + (@arg format: -f --format +takes_value possible_values(&Format::variants()) + default_value("Bin") + "Format to write the files in.") + (@arg output: [OUTPUT] {dir_exists} default_value("output/") + "Directory to write the output files to.") + ).get_matches(); + + let truncated = matches.is_present("truncated"); + let colored = matches.is_present("colored"); + let detail = value_t!(matches.value_of("detail"), u32).unwrap_or(7); + let radius = value_t!(matches.value_of("radius"), f32).unwrap_or(1.0); + let format = value_t!(matches.value_of("format"), Format).unwrap_or(Format::Bin); + let output = matches.value_of("output").unwrap_or("output/"); + + let param_list = |detail: u32, radius: f32| -> Vec<(f32, u32)> { + let mut params = vec![]; + for detail in 0..(detail + 1) { + params.push((radius, detail)); + } + params + }; + + generate_files( + output, + format, + truncated, + colored, + param_list(detail, radius), + ); +} diff --git a/src/main.rs b/src/lib.rs similarity index 82% rename from src/main.rs rename to src/lib.rs index 9017d1d..f477fa6 100644 --- a/src/main.rs +++ b/src/lib.rs @@ -1,23 +1,22 @@ extern crate cgmath; +extern crate rand; use std::collections::HashMap; -use std::fs::File; -use std::io::Write; use std::ops::AddAssign; -use std::path::Path; use cgmath::prelude::*; use cgmath::Vector3; +use rand::prelude::*; use serde::ser::{SerializeSeq, Serializer}; use serde::Serialize; const VERT_CACHE_PRECISION: f32 = 10000_f32; #[derive(Debug)] -struct Triangle { - a: usize, - b: usize, - c: usize, +pub struct Triangle { + pub a: usize, + pub b: usize, + pub c: usize, } impl Triangle { @@ -41,13 +40,14 @@ impl Serialize for Triangle { } #[derive(Debug)] -struct ArraySerializedVector(Vector3); +pub struct ArraySerializedVector(pub Vector3); #[derive(Serialize, Debug)] -struct Polyhedron { - positions: Vec, - cells: Vec, - normals: Vec, +pub struct Polyhedron { + pub positions: Vec, + pub cells: Vec, + pub normals: Vec, + pub colors: Vec, #[serde(skip)] added_vert_cache: HashMap<(i32, i32, i32), usize>, faces: Vec>, @@ -74,17 +74,18 @@ impl AddAssign for ArraySerializedVector { } impl Polyhedron { - fn new() -> Polyhedron { + pub fn new() -> Polyhedron { Polyhedron { positions: vec![], cells: vec![], normals: vec![], + colors: vec![], added_vert_cache: HashMap::new(), faces: vec![], } } - fn new_isocahedron(radius: f32, detail: usize) -> Polyhedron { + pub fn new_isocahedron(radius: f32, detail: u32) -> Polyhedron { let t = (1.0 + (5.0 as f32).sqrt()) / 2.0; let mut base_isocahedron = Polyhedron { positions: vec![], @@ -111,6 +112,7 @@ impl Polyhedron { Triangle::new(9, 8, 1), ], normals: vec![], + colors: vec![], added_vert_cache: HashMap::new(), faces: vec![], }; @@ -129,17 +131,18 @@ impl Polyhedron { let mut subdivided = Polyhedron::new(); subdivided.subdivide(base_isocahedron, radius, detail); + subdivided.triangles_to_faces(); subdivided } - fn new_truncated_isocahedron(radius: f32, detail: usize) -> Polyhedron { + pub fn new_truncated_isocahedron(radius: f32, detail: u32) -> Polyhedron { let isocahedron = Polyhedron::new_isocahedron(radius, detail); let mut truncated_isocahedron = Polyhedron::new(); truncated_isocahedron.truncated(isocahedron); truncated_isocahedron } - fn subdivide(&mut self, other: Polyhedron, radius: f32, detail: usize) { + fn subdivide(&mut self, other: Polyhedron, radius: f32, detail: u32) { for triangle in other.cells { let a = other.positions[triangle.a].0; let b = other.positions[triangle.b].0; @@ -148,15 +151,21 @@ impl Polyhedron { } } + fn triangles_to_faces(&mut self) { + for (cell_index, _) in self.cells.iter().enumerate() { + self.faces.push(vec![cell_index]); + } + } + fn subdivide_triangle( &mut self, a: Vector3, b: Vector3, c: Vector3, radius: f32, - detail: usize, + detail: u32, ) { - let cols = 2usize.pow(detail as u32); + let cols = 2usize.pow(detail); let mut new_vertices: Vec>> = vec![]; for i in 0..=cols { @@ -207,6 +216,8 @@ impl Polyhedron { self.positions.push(ArraySerializedVector(vertex)); self.normals .push(ArraySerializedVector(Vector3::new(0.0, 0.0, 0.0))); + self.colors + .push(ArraySerializedVector(Vector3::new(1.0, 1.0, 1.0))); let added_index = self.positions.len() - 1; self.added_vert_cache.insert(vertex_key, added_index); return added_index; @@ -220,7 +231,6 @@ impl Polyhedron { let mut mid_centroid_cache: HashMap<(usize, usize, usize), Vector3> = HashMap::new(); let mut hex_count = 0; let mut pent_count = 0; - let mut count = 0; for i in 0..original_vert_count { let faces = &vert_to_faces[&i]; if faces.len() == 6 { @@ -285,6 +295,34 @@ impl Polyhedron { println!("pentagons: {}", pent_count); } + pub fn unique_vertices(&mut self, other: Polyhedron) { + for triangle in other.cells { + let vertex_a = other.positions[triangle.a].0; + let vertex_b = other.positions[triangle.b].0; + let vertex_c = other.positions[triangle.c].0; + let normal_a = other.normals[triangle.a].0; + let normal_b = other.normals[triangle.b].0; + let normal_c = other.normals[triangle.c].0; + + self.positions.push(ArraySerializedVector(vertex_a)); + self.positions.push(ArraySerializedVector(vertex_b)); + self.positions.push(ArraySerializedVector(vertex_c)); + self.normals.push(ArraySerializedVector(normal_a)); + self.normals.push(ArraySerializedVector(normal_b)); + self.normals.push(ArraySerializedVector(normal_c)); + self.colors + .push(ArraySerializedVector(Vector3::new(1.0, 1.0, 1.0))); + self.colors + .push(ArraySerializedVector(Vector3::new(1.0, 1.0, 1.0))); + self.colors + .push(ArraySerializedVector(Vector3::new(1.0, 1.0, 1.0))); + let added_index = self.positions.len() - 1; + self.cells + .push(Triangle::new(added_index - 2, added_index - 1, added_index)); + } + self.faces = other.faces; + } + fn vert_to_faces(&self) -> HashMap> { let mut vert_to_faces: HashMap> = HashMap::new(); for i in 0..self.cells.len() { @@ -375,7 +413,7 @@ impl Polyhedron { None } - fn compute_triangle_normals(&mut self) { + pub fn compute_triangle_normals(&mut self) { let origin = Vector3::new(0.0, 0.0, 0.0); for i in 0..self.cells.len() { let vertex_a = &self.positions[self.cells[i].a].0; @@ -406,7 +444,7 @@ impl Polyhedron { } } - fn compute_face_normals(&mut self) { + pub fn compute_face_normals(&mut self) { let origin = Vector3::new(0.0, 0.0, 0.0); for i in 0..self.faces.len() { let first_cell = &self.cells[self.faces[i][0]]; @@ -442,6 +480,31 @@ impl Polyhedron { *normal = ArraySerializedVector(normal.0.normalize()); } } + + pub fn assign_random_face_colors(&mut self) { + let mut rng = rand::thread_rng(); + for i in 0..self.faces.len() { + let face_color = Vector3::new(rng.gen(), rng.gen(), rng.gen()); + + for c in 0..self.faces[i].len() { + let face_cell = &self.cells[self.faces[i][c]]; + + self.colors[face_cell.a] = ArraySerializedVector(face_color); + self.colors[face_cell.b] = ArraySerializedVector(face_color); + self.colors[face_cell.c] = ArraySerializedVector(face_color); + } + } + } + + pub fn export_cells(&self) -> Vec { + let mut cell_vec: Vec = vec![]; + for cell in &self.cells { + cell_vec.push(cell.a as u32); + cell_vec.push(cell.b as u32); + cell_vec.push(cell.c as u32); + } + cell_vec + } } fn calculate_centroid(pa: Vector3, pb: Vector3, pc: Vector3) -> Vector3 { @@ -461,71 +524,3 @@ fn find_center_of_triangles( center_point /= triangle_indices.len() as f32; center_point } - -fn generate_icosahedron_files(dir: &str, param_list: Vec<(f32, usize)>) { - for param in param_list { - println!( - "Generating icosahedron with radius {} and detail {}...", - param.0, param.1 - ); - let filename = Path::new(dir).join(format!("icosahedron_r{}_d{}.json", param.0, param.1)); - let mut file = File::create(filename).expect("Can't create file"); - let mut icosahedron = Polyhedron::new_isocahedron(param.0, param.1); - icosahedron.compute_triangle_normals(); - println!("triangles: {}", icosahedron.cells.len()); - println!("vertices: {}", icosahedron.positions.len()); - let icosahedron_json = serde_json::to_string(&icosahedron).expect("Problem serializing"); - file.write_all(icosahedron_json.as_bytes()) - .expect("Can't write to file"); - } -} - -fn generate_hexsphere_files(dir: &str, param_list: Vec<(f32, usize)>) { - for param in param_list { - println!( - "Generating hexsphere with radius {} and detail {}...", - param.0, param.1 - ); - let filename = Path::new(dir).join(format!("hexsphere_r{}_d{}.json", param.0, param.1)); - let mut file = File::create(filename).expect("Can't create file"); - let mut hexsphere = Polyhedron::new_truncated_isocahedron(param.0, param.1); - hexsphere.compute_triangle_normals(); - // hexsphere.compute_face_normals(); - println!("triangles: {}", hexsphere.cells.len()); - println!("vertices: {}", hexsphere.positions.len()); - let hexsphere_json = serde_json::to_string(&hexsphere).expect("Problem serializing"); - file.write_all(hexsphere_json.as_bytes()) - .expect("Can't write to file"); - } -} - -fn main() { - generate_hexsphere_files( - "output/", - vec![ - (1.0, 0), - (1.0, 1), - (1.0, 2), - (1.0, 3), - (1.0, 4), - (1.0, 5), - (1.0, 6), - (1.0, 7), - // (1.0, 8), - // (1.0, 9), - ], - ); - generate_icosahedron_files( - "output/", - vec![ - (1.0, 0), - (1.0, 1), - (1.0, 2), - (1.0, 3), - (1.0, 4), - (1.0, 5), - (1.0, 6), - (1.0, 7), - ], - ); -}