reset files to before desktop config, added more ui cleanup, store classes, examples
This commit is contained in:
@@ -9,7 +9,6 @@ function createWindow() {
|
||||
preload: path.join(__dirname, 'preload.js'),
|
||||
}
|
||||
});
|
||||
|
||||
win.loadFile(path.join(__dirname, '../../public/index.html'));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
const replaceText = (selector, text) => {
|
||||
const element = document.getElementById(selector);
|
||||
if (element) {
|
||||
element.innerText = text;
|
||||
}
|
||||
|
||||
}
|
||||
for (const dependency of ['chrome', 'node', 'electron']) {
|
||||
replaceText(`${dependency}-version`, process.versions[dependency]);
|
||||
}
|
||||
});
|
||||
@@ -1,9 +1,10 @@
|
||||
import App from './ui/App.svelte';
|
||||
import PolycubeScene from "./ui/threedee/PolycubeScene";
|
||||
|
||||
const app = new App({
|
||||
target: document.body,
|
||||
props: {
|
||||
name: 'world'
|
||||
scene: new PolycubeScene()
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
128
src/solve.ts
Normal file
128
src/solve.ts
Normal file
@@ -0,0 +1,128 @@
|
||||
import SomaSolution from "./SomaSolution";
|
||||
import {get} from "svelte/store";
|
||||
import VoxelSpaceBigInt from "./VoxelSpaceBigInt";
|
||||
import {
|
||||
activeSolution,
|
||||
polycubes,
|
||||
showingSolution,
|
||||
solutions,
|
||||
solving,
|
||||
somaDimX,
|
||||
somaDimY,
|
||||
somaDimZ,
|
||||
totalVolume
|
||||
} from "./store";
|
||||
|
||||
const worker = new Worker('./solver/main.js', {type: 'module'});
|
||||
async function respondWasm(event: MessageEvent) {
|
||||
solutions.set(event.data.map((wasmSolution) => {
|
||||
const solnObj = new SomaSolution(somaDimX.currentVal(), somaDimY.currentVal(), somaDimZ.currentVal());
|
||||
const spaceReps = wasmSolution.split(",");
|
||||
for (let i = 0; i < spaceReps.length; i++) {
|
||||
solnObj.addSpace(new VoxelSpaceBigInt({
|
||||
id: i,
|
||||
dims: [somaDimX.currentVal(), somaDimY.currentVal(), somaDimZ.currentVal()],
|
||||
space: BigInt(parseInt(spaceReps[i])),
|
||||
color: get(polycubes)[i].getColor(),
|
||||
cullEmpty: false,
|
||||
}));
|
||||
}
|
||||
return solnObj;
|
||||
}));
|
||||
if (event.data.length > 0) {
|
||||
activeSolution.set(0);
|
||||
showingSolution.set(true);
|
||||
} else {
|
||||
showingSolution.set(false);
|
||||
activeSolution.set(null);
|
||||
}
|
||||
solving.set(false);
|
||||
}
|
||||
|
||||
function respondJs(event: MessageEvent) {
|
||||
solutions.set(event.data.solns.map(solnSpaces => {
|
||||
const solnObj = new SomaSolution(somaDimX.currentVal(), somaDimY.currentVal(), somaDimZ.currentVal());
|
||||
for (let i = 0; i < solnSpaces.length; i++) {
|
||||
solnObj.addSpace(new VoxelSpaceBigInt({
|
||||
id: i,
|
||||
dims: [somaDimX.currentVal(), somaDimY.currentVal(), somaDimZ.currentVal()],
|
||||
space: BigInt(`0b${ solnSpaces[i] }`),
|
||||
color: get(polycubes)[i].getColor(),
|
||||
cullEmpty: false,
|
||||
}));
|
||||
}
|
||||
return solnObj;
|
||||
}));
|
||||
if (event.data.length > 0) {
|
||||
activeSolution.set(0);
|
||||
showingSolution.set(true);
|
||||
} else {
|
||||
showingSolution.set(false);
|
||||
activeSolution.set(null);
|
||||
}
|
||||
solving.set(false);
|
||||
}
|
||||
|
||||
export function solve() {
|
||||
const doWasm = get(totalVolume) <= 32;
|
||||
let inputCubes;
|
||||
if (doWasm) {
|
||||
worker.onmessage = (e) => respondWasm(e);
|
||||
} else {
|
||||
worker.onmessage = (e) => respondJs(e);
|
||||
}
|
||||
inputCubes = polycubes.currentVal().map(cubeInput => cubeInput.getRaw());
|
||||
solving.set(true);
|
||||
worker.postMessage({
|
||||
type: doWasm ? 'wasm' : 'js',
|
||||
polycubes: inputCubes,
|
||||
dimX: somaDimX.currentVal(),
|
||||
dimY: somaDimY.currentVal(),
|
||||
dimZ: somaDimZ.currentVal()
|
||||
});
|
||||
}
|
||||
|
||||
// async function solveSync() {
|
||||
// const solver = new SomaSolver(somaDimX.currentVal(), somaDimY.currentVal(), somaDimZ.currentVal());
|
||||
// function showSolutionWaitUserFeedback(soln: SomaSolution) {
|
||||
// activeSolution.set(0);
|
||||
// solutions.set([soln]);
|
||||
// showingSolution.set(true);
|
||||
// return new Promise<void>((resolve) => {
|
||||
// const callback = (e: KeyboardEvent) => {
|
||||
// resolve();
|
||||
// window.removeEventListener("keydown", callback);
|
||||
// };
|
||||
// window.addEventListener("keydown", callback);
|
||||
// });
|
||||
// }
|
||||
// solver.setDebug({
|
||||
// showSoln(soln: SomaSolution) {
|
||||
// return showSolutionWaitUserFeedback(soln);
|
||||
// },
|
||||
// showSpace(cube: VoxelSpaceBoolean) {
|
||||
// const testSoln = new SomaSolution(somaDimX.currentVal(), somaDimY.currentVal(), somaDimZ.currentVal());
|
||||
// testSoln.addSpace(cube);
|
||||
// return showSolutionWaitUserFeedback(testSoln);
|
||||
// }
|
||||
// });
|
||||
// solving.set(true);
|
||||
// await solver.solve(polycubes.currentVal().map(cubeInput => new VoxelSpaceBoolean({
|
||||
// id: cubeInput.getId(),
|
||||
// dims: cubeInput.getDims(),
|
||||
// space: cubeInput.getRaw(),
|
||||
// color: cubeInput.getColor(),
|
||||
// cullEmpty: true
|
||||
// })));
|
||||
// const solns = solver.getSolutions();
|
||||
//
|
||||
// if (solns.length > 0) {
|
||||
// activeSolution.set(0);
|
||||
// solutions.set(solns);
|
||||
// showingSolution.set(true);
|
||||
// } else {
|
||||
// showingSolution.set(false);
|
||||
// activeSolution.set(null);
|
||||
// }
|
||||
// solving.set(false);
|
||||
// }
|
||||
337
src/store.ts
337
src/store.ts
@@ -1,27 +1,22 @@
|
||||
import { derived, writable } from 'svelte/store';
|
||||
import { get } from 'svelte/store';
|
||||
import SomaSolution from "./SomaSolution";
|
||||
import VoxelSpaceBigInt from "./VoxelSpaceBigInt";
|
||||
import type {DimensionDef} from "./VoxelSpaceBoolean";
|
||||
import PolycubeScene from "./ui/threedee/PolycubeScene";
|
||||
import type SomaSolution from "./SomaSolution";
|
||||
import type VoxelSpaceBigInt from "./VoxelSpaceBigInt";
|
||||
import DimStore from "./stores/DimStore";
|
||||
import PolycubeStore from "./stores/PolycubeStore";
|
||||
|
||||
export const MAX_DIMS = 20;
|
||||
export const MIN_DIMS = 1;
|
||||
|
||||
export const solving = writable(false);
|
||||
export const debug = writable(false);
|
||||
export const somaDimX = dimStore(3);
|
||||
export const somaDimY = dimStore(3);
|
||||
export const somaDimZ = dimStore(3);
|
||||
export const polycubes = polycubeStore();
|
||||
export const selectedCube = writable(0);
|
||||
export const solutions = writable([] as SomaSolution[]);
|
||||
export const activeSolution = writable<number | null>(null);
|
||||
export const showingSolution = writable(false);
|
||||
export const somaDimX = new DimStore(3);
|
||||
export const somaDimY = new DimStore(3);
|
||||
export const somaDimZ = new DimStore(3);
|
||||
export const totalVolume = derived(
|
||||
[somaDimX, somaDimY, somaDimZ],
|
||||
([$dimX, $dimY, $dimZ]: [number, number, number]) => $dimX*$dimY*$dimZ
|
||||
);
|
||||
export const polycubes = new PolycubeStore(somaDimX, somaDimY, somaDimZ);
|
||||
export const solving = writable(false);
|
||||
export const debug = writable(false);
|
||||
export const solutions = writable([] as SomaSolution[]);
|
||||
export const activeSolution = writable<number | null>(null);
|
||||
export const showingSolution = writable(false);
|
||||
export const isMaxPolycubes = derived(
|
||||
[polycubes, totalVolume],
|
||||
([$cubes, $vol]: [VoxelSpaceBigInt[], number]) => $cubes.length >= $vol
|
||||
@@ -30,221 +25,93 @@ export const isMinPolycubes = derived(
|
||||
polycubes,
|
||||
($polycubes: VoxelSpaceBigInt[]) => $polycubes.length <= 1
|
||||
);
|
||||
export const cubeScene = new PolycubeScene();
|
||||
|
||||
|
||||
function dimStore(init: number) {
|
||||
const dimStore = writable(init);
|
||||
return {
|
||||
subscribe: dimStore.subscribe,
|
||||
inc() {
|
||||
dimStore.set(get(dimStore) + 1);
|
||||
},
|
||||
dec() {
|
||||
dimStore.set(get(dimStore) - 1);
|
||||
},
|
||||
set(dim: number) {
|
||||
if (dim > MAX_DIMS || dim < MIN_DIMS) {
|
||||
return;
|
||||
}
|
||||
dimStore.set(dim);
|
||||
polycubes.reset();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
function polycubeStore() {
|
||||
function freshCube(id: number) {
|
||||
return new VoxelSpaceBigInt({
|
||||
id: id,
|
||||
dims: [get(somaDimX), get(somaDimY), get(somaDimZ)],
|
||||
color: colorFromIndex(id),
|
||||
cullEmpty: false
|
||||
});
|
||||
}
|
||||
const polycubeStore = writable<VoxelSpaceBigInt[]>([freshCube(0)]);
|
||||
return {
|
||||
subscribe: polycubeStore.subscribe,
|
||||
setColor(cubeIndex: number, color: string) {
|
||||
const cubes = get(polycubeStore);
|
||||
cubes[cubeIndex].setColor(color);
|
||||
polycubeStore.set(cubes);
|
||||
},
|
||||
addCube() {
|
||||
if (!get(isMaxPolycubes)) {
|
||||
polycubeStore.update((polycubes: VoxelSpaceBigInt[]) =>
|
||||
polycubes.concat(freshCube(polycubes.length)));
|
||||
}
|
||||
},
|
||||
removeCube() {
|
||||
if (!get(isMinPolycubes)) {
|
||||
polycubeStore.update((polycubes: VoxelSpaceBigInt[]) => polycubes.splice(0, polycubes.length - 1));
|
||||
}
|
||||
const newLength = get(polycubeStore).length;
|
||||
if (newLength <= get(selectedCube)) {
|
||||
selectedCube.set(newLength - 1);
|
||||
}
|
||||
},
|
||||
toggle(cubeIndex: number, x: number, y: number, z: number) {
|
||||
const cubes = get(polycubeStore);
|
||||
cubes[cubeIndex].toggle(x, y, z);
|
||||
polycubeStore.set(cubes);
|
||||
},
|
||||
set(cubeIndex: number, val: boolean, x: number, y: number, z: number) {
|
||||
const cubes = get(polycubeStore);
|
||||
cubes[cubeIndex].set(x, y, z, val);
|
||||
polycubeStore.set(cubes);
|
||||
},
|
||||
reset() {
|
||||
polycubeStore.update((polycubes: VoxelSpaceBigInt[]) => {
|
||||
const result: VoxelSpaceBigInt[] = [];
|
||||
for (let i = 0; i < Math.min(polycubes.length, get(totalVolume)); i++) {
|
||||
result.push(freshCube(i));
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function rgbToHex(rgbStr: string): string {
|
||||
const sep = rgbStr.indexOf(",") > -1 ? "," : " ";
|
||||
const rgb = rgbStr.substr(4).split(")")[0].split(sep);
|
||||
const r = (+rgb[0]).toString(16).padStart(2, "0");
|
||||
const g = (+rgb[1]).toString(16).padStart(2, "0");
|
||||
const b = (+rgb[2]).toString(16).padStart(2, "0");
|
||||
return "#" + r + g + b;
|
||||
}
|
||||
|
||||
function hslToRgb(hslStr: string): string {
|
||||
const opt = new Option();
|
||||
opt.style.color = hslStr;
|
||||
return opt.style.color;
|
||||
}
|
||||
|
||||
export function colorFromIndex(index: number): string {
|
||||
const colorWheelCycle = Math.floor(index / 6);
|
||||
const darknessCycle = Math.floor(index / 12);
|
||||
const spacing = (360 / 6);
|
||||
const offset = colorWheelCycle === 0 ? 0 : spacing / (colorWheelCycle + 2);
|
||||
let hue = spacing * (index % 6) + offset;
|
||||
const saturation = 100;
|
||||
const lightness = 1 / (2 + darknessCycle) * 100;
|
||||
return rgbToHex(hslToRgb(`hsl(${hue},${saturation}%,${Math.round(lightness)}%)`));
|
||||
}
|
||||
|
||||
const worker = new Worker('../solver/main.js', {type: "module"});
|
||||
async function respondWasm(event: MessageEvent) {
|
||||
solutions.set(event.data.map((wasmSolution) => {
|
||||
const solnObj = new SomaSolution(get(somaDimX), get(somaDimY), get(somaDimZ));
|
||||
const spaceReps = wasmSolution.split(",");
|
||||
for (let i = 0; i < spaceReps.length; i++) {
|
||||
solnObj.addSpace(new VoxelSpaceBigInt({
|
||||
id: i,
|
||||
dims: [get(somaDimX), get(somaDimY), get(somaDimZ)] as DimensionDef,
|
||||
space: BigInt(parseInt(spaceReps[i])),
|
||||
color: get(polycubes)[i].getColor(),
|
||||
cullEmpty: false,
|
||||
}));
|
||||
}
|
||||
return solnObj;
|
||||
}));
|
||||
if (event.data.length > 0) {
|
||||
activeSolution.set(0);
|
||||
showingSolution.set(true);
|
||||
} else {
|
||||
showingSolution.set(false);
|
||||
activeSolution.set(null);
|
||||
}
|
||||
solving.set(false);
|
||||
}
|
||||
|
||||
function respondJs(event: MessageEvent) {
|
||||
solutions.set(event.data.solns.map(solnSpaces => {
|
||||
const solnObj = new SomaSolution(get(somaDimX), get(somaDimY), get(somaDimZ));
|
||||
for (let i = 0; i < solnSpaces.length; i++) {
|
||||
solnObj.addSpace(new VoxelSpaceBigInt({
|
||||
id: i,
|
||||
dims: [get(somaDimX), get(somaDimY), get(somaDimZ)] as DimensionDef,
|
||||
space: BigInt(`0b${ solnSpaces[i] }`),
|
||||
color: get(polycubes)[i].getColor(),
|
||||
cullEmpty: false,
|
||||
}));
|
||||
}
|
||||
return solnObj;
|
||||
}));
|
||||
if (event.data.length > 0) {
|
||||
activeSolution.set(0);
|
||||
showingSolution.set(true);
|
||||
} else {
|
||||
showingSolution.set(false);
|
||||
activeSolution.set(null);
|
||||
}
|
||||
solving.set(false);
|
||||
}
|
||||
|
||||
export function solve() {
|
||||
const doWasm = get(totalVolume) <= 32;
|
||||
let inputCubes;
|
||||
if (doWasm) {
|
||||
worker.onmessage = (e) => respondWasm(e);
|
||||
} else {
|
||||
worker.onmessage = (e) => respondJs(e);
|
||||
}
|
||||
inputCubes = get(polycubes).map(cubeInput => cubeInput.getRaw());
|
||||
solving.set(true);
|
||||
worker.postMessage({
|
||||
type: doWasm ? 'wasm' : 'js',
|
||||
polycubes: inputCubes,
|
||||
dimX: get(somaDimX),
|
||||
dimY: get(somaDimY),
|
||||
dimZ: get(somaDimZ)
|
||||
});
|
||||
}
|
||||
|
||||
// async function solveSync() {
|
||||
// const solver = new SomaSolver(get(somaDimX), get(somaDimY), get(somaDimZ));
|
||||
// function showSolutionWaitUserFeedback(soln: SomaSolution) {
|
||||
// activeSolution.set(0);
|
||||
// solutions.set([soln]);
|
||||
// showingSolution.set(true);
|
||||
// return new Promise<void>((resolve) => {
|
||||
// const callback = (e: KeyboardEvent) => {
|
||||
// resolve();
|
||||
// window.removeEventListener("keydown", callback);
|
||||
// };
|
||||
// window.addEventListener("keydown", callback);
|
||||
// });
|
||||
// }
|
||||
// if (get(debug)) {
|
||||
// solver.setDebug({
|
||||
// showSoln(soln: SomaSolution) {
|
||||
// return showSolutionWaitUserFeedback(soln);
|
||||
// },
|
||||
// showSpace(cube: VoxelSpaceBoolean) {
|
||||
// const testSoln = new SomaSolution(get(somaDimX), get(somaDimY), get(somaDimZ));
|
||||
// testSoln.addSpace(cube);
|
||||
// return showSolutionWaitUserFeedback(testSoln);
|
||||
// }
|
||||
// });
|
||||
// }
|
||||
// solving.set(true);
|
||||
// await solver.solve(get(polycubes).map(cubeInput => new VoxelSpaceBoolean({
|
||||
// id: cubeInput.getId(),
|
||||
// dims: cubeInput.getDims(),
|
||||
// space: cubeInput.getRaw(),
|
||||
// color: cubeInput.getColor(),
|
||||
// cullEmpty: true
|
||||
// })));
|
||||
// const solns = solver.getSolutions();
|
||||
//
|
||||
// if (solns.length > 0) {
|
||||
// activeSolution.set(0);
|
||||
// solutions.set(solns);
|
||||
// showingSolution.set(true);
|
||||
// } else {
|
||||
// showingSolution.set(false);
|
||||
// activeSolution.set(null);
|
||||
// }
|
||||
// solving.set(false);
|
||||
// }
|
||||
export const examples = [
|
||||
{
|
||||
name: "Standard Soma Cube",
|
||||
dimX: 3,
|
||||
dimY: 3,
|
||||
dimZ: 3,
|
||||
cubes: [
|
||||
{space: 23n, color: "#ff0000"},
|
||||
{space: 30n, color: "#ffff00"},
|
||||
{space: 15n, color: "#00ff00"},
|
||||
{space: 8344n, color: "#00ffff"},
|
||||
{space: 9240n, color: "#0000ff"},
|
||||
{space: 4632n, color: "#ff00ff"},
|
||||
{space: 152n, color: "#ff5500"},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Convolution TG 5850 (4x4x4)",
|
||||
dimX: 4,
|
||||
dimY: 4,
|
||||
dimZ: 4,
|
||||
cubes: [
|
||||
{space: 12651033568030492808n, color: "#ff0000"},
|
||||
{space: 1123868011502010368n, color: "#ffff00"},
|
||||
{space: 124314703626304n, color: "#00ff00"},
|
||||
{space: 263883079155712n, color: "#00ffff"},
|
||||
{space: 3952148496n, color: "#0000ff"},
|
||||
{space: 166723584n, color: "#ff00ff"},
|
||||
{space: 1048576n, color: "#ff5500"},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "3x3x4, 7 Pieces",
|
||||
dimX: 3,
|
||||
dimY: 3,
|
||||
dimZ: 4,
|
||||
cubes: [
|
||||
{space: 244n, color: "#ff0000"},
|
||||
{space: 625n, color: "#ffff00"},
|
||||
{space: 140080n, color: "#00ff00"},
|
||||
{space: 31n, color: "#00ffff"},
|
||||
{space: 738n, color: "#0000ff"},
|
||||
{space: 537002290n, color: "#ff00ff"},
|
||||
{space: 275n, color: "#ff5500"},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "3x3x3, 7 Pieces",
|
||||
dimX: 3,
|
||||
dimY: 3,
|
||||
dimZ: 3,
|
||||
cubes: [
|
||||
{space: 23n, color: "#ff0000"},
|
||||
{space: 47n, color: "#ffff00"},
|
||||
{space: 474n, color: "#00ff00"},
|
||||
{space: 8n, color: "#00ffff"},
|
||||
{space: 24n, color: "#0000ff"},
|
||||
{space: 316n, color: "#ff00ff"},
|
||||
{space: 23n, color: "#ff5500"},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "3x3x3, 6 Pieces",
|
||||
dimX: 3,
|
||||
dimY: 3,
|
||||
dimZ: 3,
|
||||
cubes: [
|
||||
{space: 30n, color: "#ff0000"},
|
||||
{space: 29712n, color: "#ffff00"},
|
||||
{space: 29216n, color: "#00ff00"},
|
||||
{space: 15392n, color: "#00ffff"},
|
||||
{space: 15364n, color: "#0000ff"},
|
||||
{space: 536871032n, color: "#ff00ff"},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "3x3x3, 5 Pieces",
|
||||
dimX: 3,
|
||||
dimY: 3,
|
||||
dimZ: 3,
|
||||
cubes: [
|
||||
{space: 376n, color: "#ff0000"},
|
||||
{space: 2428n, color: "#ffff00"},
|
||||
{space: 28960n, color: "#00ff00"},
|
||||
{space: 48136n, color: "#00ffff"},
|
||||
{space: 120n, color: "#0000ff"},
|
||||
],
|
||||
},
|
||||
];
|
||||
34
src/stores/DimStore.ts
Normal file
34
src/stores/DimStore.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import {get, Writable, writable} from "svelte/store";
|
||||
|
||||
export default class DimStore {
|
||||
static readonly MAX_DIMS = 20;
|
||||
static readonly MIN_DIMS = 1;
|
||||
private store: Writable<number>;
|
||||
|
||||
constructor(init: number) {
|
||||
this.store = writable(init);
|
||||
}
|
||||
|
||||
currentVal() {
|
||||
return get(this.store);
|
||||
}
|
||||
|
||||
subscribe(cb: (val: number) => any) {
|
||||
return this.store.subscribe(cb);
|
||||
}
|
||||
|
||||
inc() {
|
||||
this.set(this.currentVal() + 1);
|
||||
}
|
||||
|
||||
dec() {
|
||||
this.set(this.currentVal() - 1);
|
||||
}
|
||||
|
||||
set(dim: number) {
|
||||
if (dim > DimStore.MAX_DIMS || dim < DimStore.MIN_DIMS) {
|
||||
return;
|
||||
}
|
||||
this.store.set(dim);
|
||||
}
|
||||
}
|
||||
122
src/stores/PolycubeStore.ts
Normal file
122
src/stores/PolycubeStore.ts
Normal file
@@ -0,0 +1,122 @@
|
||||
import VoxelSpaceBigInt from "../VoxelSpaceBigInt";
|
||||
import {get, Writable, writable} from "svelte/store";
|
||||
import type DimStore from "./DimStore";
|
||||
import {colorFromIndex} from "../utils";
|
||||
|
||||
export default class PolycubeStore {
|
||||
private store: Writable<VoxelSpaceBigInt[]>;
|
||||
private dimX: DimStore;
|
||||
private dimY: DimStore;
|
||||
private dimZ: DimStore;
|
||||
private selectedCube: Writable<number>;
|
||||
|
||||
constructor(dimX: DimStore, dimY: DimStore, dimZ: DimStore) {
|
||||
this.selectedCube = writable(0);
|
||||
this.dimX = dimX;
|
||||
this.dimY = dimY;
|
||||
this.dimZ = dimZ;
|
||||
this.store = writable<VoxelSpaceBigInt[]>([this.freshCube(0)]);
|
||||
this.dimX.subscribe(() => this.reset());
|
||||
this.dimY.subscribe(() => this.reset());
|
||||
this.dimZ.subscribe(() => this.reset());
|
||||
|
||||
}
|
||||
|
||||
private freshCube(id: number) {
|
||||
return new VoxelSpaceBigInt({
|
||||
id: id,
|
||||
dims: [this.dimX.currentVal(), this.dimY.currentVal(), this.dimZ.currentVal()],
|
||||
color: colorFromIndex(id),
|
||||
cullEmpty: false
|
||||
});
|
||||
}
|
||||
|
||||
private volume() {
|
||||
return this.dimX.currentVal() * this.dimY.currentVal() * this.dimZ.currentVal();
|
||||
}
|
||||
|
||||
private isMaxPolycubes() {
|
||||
return this.currentVal().length >= this.volume();
|
||||
|
||||
}
|
||||
|
||||
private isMinPolycubes() {
|
||||
return this.currentVal().length <= 1;
|
||||
}
|
||||
|
||||
private getSelectedCube() {
|
||||
return get(this.selectedCube);
|
||||
}
|
||||
|
||||
selected() {
|
||||
return this.selectedCube;
|
||||
}
|
||||
|
||||
currentVal() {
|
||||
return get(this.store);
|
||||
}
|
||||
|
||||
subscribe(cb: (cubes: VoxelSpaceBigInt[]) => any) {
|
||||
return this.store.subscribe(cb);
|
||||
}
|
||||
|
||||
setColor(cubeIndex: number, color: string) {
|
||||
const cubes = this.currentVal();
|
||||
cubes[cubeIndex].setColor(color);
|
||||
this.store.set(cubes);
|
||||
}
|
||||
|
||||
addCube() {
|
||||
if (!this.isMaxPolycubes()) {
|
||||
this.store.update((polycubes: VoxelSpaceBigInt[]) =>
|
||||
polycubes.concat(this.freshCube(polycubes.length)));
|
||||
}
|
||||
}
|
||||
|
||||
removeCube() {
|
||||
if (!this.isMinPolycubes()) {
|
||||
this.store.update((polycubes: VoxelSpaceBigInt[]) => polycubes.splice(0, polycubes.length - 1));
|
||||
}
|
||||
const newLength = this.currentVal().length;
|
||||
if (newLength <= this.getSelectedCube()) {
|
||||
this.selectedCube.set(newLength - 1);
|
||||
}
|
||||
}
|
||||
|
||||
toggle(cubeIndex: number, x: number, y: number, z: number) {
|
||||
const cubes = this.currentVal();
|
||||
cubes[cubeIndex].toggle(x, y, z);
|
||||
this.store.set(cubes);
|
||||
}
|
||||
|
||||
set(cubeIndex: number, val: boolean, x: number, y: number, z: number) {
|
||||
const cubes = this.currentVal();
|
||||
cubes[cubeIndex].set(x, y, z, val);
|
||||
this.store.set(cubes);
|
||||
}
|
||||
|
||||
reset() {
|
||||
this.store.update((polycubes: VoxelSpaceBigInt[]) => {
|
||||
const result: VoxelSpaceBigInt[] = [];
|
||||
for (let i = 0; i < Math.min(polycubes.length, this.volume()); i++) {
|
||||
result.push(this.freshCube(i));
|
||||
}
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
setCubes(cubes: VoxelSpaceBigInt[]) {
|
||||
let lastDims = cubes[0].getDims();
|
||||
for (const cube of cubes) {
|
||||
const dimsMatch = !cube.getDims().some((dim, i) => lastDims[i] !== dim);
|
||||
if (!dimsMatch) {
|
||||
throw new Error("Error setting cubes: not all dimensions match.");
|
||||
}
|
||||
}
|
||||
this.dimX.set(lastDims[0]);
|
||||
this.dimY.set(lastDims[1]);
|
||||
this.dimZ.set(lastDims[2]);
|
||||
this.store.set(cubes);
|
||||
this.selectedCube.set(0);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import Sidebar from "./Sidebar.svelte";
|
||||
import SolutionInteractor from "./Interactor.svelte";
|
||||
import Stage from "./Stage.svelte";
|
||||
import PolycubeScene from "./threedee/PolycubeScene";
|
||||
|
||||
export let scene: PolycubeScene;
|
||||
</script>
|
||||
|
||||
<main>
|
||||
@@ -8,7 +11,7 @@
|
||||
<Sidebar />
|
||||
</div>
|
||||
<div class="solutionBodyContainer">
|
||||
<SolutionInteractor />
|
||||
<Stage scene="{scene}" />
|
||||
</div>
|
||||
</main>
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<script lang="ts">
|
||||
import {somaDimX, somaDimY, somaDimZ, polycubes, selectedCube, showingSolution} from "../store";
|
||||
import {somaDimX, somaDimY, somaDimZ, polycubes, showingSolution} from "../store";
|
||||
import VoxelSpaceBoolean from "../VoxelSpaceBoolean";
|
||||
export let cubeNo: number;
|
||||
|
||||
$: cube = $polycubes[cubeNo] as VoxelSpaceBoolean;
|
||||
$: cubeColor = cube.getColor();
|
||||
$: currentlyVisualised = $selectedCube === cubeNo && !$showingSolution;
|
||||
const currentlySelected = polycubes.selected();
|
||||
$: currentlyVisualised = $currentlySelected === cubeNo && !$showingSolution;
|
||||
let cellStartDragInitialVal: boolean = false;
|
||||
let cellStartDrag: number = 0;
|
||||
let cellDragStartPos: {x: number, y: number} = {x: 0, y: 0};
|
||||
@@ -24,7 +25,7 @@
|
||||
function onMouseOverCell(event: MouseEvent, x: number, y: number, z: number) {
|
||||
if (event.buttons !== 0) {
|
||||
polycubes.set(cubeNo, event.buttons === 1, x, y, z);
|
||||
selectedCube.set(cubeNo);
|
||||
polycubes.selected().set(cubeNo);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +57,7 @@
|
||||
|
||||
function onClickCube() {
|
||||
showingSolution.set(false);
|
||||
selectedCube.set(cubeNo);
|
||||
currentlySelected.set(cubeNo);
|
||||
}
|
||||
|
||||
function onColorChange(event: InputEvent) {
|
||||
|
||||
47
src/ui/CubeInputSet.svelte
Normal file
47
src/ui/CubeInputSet.svelte
Normal file
@@ -0,0 +1,47 @@
|
||||
<script lang="ts">
|
||||
import CubeInput from "./CubeInput.svelte";
|
||||
import {polycubes, somaDimX, somaDimY, somaDimZ} from "../store";
|
||||
|
||||
export let numCubes;
|
||||
$: numCubes = $polycubes.length;
|
||||
|
||||
window.addEventListener("keypress", () => {
|
||||
for (const cube of $polycubes) {
|
||||
console.log({
|
||||
name: "",
|
||||
dimX: $somaDimX,
|
||||
dimY: $somaDimY,
|
||||
dimZ: $somaDimZ,
|
||||
cubes: $polycubes.map(cube => ({space: cube.getRaw(), color: cube.getColor()})),
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
{#each {length: numCubes} as _, cubeNo}
|
||||
<div class="cube-input">
|
||||
<div class="padder">
|
||||
<CubeInput
|
||||
cubeNo={cubeNo}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.padder {
|
||||
padding: 1em;
|
||||
}
|
||||
.cube-input {
|
||||
margin: auto;
|
||||
}
|
||||
.container {
|
||||
flex: 1 1 auto;
|
||||
overflow-x: scroll;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
margin: auto;
|
||||
}
|
||||
</style>
|
||||
35
src/ui/ExamplesList.svelte
Normal file
35
src/ui/ExamplesList.svelte
Normal file
@@ -0,0 +1,35 @@
|
||||
<script lang="ts">
|
||||
import List from "./List.svelte";
|
||||
import {polycubes, examples} from "../store";
|
||||
import VoxelSpaceBigInt from "../VoxelSpaceBigInt";
|
||||
|
||||
let lastClickedExample = 0;
|
||||
|
||||
function hydrateExample(exNo: number) {
|
||||
const example = examples[exNo];
|
||||
polycubes.setCubes(example.cubes.map((cube, i) => new VoxelSpaceBigInt({
|
||||
id: i,
|
||||
dims: [example.dimX, example.dimY, example.dimZ],
|
||||
space: cube.space,
|
||||
color: cube.color,
|
||||
cullEmpty: false,
|
||||
})));
|
||||
lastClickedExample = exNo;
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<List
|
||||
defaultText="No examples found..."
|
||||
items="{examples.map(example => example.name)}"
|
||||
activeItem={lastClickedExample}
|
||||
onClick={(i) => hydrateExample(i)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
max-height: 10em;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
</style>
|
||||
@@ -3,12 +3,12 @@
|
||||
export let down: () => void;
|
||||
export let val: number;
|
||||
export let upDisabled: boolean;
|
||||
export let title: string;
|
||||
export let title: string = "";
|
||||
export let downDisabled: boolean;
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
{#if title}
|
||||
{#if title !== ""}
|
||||
<p class="title">{title}</p>
|
||||
{/if}
|
||||
<div class="controls">
|
||||
@@ -24,7 +24,7 @@
|
||||
display: inline-block;
|
||||
}
|
||||
.title {
|
||||
margin-bottom: 0;
|
||||
margin: 0;
|
||||
}
|
||||
.val {
|
||||
font-weight: bold;
|
||||
|
||||
55
src/ui/InputParameters.svelte
Normal file
55
src/ui/InputParameters.svelte
Normal file
@@ -0,0 +1,55 @@
|
||||
<script lang="ts">
|
||||
import {somaDimX, somaDimY, somaDimZ, totalVolume, polycubes, isMinPolycubes, isMaxPolycubes} from "../store";
|
||||
import IncDecNum from "./IncDecNum.svelte";
|
||||
import PolycubeStore from "../stores/PolycubeStore";
|
||||
|
||||
$: numCubes = $polycubes.length;
|
||||
</script>
|
||||
|
||||
<div class="option">
|
||||
<p>Dimensions:</p>
|
||||
<IncDecNum
|
||||
title="X"
|
||||
val="{$somaDimX}"
|
||||
upDisabled="{$somaDimX >= PolycubeStore.MAX_DIMS}"
|
||||
up="{() => somaDimX.set($somaDimX + 1)}"
|
||||
downDisabled="{$somaDimX <= PolycubeStore.MIN_DIMS}"
|
||||
down="{() => somaDimX.set($somaDimX - 1)}"
|
||||
/>
|
||||
<IncDecNum
|
||||
title="Y"
|
||||
val="{$somaDimY}"
|
||||
upDisabled="{$somaDimY >= PolycubeStore.MAX_DIMS}"
|
||||
up="{() => somaDimY.set($somaDimY + 1)}"
|
||||
downDisabled="{$somaDimY <= PolycubeStore.MIN_DIMS}"
|
||||
down="{() => somaDimY.set($somaDimY - 1)}"
|
||||
/>
|
||||
<IncDecNum
|
||||
title="Z"
|
||||
val="{$somaDimZ}"
|
||||
upDisabled="{$somaDimZ >= PolycubeStore.MAX_DIMS}"
|
||||
up="{() => somaDimZ.set($somaDimZ + 1)}"
|
||||
downDisabled="{$somaDimZ <= PolycubeStore.MIN_DIMS}"
|
||||
down="{() => somaDimZ.set($somaDimZ - 1)}"
|
||||
/>
|
||||
{#if $totalVolume > 32}
|
||||
<p class="warn">The total number of units exceeds 32. Attempting to solve puzzles with more than 32 units results in significantly slower computation time.</p>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<p>Cubes:</p>
|
||||
<IncDecNum
|
||||
down="{() => polycubes.removeCube()}"
|
||||
downDisabled="{$isMinPolycubes}"
|
||||
up="{() => polycubes.addCube()}"
|
||||
upDisabled="{$isMaxPolycubes}"
|
||||
val="{numCubes}"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.warn {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
42
src/ui/List.svelte
Normal file
42
src/ui/List.svelte
Normal file
@@ -0,0 +1,42 @@
|
||||
<script lang="ts">
|
||||
export let defaultText: string = "...";
|
||||
export let activeItem: number = 0;
|
||||
export let items: string[] = [];
|
||||
export let onClick = (itemNo: number) => { activeItem = itemNo };
|
||||
</script>
|
||||
|
||||
<ul>
|
||||
{#if items.length === 0}
|
||||
<li>{defaultText}</li>
|
||||
{/if}
|
||||
{#each items as item, i}
|
||||
<li class:active={activeItem === i} on:click={() => onClick(i)}>
|
||||
{item}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
li:hover:not(.active) {
|
||||
background-color: #aaaaaa;
|
||||
}
|
||||
li {
|
||||
transition: background-color 100ms;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
height: 2em;
|
||||
line-height: 2em;
|
||||
}
|
||||
ul {
|
||||
width: 100%;
|
||||
overflow-y: scroll;
|
||||
flex: 1;
|
||||
padding: 0.5em;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
background-color: #666;
|
||||
}
|
||||
.active {
|
||||
background-color: #ff3e00;
|
||||
}
|
||||
</style>
|
||||
@@ -1,122 +1,34 @@
|
||||
<script lang="ts">
|
||||
import {
|
||||
isMaxPolycubes,
|
||||
isMinPolycubes,
|
||||
polycubes,
|
||||
solutions,
|
||||
solving,
|
||||
totalVolume,
|
||||
somaDimX,
|
||||
somaDimY,
|
||||
somaDimZ,
|
||||
MAX_DIMS,
|
||||
MIN_DIMS,
|
||||
solve
|
||||
} from "../store";
|
||||
import SolutionList from "./SolutionList.svelte";
|
||||
import IncDecNum from "./IncDecNum.svelte";
|
||||
|
||||
$: numCubes = $polycubes.length;
|
||||
$: cubes = $polycubes;
|
||||
let noEmpties: boolean;
|
||||
let enoughSubcubes: boolean;
|
||||
let readyToSolve: boolean;
|
||||
let size: number;
|
||||
$: {
|
||||
size = cubes.reduce((prev, cube) => cube.size() + prev, 0);
|
||||
noEmpties = cubes.reduce((prev, cube) => (cube.size() !== 0) && prev, true);
|
||||
enoughSubcubes = size === $totalVolume;
|
||||
readyToSolve = enoughSubcubes && noEmpties;
|
||||
}
|
||||
|
||||
function genTooltip() {
|
||||
let messages = [];
|
||||
if (!enoughSubcubes) {
|
||||
messages.push(`You have not input enough subcubes to form a rectangular prism with side lengths ${$somaDimX}, ${$somaDimY}, and ${$somaDimZ}. Needed: ${$totalVolume}, current: ${size}.`);
|
||||
}
|
||||
if (!noEmpties) {
|
||||
messages.push("You have left some of the polycube inputs empty. Remove them to solve.");
|
||||
}
|
||||
return messages.join("\n");
|
||||
}
|
||||
import InputParameters from "./InputParameters.svelte";
|
||||
import ExamplesList from "./ExamplesList.svelte";
|
||||
import Tabs from "./Tabs.svelte";
|
||||
import SolveButton from "./SolveButton.svelte";
|
||||
</script>
|
||||
|
||||
<div class="container">
|
||||
<h1>Somaesque</h1>
|
||||
<div class="widgets">
|
||||
<div class="option">
|
||||
<p>Dimensions:</p>
|
||||
<div class="choice">
|
||||
<IncDecNum
|
||||
title="X"
|
||||
val="{$somaDimX}"
|
||||
upDisabled="{$somaDimX >= MAX_DIMS}"
|
||||
up="{() => somaDimX.set($somaDimX + 1)}"
|
||||
downDisabled="{$somaDimX <= MIN_DIMS}"
|
||||
down="{() => somaDimX.set($somaDimX - 1)}"
|
||||
/>
|
||||
<IncDecNum
|
||||
title="Y"
|
||||
val="{$somaDimY}"
|
||||
upDisabled="{$somaDimY >= MAX_DIMS}"
|
||||
up="{() => somaDimY.set($somaDimY + 1)}"
|
||||
downDisabled="{$somaDimY <= MIN_DIMS}"
|
||||
down="{() => somaDimY.set($somaDimY - 1)}"
|
||||
/>
|
||||
<IncDecNum
|
||||
title="Z"
|
||||
val="{$somaDimZ}"
|
||||
upDisabled="{$somaDimZ >= MAX_DIMS}"
|
||||
up="{() => somaDimZ.set($somaDimZ + 1)}"
|
||||
downDisabled="{$somaDimZ <= MIN_DIMS}"
|
||||
down="{() => somaDimZ.set($somaDimZ - 1)}"
|
||||
/>
|
||||
{#if $totalVolume > 32}
|
||||
<p class="warn">The total number of units exceeds 32. Attempting to solve puzzles with more than 32 units results in significantly slower computation time.</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<p>Cubes:</p>
|
||||
<div class="choice">
|
||||
<IncDecNum
|
||||
down="{polycubes.removeCube}"
|
||||
downDisabled="{$isMinPolycubes}"
|
||||
up="{polycubes.addCube}"
|
||||
upDisabled="{$isMaxPolycubes}"
|
||||
val="{numCubes}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="option">
|
||||
<button
|
||||
class="solve"
|
||||
on:click={solve}
|
||||
title="{genTooltip(enoughSubcubes, noEmpties, size)}"
|
||||
disabled="{$solving || !readyToSolve}">
|
||||
{$solving ? "Solving..." : "Solve!"}
|
||||
</button>
|
||||
</div>
|
||||
<Tabs
|
||||
selectedTab={"Parameters"}
|
||||
tabs={{
|
||||
"Parameters": InputParameters,
|
||||
"Examples": ExamplesList,
|
||||
}}/>
|
||||
<SolveButton/>
|
||||
</div>
|
||||
<h3>Solutions: {$solutions.length}</h3>
|
||||
<SolutionList/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.warn {
|
||||
color: red;
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
}
|
||||
.choice {
|
||||
display: block;
|
||||
text-align: center;
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
input {
|
||||
display: inline-block;
|
||||
background-color: #999999;
|
||||
@@ -124,26 +36,6 @@
|
||||
height: 2em;
|
||||
border-style: none;
|
||||
}
|
||||
.selected:disabled {
|
||||
color: white;
|
||||
background-color: #ff3e00;
|
||||
}
|
||||
button.solve {
|
||||
width: auto;
|
||||
color: white;
|
||||
background-color: #ff3e00;
|
||||
font-size: 2em;
|
||||
border-radius: 0.5em;
|
||||
border-style: none;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
button.solve:disabled {
|
||||
width: auto;
|
||||
color: #999999;
|
||||
background-color: #a36754;
|
||||
font-size: 2em;
|
||||
}
|
||||
.container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -157,16 +49,6 @@
|
||||
.widgets {
|
||||
width: 100%;
|
||||
}
|
||||
.widgets:first-child {
|
||||
padding-top: 0;
|
||||
}
|
||||
.widgets:last-child {
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.widgets > * {
|
||||
padding-top: 0.5em;
|
||||
padding-bottom: 0.5em;
|
||||
}
|
||||
h1 {
|
||||
margin: 0;
|
||||
color: #ff3e00;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<script lang="ts">
|
||||
import {solutions, activeSolution, showingSolution} from "../store";
|
||||
import List from "./List.svelte";
|
||||
|
||||
function selectSolution(i: number) {
|
||||
activeSolution.set(i);
|
||||
@@ -7,38 +8,9 @@
|
||||
}
|
||||
</script>
|
||||
|
||||
<ul>
|
||||
{#if $solutions.length === 0}
|
||||
<li>No solutions yet...</li>
|
||||
{/if}
|
||||
{#each $solutions as soln, i}
|
||||
<li class:active={$activeSolution === i} on:click={() => selectSolution(i)}>
|
||||
Solution #{i + 1}
|
||||
</li>
|
||||
{/each}
|
||||
</ul>
|
||||
|
||||
<style>
|
||||
li:hover:not(.active) {
|
||||
background-color: #aaaaaa;
|
||||
}
|
||||
li {
|
||||
transition: background-color 100ms;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
height: 2em;
|
||||
line-height: 2em;
|
||||
}
|
||||
ul {
|
||||
width: 100%;
|
||||
overflow-y: scroll;
|
||||
flex: 1;
|
||||
padding: 0.5em;
|
||||
margin: 0;
|
||||
text-align: center;
|
||||
background-color: #666;
|
||||
}
|
||||
.active {
|
||||
background-color: #ff3e00;
|
||||
}
|
||||
</style>
|
||||
<List
|
||||
activeItem={$activeSolution}
|
||||
items={$solutions.map((soln, i) => `Solution ${i + 1}`)}
|
||||
defaultText="No solutions yet..."
|
||||
onClick={(i) => selectSolution(i)}
|
||||
/>
|
||||
@@ -1,13 +1,15 @@
|
||||
<script lang="ts">
|
||||
import PolycubeScene from "./threedee/PolycubeScene";
|
||||
import {onMount} from "svelte";
|
||||
import {polycubes, selectedCube, solutions, activeSolution, showingSolution, cubeScene} from "../store";
|
||||
import {polycubes, solutions, activeSolution, showingSolution} from "../store";
|
||||
import Solution2D from "./Solution2D.svelte";
|
||||
|
||||
$: cube = $polycubes[$selectedCube];
|
||||
export let scene: PolycubeScene;
|
||||
const selectedStore = polycubes.selected();
|
||||
$: selectedCube = $selectedStore;
|
||||
$: cube = $polycubes[selectedCube];
|
||||
$: soln = $solutions[$activeSolution];
|
||||
let el: HTMLDivElement;
|
||||
let scene: PolycubeScene;
|
||||
let loaded: boolean = false;
|
||||
|
||||
const canvasStyle: Partial<CSSStyleDeclaration> = {
|
||||
@@ -15,8 +17,8 @@
|
||||
};
|
||||
|
||||
onMount(() => {
|
||||
cubeScene.onLoaded(() => {
|
||||
cubeScene.mount(el);
|
||||
scene.onLoaded(() => {
|
||||
scene.mount(el);
|
||||
Object.assign((el.children.item(0) as HTMLElement).style, canvasStyle);
|
||||
loaded = true;
|
||||
});
|
||||
@@ -25,17 +27,15 @@
|
||||
$: {
|
||||
if (loaded) {
|
||||
if ($showingSolution) {
|
||||
const colorMap = {};
|
||||
$polycubes.forEach((polycube, i) => colorMap[i] = polycube.color);
|
||||
cubeScene.showSolution(soln);
|
||||
scene.showSolution(soln);
|
||||
} else {
|
||||
cubeScene.showPolycube(cube);
|
||||
scene.showPolycube(cube);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<div class="top">
|
||||
<div class="container">
|
||||
{#if $activeSolution !== null}
|
||||
<div class="soln2d-container">
|
||||
<Solution2D/>
|
||||
@@ -45,13 +45,17 @@
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.top {
|
||||
display: flex;
|
||||
justify-content: space-evenly;
|
||||
align-items: center;
|
||||
}
|
||||
.soln2d-container {
|
||||
flex: 0 1 auto;
|
||||
display: inline-block;
|
||||
}
|
||||
.container {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
align-content: center;
|
||||
justify-content: space-evenly;
|
||||
text-align: center;
|
||||
align-items: center;
|
||||
}
|
||||
</style>
|
||||
54
src/ui/SolveButton.svelte
Normal file
54
src/ui/SolveButton.svelte
Normal file
@@ -0,0 +1,54 @@
|
||||
<script lang="ts">
|
||||
import {polycubes, solving, somaDimX, somaDimY, somaDimZ, totalVolume} from "../store";
|
||||
import {solve} from "../solve";
|
||||
|
||||
$: cubes = $polycubes;
|
||||
let noEmpties: boolean;
|
||||
let enoughSubcubes: boolean;
|
||||
let readyToSolve: boolean;
|
||||
let size: number;
|
||||
$: {
|
||||
size = cubes.reduce((prev, cube) => cube.size() + prev, 0);
|
||||
noEmpties = cubes.reduce((prev, cube) => (cube.size() !== 0) && prev, true);
|
||||
enoughSubcubes = size === $totalVolume;
|
||||
readyToSolve = enoughSubcubes && noEmpties;
|
||||
}
|
||||
|
||||
function genTooltip() {
|
||||
let messages = [];
|
||||
if (!enoughSubcubes) {
|
||||
messages.push(`You have not input enough subcubes to form a rectangular prism with side lengths ${$somaDimX}, ${$somaDimY}, and ${$somaDimZ}. Needed: ${$totalVolume}, current: ${size}.`);
|
||||
}
|
||||
if (!noEmpties) {
|
||||
messages.push("You have left some of the polycube inputs empty. Remove them to solve.");
|
||||
}
|
||||
return messages.join("\n");
|
||||
}
|
||||
</script>
|
||||
|
||||
<button
|
||||
class="solve"
|
||||
on:click={solve}
|
||||
title="{genTooltip(enoughSubcubes, noEmpties, size)}"
|
||||
disabled="{$solving || !readyToSolve}">
|
||||
{$solving ? "Solving..." : "Solve!"}
|
||||
</button>
|
||||
|
||||
<style>
|
||||
button.solve {
|
||||
width: auto;
|
||||
color: white;
|
||||
background-color: #ff3e00;
|
||||
font-size: 2em;
|
||||
border-radius: 0.5em;
|
||||
border-style: none;
|
||||
margin: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
button.solve:disabled {
|
||||
width: auto;
|
||||
color: #999999;
|
||||
background-color: #a36754;
|
||||
font-size: 2em;
|
||||
}
|
||||
</style>
|
||||
@@ -1,8 +1,9 @@
|
||||
<script lang="ts">
|
||||
import {polycubes} from "../store";
|
||||
import CubeInput from "./CubeInput.svelte";
|
||||
import SolutionViewer from "./SolutionViewer.svelte";
|
||||
$: numCubes = $polycubes.length;
|
||||
import CubeInputSet from "./CubeInputSet.svelte";
|
||||
import PolycubeScene from "./threedee/PolycubeScene";
|
||||
|
||||
export let scene: PolycubeScene;
|
||||
let showInput = true;
|
||||
let smallViewport = true;
|
||||
|
||||
@@ -24,37 +25,13 @@
|
||||
<div class="tab" class:selected={!showInput} on:click="{() => showInput = false}">3D</div>
|
||||
</div>
|
||||
{#if showInput}
|
||||
<div class="input-container">
|
||||
{#each {length: numCubes} as _, cubeNo}
|
||||
<div class="cube-input">
|
||||
<div class="padder">
|
||||
<CubeInput
|
||||
cubeNo={cubeNo}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<CubeInputSet/>
|
||||
{:else}
|
||||
<div class="threedee">
|
||||
<SolutionViewer/>
|
||||
</div>
|
||||
<SolutionViewer scene="{scene}"/>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="input-container">
|
||||
{#each {length: numCubes} as _, cubeNo}
|
||||
<div class="cube-input">
|
||||
<div class="padder">
|
||||
<CubeInput
|
||||
cubeNo={cubeNo}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="threedee">
|
||||
<SolutionViewer/>
|
||||
</div>
|
||||
<CubeInputSet/>
|
||||
<SolutionViewer scene="{scene}"/>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
@@ -81,26 +58,6 @@
|
||||
background-color: grey;
|
||||
border-width: 1px 0 0 0;
|
||||
}
|
||||
.threedee {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-content: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
}
|
||||
.padder {
|
||||
padding: 1em;
|
||||
}
|
||||
.cube-input {
|
||||
margin: auto;
|
||||
}
|
||||
.input-container {
|
||||
flex: 1 1 auto;
|
||||
overflow-x: scroll;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
}
|
||||
.viewport {
|
||||
overflow: scroll;
|
||||
display: flex;
|
||||
44
src/ui/Tabs.svelte
Normal file
44
src/ui/Tabs.svelte
Normal file
@@ -0,0 +1,44 @@
|
||||
<script lang="ts">
|
||||
import {SvelteComponent} from "svelte/internal";
|
||||
|
||||
export let selectedTab: string;
|
||||
export let tabs: Record<string, SvelteComponent>;
|
||||
|
||||
$: displayedComponent = tabs[selectedTab];
|
||||
</script>
|
||||
|
||||
<div class="tabs">
|
||||
{#each Object.keys(tabs) as key}
|
||||
<div class="tab" class:selected={selectedTab === key} on:click="{() => selectedTab = key}">{key}</div>
|
||||
{/each}
|
||||
</div>
|
||||
<div class="container">
|
||||
<svelte:component this={displayedComponent}/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.container {
|
||||
background-color: grey;
|
||||
padding: 1em;
|
||||
}
|
||||
.tabs {
|
||||
height: 3em;
|
||||
flex: 0 1 auto;
|
||||
display: flex;
|
||||
cursor: pointer;
|
||||
}
|
||||
.tab {
|
||||
flex: 1;
|
||||
text-align: center;
|
||||
border-radius: 1em 1em 0 0;
|
||||
background-color: #555555;
|
||||
line-height: 3em;
|
||||
transition: background-color 100ms;
|
||||
}
|
||||
.tab:hover {
|
||||
background-color: #999999;
|
||||
}
|
||||
.tab.selected {
|
||||
background-color: grey;
|
||||
}
|
||||
</style>
|
||||
@@ -88,6 +88,683 @@ const ROT_CODE_MAP = {
|
||||
c(mesh: THREE.Object3D) { mesh.rotateZ(-Math.PI/2); },
|
||||
} as const;
|
||||
|
||||
const OBJ = `
|
||||
# Blender v2.82 (sub 7) OBJ File: ''
|
||||
# www.blender.org
|
||||
o Cube_Cube.001
|
||||
v 0.399961 0.500000 -0.399961
|
||||
v 0.500000 0.399961 -0.399961
|
||||
v 0.399961 0.399961 -0.500000
|
||||
v 0.438244 0.492385 -0.399961
|
||||
v 0.470699 0.470699 -0.399961
|
||||
v 0.399961 0.492385 -0.438244
|
||||
v 0.439203 0.483194 -0.439203
|
||||
v 0.465612 0.465612 -0.437212
|
||||
v 0.457718 0.457718 -0.457718
|
||||
v 0.492385 0.399961 -0.438244
|
||||
v 0.470699 0.399961 -0.470699
|
||||
v 0.492385 0.438244 -0.399961
|
||||
v 0.483194 0.439203 -0.439203
|
||||
v 0.465612 0.437212 -0.465612
|
||||
v 0.399961 0.438244 -0.492385
|
||||
v 0.399961 0.470699 -0.470699
|
||||
v 0.438244 0.399961 -0.492385
|
||||
v 0.439203 0.439203 -0.483194
|
||||
v 0.437212 0.465612 -0.465612
|
||||
v 0.500000 -0.399961 -0.399961
|
||||
v 0.399961 -0.500000 -0.399961
|
||||
v 0.399961 -0.399961 -0.500000
|
||||
v 0.492385 -0.438244 -0.399961
|
||||
v 0.470699 -0.470699 -0.399961
|
||||
v 0.492385 -0.399961 -0.438244
|
||||
v 0.483194 -0.439203 -0.439203
|
||||
v 0.465612 -0.465612 -0.437212
|
||||
v 0.457718 -0.457718 -0.457718
|
||||
v 0.399961 -0.492385 -0.438244
|
||||
v 0.399961 -0.470699 -0.470699
|
||||
v 0.438244 -0.492385 -0.399961
|
||||
v 0.439203 -0.483194 -0.439203
|
||||
v 0.437212 -0.465612 -0.465612
|
||||
v 0.438244 -0.399961 -0.492385
|
||||
v 0.470699 -0.399961 -0.470699
|
||||
v 0.399961 -0.438244 -0.492385
|
||||
v 0.439203 -0.439203 -0.483194
|
||||
v 0.465612 -0.437212 -0.465612
|
||||
v 0.500000 0.399961 0.399961
|
||||
v 0.399961 0.500000 0.399961
|
||||
v 0.399961 0.399961 0.500000
|
||||
v 0.492385 0.438244 0.399961
|
||||
v 0.470699 0.470699 0.399961
|
||||
v 0.492385 0.399961 0.438244
|
||||
v 0.483194 0.439203 0.439203
|
||||
v 0.465612 0.465612 0.437212
|
||||
v 0.457718 0.457718 0.457718
|
||||
v 0.399961 0.492385 0.438244
|
||||
v 0.399961 0.470699 0.470699
|
||||
v 0.438244 0.492385 0.399961
|
||||
v 0.439203 0.483194 0.439203
|
||||
v 0.437212 0.465612 0.465612
|
||||
v 0.438244 0.399961 0.492385
|
||||
v 0.470699 0.399961 0.470699
|
||||
v 0.399961 0.438244 0.492385
|
||||
v 0.439203 0.439203 0.483194
|
||||
v 0.465612 0.437212 0.465612
|
||||
v 0.399961 -0.399961 0.500000
|
||||
v 0.399961 -0.500000 0.399961
|
||||
v 0.500000 -0.399961 0.399961
|
||||
v 0.399961 -0.438244 0.492385
|
||||
v 0.399961 -0.470699 0.470699
|
||||
v 0.438244 -0.399961 0.492385
|
||||
v 0.439203 -0.439203 0.483194
|
||||
v 0.437212 -0.465612 0.465612
|
||||
v 0.457718 -0.457718 0.457718
|
||||
v 0.438244 -0.492385 0.399961
|
||||
v 0.470699 -0.470699 0.399961
|
||||
v 0.399961 -0.492385 0.438244
|
||||
v 0.439203 -0.483194 0.439203
|
||||
v 0.465612 -0.465612 0.437212
|
||||
v 0.492385 -0.399961 0.438244
|
||||
v 0.470699 -0.399961 0.470699
|
||||
v 0.492385 -0.438244 0.399961
|
||||
v 0.483194 -0.439203 0.439203
|
||||
v 0.465612 -0.437212 0.465612
|
||||
v -0.500000 0.399961 -0.399961
|
||||
v -0.399961 0.500000 -0.399961
|
||||
v -0.399961 0.399961 -0.500000
|
||||
v -0.492385 0.438244 -0.399961
|
||||
v -0.470699 0.470699 -0.399961
|
||||
v -0.492385 0.399961 -0.438244
|
||||
v -0.483194 0.439203 -0.439203
|
||||
v -0.465612 0.465612 -0.437212
|
||||
v -0.457718 0.457718 -0.457718
|
||||
v -0.399961 0.492385 -0.438244
|
||||
v -0.399961 0.470699 -0.470699
|
||||
v -0.438244 0.492385 -0.399961
|
||||
v -0.439203 0.483194 -0.439203
|
||||
v -0.437212 0.465612 -0.465612
|
||||
v -0.438244 0.399961 -0.492385
|
||||
v -0.470699 0.399961 -0.470699
|
||||
v -0.399961 0.438244 -0.492385
|
||||
v -0.439203 0.439203 -0.483194
|
||||
v -0.465612 0.437212 -0.465612
|
||||
v -0.399961 -0.399961 -0.500000
|
||||
v -0.399961 -0.500000 -0.399961
|
||||
v -0.500000 -0.399961 -0.399961
|
||||
v -0.399961 -0.438244 -0.492385
|
||||
v -0.399961 -0.470699 -0.470699
|
||||
v -0.438244 -0.399961 -0.492385
|
||||
v -0.439203 -0.439203 -0.483194
|
||||
v -0.437212 -0.465612 -0.465612
|
||||
v -0.457718 -0.457718 -0.457718
|
||||
v -0.438244 -0.492385 -0.399961
|
||||
v -0.470699 -0.470699 -0.399961
|
||||
v -0.399961 -0.492385 -0.438244
|
||||
v -0.439203 -0.483194 -0.439203
|
||||
v -0.465612 -0.465612 -0.437212
|
||||
v -0.492385 -0.399961 -0.438244
|
||||
v -0.470699 -0.399961 -0.470699
|
||||
v -0.492385 -0.438244 -0.399961
|
||||
v -0.483194 -0.439203 -0.439203
|
||||
v -0.465612 -0.437212 -0.465612
|
||||
v -0.500000 0.399961 0.399961
|
||||
v -0.399961 0.399961 0.500000
|
||||
v -0.399961 0.500000 0.399961
|
||||
v -0.492385 0.399961 0.438244
|
||||
v -0.470699 0.399961 0.470699
|
||||
v -0.492385 0.438244 0.399961
|
||||
v -0.483194 0.439203 0.439203
|
||||
v -0.465612 0.437212 0.465612
|
||||
v -0.457718 0.457718 0.457718
|
||||
v -0.399961 0.438244 0.492385
|
||||
v -0.399961 0.470699 0.470699
|
||||
v -0.438244 0.399961 0.492385
|
||||
v -0.439203 0.439203 0.483194
|
||||
v -0.437212 0.465612 0.465612
|
||||
v -0.438244 0.492385 0.399961
|
||||
v -0.470699 0.470699 0.399961
|
||||
v -0.399961 0.492385 0.438244
|
||||
v -0.439203 0.483194 0.439203
|
||||
v -0.465612 0.465612 0.437212
|
||||
v -0.399961 -0.399961 0.500000
|
||||
v -0.500000 -0.399961 0.399961
|
||||
v -0.399961 -0.500000 0.399961
|
||||
v -0.438244 -0.399961 0.492385
|
||||
v -0.470699 -0.399961 0.470699
|
||||
v -0.399961 -0.438244 0.492385
|
||||
v -0.439203 -0.439203 0.483194
|
||||
v -0.465612 -0.437212 0.465612
|
||||
v -0.457718 -0.457718 0.457718
|
||||
v -0.492385 -0.438244 0.399961
|
||||
v -0.470699 -0.470699 0.399961
|
||||
v -0.492385 -0.399961 0.438244
|
||||
v -0.483194 -0.439203 0.439203
|
||||
v -0.465612 -0.465612 0.437212
|
||||
v -0.399961 -0.492385 0.438244
|
||||
v -0.399961 -0.470699 0.470699
|
||||
v -0.438244 -0.492385 0.399961
|
||||
v -0.439203 -0.483194 0.439203
|
||||
v -0.437212 -0.465612 0.465612
|
||||
vt 0.150010 0.525010
|
||||
vt 0.349990 0.525010
|
||||
vt 0.349990 0.724990
|
||||
vt 0.150010 0.724990
|
||||
vt 0.650010 0.525010
|
||||
vt 0.849990 0.525010
|
||||
vt 0.849990 0.724990
|
||||
vt 0.650010 0.724990
|
||||
vt 0.400010 0.275010
|
||||
vt 0.599990 0.275010
|
||||
vt 0.599990 0.474990
|
||||
vt 0.400010 0.474990
|
||||
vt 0.400010 0.775010
|
||||
vt 0.599990 0.775010
|
||||
vt 0.599990 0.974990
|
||||
vt 0.400010 0.974990
|
||||
vt 0.400010 0.025010
|
||||
vt 0.599990 0.025010
|
||||
vt 0.599990 0.224990
|
||||
vt 0.400010 0.224990
|
||||
vt 0.400010 0.525010
|
||||
vt 0.390439 0.525010
|
||||
vt 0.390199 0.515199
|
||||
vt 0.400010 0.515439
|
||||
vt 0.375000 0.525010
|
||||
vt 0.375000 0.515697
|
||||
vt 0.390697 0.500000
|
||||
vt 0.400010 0.500000
|
||||
vt 0.375000 0.510570
|
||||
vt 0.599990 0.265439
|
||||
vt 0.609801 0.265199
|
||||
vt 0.609561 0.275010
|
||||
vt 0.599990 0.250000
|
||||
vt 0.609303 0.250000
|
||||
vt 0.625000 0.265697
|
||||
vt 0.625000 0.275010
|
||||
vt 0.614430 0.250000
|
||||
vt 0.859561 0.724990
|
||||
vt 0.859801 0.734801
|
||||
vt 0.849990 0.734561
|
||||
vt 0.875000 0.724990
|
||||
vt 0.875000 0.734303
|
||||
vt 0.859303 0.750000
|
||||
vt 0.849990 0.750000
|
||||
vt 0.875000 0.739430
|
||||
vt 0.390439 0.275010
|
||||
vt 0.390199 0.265199
|
||||
vt 0.400010 0.265439
|
||||
vt 0.375000 0.275010
|
||||
vt 0.375000 0.265697
|
||||
vt 0.390697 0.250000
|
||||
vt 0.400010 0.250000
|
||||
vt 0.375000 0.260570
|
||||
vt 0.599990 0.015439
|
||||
vt 0.609801 0.015199
|
||||
vt 0.609561 0.025010
|
||||
vt 0.599990 0.000000
|
||||
vt 0.609303 0.000000
|
||||
vt 0.625000 0.015697
|
||||
vt 0.625000 0.025010
|
||||
vt 0.614430 0.000000
|
||||
vt 0.650010 0.734561
|
||||
vt 0.640199 0.734801
|
||||
vt 0.640439 0.724990
|
||||
vt 0.650010 0.750000
|
||||
vt 0.640697 0.750000
|
||||
vt 0.625000 0.734303
|
||||
vt 0.625000 0.724990
|
||||
vt 0.635570 0.750000
|
||||
vt 0.609561 0.474990
|
||||
vt 0.609801 0.484801
|
||||
vt 0.599990 0.484561
|
||||
vt 0.625000 0.474990
|
||||
vt 0.625000 0.484303
|
||||
vt 0.609303 0.500000
|
||||
vt 0.599990 0.500000
|
||||
vt 0.625000 0.489430
|
||||
vt 0.400010 0.724990
|
||||
vt 0.400010 0.734561
|
||||
vt 0.390199 0.734801
|
||||
vt 0.390439 0.724990
|
||||
vt 0.400010 0.750000
|
||||
vt 0.390697 0.750000
|
||||
vt 0.375000 0.734303
|
||||
vt 0.375000 0.724990
|
||||
vt 0.385570 0.750000
|
||||
vt 0.349990 0.515439
|
||||
vt 0.359801 0.515199
|
||||
vt 0.359561 0.525010
|
||||
vt 0.349990 0.500000
|
||||
vt 0.359303 0.500000
|
||||
vt 0.375000 0.515697
|
||||
vt 0.375000 0.525010
|
||||
vt 0.364430 0.500000
|
||||
vt 0.140439 0.525010
|
||||
vt 0.140199 0.515199
|
||||
vt 0.150010 0.515439
|
||||
vt 0.125000 0.525010
|
||||
vt 0.125000 0.515697
|
||||
vt 0.140697 0.500000
|
||||
vt 0.150010 0.500000
|
||||
vt 0.125000 0.510570
|
||||
vt 0.609561 0.224990
|
||||
vt 0.609801 0.234801
|
||||
vt 0.599990 0.234561
|
||||
vt 0.625000 0.224990
|
||||
vt 0.625000 0.234303
|
||||
vt 0.609303 0.250000
|
||||
vt 0.599990 0.250000
|
||||
vt 0.625000 0.239430
|
||||
vt 0.400010 0.484561
|
||||
vt 0.390199 0.484801
|
||||
vt 0.390439 0.474990
|
||||
vt 0.400010 0.500000
|
||||
vt 0.390697 0.500000
|
||||
vt 0.375000 0.484303
|
||||
vt 0.375000 0.474990
|
||||
vt 0.385570 0.500000
|
||||
vt 0.609561 0.974990
|
||||
vt 0.609801 0.984801
|
||||
vt 0.599990 0.984561
|
||||
vt 0.625000 0.974990
|
||||
vt 0.625000 0.984303
|
||||
vt 0.609303 1.000000
|
||||
vt 0.599990 1.000000
|
||||
vt 0.625000 0.989430
|
||||
vt 0.599990 0.525010
|
||||
vt 0.599990 0.515439
|
||||
vt 0.609801 0.515199
|
||||
vt 0.609561 0.525010
|
||||
vt 0.599990 0.500000
|
||||
vt 0.609303 0.500000
|
||||
vt 0.625000 0.515697
|
||||
vt 0.625000 0.525010
|
||||
vt 0.614430 0.500000
|
||||
vt 0.849990 0.515439
|
||||
vt 0.859801 0.515199
|
||||
vt 0.859561 0.525010
|
||||
vt 0.849990 0.500000
|
||||
vt 0.859303 0.500000
|
||||
vt 0.875000 0.515697
|
||||
vt 0.875000 0.525010
|
||||
vt 0.864430 0.500000
|
||||
vt 0.640439 0.525010
|
||||
vt 0.640199 0.515199
|
||||
vt 0.650010 0.515439
|
||||
vt 0.625000 0.525010
|
||||
vt 0.625000 0.515697
|
||||
vt 0.640697 0.500000
|
||||
vt 0.650010 0.500000
|
||||
vt 0.625000 0.510570
|
||||
vt 0.390439 0.025010
|
||||
vt 0.390199 0.015199
|
||||
vt 0.400010 0.015439
|
||||
vt 0.375000 0.025010
|
||||
vt 0.375000 0.015697
|
||||
vt 0.390697 0.000000
|
||||
vt 0.400010 0.000000
|
||||
vt 0.375000 0.010570
|
||||
vt 0.400010 0.984561
|
||||
vt 0.390199 0.984801
|
||||
vt 0.390439 0.974990
|
||||
vt 0.400010 1.000000
|
||||
vt 0.390697 1.000000
|
||||
vt 0.375000 0.984303
|
||||
vt 0.375000 0.974990
|
||||
vt 0.385570 1.000000
|
||||
vt 0.599990 0.765439
|
||||
vt 0.609801 0.765199
|
||||
vt 0.609561 0.775010
|
||||
vt 0.599990 0.750000
|
||||
vt 0.609303 0.750000
|
||||
vt 0.625000 0.765697
|
||||
vt 0.625000 0.775010
|
||||
vt 0.614430 0.750000
|
||||
vt 0.359561 0.724990
|
||||
vt 0.359801 0.734801
|
||||
vt 0.349990 0.734561
|
||||
vt 0.375000 0.724990
|
||||
vt 0.375000 0.734303
|
||||
vt 0.359303 0.750000
|
||||
vt 0.349990 0.750000
|
||||
vt 0.375000 0.739430
|
||||
vt 0.599990 0.724990
|
||||
vt 0.609561 0.724990
|
||||
vt 0.609801 0.734801
|
||||
vt 0.599990 0.734561
|
||||
vt 0.625000 0.724990
|
||||
vt 0.625000 0.734303
|
||||
vt 0.609303 0.750000
|
||||
vt 0.599990 0.750000
|
||||
vt 0.625000 0.739430
|
||||
vt 0.150010 0.734561
|
||||
vt 0.140199 0.734801
|
||||
vt 0.140439 0.724990
|
||||
vt 0.150010 0.750000
|
||||
vt 0.140697 0.750000
|
||||
vt 0.125000 0.734303
|
||||
vt 0.125000 0.724990
|
||||
vt 0.135570 0.750000
|
||||
vt 0.390439 0.775010
|
||||
vt 0.390199 0.765199
|
||||
vt 0.400010 0.765439
|
||||
vt 0.375000 0.775010
|
||||
vt 0.375000 0.765697
|
||||
vt 0.390697 0.750000
|
||||
vt 0.400010 0.750000
|
||||
vt 0.375000 0.760570
|
||||
vt 0.400010 0.234561
|
||||
vt 0.390199 0.234801
|
||||
vt 0.390439 0.224990
|
||||
vt 0.400010 0.250000
|
||||
vt 0.390697 0.250000
|
||||
vt 0.375000 0.234303
|
||||
vt 0.375000 0.224990
|
||||
vt 0.385570 0.250000
|
||||
vn 0.1004 -0.1004 0.9899
|
||||
vn 0.1004 0.1004 0.9899
|
||||
vn -0.1004 0.1004 0.9899
|
||||
vn -0.1004 -0.1004 0.9899
|
||||
vn -0.1004 -0.1004 -0.9899
|
||||
vn -0.1004 0.1004 -0.9899
|
||||
vn 0.1004 0.1004 -0.9899
|
||||
vn 0.1004 -0.1004 -0.9899
|
||||
vn 0.9899 -0.1004 -0.1004
|
||||
vn 0.9899 0.1004 -0.1004
|
||||
vn 0.9899 0.1004 0.1004
|
||||
vn 0.9899 -0.1004 0.1004
|
||||
vn -0.9899 -0.1004 0.1004
|
||||
vn -0.9899 0.1004 0.1004
|
||||
vn -0.9899 0.1004 -0.1004
|
||||
vn -0.9899 -0.1004 -0.1004
|
||||
vn -0.1004 -0.9899 -0.1004
|
||||
vn 0.1004 -0.9899 -0.1004
|
||||
vn 0.1004 -0.9899 0.1004
|
||||
vn -0.1004 -0.9899 0.1004
|
||||
vn 0.1004 0.9899 -0.1004
|
||||
vn 0.3792 0.9201 -0.0981
|
||||
vn 0.3673 0.8545 -0.3673
|
||||
vn 0.0981 0.9201 -0.3792
|
||||
vn 0.7041 0.7041 -0.0919
|
||||
vn 0.6663 0.6663 -0.3347
|
||||
vn 0.3347 0.6663 -0.6663
|
||||
vn 0.0919 0.7041 -0.7041
|
||||
vn 0.5774 0.5774 -0.5774
|
||||
vn 0.9201 0.0981 -0.3792
|
||||
vn 0.8545 0.3673 -0.3673
|
||||
vn 0.9201 0.3792 -0.0981
|
||||
vn 0.7041 0.0919 -0.7041
|
||||
vn 0.6663 0.3347 -0.6663
|
||||
vn 0.0981 0.3792 -0.9201
|
||||
vn 0.3673 0.3673 -0.8545
|
||||
vn 0.3792 0.0981 -0.9201
|
||||
vn 0.9201 -0.3792 -0.0981
|
||||
vn 0.8545 -0.3673 -0.3673
|
||||
vn 0.9201 -0.0981 -0.3792
|
||||
vn 0.7041 -0.7041 -0.0919
|
||||
vn 0.6663 -0.6663 -0.3347
|
||||
vn 0.6663 -0.3347 -0.6663
|
||||
vn 0.7041 -0.0919 -0.7041
|
||||
vn 0.5774 -0.5774 -0.5773
|
||||
vn 0.0981 -0.9201 -0.3792
|
||||
vn 0.3673 -0.8545 -0.3673
|
||||
vn 0.3792 -0.9201 -0.0981
|
||||
vn 0.0919 -0.7041 -0.7041
|
||||
vn 0.3347 -0.6663 -0.6663
|
||||
vn 0.3792 -0.0981 -0.9201
|
||||
vn 0.3673 -0.3673 -0.8545
|
||||
vn 0.0981 -0.3792 -0.9201
|
||||
vn 0.9201 0.3792 0.0981
|
||||
vn 0.8545 0.3673 0.3673
|
||||
vn 0.9201 0.0981 0.3792
|
||||
vn 0.7041 0.7041 0.0919
|
||||
vn 0.6663 0.6663 0.3347
|
||||
vn 0.6663 0.3347 0.6663
|
||||
vn 0.7041 0.0919 0.7041
|
||||
vn 0.5774 0.5774 0.5773
|
||||
vn 0.1004 0.9899 0.1004
|
||||
vn 0.0981 0.9201 0.3792
|
||||
vn 0.3673 0.8545 0.3673
|
||||
vn 0.3792 0.9201 0.0981
|
||||
vn 0.0919 0.7041 0.7041
|
||||
vn 0.3347 0.6663 0.6663
|
||||
vn 0.3792 0.0981 0.9201
|
||||
vn 0.3673 0.3673 0.8545
|
||||
vn 0.0981 0.3792 0.9201
|
||||
vn 0.0981 -0.3792 0.9201
|
||||
vn 0.3673 -0.3673 0.8545
|
||||
vn 0.3792 -0.0981 0.9201
|
||||
vn 0.0919 -0.7041 0.7041
|
||||
vn 0.3347 -0.6663 0.6663
|
||||
vn 0.6663 -0.3347 0.6663
|
||||
vn 0.7041 -0.0919 0.7041
|
||||
vn 0.5773 -0.5774 0.5774
|
||||
vn 0.3792 -0.9201 0.0981
|
||||
vn 0.3673 -0.8545 0.3673
|
||||
vn 0.0981 -0.9201 0.3792
|
||||
vn 0.7041 -0.7041 0.0919
|
||||
vn 0.6663 -0.6663 0.3347
|
||||
vn 0.9201 -0.0981 0.3792
|
||||
vn 0.8545 -0.3673 0.3673
|
||||
vn 0.9201 -0.3792 0.0981
|
||||
vn -0.9201 0.3792 -0.0981
|
||||
vn -0.8545 0.3673 -0.3673
|
||||
vn -0.9201 0.0981 -0.3792
|
||||
vn -0.7041 0.7041 -0.0919
|
||||
vn -0.6663 0.6663 -0.3347
|
||||
vn -0.6663 0.3347 -0.6663
|
||||
vn -0.7041 0.0919 -0.7041
|
||||
vn -0.5774 0.5774 -0.5773
|
||||
vn -0.1004 0.9899 -0.1004
|
||||
vn -0.0981 0.9201 -0.3792
|
||||
vn -0.3673 0.8545 -0.3673
|
||||
vn -0.3792 0.9201 -0.0981
|
||||
vn -0.0919 0.7041 -0.7041
|
||||
vn -0.3347 0.6663 -0.6663
|
||||
vn -0.3792 0.0981 -0.9201
|
||||
vn -0.3673 0.3673 -0.8545
|
||||
vn -0.0981 0.3792 -0.9201
|
||||
vn -0.0981 -0.3792 -0.9201
|
||||
vn -0.3673 -0.3673 -0.8545
|
||||
vn -0.3792 -0.0981 -0.9201
|
||||
vn -0.0919 -0.7041 -0.7041
|
||||
vn -0.3347 -0.6663 -0.6663
|
||||
vn -0.6663 -0.3347 -0.6663
|
||||
vn -0.7041 -0.0919 -0.7041
|
||||
vn -0.5773 -0.5774 -0.5774
|
||||
vn -0.3792 -0.9201 -0.0981
|
||||
vn -0.3673 -0.8545 -0.3673
|
||||
vn -0.0981 -0.9201 -0.3792
|
||||
vn -0.7041 -0.7041 -0.0919
|
||||
vn -0.6663 -0.6663 -0.3347
|
||||
vn -0.9201 -0.0981 -0.3792
|
||||
vn -0.8545 -0.3673 -0.3673
|
||||
vn -0.9201 -0.3792 -0.0981
|
||||
vn -0.9201 0.0981 0.3792
|
||||
vn -0.8545 0.3673 0.3673
|
||||
vn -0.9201 0.3792 0.0981
|
||||
vn -0.7041 0.0919 0.7041
|
||||
vn -0.6663 0.3347 0.6663
|
||||
vn -0.6663 0.6663 0.3347
|
||||
vn -0.7041 0.7041 0.0919
|
||||
vn -0.5774 0.5774 0.5773
|
||||
vn -0.0981 0.3792 0.9201
|
||||
vn -0.3673 0.3673 0.8545
|
||||
vn -0.3792 0.0981 0.9201
|
||||
vn -0.0919 0.7041 0.7041
|
||||
vn -0.3347 0.6663 0.6663
|
||||
vn -0.1004 0.9899 0.1004
|
||||
vn -0.3792 0.9201 0.0981
|
||||
vn -0.3673 0.8545 0.3673
|
||||
vn -0.0981 0.9201 0.3792
|
||||
vn -0.3792 -0.0981 0.9201
|
||||
vn -0.3673 -0.3673 0.8545
|
||||
vn -0.0981 -0.3792 0.9201
|
||||
vn -0.7041 -0.0919 0.7041
|
||||
vn -0.6663 -0.3347 0.6663
|
||||
vn -0.3347 -0.6663 0.6663
|
||||
vn -0.0919 -0.7041 0.7041
|
||||
vn -0.5774 -0.5774 0.5773
|
||||
vn -0.9201 -0.3792 0.0981
|
||||
vn -0.8545 -0.3673 0.3673
|
||||
vn -0.9201 -0.0981 0.3792
|
||||
vn -0.7041 -0.7041 0.0919
|
||||
vn -0.6663 -0.6663 0.3347
|
||||
vn -0.0981 -0.9201 0.3792
|
||||
vn -0.3673 -0.8545 0.3673
|
||||
vn -0.3792 -0.9201 0.0981
|
||||
s 1
|
||||
f 58/1/1 41/2/2 116/3/3 134/4/4
|
||||
f 96/5/5 79/6/6 3/7/7 22/8/8
|
||||
f 20/9/9 2/10/10 39/11/11 60/12/12
|
||||
f 135/13/13 115/14/14 77/15/15 98/16/16
|
||||
f 97/17/17 21/18/18 59/19/19 136/20/20
|
||||
f 1/21/21 4/22/22 7/23/23 6/24/24
|
||||
f 4/22/22 5/25/25 8/26/26 7/23/23
|
||||
f 6/24/24 7/23/23 19/27/27 16/28/28
|
||||
f 7/23/23 8/26/26 9/29/29 19/27/27
|
||||
f 2/10/10 10/30/30 13/31/31 12/32/32
|
||||
f 10/30/30 11/33/33 14/34/34 13/31/31
|
||||
f 12/32/32 13/31/31 8/35/26 5/36/25
|
||||
f 13/31/31 14/34/34 9/37/29 8/35/26
|
||||
f 3/7/7 15/38/35 18/39/36 17/40/37
|
||||
f 15/38/35 16/41/28 19/42/27 18/39/36
|
||||
f 17/40/37 18/39/36 14/43/34 11/44/33
|
||||
f 18/39/36 19/42/27 9/45/29 14/43/34
|
||||
f 20/9/9 23/46/38 26/47/39 25/48/40
|
||||
f 23/46/38 24/49/41 27/50/42 26/47/39
|
||||
f 25/48/40 26/47/39 38/51/43 35/52/44
|
||||
f 26/47/39 27/50/42 28/53/45 38/51/43
|
||||
f 21/18/18 29/54/46 32/55/47 31/56/48
|
||||
f 29/54/46 30/57/49 33/58/50 32/55/47
|
||||
f 31/56/48 32/55/47 27/59/42 24/60/41
|
||||
f 32/55/47 33/58/50 28/61/45 27/59/42
|
||||
f 22/8/8 34/62/51 37/63/52 36/64/53
|
||||
f 34/62/51 35/65/44 38/66/43 37/63/52
|
||||
f 36/64/53 37/63/52 33/67/50 30/68/49
|
||||
f 37/63/52 38/66/43 28/69/45 33/67/50
|
||||
f 39/11/11 42/70/54 45/71/55 44/72/56
|
||||
f 42/70/54 43/73/57 46/74/58 45/71/55
|
||||
f 44/72/56 45/71/55 57/75/59 54/76/60
|
||||
f 45/71/55 46/74/58 47/77/61 57/75/59
|
||||
f 40/78/62 48/79/63 51/80/64 50/81/65
|
||||
f 48/79/63 49/82/66 52/83/67 51/80/64
|
||||
f 50/81/65 51/80/64 46/84/58 43/85/57
|
||||
f 51/80/64 52/83/67 47/86/61 46/84/58
|
||||
f 41/2/2 53/87/68 56/88/69 55/89/70
|
||||
f 53/87/68 54/90/60 57/91/59 56/88/69
|
||||
f 55/89/70 56/88/69 52/92/67 49/93/66
|
||||
f 56/88/69 57/91/59 47/94/61 52/92/67
|
||||
f 58/1/1 61/95/71 64/96/72 63/97/73
|
||||
f 61/95/71 62/98/74 65/99/75 64/96/72
|
||||
f 63/97/73 64/96/72 76/100/76 73/101/77
|
||||
f 64/96/72 65/99/75 66/102/78 76/100/76
|
||||
f 59/19/19 67/103/79 70/104/80 69/105/81
|
||||
f 67/103/79 68/106/82 71/107/83 70/104/80
|
||||
f 69/105/81 70/104/80 65/108/75 62/109/74
|
||||
f 70/104/80 71/107/83 66/110/78 65/108/75
|
||||
f 60/12/12 72/111/84 75/112/85 74/113/86
|
||||
f 72/111/84 73/114/77 76/115/76 75/112/85
|
||||
f 74/113/86 75/112/85 71/116/83 68/117/82
|
||||
f 75/112/85 76/115/76 66/118/78 71/116/83
|
||||
f 77/15/15 80/119/87 83/120/88 82/121/89
|
||||
f 80/119/87 81/122/90 84/123/91 83/120/88
|
||||
f 82/121/89 83/120/88 95/124/92 92/125/93
|
||||
f 83/120/88 84/123/91 85/126/94 95/124/92
|
||||
f 78/127/95 86/128/96 89/129/97 88/130/98
|
||||
f 86/128/96 87/131/99 90/132/100 89/129/97
|
||||
f 88/130/98 89/129/97 84/133/91 81/134/90
|
||||
f 89/129/97 90/132/100 85/135/94 84/133/91
|
||||
f 79/6/6 91/136/101 94/137/102 93/138/103
|
||||
f 91/136/101 92/139/93 95/140/92 94/137/102
|
||||
f 93/138/103 94/137/102 90/141/100 87/142/99
|
||||
f 94/137/102 95/140/92 85/143/94 90/141/100
|
||||
f 96/5/5 99/144/104 102/145/105 101/146/106
|
||||
f 99/144/104 100/147/107 103/148/108 102/145/105
|
||||
f 101/146/106 102/145/105 114/149/109 111/150/110
|
||||
f 102/145/105 103/148/108 104/151/111 114/149/109
|
||||
f 97/17/17 105/152/112 108/153/113 107/154/114
|
||||
f 105/152/112 106/155/115 109/156/116 108/153/113
|
||||
f 107/154/114 108/153/113 103/157/108 100/158/107
|
||||
f 108/153/113 109/156/116 104/159/111 103/157/108
|
||||
f 98/16/16 110/160/117 113/161/118 112/162/119
|
||||
f 110/160/117 111/163/110 114/164/109 113/161/118
|
||||
f 112/162/119 113/161/118 109/165/116 106/166/115
|
||||
f 113/161/118 114/164/109 104/167/111 109/165/116
|
||||
f 115/14/14 118/168/120 121/169/121 120/170/122
|
||||
f 118/168/120 119/171/123 122/172/124 121/169/121
|
||||
f 120/170/122 121/169/121 133/173/125 130/174/126
|
||||
f 121/169/121 122/172/124 123/175/127 133/173/125
|
||||
f 116/3/3 124/176/128 127/177/129 126/178/130
|
||||
f 124/176/128 125/179/131 128/180/132 127/177/129
|
||||
f 126/178/130 127/177/129 122/181/124 119/182/123
|
||||
f 127/177/129 128/180/132 123/183/127 122/181/124
|
||||
f 117/184/133 129/185/134 132/186/135 131/187/136
|
||||
f 129/185/134 130/188/126 133/189/125 132/186/135
|
||||
f 131/187/136 132/186/135 128/190/132 125/191/131
|
||||
f 132/186/135 133/189/125 123/192/127 128/190/132
|
||||
f 134/4/4 137/193/137 140/194/138 139/195/139
|
||||
f 137/193/137 138/196/140 141/197/141 140/194/138
|
||||
f 139/195/139 140/194/138 152/198/142 149/199/143
|
||||
f 140/194/138 141/197/141 142/200/144 152/198/142
|
||||
f 135/13/13 143/201/145 146/202/146 145/203/147
|
||||
f 143/201/145 144/204/148 147/205/149 146/202/146
|
||||
f 145/203/147 146/202/146 141/206/141 138/207/140
|
||||
f 146/202/146 147/205/149 142/208/144 141/206/141
|
||||
f 136/20/20 148/209/150 151/210/151 150/211/152
|
||||
f 148/209/150 149/212/143 152/213/142 151/210/151
|
||||
f 150/211/152 151/210/151 147/214/149 144/215/148
|
||||
f 151/210/151 152/213/142 142/216/144 147/214/149
|
||||
f 136/20/20 59/19/19 69/105/81 148/209/150
|
||||
f 148/209/150 69/105/81 62/109/74 149/212/143
|
||||
f 149/199/143 62/98/74 61/95/71 139/195/139
|
||||
f 139/195/139 61/95/71 58/1/1 134/4/4
|
||||
f 59/19/19 21/18/18 31/56/48 67/103/79
|
||||
f 67/103/79 31/56/48 24/60/41 68/106/82
|
||||
f 68/117/82 24/49/41 23/46/38 74/113/86
|
||||
f 74/113/86 23/46/38 20/9/9 60/12/12
|
||||
f 1/21/21 40/78/62 50/81/65 4/22/22
|
||||
f 4/22/22 50/81/65 43/85/57 5/25/25
|
||||
f 5/36/25 43/73/57 42/70/54 12/32/32
|
||||
f 12/32/32 42/70/54 39/11/11 2/10/10
|
||||
f 21/18/18 97/17/17 107/154/114 29/54/46
|
||||
f 29/54/46 107/154/114 100/158/107 30/57/49
|
||||
f 30/68/49 100/147/107 99/144/104 36/64/53
|
||||
f 36/64/53 99/144/104 96/5/5 22/8/8
|
||||
f 117/184/133 78/127/95 88/130/98 129/185/134
|
||||
f 129/185/134 88/130/98 81/134/90 130/188/126
|
||||
f 130/174/126 81/122/90 80/119/87 120/170/122
|
||||
f 120/170/122 80/119/87 77/15/15 115/14/14
|
||||
f 97/17/17 136/20/20 150/211/152 105/152/112
|
||||
f 105/152/112 150/211/152 144/215/148 106/155/115
|
||||
f 106/166/115 144/204/148 143/201/145 112/162/119
|
||||
f 112/162/119 143/201/145 135/13/13 98/16/16
|
||||
f 40/78/62 117/184/133 131/187/136 48/79/63
|
||||
f 48/79/63 131/187/136 125/191/131 49/82/66
|
||||
f 49/93/66 125/179/131 124/176/128 55/89/70
|
||||
f 55/89/70 124/176/128 116/3/3 41/2/2
|
||||
f 41/2/2 58/1/1 63/97/73 53/87/68
|
||||
f 53/87/68 63/97/73 73/101/77 54/90/60
|
||||
f 54/76/60 73/114/77 72/111/84 44/72/56
|
||||
f 44/72/56 72/111/84 60/12/12 39/11/11
|
||||
f 2/10/10 20/9/9 25/48/40 10/30/30
|
||||
f 10/30/30 25/48/40 35/52/44 11/33/33
|
||||
f 11/44/33 35/65/44 34/62/51 17/40/37
|
||||
f 17/40/37 34/62/51 22/8/8 3/7/7
|
||||
f 134/4/4 116/3/3 126/178/130 137/193/137
|
||||
f 137/193/137 126/178/130 119/182/123 138/196/140
|
||||
f 138/207/140 119/171/123 118/168/120 145/203/147
|
||||
f 145/203/147 118/168/120 115/14/14 135/13/13
|
||||
f 78/127/95 1/21/21 6/24/24 86/128/96
|
||||
f 86/128/96 6/24/24 16/28/28 87/131/99
|
||||
f 87/142/99 16/41/28 15/38/35 93/138/103
|
||||
f 93/138/103 15/38/35 3/7/7 79/6/6
|
||||
f 79/6/6 96/5/5 101/146/106 91/136/101
|
||||
f 91/136/101 101/146/106 111/150/110 92/139/93
|
||||
f 92/125/93 111/163/110 110/160/117 82/121/89
|
||||
f 82/121/89 110/160/117 98/16/16 77/15/15
|
||||
f 1/21/21 78/127/95 117/184/133 40/78/62
|
||||
`;
|
||||
|
||||
type GeomRecord = Record<SomaesqueGeometry, THREE.BufferGeometry>;
|
||||
|
||||
export default class GeometryManager {
|
||||
@@ -108,12 +785,8 @@ export default class GeometryManager {
|
||||
};
|
||||
const load = (resolve: (geom: THREE.BufferGeometry) => any, reject: (err: string) => any) => {
|
||||
const loader = new OBJLoader();
|
||||
loader.load(
|
||||
`${this.root}${id}.obj`,
|
||||
obj => onLoaded(obj, resolve),
|
||||
() => {},
|
||||
(err) => reject(`Error loading OBJ file: ${err}`),
|
||||
);
|
||||
const result = loader.parse(OBJ);
|
||||
onLoaded(result, resolve);
|
||||
};
|
||||
return new Promise(load);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@ export default class PolycubeScene {
|
||||
this.cubeScene.rotateX(Math.PI/4);
|
||||
this.cubeScene.rotateY(Math.PI/4);
|
||||
this.controls = new RotationControl(this.cubeScene, this.polycubeMeshes, this.camera, this.canvas);
|
||||
this.geomManager = await new GeometryManager('../resources/', () => {
|
||||
this.geomManager = await new GeometryManager('./', () => {
|
||||
requestAnimationFrame((timestamp) => this.render(timestamp));
|
||||
});
|
||||
PolycubeMesh.setManager(this.geomManager);
|
||||
|
||||
25
src/utils.ts
Normal file
25
src/utils.ts
Normal file
@@ -0,0 +1,25 @@
|
||||
function hslToRgb(hslStr: string): string {
|
||||
const opt = new Option();
|
||||
opt.style.color = hslStr;
|
||||
return opt.style.color;
|
||||
}
|
||||
|
||||
function rgbToHex(rgbStr: string): string {
|
||||
const sep = rgbStr.indexOf(",") > -1 ? "," : " ";
|
||||
const rgb = rgbStr.substr(4).split(")")[0].split(sep);
|
||||
const r = (+rgb[0]).toString(16).padStart(2, "0");
|
||||
const g = (+rgb[1]).toString(16).padStart(2, "0");
|
||||
const b = (+rgb[2]).toString(16).padStart(2, "0");
|
||||
return "#" + r + g + b;
|
||||
}
|
||||
|
||||
export function colorFromIndex(index: number): string {
|
||||
const colorWheelCycle = Math.floor(index / 6);
|
||||
const darknessCycle = Math.floor(index / 12);
|
||||
const spacing = (360 / 6);
|
||||
const offset = colorWheelCycle === 0 ? 0 : spacing / (colorWheelCycle + 2);
|
||||
let hue = spacing * (index % 6) + offset;
|
||||
const saturation = 100;
|
||||
const lightness = 1 / (2 + darknessCycle) * 100;
|
||||
return rgbToHex(hslToRgb(`hsl(${hue},${saturation}%,${Math.round(lightness)}%)`));
|
||||
}
|
||||
Reference in New Issue
Block a user