diff --git a/packages/frontend/src/main/components/viewer/CanonicalViews.vue b/packages/frontend/src/main/components/viewer/CanonicalViews.vue index 6a6570130..060ac0ec4 100644 --- a/packages/frontend/src/main/components/viewer/CanonicalViews.vue +++ b/packages/frontend/src/main/components/viewer/CanonicalViews.vue @@ -53,7 +53,7 @@ export default defineComponent({ }, methods: { setView(view: string) { - this.viewer.interactions.rotateTo(view.toLowerCase()) + this.viewer.rotateTo(view.toLowerCase()) } } }) diff --git a/packages/frontend/src/main/components/viewer/CommentAddOverlay.vue b/packages/frontend/src/main/components/viewer/CommentAddOverlay.vue index 7c2347423..313a7ccbb 100644 --- a/packages/frontend/src/main/components/viewer/CommentAddOverlay.vue +++ b/packages/frontend/src/main/components/viewer/CommentAddOverlay.vue @@ -405,7 +405,8 @@ export default { sectionBox: this.viewer.sectionBox.getCurrentBox(), selection: null // TODO for later, lazy now }, - screenshot: this.viewer.interactions.screenshot() + //@Dim: Changed this to use the API + screenshot: this.viewer.screenshot() } if (this.$route.query.overlay) { commentInput.resources.push( @@ -445,7 +446,8 @@ export default { this.visible = false this.commentValue = { doc: null, attachments: [] } setIsAddingComment(false) - this.viewer.interactions.deselectObjects() + //@Dim: Changed this to use the API + this.viewer.resetSelection() }, sendStatusUpdate() { // TODO: typing or not diff --git a/packages/frontend/src/main/components/viewer/CommentsOverlay.vue b/packages/frontend/src/main/components/viewer/CommentsOverlay.vue index b6dc0b31b..ca4cdea31 100644 --- a/packages/frontend/src/main/components/viewer/CommentsOverlay.vue +++ b/packages/frontend/src/main/components/viewer/CommentsOverlay.vue @@ -516,10 +516,11 @@ export default { if (camToSet[6] === 1) { this.viewer.toggleCameraProjection() } - this.viewer.interactions.setLookAt( - { x: camToSet[0], y: camToSet[1], z: camToSet[2] }, // position - { x: camToSet[3], y: camToSet[4], z: camToSet[5] } // target - ) + //@Dim: This needs to use the API. + // this.viewer.interactions.setLookAt( + // { x: camToSet[0], y: camToSet[1], z: camToSet[2] }, // position + // { x: camToSet[3], y: camToSet[4], z: camToSet[5] } // target + // ) if (camToSet[6] === 1) { this.viewer.cameraHandler.activeCam.controls.zoom(camToSet[7], true) } diff --git a/packages/frontend/src/main/components/viewer/ViewerBubbles.vue b/packages/frontend/src/main/components/viewer/ViewerBubbles.vue index e0bdf8691..4e553ca5b 100644 --- a/packages/frontend/src/main/components/viewer/ViewerBubbles.vue +++ b/packages/frontend/src/main/components/viewer/ViewerBubbles.vue @@ -254,10 +254,11 @@ export default { if (camToSet[6] === 1) { this.viewer.toggleCameraProjection() } - this.viewer.interactions.setLookAt( - { x: camToSet[0], y: camToSet[1], z: camToSet[2] }, // position - { x: camToSet[3], y: camToSet[4], z: camToSet[5] } // target - ) + //@Dim: This needs to use the API + // this.viewer.interactions.setLookAt( + // { x: camToSet[0], y: camToSet[1], z: camToSet[2] }, // position + // { x: camToSet[3], y: camToSet[4], z: camToSet[5] } // target + // ) if (camToSet[6] === 1) { this.viewer.cameraHandler.activeCam.controls.zoom(camToSet[7], true) } @@ -466,8 +467,8 @@ export default { uArrowEl.style.transform = `translate(${newTarget.x}px,${newTarget.y}px) rotate(${angle}rad)` uArrowEl.style.opacity = user.clipped ? '0' : '1' } - - this.viewer.interactions.overlayObjects(selectedObjects) + //@Dim: This shouldn't be needed anymore, right? + // this.viewer.interactions.overlayObjects(selectedObjects) } } } diff --git a/packages/frontend/src/main/lib/viewer/commit-object-viewer/stateManager.ts b/packages/frontend/src/main/lib/viewer/commit-object-viewer/stateManager.ts index 1242d7c12..cf8072b60 100644 --- a/packages/frontend/src/main/lib/viewer/commit-object-viewer/stateManager.ts +++ b/packages/frontend/src/main/lib/viewer/commit-object-viewer/stateManager.ts @@ -727,6 +727,6 @@ export async function resetFilter() { currentFilterState: null }) - await viewer.reset() + await viewer.resetFilters() viewer.applyFilter(null) } diff --git a/packages/frontend/src/main/pages/stream/CommitObjectViewer.vue b/packages/frontend/src/main/pages/stream/CommitObjectViewer.vue index d0cd3b698..33e2a4183 100644 --- a/packages/frontend/src/main/pages/stream/CommitObjectViewer.vue +++ b/packages/frontend/src/main/pages/stream/CommitObjectViewer.vue @@ -269,6 +269,7 @@ import { Nullable } from '@/helpers/typeHelpers' import { getCamArray } from '@/main/lib/viewer/core/helpers/cameraHelper' import CommitObjectViewerScope from '@/main/components/viewer/CommitObjectViewerScope.vue' import PrioritizedPortal from '@/main/components/common/utility/PrioritizedPortal.vue' +import { ViewerEvent } from '@speckle/viewer' type ErroredResourceData = { error: boolean @@ -515,7 +516,7 @@ export default defineComponent({ } } - this.viewer.on('busy', (val: boolean) => { + this.viewer.on(ViewerEvent.Busy, (val: boolean) => { setIsViewerBusy(!!val) this.viewerBusy = val if (!val && this.camToSet) { @@ -525,12 +526,14 @@ export default defineComponent({ if (this.camToSet[6] === 1) { this.viewer.toggleCameraProjection() } - this.viewer.interactions.setLookAt( - { x: this.camToSet[0], y: this.camToSet[1], z: this.camToSet[2] }, // position - { x: this.camToSet[3], y: this.camToSet[4], z: this.camToSet[5] } // target - ) + //@Dim: This needs to be replaced with a call from the API. + // this.viewer.interactions.setLookAt( + // { x: this.camToSet[0], y: this.camToSet[1], z: this.camToSet[2] }, // position + // { x: this.camToSet[3], y: this.camToSet[4], z: this.camToSet[5] } // target + // ) if (this.camToSet[6] === 1) { - this.viewer.cameraHandler.activeCam.controls.zoom(this.camToSet[7], true) + //@Dim: This needs to be replaced with a call from the API. + // this.viewer.cameraHandler.activeCam.controls.zoom(this.camToSet[7], true) } this.camToSet = null }, 200) @@ -726,7 +729,7 @@ export default defineComponent({ async setFilters() { try { // repopulate object props - this.objectProperties = await this.viewer.getObjectsProperties() + this.objectProperties = this.viewer.getObjectProperties() } catch (e) { this.$eventHub.$emit('notification', { text: 'Failed to get object properties from viewer.' diff --git a/packages/preview-service/routes/preview.js b/packages/preview-service/routes/preview.js index 8707ac05a..3332e7fba 100644 --- a/packages/preview-service/routes/preview.js +++ b/packages/preview-service/routes/preview.js @@ -26,15 +26,17 @@ async function pageFunction(objectUrl) { // Main call failed. Wait some time for other objects to load inside the viewer and generate the preview anyway await waitForAnimation(1000) } - - v.interactions.zoomExtents(0.95, false) + //@Dim: This needs to use the API + // v.interactions.zoomExtents(0.95, false) await waitForAnimation(100) // full 360 for (let i = 0; i < 24; i++) { - v.interactions.rotateCamera(undefined, undefined, false) + //@Dim: This needs to use the API + // v.interactions.rotateCamera(undefined, undefined, false) await waitForAnimation() - ret.scr[i + ''] = v.interactions.screenshot() + //@Dim: Changed this to use the API + ret.scr[i + ''] = v.screenshot() } /* diff --git a/packages/viewer-sandbox/src/main.ts b/packages/viewer-sandbox/src/main.ts index 4a5a31be3..89dc74c76 100644 --- a/packages/viewer-sandbox/src/main.ts +++ b/packages/viewer-sandbox/src/main.ts @@ -7,6 +7,7 @@ import { import './style.css' import Sandbox from './Sandbox' +import { IViewer } from '@speckle/viewer' const container = document.querySelector('#renderer') if (!container) { @@ -20,7 +21,7 @@ params.showStats = true // 'https://speckle-xyz-assets.ams3.digitaloceanspaces.com/studio010.hdr' // 'http://localhost:3033/sample-hdri.exr' -const viewer = new Viewer(container, params) +const viewer: IViewer = new Viewer(container, params) await viewer.init() const sandbox = new Sandbox(viewer) @@ -39,8 +40,8 @@ viewer.on( ) viewer.on(ViewerEvent.LoadComplete, () => { - Object.assign(Sandbox.sceneParams.worldSize, viewer.worldSize) - Object.assign(Sandbox.sceneParams.worldOrigin, viewer.worldOrigin) + Object.assign(Sandbox.sceneParams.worldSize, viewer.World.worldSize) + Object.assign(Sandbox.sceneParams.worldOrigin, viewer.World.worldOrigin) sandbox.refresh() }) @@ -75,11 +76,3 @@ await sandbox.loadUrl( // 'https://latest.speckle.dev/streams/444bfbd6e4/commits/e22f696b08' // 'https://latest.speckle.dev/streams/92b620fb17/commits/af6098915b?c=%5B0.02144,-0.0377,0.05554,0.00566,0.00236,0,0,1%5D' ) - -// const dataTree: DataTree = viewer.getDataTree() -// console.log(`Built data tree `, dataTree) -// console.log( -// dataTree.findAll((obj: SpeckleObject) => { -// return obj.speckle_type === 'Objects.Geometry.Mesh' -// }) -// ) diff --git a/packages/viewer/src/IViewer.ts b/packages/viewer/src/IViewer.ts index 988cada84..122378bc2 100644 --- a/packages/viewer/src/IViewer.ts +++ b/packages/viewer/src/IViewer.ts @@ -3,6 +3,7 @@ import sampleHdri from './assets/sample-hdri.png' import { FilteringState } from './modules/filtering/FilteringManager' import { PropertyInfo } from './modules/filtering/PropertyManager' import { DataTree } from './modules/tree/DataTree' +import { World } from './modules/World' export interface ViewerParams { postprocessing: boolean @@ -48,7 +49,8 @@ export enum ViewerEvent { LoadComplete = 'load-complete', LoadProgress = 'load-progress', UnloadComplete = 'unload-complete', - UnloadAllComplete = 'unload-all-complete' + UnloadAllComplete = 'unload-all-complete', + Busy = 'busy' } export type SelectionEvent = { @@ -86,7 +88,6 @@ export const DefaultLightConfiguration: SunLightConfiguration = { */ export interface IViewer { init(): Promise - onWindowResize(): void on(eventType: ViewerEvent, handler: (arg) => void) toggleSectionBox(): void sectionBoxOff(): void @@ -144,6 +145,7 @@ export interface IViewer { /** Data ops */ getDataTree(): DataTree + get World(): World dispose(): void } diff --git a/packages/viewer/src/index.ts b/packages/viewer/src/index.ts index dc9b5fa9a..368136068 100644 --- a/packages/viewer/src/index.ts +++ b/packages/viewer/src/index.ts @@ -15,8 +15,9 @@ import { import { SunLightConfiguration } from './IViewer' import { DataTree, ObjectPredicate, SpeckleObject } from './modules/tree/DataTree' +import { World } from './modules/World' -export { Viewer, DefaultViewerParams, ViewerEvent, DefaultLightConfiguration } +export { Viewer, DefaultViewerParams, ViewerEvent, DefaultLightConfiguration, World } export type { IViewer, diff --git a/packages/viewer/src/modules/SectionBox.js b/packages/viewer/src/modules/SectionBox.js index d72ee1066..0055915df 100644 --- a/packages/viewer/src/modules/SectionBox.js +++ b/packages/viewer/src/modules/SectionBox.js @@ -133,12 +133,14 @@ export default class SectionBox { const val = !!event.value if (val) { this.dragging = val - this.viewer.interactions.preventSelection = val + //@Dim: Not sure what this needs to do in the new viewer + // this.viewer.interactions.preventSelection = val this.viewer.cameraHandler.enabled = !val } else { setTimeout(() => { this.dragging = val - this.viewer.interactions.preventSelection = val + //@Dim: Not sure what this needs to do in the new viewer + // this.viewer.interactions.preventSelection = val this.viewer.cameraHandler.enabled = !val }, 100) } @@ -351,9 +353,10 @@ export default class SectionBox { if (targetBox) box = targetBox else { + /* //@Dim: Not sure what this needs to do in the new viewer if (this.viewer.interactions.selectedObjects.children.length !== 0) { box = new THREE.Box3().setFromObject(this.viewer.interactions.selectedObjects) - } else if (this.viewer.speckleRenderer.allObjects.children.length !== 0) { + } else*/ if (this.viewer.speckleRenderer.allObjects.children.length !== 0) { box = new THREE.Box3().setFromObject(this.viewer.speckleRenderer.allObjects) } else { box = new Box3(new THREE.Vector3(-1, -1, -1), new THREE.Vector3(1, 1, 1)) diff --git a/packages/viewer/src/modules/Viewer.ts b/packages/viewer/src/modules/Viewer.ts index db89c64df..346c4dece 100644 --- a/packages/viewer/src/modules/Viewer.ts +++ b/packages/viewer/src/modules/Viewer.ts @@ -3,11 +3,10 @@ import Stats from 'three/examples/jsm/libs/stats.module' import ViewerObjectLoader from './ViewerObjectLoader' import EventEmitter from './EventEmitter' -import InteractionHandler from './legacy/InteractionHandler' import CameraHandler from './context/CameraHanlder' import SectionBox from './SectionBox' -import { Clock, Color, MathUtils, Texture, Vector3 } from 'three' +import { Clock, Texture } from 'three' import { Assets } from './Assets' import { Optional } from '../helpers/typeHelper' import { @@ -21,32 +20,34 @@ import { import { World } from './World' import { TreeNode, WorldTree } from './tree/WorldTree' import SpeckleRenderer from './SpeckleRenderer' -import { - FilterMaterialType, - FilteringManager, - FilteringState -} from './filtering/FilteringManager' +import { FilteringManager, FilteringState } from './filtering/FilteringManager' import { PropertyInfo, PropertyManager } from './filtering/PropertyManager' import { SpeckleType } from './converter/GeometryConverter' import { DataTree } from './tree/DataTree' export class Viewer extends EventEmitter implements IViewer { - public speckleRenderer: SpeckleRenderer - private clock: Clock + /** Container and optional stats element */ private container: HTMLElement private stats: Optional - private loaders: { [id: string]: ViewerObjectLoader } = {} - private _needsRender: boolean - private inProgressOperations: number - public sectionBox: SectionBox - public interactions: InteractionHandler - public cameraHandler: CameraHandler + /** Viewer params used at init time */ private startupParams: ViewerParams + /** Viewer components */ public static Assets: Assets - + private speckleRenderer: SpeckleRenderer private filteringManager: FilteringManager + /** Legacy viewer components (will revisit soon) */ + public sectionBox: SectionBox + public cameraHandler: CameraHandler + + /** Render flag for on-demand rendering */ + private _needsRender: boolean + + /** Misc members */ + private inProgressOperations: number + private clock: Clock + private loaders: { [id: string]: ViewerObjectLoader } = {} public get needsRender(): boolean { return this._needsRender @@ -56,19 +57,9 @@ export class Viewer extends EventEmitter implements IViewer { this._needsRender = value || this._needsRender } - private _worldOrigin: Vector3 = new Vector3() - public get worldSize() { - World.worldBox.getCenter(this._worldOrigin) - const size = new Vector3().subVectors(World.worldBox.max, World.worldBox.min) - return { - x: size.x, - y: size.y, - z: size.z - } - } - - public get worldOrigin() { - return this._worldOrigin + /** Gets the World object. Currently it's used for statistics mostly */ + public get World(): World { + return World } public constructor( @@ -77,54 +68,84 @@ export class Viewer extends EventEmitter implements IViewer { ) { super() - window.THREE = THREE // Do we really need this? - this.startupParams = params - this.clock = new THREE.Clock() - this.container = container || document.getElementById('renderer') - - this.speckleRenderer = new SpeckleRenderer(this) - this.speckleRenderer.create(this.container) - new Assets(this.speckleRenderer.renderer) - - this.cameraHandler = new CameraHandler(this) - if (params.showStats) { this.stats = Stats() this.container.appendChild(this.stats.dom) } + this.loaders = {} + this.startupParams = params + this.clock = new THREE.Clock() + this.inProgressOperations = 0 + this.speckleRenderer = new SpeckleRenderer(this) + this.speckleRenderer.create(this.container) window.addEventListener('resize', this.onWindowResize.bind(this), false) - this.loaders = {} + new Assets(this.speckleRenderer.renderer) + this.filteringManager = new FilteringManager(this.speckleRenderer) + this.cameraHandler = new CameraHandler(this) this.sectionBox = new SectionBox(this) this.sectionBox.off() this.sectionBox.controls.addEventListener('change', () => { this.speckleRenderer.updateClippingPlanes(this.sectionBox.planes) }) - this.interactions = new InteractionHandler(this) - this.frame() this.onWindowResize() this.needsRender = true - this.inProgressOperations = 0 - this.on(ViewerEvent.LoadComplete, (url) => { WorldTree.getRenderTree(url).buildRenderTree() this.speckleRenderer.addRenderTree(url) this.zoomExtents() }) + } - this.filteringManager = new FilteringManager(this.speckleRenderer) - // eslint-disable-next-line @typescript-eslint/no-explicit-any - // ;(window as any).WT = WorldTree - // eslint-disable-next-line @typescript-eslint/no-explicit-any - // ;(window as any).FM = this.filteringManager - // eslint-disable-next-line @typescript-eslint/no-explicit-any - // ;(window as any).V = this + private onWindowResize() { + this.speckleRenderer.renderer.setSize( + this.container.offsetWidth, + this.container.offsetHeight + ) + this.needsRender = true + } + + private frame() { + this.update() + this.render() + } + + private update() { + const delta = this.clock.getDelta() + this.needsRender = this.cameraHandler.controls.update(delta) + this.speckleRenderer.update(delta) + this.stats?.update() + requestAnimationFrame(this.frame.bind(this)) + } + + private render() { + if (this.needsRender) { + this.speckleRenderer.render(this.cameraHandler.activeCam.camera) + this._needsRender = false + } + } + + public async init(): Promise { + if (this.startupParams.environmentSrc) { + Assets.getEnvironment(this.startupParams.environmentSrc) + .then((value: Texture) => { + this.speckleRenderer.indirectIBL = value + }) + .catch((reason) => { + console.warn(reason) + console.warn('Fallback to null environment!') + }) + } + } + + public on(eventType: ViewerEvent, listener: (arg) => void): void { + super.on(eventType, listener) } public getObjectProperties(resourceURL: string = null): PropertyInfo[] { @@ -225,54 +246,19 @@ export class Viewer extends EventEmitter implements IViewer { }) } + /** + * LEGACY: Handles (or tries to handle) old viewer filtering. + * @param args legacy filter object + */ + public async applyFilter(filter: unknown) { + filter + // return this.FilteringManager.handleLegacyFilter(filter) + } + public getDataTree(): DataTree { return WorldTree.getDataTree() } - public async init(): Promise { - if (this.startupParams.environmentSrc) { - Assets.getEnvironment(this.startupParams.environmentSrc) - .then((value: Texture) => { - this.speckleRenderer.indirectIBL = value - }) - .catch((reason) => { - console.warn(reason) - console.warn('Fallback to null environment!') - }) - } - } - - public on(eventType: ViewerEvent, listener: (arg) => void): void { - super.on(eventType, listener) - } - - public onWindowResize() { - this.speckleRenderer.renderer.setSize( - this.container.offsetWidth, - this.container.offsetHeight - ) - this.needsRender = true - } - - private frame() { - this.update() - this.render() - } - - private update() { - const delta = this.clock.getDelta() - this.needsRender = this.cameraHandler.controls.update(delta) - this.speckleRenderer.update(delta) - this.stats?.update() - requestAnimationFrame(this.frame.bind(this)) - } - - private render() { - if (this.needsRender) { - this.speckleRenderer.render(this.cameraHandler.activeCam.camera) - } - } - public toggleSectionBox() { this.sectionBox.toggle() } @@ -342,15 +328,20 @@ export class Viewer extends EventEmitter implements IViewer { }) } + /** + * OBJECT LOADING/UNLOADING + */ public async loadObject(url: string, token: string = null, enableCaching = true) { try { - if (++this.inProgressOperations === 1) (this as EventEmitter).emit('busy', true) + if (++this.inProgressOperations === 1) + (this as EventEmitter).emit(ViewerEvent.Busy, true) const loader = new ViewerObjectLoader(this, url, token, enableCaching) this.loaders[url] = loader await loader.load() } finally { - if (--this.inProgressOperations === 0) (this as EventEmitter).emit('busy', false) + if (--this.inProgressOperations === 0) + (this as EventEmitter).emit(ViewerEvent.Busy, false) } } @@ -364,14 +355,15 @@ export class Viewer extends EventEmitter implements IViewer { public async unloadObject(url: string) { try { - if (++this.inProgressOperations === 1) (this as EventEmitter).emit('busy', true) + if (++this.inProgressOperations === 1) + (this as EventEmitter).emit(ViewerEvent.Busy, true) delete this.loaders[url] this.speckleRenderer.removeRenderTree(url) WorldTree.getRenderTree(url).purge() WorldTree.getInstance().purge(url) } finally { if (--this.inProgressOperations === 0) { - ;(this as EventEmitter).emit('busy', false) + ;(this as EventEmitter).emit(ViewerEvent.Busy, false) console.warn(`Removed subtree ${url}`) ;(this as EventEmitter).emit(ViewerEvent.UnloadComplete, url) } @@ -380,7 +372,8 @@ export class Viewer extends EventEmitter implements IViewer { public async unloadAll() { try { - if (++this.inProgressOperations === 1) (this as EventEmitter).emit('busy', true) + if (++this.inProgressOperations === 1) + (this as EventEmitter).emit(ViewerEvent.Busy, true) for (const key of Object.keys(this.loaders)) { delete this.loaders[key] } @@ -393,198 +386,13 @@ export class Viewer extends EventEmitter implements IViewer { WorldTree.getInstance().purge() } finally { if (--this.inProgressOperations === 0) { - ;(this as EventEmitter).emit('busy', false) + ;(this as EventEmitter).emit(ViewerEvent.Busy, false) console.warn(`Removed all subtrees`) ;(this as EventEmitter).emit(ViewerEvent.UnloadAllComplete) } } } - /** - * LEGACY: Handles (or tries to handle) old viewer filtering. - * @param args legacy filter object - */ - public async applyFilter(filter: unknown) { - filter - // return this.FilteringManager.handleLegacyFilter(filter) - } - - public debugGetFilterByNumericPropetyData(propertyName: string): { - min: number - max: number - nodes: TreeNode[] - } { - const volumeNodes = [] - let min = Infinity - let max = 0 - WorldTree.getInstance().walk((node: TreeNode) => { - const params = node.model.raw.parameters - if (params) { - for (const k in params) { - if (!(params[k] instanceof Object)) continue - if (params[k].name === propertyName) { - min = Math.min(min, params[k].value) - max = Math.max(max, params[k].value) - volumeNodes.push(node) - } - } - } - return true - }) - - return { - min, - max, - nodes: volumeNodes - } - } - - public debugApplyByNumericPropetyFilter( - data: { min: number; max: number; nodes: TreeNode[] }, - propertyName: string, - min?: number, - max?: number - ) { - const start = performance.now() - const nodesGradient = [] - const nodesGhost = [] - const values = [] - - /** This is the lazy approach */ - WorldTree.getInstance().walk((node: TreeNode) => { - const params = node.model.raw.parameters - if (params) { - for (const k in params) { - if (!(params[k] instanceof Object)) continue - if (params[k].name === propertyName) { - const propertyValue = params[k].value - const passMin = min !== undefined ? propertyValue >= min : true - const passMax = max !== undefined ? propertyValue <= max : true - if ( - data.nodes.includes(node) && - passMin && - passMax && - !nodesGradient.includes(node) - ) { - nodesGradient.push(node) - values.push(propertyValue) - } - } else { - if (!nodesGhost.includes(node)) nodesGhost.push(node) - } - } - } - return true - }) - this.speckleRenderer.clearFilter() - this.speckleRenderer.beginFilter() - const ghostRvs = [] - for (let k = 0; k < nodesGhost.length; k++) { - ghostRvs.push( - ...WorldTree.getRenderTree().getRenderViewsForNode(nodesGhost[k], nodesGhost[k]) - ) - } - this.speckleRenderer.applyFilter(ghostRvs, { - filterType: FilterMaterialType.GHOST - }) - - for (let k = 0; k < nodesGradient.length; k++) { - const rvs = WorldTree.getRenderTree().getRenderViewsForNode( - nodesGradient[k], - nodesGradient[k] - ) - // .map((value) => value.renderData.id) - const t = (values[k] - data.min) / (data.max - data.min) - this.speckleRenderer.applyFilter(rvs, { - filterType: FilterMaterialType.GRADIENT, - rampIndex: t - }) - } - - this.speckleRenderer.endFilter() - console.warn(`Filter time: ${performance.now() - start}`) - } - - public debugGetFilterByNonNumericPropetyData(propertyName: string): { - color?: { name: string; color: string; colorIndex: number; nodes: [] } - } { - // OG implementation - const getColorHash = (objValue) => { - const objValueAsString = '' + objValue - let hash = 0 - for (let i = 0; i < objValueAsString.length; i++) { - const chr = objValueAsString.charCodeAt(i) - hash = (hash << 5) - hash + chr - hash |= 0 // Convert to 32bit integer - } - hash = Math.abs(hash) - const colorHue = hash % 360 - const rgb = new Color(`hsl(${colorHue}, 50%, 30%)`) - return rgb.getHex() - } - - const data: { - color?: { name: string; color: string; colorIndex: number; nodes: [] } - } = {} - - let colorCount = 0 - - /** This is the lazy approach */ - WorldTree.getInstance().walk((node: TreeNode) => { - if (!node.model.atomic) return true - const propertyValue = node.model.raw[propertyName] - if (propertyValue !== null && propertyValue !== undefined) { - const color = getColorHash(propertyValue.split('.').reverse()[0]) - if (data[color] === undefined) { - data[color] = { - name: propertyValue.split('.').reverse()[0], - color: new Color(MathUtils.randInt(0, 0xffffff)).getHex(), - colorIndex: colorCount, - nodes: [] - } - colorCount++ - } - if (!data[color].nodes.includes(node)) data[color].nodes.push(node) - } - - return true - }) - - return data - } - - public debugApplyByNonNumericPropetyFilter(data: { - color?: { name: string; color: number; colorIndex: number; nodes: [] } - }) { - const start = performance.now() - const colors = Object.values(data) - colors.sort((a, b) => a.colorIndex - b.colorIndex) - - const rampTexture = Assets.generateDiscreetRampTexture( - colors.map((val) => val.color) - ) - this.speckleRenderer.clearFilter() - this.speckleRenderer.beginFilter() - - for (let k = 0; k < colors.length; k++) { - const nodes = colors[k].nodes - let rvs = [] - for (let i = 0; i < nodes.length; i++) { - rvs = rvs.concat( - WorldTree.getRenderTree().getRenderViewsForNode(nodes[i], nodes[i]) - ) - } - this.speckleRenderer.applyFilter(rvs, { - filterType: FilterMaterialType.COLORED, - rampIndex: colors[k].colorIndex / colors.length, - rampIndexColor: new Color(colors[k].color), - rampTexture - }) - } - this.speckleRenderer.endFilter() - console.warn(`Filter time: ${performance.now() - start}`) - } - public dispose() { // TODO: currently it's easier to simply refresh the page :) } diff --git a/packages/viewer/src/modules/World.ts b/packages/viewer/src/modules/World.ts index 41d0434f7..4ccdfba56 100644 --- a/packages/viewer/src/modules/World.ts +++ b/packages/viewer/src/modules/World.ts @@ -1,10 +1,25 @@ -import { Box3 } from 'three' +import { Box3, Vector3 } from 'three' export class World { /* This will no longer exist when we have a scene tree */ private static readonly boxes: Array = new Array() public static readonly worldBox: Box3 = new Box3() + private static _worldOrigin: Vector3 = new Vector3() + public static get worldSize() { + World.worldBox.getCenter(this._worldOrigin) + const size = new Vector3().subVectors(World.worldBox.max, World.worldBox.min) + return { + x: size.x, + y: size.y, + z: size.z + } + } + + public static get worldOrigin() { + return World._worldOrigin + } + public static expandWorld(box: Box3) { World.boxes.push(box) World.updateWorld() diff --git a/packages/viewer/src/modules/legacy/example.js b/packages/viewer/src/modules/legacy/example.js index 64c5cf03a..d5d4d736e 100644 --- a/packages/viewer/src/modules/legacy/example.js +++ b/packages/viewer/src/modules/legacy/example.js @@ -52,7 +52,8 @@ v.on('section-box', (status) => { }) window.viewerScreenshot = function () { - let data = v.interactions.screenshot() // transparent png. + //@Dim: Changed this to use the API + let data = v.screenshot() // transparent png. let pop = window.open() pop.document.title = 'super screenshot' @@ -64,5 +65,6 @@ window.viewerScreenshot = function () { } window.zoomFast = function () { - v.interactions.zoomExtents(0.95, false) + //@Dim: This needs to use the API + // v.interactions.zoomExtents(0.95, false) }