generated from graasp/graasp-app-starter-ts-vite
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: display the heat loss rate with arrows (#47)
* feat(refactor): split the house into smaller components * feat: compute the heat loss for each wall directly * feat: improve the simulation informations UI * feat: simplify the house and set it as a square
- Loading branch information
Showing
36 changed files
with
1,013 additions
and
254 deletions.
There are no files selected for viewing
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,70 +1,91 @@ | ||
import { useEffect, useMemo, useState } from 'react'; | ||
|
||
import { Material } from '@/types/material'; | ||
import { HeatLossPerComponent, HouseComponents } from '@/types/houseComponent'; | ||
import { TimeUnitType } from '@/types/time'; | ||
import { | ||
calculateHeatLossConstantFactor, | ||
sumHeatLossRate, | ||
} from '@/utils/heatLoss'; | ||
|
||
type Props = { | ||
material: Material; | ||
area: number; | ||
houseComponents: HouseComponents; | ||
indoorTemperature: number; | ||
measurementFrequency: TimeUnitType; | ||
temperatures: number[]; | ||
}; | ||
|
||
type UseHeatLossReturnType = { | ||
heatLoss: number; | ||
heatLosses: HeatLossPerComponent; | ||
totalHeatLoss: number; | ||
}; | ||
|
||
export const useHeatLoss = ({ | ||
material, | ||
area, | ||
houseComponents, | ||
indoorTemperature, | ||
measurementFrequency, | ||
temperatures, | ||
}: Props): UseHeatLossReturnType => { | ||
const [heatLoss, setHeatLoss] = useState(0); | ||
const [heatLossPerComponent, setHeatLossPerComponent] = | ||
useState<HeatLossPerComponent>({}); | ||
const [totalHeatLoss, setTotalHeatLoss] = useState(0); | ||
|
||
const heatLossConstantFactor = useMemo( | ||
// Compute the constant factors per house's components | ||
const heatLossConstantFactors = useMemo( | ||
() => | ||
calculateHeatLossConstantFactor({ | ||
area, | ||
thermalConductivity: material.thermalConductivity, | ||
materialThickness: material.thickness, | ||
}), | ||
[area, material.thermalConductivity, material.thickness], | ||
Array.from(houseComponents.entries()).reduce<HeatLossPerComponent>( | ||
(acc, [id, c]) => ({ | ||
...acc, | ||
[id]: calculateHeatLossConstantFactor({ | ||
area: c.area, | ||
thermalConductivity: c.material.thermalConductivity, | ||
materialThickness: c.material.thickness, | ||
}), | ||
}), | ||
{}, | ||
), | ||
[houseComponents], | ||
); | ||
|
||
useEffect(() => { | ||
if (!temperatures) { | ||
setHeatLoss(0); | ||
setHeatLossPerComponent({}); | ||
setTotalHeatLoss(0); | ||
return; | ||
} | ||
|
||
const newHeatLoss = sumHeatLossRate({ | ||
temperatures, | ||
constantFactor: heatLossConstantFactor, | ||
indoorTemperature, | ||
timeUnit: measurementFrequency, | ||
}); | ||
const newHeatLossPerComponent = Object.entries( | ||
heatLossConstantFactors, | ||
).reduce<HeatLossPerComponent>( | ||
(acc, [componentId, heatLossConstantFactor]) => ({ | ||
...acc, | ||
[componentId]: sumHeatLossRate({ | ||
temperatures, | ||
constantFactor: heatLossConstantFactor, | ||
indoorTemperature, | ||
timeUnit: measurementFrequency, | ||
}), | ||
}), | ||
{}, | ||
); | ||
|
||
setHeatLoss(newHeatLoss); | ||
setTotalHeatLoss((prevT) => prevT + newHeatLoss); | ||
setHeatLossPerComponent(newHeatLossPerComponent); | ||
setTotalHeatLoss( | ||
(prevT) => | ||
prevT + | ||
Object.values(newHeatLossPerComponent).reduce( | ||
(acc, heatLoss) => acc + heatLoss, | ||
0, | ||
), | ||
); | ||
}, [ | ||
measurementFrequency, | ||
heatLossConstantFactor, | ||
temperatures, | ||
indoorTemperature, | ||
heatLossConstantFactors, | ||
]); | ||
|
||
return { | ||
heatLoss, | ||
heatLosses: heatLossPerComponent, | ||
totalHeatLoss, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import { useCallback, useRef, useState } from 'react'; | ||
|
||
import { Vector2 } from 'three'; | ||
|
||
import { HouseComponentType, HouseComponents } from '@/types/houseComponent'; | ||
import { Material } from '@/types/material'; | ||
|
||
export type RegisterComponentParams = { | ||
id: string; | ||
size: Vector2; | ||
componentType: HouseComponentType; | ||
}; | ||
|
||
type UseHouseComponentsReturnType = { | ||
houseComponents: HouseComponents; | ||
registerComponent: (params: RegisterComponentParams) => void; | ||
}; | ||
|
||
type Props = { | ||
materials: Map<HouseComponentType, Material>; | ||
}; | ||
|
||
export const useHouseComponents = ({ | ||
materials, | ||
}: Props): UseHouseComponentsReturnType => { | ||
const houseComponentsRegister = useRef<HouseComponents>(new Map()); | ||
const [houseComponents, setHouseComponents] = useState<HouseComponents>( | ||
() => new Map(), | ||
); | ||
|
||
const registerComponent = useCallback( | ||
({ id, size, componentType }: RegisterComponentParams): void => { | ||
const material = materials.get(componentType); | ||
|
||
if (!material) { | ||
throw new Error( | ||
`No material was found for the component ${componentType}`, | ||
); | ||
} | ||
|
||
// The ref is used here to avoid concurrency of updating the state. | ||
// Without the ref, if multiple components register at the same time, | ||
// only the last call to registerComponent will be set in the state. | ||
houseComponentsRegister.current.set(id, { | ||
area: size.x * size.y, | ||
material, | ||
}); | ||
setHouseComponents(houseComponentsRegister.current); | ||
}, | ||
[houseComponentsRegister, materials], | ||
); | ||
|
||
return { | ||
houseComponents, | ||
registerComponent, | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
/* | ||
Auto-generated by: https://github.com/pmndrs/gltfjsx | ||
Command: npx [email protected] OriginalArrow.glb --transform --types | ||
Files: OriginalArrow.glb [21.84KB] > Arrow.glb [3.86KB] (82%) | ||
Author: Alihan (https://sketchfab.com/Dare0) | ||
License: CC-BY-4.0 (http://creativecommons.org/licenses/by/4.0/) | ||
Source: https://sketchfab.com/3d-models/direction-arrow-6ef46718c7b242e39fcad7f27ee858a5 | ||
Title: Direction Arrow | ||
*/ | ||
import { useRef } from 'react'; | ||
|
||
import GLB_FILE_PATH from '@models/HeatLossArrow.glb?url'; | ||
import { useGLTF } from '@react-three/drei'; | ||
import { useFrame } from '@react-three/fiber'; | ||
import { Color, Group, Mesh, MeshStandardMaterial, Vector3 } from 'three'; | ||
import { GLTF } from 'three-stdlib'; | ||
|
||
import { Position } from '@/types/wall'; | ||
import { formatHeatLossRate, powerConversionFactors } from '@/utils/heatLoss'; | ||
|
||
import { HeatLossTextArrow } from './HeatLossTextArrow'; | ||
|
||
type GLTFResult = GLTF & { | ||
nodes: { | ||
Arrow: Mesh; | ||
}; | ||
materials: { | ||
Arrow: MeshStandardMaterial; | ||
}; | ||
}; | ||
|
||
type Props = JSX.IntrinsicElements['group'] & { | ||
heatLoss: number; | ||
position?: Position; | ||
}; | ||
|
||
// These factors will affect the range of sizes of the arrows. | ||
const MIN_HEATLOSS = 0; | ||
const MAX_HEATLOSS = 5 * powerConversionFactors.KiloWatt; | ||
const MIN_SCALE = 0.8; | ||
const MAX_SCALE = 1.6; | ||
|
||
const ARRAY_COLOR = new Color('red'); | ||
const TEXT_COLOR = 'white'; | ||
|
||
export const HeatLossArrow = ({ | ||
heatLoss, | ||
position, | ||
...props | ||
}: Props): JSX.Element => { | ||
const { nodes, materials } = useGLTF(GLB_FILE_PATH) as GLTFResult; | ||
const material = materials.Arrow; | ||
|
||
const scale = | ||
MIN_SCALE + | ||
(MAX_SCALE - MIN_SCALE) * | ||
Math.min( | ||
1, | ||
Math.max( | ||
0.1, | ||
(heatLoss - MIN_HEATLOSS) / (MAX_HEATLOSS - MIN_HEATLOSS), | ||
), | ||
); | ||
|
||
const scaleRef = useRef<Group>(null); | ||
|
||
useFrame((_, delta) => { | ||
if (scaleRef.current) { | ||
scaleRef.current.scale.lerp( | ||
new Vector3(1 * scale, 1 * scale, 1 * scale), | ||
delta * 3, | ||
); // Smooth transition | ||
} | ||
}); | ||
|
||
material.color = ARRAY_COLOR; | ||
|
||
return ( | ||
<group ref={scaleRef} {...props} position={position} dispose={null}> | ||
<mesh geometry={nodes.Arrow.geometry} material={material} /> | ||
<HeatLossTextArrow | ||
heatLoss={formatHeatLossRate(heatLoss)} | ||
color={TEXT_COLOR} | ||
/> | ||
</group> | ||
); | ||
}; | ||
|
||
useGLTF.preload(GLB_FILE_PATH); |
Oops, something went wrong.