// Polyeder is a list: [faces, vertices] // faces is a list of f32 Vectors // vertices is a list of f32 Vectors const EPS = 1e-3; const PHI = (1. + sqrt(5.)) / 2.; fn roll(v, i) { if i == 0 { return v; } if i == 1 { return Vector(v[1], v[2], v[0]); } if i == 2 { return Vector(v[2], v[0], v[1]); } throw "invalid roll"; } fn max(a, b) { if a < b { return b; } else { return a; } } fn normalize(poly) { let max_norm = 0.; for v in poly.vertices { max_norm = max(max_norm, v.norm()); } let norm_v = (|s, v| v * s).curry(1. / max_norm); let norm_f = (|s, v| v * s).curry(1. * max_norm); return #{faces: poly.faces.map(norm_f), vertices: poly.vertices.map(norm_v)}; } fn add_face(faces, d, l) { let a = d / (d.norm() * l); let face_exists = false; for f in faces { if (f - a).norm() < global::EPS { face_exists = true; break; } } if !face_exists { faces.push(a); } return faces; } // Input is an Array of Vertices. fn autoface(v) { // WARNING: ONLY WORKS IF ALL EDGES HAVE EQUAL LENGTH let faces = []; let edge_length = 1e10; for (a, ai) in v { for (b, bi) in v { if ai == bi { continue; } let l = (a - b).norm(); if l < edge_length { edge_length = l; } } } for (a, ai) in v { for (b, bi) in v { if bi <= ai || (a - b).norm() > (edge_length + global::EPS) { continue; } for (c, ci) in v { if ci <= bi || (a - c).norm() > (edge_length + global::EPS) { continue; } let n = (b - a).cross(c - a); n /= n.norm(); let d = n.dot(a); if d < 0. { n = -n; d = -d; } let f = true; for p in v { if n.dot(p) > (d + global::EPS) { f = false; break; } } if f { faces = add_face(faces, n, d); } } } } print("autoface: "); print(v.len); print(faces.len); return #{faces: faces, vertices: v}; } fn dual(poly) { return #{vertices: poly.faces, faces: poly.vertices}; } fn make_obj(poly) { make_obj(poly, 0.05) } fn make_obj(poly, r) { poly = normalize(poly); // Union( // make_vertices(poly, r) // make_edges(poly, r) // + [make_solid(poly)] // ) make_solid(poly).smooth_exponential(100.) } fn make_vertices(poly, radius) { let vertices = []; for v in poly.vertices { vertices.push(Sphere(radius).translate(v[0], v[1], v[2])); } vertices } fn make_edges(poly, radius) { let lines = []; for face in poly.faces { let p = []; for (b, bi) in poly.vertices { if face.dot(b) > (1. - global::EPS) { p.push(bi); } } for (c, ci) in p { let p_copy = p; for d in p_copy.split(ci + 1) { let f = true; for e in p { if e != c && e != d && poly.vertices[c].cross(poly.vertices[d]).dot(poly.vertices[e]) < 0. { f = false; break; } } if f { lines.push(Capsule(radius, poly.vertices[c], poly.vertices[d])); } } } } lines } fn make_solid(poly) { let planes = []; for f in poly.faces { let d = f.norm(); planes.push(Plane(f / d, -1./d)); } return Intersection(planes); } fn addpointsevensgn(p) { let v = []; for m in [Vector( 1., 1., 1.), Vector(-1., -1., 1.), Vector(-1., 1.,-1.), Vector( 1., -1.,-1.)] { v.push(m * p); } return v; } fn addpointssgn(a, s) { let v = [a]; if s[0] != 0. { v += addpointssgn(a * Vector(-1.,1.,1.), s * Vector(0.,1.,1.)); } if s[1] != 0. { v += addpointssgn(a * Vector(1.,-1.,1.), s * Vector(0.,0.,1.)); } if s[2] != 0. { v.push(a * Vector(1.,1.,-1.)); } return v; } fn addevenpermssgn(a, s) { let v = []; for r in 0..3 { v += addpointssgn(roll(a, r), roll(s, r)); } return v; } fn addevenperms(a) { let v = []; for s in 0..3 { v.push(roll(a, s)) } return v; } fn addevenpermsevensgn(a) { let v = addevenperms(a); v += addevenperms(a * Vector(-1., -1., 1.)); v += addevenperms(a * Vector(-1., 1., -1.)); v += addevenperms(a * Vector( 1., -1., -1.)); return v; } fn addpermssgn(a, s) { let v = addevenpermssgn(a, s); v + addevenpermssgn(Vector(a[0], a[2], a[1]), Vector(s[0], s[2], s[1])) } fn addpermsaltsgn(a) { let v = addevenpermsevensgn(a); v + addevenpermsevensgn(Vector(a[0], a[2], -a[1])) } // Platonic Solids fn tetrahedron() { let v = addpointsevensgn(Vector(1., 1., 1.)); return autoface(v); } fn hexahedron() { let v = addpointssgn(Vector(1., 1., 1.), Vector(1., 1., 1.)); return autoface(v); } fn octahedron() { let v = addevenpermssgn(Vector(1.,0.,0.), Vector(1.,0.,0.)); return autoface(v); } fn dodecahedron() { let v = addpointssgn(Vector(1.,1.,1.), Vector(1.,1.,1.)); v += addevenpermssgn(Vector(0., 1. / global::PHI, global::PHI) , Vector(0.,1.,1.)); return autoface(v); } fn icosahedron() { let v = addevenpermssgn(Vector(0., 1., global::PHI) , Vector(0.,1.,1.)); return autoface(v); } // Archimedian Solids fn cuboctahedron() { let v = addevenpermssgn(Vector(0., 1., 1.), Vector(0., 1., 1.)); return autoface(v); } fn icosidodecahedron() { let v = addevenpermssgn(Vector(0., 0., 2. * global::PHI), Vector(0., 0., 1.)); v += addevenpermssgn(Vector(1., global::PHI, 1. + global::PHI), Vector(1., 1., 1.)); return autoface(v); } fn truncatedtetrahedron() { let v = addevenpermsevensgn(Vector(1., 1., 3.)); return autoface(v); } fn truncatedhexahedron() { let v = addevenpermssgn(Vector(sqrt(2.) - 1., 1., 1.), Vector(1., 1., 1.)); return autoface(v); } fn truncatedoctahedron() { let v = addpermssgn(Vector(0., 1., 2.), Vector(0., 1., 1.)); return autoface(v); } fn truncateddodecahedron() { let v = addevenpermssgn(Vector(0., 1. / global::PHI, 2. + global::PHI), Vector(0., 1., 1.)); v += addevenpermssgn(Vector(1. / global::PHI, global::PHI, 2. * global::PHI), Vector(1., 1., 1.)); v += addevenpermssgn(Vector(global::PHI, 2., 1. + global::PHI), Vector(1., 1., 1.)); return autoface(v); } fn truncatedicosahedron() { let v = addevenpermssgn(Vector(0., 1., 3. * global::PHI), Vector(0., 1., 1.)); v += addevenpermssgn(Vector(2., 1 + 2 * global::PHI, global::PHI), Vector(1., 1., 1.)); v += addevenpermssgn(Vector(1., 2. + global::PHI, 2. * global::PHI), Vector(1., 1., 1.)); return autoface(v); } fn rhombicuboctahedron() { let v = addevenpermssgn(Vector(1. + sqrt(2.), 1., 1.), Vector(1., 1., 1.)); return autoface(v); } fn truncatedcuboctahedron() { let v = addpermssgn(Vector(1., 1. + sqrt(2.), 1. + sqrt(2.) * 2), Vector(1., 1., 1.)); return autoface(v); } fn rhombicosidodecahedron() { let v = addevenpermssgn(Vector(1., 1., 1. + 2. * global::PHI), Vector(1., 1., 1.)); v += addevenpermssgn(Vector(global::PHI, 2. * global::PHI, 1. + global::PHI), Vector(1., 1., 1.)); v += addevenpermssgn(Vector(2. + global::PHI, 0., 1. + global::PHI), Vector(1., 0., 1.)); return autoface(v); } fn truncatedicosidodecahedron() { let v = addevenpermssgn(Vector(1. / global::PHI, 1. / global::PHI, 3. + global::PHI), Vector(1., 1., 1.)); v += addevenpermssgn(Vector(2. / global::PHI, global::PHI, 1. + 2. * global::PHI), Vector(1., 1., 1.)); v += addevenpermssgn(Vector(1. / global::PHI, 1. + global::PHI, 3. * global::PHI - 1), Vector(1., 1., 1.)); v += addevenpermssgn(Vector(2. * global::PHI - 1., 2., 2. + global::PHI), Vector(1., 1., 1.)); v += addevenpermssgn(Vector(global::PHI, 3., 2. * global::PHI), Vector(1., 1., 1.)); return autoface(v); } fn pow(a, b) { exp(b * ln(a)) } fn snubhexahedron(s) { let xi = (pow(sqrt(297.) + 17., 1./3.) - pow(sqrt(297.) - 17., 1./3.) - 1.) / 3.; let v = addpermsaltsgn(Vector(1., 1. / xi, xi) * s); return autoface(v); } fn snubdodecahedron(s) { let sqweird = sqrt(global::PHI - 5. / 27.); let ouch = pow((global::PHI + sqweird) / 2., 1. / 3.) + pow((global::PHI - sqweird) / 2., 1. / 3.); let alpha = ouch - 1. / ouch; let theta = (ouch + global::PHI + 1. / ouch) * global::PHI; let v = addevenpermsevensgn(Vector(2. * alpha, 2., 2. * theta) * s); v += addevenpermsevensgn(Vector(alpha + theta / global::PHI + global::PHI, -alpha * global::PHI + theta + 1. / global::PHI, alpha / global::PHI + theta * global::PHI - 1.) * s); v += addevenpermsevensgn(Vector(-alpha / global::PHI + theta * global::PHI + 1., -alpha + theta / global::PHI - global::PHI, alpha * global::PHI + theta - 1. / global::PHI) * s); v += addevenpermsevensgn(Vector(-alpha / global::PHI + theta * global::PHI - 1., alpha - theta / global::PHI - global::PHI, alpha * global::PHI + theta + 1 / global::PHI) * s); v += addevenpermsevensgn(Vector(alpha + theta / global::PHI - global::PHI, alpha * global::PHI - theta + 1. / global::PHI, alpha / global::PHI + theta * global::PHI + 1.) * s); return autoface(v); } // Catalan Solids fn rhombicdodecahedron() { dual(cuboctahedron()) } fn rhombictriacontahedron() { dual(icosidodecahedron()) } fn triakistetrahedron() { dual(truncatedtetrahedron()) } fn triakisoctahedron() { dual(truncatedhexahedron()) } fn tetrakishexahedron() { dual(truncatedoctahedron()) } fn triakisicosahedron() { dual(truncateddodecahedron()) } fn pentakisdodecahedron() { dual(truncatedicosahedron()) } fn deltoidalicositetrahedron() { dual(rhombicuboctahedron()) } fn disdyakisdodecahedron() { dual(truncatedcuboctahedron()) } fn deltoidalhexecontahedron() { dual(rhombicosidodecahedron()) } fn disdyakistriacontahedron() { dual(truncatedicosidodecahedron()) } fn pentagonalicositetrahedron(s) { dual(snubhexahedron(s)) } fn pentagonalhexecontahedron(s) { dual(snubdodecahedron(s)) } // Platonic Solids //make_obj(tetrahedron()) //make_obj(hexahedron()) //make_obj(octahedron()) make_obj(dodecahedron()) //make_obj(icosahedron()) // Archimedian Solids //make_obj(cuboctahedron()) //make_obj(icosidodecahedron()) //make_obj(truncatedtetrahedron()) //make_obj(truncatedhexahedron()) //make_obj(truncatedoctahedron()) //make_obj(truncateddodecahedron()) //make_obj(truncatedicosahedron()) //make_obj(rhombicuboctahedron()) //make_obj(truncatedcuboctahedron()) //make_obj(rhombicosidodecahedron()) //make_obj(truncatedicosidodecahedron()) //make_obj(snubhexahedron(-1.)) //make_obj(snubhexahedron(1.)) //make_obj(snubdodecahedron(-1.)) //make_obj(snubdodecahedron(1.)) // Catalan Solids //make_obj(rhombicdodecahedron()) //make_obj(rhombictriacontahedron()) //make_obj(triakistetrahedron()) //make_obj(triakisoctahedron()) //make_obj(tetrakishexahedron()) //make_obj(triakisicosahedron()) //make_obj(pentakisdodecahedron()) //make_obj(deltoidalicositetrahedron()) //make_obj(disdyakisdodecahedron()) //make_obj(deltoidalhexecontahedron()) //make_obj(disdyakistriacontahedron()) //make_obj(pentagonalicositetrahedron(-1.)) //make_obj(pentagonalicositetrahedron(1.)) //make_obj(pentagonalhexecontahedron(-1.)) //make_obj(pentagonalhexecontahedron(1.))
Run
Mesh