Multi Viewer (#1518)
* Fixed an issue with HDRIs not generating proper PMREMs over multiple viewer instances * WIP on makign the world tree multiple instanced * The WorldTree is no longer static. Each viewer has it's own instance and it hands it over to whoever needs it. * Fixed an issue with filtering and the new non-static tree. Also removed the 'root' key from the NodeData structure since it's not needed * Added an guard when building batches for situations where all render views have invalid geometries. This generally means there is somethign wrong with the stream itself * multi-viewer css fixes --------- Co-authored-by: Dimitrie Stefanescu <didimitrie@gmail.com>
This commit is contained in:
committed by
GitHub
parent
90439d7d41
commit
4aef572a44
@@ -8,7 +8,30 @@
|
||||
<script src="https://cdn.tailwindcss.com"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="renderer"></div>
|
||||
<div class="w-screen h-screen">
|
||||
<div id="renderer" class="absolute w-full h-full"></div>
|
||||
<div
|
||||
id="renderer-controls"
|
||||
class="relative overflow-y-scroll h-full pointer-events-none w-auto"
|
||||
></div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
<!-- <div class="w-screen h-screen flex flex-col" id="multi-root">
|
||||
<div class="h-1/2">
|
||||
<div class="absolute w-full h-1/2" id="renderer0"></div>
|
||||
<div
|
||||
id="renderer0-controls"
|
||||
class="relative overflow-y-scroll h-full pointer-events-none w-auto"
|
||||
></div>
|
||||
</div>
|
||||
<div class="border-t-2 border-blue-500 h-1/2">
|
||||
<div class="absolute w-full h-1/2" id="renderer1"></div>
|
||||
<div
|
||||
id="renderer1-controls"
|
||||
class="relative overflow-y-scroll h-full pointer-events-none w-auto"
|
||||
></div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/src/main-multi.ts"></script> -->
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Box3, Viewer, WorldTree } from '@speckle/viewer'
|
||||
import { Box3, WorldTree } from '@speckle/viewer'
|
||||
import { Vector3 } from '@speckle/viewer'
|
||||
import {
|
||||
CanonicalView,
|
||||
@@ -23,11 +23,11 @@ export default class Sandbox {
|
||||
private objectControls
|
||||
private batchesFolder
|
||||
|
||||
public static urlParams = {
|
||||
public urlParams = {
|
||||
url: 'https://latest.speckle.dev/streams/c43ac05d04/commits/ec724cfbeb'
|
||||
}
|
||||
|
||||
public static sceneParams = {
|
||||
public sceneParams = {
|
||||
worldSize: { x: 0, y: 0, z: 0 },
|
||||
worldOrigin: { x: 0, y: 0, z: 0 },
|
||||
pixelThreshold: 0.5,
|
||||
@@ -35,7 +35,7 @@ export default class Sandbox {
|
||||
tonemapping: 4 //'ACESFilmicToneMapping'
|
||||
}
|
||||
|
||||
public static pipelineParams = {
|
||||
public pipelineParams = {
|
||||
pipelineOutput: 8,
|
||||
accumulationFrames: 16,
|
||||
dynamicAoEnabled: true,
|
||||
@@ -61,7 +61,7 @@ export default class Sandbox {
|
||||
}
|
||||
}
|
||||
|
||||
public static lightParams: SunLightConfiguration = {
|
||||
public lightParams: SunLightConfiguration = {
|
||||
enabled: true,
|
||||
castShadow: true,
|
||||
intensity: 5,
|
||||
@@ -73,7 +73,7 @@ export default class Sandbox {
|
||||
shadowcatcher: true
|
||||
}
|
||||
|
||||
public static batchesParams = {
|
||||
public batchesParams = {
|
||||
showBvh: false,
|
||||
totalBvhSize: 0,
|
||||
explode: 0,
|
||||
@@ -81,11 +81,11 @@ export default class Sandbox {
|
||||
culling: true
|
||||
}
|
||||
|
||||
public static filterParams = {
|
||||
public filterParams = {
|
||||
filterBy: 'Volume'
|
||||
}
|
||||
|
||||
public static shadowCatcherParams = {
|
||||
public shadowCatcherParams = {
|
||||
textureSize: 512,
|
||||
weights: { x: 1, y: 1, z: 0, w: 1 },
|
||||
blurRadius: 16,
|
||||
@@ -94,12 +94,17 @@ export default class Sandbox {
|
||||
sigmoidStrength: 2
|
||||
}
|
||||
|
||||
public constructor(viewer: DebugViewer, selectionList: SelectionEvent[]) {
|
||||
public constructor(
|
||||
container: HTMLElement,
|
||||
viewer: DebugViewer,
|
||||
selectionList: SelectionEvent[]
|
||||
) {
|
||||
this.viewer = viewer
|
||||
this.selectionList = selectionList
|
||||
this.pane = new Pane({ title: 'Speckle Sandbox', expanded: true })
|
||||
this.pane['containerElem_'].style =
|
||||
'position:fixed; top: 5px; right: 5px; width: 300px;'
|
||||
// Mad HTML/CSS skills
|
||||
container.appendChild(this.pane['containerElem_'])
|
||||
this.pane['containerElem_'].style = 'pointer-events:auto;'
|
||||
|
||||
this.tabs = this.pane.addTab({
|
||||
pages: [
|
||||
@@ -116,20 +121,20 @@ export default class Sandbox {
|
||||
this.addViewControls()
|
||||
this.addBatches()
|
||||
this.properties = this.viewer.getObjectProperties()
|
||||
Sandbox.batchesParams.totalBvhSize = this.getBVHSize()
|
||||
this.batchesParams.totalBvhSize = this.getBVHSize()
|
||||
this.refresh()
|
||||
})
|
||||
viewer.on(ViewerEvent.UnloadComplete, (url: string) => {
|
||||
this.removeViewControls()
|
||||
this.addViewControls()
|
||||
this.properties = this.viewer.getObjectProperties()
|
||||
Viewer.World.reduceWorld(WorldTree.getRenderTree(url).treeBounds)
|
||||
viewer.World.reduceWorld(WorldTree.getRenderTree(url).treeBounds)
|
||||
})
|
||||
viewer.on(ViewerEvent.UnloadAllComplete, (url: string) => {
|
||||
this.removeViewControls()
|
||||
this.addViewControls()
|
||||
this.properties = this.viewer.getObjectProperties()
|
||||
Viewer.World.resetWorld()
|
||||
viewer.World.resetWorld()
|
||||
url
|
||||
})
|
||||
viewer.on(ViewerEvent.ObjectClicked, (selectionEvent: SelectionEvent) => {
|
||||
@@ -284,7 +289,7 @@ export default class Sandbox {
|
||||
}
|
||||
|
||||
public makeGenericUI() {
|
||||
this.tabs.pages[0].addInput(Sandbox.urlParams, 'url', {
|
||||
this.tabs.pages[0].addInput(this.urlParams, 'url', {
|
||||
title: 'url'
|
||||
})
|
||||
|
||||
@@ -293,7 +298,7 @@ export default class Sandbox {
|
||||
})
|
||||
|
||||
loadButton.on('click', () => {
|
||||
this.loadUrl(Sandbox.urlParams.url)
|
||||
this.loadUrl(this.urlParams.url)
|
||||
})
|
||||
|
||||
const clearButton = this.tabs.pages[0].addButton({
|
||||
@@ -343,13 +348,19 @@ export default class Sandbox {
|
||||
})
|
||||
const dark = localStorage.getItem('dark') === 'dark'
|
||||
if (dark) {
|
||||
console.log(document.getElementById('multi-root'))
|
||||
document.getElementById('multi-root')?.classList.toggle('background-dark')
|
||||
document.getElementById('renderer')?.classList.toggle('background-dark')
|
||||
}
|
||||
|
||||
darkModeToggle.on('click', () => {
|
||||
const dark = document
|
||||
.getElementById('renderer')
|
||||
?.classList.toggle('background-dark')
|
||||
let dark = false
|
||||
if (document.getElementById('renderer'))
|
||||
dark = document.getElementById('renderer')?.classList.toggle('background-dark')
|
||||
else
|
||||
dark = document
|
||||
.getElementById('multi-root')
|
||||
?.classList.toggle('background-dark')
|
||||
|
||||
localStorage.setItem('dark', dark ? `dark` : `light`)
|
||||
})
|
||||
@@ -397,31 +408,31 @@ export default class Sandbox {
|
||||
title: 'World',
|
||||
expanded: true
|
||||
})
|
||||
worldFolder.addInput(Sandbox.sceneParams.worldSize, 'x', {
|
||||
worldFolder.addInput(this.sceneParams.worldSize, 'x', {
|
||||
disabled: true,
|
||||
label: 'Size-x',
|
||||
step: 0.00000001
|
||||
})
|
||||
worldFolder.addInput(Sandbox.sceneParams.worldSize, 'y', {
|
||||
worldFolder.addInput(this.sceneParams.worldSize, 'y', {
|
||||
disabled: true,
|
||||
label: 'Size-y',
|
||||
step: 0.00000001
|
||||
})
|
||||
worldFolder.addInput(Sandbox.sceneParams.worldSize, 'z', {
|
||||
worldFolder.addInput(this.sceneParams.worldSize, 'z', {
|
||||
disabled: true,
|
||||
label: 'Size-z',
|
||||
step: 0.00000001
|
||||
})
|
||||
worldFolder.addSeparator()
|
||||
worldFolder.addInput(Sandbox.sceneParams.worldOrigin, 'x', {
|
||||
worldFolder.addInput(this.sceneParams.worldOrigin, 'x', {
|
||||
disabled: true,
|
||||
label: 'Origin-x'
|
||||
})
|
||||
worldFolder.addInput(Sandbox.sceneParams.worldOrigin, 'y', {
|
||||
worldFolder.addInput(this.sceneParams.worldOrigin, 'y', {
|
||||
disabled: true,
|
||||
label: 'Origin-y'
|
||||
})
|
||||
worldFolder.addInput(Sandbox.sceneParams.worldOrigin, 'z', {
|
||||
worldFolder.addInput(this.sceneParams.worldOrigin, 'z', {
|
||||
disabled: true,
|
||||
label: 'Origin-z'
|
||||
})
|
||||
@@ -433,13 +444,13 @@ export default class Sandbox {
|
||||
})
|
||||
|
||||
postFolder
|
||||
.addInput(Sandbox.sceneParams, 'exposure', {
|
||||
.addInput(this.sceneParams, 'exposure', {
|
||||
min: 0,
|
||||
max: 1
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().renderer.toneMappingExposure =
|
||||
Sandbox.sceneParams.exposure
|
||||
this.sceneParams.exposure
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
@@ -468,14 +479,14 @@ export default class Sandbox {
|
||||
})
|
||||
|
||||
postFolder
|
||||
.addInput(Sandbox.sceneParams, 'tonemapping', {
|
||||
.addInput(this.sceneParams, 'tonemapping', {
|
||||
options: {
|
||||
Linear: 1,
|
||||
ACES: 4
|
||||
}
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().renderer.toneMapping = Sandbox.sceneParams.tonemapping
|
||||
this.viewer.getRenderer().renderer.toneMapping = this.sceneParams.tonemapping
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
@@ -484,7 +495,7 @@ export default class Sandbox {
|
||||
expanded: true
|
||||
})
|
||||
pipelineFolder
|
||||
.addInput(Sandbox.pipelineParams, 'pipelineOutput', {
|
||||
.addInput(this.pipelineParams, 'pipelineOutput', {
|
||||
options: {
|
||||
DEPTH_RGBA: 0,
|
||||
DEPTH: 1,
|
||||
@@ -498,18 +509,18 @@ export default class Sandbox {
|
||||
}
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
pipelineFolder
|
||||
.addInput(Sandbox.pipelineParams, 'accumulationFrames', {
|
||||
.addInput(this.pipelineParams, 'accumulationFrames', {
|
||||
min: 1,
|
||||
max: 128,
|
||||
step: 1
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
@@ -519,33 +530,33 @@ export default class Sandbox {
|
||||
})
|
||||
|
||||
dynamicAoFolder
|
||||
.addInput(Sandbox.pipelineParams.dynamicAoParams, 'intensity', { min: 0, max: 5 })
|
||||
.addInput(this.pipelineParams.dynamicAoParams, 'intensity', { min: 0, max: 5 })
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
dynamicAoFolder
|
||||
.addInput(Sandbox.pipelineParams.dynamicAoParams, 'kernelRadius', {
|
||||
.addInput(this.pipelineParams.dynamicAoParams, 'kernelRadius', {
|
||||
min: 0,
|
||||
max: 500
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
dynamicAoFolder
|
||||
.addInput(Sandbox.pipelineParams.dynamicAoParams, 'bias', {
|
||||
.addInput(this.pipelineParams.dynamicAoParams, 'bias', {
|
||||
min: -1,
|
||||
max: 1
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
dynamicAoFolder
|
||||
.addInput(Sandbox.pipelineParams.dynamicAoParams, 'normalsType', {
|
||||
.addInput(this.pipelineParams.dynamicAoParams, 'normalsType', {
|
||||
options: {
|
||||
DEFAULT: 0,
|
||||
ADVANCED: 1,
|
||||
@@ -553,35 +564,35 @@ export default class Sandbox {
|
||||
}
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
dynamicAoFolder
|
||||
.addInput(Sandbox.pipelineParams.dynamicAoParams, 'blurEnabled', {})
|
||||
.addInput(this.pipelineParams.dynamicAoParams, 'blurEnabled', {})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
dynamicAoFolder
|
||||
.addInput(Sandbox.pipelineParams.dynamicAoParams, 'blurRadius', {
|
||||
.addInput(this.pipelineParams.dynamicAoParams, 'blurRadius', {
|
||||
min: 0,
|
||||
max: 10
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
dynamicAoFolder
|
||||
.addInput(Sandbox.pipelineParams.dynamicAoParams, 'blurDepthCutoff', {
|
||||
.addInput(this.pipelineParams.dynamicAoParams, 'blurDepthCutoff', {
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.00001
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
@@ -596,13 +607,13 @@ export default class Sandbox {
|
||||
// this.viewer.requestRender()
|
||||
// })
|
||||
staticAoFolder
|
||||
.addInput(Sandbox.pipelineParams.staticAoParams, 'intensity', {
|
||||
.addInput(this.pipelineParams.staticAoParams, 'intensity', {
|
||||
min: 0,
|
||||
max: 5,
|
||||
step: 0.01
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
// staticAoFolder
|
||||
@@ -627,34 +638,34 @@ export default class Sandbox {
|
||||
// this.viewer.requestRender()
|
||||
// })
|
||||
staticAoFolder
|
||||
.addInput(Sandbox.pipelineParams.staticAoParams, 'kernelRadius', {
|
||||
.addInput(this.pipelineParams.staticAoParams, 'kernelRadius', {
|
||||
min: 0,
|
||||
max: 1000
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
staticAoFolder
|
||||
.addInput(Sandbox.pipelineParams.staticAoParams, 'bias', {
|
||||
.addInput(this.pipelineParams.staticAoParams, 'bias', {
|
||||
min: -1,
|
||||
max: 1,
|
||||
step: 0.0001
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
staticAoFolder
|
||||
.addInput(Sandbox.pipelineParams.staticAoParams, 'kernelSize', {
|
||||
.addInput(this.pipelineParams.staticAoParams, 'kernelSize', {
|
||||
min: 1,
|
||||
max: 128,
|
||||
step: 1
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.getRenderer().pipelineOptions = Sandbox.pipelineParams
|
||||
this.viewer.getRenderer().pipelineOptions = this.pipelineParams
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
|
||||
@@ -667,62 +678,62 @@ export default class Sandbox {
|
||||
expanded: true
|
||||
})
|
||||
directLightFolder
|
||||
.addInput(Sandbox.lightParams, 'enabled', {
|
||||
.addInput(this.lightParams, 'enabled', {
|
||||
label: 'Sun Enabled'
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.setLightConfiguration(Sandbox.lightParams)
|
||||
this.viewer.setLightConfiguration(this.lightParams)
|
||||
})
|
||||
directLightFolder
|
||||
.addInput(Sandbox.lightParams, 'castShadow', {
|
||||
.addInput(this.lightParams, 'castShadow', {
|
||||
label: 'Sun Shadows'
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.setLightConfiguration(Sandbox.lightParams)
|
||||
this.viewer.setLightConfiguration(this.lightParams)
|
||||
})
|
||||
directLightFolder
|
||||
.addInput(Sandbox.lightParams, 'intensity', {
|
||||
.addInput(this.lightParams, 'intensity', {
|
||||
label: 'Sun Intensity',
|
||||
min: 0,
|
||||
max: 10
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.setLightConfiguration(Sandbox.lightParams)
|
||||
this.viewer.setLightConfiguration(this.lightParams)
|
||||
})
|
||||
directLightFolder
|
||||
.addInput(Sandbox.lightParams, 'color', {
|
||||
.addInput(this.lightParams, 'color', {
|
||||
view: 'color',
|
||||
label: 'Sun Color'
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.setLightConfiguration(Sandbox.lightParams)
|
||||
this.viewer.setLightConfiguration(this.lightParams)
|
||||
})
|
||||
directLightFolder
|
||||
.addInput(Sandbox.lightParams, 'elevation', {
|
||||
.addInput(this.lightParams, 'elevation', {
|
||||
label: 'Sun Elevation',
|
||||
min: 0,
|
||||
max: Math.PI
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.setLightConfiguration(Sandbox.lightParams)
|
||||
this.viewer.setLightConfiguration(this.lightParams)
|
||||
})
|
||||
directLightFolder
|
||||
.addInput(Sandbox.lightParams, 'azimuth', {
|
||||
.addInput(this.lightParams, 'azimuth', {
|
||||
label: 'Sun Azimuth',
|
||||
min: -Math.PI * 0.5,
|
||||
max: Math.PI * 0.5
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.setLightConfiguration(Sandbox.lightParams)
|
||||
this.viewer.setLightConfiguration(this.lightParams)
|
||||
})
|
||||
directLightFolder
|
||||
.addInput(Sandbox.lightParams, 'radius', {
|
||||
.addInput(this.lightParams, 'radius', {
|
||||
label: 'Sun Radius',
|
||||
min: 0,
|
||||
max: 1000
|
||||
})
|
||||
.on('change', () => {
|
||||
this.viewer.setLightConfiguration(Sandbox.lightParams)
|
||||
this.viewer.setLightConfiguration(this.lightParams)
|
||||
})
|
||||
|
||||
directLightFolder
|
||||
@@ -757,14 +768,14 @@ export default class Sandbox {
|
||||
})
|
||||
|
||||
indirectLightsFolder
|
||||
.addInput(Sandbox.lightParams, 'indirectLightIntensity', {
|
||||
.addInput(this.lightParams, 'indirectLightIntensity', {
|
||||
label: 'Probe Intensity',
|
||||
min: 0,
|
||||
max: 10
|
||||
})
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.setLightConfiguration(Sandbox.lightParams)
|
||||
this.viewer.setLightConfiguration(this.lightParams)
|
||||
})
|
||||
|
||||
const shadowcatcherFolder = this.tabs.pages[1].addFolder({
|
||||
@@ -773,14 +784,14 @@ export default class Sandbox {
|
||||
})
|
||||
|
||||
shadowcatcherFolder
|
||||
.addInput(Sandbox.lightParams, 'shadowcatcher', { label: 'Enabled' })
|
||||
.addInput(this.lightParams, 'shadowcatcher', { label: 'Enabled' })
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.setLightConfiguration(Sandbox.lightParams)
|
||||
this.viewer.setLightConfiguration(this.lightParams)
|
||||
})
|
||||
|
||||
shadowcatcherFolder
|
||||
.addInput(Sandbox.shadowCatcherParams, 'textureSize', {
|
||||
.addInput(this.shadowCatcherParams, 'textureSize', {
|
||||
label: 'Texture Size',
|
||||
min: 1,
|
||||
max: 1024,
|
||||
@@ -788,12 +799,11 @@ export default class Sandbox {
|
||||
})
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.getRenderer().shadowcatcher.configuration =
|
||||
Sandbox.shadowCatcherParams
|
||||
this.viewer.getRenderer().shadowcatcher.configuration = this.shadowCatcherParams
|
||||
this.viewer.getRenderer().updateShadowCatcher()
|
||||
})
|
||||
shadowcatcherFolder
|
||||
.addInput(Sandbox.shadowCatcherParams, 'weights', {
|
||||
.addInput(this.shadowCatcherParams, 'weights', {
|
||||
label: 'weights',
|
||||
x: { min: 0, max: 100 },
|
||||
y: { min: 0, max: 100 },
|
||||
@@ -802,12 +812,11 @@ export default class Sandbox {
|
||||
})
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.getRenderer().shadowcatcher.configuration =
|
||||
Sandbox.shadowCatcherParams
|
||||
this.viewer.getRenderer().shadowcatcher.configuration = this.shadowCatcherParams
|
||||
this.viewer.getRenderer().updateShadowCatcher()
|
||||
})
|
||||
shadowcatcherFolder
|
||||
.addInput(Sandbox.shadowCatcherParams, 'blurRadius', {
|
||||
.addInput(this.shadowCatcherParams, 'blurRadius', {
|
||||
label: 'Blur Radius',
|
||||
min: 1,
|
||||
max: 128,
|
||||
@@ -815,12 +824,11 @@ export default class Sandbox {
|
||||
})
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.getRenderer().shadowcatcher.configuration =
|
||||
Sandbox.shadowCatcherParams
|
||||
this.viewer.getRenderer().shadowcatcher.configuration = this.shadowCatcherParams
|
||||
this.viewer.getRenderer().updateShadowCatcher()
|
||||
})
|
||||
shadowcatcherFolder
|
||||
.addInput(Sandbox.shadowCatcherParams, 'stdDeviation', {
|
||||
.addInput(this.shadowCatcherParams, 'stdDeviation', {
|
||||
label: 'Blur Std Deviation',
|
||||
min: 1,
|
||||
max: 128,
|
||||
@@ -828,12 +836,11 @@ export default class Sandbox {
|
||||
})
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.getRenderer().shadowcatcher.configuration =
|
||||
Sandbox.shadowCatcherParams
|
||||
this.viewer.getRenderer().shadowcatcher.configuration = this.shadowCatcherParams
|
||||
this.viewer.getRenderer().updateShadowCatcher()
|
||||
})
|
||||
shadowcatcherFolder
|
||||
.addInput(Sandbox.shadowCatcherParams, 'sigmoidRange', {
|
||||
.addInput(this.shadowCatcherParams, 'sigmoidRange', {
|
||||
label: 'Sigmoid Range',
|
||||
min: -10,
|
||||
max: 10,
|
||||
@@ -841,12 +848,11 @@ export default class Sandbox {
|
||||
})
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.getRenderer().shadowcatcher.configuration =
|
||||
Sandbox.shadowCatcherParams
|
||||
this.viewer.getRenderer().shadowcatcher.configuration = this.shadowCatcherParams
|
||||
this.viewer.getRenderer().updateShadowCatcher()
|
||||
})
|
||||
shadowcatcherFolder
|
||||
.addInput(Sandbox.shadowCatcherParams, 'sigmoidStrength', {
|
||||
.addInput(this.shadowCatcherParams, 'sigmoidStrength', {
|
||||
label: 'Sigmoid Strength',
|
||||
min: -10,
|
||||
max: 10,
|
||||
@@ -854,8 +860,7 @@ export default class Sandbox {
|
||||
})
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.getRenderer().shadowcatcher.configuration =
|
||||
Sandbox.shadowCatcherParams
|
||||
this.viewer.getRenderer().shadowcatcher.configuration = this.shadowCatcherParams
|
||||
this.viewer.getRenderer().updateShadowCatcher()
|
||||
})
|
||||
}
|
||||
@@ -866,7 +871,7 @@ export default class Sandbox {
|
||||
expanded: true
|
||||
})
|
||||
|
||||
filteringFolder.addInput(Sandbox.filterParams, 'filterBy', {
|
||||
filteringFolder.addInput(this.filterParams, 'filterBy', {
|
||||
options: {
|
||||
Volume: 'parameters.HOST_VOLUME_COMPUTED.value',
|
||||
Area: 'parameters.HOST_AREA_COMPUTED.value',
|
||||
@@ -883,7 +888,7 @@ export default class Sandbox {
|
||||
})
|
||||
.on('click', () => {
|
||||
const data = this.properties.find((value) => {
|
||||
return value.key === Sandbox.filterParams.filterBy
|
||||
return value.key === this.filterParams.filterBy
|
||||
}) as PropertyInfo
|
||||
this.viewer.setColorFilter(data)
|
||||
this.pane.refresh()
|
||||
@@ -909,19 +914,19 @@ export default class Sandbox {
|
||||
})
|
||||
|
||||
container
|
||||
.addInput(Sandbox.batchesParams, 'showBvh', {
|
||||
.addInput(this.batchesParams, 'showBvh', {
|
||||
label: 'Show BVH'
|
||||
})
|
||||
.on('change', (ev) => {
|
||||
this.viewer.getRenderer().showBVH = ev.value
|
||||
this.viewer.requestRender()
|
||||
})
|
||||
container.addInput(Sandbox.batchesParams, 'totalBvhSize', {
|
||||
container.addInput(this.batchesParams, 'totalBvhSize', {
|
||||
label: 'BVH Size(MB)',
|
||||
disabled: true
|
||||
})
|
||||
container
|
||||
.addInput(Sandbox.batchesParams, 'explode', {
|
||||
.addInput(this.batchesParams, 'explode', {
|
||||
label: 'Explode',
|
||||
min: 0,
|
||||
max: 0.25,
|
||||
@@ -929,13 +934,10 @@ export default class Sandbox {
|
||||
})
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.explode(
|
||||
Sandbox.batchesParams.explode,
|
||||
Sandbox.batchesParams.explodeRange
|
||||
)
|
||||
this.viewer.explode(this.batchesParams.explode, this.batchesParams.explodeRange)
|
||||
})
|
||||
container
|
||||
.addInput(Sandbox.batchesParams, 'explodeRange', {
|
||||
.addInput(this.batchesParams, 'explodeRange', {
|
||||
label: 'Explode Range',
|
||||
min: 1,
|
||||
max: 1000,
|
||||
@@ -943,10 +945,7 @@ export default class Sandbox {
|
||||
})
|
||||
.on('change', (value) => {
|
||||
value
|
||||
this.viewer.explode(
|
||||
Sandbox.batchesParams.explode,
|
||||
Sandbox.batchesParams.explodeRange
|
||||
)
|
||||
this.viewer.explode(this.batchesParams.explode, this.batchesParams.explodeRange)
|
||||
})
|
||||
// container
|
||||
// .addInput(Sandbox.batchesParams, 'culling', {
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
import {
|
||||
DefaultViewerParams,
|
||||
SelectionEvent,
|
||||
ViewerEvent,
|
||||
DebugViewer,
|
||||
Viewer
|
||||
} from '@speckle/viewer'
|
||||
|
||||
import './style.css'
|
||||
import Sandbox from './Sandbox'
|
||||
|
||||
// const container0 = document.querySelector<HTMLElement>('#renderer0')
|
||||
// if (!container0) {
|
||||
// throw new Error("Couldn't find #app container!")
|
||||
// }
|
||||
|
||||
// const container1 = document.querySelector<HTMLElement>('#renderer1')
|
||||
// if (!container1) {
|
||||
// throw new Error("Couldn't find #app container!")
|
||||
// }
|
||||
|
||||
const createViewer = async (containerName: string, stream: string) => {
|
||||
const container = document.querySelector<HTMLElement>(containerName)
|
||||
const controlsContainer = document.querySelector<HTMLElement>(
|
||||
`${containerName}-controls`
|
||||
)
|
||||
if (!container) {
|
||||
throw new Error("Couldn't find #app container!")
|
||||
}
|
||||
if (!controlsContainer) {
|
||||
throw new Error("Couldn't find #app controls container!")
|
||||
}
|
||||
|
||||
// Viewer setup
|
||||
const params = DefaultViewerParams
|
||||
params.showStats = true
|
||||
params.verbose = true
|
||||
|
||||
const multiSelectList: SelectionEvent[] = []
|
||||
const viewer: Viewer = new DebugViewer(container, params)
|
||||
await viewer.init()
|
||||
|
||||
const sandbox = new Sandbox(controlsContainer, viewer as DebugViewer, multiSelectList)
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
viewer.resize()
|
||||
})
|
||||
|
||||
viewer.on(
|
||||
ViewerEvent.LoadProgress,
|
||||
(a: { progress: number; id: string; url: string }) => {
|
||||
if (a.progress >= 1) {
|
||||
viewer.resize()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
viewer.on(ViewerEvent.LoadComplete, () => {
|
||||
Object.assign(sandbox.sceneParams.worldSize, viewer.World.worldSize)
|
||||
Object.assign(sandbox.sceneParams.worldOrigin, viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
})
|
||||
|
||||
viewer.on(ViewerEvent.UnloadComplete, () => {
|
||||
Object.assign(sandbox.sceneParams.worldSize, viewer.World.worldSize)
|
||||
Object.assign(sandbox.sceneParams.worldOrigin, viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
})
|
||||
viewer.on(ViewerEvent.UnloadAllComplete, () => {
|
||||
Object.assign(sandbox.sceneParams.worldSize, viewer.World.worldSize)
|
||||
Object.assign(sandbox.sceneParams.worldOrigin, viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
})
|
||||
|
||||
viewer.on(ViewerEvent.ObjectClicked, async (selectionInfo: SelectionEvent) => {
|
||||
if (!selectionInfo) {
|
||||
multiSelectList.length = 0
|
||||
await viewer.resetSelection()
|
||||
viewer.setSectionBox()
|
||||
return
|
||||
}
|
||||
if (!selectionInfo.multiple) multiSelectList.length = 0
|
||||
|
||||
const guids = multiSelectList.map((val) => val.hits[0].guid)
|
||||
if (
|
||||
(selectionInfo.multiple && !guids.includes(selectionInfo.hits[0].guid)) ||
|
||||
multiSelectList.length === 0
|
||||
) {
|
||||
multiSelectList.push(selectionInfo)
|
||||
}
|
||||
|
||||
const ids = multiSelectList.map((val) => val.hits[0].object.id)
|
||||
console.log(selectionInfo)
|
||||
await viewer.selectObjects(ids as string[])
|
||||
})
|
||||
|
||||
viewer.on(ViewerEvent.ObjectDoubleClicked, async (selectionInfo: SelectionEvent) => {
|
||||
if (!selectionInfo) {
|
||||
viewer.zoom()
|
||||
return
|
||||
}
|
||||
|
||||
viewer.zoom([selectionInfo.hits[0].object.id as string])
|
||||
})
|
||||
|
||||
sandbox.makeGenericUI()
|
||||
sandbox.makeSceneUI()
|
||||
sandbox.makeFilteringUI()
|
||||
sandbox.makeBatchesUI()
|
||||
|
||||
await sandbox.loadUrl(stream)
|
||||
}
|
||||
|
||||
createViewer(
|
||||
'#renderer0',
|
||||
'https://latest.speckle.dev/streams/0c6ad366c4/commits/aa1c393aec'
|
||||
)
|
||||
createViewer('#renderer1', 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8')
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const getStream = () => {
|
||||
return (
|
||||
// prettier-ignore
|
||||
// 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8?c=%5B-7.66134,10.82932,6.41935,-0.07739,-13.88552,1.8697,0,1%5D'
|
||||
// Revit sample house (good for bim-like stuff with many display meshes)
|
||||
|
||||
'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8'
|
||||
// 'Super' heavy revit shit
|
||||
// 'https://speckle.xyz/streams/e6f9156405/commits/0694d53bb5'
|
||||
// IFC building (good for a tree based structure)
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/2ebd336223'
|
||||
// IFC story, a subtree of the above
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/objects/8247bbc53865b0e0cb5ee4e252e66216'
|
||||
// Small scale lines
|
||||
// 'https://speckle.xyz/streams/638d3b1f83/commits/6025e2b546?c=%5B2.18058,-0.20814,9.67642,3.85491,5.05364,0,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/3ed8357f29/commits/d10f2af1ce'
|
||||
// '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'
|
||||
// AutoCAD
|
||||
// 'https://latest.speckle.dev/streams/3ed8357f29/commits/d10f2af1ce'
|
||||
//Blizzard world
|
||||
// 'https://latest.speckle.dev/streams/0c6ad366c4/commits/aa1c393aec'
|
||||
//Car
|
||||
// 'https://latest.speckle.dev/streams/17d2e25a97/commits/6b6cf3d43e'
|
||||
// Jonathon's
|
||||
// 'https://latest.speckle.dev/streams/501258ee5f/commits/f885570011'
|
||||
// Alex's cube
|
||||
// 'https://latest.speckle.dev/streams/46e3e0e1ec/commits/a6392c19d6?c=%5B6.85874,2.9754,0.79022,0,0,0,0,1%5D'
|
||||
// Groups of groups
|
||||
// 'https://speckle.xyz/streams/1ce562e99a/commits/6fa28a5a0f'
|
||||
// Arc flowers
|
||||
// 'https://latest.speckle.dev/streams/9e6c4343ba/commits/037e382aa2'
|
||||
// Car lines
|
||||
// 'https://speckle.xyz/streams/638d3b1f83/commits/6025e2b546?c=%5B2.18058,-0.20814,9.67642,3.85491,5.05364,0,0,1%5D'
|
||||
// Arc and lines
|
||||
// ' https://speckle.xyz/streams/99abc74dd4/commits/b32fdcf171?c=%5B198440.6051,6522070.21462,19199.49584,176653.24219,6523663.5,0,0,1%5D'
|
||||
// AUTOCAD test stream
|
||||
// 'https://latest.speckle.dev/streams/3ed8357f29/commits/b49bfc73ea'
|
||||
// REVIT test stream
|
||||
// 'https://latest.speckle.dev/streams/c544db35f5/commits/7c29374369'
|
||||
// Arcs
|
||||
// 'https://latest.speckle.dev/streams/0c6ad366c4/commits/912d83412e'
|
||||
// Freezers
|
||||
// 'https://speckle.xyz/streams/f0532359ac/commits/98678e2a3d?c=%5B2455.15367,2689.87156,4366.68444,205.422,-149.41199,148.749,0,1%5D'
|
||||
//Gergo's house
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/78bdd8eb76'
|
||||
// Point cloud
|
||||
// 'https://latest.speckle.dev/streams/2d19273d31/commits/9ceb423feb'
|
||||
// 'https://latest.speckle.dev/streams/7707df6cae/commits/02bdf09092'
|
||||
// 'https://latest.speckle.dev/streams/ca0378725b/commits/fbae00db5a'
|
||||
// Luis sphere
|
||||
// 'https://speckle.xyz/streams/b85d53c3b4/commits/b47f21b707'
|
||||
// Crankshaft
|
||||
// 'https://speckle.xyz/streams/c239718aff/commits/b3a8cfb97d'
|
||||
// Building AO params
|
||||
// 'https://latest.speckle.dev/streams/0dd74866d0/commits/317e210afa'
|
||||
// Murder Cube
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/7f0c4d2fc1/'
|
||||
// Classroom
|
||||
// 'https://speckle.xyz/streams/0208ffb67b/commits/a980292728'
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/328bd99997'
|
||||
// 'https://latest.speckle.dev/streams/83e18d886f/commits/532bd6be3e'
|
||||
// 'https://latest.speckle.dev/streams/1c2b3db9fb/commits/f12861736e'
|
||||
// 'https://latest.speckle.dev/streams/1c2b3db9fb/commits/1015d417ea'
|
||||
// Jedd's views
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/e6632fe057'
|
||||
// 'https://latest.speckle.dev/streams/7d051a6449/commits/7632757a33'
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/d8ec9cccf7'
|
||||
// MEPs (whatever they are)
|
||||
// 'https://latest.speckle.dev/streams/85bc4f61c6/commits/8575fe2978'
|
||||
// Alex cubes
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/d8ec9cccf7'
|
||||
// Tekla
|
||||
// 'https://latest.speckle.dev/streams/caec6d6676/commits/588c731104'
|
||||
// Purple market square
|
||||
// 'https://latest.speckle.dev/streams/4ed51ed832/commits/5a313ac116'
|
||||
// Sum building
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/4ea2759162'
|
||||
// Boat
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/ba5df427db'
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/c9ebe49824'
|
||||
// Dim's dome
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/158d4e8bec'
|
||||
// Engines 'n Shit
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/80b25e6e6c'
|
||||
// Dim's tower
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/7fd3ec04c0'
|
||||
//COD
|
||||
// 'https://latest.speckle.dev/streams/d3c83b47bf/commits/5f76b7ef3d?overlay=34577a1a92,571d460754,4c39b56c32,a62dd3a5da&c=%5B2046.38919,1074.97765,125.18054,2088.91862,1025.71927,94.66317,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/0feb23d263'
|
||||
// Jonathon's not loading
|
||||
// 'https://speckle.xyz/streams/ca99defd4b/commits/589b265c99'
|
||||
// Jonathon's 3070
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/d29e56fe75'
|
||||
// Filter issue
|
||||
// 'https://speckle.xyz/streams/f95d8deb90/commits/30f31becb6'
|
||||
// Transparent
|
||||
// 'https://latest.speckle.dev/streams/b5cc4e967c/objects/20343e0e8d469613a9d407499a6c38b1'
|
||||
// dark
|
||||
// 'https://latest.speckle.dev/streams/b5cc4e967c/commits/efdf3e2728?c=%5B-59.16128,-41.76491,-4.77376,-4.08052,-12.63558,-4.77376,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/b4366a7086?filter=%7B%7D&c=%5B-31.02357,37.60008,96.58899,11.01564,7.40652,66.0411,0,1%5D)'
|
||||
// double
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/b4366a7086?overlay=c009dbe144&filter=%7B%7D&c=%5B-104.70053,-98.80617,67.44669,6.53096,1.8739,38.584,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/c43ac05d04/commits/ec724cfbeb',
|
||||
// 'https://latest.speckle.dev/streams/efd2c6a31d/commits/4b495e1901'
|
||||
// 'https://latest.speckle.dev/streams/efd2c6a31d/commits/4b495e1901'
|
||||
// tekla 2
|
||||
// 'https://speckle.xyz/streams/be4813ccd2/commits/da85000921?c=%5B-1.12295,-2.60901,6.12402,4.77979,0.555,3.63346,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/85bc4f61c6/commits/bb7b718a1a'
|
||||
|
||||
// large meshes
|
||||
// 'https://speckle.xyz/streams/48e6e33aa6/commits/2cf892f1b0'
|
||||
// large lines
|
||||
// 'https://latest.speckle.dev/streams/444bfbd6e4/commits/8f297ad0cd'
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/6b1b1195c4'
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/cef1e7527b'
|
||||
// large lines
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/49dad07ae2'
|
||||
// Instances Rhino
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/1fff853107'
|
||||
// Instances Revit
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/92858681b7'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/655771674e'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/00dbbf4509'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/46fd255010'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/038a587267'
|
||||
// 'https://latest.speckle.dev/streams/3f895e614f/commits/8a3e424997'
|
||||
// Big curves
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/49dad07ae2'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/afda4ffdf8'
|
||||
// Jonathon's lines
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/8cd9e7e4fc'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/objects/f46f95746975591c18b0b854dab5b570 '
|
||||
// 'https://speckle.xyz/streams/813b728084/commits/e2f5ac9775'
|
||||
// Overlayhs
|
||||
// 'https://latest.speckle.dev/streams/85b9f0b9f5/commits/cdfbf3e036?overlay=71f61af444,00fe449457,53a6692b79'
|
||||
//'Rafinery'
|
||||
// 'https://speckle.xyz/streams/b7cac6a6df/commits/2e42381302'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/b8bbfd0c05?c=%5B-4.50925,11.1348,5.38124,-0.23829,0.68512,-0.09006,0,1%5D'
|
||||
)
|
||||
}
|
||||
+236
-270
@@ -9,279 +9,245 @@ import {
|
||||
import './style.css'
|
||||
import Sandbox from './Sandbox'
|
||||
|
||||
const container = document.querySelector<HTMLElement>('#renderer')
|
||||
if (!container) {
|
||||
throw new Error("Couldn't find #app container!")
|
||||
const createViewer = async (containerName: string, stream: string) => {
|
||||
const container = document.querySelector<HTMLElement>(containerName)
|
||||
|
||||
const controlsContainer = document.querySelector<HTMLElement>(
|
||||
`${containerName}-controls`
|
||||
)
|
||||
if (!container) {
|
||||
throw new Error("Couldn't find #app container!")
|
||||
}
|
||||
if (!controlsContainer) {
|
||||
throw new Error("Couldn't find #app controls container!")
|
||||
}
|
||||
|
||||
// Viewer setup
|
||||
const params = DefaultViewerParams
|
||||
params.showStats = true
|
||||
params.verbose = true
|
||||
|
||||
const multiSelectList: SelectionEvent[] = []
|
||||
const viewer: Viewer = new DebugViewer(container, params)
|
||||
await viewer.init()
|
||||
|
||||
const sandbox = new Sandbox(controlsContainer, viewer as DebugViewer, multiSelectList)
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
viewer.resize()
|
||||
})
|
||||
|
||||
viewer.on(
|
||||
ViewerEvent.LoadProgress,
|
||||
(a: { progress: number; id: string; url: string }) => {
|
||||
if (a.progress >= 1) {
|
||||
viewer.resize()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
viewer.on(ViewerEvent.LoadComplete, () => {
|
||||
Object.assign(sandbox.sceneParams.worldSize, viewer.World.worldSize)
|
||||
Object.assign(sandbox.sceneParams.worldOrigin, viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
})
|
||||
|
||||
viewer.on(ViewerEvent.UnloadComplete, () => {
|
||||
Object.assign(sandbox.sceneParams.worldSize, viewer.World.worldSize)
|
||||
Object.assign(sandbox.sceneParams.worldOrigin, viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
})
|
||||
viewer.on(ViewerEvent.UnloadAllComplete, () => {
|
||||
Object.assign(sandbox.sceneParams.worldSize, viewer.World.worldSize)
|
||||
Object.assign(sandbox.sceneParams.worldOrigin, viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
})
|
||||
|
||||
viewer.on(ViewerEvent.ObjectClicked, async (selectionInfo: SelectionEvent) => {
|
||||
if (!selectionInfo) {
|
||||
multiSelectList.length = 0
|
||||
await viewer.resetSelection()
|
||||
viewer.setSectionBox()
|
||||
return
|
||||
}
|
||||
if (!selectionInfo.multiple) multiSelectList.length = 0
|
||||
|
||||
const guids = multiSelectList.map((val) => val.hits[0].guid)
|
||||
if (
|
||||
(selectionInfo.multiple && !guids.includes(selectionInfo.hits[0].guid)) ||
|
||||
multiSelectList.length === 0
|
||||
) {
|
||||
multiSelectList.push(selectionInfo)
|
||||
}
|
||||
|
||||
const ids = multiSelectList.map((val) => val.hits[0].object.id)
|
||||
console.log(selectionInfo)
|
||||
await viewer.selectObjects(ids as string[])
|
||||
})
|
||||
|
||||
viewer.on(ViewerEvent.ObjectDoubleClicked, async (selectionInfo: SelectionEvent) => {
|
||||
if (!selectionInfo) {
|
||||
viewer.zoom()
|
||||
return
|
||||
}
|
||||
|
||||
viewer.zoom([selectionInfo.hits[0].object.id as string])
|
||||
})
|
||||
|
||||
sandbox.makeGenericUI()
|
||||
sandbox.makeSceneUI()
|
||||
sandbox.makeFilteringUI()
|
||||
sandbox.makeBatchesUI()
|
||||
|
||||
await sandbox.loadUrl(stream)
|
||||
}
|
||||
|
||||
// Viewer setup
|
||||
const params = DefaultViewerParams
|
||||
params.showStats = true
|
||||
params.verbose = true
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
const getStream = () => {
|
||||
return (
|
||||
// prettier-ignore
|
||||
// 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8?c=%5B-7.66134,10.82932,6.41935,-0.07739,-13.88552,1.8697,0,1%5D'
|
||||
// Revit sample house (good for bim-like stuff with many display meshes)
|
||||
|
||||
const multiSelectList: SelectionEvent[] = []
|
||||
const viewer: Viewer = new DebugViewer(container, params)
|
||||
await viewer.init()
|
||||
'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8'
|
||||
// 'Super' heavy revit shit
|
||||
// 'https://speckle.xyz/streams/e6f9156405/commits/0694d53bb5'
|
||||
// IFC building (good for a tree based structure)
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/2ebd336223'
|
||||
// IFC story, a subtree of the above
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/objects/8247bbc53865b0e0cb5ee4e252e66216'
|
||||
// Small scale lines
|
||||
// 'https://speckle.xyz/streams/638d3b1f83/commits/6025e2b546?c=%5B2.18058,-0.20814,9.67642,3.85491,5.05364,0,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/3ed8357f29/commits/d10f2af1ce'
|
||||
// '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'
|
||||
// AutoCAD
|
||||
// 'https://latest.speckle.dev/streams/3ed8357f29/commits/d10f2af1ce'
|
||||
//Blizzard world
|
||||
// 'https://latest.speckle.dev/streams/0c6ad366c4/commits/aa1c393aec'
|
||||
//Car
|
||||
// 'https://latest.speckle.dev/streams/17d2e25a97/commits/6b6cf3d43e'
|
||||
// Jonathon's
|
||||
// 'https://latest.speckle.dev/streams/501258ee5f/commits/f885570011'
|
||||
// Alex's cube
|
||||
// 'https://latest.speckle.dev/streams/46e3e0e1ec/commits/a6392c19d6?c=%5B6.85874,2.9754,0.79022,0,0,0,0,1%5D'
|
||||
// Groups of groups
|
||||
// 'https://speckle.xyz/streams/1ce562e99a/commits/6fa28a5a0f'
|
||||
// Arc flowers
|
||||
// 'https://latest.speckle.dev/streams/9e6c4343ba/commits/037e382aa2'
|
||||
// Car lines
|
||||
// 'https://speckle.xyz/streams/638d3b1f83/commits/6025e2b546?c=%5B2.18058,-0.20814,9.67642,3.85491,5.05364,0,0,1%5D'
|
||||
// Arc and lines
|
||||
// ' https://speckle.xyz/streams/99abc74dd4/commits/b32fdcf171?c=%5B198440.6051,6522070.21462,19199.49584,176653.24219,6523663.5,0,0,1%5D'
|
||||
// AUTOCAD test stream
|
||||
// 'https://latest.speckle.dev/streams/3ed8357f29/commits/b49bfc73ea'
|
||||
// REVIT test stream
|
||||
// 'https://latest.speckle.dev/streams/c544db35f5/commits/7c29374369'
|
||||
// Arcs
|
||||
// 'https://latest.speckle.dev/streams/0c6ad366c4/commits/912d83412e'
|
||||
// Freezers
|
||||
// 'https://speckle.xyz/streams/f0532359ac/commits/98678e2a3d?c=%5B2455.15367,2689.87156,4366.68444,205.422,-149.41199,148.749,0,1%5D'
|
||||
//Gergo's house
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/78bdd8eb76'
|
||||
// Point cloud
|
||||
// 'https://latest.speckle.dev/streams/2d19273d31/commits/9ceb423feb'
|
||||
// 'https://latest.speckle.dev/streams/7707df6cae/commits/02bdf09092'
|
||||
// 'https://latest.speckle.dev/streams/ca0378725b/commits/fbae00db5a'
|
||||
// Luis sphere
|
||||
// 'https://speckle.xyz/streams/b85d53c3b4/commits/b47f21b707'
|
||||
// Crankshaft
|
||||
// 'https://speckle.xyz/streams/c239718aff/commits/b3a8cfb97d'
|
||||
// Building AO params
|
||||
// 'https://latest.speckle.dev/streams/0dd74866d0/commits/317e210afa'
|
||||
// Murder Cube
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/7f0c4d2fc1/'
|
||||
// Classroom
|
||||
// 'https://speckle.xyz/streams/0208ffb67b/commits/a980292728'
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/328bd99997'
|
||||
// 'https://latest.speckle.dev/streams/83e18d886f/commits/532bd6be3e'
|
||||
// 'https://latest.speckle.dev/streams/1c2b3db9fb/commits/f12861736e'
|
||||
// 'https://latest.speckle.dev/streams/1c2b3db9fb/commits/1015d417ea'
|
||||
// Jedd's views
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/e6632fe057'
|
||||
// 'https://latest.speckle.dev/streams/7d051a6449/commits/7632757a33'
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/d8ec9cccf7'
|
||||
// MEPs (whatever they are)
|
||||
// 'https://latest.speckle.dev/streams/85bc4f61c6/commits/8575fe2978'
|
||||
// Alex cubes
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/d8ec9cccf7'
|
||||
// Tekla
|
||||
// 'https://latest.speckle.dev/streams/caec6d6676/commits/588c731104'
|
||||
// Purple market square
|
||||
// 'https://latest.speckle.dev/streams/4ed51ed832/commits/5a313ac116'
|
||||
// Sum building
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/4ea2759162'
|
||||
// Boat
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/ba5df427db'
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/c9ebe49824'
|
||||
// Dim's dome
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/158d4e8bec'
|
||||
// Engines 'n Shit
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/80b25e6e6c'
|
||||
// Dim's tower
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/7fd3ec04c0'
|
||||
//COD
|
||||
// 'https://latest.speckle.dev/streams/d3c83b47bf/commits/5f76b7ef3d?overlay=34577a1a92,571d460754,4c39b56c32,a62dd3a5da&c=%5B2046.38919,1074.97765,125.18054,2088.91862,1025.71927,94.66317,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/0feb23d263'
|
||||
// Jonathon's not loading
|
||||
// 'https://speckle.xyz/streams/ca99defd4b/commits/589b265c99'
|
||||
// Jonathon's 3070
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/d29e56fe75'
|
||||
// Filter issue
|
||||
// 'https://speckle.xyz/streams/f95d8deb90/commits/30f31becb6'
|
||||
// Transparent
|
||||
// 'https://latest.speckle.dev/streams/b5cc4e967c/objects/20343e0e8d469613a9d407499a6c38b1'
|
||||
// dark
|
||||
// 'https://latest.speckle.dev/streams/b5cc4e967c/commits/efdf3e2728?c=%5B-59.16128,-41.76491,-4.77376,-4.08052,-12.63558,-4.77376,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/b4366a7086?filter=%7B%7D&c=%5B-31.02357,37.60008,96.58899,11.01564,7.40652,66.0411,0,1%5D)'
|
||||
// double
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/b4366a7086?overlay=c009dbe144&filter=%7B%7D&c=%5B-104.70053,-98.80617,67.44669,6.53096,1.8739,38.584,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/c43ac05d04/commits/ec724cfbeb',
|
||||
// 'https://latest.speckle.dev/streams/efd2c6a31d/commits/4b495e1901'
|
||||
// 'https://latest.speckle.dev/streams/efd2c6a31d/commits/4b495e1901'
|
||||
// tekla 2
|
||||
// 'https://speckle.xyz/streams/be4813ccd2/commits/da85000921?c=%5B-1.12295,-2.60901,6.12402,4.77979,0.555,3.63346,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/85bc4f61c6/commits/bb7b718a1a'
|
||||
|
||||
const sandbox = new Sandbox(viewer as DebugViewer, multiSelectList)
|
||||
// large meshes
|
||||
// 'https://speckle.xyz/streams/48e6e33aa6/commits/2cf892f1b0'
|
||||
// large lines
|
||||
// 'https://latest.speckle.dev/streams/444bfbd6e4/commits/8f297ad0cd'
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/6b1b1195c4'
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/cef1e7527b'
|
||||
// large lines
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/49dad07ae2'
|
||||
// Instances Rhino
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/1fff853107'
|
||||
// Instances Revit
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/92858681b7'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/655771674e'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/00dbbf4509'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/46fd255010'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/038a587267'
|
||||
// 'https://latest.speckle.dev/streams/3f895e614f/commits/8a3e424997'
|
||||
// Big curves
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/49dad07ae2'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/afda4ffdf8'
|
||||
// Jonathon's lines
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/8cd9e7e4fc'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/objects/f46f95746975591c18b0b854dab5b570 '
|
||||
// 'https://speckle.xyz/streams/813b728084/commits/e2f5ac9775'
|
||||
// Overlayhs
|
||||
// 'https://latest.speckle.dev/streams/85b9f0b9f5/commits/cdfbf3e036?overlay=71f61af444,00fe449457,53a6692b79'
|
||||
//'Rafinery'
|
||||
// 'https://speckle.xyz/streams/b7cac6a6df/commits/2e42381302'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/b8bbfd0c05?c=%5B-4.50925,11.1348,5.38124,-0.23829,0.68512,-0.09006,0,1%5D'
|
||||
)
|
||||
}
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
viewer.resize()
|
||||
})
|
||||
const container0 = document.querySelector<HTMLElement>('#renderer')
|
||||
if (!container0) {
|
||||
throw new Error("Couldn't find app container!")
|
||||
}
|
||||
|
||||
/** QUERY TEST */
|
||||
// container.addEventListener('mousemove', async (ev) => {
|
||||
// const point = viewer.Utils.screenToNDC(ev.clientX, ev.clientY)
|
||||
// const res: QueryResult = viewer.query<IntersectionQuery>({
|
||||
// id: 'test',
|
||||
// point,
|
||||
// operation: 'Pick'
|
||||
// })
|
||||
// if (!res) return
|
||||
// const hitPoint = {
|
||||
// x: res.objects[0].point.x,
|
||||
// y: res.objects[0].point.y,
|
||||
// z: res.objects[0].point.z
|
||||
// }
|
||||
// await viewer.selectObjects([res.objects[0].object.id])
|
||||
// const resProj: QueryResult = viewer.query<PointQuery>({
|
||||
// id: 'test',
|
||||
// point: hitPoint,
|
||||
// operation: 'Project'
|
||||
// })
|
||||
// // console.log(viewer.Utils.NDCToScreen(res_p.x, res_p.y))
|
||||
// const resUnProj: QueryResult = viewer.query<PointQuery>({
|
||||
// id: 'test',
|
||||
// point: { x: resProj.x, y: resProj.y, z: resProj.z },
|
||||
// operation: 'Unproject'
|
||||
// })
|
||||
// console.log(
|
||||
// hitPoint.x - resUnProj.x,
|
||||
// hitPoint.y - resUnProj.y,
|
||||
// hitPoint.z - resUnProj.z
|
||||
// )
|
||||
// })
|
||||
|
||||
viewer.on(
|
||||
ViewerEvent.LoadProgress,
|
||||
(a: { progress: number; id: string; url: string }) => {
|
||||
if (a.progress >= 1) {
|
||||
viewer.resize()
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// const updt = () => {
|
||||
// const resOcc = viewer.query<IntersectionQuery>({
|
||||
// id: 'testX',
|
||||
// point: { x: -2.2779617121296436, y: -1.9397099063369891, z: 7.411126386421243 },
|
||||
// tolerance: 0.001,
|
||||
// operation: 'Occlusion'
|
||||
// })
|
||||
// if (resOcc) console.log(resOcc.objects === null)
|
||||
// requestAnimationFrame(updt)
|
||||
// }
|
||||
|
||||
// requestAnimationFrame(updt)
|
||||
|
||||
viewer.on(ViewerEvent.LoadComplete, () => {
|
||||
Object.assign(Sandbox.sceneParams.worldSize, Viewer.World.worldSize)
|
||||
Object.assign(Sandbox.sceneParams.worldOrigin, Viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
})
|
||||
viewer.on(ViewerEvent.UnloadComplete, () => {
|
||||
Object.assign(Sandbox.sceneParams.worldSize, Viewer.World.worldSize)
|
||||
Object.assign(Sandbox.sceneParams.worldOrigin, Viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
})
|
||||
viewer.on(ViewerEvent.UnloadAllComplete, () => {
|
||||
Object.assign(Sandbox.sceneParams.worldSize, Viewer.World.worldSize)
|
||||
Object.assign(Sandbox.sceneParams.worldOrigin, Viewer.World.worldOrigin)
|
||||
sandbox.refresh()
|
||||
})
|
||||
|
||||
viewer.on(ViewerEvent.ObjectClicked, async (selectionInfo: SelectionEvent) => {
|
||||
if (!selectionInfo) {
|
||||
multiSelectList.length = 0
|
||||
await viewer.resetSelection()
|
||||
viewer.setSectionBox()
|
||||
return
|
||||
}
|
||||
if (!selectionInfo.multiple) multiSelectList.length = 0
|
||||
|
||||
const guids = multiSelectList.map((val) => val.hits[0].guid)
|
||||
if (
|
||||
(selectionInfo.multiple && !guids.includes(selectionInfo.hits[0].guid)) ||
|
||||
multiSelectList.length === 0
|
||||
) {
|
||||
multiSelectList.push(selectionInfo)
|
||||
}
|
||||
|
||||
const ids = multiSelectList.map((val) => val.hits[0].object.id)
|
||||
console.log(selectionInfo)
|
||||
await viewer.selectObjects(ids as string[])
|
||||
})
|
||||
|
||||
viewer.on(ViewerEvent.ObjectDoubleClicked, async (selectionInfo: SelectionEvent) => {
|
||||
if (!selectionInfo) {
|
||||
viewer.zoom()
|
||||
return
|
||||
}
|
||||
|
||||
viewer.zoom([selectionInfo.hits[0].object.id as string])
|
||||
})
|
||||
|
||||
sandbox.makeGenericUI()
|
||||
sandbox.makeSceneUI()
|
||||
sandbox.makeFilteringUI()
|
||||
sandbox.makeBatchesUI()
|
||||
// Load demo object
|
||||
// setTimeout(async () => {
|
||||
// const objUrl = (
|
||||
// await UrlHelper.getResourceUrls(
|
||||
// 'https://speckle.xyz/streams/e6f9156405/commits/0694d53bb5'
|
||||
// )
|
||||
// )[0]
|
||||
// viewer.cancelLoad(objUrl)
|
||||
// }, 1500)
|
||||
await sandbox.loadUrl(
|
||||
// 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8?c=%5B-7.66134,10.82932,6.41935,-0.07739,-13.88552,1.8697,0,1%5D'
|
||||
// Revit sample house (good for bim-like stuff with many display meshes)
|
||||
// 'https://speckle.xyz/streams/da9e320dad/commits/5388ef24b8'
|
||||
// 'Super' heavy revit shit
|
||||
// 'https://speckle.xyz/streams/e6f9156405/commits/0694d53bb5'
|
||||
// IFC building (good for a tree based structure)
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/2ebd336223'
|
||||
// IFC story, a subtree of the above
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/objects/8247bbc53865b0e0cb5ee4e252e66216'
|
||||
// Small scale lines
|
||||
// 'https://speckle.xyz/streams/638d3b1f83/commits/6025e2b546?c=%5B2.18058,-0.20814,9.67642,3.85491,5.05364,0,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/3ed8357f29/commits/d10f2af1ce'
|
||||
// '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'
|
||||
// AutoCAD
|
||||
// 'https://latest.speckle.dev/streams/3ed8357f29/commits/d10f2af1ce'
|
||||
//Blizzard world
|
||||
// 'https://latest.speckle.dev/streams/0c6ad366c4/commits/aa1c393aec'
|
||||
//Car
|
||||
// 'https://latest.speckle.dev/streams/17d2e25a97/commits/6b6cf3d43e'
|
||||
// Jonathon's
|
||||
// 'https://latest.speckle.dev/streams/501258ee5f/commits/f885570011'
|
||||
// Alex's cube
|
||||
// 'https://latest.speckle.dev/streams/46e3e0e1ec/commits/a6392c19d6?c=%5B6.85874,2.9754,0.79022,0,0,0,0,1%5D'
|
||||
// Groups of groups
|
||||
// 'https://speckle.xyz/streams/1ce562e99a/commits/6fa28a5a0f'
|
||||
// Arc flowers
|
||||
// 'https://latest.speckle.dev/streams/9e6c4343ba/commits/037e382aa2'
|
||||
// Car lines
|
||||
// 'https://speckle.xyz/streams/638d3b1f83/commits/6025e2b546?c=%5B2.18058,-0.20814,9.67642,3.85491,5.05364,0,0,1%5D'
|
||||
// Arc and lines
|
||||
// ' https://speckle.xyz/streams/99abc74dd4/commits/b32fdcf171?c=%5B198440.6051,6522070.21462,19199.49584,176653.24219,6523663.5,0,0,1%5D'
|
||||
// AUTOCAD test stream
|
||||
// 'https://latest.speckle.dev/streams/3ed8357f29/commits/b49bfc73ea'
|
||||
// REVIT test stream
|
||||
// 'https://latest.speckle.dev/streams/c544db35f5/commits/7c29374369'
|
||||
// Arcs
|
||||
// 'https://latest.speckle.dev/streams/0c6ad366c4/commits/912d83412e'
|
||||
// Freezers
|
||||
// 'https://speckle.xyz/streams/f0532359ac/commits/98678e2a3d?c=%5B2455.15367,2689.87156,4366.68444,205.422,-149.41199,148.749,0,1%5D'
|
||||
//Gergo's house
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/78bdd8eb76'
|
||||
// Point cloud
|
||||
// 'https://latest.speckle.dev/streams/2d19273d31/commits/9ceb423feb'
|
||||
// 'https://latest.speckle.dev/streams/7707df6cae/commits/02bdf09092'
|
||||
// 'https://latest.speckle.dev/streams/ca0378725b/commits/fbae00db5a'
|
||||
// Luis sphere
|
||||
// 'https://speckle.xyz/streams/b85d53c3b4/commits/b47f21b707'
|
||||
// Crankshaft
|
||||
// 'https://speckle.xyz/streams/c239718aff/commits/b3a8cfb97d'
|
||||
// Building AO params
|
||||
// 'https://latest.speckle.dev/streams/0dd74866d0/commits/317e210afa'
|
||||
// Murder Cube
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/7f0c4d2fc1/'
|
||||
// Classroom
|
||||
// 'https://speckle.xyz/streams/0208ffb67b/commits/a980292728'
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/328bd99997'
|
||||
// 'https://latest.speckle.dev/streams/83e18d886f/commits/532bd6be3e'
|
||||
// 'https://latest.speckle.dev/streams/1c2b3db9fb/commits/f12861736e'
|
||||
// 'https://latest.speckle.dev/streams/1c2b3db9fb/commits/1015d417ea'
|
||||
// Jedd's views
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/e6632fe057'
|
||||
// 'https://latest.speckle.dev/streams/7d051a6449/commits/7632757a33'
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/d8ec9cccf7'
|
||||
// MEPs (whatever they are)
|
||||
// 'https://latest.speckle.dev/streams/85bc4f61c6/commits/8575fe2978'
|
||||
// Alex cubes
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/d8ec9cccf7'
|
||||
// Tekla
|
||||
// 'https://latest.speckle.dev/streams/caec6d6676/commits/588c731104'
|
||||
// Purple market square
|
||||
// 'https://latest.speckle.dev/streams/4ed51ed832/commits/5a313ac116'
|
||||
// Sum building
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/4ea2759162'
|
||||
// Boat
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/ba5df427db'
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/c9ebe49824'
|
||||
// Dim's dome
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/158d4e8bec'
|
||||
// Engines 'n Shit
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/80b25e6e6c'
|
||||
// Dim's tower
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/7fd3ec04c0'
|
||||
//COD
|
||||
// 'https://latest.speckle.dev/streams/d3c83b47bf/commits/5f76b7ef3d?overlay=34577a1a92,571d460754,4c39b56c32,a62dd3a5da&c=%5B2046.38919,1074.97765,125.18054,2088.91862,1025.71927,94.66317,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/4658eb53b9/commits/0feb23d263'
|
||||
// Jonathon's not loading
|
||||
// 'https://speckle.xyz/streams/ca99defd4b/commits/589b265c99'
|
||||
// Jonathon's 3070
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/d29e56fe75'
|
||||
// Filter issue
|
||||
// 'https://speckle.xyz/streams/f95d8deb90/commits/30f31becb6'
|
||||
// Transparent
|
||||
// 'https://latest.speckle.dev/streams/b5cc4e967c/objects/20343e0e8d469613a9d407499a6c38b1'
|
||||
// dark
|
||||
// 'https://latest.speckle.dev/streams/b5cc4e967c/commits/efdf3e2728?c=%5B-59.16128,-41.76491,-4.77376,-4.08052,-12.63558,-4.77376,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/b4366a7086?filter=%7B%7D&c=%5B-31.02357,37.60008,96.58899,11.01564,7.40652,66.0411,0,1%5D)'
|
||||
// double
|
||||
// 'https://latest.speckle.dev/streams/92b620fb17/commits/b4366a7086?overlay=c009dbe144&filter=%7B%7D&c=%5B-104.70053,-98.80617,67.44669,6.53096,1.8739,38.584,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/c43ac05d04/commits/ec724cfbeb',
|
||||
// 'https://latest.speckle.dev/streams/efd2c6a31d/commits/4b495e1901'
|
||||
// 'https://latest.speckle.dev/streams/efd2c6a31d/commits/4b495e1901'
|
||||
// tekla 2
|
||||
// 'https://speckle.xyz/streams/be4813ccd2/commits/da85000921?c=%5B-1.12295,-2.60901,6.12402,4.77979,0.555,3.63346,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/85bc4f61c6/commits/bb7b718a1a'
|
||||
|
||||
// large meshes
|
||||
// 'https://speckle.xyz/streams/48e6e33aa6/commits/2cf892f1b0'
|
||||
// large lines
|
||||
// 'https://latest.speckle.dev/streams/444bfbd6e4/commits/8f297ad0cd'
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/6b1b1195c4'
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/cef1e7527b'
|
||||
// large lines
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/49dad07ae2'
|
||||
// Instances Rhino
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/1fff853107'
|
||||
// Instances Revit
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/92858681b7'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/655771674e'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/00dbbf4509'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/46fd255010'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/038a587267'
|
||||
// 'https://latest.speckle.dev/streams/3f895e614f/commits/8a3e424997'
|
||||
// Big curves
|
||||
// 'https://latest.speckle.dev/streams/c1faab5c62/commits/49dad07ae2'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/afda4ffdf8'
|
||||
// Jonathon's lines
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/8cd9e7e4fc'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/objects/f46f95746975591c18b0b854dab5b570 '
|
||||
// 'https://speckle.xyz/streams/813b728084/commits/e2f5ac9775'
|
||||
// Overlayhs
|
||||
// 'https://latest.speckle.dev/streams/85b9f0b9f5/commits/cdfbf3e036?overlay=71f61af444,00fe449457,53a6692b79'
|
||||
//'Rafinery'
|
||||
// 'https://speckle.xyz/streams/b7cac6a6df/commits/2e42381302'
|
||||
// 'https://speckle.xyz/streams/7ce9010d71/commits/b8bbfd0c05?c=%5B-4.50925,11.1348,5.38124,-0.23829,0.68512,-0.09006,0,1%5D'
|
||||
// 'https://latest.speckle.dev/streams/caec6d6676/commits/588c731104'
|
||||
// 'https://latest.speckle.dev/streams/f92e060177/commits/1fff853107'
|
||||
'https://latest.speckle.dev/streams/c43ac05d04/commits/ec724cfbeb'
|
||||
// 'https://latest.speckle.dev/streams/bbdf474833/commits/83d0eb7e06 '
|
||||
)
|
||||
createViewer('#renderer', getStream())
|
||||
|
||||
@@ -23,6 +23,17 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#renderer0-controls:first-child {
|
||||
pointer-events: auto;
|
||||
}
|
||||
#renderer1-controls:first-child {
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
canvas {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.button {
|
||||
border: 0;
|
||||
line-height: 1.5;
|
||||
|
||||
@@ -6,6 +6,8 @@ import { PropertyInfo } from './modules/filtering/PropertyManager'
|
||||
import { Query, QueryArgsResultMap, QueryResult } from './modules/queries/Query'
|
||||
import { DataTree } from './modules/tree/DataTree'
|
||||
import { Utils } from './modules/Utils'
|
||||
import { WorldTree } from './modules/tree/WorldTree'
|
||||
import { World } from './modules/World'
|
||||
|
||||
export interface ViewerParams {
|
||||
showStats: boolean
|
||||
@@ -213,9 +215,11 @@ export interface IViewer {
|
||||
|
||||
/** Data ops */
|
||||
getDataTree(): DataTree
|
||||
getWorldTree(): WorldTree
|
||||
query<T extends Query>(query: T): QueryArgsResultMap[T['operation']]
|
||||
queryAsync(query: Query): Promise<QueryResult>
|
||||
get Utils(): Utils
|
||||
get World(): World
|
||||
|
||||
getObjects(id: string): BatchObject[]
|
||||
explode(time: number, range: number)
|
||||
|
||||
@@ -13,12 +13,6 @@ import Logger from 'js-logger'
|
||||
|
||||
export class Assets {
|
||||
private static _cache: { [name: string]: Texture } = {}
|
||||
private static pmremGenerator: PMREMGenerator
|
||||
|
||||
public constructor(renderer: WebGLRenderer) {
|
||||
Assets.pmremGenerator = new PMREMGenerator(renderer)
|
||||
Assets.pmremGenerator.compileEquirectangularShader()
|
||||
}
|
||||
|
||||
private static getLoader(src: string, assetType: AssetType): TextureLoader {
|
||||
if (assetType === undefined) assetType = src.split('.').pop() as AssetType
|
||||
@@ -36,7 +30,10 @@ export class Assets {
|
||||
}
|
||||
}
|
||||
|
||||
public static getEnvironment(asset: Asset | string): Promise<Texture> {
|
||||
public static getEnvironment(
|
||||
asset: Asset | string,
|
||||
renderer: WebGLRenderer
|
||||
): Promise<Texture> {
|
||||
let srcUrl: string = null
|
||||
let assetType: AssetType = undefined
|
||||
if ((<Asset>asset).src) {
|
||||
@@ -55,9 +52,12 @@ export class Assets {
|
||||
loader.load(
|
||||
srcUrl,
|
||||
(texture) => {
|
||||
const pmremRT = this.pmremGenerator.fromEquirectangular(texture)
|
||||
const generator = new PMREMGenerator(renderer)
|
||||
generator.compileEquirectangularShader()
|
||||
const pmremRT = generator.fromEquirectangular(texture)
|
||||
this._cache[srcUrl] = pmremRT.texture
|
||||
texture.dispose()
|
||||
generator.dispose()
|
||||
resolve(this._cache[srcUrl])
|
||||
},
|
||||
undefined,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { WorldTree } from './tree/WorldTree'
|
||||
import { Viewer } from './Viewer'
|
||||
|
||||
export class DebugViewer extends Viewer {
|
||||
@@ -9,8 +8,4 @@ export class DebugViewer extends Viewer {
|
||||
requestRenderShadowmap() {
|
||||
this.getRenderer().updateDirectLights()
|
||||
}
|
||||
|
||||
getWorldTree() {
|
||||
return WorldTree.getInstance()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,11 +376,6 @@ export default class SectionBox extends EventEmitter {
|
||||
this.controls.showZ = true
|
||||
}
|
||||
|
||||
// setBoxFromObjects(objectIds: string[], offset = 0.05) {
|
||||
// WorldTree.getInstance().walk() => Solved
|
||||
// this.setBox(...)
|
||||
// }
|
||||
|
||||
setBox(targetBox, offset = 0.05) {
|
||||
let box
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import SpeckleDepthMaterial from './materials/SpeckleDepthMaterial'
|
||||
import SpeckleStandardMaterial from './materials/SpeckleStandardMaterial'
|
||||
import { NodeRenderView } from './tree/NodeRenderView'
|
||||
import { Viewer } from './Viewer'
|
||||
import { TreeNode, WorldTree } from './tree/WorldTree'
|
||||
import { TreeNode } from './tree/WorldTree'
|
||||
import {
|
||||
CanonicalView,
|
||||
DefaultLightConfiguration,
|
||||
@@ -482,7 +482,10 @@ export default class SpeckleRenderer {
|
||||
}
|
||||
|
||||
public addRenderTree(subtreeId: string) {
|
||||
this.batcher.makeBatches(subtreeId, SpeckleTypeAllRenderables)
|
||||
this.batcher.makeBatches(
|
||||
this.viewer.getWorldTree().getRenderTree(subtreeId),
|
||||
SpeckleTypeAllRenderables
|
||||
)
|
||||
const subtreeGroup = new Group()
|
||||
subtreeGroup.name = subtreeId
|
||||
subtreeGroup.layers.set(ObjectLayers.STREAM_CONTENT)
|
||||
@@ -510,12 +513,14 @@ export default class SpeckleRenderer {
|
||||
this.rootGroup.add(subtreeGroup)
|
||||
|
||||
const generator = this.batcher.makeBatchesAsync(
|
||||
subtreeId,
|
||||
this.viewer.getWorldTree().getRenderTree(subtreeId),
|
||||
SpeckleTypeAllRenderables,
|
||||
undefined,
|
||||
priority
|
||||
)
|
||||
for await (const batch of generator) {
|
||||
if (!batch) continue
|
||||
|
||||
this.addBatch(batch, subtreeGroup)
|
||||
this.zoom()
|
||||
if (batch.geometryType === GeometryType.MESH) {
|
||||
@@ -572,6 +577,7 @@ export default class SpeckleRenderer {
|
||||
parent.add(bvhHelper)
|
||||
}
|
||||
}
|
||||
this.viewer.World.expandWorld(batch.bounds)
|
||||
}
|
||||
|
||||
public removeRenderTree(subtreeId: string) {
|
||||
@@ -829,7 +835,7 @@ export default class SpeckleRenderer {
|
||||
const queryResult = []
|
||||
for (let k = 0; k < rvs.length; k++) {
|
||||
const hitId = rvs[k].renderData.id
|
||||
const hitNode = WorldTree.getInstance().findId(hitId)
|
||||
const hitNode = this.viewer.getWorldTree().findId(hitId)
|
||||
let parentNode = hitNode
|
||||
while (!parentNode.model.atomic && parentNode.parent) {
|
||||
parentNode = parentNode.parent
|
||||
@@ -952,11 +958,16 @@ export default class SpeckleRenderer {
|
||||
let box = new Box3()
|
||||
const rvs: NodeRenderView[] = []
|
||||
if (objectIds.length > 0) {
|
||||
WorldTree.getInstance().walk((node: TreeNode) => {
|
||||
this.viewer.getWorldTree().walk((node: TreeNode) => {
|
||||
if (!node.model.atomic) return true
|
||||
if (!node.model.raw) return true
|
||||
if (objectIds.indexOf(node.model.raw.id) !== -1) {
|
||||
rvs.push(...WorldTree.getRenderTree().getRenderViewsForNode(node, node))
|
||||
rvs.push(
|
||||
...this.viewer
|
||||
.getWorldTree()
|
||||
.getRenderTree()
|
||||
.getRenderViewsForNode(node, node)
|
||||
)
|
||||
}
|
||||
return true
|
||||
})
|
||||
@@ -1241,41 +1252,41 @@ export default class SpeckleRenderer {
|
||||
}
|
||||
|
||||
/** DEBUG */
|
||||
public onObjectClickDebug(e) {
|
||||
const results: Array<Intersection> = this._intersections.intersect(
|
||||
this._scene,
|
||||
this.viewer.cameraHandler.activeCam.camera,
|
||||
e,
|
||||
true,
|
||||
this.viewer.sectionBox.getCurrentBox()
|
||||
)
|
||||
if (!results) {
|
||||
this.batcher.resetBatchesDrawRanges()
|
||||
return
|
||||
}
|
||||
const result = results[0]
|
||||
// console.warn(result)
|
||||
const rv = this.batcher.getRenderView(
|
||||
result.object.uuid,
|
||||
result.faceIndex !== undefined ? result.faceIndex : result.index
|
||||
)
|
||||
const hitId = rv.renderData.id
|
||||
// public onObjectClickDebug(e) {
|
||||
// const results: Array<Intersection> = this._intersections.intersect(
|
||||
// this._scene,
|
||||
// this.viewer.cameraHandler.activeCam.camera,
|
||||
// e,
|
||||
// true,
|
||||
// this.viewer.sectionBox.getCurrentBox()
|
||||
// )
|
||||
// if (!results) {
|
||||
// this.batcher.resetBatchesDrawRanges()
|
||||
// return
|
||||
// }
|
||||
// const result = results[0]
|
||||
// // console.warn(result)
|
||||
// const rv = this.batcher.getRenderView(
|
||||
// result.object.uuid,
|
||||
// result.faceIndex !== undefined ? result.faceIndex : result.index
|
||||
// )
|
||||
// const hitId = rv.renderData.id
|
||||
|
||||
// const hitNode = WorldTree.getInstance().findId(hitId)
|
||||
// console.log(hitNode)
|
||||
// // const hitNode = WorldTree.getInstance(this.viewer.viewerGuid).findId(hitId)
|
||||
// // console.log(hitNode)
|
||||
|
||||
this.batcher.resetBatchesDrawRanges()
|
||||
// this.batcher.resetBatchesDrawRanges()
|
||||
|
||||
this.batcher.isolateRenderViewBatch(hitId)
|
||||
if (this.SHOW_BVH) {
|
||||
this.allObjects.traverse((obj) => {
|
||||
if (obj.name.includes('_bvh')) {
|
||||
obj.visible = false
|
||||
}
|
||||
})
|
||||
this.scene.getObjectByName(result.object.id + '_bvh').visible = true
|
||||
}
|
||||
}
|
||||
// this.batcher.isolateRenderViewBatch(hitId)
|
||||
// if (this.SHOW_BVH) {
|
||||
// this.allObjects.traverse((obj) => {
|
||||
// if (obj.name.includes('_bvh')) {
|
||||
// obj.visible = false
|
||||
// }
|
||||
// })
|
||||
// this.scene.getObjectByName(result.object.id + '_bvh').visible = true
|
||||
// }
|
||||
// }
|
||||
|
||||
public debugShowBatches() {
|
||||
this.batcher.resetBatchesDrawRanges()
|
||||
@@ -1318,7 +1329,7 @@ export default class SpeckleRenderer {
|
||||
const objects = batches[k].mesh.batchObjects
|
||||
for (let i = 0; i < objects.length; i++) {
|
||||
const center = objects[i].renderView.aabb.getCenter(new Vector3())
|
||||
const dir = center.sub(Viewer.World.worldOrigin)
|
||||
const dir = center.sub(this.viewer.World.worldOrigin)
|
||||
dir.normalize().multiplyScalar(time * range)
|
||||
objects[i].transformTRS(dir, undefined, undefined, undefined)
|
||||
}
|
||||
@@ -1330,8 +1341,11 @@ export default class SpeckleRenderer {
|
||||
}
|
||||
|
||||
public getObjects(id: string): BatchObject[] {
|
||||
const node = WorldTree.getInstance().findId(id)
|
||||
const rvs = WorldTree.getRenderTree().getRenderViewsForNode(node, node)
|
||||
const node = this.viewer.getWorldTree().findId(id)
|
||||
const rvs = this.viewer
|
||||
.getWorldTree()
|
||||
.getRenderTree()
|
||||
.getRenderViewsForNode(node, node)
|
||||
const batches = this.batcher.getBatches(undefined, GeometryType.MESH) as MeshBatch[]
|
||||
const meshes = batches.map((batch: MeshBatch) => batch.mesh)
|
||||
const objects = meshes.flatMap((mesh) => mesh.batchObjects)
|
||||
|
||||
@@ -42,10 +42,12 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
private startupParams: ViewerParams
|
||||
|
||||
/** Viewer components */
|
||||
private static world: World = new World()
|
||||
private tree: WorldTree = new WorldTree()
|
||||
private world: World = new World()
|
||||
public static Assets: Assets
|
||||
protected speckleRenderer: SpeckleRenderer
|
||||
private filteringManager: FilteringManager
|
||||
private propertyManager: PropertyManager
|
||||
/** Legacy viewer components (will revisit soon) */
|
||||
public sectionBox: SectionBox
|
||||
public cameraHandler: CameraHandler
|
||||
@@ -58,7 +60,7 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
/** various utils/helpers */
|
||||
private utils: Utils
|
||||
/** Gets the World object. Currently it's used for info mostly */
|
||||
public static get World(): World {
|
||||
public get World(): World {
|
||||
return this.world
|
||||
}
|
||||
|
||||
@@ -84,7 +86,8 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
this.container = container || document.getElementById('renderer')
|
||||
if (params.showStats) {
|
||||
this.stats = Stats()
|
||||
this.container.appendChild(this.stats.dom)
|
||||
this.container.prepend(this.stats.dom)
|
||||
this.stats.dom.style.position = 'relative' // Mad CSS skills
|
||||
}
|
||||
this.loaders = {}
|
||||
this.startupParams = params
|
||||
@@ -97,8 +100,9 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
this.speckleRenderer.create(this.container)
|
||||
window.addEventListener('resize', this.resize.bind(this), false)
|
||||
|
||||
new Assets(this.speckleRenderer.renderer)
|
||||
this.filteringManager = new FilteringManager(this.speckleRenderer)
|
||||
new Assets()
|
||||
this.filteringManager = new FilteringManager(this.speckleRenderer, this.tree)
|
||||
this.propertyManager = new PropertyManager()
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
// ;(window as any)._V = this // For debugging! ಠ_ಠ
|
||||
@@ -183,7 +187,10 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
|
||||
public async init(): Promise<void> {
|
||||
if (this.startupParams.environmentSrc) {
|
||||
Assets.getEnvironment(this.startupParams.environmentSrc)
|
||||
Assets.getEnvironment(
|
||||
this.startupParams.environmentSrc,
|
||||
this.speckleRenderer.renderer
|
||||
)
|
||||
.then((value: Texture) => {
|
||||
this.speckleRenderer.indirectIBL = value
|
||||
})
|
||||
@@ -202,7 +209,7 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
resourceURL: string = null,
|
||||
bypassCache = true
|
||||
): PropertyInfo[] {
|
||||
return PropertyManager.getProperties(resourceURL, bypassCache)
|
||||
return this.propertyManager.getProperties(this.tree, resourceURL, bypassCache)
|
||||
}
|
||||
|
||||
public selectObjects(objectIds: string[]): Promise<FilteringState> {
|
||||
@@ -325,7 +332,11 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
}
|
||||
|
||||
public getDataTree(): DataTree {
|
||||
return WorldTree.getDataTree()
|
||||
return this.tree.getDataTree()
|
||||
}
|
||||
|
||||
public getWorldTree(): WorldTree {
|
||||
return this.tree
|
||||
}
|
||||
|
||||
public query<T extends Query>(query: T): QueryArgsResultMap[T['operation']] {
|
||||
@@ -378,7 +389,7 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
}
|
||||
|
||||
public getViews(): SpeckleView[] {
|
||||
return WorldTree.getInstance()
|
||||
return this.tree
|
||||
.findAll((node: TreeNode) => {
|
||||
return node.model.renderView?.speckleType === SpeckleType.View3D
|
||||
})
|
||||
@@ -442,7 +453,7 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
await this.downloadObject(url, token, enableCaching)
|
||||
|
||||
let t0 = performance.now()
|
||||
WorldTree.getRenderTree(url).buildRenderTree()
|
||||
this.tree.getRenderTree(url).buildRenderTree()
|
||||
Logger.log('SYNC Tree build time -> ', performance.now() - t0)
|
||||
|
||||
t0 = performance.now()
|
||||
@@ -465,7 +476,7 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
await this.downloadObject(url, token, enableCaching)
|
||||
|
||||
let t0 = performance.now()
|
||||
const treeBuilt = await WorldTree.getRenderTree(url).buildRenderTreeAsync(priority)
|
||||
const treeBuilt = await this.tree.getRenderTree(url).buildRenderTreeAsync(priority)
|
||||
Logger.log('ASYNC Tree build time -> ', performance.now() - t0)
|
||||
|
||||
if (treeBuilt) {
|
||||
@@ -481,7 +492,7 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
|
||||
public async cancelLoad(url: string, unload = false) {
|
||||
this.loaders[url].cancelLoad()
|
||||
WorldTree.getRenderTree(url).cancelBuild(url)
|
||||
this.tree.getRenderTree(url).cancelBuild(url)
|
||||
this.speckleRenderer.cancelRenderTree(url)
|
||||
if (unload) {
|
||||
await this.unloadObject(url)
|
||||
@@ -495,8 +506,8 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
(this as EventEmitter).emit(ViewerEvent.Busy, true)
|
||||
delete this.loaders[url]
|
||||
this.speckleRenderer.removeRenderTree(url)
|
||||
WorldTree.getRenderTree(url).purge()
|
||||
WorldTree.getInstance().purge(url)
|
||||
this.tree.getRenderTree(url).purge()
|
||||
this.tree.purge(url)
|
||||
} finally {
|
||||
if (--this.inProgressOperations === 0) {
|
||||
;(this as EventEmitter).emit(ViewerEvent.Busy, false)
|
||||
@@ -514,12 +525,12 @@ export class Viewer extends EventEmitter implements IViewer {
|
||||
delete this.loaders[key]
|
||||
}
|
||||
this.filteringManager.reset()
|
||||
WorldTree.getInstance().root.children.forEach((node) => {
|
||||
this.tree.root.children.forEach((node) => {
|
||||
this.speckleRenderer.removeRenderTree(node.model.id)
|
||||
WorldTree.getRenderTree().purge()
|
||||
this.tree.getRenderTree().purge()
|
||||
})
|
||||
|
||||
WorldTree.getInstance().purge()
|
||||
this.tree.purge()
|
||||
} finally {
|
||||
if (--this.inProgressOperations === 0) {
|
||||
;(this as EventEmitter).emit(ViewerEvent.Busy, false)
|
||||
|
||||
@@ -3,6 +3,7 @@ import { ViewerEvent } from '../IViewer'
|
||||
import Converter from './converter/Converter'
|
||||
import EventEmitter from './EventEmitter'
|
||||
import Logger from 'js-logger'
|
||||
import { Viewer } from './Viewer'
|
||||
/**
|
||||
* Helper wrapper around the ObjectLoader class, with some built in assumptions.
|
||||
*/
|
||||
@@ -22,8 +23,8 @@ export default class ViewerObjectLoader {
|
||||
return this._objectUrl
|
||||
}
|
||||
|
||||
constructor(parentEmitter: EventEmitter, objectUrl, authToken, enableCaching) {
|
||||
this.emiter = parentEmitter
|
||||
constructor(parent: Viewer, objectUrl, authToken, enableCaching) {
|
||||
this.emiter = parent
|
||||
this._objectUrl = objectUrl
|
||||
this.token = null
|
||||
try {
|
||||
@@ -64,7 +65,7 @@ export default class ViewerObjectLoader {
|
||||
options: { enableCaching, customLogger: (Logger as any).log }
|
||||
})
|
||||
|
||||
this.converter = new Converter(this.loader)
|
||||
this.converter = new Converter(this.loader, parent.getWorldTree())
|
||||
|
||||
this.cancel = false
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Material, Object3D, WebGLRenderer } from 'three'
|
||||
import { Box3, Material, Object3D, WebGLRenderer } from 'three'
|
||||
import { MaterialOptions } from '../materials/Materials'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
|
||||
@@ -17,6 +17,8 @@ export interface Batch {
|
||||
renderObject: Object3D
|
||||
geometryType: GeometryType
|
||||
|
||||
get bounds(): Box3
|
||||
|
||||
getCount(): number
|
||||
setBatchMaterial(material: Material): void
|
||||
setVisibleRange(...range: BatchUpdateRange[])
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { generateUUID } from 'three/src/math/MathUtils'
|
||||
import MeshBatch from './MeshBatch'
|
||||
import { SpeckleType } from '../converter/GeometryConverter'
|
||||
import { WorldTree } from '../tree/WorldTree'
|
||||
import LineBatch from './LineBatch'
|
||||
import Materials from '../materials/Materials'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
@@ -18,6 +17,7 @@ import { Material, Mesh, WebGLRenderer } from 'three'
|
||||
import { FilterMaterial, FilterMaterialType } from '../filtering/FilteringManager'
|
||||
import Logger from 'js-logger'
|
||||
import { World } from '../World'
|
||||
import { RenderTree } from '../tree/RenderTree'
|
||||
import SpeckleMesh from '../objects/SpeckleMesh'
|
||||
|
||||
export enum TransformStorage {
|
||||
@@ -44,17 +44,15 @@ export default class Batcher {
|
||||
}
|
||||
|
||||
public makeBatches(
|
||||
subtreeId: string,
|
||||
renderTree: RenderTree,
|
||||
speckleType: SpeckleType[],
|
||||
batchType?: GeometryType
|
||||
) {
|
||||
const renderViews = WorldTree.getRenderTree(subtreeId)
|
||||
.getAtomicRenderViews(...speckleType)
|
||||
.sort((a, b) => {
|
||||
if (a.renderMaterialHash === 0) return -1
|
||||
if (b.renderMaterialHash === 0) return 1
|
||||
return a.renderMaterialHash - b.renderMaterialHash
|
||||
})
|
||||
const renderViews = renderTree.getAtomicRenderViews(...speckleType).sort((a, b) => {
|
||||
if (a.renderMaterialHash === 0) return -1
|
||||
if (b.renderMaterialHash === 0) return 1
|
||||
return a.renderMaterialHash - b.renderMaterialHash
|
||||
})
|
||||
const materialHashes = [
|
||||
...Array.from(new Set(renderViews.map((value) => value.renderMaterialHash)))
|
||||
]
|
||||
@@ -78,7 +76,7 @@ export default class Batcher {
|
||||
for (let k = 0; k < batches.length; k++) {
|
||||
const restrictedRvs = batches[k]
|
||||
const batch = this.buildBatch(
|
||||
subtreeId,
|
||||
renderTree,
|
||||
restrictedRvs,
|
||||
materialHashes[i],
|
||||
batchType
|
||||
@@ -89,20 +87,18 @@ export default class Batcher {
|
||||
}
|
||||
|
||||
public async *makeBatchesAsync(
|
||||
subtreeId: string,
|
||||
renderTree: RenderTree,
|
||||
speckleType: SpeckleType[],
|
||||
batchType?: GeometryType,
|
||||
priority?: number
|
||||
) {
|
||||
const pause = World.getPause(priority)
|
||||
|
||||
const renderViews = WorldTree.getRenderTree(subtreeId)
|
||||
.getAtomicRenderViews(...speckleType)
|
||||
.sort((a, b) => {
|
||||
if (a.renderMaterialHash === 0) return -1
|
||||
if (b.renderMaterialHash === 0) return 1
|
||||
return a.renderMaterialHash - b.renderMaterialHash
|
||||
})
|
||||
const renderViews = renderTree.getAtomicRenderViews(...speckleType).sort((a, b) => {
|
||||
if (a.renderMaterialHash === 0) return -1
|
||||
if (b.renderMaterialHash === 0) return 1
|
||||
return a.renderMaterialHash - b.renderMaterialHash
|
||||
})
|
||||
const materialHashes = [
|
||||
...Array.from(new Set(renderViews.map((value) => value.renderMaterialHash)))
|
||||
]
|
||||
@@ -129,7 +125,7 @@ export default class Batcher {
|
||||
for (let k = 0; k < batches.length; k++) {
|
||||
const restrictedRvs = batches[k]
|
||||
const batch = this.buildBatch(
|
||||
subtreeId,
|
||||
renderTree,
|
||||
restrictedRvs,
|
||||
materialHashes[i],
|
||||
batchType
|
||||
@@ -203,13 +199,27 @@ export default class Batcher {
|
||||
}
|
||||
|
||||
private buildBatch(
|
||||
subtreeId: string,
|
||||
renderTree: RenderTree,
|
||||
renderViews: NodeRenderView[],
|
||||
materialHash: number,
|
||||
batchType?: GeometryType
|
||||
): Batch {
|
||||
const geometryType =
|
||||
batchType !== undefined ? batchType : renderViews[0].geometryType
|
||||
let batch = renderViews.filter((value) => value.renderMaterialHash === materialHash)
|
||||
/** Prune any meshes with no geometry data */
|
||||
batch = batch.filter((value) => value.validGeometry)
|
||||
|
||||
if (!batch.length) {
|
||||
/** This is for the case when all renderviews have invalid geometries, and it generally
|
||||
* means there is something wrong with the stream
|
||||
*/
|
||||
Logger.warn(
|
||||
'All renderviews have invalid geometries. Skipping batch!',
|
||||
renderViews
|
||||
)
|
||||
return null
|
||||
}
|
||||
|
||||
const geometryType = batchType !== undefined ? batchType : batch[0].geometryType
|
||||
let matRef = null
|
||||
|
||||
if (geometryType === GeometryType.MESH) {
|
||||
@@ -230,21 +240,21 @@ export default class Batcher {
|
||||
case GeometryType.MESH:
|
||||
geometryBatch = new MeshBatch(
|
||||
batchID,
|
||||
subtreeId,
|
||||
renderViews,
|
||||
renderTree.id,
|
||||
batch,
|
||||
this.floatTextures
|
||||
? TransformStorage.VERTEX_TEXTURE
|
||||
: TransformStorage.UNIFORM_ARRAY
|
||||
)
|
||||
break
|
||||
case GeometryType.LINE:
|
||||
geometryBatch = new LineBatch(batchID, subtreeId, renderViews)
|
||||
geometryBatch = new LineBatch(batchID, renderTree.id, batch)
|
||||
break
|
||||
case GeometryType.POINT:
|
||||
geometryBatch = new PointBatch(batchID, subtreeId, renderViews)
|
||||
geometryBatch = new PointBatch(batchID, renderTree.id, batch)
|
||||
break
|
||||
case GeometryType.POINT_CLOUD:
|
||||
geometryBatch = new PointBatch(batchID, subtreeId, renderViews)
|
||||
geometryBatch = new PointBatch(batchID, renderTree.id, batch)
|
||||
break
|
||||
}
|
||||
|
||||
@@ -469,56 +479,9 @@ export default class Batcher {
|
||||
/**
|
||||
* Used for debuggin only
|
||||
*/
|
||||
public isolateRenderView(id: string) {
|
||||
const rvs = WorldTree.getRenderTree().getRenderViewsForNodeId(id)
|
||||
const batchIds = [...Array.from(new Set(rvs.map((value) => value.batchId)))]
|
||||
for (const k in this.batches) {
|
||||
if (!batchIds.includes(k)) {
|
||||
this.batches[k].setDrawRanges({
|
||||
offset: 0,
|
||||
count: Infinity,
|
||||
material: this.materials.getFilterMaterial(
|
||||
this.batches[k].renderViews[0],
|
||||
FilterMaterialType.GHOST
|
||||
)
|
||||
})
|
||||
this.batches[k].setVisibleRange(HideAllBatchUpdateRange)
|
||||
} else {
|
||||
const drawRanges = []
|
||||
for (let i = 0; i < this.batches[k].renderViews.length; i++) {
|
||||
if (!rvs.includes(this.batches[k].renderViews[i])) {
|
||||
drawRanges.push({
|
||||
offset: this.batches[k].renderViews[i].batchStart,
|
||||
count: this.batches[k].renderViews[i].batchCount,
|
||||
material: this.materials.getFilterMaterial(
|
||||
this.batches[k].renderViews[i],
|
||||
FilterMaterialType.GHOST
|
||||
)
|
||||
})
|
||||
} else {
|
||||
drawRanges.push({
|
||||
offset: this.batches[k].renderViews[i].batchStart,
|
||||
count: this.batches[k].renderViews[i].batchCount,
|
||||
material: this.materials.getFilterMaterial(
|
||||
this.batches[k].renderViews[i],
|
||||
FilterMaterialType.SELECT
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
if (drawRanges.length > 0) {
|
||||
this.batches[k].setDrawRanges(...drawRanges)
|
||||
this.batches[k].autoFillDrawRanges()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Used for debuggin only
|
||||
*/
|
||||
public async isolateRenderViewBatch(id: string) {
|
||||
const rv = WorldTree.getRenderTree().getRenderViewForNodeId(id)
|
||||
public async isolateRenderViewBatch(id: string, renderTree: RenderTree) {
|
||||
const rv = renderTree.getRenderViewForNodeId(id)
|
||||
for (const k in this.batches) {
|
||||
if (k !== rv.batchId) {
|
||||
this.batches[k].setDrawRanges({
|
||||
|
||||
@@ -15,7 +15,6 @@ import { Geometry } from '../converter/Geometry'
|
||||
import SpeckleLineMaterial from '../materials/SpeckleLineMaterial'
|
||||
import { ObjectLayers } from '../SpeckleRenderer'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
import { Viewer } from '../Viewer'
|
||||
import {
|
||||
AllBatchUpdateRange,
|
||||
Batch,
|
||||
@@ -34,6 +33,11 @@ export default class LineBatch implements Batch {
|
||||
public colorBuffer: InstancedInterleavedBuffer
|
||||
private static readonly vector4Buffer: Vector4 = new Vector4()
|
||||
|
||||
public get bounds() {
|
||||
if (!this.geometry.boundingBox) this.geometry.computeBoundingBox()
|
||||
return this.geometry.boundingBox
|
||||
}
|
||||
|
||||
public constructor(id: string, subtreeId: string, renderViews: NodeRenderView[]) {
|
||||
this.id = id
|
||||
this.subtreeId = subtreeId
|
||||
@@ -221,7 +225,6 @@ export default class LineBatch implements Batch {
|
||||
private makeLineGeometry(position: Float64Array) {
|
||||
this.geometry = this.makeLineGeometryTriangle(new Float32Array(position))
|
||||
Geometry.updateRTEGeometry(this.geometry, position)
|
||||
Viewer.World.expandWorld(this.geometry.boundingBox)
|
||||
}
|
||||
|
||||
private makeLineGeometryTriangle(position: Float32Array): LineSegmentsGeometry {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import {
|
||||
Box3,
|
||||
BufferAttribute,
|
||||
BufferGeometry,
|
||||
DynamicDrawUsage,
|
||||
@@ -13,7 +14,6 @@ import { Geometry } from '../converter/Geometry'
|
||||
import SpeckleStandardColoredMaterial from '../materials/SpeckleStandardColoredMaterial'
|
||||
import SpeckleMesh from '../objects/SpeckleMesh'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
import { Viewer } from '../Viewer'
|
||||
import {
|
||||
AllBatchUpdateRange,
|
||||
Batch,
|
||||
@@ -41,6 +41,10 @@ export default class MeshBatch implements Batch {
|
||||
private indexBuffer1: BufferAttribute
|
||||
private indexBufferIndex = 0
|
||||
|
||||
public get bounds(): Box3 {
|
||||
return this.mesh.BVH.getBoundingBox(new Box3())
|
||||
}
|
||||
|
||||
public constructor(
|
||||
id: string,
|
||||
subtreeId: string,
|
||||
@@ -548,8 +552,6 @@ export default class MeshBatch implements Batch {
|
||||
this.geometry.computeBoundingSphere()
|
||||
this.geometry.computeBoundingBox()
|
||||
|
||||
Viewer.World.expandWorld(this.geometry.boundingBox)
|
||||
|
||||
Geometry.updateRTEGeometry(this.geometry, position)
|
||||
|
||||
return this.geometry
|
||||
|
||||
@@ -8,7 +8,6 @@ import {
|
||||
} from 'three'
|
||||
import { Geometry } from '../converter/Geometry'
|
||||
import { NodeRenderView } from '../tree/NodeRenderView'
|
||||
import { Viewer } from '../Viewer'
|
||||
import {
|
||||
AllBatchUpdateRange,
|
||||
Batch,
|
||||
@@ -28,6 +27,11 @@ export default class PointBatch implements Batch {
|
||||
public batchMaterial: Material
|
||||
public mesh: Points
|
||||
|
||||
public get bounds() {
|
||||
if (!this.geometry.boundingBox) this.geometry.computeBoundingBox()
|
||||
return this.geometry.boundingBox
|
||||
}
|
||||
|
||||
public constructor(id: string, subtreeId: string, renderViews: NodeRenderView[]) {
|
||||
this.id = id
|
||||
this.subtreeId = subtreeId
|
||||
@@ -321,7 +325,6 @@ export default class PointBatch implements Batch {
|
||||
this.geometry.computeBoundingSphere()
|
||||
this.geometry.computeBoundingBox()
|
||||
|
||||
Viewer.World.expandWorld(this.geometry.boundingBox)
|
||||
Geometry.updateRTEGeometry(this.geometry, position)
|
||||
|
||||
return this.geometry
|
||||
|
||||
@@ -16,7 +16,7 @@ export default class Coverter {
|
||||
private activePromises: number
|
||||
private maxChildrenPromises: number
|
||||
private spoofIDs = true
|
||||
private isRoot = true
|
||||
private tree: WorldTree
|
||||
|
||||
private readonly NodeConverterMapping: {
|
||||
[name: string]: ConverterNodeDelegate
|
||||
@@ -38,7 +38,7 @@ export default class Coverter {
|
||||
RevitInstance: this.RevitInstanceToNode.bind(this)
|
||||
}
|
||||
|
||||
constructor(objectLoader: unknown) {
|
||||
constructor(objectLoader: unknown, tree: WorldTree) {
|
||||
if (!objectLoader) {
|
||||
Logger.warn(
|
||||
'Converter initialized without a corresponding object loader. Any objects that include references will throw errors.'
|
||||
@@ -46,11 +46,10 @@ export default class Coverter {
|
||||
}
|
||||
|
||||
this.objectLoader = objectLoader
|
||||
|
||||
this.lastAsyncPause = Date.now()
|
||||
this.activePromises = 0
|
||||
this.maxChildrenPromises = 200
|
||||
WorldTree.getInstance()
|
||||
this.tree = tree
|
||||
}
|
||||
|
||||
public async asyncPause() {
|
||||
@@ -99,20 +98,18 @@ export default class Coverter {
|
||||
return
|
||||
}
|
||||
|
||||
const childNode: TreeNode = WorldTree.getInstance().parse({
|
||||
const childNode: TreeNode = this.tree.parse({
|
||||
id: !node ? objectURL : this.getNodeId(obj),
|
||||
raw: Object.assign({}, obj),
|
||||
atomic: true,
|
||||
root: this.isRoot,
|
||||
children: []
|
||||
})
|
||||
this.isRoot = false
|
||||
|
||||
if (node === null) {
|
||||
WorldTree.getInstance().addSubtree(childNode)
|
||||
this.tree.addSubtree(childNode)
|
||||
// console.warn(`Added root node with id ${obj.id}`)
|
||||
} else {
|
||||
WorldTree.getInstance().addNode(childNode, node)
|
||||
this.tree.addNode(childNode, node)
|
||||
// console.warn(`Added child node with id ${obj.id} to parent node ${node.model.id}`)
|
||||
}
|
||||
|
||||
@@ -148,14 +145,14 @@ export default class Coverter {
|
||||
displayValue = await this.resolveReference(displayValue)
|
||||
if (!displayValue.units) displayValue.units = obj.units
|
||||
try {
|
||||
const nestedNode: TreeNode = WorldTree.getInstance().parse({
|
||||
const nestedNode: TreeNode = this.tree.parse({
|
||||
id: this.getNodeId(displayValue),
|
||||
raw: Object.assign({}, displayValue),
|
||||
atomic: false,
|
||||
children: []
|
||||
})
|
||||
await this.convertToNode(displayValue, nestedNode)
|
||||
WorldTree.getInstance().addNode(nestedNode, childNode)
|
||||
this.tree.addNode(nestedNode, childNode)
|
||||
await callback({}) // use the parent's metadata!
|
||||
} catch (e) {
|
||||
Logger.warn(
|
||||
@@ -166,14 +163,14 @@ export default class Coverter {
|
||||
for (const element of displayValue) {
|
||||
const val = await this.resolveReference(element)
|
||||
if (!val.units) val.units = obj.units
|
||||
const nestedNode: TreeNode = WorldTree.getInstance().parse({
|
||||
const nestedNode: TreeNode = this.tree.parse({
|
||||
id: this.getNodeId(val),
|
||||
raw: Object.assign({}, val),
|
||||
atomic: false,
|
||||
children: []
|
||||
})
|
||||
await this.convertToNode(val, nestedNode)
|
||||
WorldTree.getInstance().addNode(nestedNode, childNode)
|
||||
this.tree.addNode(nestedNode, childNode)
|
||||
await callback({})
|
||||
}
|
||||
}
|
||||
@@ -309,13 +306,13 @@ export default class Coverter {
|
||||
node.model.raw.definition = definition
|
||||
for (const def of definition.geometry) {
|
||||
const ref = await this.resolveReference(def)
|
||||
const childNode: TreeNode = WorldTree.getInstance().parse({
|
||||
const childNode: TreeNode = this.tree.parse({
|
||||
id: this.getNodeId(ref),
|
||||
raw: Object.assign({}, ref),
|
||||
atomic: true,
|
||||
children: []
|
||||
})
|
||||
WorldTree.getInstance().addNode(childNode, node)
|
||||
this.tree.addNode(childNode, node)
|
||||
// console.warn(
|
||||
// `Added child node with id ${childNode.model.id} to parent node ${node.model.id}`
|
||||
// )
|
||||
@@ -329,7 +326,7 @@ export default class Coverter {
|
||||
if (!list) return
|
||||
for (const def of list) {
|
||||
const ref = await this.resolveReference(def)
|
||||
const childNode: TreeNode = WorldTree.getInstance().parse({
|
||||
const childNode: TreeNode = this.tree.parse({
|
||||
id: this.getNodeId(ref),
|
||||
raw: Object.assign({}, ref),
|
||||
atomic: true,
|
||||
@@ -338,7 +335,7 @@ export default class Coverter {
|
||||
if (hostId) {
|
||||
childNode.model.raw.host = hostId
|
||||
}
|
||||
WorldTree.getInstance().addNode(childNode, node)
|
||||
this.tree.addNode(childNode, node)
|
||||
await this.convertToNode(ref, childNode)
|
||||
}
|
||||
}
|
||||
@@ -362,14 +359,14 @@ export default class Coverter {
|
||||
let displayValue = obj.displayValue || obj.displayMesh
|
||||
if (Array.isArray(displayValue)) displayValue = displayValue[0] //Just take the first display value for now (not ideal)
|
||||
const ref = await this.resolveReference(displayValue)
|
||||
const nestedNode: TreeNode = WorldTree.getInstance().parse({
|
||||
const nestedNode: TreeNode = this.tree.parse({
|
||||
id: this.getNodeId(ref),
|
||||
raw: Object.assign({}, ref),
|
||||
atomic: false,
|
||||
children: []
|
||||
})
|
||||
await this.convertToNode(ref, nestedNode)
|
||||
WorldTree.getInstance().addNode(nestedNode, node)
|
||||
this.tree.addNode(nestedNode, node)
|
||||
|
||||
// deletes known unneeded fields
|
||||
delete obj.Edges
|
||||
@@ -433,7 +430,7 @@ export default class Coverter {
|
||||
element = await this.resolveReference(element)
|
||||
}
|
||||
}
|
||||
const nestedNode: TreeNode = WorldTree.getInstance().parse({
|
||||
const nestedNode: TreeNode = this.tree.parse({
|
||||
id: this.getNodeId(element),
|
||||
raw: Object.assign({}, element),
|
||||
atomic: false,
|
||||
@@ -442,7 +439,7 @@ export default class Coverter {
|
||||
await this.convertToNode(element, nestedNode)
|
||||
/** We're not adding the segments as children since they shouldn't exist as individual line elements */
|
||||
node.model.nestedNodes.push(nestedNode)
|
||||
// WorldTree.getInstance().addNode(nestedNode, node)
|
||||
// WorldTree.getInstance(this.treeInstaceId).addNode(nestedNode, node)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,14 +452,14 @@ export default class Coverter {
|
||||
}
|
||||
const displayValue = await this.resolveReference(obj.displayValue)
|
||||
displayValue.units = displayValue.units || obj.units
|
||||
const nestedNode: TreeNode = WorldTree.getInstance().parse({
|
||||
const nestedNode: TreeNode = this.tree.parse({
|
||||
id: this.getNodeId(displayValue),
|
||||
raw: Object.assign({}, displayValue),
|
||||
atomic: false,
|
||||
children: []
|
||||
})
|
||||
await this.convertToNode(displayValue, nestedNode)
|
||||
WorldTree.getInstance().addNode(nestedNode, node)
|
||||
this.tree.addNode(nestedNode, node)
|
||||
}
|
||||
|
||||
private async CircleToNode(obj, node) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
NumericPropertyInfo
|
||||
} from './PropertyManager'
|
||||
import SpeckleRenderer from '../SpeckleRenderer'
|
||||
import { RenderTree } from '../tree/RenderTree'
|
||||
|
||||
export type FilteringState = {
|
||||
selectedObjects?: string[]
|
||||
@@ -39,6 +40,7 @@ export interface FilterMaterial {
|
||||
|
||||
export class FilteringManager {
|
||||
public WTI: WorldTree
|
||||
public RTI: RenderTree
|
||||
private Renderer: SpeckleRenderer
|
||||
private StateKey: string = null
|
||||
|
||||
@@ -50,8 +52,9 @@ export class FilteringManager {
|
||||
private UserspaceColorState = new UserspaceColorState()
|
||||
private ColorStringFilterState2: ColorStringFilterState = null
|
||||
|
||||
public constructor(renderer: SpeckleRenderer) {
|
||||
this.WTI = WorldTree.getInstance()
|
||||
public constructor(renderer: SpeckleRenderer, tree: WorldTree) {
|
||||
this.WTI = tree
|
||||
this.RTI = tree.getRenderTree()
|
||||
this.Renderer = renderer
|
||||
}
|
||||
|
||||
@@ -173,16 +176,14 @@ export class FilteringManager {
|
||||
private visibilityWalk(node: TreeNode): boolean {
|
||||
if (!node.model.atomic) return true
|
||||
if (this.VisibilityState.ids.indexOf(node.model.raw.id) !== -1) {
|
||||
this.VisibilityState.rvs.push(
|
||||
...WorldTree.getRenderTree().getRenderViewsForNode(node, node)
|
||||
)
|
||||
this.VisibilityState.rvs.push(...this.RTI.getRenderViewsForNode(node, node))
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private isolationWalk(node: TreeNode): boolean {
|
||||
if (!node.model.atomic || node.model.id === 'MOTHERSHIP') return true
|
||||
const rvs = WorldTree.getRenderTree().getRenderViewsForNode(node, node)
|
||||
if (!node.model.atomic || this.WTI.isRoot(node)) return true
|
||||
const rvs = this.RTI.getRenderViewsForNode(node, node)
|
||||
if (this.VisibilityState.ids.indexOf(node.model.raw.id) === -1) {
|
||||
this.VisibilityState.rvs.push(...rvs)
|
||||
} else {
|
||||
@@ -223,10 +224,9 @@ export class FilteringManager {
|
||||
const nonMatchingRvs: NodeRenderView[] = []
|
||||
const colorGroups: ValueGroupColorItemNumericProps[] = []
|
||||
|
||||
WorldTree.getInstance().walk((node: TreeNode) => {
|
||||
if (!node.model.atomic || node.model.id === 'MOTHERSHIP' || node.model.root)
|
||||
return true
|
||||
const rvs = WorldTree.getRenderTree().getRenderViewsForNode(node, node)
|
||||
this.WTI.walk((node: TreeNode) => {
|
||||
if (!node.model.atomic || this.WTI.isRoot(node)) return true
|
||||
const rvs = this.RTI.getRenderViewsForNode(node, node)
|
||||
const idx = matchingIds.indexOf(node.model.raw.id)
|
||||
if (idx === -1) {
|
||||
nonMatchingRvs.push(...rvs)
|
||||
@@ -267,11 +267,11 @@ export class FilteringManager {
|
||||
// windows (family instances) inside walls get the same color as the walls, even though
|
||||
// they are identified as a different category.
|
||||
this.WTI.walk((node: TreeNode) => {
|
||||
if (!node.model.atomic || node.model.id === 'MOTHERSHIP') {
|
||||
if (!node.model.atomic || this.WTI.isRoot(node)) {
|
||||
return true
|
||||
}
|
||||
const vg = valueGroupColors.find((v) => v.ids.indexOf(node.model.raw.id) !== -1)
|
||||
const rvs = WorldTree.getRenderTree().getRenderViewsForNode(node, node)
|
||||
const rvs = this.RTI.getRenderViewsForNode(node, node)
|
||||
if (!vg) {
|
||||
nonMatchingRvs.push(...rvs)
|
||||
return true
|
||||
@@ -316,14 +316,14 @@ export class FilteringManager {
|
||||
return { ...g, nodes: [], rvs: [] }
|
||||
})
|
||||
|
||||
WorldTree.getInstance().walk((node: TreeNode) => {
|
||||
this.WTI.walk((node: TreeNode) => {
|
||||
if (!node.model?.raw?.id) return true
|
||||
for (const group of localGroups) {
|
||||
if (group.objectIds.includes(node.model.raw.id)) {
|
||||
group.nodes.push(node)
|
||||
const rvsNodes = WorldTree.getRenderTree()
|
||||
.getRenderViewNodesForNode(node, node)
|
||||
.map((rvNode) => rvNode.model.renderView)
|
||||
const rvsNodes = this.RTI.getRenderViewNodesForNode(node, node).map(
|
||||
(rvNode) => rvNode.model.renderView
|
||||
)
|
||||
if (rvsNodes) group.rvs.push(...rvsNodes)
|
||||
}
|
||||
}
|
||||
@@ -354,7 +354,7 @@ export class FilteringManager {
|
||||
const nodes = []
|
||||
if (ids.length !== 0) {
|
||||
/** This walk still takes longer than we'd like */
|
||||
WorldTree.getInstance().walk((node: TreeNode) => {
|
||||
this.WTI.walk((node: TreeNode) => {
|
||||
if (ids.indexOf(node.model.raw.id) !== -1) {
|
||||
nodes.push(node)
|
||||
}
|
||||
@@ -364,10 +364,7 @@ export class FilteringManager {
|
||||
/** There's also quite a lot of redundancy here as well. The nodes coming are
|
||||
* hierarchical and we end up getting the same render views more than once.
|
||||
*/
|
||||
const rvs = WorldTree.getRenderTree().getRenderViewNodesForNode(
|
||||
nodes[k],
|
||||
nodes[k]
|
||||
)
|
||||
const rvs = this.RTI.getRenderViewNodesForNode(nodes[k], nodes[k])
|
||||
if (rvs) {
|
||||
state.rvs.push(...rvs.map((e) => e.model.renderView))
|
||||
state.ids.push(...rvs.map((e) => e.model.raw.id))
|
||||
|
||||
@@ -2,9 +2,7 @@ import flatten from '../../helpers/flatten'
|
||||
import { TreeNode, WorldTree } from '../tree/WorldTree'
|
||||
|
||||
export class PropertyManager {
|
||||
private static WT: WorldTree = WorldTree.getInstance()
|
||||
|
||||
private static propCache = {} as Record<string, PropertyInfo[]>
|
||||
private propCache = {} as Record<string, PropertyInfo[]>
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -12,11 +10,12 @@ export class PropertyManager {
|
||||
* @param bypassCache Forces a full rescan if set to true.
|
||||
* @returns a list of property infos containing basic information for filtering purposes.
|
||||
*/
|
||||
public static getProperties(
|
||||
public getProperties(
|
||||
tree: WorldTree,
|
||||
resourceUrl: string = null,
|
||||
bypassCache = false
|
||||
): PropertyInfo[] {
|
||||
let rootNode: TreeNode = PropertyManager.WT.root
|
||||
let rootNode: TreeNode = tree.root
|
||||
|
||||
if (!bypassCache && this.propCache[resourceUrl ? resourceUrl : rootNode.model.id])
|
||||
return this.propCache[resourceUrl ? resourceUrl : rootNode.model.id]
|
||||
@@ -31,7 +30,7 @@ export class PropertyManager {
|
||||
|
||||
const propValues = {}
|
||||
|
||||
PropertyManager.WT.walk((node: TreeNode) => {
|
||||
tree.walk((node: TreeNode) => {
|
||||
if (!node.model.atomic) return true
|
||||
const obj = flatten(node.model.raw)
|
||||
for (const key in obj) {
|
||||
|
||||
@@ -16,7 +16,7 @@ class DataTreeInternal implements DataTree {
|
||||
|
||||
public constructor() {
|
||||
this.tree = new TreeModel()
|
||||
this.root = this.tree.parse({ guid: 'MOTHERSHIP' })
|
||||
this.root = this.tree.parse({ guid: WorldTree.ROOT_ID })
|
||||
}
|
||||
public findAll(predicate: ObjectPredicate): SpeckleObject[] {
|
||||
return this.root
|
||||
@@ -43,10 +43,10 @@ class DataTreeInternal implements DataTree {
|
||||
}
|
||||
|
||||
export class DataTreeBuilder {
|
||||
public static build(root: TreeNode): DataTree {
|
||||
public static build(tree: WorldTree): DataTree {
|
||||
const dataTree = new DataTreeInternal()
|
||||
let parent = null
|
||||
WorldTree.getInstance().walk((node: TreeNode) => {
|
||||
tree.root.walk((node: TreeNode) => {
|
||||
if (!node.parent) {
|
||||
parent = dataTree.root
|
||||
return true
|
||||
@@ -56,7 +56,7 @@ export class DataTreeBuilder {
|
||||
return localNode.model.guid === node.parent.model.id
|
||||
})
|
||||
|
||||
const _node: TreeNode = WorldTree.getInstance().parse({
|
||||
const _node: TreeNode = tree.parse({
|
||||
guid: node.model.id,
|
||||
data: node.model.raw,
|
||||
atomic: node.model.atomic,
|
||||
@@ -65,7 +65,7 @@ export class DataTreeBuilder {
|
||||
parent.addChild(_node)
|
||||
|
||||
return true
|
||||
}, root)
|
||||
}, tree.root)
|
||||
return dataTree as DataTree
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import { Geometry } from '../converter/Geometry'
|
||||
import Logger from 'js-logger'
|
||||
|
||||
export class RenderTree {
|
||||
private tree: WorldTree
|
||||
private root: TreeNode
|
||||
private _treeBounds: Box3 = new Box3()
|
||||
private cancel = false
|
||||
@@ -15,12 +16,17 @@ export class RenderTree {
|
||||
return this._treeBounds
|
||||
}
|
||||
|
||||
public constructor(root: TreeNode) {
|
||||
this.root = root
|
||||
public get id(): string {
|
||||
return this.root.model.id
|
||||
}
|
||||
|
||||
public constructor(tree: WorldTree, subtreeRoot: TreeNode) {
|
||||
this.tree = tree
|
||||
this.root = subtreeRoot
|
||||
}
|
||||
|
||||
public buildRenderTree() {
|
||||
this.root.walk((node: TreeNode): boolean => {
|
||||
this.tree.walk((node: TreeNode): boolean => {
|
||||
const rendeNode = this.buildRenderNode(node)
|
||||
node.model.renderView = rendeNode ? new NodeRenderView(rendeNode) : null
|
||||
if (node.model.renderView && node.model.renderView.hasGeometry) {
|
||||
@@ -42,7 +48,7 @@ export class RenderTree {
|
||||
}
|
||||
|
||||
public buildRenderTreeAsync(priority: number): Promise<boolean> {
|
||||
const p = WorldTree.getInstance().walkAsync(
|
||||
const p = this.tree.walkAsync(
|
||||
(node: TreeNode): boolean => {
|
||||
const rendeNode = this.buildRenderNode(node)
|
||||
node.model.renderView = rendeNode ? new NodeRenderView(rendeNode) : null
|
||||
@@ -93,7 +99,7 @@ export class RenderTree {
|
||||
if (node.model.raw.renderMaterial) {
|
||||
return node
|
||||
}
|
||||
const ancestors = WorldTree.getInstance().getAncestors(node)
|
||||
const ancestors = this.tree.getAncestors(node)
|
||||
for (let k = 0; k < ancestors.length; k++) {
|
||||
if (ancestors[k].model.raw.renderMaterial) {
|
||||
return ancestors[k]
|
||||
@@ -105,7 +111,7 @@ export class RenderTree {
|
||||
if (node.model.raw.displayStyle) {
|
||||
return node
|
||||
}
|
||||
const ancestors = WorldTree.getInstance().getAncestors(node)
|
||||
const ancestors = this.tree.getAncestors(node)
|
||||
for (let k = 0; k < ancestors.length; k++) {
|
||||
if (ancestors[k].model.raw.displayStyle) {
|
||||
return ancestors[k]
|
||||
@@ -115,7 +121,7 @@ export class RenderTree {
|
||||
|
||||
public computeTransform(node: TreeNode): Matrix4 {
|
||||
const transform = new Matrix4()
|
||||
const ancestors = WorldTree.getInstance().getAncestors(node)
|
||||
const ancestors = this.tree.getAncestors(node)
|
||||
for (let k = 0; k < ancestors.length; k++) {
|
||||
if (ancestors[k].model.renderView) {
|
||||
const renderNode: NodeRenderData = ancestors[k].model.renderView.renderData
|
||||
@@ -177,13 +183,11 @@ export class RenderTree {
|
||||
if (node.model.atomic) {
|
||||
return node.model.renderView
|
||||
}
|
||||
return WorldTree.getInstance()
|
||||
.getAncestors(node)
|
||||
.find((node) => node.model.atomic)
|
||||
return this.tree.getAncestors(node).find((node) => node.model.atomic)
|
||||
}
|
||||
|
||||
public getRenderViewsForNodeId(id: string): NodeRenderView[] {
|
||||
const node = WorldTree.getInstance().findId(id)
|
||||
const node = this.tree.findId(id)
|
||||
if (!node) {
|
||||
Logger.warn(`Id ${id} does not exist`)
|
||||
return null
|
||||
@@ -192,7 +196,7 @@ export class RenderTree {
|
||||
}
|
||||
|
||||
public getRenderViewForNodeId(id: string): NodeRenderView {
|
||||
const node = WorldTree.getInstance().findId(id)
|
||||
const node = this.tree.findId(id)
|
||||
if (!node) {
|
||||
Logger.warn(`Id ${id} does not exist`)
|
||||
return null
|
||||
@@ -201,12 +205,12 @@ export class RenderTree {
|
||||
}
|
||||
|
||||
public purge() {
|
||||
this.root = null
|
||||
this.tree = null
|
||||
}
|
||||
|
||||
public cancelBuild(id: string) {
|
||||
public cancelBuild(subtreeId: string) {
|
||||
this.cancel = true
|
||||
WorldTree.getInstance().purge(id)
|
||||
this.tree.purge(subtreeId)
|
||||
this.purge()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,56 +15,42 @@ export interface NodeData {
|
||||
children: TreeNode[]
|
||||
nestedNodes: TreeNode[]
|
||||
atomic: boolean
|
||||
/**
|
||||
* Keeps track wether this the root commit object or not.
|
||||
* TODO: Ask Alex wether this is somehow avoidable.
|
||||
*/
|
||||
root: boolean
|
||||
renderView?: NodeRenderView
|
||||
}
|
||||
|
||||
export class WorldTree {
|
||||
private static instance: WorldTree
|
||||
private static renderTreeInstances: { [id: string]: RenderTree } = {}
|
||||
private renderTreeInstances: { [id: string]: RenderTree } = {}
|
||||
private readonly supressWarnings = true
|
||||
public static readonly ROOT_ID = 'ROOT'
|
||||
|
||||
private constructor() {
|
||||
public constructor() {
|
||||
this.tree = new TreeModel()
|
||||
this._root = this.parse({
|
||||
id: WorldTree.ROOT_ID,
|
||||
raw: {},
|
||||
atomic: true,
|
||||
children: [],
|
||||
renderView: null
|
||||
})
|
||||
}
|
||||
|
||||
public static getInstance(): WorldTree {
|
||||
if (!WorldTree.instance) {
|
||||
WorldTree.instance = new WorldTree()
|
||||
WorldTree.instance._root = WorldTree.getInstance().parse({
|
||||
id: 'MOTHERSHIP',
|
||||
raw: {},
|
||||
atomic: true,
|
||||
children: [],
|
||||
renderView: null
|
||||
})
|
||||
}
|
||||
|
||||
return WorldTree.instance
|
||||
}
|
||||
|
||||
public static getRenderTree(subtreeId?: string): RenderTree {
|
||||
if (!WorldTree.getInstance()._root) {
|
||||
public getRenderTree(subtreeId?: string): RenderTree {
|
||||
if (!this._root) {
|
||||
console.error(`WorldTree not initialised`)
|
||||
return null
|
||||
}
|
||||
|
||||
const id = subtreeId ? subtreeId : WorldTree.getInstance().root.model.id
|
||||
if (!WorldTree.renderTreeInstances[id]) {
|
||||
WorldTree.renderTreeInstances[id] = new RenderTree(
|
||||
WorldTree.getInstance().findId(id)
|
||||
)
|
||||
const id = subtreeId ? subtreeId : this.root.model.id
|
||||
|
||||
if (!this.renderTreeInstances[id]) {
|
||||
this.renderTreeInstances[id] = new RenderTree(this, this.findId(id))
|
||||
}
|
||||
|
||||
return WorldTree.renderTreeInstances[id]
|
||||
return this.renderTreeInstances[id]
|
||||
}
|
||||
|
||||
public static getDataTree(): DataTree {
|
||||
return DataTreeBuilder.build(WorldTree.instance._root)
|
||||
public getDataTree(): DataTree {
|
||||
return DataTreeBuilder.build(this)
|
||||
}
|
||||
|
||||
private tree: TreeModel
|
||||
@@ -74,6 +60,10 @@ export class WorldTree {
|
||||
return this._root
|
||||
}
|
||||
|
||||
public isRoot(node: TreeNode) {
|
||||
return node === this._root
|
||||
}
|
||||
|
||||
public parse(model) {
|
||||
return this.tree.parse(model)
|
||||
}
|
||||
@@ -155,19 +145,19 @@ export class WorldTree {
|
||||
|
||||
public purge(subtreeId?: string) {
|
||||
if (subtreeId) {
|
||||
delete WorldTree.renderTreeInstances[subtreeId]
|
||||
delete this.renderTreeInstances[subtreeId]
|
||||
this.removeNode(this.findId(subtreeId))
|
||||
return
|
||||
}
|
||||
|
||||
Object.keys(WorldTree.renderTreeInstances).forEach(
|
||||
(key) => delete WorldTree.renderTreeInstances[key]
|
||||
Object.keys(this.renderTreeInstances).forEach(
|
||||
(key) => delete this.renderTreeInstances[key]
|
||||
)
|
||||
this._root.drop()
|
||||
this._root.children.length = 0
|
||||
this.tree = new TreeModel()
|
||||
this._root = WorldTree.getInstance().parse({
|
||||
id: 'MOTHERSHIP',
|
||||
this._root = this.tree.parse({
|
||||
id: WorldTree.ROOT_ID,
|
||||
raw: {},
|
||||
atomic: true,
|
||||
children: []
|
||||
|
||||
Reference in New Issue
Block a user