// Copyright (c) 2022 Marceline Cramer // SPDX-License-Identifier: AGPL-3.0-or-later // largely based on http://paulbourke.net/geometry/polygonise/ // TODO the Vec3 generic is pretty redundant, glam provides these types use std::collections::HashMap; #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] pub struct Vec3 { pub x: T, pub y: T, pub z: T, } impl Vec3 { pub fn new(x: T, y: T, z: T) -> Self { Self { x, y, z } } pub fn to_array(&self) -> [T; 3] { [self.x, self.y, self.z] } } impl Vec3 { pub fn to_glam(self) -> glam::Vec3A { glam::Vec3A::new(self.x, self.y, self.z) } } impl From> for Vec3 { fn from(other: Vec3) -> Self { Self { x: other.x as f32, y: other.y as f32, z: other.z as f32, } } } impl From> for [T; 3] { fn from(other: Vec3) -> Self { other.to_array() } } #[derive(Copy, Clone, Debug, Hash)] pub struct MarchDomain { pub min: Vec3, pub max: Vec3, } #[derive(Copy, Clone, Debug)] pub struct Vertex { pub position: Vec3, pub normal: Vec3, } // TODO support a set of march domains // TODO use index buffer // TODO cache shared vertices using HashMap> pub fn marching_cubes( scalar_field: impl Fn(i32, i32, i32) -> f32, domain: &MarchDomain, ) -> Vec { let samples = sample_corners(scalar_field, domain); let test = |corner| samples[&corner] > 0.0; // TODO this could be optimized using single-edge interpolation // TODO improve with glam vector math let interp = |cube: Vec3, edge_index| { let (c1, c2) = edge_coords(cube, edge_index); let v1 = samples[&c1]; let v2 = samples[&c2]; let p1: Vec3 = c1.into(); let p2: Vec3 = c2.into(); let mu = v1 / (v1 - v2); Vec3 { x: p1.x + mu * (p2.x - p1.x), y: p1.y + mu * (p2.y - p1.y), z: p1.z + mu * (p2.z - p1.z), } }; let mut vertices = Vec::new(); for x in domain.min.x..domain.max.x { for y in domain.min.y..domain.max.y { for z in domain.min.z..domain.max.z { let cube = Vec3::new(x, y, z); let index = configuration_index(cube, test); let edges = CUBE_CONFIGURATIONS[index]; // TODO use Paul Bourke's edge table to share a cube's triangle vertices let mut ntriangle = 0; loop { let e1 = edges[ntriangle]; if e1 < 0 { break; } let p1 = interp(cube, e1); let p2 = interp(cube, edges[ntriangle + 1]); let p3 = interp(cube, edges[ntriangle + 2]); let n = { let p1 = p1.to_glam(); let p2 = p2.to_glam(); let p3 = p3.to_glam(); let n = (p2 - p1).cross(p3 - p1).normalize(); Vec3 { x: n.x, y: n.y, z: n.z, } }; let n1 = n; let n2 = n; let n3 = n; vertices.push(Vertex { position: p1, normal: n1, }); vertices.push(Vertex { position: p2, normal: n2, }); vertices.push(Vertex { position: p3, normal: n3, }); ntriangle += 3; } } } } vertices } fn sample_corners( scalar_field: impl Fn(i32, i32, i32) -> f32, domain: &MarchDomain, ) -> HashMap, f32> { let mut samples = HashMap::new(); for x in domain.min.x..=domain.max.x { for y in domain.min.y..=domain.max.y { for z in domain.min.z..=domain.max.z { let s = scalar_field(x, y, z); let c = Vec3::new(x, y, z); samples.insert(c, s); } } } samples } #[rustfmt::skip] fn corner_coords(cube: Vec3, corner_index: i8) -> Vec3 { match corner_index { 0 => cube, 1 => Vec3 { y: cube.y + 1, ..cube }, 2 => Vec3 { x: cube.x + 1, y: cube.y + 1, ..cube }, 3 => Vec3 { x: cube.x + 1, ..cube }, 4 => Vec3 { z: cube.z + 1, ..cube }, 5 => Vec3 { y: cube.y + 1, z: cube.z + 1, ..cube }, 6 => Vec3 { x: cube.x + 1, y: cube.y + 1, z: cube.z + 1 }, 7 => Vec3 { x: cube.x + 1, z: cube.z + 1, ..cube }, index => unreachable!("invalid corner index {}", index), } } fn edge_coords(cube: Vec3, edge_index: i8) -> (Vec3, Vec3) { let c = corner_coords; match edge_index { 0 => (c(cube, 0), c(cube, 1)), 1 => (c(cube, 1), c(cube, 2)), 2 => (c(cube, 2), c(cube, 3)), 3 => (c(cube, 3), c(cube, 0)), 4 => (c(cube, 4), c(cube, 5)), 5 => (c(cube, 5), c(cube, 6)), 6 => (c(cube, 6), c(cube, 7)), 7 => (c(cube, 7), c(cube, 4)), 8 => (c(cube, 0), c(cube, 4)), 9 => (c(cube, 1), c(cube, 5)), 10 => (c(cube, 2), c(cube, 6)), 11 => (c(cube, 3), c(cube, 7)), _ => unreachable!("invalid edge index"), } } fn configuration_index(cube: Vec3, test: impl Fn(Vec3) -> bool) -> usize { let s = |cube, corner| test(corner_coords(cube, corner)) as usize; s(cube, 0) | (s(cube, 1) << 1) | (s(cube, 2) << 2) | (s(cube, 3) << 3) | (s(cube, 4) << 4) | (s(cube, 5) << 5) | (s(cube, 6) << 6) | (s(cube, 7) << 7) } // source: http://paulbourke.net/geometry/polygonise/table2.txt #[rustfmt::skip] const CUBE_CONFIGURATIONS: [[i8; 13]; 256] = [ [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 8, 3, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 9, 0, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 8, 3, 1, 8, 1, 9,-1,-1,-1,-1,-1,-1,-1], [10, 1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 8, 3, 0, 1, 2,10,-1,-1,-1,-1,-1,-1,-1], [ 9, 0, 2, 9, 2,10,-1,-1,-1,-1,-1,-1,-1], [ 3, 2, 8, 2,10, 8, 8,10, 9,-1,-1,-1,-1], [11, 2, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [11, 2, 0,11, 0, 8,-1,-1,-1,-1,-1,-1,-1], [11, 2, 3, 0, 1, 9,-1,-1,-1,-1,-1,-1,-1], [ 2, 1,11, 1, 9,11,11, 9, 8,-1,-1,-1,-1], [10, 1, 3,10, 3,11,-1,-1,-1,-1,-1,-1,-1], [ 1, 0,10, 0, 8,10,10, 8,11,-1,-1,-1,-1], [ 0, 3, 9, 3,11, 9, 9,11,10,-1,-1,-1,-1], [ 8,10, 9, 8,11,10,-1,-1,-1,-1,-1,-1,-1], [ 8, 4, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 3, 0, 4, 3, 4, 7,-1,-1,-1,-1,-1,-1,-1], [ 1, 9, 0, 8, 4, 7,-1,-1,-1,-1,-1,-1,-1], [ 9, 4, 1, 4, 7, 1, 1, 7, 3,-1,-1,-1,-1], [10, 1, 2, 8, 4, 7,-1,-1,-1,-1,-1,-1,-1], [ 2,10, 1, 0, 4, 7, 0, 7, 3,-1,-1,-1,-1], [ 4, 7, 8, 0, 2,10, 0,10, 9,-1,-1,-1,-1], [ 2, 7, 3, 2, 9, 7, 7, 9, 4, 2,10, 9,-1], [ 2, 3,11, 7, 8, 4,-1,-1,-1,-1,-1,-1,-1], [ 7,11, 4,11, 2, 4, 4, 2, 0,-1,-1,-1,-1], [ 3,11, 2, 4, 7, 8, 9, 0, 1,-1,-1,-1,-1], [ 2, 7,11, 2, 1, 7, 1, 4, 7, 1, 9, 4,-1], [ 8, 4, 7,11,10, 1,11, 1, 3,-1,-1,-1,-1], [11, 4, 7, 1, 4,11, 1,11,10, 1, 0, 4,-1], [ 3, 8, 0, 7,11, 4,11, 9, 4,11,10, 9,-1], [ 7,11, 4, 4,11, 9,11,10, 9,-1,-1,-1,-1], [ 9, 5, 4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 3, 0, 8, 4, 9, 5,-1,-1,-1,-1,-1,-1,-1], [ 5, 4, 0, 5, 0, 1,-1,-1,-1,-1,-1,-1,-1], [ 4, 8, 5, 8, 3, 5, 5, 3, 1,-1,-1,-1,-1], [ 2,10, 1, 9, 5, 4,-1,-1,-1,-1,-1,-1,-1], [ 0, 8, 3, 5, 4, 9,10, 1, 2,-1,-1,-1,-1], [10, 5, 2, 5, 4, 2, 2, 4, 0,-1,-1,-1,-1], [ 3, 4, 8, 3, 2, 4, 2, 5, 4, 2,10, 5,-1], [11, 2, 3, 9, 5, 4,-1,-1,-1,-1,-1,-1,-1], [ 9, 5, 4, 8,11, 2, 8, 2, 0,-1,-1,-1,-1], [ 3,11, 2, 1, 5, 4, 1, 4, 0,-1,-1,-1,-1], [ 8, 5, 4, 2, 5, 8, 2, 8,11, 2, 1, 5,-1], [ 5, 4, 9, 1, 3,11, 1,11,10,-1,-1,-1,-1], [ 0, 9, 1, 4, 8, 5, 8,10, 5, 8,11,10,-1], [ 3, 4, 0, 3,10, 4, 4,10, 5, 3,11,10,-1], [ 4, 8, 5, 5, 8,10, 8,11,10,-1,-1,-1,-1], [ 9, 5, 7, 9, 7, 8,-1,-1,-1,-1,-1,-1,-1], [ 0, 9, 3, 9, 5, 3, 3, 5, 7,-1,-1,-1,-1], [ 8, 0, 7, 0, 1, 7, 7, 1, 5,-1,-1,-1,-1], [ 1, 7, 3, 1, 5, 7,-1,-1,-1,-1,-1,-1,-1], [ 1, 2,10, 5, 7, 8, 5, 8, 9,-1,-1,-1,-1], [ 9, 1, 0,10, 5, 2, 5, 3, 2, 5, 7, 3,-1], [ 5, 2,10, 8, 2, 5, 8, 5, 7, 8, 0, 2,-1], [10, 5, 2, 2, 5, 3, 5, 7, 3,-1,-1,-1,-1], [11, 2, 3, 8, 9, 5, 8, 5, 7,-1,-1,-1,-1], [ 9, 2, 0, 9, 7, 2, 2, 7,11, 9, 5, 7,-1], [ 0, 3, 8, 2, 1,11, 1, 7,11, 1, 5, 7,-1], [ 2, 1,11,11, 1, 7, 1, 5, 7,-1,-1,-1,-1], [ 3, 9, 1, 3, 8, 9, 7,11,10, 7,10, 5,-1], [ 9, 1, 0,10, 7,11,10, 5, 7,-1,-1,-1,-1], [ 3, 8, 0, 7,10, 5, 7,11,10,-1,-1,-1,-1], [11, 5, 7,11,10, 5,-1,-1,-1,-1,-1,-1,-1], [10, 6, 5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 8, 3, 0,10, 6, 5,-1,-1,-1,-1,-1,-1,-1], [ 0, 1, 9, 5,10, 6,-1,-1,-1,-1,-1,-1,-1], [10, 6, 5, 9, 8, 3, 9, 3, 1,-1,-1,-1,-1], [ 1, 2, 6, 1, 6, 5,-1,-1,-1,-1,-1,-1,-1], [ 0, 8, 3, 2, 6, 5, 2, 5, 1,-1,-1,-1,-1], [ 5, 9, 6, 9, 0, 6, 6, 0, 2,-1,-1,-1,-1], [ 9, 6, 5, 3, 6, 9, 3, 9, 8, 3, 2, 6,-1], [ 3,11, 2,10, 6, 5,-1,-1,-1,-1,-1,-1,-1], [ 6, 5,10, 2, 0, 8, 2, 8,11,-1,-1,-1,-1], [ 1, 9, 0, 6, 5,10,11, 2, 3,-1,-1,-1,-1], [ 1,10, 2, 5, 9, 6, 9,11, 6, 9, 8,11,-1], [11, 6, 3, 6, 5, 3, 3, 5, 1,-1,-1,-1,-1], [ 0, 5, 1, 0,11, 5, 5,11, 6, 0, 8,11,-1], [ 0, 5, 9, 0, 3, 5, 3, 6, 5, 3,11, 6,-1], [ 5, 9, 6, 6, 9,11, 9, 8,11,-1,-1,-1,-1], [10, 6, 5, 4, 7, 8,-1,-1,-1,-1,-1,-1,-1], [ 5,10, 6, 7, 3, 0, 7, 0, 4,-1,-1,-1,-1], [ 5,10, 6, 0, 1, 9, 8, 4, 7,-1,-1,-1,-1], [ 4, 5, 9, 6, 7,10, 7, 1,10, 7, 3, 1,-1], [ 7, 8, 4, 5, 1, 2, 5, 2, 6,-1,-1,-1,-1], [ 4, 1, 0, 4, 5, 1, 6, 7, 3, 6, 3, 2,-1], [ 9, 4, 5, 8, 0, 7, 0, 6, 7, 0, 2, 6,-1], [ 4, 5, 9, 6, 3, 2, 6, 7, 3,-1,-1,-1,-1], [ 7, 8, 4, 2, 3,11,10, 6, 5,-1,-1,-1,-1], [11, 6, 7,10, 2, 5, 2, 4, 5, 2, 0, 4,-1], [11, 6, 7, 8, 0, 3, 1,10, 2, 9, 4, 5,-1], [ 6, 7,11, 1,10, 2, 9, 4, 5,-1,-1,-1,-1], [ 6, 7,11, 4, 5, 8, 5, 3, 8, 5, 1, 3,-1], [ 6, 7,11, 4, 1, 0, 4, 5, 1,-1,-1,-1,-1], [ 4, 5, 9, 3, 8, 0,11, 6, 7,-1,-1,-1,-1], [ 9, 4, 5, 7,11, 6,-1,-1,-1,-1,-1,-1,-1], [10, 6, 4,10, 4, 9,-1,-1,-1,-1,-1,-1,-1], [ 8, 3, 0, 9,10, 6, 9, 6, 4,-1,-1,-1,-1], [ 1,10, 0,10, 6, 0, 0, 6, 4,-1,-1,-1,-1], [ 8, 6, 4, 8, 1, 6, 6, 1,10, 8, 3, 1,-1], [ 9, 1, 4, 1, 2, 4, 4, 2, 6,-1,-1,-1,-1], [ 1, 0, 9, 3, 2, 8, 2, 4, 8, 2, 6, 4,-1], [ 2, 4, 0, 2, 6, 4,-1,-1,-1,-1,-1,-1,-1], [ 3, 2, 8, 8, 2, 4, 2, 6, 4,-1,-1,-1,-1], [ 2, 3,11, 6, 4, 9, 6, 9,10,-1,-1,-1,-1], [ 0,10, 2, 0, 9,10, 4, 8,11, 4,11, 6,-1], [10, 2, 1,11, 6, 3, 6, 0, 3, 6, 4, 0,-1], [10, 2, 1,11, 4, 8,11, 6, 4,-1,-1,-1,-1], [ 1, 4, 9,11, 4, 1,11, 1, 3,11, 6, 4,-1], [ 0, 9, 1, 4,11, 6, 4, 8,11,-1,-1,-1,-1], [11, 6, 3, 3, 6, 0, 6, 4, 0,-1,-1,-1,-1], [ 8, 6, 4, 8,11, 6,-1,-1,-1,-1,-1,-1,-1], [ 6, 7,10, 7, 8,10,10, 8, 9,-1,-1,-1,-1], [ 9, 3, 0, 6, 3, 9, 6, 9,10, 6, 7, 3,-1], [ 6, 1,10, 6, 7, 1, 7, 0, 1, 7, 8, 0,-1], [ 6, 7,10,10, 7, 1, 7, 3, 1,-1,-1,-1,-1], [ 7, 2, 6, 7, 9, 2, 2, 9, 1, 7, 8, 9,-1], [ 1, 0, 9, 3, 6, 7, 3, 2, 6,-1,-1,-1,-1], [ 8, 0, 7, 7, 0, 6, 0, 2, 6,-1,-1,-1,-1], [ 2, 7, 3, 2, 6, 7,-1,-1,-1,-1,-1,-1,-1], [ 7,11, 6, 3, 8, 2, 8,10, 2, 8, 9,10,-1], [11, 6, 7,10, 0, 9,10, 2, 0,-1,-1,-1,-1], [ 2, 1,10, 7,11, 6, 8, 0, 3,-1,-1,-1,-1], [ 1,10, 2, 6, 7,11,-1,-1,-1,-1,-1,-1,-1], [ 7,11, 6, 3, 9, 1, 3, 8, 9,-1,-1,-1,-1], [ 9, 1, 0,11, 6, 7,-1,-1,-1,-1,-1,-1,-1], [ 0, 3, 8,11, 6, 7,-1,-1,-1,-1,-1,-1,-1], [11, 6, 7,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [11, 7, 6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 0, 8, 3,11, 7, 6,-1,-1,-1,-1,-1,-1,-1], [ 9, 0, 1,11, 7, 6,-1,-1,-1,-1,-1,-1,-1], [ 7, 6,11, 3, 1, 9, 3, 9, 8,-1,-1,-1,-1], [ 1, 2,10, 6,11, 7,-1,-1,-1,-1,-1,-1,-1], [ 2,10, 1, 7, 6,11, 8, 3, 0,-1,-1,-1,-1], [11, 7, 6,10, 9, 0,10, 0, 2,-1,-1,-1,-1], [ 7, 6,11, 3, 2, 8, 8, 2,10, 8,10, 9,-1], [ 2, 3, 7, 2, 7, 6,-1,-1,-1,-1,-1,-1,-1], [ 8, 7, 0, 7, 6, 0, 0, 6, 2,-1,-1,-1,-1], [ 1, 9, 0, 3, 7, 6, 3, 6, 2,-1,-1,-1,-1], [ 7, 6, 2, 7, 2, 9, 2, 1, 9, 7, 9, 8,-1], [ 6,10, 7,10, 1, 7, 7, 1, 3,-1,-1,-1,-1], [ 6,10, 1, 6, 1, 7, 7, 1, 0, 7, 0, 8,-1], [ 9, 0, 3, 6, 9, 3, 6,10, 9, 6, 3, 7,-1], [ 6,10, 7, 7,10, 8,10, 9, 8,-1,-1,-1,-1], [ 8, 4, 6, 8, 6,11,-1,-1,-1,-1,-1,-1,-1], [11, 3, 6, 3, 0, 6, 6, 0, 4,-1,-1,-1,-1], [ 0, 1, 9, 4, 6,11, 4,11, 8,-1,-1,-1,-1], [ 1, 9, 4,11, 1, 4,11, 3, 1,11, 4, 6,-1], [10, 1, 2,11, 8, 4,11, 4, 6,-1,-1,-1,-1], [10, 1, 2,11, 3, 6, 6, 3, 0, 6, 0, 4,-1], [ 0, 2,10, 0,10, 9, 4,11, 8, 4, 6,11,-1], [ 2,11, 3, 6, 9, 4, 6,10, 9,-1,-1,-1,-1], [ 3, 8, 2, 8, 4, 2, 2, 4, 6,-1,-1,-1,-1], [ 2, 0, 4, 2, 4, 6,-1,-1,-1,-1,-1,-1,-1], [ 1, 9, 0, 3, 8, 2, 2, 8, 4, 2, 4, 6,-1], [ 9, 4, 1, 1, 4, 2, 4, 6, 2,-1,-1,-1,-1], [ 8, 4, 6, 8, 6, 1, 6,10, 1, 8, 1, 3,-1], [ 1, 0,10,10, 0, 6, 0, 4, 6,-1,-1,-1,-1], [ 8, 0, 3, 9, 6,10, 9, 4, 6,-1,-1,-1,-1], [10, 4, 6,10, 9, 4,-1,-1,-1,-1,-1,-1,-1], [ 9, 5, 4, 7, 6,11,-1,-1,-1,-1,-1,-1,-1], [ 4, 9, 5, 3, 0, 8,11, 7, 6,-1,-1,-1,-1], [ 6,11, 7, 4, 0, 1, 4, 1, 5,-1,-1,-1,-1], [ 6,11, 7, 4, 8, 5, 5, 8, 3, 5, 3, 1,-1], [ 6,11, 7, 1, 2,10, 9, 5, 4,-1,-1,-1,-1], [11, 7, 6, 8, 3, 0, 1, 2,10, 9, 5, 4,-1], [11, 7, 6,10, 5, 2, 2, 5, 4, 2, 4, 0,-1], [ 7, 4, 8, 2,11, 3,10, 5, 6,-1,-1,-1,-1], [ 4, 9, 5, 6, 2, 3, 6, 3, 7,-1,-1,-1,-1], [ 9, 5, 4, 8, 7, 0, 0, 7, 6, 0, 6, 2,-1], [ 4, 0, 1, 4, 1, 5, 6, 3, 7, 6, 2, 3,-1], [ 7, 4, 8, 5, 2, 1, 5, 6, 2,-1,-1,-1,-1], [ 4, 9, 5, 6,10, 7, 7,10, 1, 7, 1, 3,-1], [ 5, 6,10, 0, 9, 1, 8, 7, 4,-1,-1,-1,-1], [ 5, 6,10, 7, 0, 3, 7, 4, 0,-1,-1,-1,-1], [10, 5, 6, 4, 8, 7,-1,-1,-1,-1,-1,-1,-1], [ 5, 6, 9, 6,11, 9, 9,11, 8,-1,-1,-1,-1], [ 0, 9, 5, 0, 5, 3, 3, 5, 6, 3, 6,11,-1], [ 0, 1, 5, 0, 5,11, 5, 6,11, 0,11, 8,-1], [11, 3, 6, 6, 3, 5, 3, 1, 5,-1,-1,-1,-1], [ 1, 2,10, 5, 6, 9, 9, 6,11, 9,11, 8,-1], [ 1, 0, 9, 6,10, 5,11, 3, 2,-1,-1,-1,-1], [ 6,10, 5, 2, 8, 0, 2,11, 8,-1,-1,-1,-1], [ 3, 2,11,10, 5, 6,-1,-1,-1,-1,-1,-1,-1], [ 9, 5, 6, 3, 9, 6, 3, 8, 9, 3, 6, 2,-1], [ 5, 6, 9, 9, 6, 0, 6, 2, 0,-1,-1,-1,-1], [ 0, 3, 8, 2, 5, 6, 2, 1, 5,-1,-1,-1,-1], [ 1, 6, 2, 1, 5, 6,-1,-1,-1,-1,-1,-1,-1], [10, 5, 6, 9, 3, 8, 9, 1, 3,-1,-1,-1,-1], [ 0, 9, 1, 5, 6,10,-1,-1,-1,-1,-1,-1,-1], [ 8, 0, 3,10, 5, 6,-1,-1,-1,-1,-1,-1,-1], [10, 5, 6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [11, 7, 5,11, 5,10,-1,-1,-1,-1,-1,-1,-1], [ 3, 0, 8, 7, 5,10, 7,10,11,-1,-1,-1,-1], [ 9, 0, 1,10,11, 7,10, 7, 5,-1,-1,-1,-1], [ 3, 1, 9, 3, 9, 8, 7,10,11, 7, 5,10,-1], [ 2,11, 1,11, 7, 1, 1, 7, 5,-1,-1,-1,-1], [ 0, 8, 3, 2,11, 1, 1,11, 7, 1, 7, 5,-1], [ 9, 0, 2, 9, 2, 7, 2,11, 7, 9, 7, 5,-1], [11, 3, 2, 8, 5, 9, 8, 7, 5,-1,-1,-1,-1], [10, 2, 5, 2, 3, 5, 5, 3, 7,-1,-1,-1,-1], [ 5,10, 2, 8, 5, 2, 8, 7, 5, 8, 2, 0,-1], [ 9, 0, 1,10, 2, 5, 5, 2, 3, 5, 3, 7,-1], [ 1,10, 2, 5, 8, 7, 5, 9, 8,-1,-1,-1,-1], [ 1, 3, 7, 1, 7, 5,-1,-1,-1,-1,-1,-1,-1], [ 8, 7, 0, 0, 7, 1, 7, 5, 1,-1,-1,-1,-1], [ 0, 3, 9, 9, 3, 5, 3, 7, 5,-1,-1,-1,-1], [ 9, 7, 5, 9, 8, 7,-1,-1,-1,-1,-1,-1,-1], [ 4, 5, 8, 5,10, 8, 8,10,11,-1,-1,-1,-1], [ 3, 0, 4, 3, 4,10, 4, 5,10, 3,10,11,-1], [ 0, 1, 9, 4, 5, 8, 8, 5,10, 8,10,11,-1], [ 5, 9, 4, 1,11, 3, 1,10,11,-1,-1,-1,-1], [ 8, 4, 5, 2, 8, 5, 2,11, 8, 2, 5, 1,-1], [ 3, 2,11, 1, 4, 5, 1, 0, 4,-1,-1,-1,-1], [ 9, 4, 5, 8, 2,11, 8, 0, 2,-1,-1,-1,-1], [11, 3, 2, 9, 4, 5,-1,-1,-1,-1,-1,-1,-1], [ 3, 8, 4, 3, 4, 2, 2, 4, 5, 2, 5,10,-1], [10, 2, 5, 5, 2, 4, 2, 0, 4,-1,-1,-1,-1], [ 0, 3, 8, 5, 9, 4,10, 2, 1,-1,-1,-1,-1], [ 2, 1,10, 9, 4, 5,-1,-1,-1,-1,-1,-1,-1], [ 4, 5, 8, 8, 5, 3, 5, 1, 3,-1,-1,-1,-1], [ 5, 0, 4, 5, 1, 0,-1,-1,-1,-1,-1,-1,-1], [ 3, 8, 0, 4, 5, 9,-1,-1,-1,-1,-1,-1,-1], [ 9, 4, 5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 7, 4,11, 4, 9,11,11, 9,10,-1,-1,-1,-1], [ 3, 0, 8, 7, 4,11,11, 4, 9,11, 9,10,-1], [11, 7, 4, 1,11, 4, 1,10,11, 1, 4, 0,-1], [ 8, 7, 4,11, 1,10,11, 3, 1,-1,-1,-1,-1], [ 2,11, 7, 2, 7, 1, 1, 7, 4, 1, 4, 9,-1], [ 3, 2,11, 4, 8, 7, 9, 1, 0,-1,-1,-1,-1], [ 7, 4,11,11, 4, 2, 4, 0, 2,-1,-1,-1,-1], [ 2,11, 3, 7, 4, 8,-1,-1,-1,-1,-1,-1,-1], [ 2, 3, 7, 2, 7, 9, 7, 4, 9, 2, 9,10,-1], [ 4, 8, 7, 0,10, 2, 0, 9,10,-1,-1,-1,-1], [ 2, 1,10, 0, 7, 4, 0, 3, 7,-1,-1,-1,-1], [10, 2, 1, 8, 7, 4,-1,-1,-1,-1,-1,-1,-1], [ 9, 1, 4, 4, 1, 7, 1, 3, 7,-1,-1,-1,-1], [ 1, 0, 9, 8, 7, 4,-1,-1,-1,-1,-1,-1,-1], [ 3, 4, 0, 3, 7, 4,-1,-1,-1,-1,-1,-1,-1], [ 8, 7, 4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 8, 9,10, 8,10,11,-1,-1,-1,-1,-1,-1,-1], [ 0, 9, 3, 3, 9,11, 9,10,11,-1,-1,-1,-1], [ 1,10, 0, 0,10, 8,10,11, 8,-1,-1,-1,-1], [10, 3, 1,10,11, 3,-1,-1,-1,-1,-1,-1,-1], [ 2,11, 1, 1,11, 9,11, 8, 9,-1,-1,-1,-1], [11, 3, 2, 0, 9, 1,-1,-1,-1,-1,-1,-1,-1], [11, 0, 2,11, 8, 0,-1,-1,-1,-1,-1,-1,-1], [11, 3, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 3, 8, 2, 2, 8,10, 8, 9,10,-1,-1,-1,-1], [ 9, 2, 0, 9,10, 2,-1,-1,-1,-1,-1,-1,-1], [ 8, 0, 3, 1,10, 2,-1,-1,-1,-1,-1,-1,-1], [10, 2, 1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 8, 1, 3, 8, 9, 1,-1,-1,-1,-1,-1,-1,-1], [ 9, 1, 0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [ 8, 0, 3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1], [-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1] ];