#827. Generalizes all gradient based filtering. We can now filter by any property which is numerical from the sandbox. Implemented ramp texture generation. We will need this to generate the ramp texture for discreet colored filters like filterByType, filterByFamily ,etc

This commit is contained in:
AlexandruPopovici
2022-07-22 01:03:01 +03:00
parent c238cdaa07
commit 92009018fc
5 changed files with 115 additions and 70 deletions
+51 -57
View File
@@ -3,6 +3,7 @@ import { GeometryConverter } from '@speckle/viewer'
import { Viewer, IViewer, WorldTree } from '@speckle/viewer'
import SpeckleLineMaterial from '@speckle/viewer/dist/modules/materials/SpeckleLineMaterial'
import { Object3D } from '@speckle/viewer/node_modules/@types/three'
import { Pane } from 'tweakpane'
import UrlHelper from './UrlHelper'
export default class Sandbox {
private viewer: IViewer
@@ -29,9 +30,10 @@ export default class Sandbox {
}
public static filterParams = {
volumeData: {},
minVolume: 0,
maxVolume: 10000
filterBy: 'Volume',
data: {},
minValue: 0,
maxValue: 10000
}
public constructor(viewer: Viewer) {
@@ -233,68 +235,60 @@ export default class Sandbox {
title: 'Filtering',
expanded: true
})
// filteringFolder
// .addButton({
// title: 'Select Random'
// })
// .on('click', () => {
// this.viewer.speckleRenderer.clearFilter()
// this.viewer.speckleRenderer.beginFilter()
// this.viewer.speckleRenderer.applyFilter(
// this.getRandomNodeIds(0.25),
// FilterMaterial.GRADIENT
// )
// this.viewer.speckleRenderer.endFilter()
// })
filteringFolder.addInput(Sandbox.filterParams, 'filterBy', {
options: {
Volume: 'Volume',
Area: 'Area',
SpeckleType: 'speckle_type'
}
})
filteringFolder
.addButton({
title: 'Filter By Volume'
title: 'Apply Filter'
})
.on('click', () => {
Sandbox.filterParams.volumeData = this.viewer.debugGetVolumeNodes()
Sandbox.filterParams.minVolume = Sandbox.filterParams.volumeData.min
Sandbox.filterParams.maxVolume = Sandbox.filterParams.volumeData.max
Sandbox.filterParams.data = this.viewer.debugGetFilterByPropetyNodes(
Sandbox.filterParams.filterBy
)
Sandbox.filterParams.minValue = Sandbox.filterParams.data.min
Sandbox.filterParams.maxValue = Sandbox.filterParams.data.max
this.viewer.debugApplyVolumeFilter(Sandbox.filterParams.volumeData)
this.minVolumeControl.controller_.valueController.value.constraint_.constraints[0].minValue =
Sandbox.filterParams.minVolume
this.minVolumeControl.controller_.valueController.value.constraint_.constraints[0].maxValue =
Sandbox.filterParams.maxVolume
this.maxVolumeControl.controller_.valueController.value.constraint_.constraints[0].minValue =
Sandbox.filterParams.minVolume
this.maxVolumeControl.controller_.valueController.value.constraint_.constraints[0].maxValue =
Sandbox.filterParams.maxVolume
this.maxVolumeControl.disabled = false
this.minVolumeControl.disabled = false
this.viewer.debugApplyByPropetyFilter(
Sandbox.filterParams.data,
Sandbox.filterParams.filterBy
)
if (this.maxVolumeControl) this.maxVolumeControl.dispose()
if (this.minVolumeControl) this.minVolumeControl.dispose()
this.minVolumeControl = filteringFolder
.addInput(Sandbox.filterParams, 'minValue', {
min: Sandbox.filterParams.minValue,
max: Sandbox.filterParams.maxValue
})
.on('change', () => {
this.viewer.debugApplyByPropetyFilter(
Sandbox.filterParams.data,
Sandbox.filterParams.filterBy,
Sandbox.filterParams.minValue,
Sandbox.filterParams.maxValue
)
})
this.maxVolumeControl = filteringFolder
.addInput(Sandbox.filterParams, 'maxValue', {
min: Sandbox.filterParams.minValue,
max: Sandbox.filterParams.maxValue
})
.on('change', () => {
this.viewer.debugApplyByPropetyFilter(
Sandbox.filterParams.data,
Sandbox.filterParams.filterBy,
Sandbox.filterParams.minValue,
Sandbox.filterParams.maxValue
)
})
this.pane.refresh()
})
this.minVolumeControl = filteringFolder
.addInput(Sandbox.filterParams, 'minVolume', {
min: 0,
max: 100,
disabled: true
})
.on('change', () => {
this.viewer.debugApplyVolumeFilter(
Sandbox.filterParams.volumeData,
Sandbox.filterParams.minVolume,
Sandbox.filterParams.maxVolume
)
})
this.maxVolumeControl = filteringFolder
.addInput(Sandbox.filterParams, 'maxVolume', {
min: 0,
max: 100,
disabled: true
})
.on('change', () => {
this.viewer.debugApplyVolumeFilter(
Sandbox.filterParams.volumeData,
Sandbox.filterParams.minVolume,
Sandbox.filterParams.maxVolume
)
})
}
public async loadUrl(url: string) {
+41 -1
View File
@@ -1,4 +1,11 @@
import { Texture, PMREMGenerator, WebGLRenderer, TextureLoader } from 'three'
import {
Texture,
PMREMGenerator,
WebGLRenderer,
TextureLoader,
Color,
DataTexture
} from 'three'
import { EXRLoader } from 'three/examples/jsm/loaders/EXRLoader.js'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'
import { Asset, AssetType } from '../IViewer'
@@ -96,4 +103,37 @@ export class Assets {
}
})
}
public static generateGradientRampTexture(
fromColor: string,
toColor: string,
steps: number
) {
fromColor
toColor
steps
// NOT NECESSARY AT THE MOMENT. USING STATIC GRADIENT RAMP
}
public static generateDiscreetRampTexture(hexColors: string[]): Texture {
const width = hexColors.length
const height = 1
const size = width * height
const data = new Uint8Array(4 * size)
for (let k = 0; k < hexColors.length; k++) {
const stride = k * 4
const color = new Color(hexColors[k])
color.convertSRGBToLinear()
data[stride] = Math.floor(color.r * 255)
data[stride + 1] = Math.floor(color.g * 255)
data[stride + 2] = Math.floor(color.b * 255)
data[stride + 3] = 255
}
const texture = new DataTexture(data, width, height)
texture.needsUpdate = true
return texture
}
}
@@ -1,11 +1,16 @@
import { Texture } from 'three'
export enum FilterMaterialType {
SELECT,
GHOST,
GRADIENT
GRADIENT,
COLORED
}
export interface FilterMaterial {
filterType: FilterMaterialType
gradientIndex?: number
rampIndex?: number
rampTexture?: Texture
}
export class FilteringManager {
+14 -8
View File
@@ -322,7 +322,11 @@ export class Viewer extends EventEmitter implements IViewer {
}
}
public debugGetVolumeNodes(): { min: number; max: number; nodes: TreeNode[] } {
public debugGetFilterByPropetyNodes(propertyName: string): {
min: number
max: number
nodes: TreeNode[]
} {
const volumeNodes = []
let minVolume = Infinity
let maxVolume = 0
@@ -331,7 +335,7 @@ export class Viewer extends EventEmitter implements IViewer {
if (params) {
for (const k in params) {
if (!(params[k] instanceof Object)) continue
if (params[k].name === 'Volume') {
if (params[k].name === propertyName) {
minVolume = Math.min(minVolume, params[k].value)
maxVolume = Math.max(maxVolume, params[k].value)
volumeNodes.push(node)
@@ -348,21 +352,23 @@ export class Viewer extends EventEmitter implements IViewer {
}
}
public debugApplyVolumeFilter(
public debugApplyByPropetyFilter(
data: { min: number; max: number; nodes: TreeNode[] },
propertyName: string,
min?: number,
max?: number
) {
const nodesGradient = []
const nodesGhost = []
const volumeValues = []
const values = []
/** This is the lazy approach */
WorldTree.getInstance().walk((node: TreeNode) => {
const params = node.model.raw.parameters
if (params) {
for (const k in params) {
if (!(params[k] instanceof Object)) continue
if (params[k].name === 'Volume') {
if (params[k].name === propertyName) {
const volumeValue = params[k].value
const pasMin = min !== undefined ? volumeValue >= min : true
const pasMax = max !== undefined ? volumeValue <= max : true
@@ -373,7 +379,7 @@ export class Viewer extends EventEmitter implements IViewer {
!nodesGradient.includes(node)
) {
nodesGradient.push(node)
volumeValues.push(volumeValue)
values.push(volumeValue)
}
} else {
if (!nodesGhost.includes(node)) nodesGhost.push(node)
@@ -397,10 +403,10 @@ export class Viewer extends EventEmitter implements IViewer {
const ids = WorldTree.getRenderTree()
.getRenderViewsForNode(nodesGradient[k], nodesGradient[k])
.map((value) => value.renderData.id)
const t = (volumeValues[k] - data.min) / (data.max - data.min)
const t = (values[k] - data.min) / (data.max - data.min)
this.speckleRenderer.applyFilter(ids, {
filterType: FilterMaterialType.GRADIENT,
gradientIndex: t
rampIndex: t
})
}
@@ -385,9 +385,9 @@ export default class Materials {
}
public getFilterMaterialOptions(filterMaterial: FilterMaterial) {
return filterMaterial.gradientIndex
return filterMaterial.rampIndex
? {
gradientIndex: filterMaterial.gradientIndex
gradientIndex: filterMaterial.rampIndex
}
: null
}