refactor: clean up comments and improve code readability in heatmap components

This commit is contained in:
2025-09-06 13:15:12 +05:30
parent 02752d6ce1
commit aa1a5269dc
3 changed files with 26 additions and 32 deletions

View File

@@ -18,9 +18,6 @@ const BakedHeatMap = () => {
const height = CONSTANTS.gridConfig.size; const height = CONSTANTS.gridConfig.size;
const width = CONSTANTS.gridConfig.size; const width = CONSTANTS.gridConfig.size;
/**
* Helper: Create a DataTexture from filtered baked points
*/
const createPointTexture = useCallback( const createPointTexture = useCallback(
(filteredPoints: typeof bakedPoints) => { (filteredPoints: typeof bakedPoints) => {
if (filteredPoints.length === 0) return null; if (filteredPoints.length === 0) return null;
@@ -30,8 +27,8 @@ const BakedHeatMap = () => {
const index = i * 4; const index = i * 4;
data[index] = (p.points.x + width / 2) / width; data[index] = (p.points.x + width / 2) / width;
data[index + 1] = (p.points.y + height / 2) / height; data[index + 1] = (p.points.y + height / 2) / height;
data[index + 2] = 0.3; // heat strength data[index + 2] = 0.3;
data[index + 3] = 0.0; // unused data[index + 3] = 0.0;
}); });
const texture = new THREE.DataTexture( const texture = new THREE.DataTexture(
@@ -55,25 +52,20 @@ const BakedHeatMap = () => {
u_growthRate: { value: GROWTH_RATE }, u_growthRate: { value: GROWTH_RATE },
}); });
/**
* Render the heatmap to a base64 PNG for a specific type (human/vehicle)
*/
const renderHeatmapToImage = useCallback( const renderHeatmapToImage = useCallback(
(type: string) => { (type: string) => {
if (!meshRef.current) return null; if (!meshRef.current) return null;
// Filter points by type first
const filteredPoints = bakedPoints.filter((p) => p.type === type); const filteredPoints = bakedPoints.filter((p) => p.type === type);
if (filteredPoints.length === 0) return null; if (filteredPoints.length === 0) return null;
// Create texture for these points
const pointTexture = createPointTexture(filteredPoints); const pointTexture = createPointTexture(filteredPoints);
if (!pointTexture) return null; if (!pointTexture) return null;
uniformsRef.current.u_points.value = pointTexture; uniformsRef.current.u_points.value = pointTexture;
uniformsRef.current.u_count.value = filteredPoints.length; uniformsRef.current.u_count.value = filteredPoints.length;
// Temporary top-down orthographic camera
const exportCamera = new THREE.OrthographicCamera( const exportCamera = new THREE.OrthographicCamera(
width / -2, width / -2,
width / 2, width / 2,
@@ -85,26 +77,23 @@ const BakedHeatMap = () => {
exportCamera.position.set(0, 1, 0); exportCamera.position.set(0, 1, 0);
exportCamera.lookAt(0, 0, 0); exportCamera.lookAt(0, 0, 0);
// Offscreen render target
const renderTarget = new THREE.WebGLRenderTarget(1024, 1024, { const renderTarget = new THREE.WebGLRenderTarget(1024, 1024, {
format: THREE.RGBAFormat, format: THREE.RGBAFormat,
type: THREE.UnsignedByteType, type: THREE.UnsignedByteType,
}); });
// Temporary scene with only this mesh
const tempScene = new THREE.Scene(); const tempScene = new THREE.Scene();
tempScene.add(meshRef.current); tempScene.add(meshRef.current);
// Render to texture
gl.setRenderTarget(renderTarget); gl.setRenderTarget(renderTarget);
gl.render(tempScene, exportCamera); gl.render(tempScene, exportCamera);
gl.setRenderTarget(null); gl.setRenderTarget(null);
// Read pixels
const pixels = new Uint8Array(1024 * 1024 * 4); const pixels = new Uint8Array(1024 * 1024 * 4);
gl.readRenderTargetPixels(renderTarget, 0, 0, 1024, 1024, pixels); gl.readRenderTargetPixels(renderTarget, 0, 0, 1024, 1024, pixels);
// Convert pixels to base64 PNG
const canvas = document.createElement("canvas"); const canvas = document.createElement("canvas");
canvas.width = 1024; canvas.width = 1024;
canvas.height = 1024; canvas.height = 1024;
@@ -116,30 +105,38 @@ const BakedHeatMap = () => {
ctx.putImageData(imageData, 0, 0); ctx.putImageData(imageData, 0, 0);
return canvas.toDataURL("image/png"); return canvas.toDataURL("image/png");
} }
return null; return null;
}, },
[gl, width, height, bakedPoints, createPointTexture] [gl, width, height, bakedPoints, createPointTexture]
); );
/**
* Export both human and vehicle heatmaps and log them const downloadImage = (base64: string, filename: string) => {
*/ const link = document.createElement("a");
link.href = base64;
link.download = filename;
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
};
const exportHeatmapAsPNG = useCallback(() => { const exportHeatmapAsPNG = useCallback(() => {
const types = ["human", "vehicle"]; const types = ["human", "vehicle"];
const result = types.map((type) => { const result = types.map((type) => {
const image = renderHeatmapToImage(type); const image = renderHeatmapToImage(type);
return { if (image) {
type, downloadImage(image, `${type}-heatmap.png`);
image, }
}; return { type, image };
}); });
console.log("Exported Heatmaps:", result); console.log("Exported Heatmaps:", result);
return result; return result;
}, [renderHeatmapToImage]); }, [renderHeatmapToImage]);
// Create default texture for initial rendering
const pointTexture = useMemo(() => createPointTexture(bakedPoints), [bakedPoints, createPointTexture]); const pointTexture = useMemo(() => createPointTexture(bakedPoints), [bakedPoints, createPointTexture]);
useEffect(() => { useEffect(() => {
@@ -149,6 +146,7 @@ const BakedHeatMap = () => {
return ( return (
<> <>
<mesh ref={meshRef} rotation={[Math.PI / 2, 0, 0]} position={[0, 0.025, 0]}> <mesh ref={meshRef} rotation={[Math.PI / 2, 0, 0]} position={[0, 0.025, 0]}>
<planeGeometry args={[width, height]} /> <planeGeometry args={[width, height]} />
<shaderMaterial <shaderMaterial
@@ -211,7 +209,6 @@ const BakedHeatMap = () => {
/> />
</mesh> </mesh>
{/* Button to export */}
<Html> <Html>
<button <button
style={{ style={{

View File

@@ -7,7 +7,7 @@ function HeatMap() {
const { bakedPoints, setBakedPoints } = useHeatMapStore(); const { bakedPoints, setBakedPoints } = useHeatMapStore();
useEffect(() => { useEffect(() => {
console.log("bakedPoints: ", bakedPoints); // console.log("bakedPoints: ", bakedPoints);
}, [bakedPoints]); }, [bakedPoints]);
return ( return (

View File

@@ -1,11 +1,10 @@
import * as THREE from "three"; import * as THREE from "three";
import { useEffect, useMemo, useRef, useState } from "react"; import { useEffect, useMemo, useRef, useState } from "react";
import { useFrame, useThree } from "@react-three/fiber"; import { useFrame, useThree } from "@react-three/fiber";
import { useProductContext } from "../../../modules/simulation/products/productContext";
import { useSceneContext } from "../../../modules/scene/sceneContext"; import { useSceneContext } from "../../../modules/scene/sceneContext";
import * as CONSTANTS from "../../../types/world/worldConstants"; import * as CONSTANTS from "../../../types/world/worldConstants";
import { determineExecutionMachineSequences } from "../../../modules/simulation/simulator/functions/determineExecutionMachineSequences"; import { determineExecutionMachineSequences } from "../../../modules/simulation/simulator/functions/determineExecutionMachineSequences";
import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from "../../../store/usePlayButtonStore"; import { useAnimationPlaySpeed, usePauseButtonStore, usePlayButtonStore, useResetButtonStore } from "../../../store/ui/usePlayButtonStore";
import { useHeatMapStore } from "../../../store/simulation/useHeatMapStore"; import { useHeatMapStore } from "../../../store/simulation/useHeatMapStore";
const DECAY_RATE = 0.01; const DECAY_RATE = 0.01;
@@ -28,9 +27,7 @@ const RealTimeHeatMap = () => {
const debugMode: "solid" | "grayscale" | "normal" = "normal"; const debugMode: "solid" | "grayscale" | "normal" = "normal";
const debugModeMap = { solid: 0, grayscale: 1, normal: 2 } as const; const debugModeMap = { solid: 0, grayscale: 1, normal: 2 } as const;
const { productStore } = useSceneContext(); const { productStore } = useSceneContext();
const { getProductById, products } = productStore(); const { getProductById, products, selectedProduct } = productStore();
const { selectedProductStore } = useProductContext();
const { selectedProduct } = selectedProductStore();
const { hasHuman, hasVehicle, monitoringHuman, monitoringVehicle, addMonitoringHuman, addMonitoringVehicle, addBakedPoint } = useHeatMapStore(); const { hasHuman, hasVehicle, monitoringHuman, monitoringVehicle, addMonitoringHuman, addMonitoringVehicle, addBakedPoint } = useHeatMapStore();
const { isPlaying } = usePlayButtonStore(); const { isPlaying } = usePlayButtonStore();
const { isReset } = useResetButtonStore(); const { isReset } = useResetButtonStore();
@@ -51,7 +48,7 @@ const RealTimeHeatMap = () => {
u_radius: { value: RADIUS }, u_radius: { value: RADIUS },
u_opacity: { value: OPACITY }, u_opacity: { value: OPACITY },
u_debugMode: { value: debugModeMap[debugMode] }, u_debugMode: { value: debugModeMap[debugMode] },
u_growthRate: { value: GROWTH_TIME_MULTIPLIER }, // NEW u_growthRate: { value: GROWTH_TIME_MULTIPLIER },
}); });
useEffect(() => { useEffect(() => {