From e4e95b0a1f83ce6ab1f24808741e7492292ac24e Mon Sep 17 00:00:00 2001 From: Lucas Dower Date: Sat, 21 Jan 2023 00:25:02 +0000 Subject: [PATCH] * Added 'rotation' option when loading a model * Fixed `voxelise` action not enabling after `import` action succeeds --- src/app_context.ts | 3 ++- src/mesh.ts | 34 +++++++++++++++++++++++++++++++ src/ui/elements/vector_spinbox.ts | 23 +-------------------- src/ui/layout.ts | 5 ++++- src/worker_client.ts | 1 + src/worker_types.ts | 23 +++++++++++---------- styles.css | 17 +++++++--------- tests/objlitematic.test.ts | 2 ++ tests/objobj.test.ts | 2 ++ tests/objschem.test.ts | 2 ++ tests/objschematic.test.ts | 2 ++ tools/headless-config.ts | 3 ++- 12 files changed, 71 insertions(+), 46 deletions(-) diff --git a/src/app_context.ts b/src/app_context.ts index df09dfb..98d5763 100644 --- a/src/app_context.ts +++ b/src/app_context.ts @@ -188,6 +188,7 @@ export class AppContext { action: 'Import', params: { filepath: uiElements.input.getValue(), + rotation: uiElements.rotation.getValue(), }, }; @@ -295,7 +296,7 @@ export class AppContext { const callback = (payload: TFromWorkerMessage) => { // This callback is not managed through `AppContext::do`, therefore // we need to check the payload is not an error - this._ui.enableTo(EAction.Materials); + this._ui.enableTo(EAction.Voxelise); switch (payload.action) { case 'KnownError': diff --git a/src/mesh.ts b/src/mesh.ts index 2f20f69..790cea3 100644 --- a/src/mesh.ts +++ b/src/mesh.ts @@ -3,6 +3,7 @@ import path from 'path'; import { Bounds } from './bounds'; import { RGBA, RGBAColours, RGBAUtil } from './colour'; +import { degreesToRadians } from './math'; import { StatusHandler } from './status'; import { Texture, TextureConverter, TextureFiltering } from './texture'; import { Triangle, UVTriangle } from './triangle'; @@ -81,6 +82,39 @@ export class Mesh { this._loadTextures(); } + public rotateMesh(pitch: number, roll: number, yaw: number) { + const cosa = Math.cos(yaw * degreesToRadians); + const sina = Math.sin(yaw * degreesToRadians); + + const cosb = Math.cos(pitch * degreesToRadians); + const sinb = Math.sin(pitch * degreesToRadians); + + const cosc = Math.cos(roll * degreesToRadians); + const sinc = Math.sin(roll * degreesToRadians); + + const Axx = cosa*cosb; + const Axy = cosa*sinb*sinc - sina*cosc; + const Axz = cosa*sinb*cosc + sina*sinc; + + const Ayx = sina*cosb; + const Ayy = sina*sinb*sinc + cosa*cosc; + const Ayz = sina*sinb*cosc - cosa*sinc; + + const Azx = -sinb; + const Azy = cosb*sinc; + const Azz = cosb*cosc; + + this._vertices.forEach((vertex) => { + const px = vertex.x; + const py = vertex.y; + const pz = vertex.z; + + vertex.x = Axx * px + Axy * py + Axz * pz; + vertex.y = Ayx * px + Ayy * py + Ayz * pz; + vertex.z = Azx * px + Azy * py + Azz * pz; + }); + } + public getBounds() { const bounds = Bounds.getInfiniteBounds(); if (this._transform) { diff --git a/src/ui/elements/vector_spinbox.ts b/src/ui/elements/vector_spinbox.ts index 7da43c2..410c331 100644 --- a/src/ui/elements/vector_spinbox.ts +++ b/src/ui/elements/vector_spinbox.ts @@ -11,7 +11,7 @@ export class VectorSpinboxElement extends ConfigUIElement { - this._mouseover = axis; - if (this.getEnabled()) { - elementKey.classList.add('spinbox-key-hover'); - elementValue.classList.add('spinbox-value-hover'); - } - }; - elementValue.onmouseenter = () => { this._mouseover = axis; if (this.getEnabled()) { - elementKey.classList.add('spinbox-key-hover'); elementValue.classList.add('spinbox-value-hover'); } }; - elementKey.onmouseleave = () => { - this._mouseover = null; - if (this._dragging !== axis) { - elementKey.classList.remove('spinbox-key-hover'); - elementValue.classList.remove('spinbox-value-hover'); - } - }; - elementValue.onmouseleave = () => { this._mouseover = null; if (this._dragging !== axis) { - elementKey.classList.remove('spinbox-key-hover'); elementValue.classList.remove('spinbox-value-hover'); } }; @@ -125,9 +106,7 @@ export class VectorSpinboxElement extends ConfigUIElement { if (this._dragging !== null) { - const elementKey = UIUtil.getElementById(this._getKeyId(this._dragging)); const elementValue = UIUtil.getElementById(this._getKeyId(this._dragging)); - elementKey.classList.remove('spinbox-key-hover'); elementValue.classList.remove('spinbox-value-hover'); } diff --git a/src/ui/layout.ts b/src/ui/layout.ts index ec3ff4a..f20e99e 100644 --- a/src/ui/layout.ts +++ b/src/ui/layout.ts @@ -25,6 +25,7 @@ import { FileInputElement } from './elements/file_input'; import { OutputElement } from './elements/output'; import { SliderElement } from './elements/slider'; import { ToolbarItemElement } from './elements/toolbar_item'; +import { VectorSpinboxElement } from './elements/vector_spinbox'; export interface Group { label: string; @@ -48,8 +49,10 @@ export class UI { 'input': new FileInputElement() .setFileExtensions(['obj']) .setLabel('Wavefront .obj file'), + 'rotation': new VectorSpinboxElement() + .setLabel('Rotation'), }, - elementsOrder: ['input'], + elementsOrder: ['input', 'rotation'], submitButton: new ButtonElement() .setOnClick(() => { this._appContext.do(EAction.Import); diff --git a/src/worker_client.ts b/src/worker_client.ts index 1c1ad8b..ade4c8a 100644 --- a/src/worker_client.ts +++ b/src/worker_client.ts @@ -75,6 +75,7 @@ export class WorkerClient { importer.parseFile(params.filepath); this._loadedMesh = importer.toMesh(); this._loadedMesh.processMesh(); + this._loadedMesh.rotateMesh(params.rotation.y, params.rotation.x, params.rotation.z); return { triangleCount: this._loadedMesh.getTriangleCount(), diff --git a/src/worker_types.ts b/src/worker_types.ts index 1ef8b0a..775633b 100644 --- a/src/worker_types.ts +++ b/src/worker_types.ts @@ -21,20 +21,10 @@ export namespace InitParams { } } -export namespace SetMaterialsParams { - export type Input = { - materials: MaterialMap - } - - export type Output = { - materials: MaterialMap, - materialsChanged: string[], - } -} - export namespace ImportParams { export type Input = { filepath: string, + rotation: Vector3, } export type Output = { @@ -55,6 +45,17 @@ export namespace RenderMeshParams { } } +export namespace SetMaterialsParams { + export type Input = { + materials: MaterialMap + } + + export type Output = { + materials: MaterialMap, + materialsChanged: string[], + } +} + export namespace VoxeliseParams { export type Input = { constraintAxis: TAxis, diff --git a/styles.css b/styles.css index 7e1e10b..8e816a4 100644 --- a/styles.css +++ b/styles.css @@ -395,23 +395,20 @@ select:disabled { } .spinbox-value { + display: flex; + align-items: center; + justify-content: center; + height: calc(var(--property-height) - 2px); background: var(--prop-standard); border-radius: 5px; flex-grow: 1; - height: calc(32px - 8.5px); - padding: 8.5px 0px 0px 0px; font-weight: 300; - border-width: 1px 1px 1px 0px; - border-style: solid; - border: rgba(255, 255, 255, 0.0); - - color: var(--text-disabled); - align-self: center; - text-align: center; + border: 1px solid rgba(255, 255, 255, 0.0); + color: var(--text-standard); } .spinbox-value-hover { - border: rgba(255, 255, 255, 0.2) !important; + border: 1px solid rgba(255, 255, 255, 0.2) !important; background: var(--prop-hovered) !important; cursor: ew-resize; } diff --git a/tests/objlitematic.test.ts b/tests/objlitematic.test.ts index 5b96006..6eefd8a 100644 --- a/tests/objlitematic.test.ts +++ b/tests/objlitematic.test.ts @@ -1,12 +1,14 @@ import { TextureFiltering } from '../src/texture'; import { ColourSpace } from '../src/util'; import { AppPaths, PathUtil } from '../src/util/path_util'; +import { Vector3 } from '../src/vector'; import { runHeadless, THeadlessConfig } from '../tools/headless'; import { TEST_PREAMBLE } from './preamble'; const baseConfig: THeadlessConfig = { import: { filepath: '', // Must be an absolute path + rotation: new Vector3(0, 0, 0), }, voxelise: { voxeliser: 'bvh-ray', diff --git a/tests/objobj.test.ts b/tests/objobj.test.ts index 15b6872..5b4ab6c 100644 --- a/tests/objobj.test.ts +++ b/tests/objobj.test.ts @@ -1,12 +1,14 @@ import { TextureFiltering } from '../src/texture'; import { ColourSpace } from '../src/util'; import { AppPaths, PathUtil } from '../src/util/path_util'; +import { Vector3 } from '../src/vector'; import { runHeadless, THeadlessConfig } from '../tools/headless'; import { TEST_PREAMBLE } from './preamble'; const baseConfig: THeadlessConfig = { import: { filepath: '', // Must be an absolute path + rotation: new Vector3(0, 0, 0), }, voxelise: { voxeliser: 'bvh-ray', diff --git a/tests/objschem.test.ts b/tests/objschem.test.ts index cd95caa..c81721d 100644 --- a/tests/objschem.test.ts +++ b/tests/objschem.test.ts @@ -1,12 +1,14 @@ import { TextureFiltering } from '../src/texture'; import { ColourSpace } from '../src/util'; import { AppPaths, PathUtil } from '../src/util/path_util'; +import { Vector3 } from '../src/vector'; import { runHeadless, THeadlessConfig } from '../tools/headless'; import { TEST_PREAMBLE } from './preamble'; const baseConfig: THeadlessConfig = { import: { filepath: '', // Must be an absolute path + rotation: new Vector3(0, 0, 0), }, voxelise: { voxeliser: 'bvh-ray', diff --git a/tests/objschematic.test.ts b/tests/objschematic.test.ts index 2d7e33e..10434f7 100644 --- a/tests/objschematic.test.ts +++ b/tests/objschematic.test.ts @@ -1,12 +1,14 @@ import { TextureFiltering } from '../src/texture'; import { ColourSpace } from '../src/util'; import { AppPaths, PathUtil } from '../src/util/path_util'; +import { Vector3 } from '../src/vector'; import { runHeadless, THeadlessConfig } from '../tools/headless'; import { TEST_PREAMBLE } from './preamble'; const baseConfig: THeadlessConfig = { import: { filepath: '', // Must be an absolute path + rotation: new Vector3(0, 0, 0), }, voxelise: { voxeliser: 'bvh-ray', diff --git a/tools/headless-config.ts b/tools/headless-config.ts index b2259d9..8ac7761 100644 --- a/tools/headless-config.ts +++ b/tools/headless-config.ts @@ -1,10 +1,11 @@ -import { TextureFiltering } from '../src/texture'; import { ColourSpace } from '../src/util'; +import { Vector3 } from '../src/vector'; import { THeadlessConfig } from './headless'; export const headlessConfig: THeadlessConfig = { import: { filepath: '/Users/lucasdower/ObjToSchematic/res/samples/skull.obj', // Must be an absolute path + rotation: new Vector3(0, 0, 0), }, voxelise: { constraintAxis: 'y',