Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
hakon-matland-adsk committed Jan 29, 2024
1 parent 6eb18de commit 5bc555a
Show file tree
Hide file tree
Showing 10 changed files with 392 additions and 114 deletions.
2 changes: 2 additions & 0 deletions analyses/export-stl/script.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { Forma } from "https://esm.sh/forma-embedded-view-sdk/auto";
import * as THREE from "three";
import { STLExporter } from "three/addons/exporters/STLExporter.js";

console.log(await Forma.areaMetrics.calculate({ paths: ["root"] }));

document.getElementById("run").onclick = async () => {
try {
const triangles = await Forma.geometry.getTriangles({ path: "root" });
Expand Down
3 changes: 2 additions & 1 deletion analyses/wind-surrogate-playground/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
"dependencies": {
"preact": "^10.16.0",
"three": "^0.157.0",
"forma-embedded-view-sdk": "^0.16.0"
"forma-embedded-view-sdk": "^0.21.0",
"three-mesh-bvh": "^0.6.8"
},
"devDependencies": {
"@preact/preset-vite": "^2.5.0",
Expand Down
76 changes: 76 additions & 0 deletions analyses/wind-surrogate-playground/src/RenderDepthMap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useEffect, useState } from "preact/hooks";
import "./app.css";
import { Forma } from "forma-embedded-view-sdk/auto";
import {
BufferAttribute,
BufferGeometry,
Mesh,
MeshBasicMaterial,
Scene,
} from "three";
import { computeBoundsTree, disposeBoundsTree } from "three-mesh-bvh";
import { biggerGenerateDepthMap } from "./biggerDepthMapProcessor";
// Speed up raycasting using https://github.com/gkjohnson/three-mesh-bvh
// @ts-ignore
BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
// @ts-ignore
BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;

export function RenderDepthMap() {
const [allBufferGeometry, setAllBufferGeometry] =
useState<BufferGeometry | null>(null);

useEffect(() => {
Forma.geometry
.getTriangles({
path: "root",
})
.then((terrainVertexPositions) => {
const allGeometry = new BufferGeometry();
allGeometry.setAttribute(
"position",
new BufferAttribute(terrainVertexPositions, 3)
);
setAllBufferGeometry(allGeometry);
});
}, []);

useEffect(() => {
if (allBufferGeometry) {
console.time("everything");
const allScene = new Scene();

allScene.add(new Mesh(allBufferGeometry, new MeshBasicMaterial()));
biggerGenerateDepthMap(allScene, [0, 0]).then((depthMap) => {
const imageData = new ImageData(
new Uint8ClampedArray(depthMap.data),
depthMap.width,
depthMap.height
);
createImageBitmap(imageData, { imageOrientation: "flipY" }).then(
(imageBitmap) => {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d")!;
canvas.height = depthMap.height;
canvas.width = depthMap.width;
ctx.drawImage(imageBitmap, 0, 0);
Forma.terrain.groundTexture.add({
name: "test",
canvas,
position: { x: 0, y: 0, z: 30 },
scale: { x: depthMap.resolution, y: depthMap.resolution },
});
ctx.restore();
console.timeEnd("everything");
}
);
});
}
}, [allBufferGeometry]);

return (
<>
<div>Hello</div>
</>
);
}
130 changes: 81 additions & 49 deletions analyses/wind-surrogate-playground/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ import {
MeshBasicMaterial,
Scene,
} from "three";
import { computeBoundsTree, disposeBoundsTree } from "three-mesh-bvh";
import {
HeightMaps,
WindParametersResponse,
} from "forma-embedded-view-sdk/predictive-analysis";
// Speed up raycasting using https://github.com/gkjohnson/three-mesh-bvh
// @ts-ignore
BufferGeometry.prototype.computeBoundsTree = computeBoundsTree;
// @ts-ignore
BufferGeometry.prototype.disposeBoundsTree = disposeBoundsTree;

const DEFAULT_COLOR_SCALE = [
"#B2F8DA",
Expand All @@ -17,11 +27,15 @@ const DEFAULT_COLOR_SCALE = [
"#FFA900",
"#FF463A",
];
const arrayMinMax = (array: Float32Array) =>
array.reduce(
([min, max], value) => [Math.min(min, value), Math.max(max, value)],
[Number.POSITIVE_INFINITY, Number.NEGATIVE_INFINITY]
);

//const DEFAULT_COLOR_SCALE2 = [
// "#44ce1b",
// "#bbdb44",
// "#f7e379",
// "#f2a134",
// "#e51f1f",
//];

function drawOnCanvas(
canvas: HTMLCanvasElement,
{
Expand All @@ -30,7 +44,7 @@ function drawOnCanvas(
width,
height,
}: {
grid: Float32Array;
grid: Float32Array | number[];
colorScale?: string[];
width: number;
height: number;
Expand All @@ -40,62 +54,71 @@ function drawOnCanvas(
const ctx = canvas.getContext("2d")!;
canvas.height = height;
canvas.width = width;
const [minValue, maxValue] = arrayMinMax(grid.filter((v) => !isNaN(v)));

for (let k = 0; k < grid.length; k++) {
const i = Math.floor(k % canvas.width);
const j = Math.floor(k / canvas.width);

if (!isNaN(grid[k])) {
const v = grid[k];
const scaledValue = (v - minValue) / (maxValue - minValue);
const colorIndex = Math.min(
Math.floor(scaledValue * colorScale.length),
colorScale.length - 1
);

for (let index = 0; index < grid.length; index++) {
const column = Math.floor(index % canvas.width);
const row = Math.floor(index / canvas.width);

if (!isNaN(grid[index])) {
const v = grid[index];
const colorIndex = Math.round(v);
ctx.fillStyle = colorScale[colorIndex];
ctx.fillRect(i, j, 1, 1);
ctx.fillRect(column, row, 1, 1);
}
}
return canvas;
}

async function calculateAndDrawWindComfort(
depthMap: any,
windRoseData: any,
heightMaps: HeightMaps,
windRoseData: WindParametersResponse,
position: { x: number; y: number; z: number }
) {
Forma.rapidWind
.calculateWindComfort({
...depthMap,
windRose: { data: windRoseData.data, height: windRoseData.height },
const canvas = document.createElement("canvas");

Forma.terrain.groundTexture.add({
name: JSON.stringify(position),
canvas,
position,
scale: { x: 1.5, y: 1.5 },
});
Forma.predictiveAnalysis
.predictWind({
heightMaps: heightMaps,
windRose: {
data: windRoseData.data,
height: windRoseData.height,
},
type: "comfort",
roughness: windRoseData.roughness,
comfortScale: "lawson_lddc",
})
.then((data) => {
console.log(data);
const canvas = document.createElement("canvas");
drawOnCanvas(canvas, {
grid: data.grid,
width: data.meta.width,
height: data.meta.height,
width: data.width,
height: data.height,
});
Forma.terrain.groundTexture.add({
name: JSON.stringify(position),
name: JSON.stringify(position) + "result",
canvas,
position,
scale: { x: data.meta.resolution, y: data.meta.resolution },
scale: data.scale,
});
});
}

export function App() {
const [windRoseData, setWindRoseData] = useState<any | null>(null);
const [terrainScene, setTerrainScene] = useState<Scene | null>(null);
const [allScene, setAllScene] = useState<Scene | null>(null);
const [terrainBufferGeometry, setTerrainBufferGeometry] =
useState<BufferGeometry | null>(null);
const [allBufferGeometry, setAllBufferGeometry] =
useState<BufferGeometry | null>(null);

useEffect(() => {
console.log(Forma);
Forma.rapidWind.getWindRoseData().then((data) => {
Forma.predictiveAnalysis.getWindParameters().then((data) => {
console.log(data);
setWindRoseData(data);
});
Expand All @@ -117,12 +140,9 @@ export function App() {
"position",
new BufferAttribute(terrainVertexPositions, 3)
);
const terrainScene = new Scene();

terrainScene.add(
new Mesh(terrainGeometry, new MeshBasicMaterial({ color: 0xff0000 }))
);
setTerrainScene(terrainScene);
// @ts-ignore
terrainGeometry.computeBoundsTree();
setTerrainBufferGeometry(terrainGeometry);
});
}, []);

Expand All @@ -137,19 +157,31 @@ export function App() {
"position",
new BufferAttribute(terrainVertexPositions, 3)
);
const allScene = new Scene();

allScene.add(
new Mesh(allGeometry, new MeshBasicMaterial({ color: 0xff0000 }))
);
setAllScene(allScene);
// @ts-ignore
allGeometry.computeBoundsTree();
setAllBufferGeometry(allGeometry);
});
}, []);

useEffect(() => {
if (windRoseData && allScene && terrainScene) {
for (let x = 0; x <= 200; x += 200) {
for (let y = 0; y <= 200; y += 200) {
if (windRoseData && allBufferGeometry && terrainBufferGeometry) {
const allScene = new Scene();

allScene.add(
new Mesh(allBufferGeometry, new MeshBasicMaterial({ color: 0xff0000 }))
);

const terrainScene = new Scene();

terrainScene.add(
new Mesh(
terrainBufferGeometry,
new MeshBasicMaterial({ color: 0xff0000 })
)
);

for (let x = 0; x <= 500; x += 200) {
for (let y = 0; y <= 500; y += 200) {
generateDepthMap(terrainScene, allScene, [x, y]).then((depthMap) => {
calculateAndDrawWindComfort(depthMap, windRoseData, {
x,
Expand Down
Loading

0 comments on commit 5bc555a

Please sign in to comment.