Initial commit: code and output

This commit is contained in:
Tyler Hallada 2019-02-18 00:20:14 -05:00
commit ebc9fdfdb2
20 changed files with 781 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
/target
**/*.rs.bk

309
Cargo.lock generated Normal file
View File

@ -0,0 +1,309 @@
[[package]]
name = "approx"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "autocfg"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bitflags"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cgmath"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.2.6 (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)",
]
[[package]]
name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "fuchsia-cprng"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "icosahedron"
version = "0.1.0"
dependencies = [
"cgmath 0.17.0 (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)",
]
[[package]]
name = "itoa"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "libc"
version = "0.2.48"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "num-traits"
version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "proc-macro2"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "quote"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_chacha"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_core"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand_hc"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_isaac"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_jitter"
version = "0.1.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)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_os"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)",
"rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_pcg"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rand_xorshift"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rdrand"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rustc_version"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "ryu"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "semver"
version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "semver-parser"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"serde_derive 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive"
version = "1.0.88"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
version = "1.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.88 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "syn"
version = "0.15.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (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 = "winapi"
version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum approx 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3c57ff1a5b00753647aebbbcf4ea67fa1e711a65ea7a30eb90dbf07de2485aee"
"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 cgmath 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)" = "283944cdecc44bf0b8dd010ec9af888d3b4f142844fdbe026c20ef68148d6fe7"
"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 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"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4"
"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08"
"checksum rand_jitter 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b9ea758282efe12823e0d952ddb269d2e1897227e464919a554f2a03ef1b832"
"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d"
"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 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"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
"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 syn 0.15.26 (registry+https://github.com/rust-lang/crates.io-index)" = "f92e629aa1d9c827b2bb8297046c1ccffc57c99b947a680d3ccff1f136a3bee9"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"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"

10
Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "icosahedron"
version = "0.1.0"
authors = ["Tyler Hallada <tyler@hallada.net>"]
edition = "2018"
[dependencies]
cgmath = { version = "0.17.0", features = ["serde"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

18
README.md Normal file
View File

@ -0,0 +1,18 @@
Still a work in progress.
Generates the shapes and then serializes them to a JSON file with a list of
vertices (`positions`) and a list of triangle faces (`cells`) that index into
the list of vertices. Suitable for input into [Three.js's
BufferGeometry](https://threejs.org/docs/#api/en/core/BufferGeometry) or
[regl](https://github.com/regl-project/regl/blob/gh-pages/example/camera.js).
Icosahedrons can be generated significantly faster than Three.js's version in
JavaScript (which I pretty much copied into Rust).
Trunacated icosahedrons (I call them hexspheres) are a bit slower to generate
since they are made by generating a icosahedron and then subdividing it into
hexagon and pentagon faces. I still have some work to do to improve that code.
I'm still having issues rendering hexspheres of detail level 5 and higher and
icosahedrons of detail level of 7 and higher, so I'm not sure if those are
accurate.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
{"positions":[[-0.8506508,0.0,0.5257311],[0.0,0.5257311,0.8506508],[-0.5257311,0.8506508,0.0],[0.5257311,0.8506508,0.0],[0.0,0.5257311,-0.8506508],[-0.8506508,0.0,-0.5257311],[0.8506508,0.0,0.5257311],[0.0,-0.5257311,0.8506508],[-0.5257311,-0.8506508,0.0],[0.0,-0.5257311,-0.8506508],[0.8506508,0.0,-0.5257311],[0.5257311,-0.8506508,0.0]],"cells":[[0,1,2],[1,3,2],[3,4,2],[4,5,2],[5,0,2],[1,6,3],[0,7,1],[5,8,0],[4,9,5],[3,10,4],[6,7,11],[7,8,11],[8,9,11],[9,10,11],[10,6,11],[6,1,7],[7,0,8],[8,5,9],[9,4,10],[10,3,6]]}

View File

@ -0,0 +1 @@
{"positions":[[-0.809017,0.5,0.309017],[-0.309017,0.809017,0.5],[-0.5257311,0.8506508,0.0],[-0.5,0.309017,0.809017],[-0.8506508,0.0,0.5257311],[0.0,0.5257311,0.8506508],[0.0,1.0,0.0],[0.309017,0.809017,0.5],[0.5257311,0.8506508,0.0],[-0.309017,0.809017,-0.5],[0.309017,0.809017,-0.5],[0.0,0.5257311,-0.8506508],[-0.809017,0.5,-0.309017],[-0.5,0.309017,-0.809017],[-0.8506508,0.0,-0.5257311],[-1.0,0.0,0.0],[0.809017,0.5,0.309017],[0.5,0.309017,0.809017],[0.8506508,0.0,0.5257311],[0.0,0.0,1.0],[-0.5,-0.309017,0.809017],[0.0,-0.5257311,0.8506508],[-0.809017,-0.5,0.309017],[-0.809017,-0.5,-0.309017],[-0.5257311,-0.8506508,0.0],[-0.5,-0.309017,-0.809017],[0.0,0.0,-1.0],[0.0,-0.5257311,-0.8506508],[0.5,0.309017,-0.809017],[0.809017,0.5,-0.309017],[0.8506508,0.0,-0.5257311],[0.809017,-0.5,0.309017],[0.309017,-0.809017,0.5],[0.5257311,-0.8506508,0.0],[0.5,-0.309017,0.809017],[0.0,-1.0,0.0],[-0.309017,-0.809017,0.5],[0.309017,-0.809017,-0.5],[-0.309017,-0.809017,-0.5],[0.809017,-0.5,-0.309017],[0.5,-0.309017,-0.809017],[1.0,0.0,0.0]],"cells":[[0,1,2],[0,3,1],[4,3,0],[3,5,1],[1,6,2],[1,7,6],[5,7,1],[7,8,6],[6,9,2],[6,10,9],[8,10,6],[10,11,9],[9,12,2],[9,13,12],[11,13,9],[13,14,12],[12,0,2],[12,15,0],[14,15,12],[15,4,0],[7,16,8],[7,17,16],[5,17,7],[17,18,16],[3,19,5],[3,20,19],[4,20,3],[20,21,19],[15,22,4],[15,23,22],[14,23,15],[23,24,22],[13,25,14],[13,26,25],[11,26,13],[26,27,25],[10,28,11],[10,29,28],[8,29,10],[29,30,28],[31,32,33],[31,34,32],[18,34,31],[34,21,32],[32,35,33],[32,36,35],[21,36,32],[36,24,35],[35,37,33],[35,38,37],[24,38,35],[38,27,37],[37,39,33],[37,40,39],[27,40,37],[40,30,39],[39,31,33],[39,41,31],[30,41,39],[41,18,31],[34,19,21],[34,17,19],[18,17,34],[17,5,19],[36,22,24],[36,20,22],[21,20,36],[20,4,22],[38,25,27],[38,23,25],[24,23,38],[23,14,25],[40,28,30],[40,26,28],[27,26,40],[26,11,28],[41,16,18],[41,29,16],[30,29,41],[29,8,16]]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

427
src/main.rs Normal file
View File

@ -0,0 +1,427 @@
extern crate cgmath;
use std::collections::HashMap;
use std::fs::File;
use std::io::Write;
use std::path::Path;
use cgmath::prelude::*;
use cgmath::Vector3;
use serde::ser::{SerializeSeq, Serializer};
use serde::Serialize;
#[derive(Debug)]
struct Triangle {
a: usize,
b: usize,
c: usize,
}
impl Triangle {
fn new(a: usize, b: usize, c: usize) -> Triangle {
Triangle { a, b, c }
}
}
impl Serialize for Triangle {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let vec_indices = vec![self.a, self.b, self.c];
let mut seq = serializer.serialize_seq(Some(vec_indices.len()))?;
for index in vec_indices {
seq.serialize_element(&index)?;
}
seq.end()
}
}
#[derive(Debug)]
struct ArraySerializedVector(Vector3<f32>);
#[derive(Serialize, Debug)]
struct Polyhedron {
positions: Vec<ArraySerializedVector>,
cells: Vec<Triangle>,
}
impl Serialize for ArraySerializedVector {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let values = vec![self.0.x, self.0.y, self.0.z];
let mut seq = serializer.serialize_seq(Some(values.len()))?;
for value in values {
seq.serialize_element(&value)?;
}
seq.end()
}
}
impl Polyhedron {
fn new() -> Polyhedron {
Polyhedron {
positions: vec![],
cells: vec![],
}
}
fn new_isocahedron(radius: f32, detail: usize) -> Polyhedron {
let t = (1.0 + (5.0 as f32).sqrt()) / 2.0;
let base_isocahedron = Polyhedron {
positions: vec![
ArraySerializedVector(Vector3::new(-1.0, t, 0.0)),
ArraySerializedVector(Vector3::new(1.0, t, 0.0)),
ArraySerializedVector(Vector3::new(-1.0, -t, 0.0)),
ArraySerializedVector(Vector3::new(1.0, -t, 0.0)),
ArraySerializedVector(Vector3::new(0.0, -1.0, t)),
ArraySerializedVector(Vector3::new(0.0, 1.0, t)),
ArraySerializedVector(Vector3::new(0.0, -1.0, -t)),
ArraySerializedVector(Vector3::new(0.0, 1.0, -t)),
ArraySerializedVector(Vector3::new(t, 0.0, -1.0)),
ArraySerializedVector(Vector3::new(t, 0.0, 1.0)),
ArraySerializedVector(Vector3::new(-t, 0.0, -1.0)),
ArraySerializedVector(Vector3::new(-t, 0.0, 1.0)),
],
cells: vec![
Triangle::new(0, 11, 5),
Triangle::new(0, 5, 1),
Triangle::new(0, 1, 7),
Triangle::new(0, 7, 10),
Triangle::new(0, 10, 11),
Triangle::new(1, 5, 9),
Triangle::new(5, 11, 4),
Triangle::new(11, 10, 2),
Triangle::new(10, 7, 6),
Triangle::new(7, 1, 8),
Triangle::new(3, 9, 4),
Triangle::new(3, 4, 2),
Triangle::new(3, 2, 6),
Triangle::new(3, 6, 8),
Triangle::new(3, 8, 9),
Triangle::new(4, 9, 5),
Triangle::new(2, 4, 11),
Triangle::new(6, 2, 10),
Triangle::new(8, 6, 7),
Triangle::new(9, 8, 1),
],
};
let mut subdivided = Polyhedron::new();
subdivided.subdivide(base_isocahedron, radius, detail);
subdivided
}
fn new_dual_isocahedron(radius: f32, detail: usize) -> Polyhedron {
let isocahedron = Polyhedron::new_isocahedron(radius, detail);
let mut dual_isocahedron = Polyhedron::new();
dual_isocahedron.dual(isocahedron);
dual_isocahedron
}
fn subdivide(&mut self, other: Polyhedron, radius: f32, detail: usize) {
// TODO: maybe make this part of the polygon stuct to avoid having to pass it around
let mut added_vert_cache: HashMap<(i32, i32, i32), usize> = HashMap::new();
let precision = 10_f32.powi(4);
for triangle in other.cells {
let a = other.positions[triangle.a].0;
let b = other.positions[triangle.b].0;
let c = other.positions[triangle.c].0;
self.subdivide_triangle(a, b, c, radius, detail, precision, &mut added_vert_cache);
}
}
fn subdivide_triangle(
&mut self,
a: Vector3<f32>,
b: Vector3<f32>,
c: Vector3<f32>,
radius: f32,
detail: usize,
precision: f32,
added_vert_cache: &mut HashMap<(i32, i32, i32), usize>,
) {
let cols = 2usize.pow(detail as u32);
let mut new_vertices: Vec<Vec<Vector3<f32>>> = vec![];
for i in 0..=cols {
new_vertices.push(vec![]);
let aj = a.clone().lerp(c, i as f32 / cols as f32);
let bj = b.clone().lerp(c, i as f32 / cols as f32);
let rows = cols - i;
for j in 0..=rows {
if j == 0 && i == cols {
new_vertices[i].push(aj.normalize() * radius);
} else {
new_vertices[i]
.push(aj.clone().lerp(bj, j as f32 / rows as f32).normalize() * radius);
}
}
}
for i in 0..cols {
for j in 0..2 * (cols - i) - 1 {
let k = j / 2;
let mut triangle = Triangle { a: 0, b: 0, c: 0 };
if j % 2 == 0 {
triangle.a =
self.add_position(new_vertices[i][k + 1], precision, added_vert_cache);
triangle.b =
self.add_position(new_vertices[i + 1][k], precision, added_vert_cache);
triangle.c = self.add_position(new_vertices[i][k], precision, added_vert_cache);
} else {
triangle.a =
self.add_position(new_vertices[i][k + 1], precision, added_vert_cache);
triangle.b =
self.add_position(new_vertices[i + 1][k + 1], precision, added_vert_cache);
triangle.c =
self.add_position(new_vertices[i + 1][k], precision, added_vert_cache);
}
self.cells.push(triangle);
}
}
}
fn add_position(
&mut self,
vertex: Vector3<f32>,
precision: f32,
added_vert_cache: &mut HashMap<(i32, i32, i32), usize>,
) -> usize {
let vertex_key = (
(vertex.x * precision).round() as i32,
(vertex.y * precision).round() as i32,
(vertex.z * precision).round() as i32,
);
if let Some(added_vert_index) = added_vert_cache.get(&vertex_key) {
return *added_vert_index;
} else {
self.positions.push(ArraySerializedVector(vertex));
let added_index = self.positions.len() - 1;
added_vert_cache.insert(vertex_key, added_index);
return added_index;
}
}
fn dual(&mut self, other: Polyhedron) {
let vert_to_faces = other.vert_to_faces();
let original_vert_count = other.positions.len();
let triangle_centroids = other.triangle_centroids();
let mut mid_centroid_cache: HashMap<(usize, usize), Vector3<f32>> = HashMap::new();
let mut hex_count = 0;
let mut pent_count = 0;
for i in 0..original_vert_count {
let faces = &vert_to_faces[&i];
if faces.len() == 6 {
hex_count += 1;
} else {
pent_count += 1;
}
let center_point = find_center_of_triangles(faces, &triangle_centroids);
for face_index in faces {
let triangle = &other.cells[*face_index];
let other_verts: Vec<usize> = vec![triangle.a, triangle.b, triangle.c]
.drain(..)
.filter(|vert| *vert != i)
.collect();
let sorted_triangle = Triangle::new(i, other_verts[0], other_verts[1]);
let centroid = triangle_centroids[face_index];
let mid_b_centroid = other.calculate_mid_centroid(
sorted_triangle.b,
faces,
centroid,
&triangle_centroids,
&mut mid_centroid_cache,
);
let mid_c_centroid = other.calculate_mid_centroid(
sorted_triangle.c,
faces,
centroid,
&triangle_centroids,
&mut mid_centroid_cache,
);
let positions_start = self.positions.len();
// TODO: remove duplication here:
// push all triangle_centroids at beginning, same index as face_index
// push center_point once in outer loop and save index
// (is it okay if vertices show up in positions out of order like that?)
// -- yes, I think it is okay
self.positions.push(ArraySerializedVector(center_point));
self.positions.push(ArraySerializedVector(centroid));
self.positions.push(ArraySerializedVector(mid_b_centroid));
self.positions.push(ArraySerializedVector(mid_c_centroid));
self.cells.push(Triangle::new(
positions_start,
positions_start + 1,
positions_start + 2,
));
self.cells.push(Triangle::new(
positions_start,
positions_start + 1,
positions_start + 3,
));
}
}
println!("hexagons: {}", hex_count);
println!("pentagons: {}", pent_count);
}
fn vert_to_faces(&self) -> HashMap<usize, Vec<usize>> {
let mut vert_to_faces: HashMap<usize, Vec<usize>> = HashMap::new();
for i in 0..self.cells.len() {
let triangle = &self.cells[i];
if let Some(faces) = vert_to_faces.get_mut(&triangle.a) {
faces.push(i);
} else {
vert_to_faces.insert(triangle.a, vec![i]);
}
if let Some(faces) = vert_to_faces.get_mut(&triangle.b) {
faces.push(i);
} else {
vert_to_faces.insert(triangle.b, vec![i]);
}
if let Some(faces) = vert_to_faces.get_mut(&triangle.c) {
faces.push(i);
} else {
vert_to_faces.insert(triangle.c, vec![i]);
}
}
vert_to_faces
}
fn triangle_centroids(&self) -> HashMap<usize, Vector3<f32>> {
let mut triangle_centroids: HashMap<usize, Vector3<f32>> = HashMap::new();
for i in 0..self.cells.len() {
let a = self.positions[self.cells[i].a].0;
let b = self.positions[self.cells[i].b].0;
let c = self.positions[self.cells[i].c].0;
triangle_centroids.insert(i, calculate_centroid(a, b, c));
}
triangle_centroids
}
fn calculate_mid_centroid(
&self,
vertex_index: usize,
faces: &Vec<usize>,
centroid: Vector3<f32>,
triangle_centroids: &HashMap<usize, Vector3<f32>>,
mid_centroid_cache: &mut HashMap<(usize, usize), Vector3<f32>>,
) -> Vector3<f32> {
let adj_face_index = self.find_adjacent_face(vertex_index, faces).unwrap();
let adj_centroid = triangle_centroids[&adj_face_index];
if let Some(mid_centroid) = mid_centroid_cache.get(&(vertex_index, adj_face_index)) {
return *mid_centroid;
} else {
let mid_centroid = centroid.clone().lerp(adj_centroid, 0.5);
mid_centroid_cache.insert((vertex_index, adj_face_index), mid_centroid);
return mid_centroid;
}
}
fn find_adjacent_face(&self, vertex_index: usize, faces: &Vec<usize>) -> Option<usize> {
for face_index in faces {
let triangle = &self.cells[*face_index];
if triangle.a == vertex_index
|| triangle.b == vertex_index
|| triangle.c == vertex_index
{
return Some(*face_index);
}
}
None
}
}
fn calculate_centroid(pa: Vector3<f32>, pb: Vector3<f32>, pc: Vector3<f32>) -> Vector3<f32> {
let vab_half = (pb.clone() - pa) / 2.0;
let pab_half = pa.clone() + vab_half;
((pc.clone() - pab_half) * (1.0 / 3.0)) + pab_half
}
fn find_center_of_triangles(
triangle_indices: &Vec<usize>,
triangle_centroids: &HashMap<usize, Vector3<f32>>,
) -> Vector3<f32> {
let mut center_point: Vector3<f32> = Vector3::new(0.0, 0.0, 0.0);
for triangle_index in triangle_indices.iter() {
center_point += triangle_centroids[triangle_index];
}
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 icosahedron = Polyhedron::new_isocahedron(param.0, param.1);
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 hexsphere = Polyhedron::new_dual_isocahedron(param.0, param.1);
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),
],
);
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),
],
);
}