First draft of DUI3 instancing

This commit is contained in:
AlexandruPopovici 2024-07-17 17:13:55 +03:00
Родитель bf7eafeceb
Коммит 18ab05b140
7 изменённых файлов: 129 добавлений и 4 удалений

Просмотреть файл

@ -391,7 +391,12 @@ const getStream = () => {
// Rhino sRGB vertex colors
// 'https://app.speckle.systems/projects/47bbaf594f/models/ef78e94f72'
// qGIS sRGB vertex colors
'https://latest.speckle.systems/projects/5a6609a4b9/models/10f4931e8c'
// 'https://latest.speckle.systems/projects/5a6609a4b9/models/10f4931e8c'
// DUI3 blocks
// 'https://latest.speckle.systems/projects/126cd4b7bb/models/c6f3f309a2'
'https://latest.speckle.systems/projects/126cd4b7bb/models/6b62c61a22'
// 'https://latest.speckle.systems/projects/126cd4b7bb/models/0a6a715a0a'
// 'https://latest.speckle.systems/projects/126cd4b7bb/models/4dc5265453'
)
}

Просмотреть файл

@ -25,6 +25,7 @@ export type SpeckleObject = {
name?: string
referencedId?: string
units?: string
applicationId?: string
}
export interface ViewerParams {

Просмотреть файл

@ -19,6 +19,7 @@ export enum SpeckleType {
RevitInstance = 'RevitInstance',
Text = 'Text',
Transform = 'Transform',
InstanceProxy = 'InstanceProxy',
Unknown = 'Unknown'
}

Просмотреть файл

@ -1,8 +1,8 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { MathUtils } from 'three'
import { MathUtils, Matrix4 } from 'three'
import { type TreeNode, WorldTree } from '../../tree/WorldTree.js'
import { NodeMap } from '../../tree/NodeMap.js'
import type { SpeckleObject } from '../../../index.js'
import { SpeckleType, type SpeckleObject } from '../../../index.js'
import type ObjectLoader from '@speckle/objectloader'
import Logger from '../../utils/Logger.js'
@ -22,6 +22,8 @@ export default class SpeckleConverter {
private spoofIDs = false
private tree: WorldTree
private typeLookupTable: { [type: string]: string } = {}
private instanceDefinitionLookupTable: { [id: string]: TreeNode } = {}
private instancedObjectsLookupTable: { [id: string]: SpeckleObject } = {}
private instanceCounter = 0
private readonly NodeConverterMapping: {
@ -44,6 +46,8 @@ export default class SpeckleConverter {
RevitInstance: this.RevitInstanceToNode.bind(this),
Text: this.TextToNode.bind(this),
Dimension: this.DimensionToNode.bind(this),
InstanceDefinitionProxy: this.InstanceDefinitionProxyToNode.bind(this),
InstanceProxy: this.InstanceProxyToNode.bind(this),
Parameter: null
}
@ -521,6 +525,105 @@ export default class SpeckleConverter {
}
}
private async InstanceDefinitionProxyToNode(obj: SpeckleObject, node: TreeNode) {
if (!obj.applicationId) {
Logger.warn(`Instance Definition Proxy ${obj.id} has no applicationId`)
return
}
this.instanceDefinitionLookupTable[obj.applicationId] = node
}
private getInstanceProxyDefinitionId(obj: SpeckleObject): string {
return (obj.DefinitionId || obj.definitionId) as string
}
private getInstanceProxyTransform(obj: SpeckleObject): Array<number> {
if (!(obj.transform || obj.Transform)) {
return new Matrix4().toArray()
}
return (obj.transform || obj.Transform) as Array<number>
}
private createTransformNode(obj: SpeckleObject) {
const transformNodeId = MathUtils.generateUUID()
const transformData = this.getEmptyTransformData(transformNodeId)
transformData.units = obj.units as string
transformData.matrix = this.getInstanceProxyTransform(obj)
return this.tree.parse({
id: transformNodeId,
raw: transformData,
atomic: false,
children: []
})
}
private async InstanceProxyToNode(obj: SpeckleObject, node: TreeNode) {
return
}
private async ConvertInstanceProxyToNode(obj: SpeckleObject, node: TreeNode) {
const definitionId = this.getInstanceProxyDefinitionId(obj)
if (!definitionId) {
Logger.warn(`Instance Proxy ${obj.id} has no definitionId`)
return
}
const definition = this.instanceDefinitionLookupTable[definitionId]
const transformNode = this.createTransformNode(obj)
this.tree.addNode(transformNode, node)
const objectApplicationIds = definition.model.raw.Objects
for (const objectApplicationId of objectApplicationIds) {
const speckleData = this.instancedObjectsLookupTable[objectApplicationId]
const instancedNode = this.tree.parse({
id: this.getCompoundId(speckleData.id, this.instanceCounter++),
raw: speckleData,
atomic: false,
children: [],
instanced: true
})
this.tree.addNode(instancedNode, transformNode)
await this.convertToNode(speckleData, instancedNode)
}
}
public async convertInstances() {
// uh, oh
this.NodeConverterMapping.InstanceProxy = this.ConvertInstanceProxyToNode.bind(this)
for (const k in this.instanceDefinitionLookupTable) {
const definition = this.instanceDefinitionLookupTable[k]
const objectApplicationIds = definition.model.raw.Objects
for (const objectApplicationId of objectApplicationIds) {
const objectNodes = this.tree.findAll((node: TreeNode) => {
// String vs int
return (
node.model.raw.applicationId === Number.parseInt(objectApplicationId) ||
node.model.raw.applicationId === objectApplicationId
)
})
const objectNode = objectNodes[0]
this.instancedObjectsLookupTable[objectApplicationId] = objectNode.model.raw
this.tree.removeNode(objectNode, true)
}
}
const plm: TreeNode[] = []
await this.tree.walkAsync((node: TreeNode) => {
const type = this.getSpeckleType(node.model.raw)
if (type !== SpeckleType.InstanceProxy) {
return true
}
plm.push(node)
return true
})
for (let i = 0; i < plm.length; i++) {
await this.convertToNode(plm[i].model.raw, plm[i])
}
// for (let k = 0; k < this.instanceProxies.length; k++) {
// const node = this.instanceProxies[k]
// await this.convertToNode(node.model.raw, node)
// }
}
private async PointcloudToNode(obj: SpeckleObject, node: TreeNode) {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore

Просмотреть файл

@ -70,6 +70,8 @@ export class SpeckleGeometryConverter extends GeometryConverter {
return this.TextToGeometryData(node)
case SpeckleType.Transform:
return this.TransformToGeometryData(node)
case SpeckleType.InstanceProxy:
return this.InstanceProxyToGeometyData(node)
case SpeckleType.Unknown:
// console.warn(`Skipping geometry conversion for ${type}`)
return null
@ -176,6 +178,11 @@ export class SpeckleGeometryConverter extends GeometryConverter {
return null
}
private InstanceProxyToGeometyData(node: NodeData): GeometryData | null {
node
return null
}
/**
* POINT CLOUD
*/

Просмотреть файл

@ -128,6 +128,8 @@ export class SpeckleLoader extends Loader {
return Promise.resolve(false)
}
await this.converter.convertInstances()
const t0 = performance.now()
const geometryConverter = new SpeckleGeometryConverter()

Просмотреть файл

@ -108,8 +108,14 @@ export class WorldTree {
if (this.nodeMaps[parent.model.subtreeId]?.addNode(node)) parent.addChild(node)
}
public removeNode(node: TreeNode): void {
public removeNode(node: TreeNode, removeChildren: boolean): void {
const children = node.children
this.nodeMaps[node.model.subtreeId]?.removeNode(node)
node.drop()
if (!removeChildren || !children) return
for (let k = 0; k < children.length; k++) {
this.removeNode(children[k], removeChildren)
}
}
public findAll(predicate: SearchPredicate, node?: TreeNode): Array<TreeNode> {