From d27a53dcd033466fa437cc8c6f8202ce0ca183e1 Mon Sep 17 00:00:00 2001 From: Margriet Groenendijk Date: Fri, 8 Jul 2022 12:34:58 +0100 Subject: [PATCH 1/3] refactor of data loading --- src/data.ts | 179 +++++++++++++++++++++++++++++++++++++++++++++++ src/widget.ts | 189 ++++---------------------------------------------- 2 files changed, 194 insertions(+), 174 deletions(-) create mode 100644 src/data.ts diff --git a/src/data.ts b/src/data.ts new file mode 100644 index 0000000..5f4ee14 --- /dev/null +++ b/src/data.ts @@ -0,0 +1,179 @@ +// Copyright 2022 TileDB Inc. +// Licensed under the MIT License. + +import Client from '@tiledb-inc/tiledb-cloud'; +import { Layout } from '@tiledb-inc/tiledb-cloud/lib/v1'; + +export function setPointCloudSwitches(mode: string){ + var isTime = false; + var isClass = false; + var isTopo = false; + var isGltf = false; + + if (mode === "time"){ + isTime = true; + }else if (mode === "classes") { + isClass = true; + }else if(mode == "topo"){ + isTopo = true; + }else if(mode == "gltf"){ + isGltf = true; + } + return {isTime, isClass, isTopo, isGltf} + } + +export async function getPointCloud(values: any){ + + var dataIn: any + var data: any + + if (values.source === "cloud"){ + var dataUnsorted = await loadPointCloud(values).then((results) => {return results}); + if (values.mode === "time"){ + dataIn = sortDataArrays(dataUnsorted); + }else{ + dataIn = dataUnsorted; + } + }else{ + dataIn = values.data; + } + + if (values.show_fraction){ + data = reduceDataArrays(dataIn, values.show_fraction); + }else{ + data = dataIn; + } + return data; + } + +export function getPointCloudLimits(values: any, data: any){ + + var xmin: number; + var xmax: number; + var ymin: number; + var ymax: number; + var rgbMax: number; + + if (values.bbox) { + xmin = values.bbox.X[0]; + xmax = values.bbox.X[1]; + ymin = values.bbox.Y[0]; + ymax = values.bbox.Y[1]; + } + else { + xmin = data.X.reduce((accum: number, currentNumber: number) => Math.min(accum, currentNumber)); + xmax = data.X.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); + ymin = data.Y.reduce((accum: number, currentNumber: number) => Math.min(accum, currentNumber)); + ymax = data.Y.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); + } + + if (values.rgb_max) { + rgbMax = values.rgb_max; + } + else { + const redmax = data.Red.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); + const greenmax = data.Green.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); + const bluemax = data.Blue.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); + rgbMax = Math.max(redmax, greenmax, bluemax); + } + return {xmin, xmax, ymin, ymax, rgbMax}; +} + +async function loadPointCloud(values: {name_space: string, array_name: string, bbox: { X: number[], Y: number[], Z: number[]}, token: string, tiledb_env: string}) { + + const config: Record = {}; + + config.apiKey = values.token; + + if (values.tiledb_env){ + config.basePath = values.tiledb_env; + } + + const tiledbClient = new Client(config); + + const query: { layout: any, ranges: number[][], bufferSize: number, attributes: any} = { + layout: Layout.Unordered, + ranges: [values.bbox.X, values.bbox.Y, values.bbox.Z], + bufferSize: 150000000000, + attributes: ['X','Y','Z','Red','Green','Blue','GpsTime','Classification'] + }; + + for await (let results of tiledbClient.query.ReadQuery( + values.name_space, + values.array_name, + query + )) { + return results; + } +} + + +function sortDataArrays(data: any){ + + const GpsTime = data.GpsTime; + const X = data.X; + const Y = data.Y; + const Z = data.Z; + const Red = data.Red; + const Green = data.Green; + const Blue = data.Blue; + + const sortedData = sortArrays({GpsTime, X, Y, Z, Red, Green, Blue}); + + return sortedData; + +} + + +function sortArrays(arrays: any, comparator = (a: number, b: number) => (a < b) ? -1 : (a > b) ? 1 : 0) { + + const arrayKeys = Object.keys(arrays); + const [sortableArray] = Object.values(arrays) as any[]; + const indexes = Object.keys(sortableArray); + const sortedIndexes = indexes.sort((a, b) => comparator(sortableArray[a], sortableArray[b])); + + const sortByIndexes = (array: { [x: string]: any; }, sortedIndexes: any[]) => sortedIndexes.map(sortedIndex => array[sortedIndex]); + + if (Array.isArray(arrays)) { + return arrayKeys.map((arrayIndex: string) => sortByIndexes(arrays[arrayIndex as any], sortedIndexes)); + } else { + const sortedArrays: any = {}; + arrayKeys.forEach((arrayKey) => { + sortedArrays[arrayKey] = sortByIndexes(arrays[arrayKey as any], sortedIndexes) as any; + }); + return sortedArrays; + } +} + + +function reduceDataArrays(data: any, show_fraction: number){ + + const GpsTime = data.GpsTime; + const X = data.X; + const Y = data.Y; + const Z = data.Z; + const Red = data.Red; + const Green = data.Green; + const Blue = data.Blue; + + const reducedData = reduceArrays({GpsTime, X, Y, Z, Red, Green, Blue}, show_fraction); + + return reducedData; +} + + +function reduceArrays(arrays: any, show_fraction: number){ + + const arrayKeys = Object.keys(arrays); + const reducedArrays: any = {}; + + for (let arrayKey of arrayKeys) { + if (Array.isArray(arrays[arrayKey])){ + reducedArrays[arrayKey] = arrays[arrayKey].filter(function(value: any, index: any, Arr: any) { + return index % show_fraction == 0; + }); + } + } + + return reducedArrays; +} \ No newline at end of file diff --git a/src/widget.ts b/src/widget.ts index ddd6459..0b974e5 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -8,18 +8,16 @@ import { } from '@jupyter-widgets/base'; import { MODULE_NAME, MODULE_VERSION } from './version'; -import { ArcRotateCamera, Color3, Color4, Engine, PointsCloudSystem, Scene, SceneLoader, StandardMaterial, - SolidParticleSystem, MeshBuilder, +import { ArcRotateCamera, Color3, Color4, Engine, PointsCloudSystem, Scene, SceneLoader, + StandardMaterial, SolidParticleSystem, MeshBuilder, Vector3, Texture } from '@babylonjs/core'; import {AdvancedDynamicTexture, Control, StackPanel, Slider, TextBlock} from 'babylonjs-gui'; import "@babylonjs/loaders/glTF"; import "@babylonjs/core/Debug/debugLayer"; import "@babylonjs/inspector"; - -// Import the CSS import '../css/widget.css'; -import Client from '@tiledb-inc/tiledb-cloud'; -import { Layout } from '@tiledb-inc/tiledb-cloud/lib/v1'; + +import { setPointCloudSwitches, getPointCloud, getPointCloudLimits } from "./data"; export class BabylonBaseModel extends DOMWidgetModel { static model_module = MODULE_NAME; @@ -62,6 +60,7 @@ abstract class BabylonBaseView extends DOMWidgetView { this.model.on_some_change(['width', 'height'], this.resizeCanvas, this); this.engine = new Engine(this.canvas, true); + const engine = this.engine; SceneLoader.ShowLoadingScreen = false; @@ -76,6 +75,7 @@ abstract class BabylonBaseView extends DOMWidgetView { } protected async createScene(): Promise { + const scene = new Scene(this.engine as Engine); if (this.inspector) { @@ -111,88 +111,26 @@ export class BabylonPointCloudView extends BabylonBaseView { protected async createScene(): Promise { return super.createScene().then(async scene => { - var isTime = false; - var isClass = false; - var isTopo = false; - var isGltf = false; - - var dataIn: any - var data: any - - if (this.values.mode === "time"){ - isTime = true; - }else if (this.values.mode === "classes") { - isClass = true; - }else if(this.values.mode == "topo"){ - isTopo = true; - }else if(this.values.mode == "gltf"){ - isGltf = true; - } - - if (this.values.source === "cloud"){ - var dataUnsorted = await loadPointCloud(this.values).then((results) => {return results}); - if (isTime){ - dataIn = sortDataArrays(dataUnsorted); - }else{ - dataIn = dataUnsorted; - } - }else{ - dataIn = this.values.data; - } + const {isTime, isClass, isTopo, isGltf} = setPointCloudSwitches(this.values.mode); + + const data: any = await getPointCloud(this.values).then((results) => {return results}); - if (this.values.show_fraction){ - data = reduceDataArrays(dataIn, this.values.show_fraction); - }else{ - data = dataIn; - } + const {xmin, xmax, ymin, ymax, rgbMax} = getPointCloudLimits(this.values,data); const numCoords = data.X.length; + const times = data.GpsTime; + const classification = data.Classification; // this right? + const gltfData = this.values.gltf_data; const pointSize = this.values.point_size; const backgroundColor = this.values.background_color; - const times = data.GpsTime; const offset = this.values.time_offset; - const classification = this.values.data.Classification; const classes = this.values.classes; const topo_offset = this.values.topo_offset; const scale = this.zScale; + let doClear = false; - var xmin: number - var xmax: number - var ymin: number - var ymax: number - var zmin: number - var zmax: number - var rgbMax: number - - if (this.values.bbox) { - xmin = this.values.bbox.X[0]; - xmax = this.values.bbox.X[1]; - ymin = this.values.bbox.Y[0]; - ymax = this.values.bbox.Y[1]; - zmin = this.values.bbox.Z[0]; - zmax = this.values.bbox.Z[1]; - } - else { - xmin = data.X.reduce((accum: number, currentNumber: number) => Math.min(accum, currentNumber)); - xmax = data.X.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); - ymin = data.Y.reduce((accum: number, currentNumber: number) => Math.min(accum, currentNumber)); - ymax = data.Y.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); - zmin = data.Z.reduce((accum: number, currentNumber: number) => Math.min(accum, currentNumber)); - zmax = data.Z.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); - } - - if (this.values.rgb_max) { - rgbMax = this.values.rgb_max; - } - else { - const redmax = data.Red.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); - const greenmax = data.Green.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); - const bluemax = data.Blue.reduce((accum: number, currentNumber: number) => Math.max(accum, currentNumber)); - rgbMax = Math.max(redmax, greenmax, bluemax); - } - scene.clearColor = new Color4(backgroundColor[0], backgroundColor[1], backgroundColor[2],backgroundColor[3]); if (isClass) { @@ -350,7 +288,7 @@ export class BabylonPointCloudView extends BabylonBaseView { if (this.wheelPrecision > 0) camera.wheelPrecision = this.wheelPrecision; camera.alpha += Math.PI; - camera.setTarget(new Vector3((xmin + xmax) / 2, ((zmin + zmax) / 2)*0.5, (ymin + ymax) / 2)); + camera.setTarget(new Vector3((xmin + xmax) / 2, 0, (ymin + ymax) / 2)); camera.attachControl(this.canvas, false); return scene; }); @@ -513,102 +451,5 @@ export class BabylonImageView extends BabylonBaseView { } -async function loadPointCloud(values: {name_space: string, array_name: string, bbox: { X: number[], Y: number[], Z: number[]}, token: string, tiledb_env: string}) { - - const config: Record = {}; - - config.apiKey = values.token; - - if (values.tiledb_env){ - config.basePath = values.tiledb_env; - } - - const tiledbClient = new Client(config); - - const query: { layout: any, ranges: number[][], bufferSize: number, attributes: any} = { - layout: Layout.Unordered, - ranges: [values.bbox.X, values.bbox.Y, values.bbox.Z], - bufferSize: 150000000000, - attributes: ['X','Y','Z','Red','Green','Blue','GpsTime','Classification'] - }; - - for await (let results of tiledbClient.query.ReadQuery( - values.name_space, - values.array_name, - query - )) { - return results - } - -} - - -function sortDataArrays(data: any){ - - const GpsTime = data.GpsTime - const X = data.X - const Y = data.Y - const Z = data.Z - const Red = data.Red - const Green = data.Green - const Blue = data.Blue - - const sortedData = sortArrays({GpsTime, X, Y, Z, Red, Green, Blue}) - - return sortedData; - -} - - -function sortArrays(arrays: any, comparator = (a: number, b: number) => (a < b) ? -1 : (a > b) ? 1 : 0) { - - const arrayKeys = Object.keys(arrays); - const [sortableArray] = Object.values(arrays) as any[]; - const indexes = Object.keys(sortableArray); - const sortedIndexes = indexes.sort((a, b) => comparator(sortableArray[a], sortableArray[b])); - - const sortByIndexes = (array: { [x: string]: any; }, sortedIndexes: any[]) => sortedIndexes.map(sortedIndex => array[sortedIndex]); - - if (Array.isArray(arrays)) { - return arrayKeys.map((arrayIndex: string) => sortByIndexes(arrays[arrayIndex as any], sortedIndexes)); - } else { - const sortedArrays: any = {}; - arrayKeys.forEach((arrayKey) => { - sortedArrays[arrayKey] = sortByIndexes(arrays[arrayKey as any], sortedIndexes) as any; - }); - return sortedArrays; - } -} - - -function reduceDataArrays(data: any, show_fraction: number){ - - const GpsTime = data.GpsTime - const X = data.X - const Y = data.Y - const Z = data.Z - const Red = data.Red - const Green = data.Green - const Blue = data.Blue - - const reducedData = reduceArrays({GpsTime, X, Y, Z, Red, Green, Blue}, show_fraction) - - return reducedData; -} - - -function reduceArrays(arrays: any, show_fraction: number){ - const arrayKeys = Object.keys(arrays); - const reducedArrays: any = {}; - - for (let arrayKey of arrayKeys) { - if (Array.isArray(arrays[arrayKey])){ - reducedArrays[arrayKey] = arrays[arrayKey].filter(function(value: any, index: any, Arr: any) { - return index % show_fraction == 0; - }); - } - } - return reducedArrays; -} \ No newline at end of file From 3b4f34313e26b57e26ca2f5aba2d31aad685793c Mon Sep 17 00:00:00 2001 From: Margriet Groenendijk Date: Fri, 8 Jul 2022 13:55:55 +0100 Subject: [PATCH 2/3] origin shift added --- pybabylonjs/args.py | 4 ++++ src/data.ts | 19 ++++++++++++++++--- src/widget.ts | 8 +++----- 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/pybabylonjs/args.py b/pybabylonjs/args.py index 41e693c..67fc33f 100644 --- a/pybabylonjs/args.py +++ b/pybabylonjs/args.py @@ -29,9 +29,13 @@ "token": None, "tiledb_env": None, "show_fraction": None, + "origin_shift_x": None, + "origin_shift_y": None, + "origin_shift_z": None, } + def check_point_cloud_args(mode, point_cloud_args_in): if mode == "classes": diff --git a/src/data.ts b/src/data.ts index 5f4ee14..1685a23 100644 --- a/src/data.ts +++ b/src/data.ts @@ -43,17 +43,30 @@ export async function getPointCloud(values: any){ }else{ data = dataIn; } - return data; + + if (values.origin_shift_x){ + data.X = data.X.map((n: any) => n + values.origin_shift_x); + } + if (values.origin_shift_y){ + data.Y = data.Y.map((n: any) => n + values.origin_shift_y); + } + if (values.origin_shift_z){ + data.Z = data.Z.map((n: any) => n + values.origin_shift_z); + } + + const {xmin, xmax, ymin, ymax, rgbMax} = getPointCloudLimits(values, data); + + return {data, xmin, xmax, ymin, ymax, rgbMax}; } -export function getPointCloudLimits(values: any, data: any){ +function getPointCloudLimits(values: any, data: any){ var xmin: number; var xmax: number; var ymin: number; var ymax: number; var rgbMax: number; - + if (values.bbox) { xmin = values.bbox.X[0]; xmax = values.bbox.X[1]; diff --git a/src/widget.ts b/src/widget.ts index 0b974e5..00f6d4b 100644 --- a/src/widget.ts +++ b/src/widget.ts @@ -17,7 +17,7 @@ import "@babylonjs/core/Debug/debugLayer"; import "@babylonjs/inspector"; import '../css/widget.css'; -import { setPointCloudSwitches, getPointCloud, getPointCloudLimits } from "./data"; +import { setPointCloudSwitches, getPointCloud } from "./data"; export class BabylonBaseModel extends DOMWidgetModel { static model_module = MODULE_NAME; @@ -113,13 +113,11 @@ export class BabylonPointCloudView extends BabylonBaseView { const {isTime, isClass, isTopo, isGltf} = setPointCloudSwitches(this.values.mode); - const data: any = await getPointCloud(this.values).then((results) => {return results}); + var {data, xmin, xmax, ymin, ymax, rgbMax} = await getPointCloud(this.values).then((results) => {return results}); - const {xmin, xmax, ymin, ymax, rgbMax} = getPointCloudLimits(this.values,data); - const numCoords = data.X.length; const times = data.GpsTime; - const classification = data.Classification; // this right? + const classification = data.Classification; const gltfData = this.values.gltf_data; const pointSize = this.values.point_size; From da6a2c4f200222f618c4e3e7a520ee7f67c1016a Mon Sep 17 00:00:00 2001 From: Margriet Groenendijk Date: Fri, 8 Jul 2022 16:20:07 +0100 Subject: [PATCH 3/3] formatting --- pybabylonjs/args.py | 1 - 1 file changed, 1 deletion(-) diff --git a/pybabylonjs/args.py b/pybabylonjs/args.py index 67fc33f..9df2f89 100644 --- a/pybabylonjs/args.py +++ b/pybabylonjs/args.py @@ -35,7 +35,6 @@ } - def check_point_cloud_args(mode, point_cloud_args_in): if mode == "classes":