From 7669a9473f9da454ccf991719d58b67eb7d675b5 Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:29:39 +0200 Subject: [PATCH 01/10] Refactor pvSystems #242 The react state pvSystems should contain relevant metadata, not only indices. --- src/components/ThreeViewer/Meshes/PVSystem.js | 53 ---- .../ThreeViewer/Meshes/PVSystems.js | 297 ++++++++++-------- src/components/ThreeViewer/Overlay.js | 170 ++++++---- src/components/ThreeViewer/OverlayDrawPV.js | 13 +- src/components/ThreeViewer/Scene.js | 11 +- src/pages/Simulation.js | 9 +- 6 files changed, 296 insertions(+), 257 deletions(-) delete mode 100644 src/components/ThreeViewer/Meshes/PVSystem.js diff --git a/src/components/ThreeViewer/Meshes/PVSystem.js b/src/components/ThreeViewer/Meshes/PVSystem.js deleted file mode 100644 index 09414721..00000000 --- a/src/components/ThreeViewer/Meshes/PVSystem.js +++ /dev/null @@ -1,53 +0,0 @@ -import { useFrame } from "@react-three/fiber" -import React, { useRef } from "react" -import * as THREE from "three" -import TextSprite from "../TextSprite" - -const PVSystem = ({ geometry, annualYield, area }) => { - const textRef = useRef() - - const center = calculateCenter(geometry.attributes.position.array) - - useFrame(({ camera }) => { - if (textRef.current) { - textRef.current.quaternion.copy(camera.quaternion) - } - }) - - return ( - <> - - - - - ) -} - -const calculateCenter = (points) => { - const length = points.length / 3 - const sum = points.reduce( - (acc, value, index) => { - acc[index % 3] += value - return acc - }, - [0, 0, 0] - ) - return new THREE.Vector3(sum[0] / length, sum[1] / length, sum[2] / length) -} - -export default PVSystem diff --git a/src/components/ThreeViewer/Meshes/PVSystems.js b/src/components/ThreeViewer/Meshes/PVSystems.js index a3aba617..85f28508 100644 --- a/src/components/ThreeViewer/Meshes/PVSystems.js +++ b/src/components/ThreeViewer/Meshes/PVSystems.js @@ -1,159 +1,202 @@ -import { useThree } from "@react-three/fiber" -import React, { useEffect, useState } from "react" +import React, { useRef } from "react" +import { useFrame } from "react-three-fiber" import * as THREE from "three" import * as BufferGeometryUtils from "three/addons/utils/BufferGeometryUtils.js" -import PVSystem from "./PVSystem" +import TextSprite from "../TextSprite" -const PVSystems = ({ - visiblePVSystems, +export const PVSystems = ({ pvSystems }) => { + console.log("PVSystems in three module", pvSystems) + return ( + <> + {pvSystems.map((system, index) => ( + + ))} + + ) +} + +export function createPVSystem({ + setPVSystems, pvPoints, setPVPoints, simulationMeshes, -}) => { - const points = pvPoints.map((obj) => obj.point) // pvPoints is a list of objects, each object has a point and a normal - - const { scene } = useThree() - const [pvSystems, setPVSystems] = useState([]) +}) { + const points = pvPoints.map((obj) => obj.point) + if (pvPoints.length < 3) { + console.log("Not enough points to create a polygon") + return + } + const geometry = new THREE.BufferGeometry() + const vertices = [] + points.forEach((point) => { + vertices.push(point.x, point.y, point.z) + }) - useEffect(() => { - if (visiblePVSystems.length === 0 || pvPoints.length < 3) { - console.log("Not enough points to create a polygon") - return - } - const geometry = new THREE.BufferGeometry() - const vertices = [] - points.forEach((point) => { - vertices.push(point.x, point.y, point.z) - }) + const triangles = [] + const bufferTriangles = [] + const normalOffset = 0.1 // Adjust this value as needed - const triangles = [] - const bufferTriangles = [] - const normalOffset = 0.1 // Adjust this value as needed + for (let i = 1; i < pvPoints.length - 1; i++) { + const v0 = pvPoints[0] + const v1 = pvPoints[i] + const v2 = pvPoints[i + 1] - for (let i = 1; i < pvPoints.length - 1; i++) { - const v0 = pvPoints[0] - const v1 = pvPoints[i] - const v2 = pvPoints[i + 1] + const shift = (element) => ({ + x: element.point.x + element.normal.x * normalOffset, + y: element.point.y + element.normal.y * normalOffset, + z: element.point.z + element.normal.z * normalOffset, + }) - const shift = (element) => ({ - x: element.point.x + element.normal.x * normalOffset, - y: element.point.y + element.normal.y * normalOffset, - z: element.point.z + element.normal.z * normalOffset, - }) + const sv0 = shift(v0) + const sv1 = shift(v1) + const sv2 = shift(v2) + + triangles.push({ a: v0.point, b: v1.point, c: v2.point }) + bufferTriangles.push( + sv0.x, + sv0.y, + sv0.z, + sv1.x, + sv1.y, + sv1.z, + sv2.x, + sv2.y, + sv2.z + ) + } - const sv0 = shift(v0) - const sv1 = shift(v1) - const sv2 = shift(v2) - - triangles.push({ a: v0.point, b: v1.point, c: v2.point }) - bufferTriangles.push( - sv0.x, - sv0.y, - sv0.z, - sv1.x, - sv1.y, - sv1.z, - sv2.x, - sv2.y, - sv2.z - ) - } + geometry.setAttribute( + "position", + new THREE.Float32BufferAttribute(bufferTriangles, 3) + ) - geometry.setAttribute( - "position", - new THREE.Float32BufferAttribute(bufferTriangles, 3) + let subdividedTriangles = [] + const triangleSubdivisionThreshold = 0.8 + triangles.forEach((triangle) => { + subdividedTriangles = subdividedTriangles.concat( + subdivideTriangle(triangle, triangleSubdivisionThreshold) ) + }) - let subdividedTriangles = [] - const triangleSubdivisionThreshold = 0.8 - triangles.forEach((triangle) => { - subdividedTriangles = subdividedTriangles.concat( - subdivideTriangle(triangle, triangleSubdivisionThreshold) - ) - }) - - const geometries = [] + const geometries = [] - simulationMeshes.forEach((mesh) => { - const geom = mesh.geometry.clone() - geom.applyMatrix4(mesh.matrixWorld) - geometries.push(geom) - }) - const simulationGeometry = BufferGeometryUtils.mergeGeometries( - geometries, - true + simulationMeshes.forEach((mesh) => { + const geom = mesh.geometry.clone() + geom.applyMatrix4(mesh.matrixWorld) + geometries.push(geom) + }) + const simulationGeometry = BufferGeometryUtils.mergeGeometries( + geometries, + true + ) + const polygonPrefilteringCutoff = 10 + const prefilteredPolygons = filterPolygonsByDistance( + simulationGeometry, + points, + polygonPrefilteringCutoff + ) + const newVertices = [] + const newColors = [] + const newIntensities = [] + subdividedTriangles.forEach((triangle) => { + newVertices.push(triangle.a.x, triangle.a.y, triangle.a.z) + newVertices.push(triangle.b.x, triangle.b.y, triangle.b.z) + newVertices.push(triangle.c.x, triangle.c.y, triangle.c.z) + }) + for (let i = 0; i < newVertices.length; i += 3) { + const vertex = new THREE.Vector3( + newVertices[i], + newVertices[i + 1], + newVertices[i + 2] ) - const polygonPrefilteringCutoff = 10 - const prefilteredPolygons = filterPolygonsByDistance( - simulationGeometry, - points, + const closestPolygon = findClosestPolygon( + vertex, + prefilteredPolygons, polygonPrefilteringCutoff ) - const newVertices = [] - const newColors = [] - const newIntensities = [] - subdividedTriangles.forEach((triangle) => { - newVertices.push(triangle.a.x, triangle.a.y, triangle.a.z) - newVertices.push(triangle.b.x, triangle.b.y, triangle.b.z) - newVertices.push(triangle.c.x, triangle.c.y, triangle.c.z) - }) - for (let i = 0; i < newVertices.length; i += 3) { - const vertex = new THREE.Vector3( - newVertices[i], - newVertices[i + 1], - newVertices[i + 2] - ) - const closestPolygon = findClosestPolygon( - vertex, - prefilteredPolygons, - polygonPrefilteringCutoff + if (closestPolygon) { + const projectedVertex = projectOntoTriangle(vertex, closestPolygon) + const color = getColorAtPointOnTriangle(projectedVertex, closestPolygon) + const intensity = getIntensityAtPointOnTriangle( + projectedVertex, + closestPolygon ) - if (closestPolygon) { - const projectedVertex = projectOntoTriangle(vertex, closestPolygon) - const color = getColorAtPointOnTriangle(projectedVertex, closestPolygon) - const intensity = getIntensityAtPointOnTriangle( - projectedVertex, - closestPolygon - ) - newColors.push(color.r, color.g, color.b) - newIntensities.push(intensity) - } else { - newColors.push(1, 1, 1) - newIntensities.push(-1) - } + newColors.push(color.r, color.g, color.b) + newIntensities.push(intensity) + } else { + newColors.push(1, 1, 1) + newIntensities.push(-1) } - const polygonArea = calculatePolygonArea(triangles) - const polygonIntensity = calculatePolygonIntensity( - newVertices, - newIntensities - ) - const annualYield = polygonArea * polygonIntensity + } + const polygonArea = calculatePolygonArea(triangles) + const polygonIntensity = calculatePolygonIntensity( + newVertices, + newIntensities + ) + const annualYield = polygonArea * polygonIntensity - const newPVSystem = { - geometry: geometry, - annualYield: annualYield, - area: polygonArea, - } + const newPVSystem = { + geometry: geometry, + annualYield: annualYield, + area: polygonArea, + } + console.log("newPVSystem", newPVSystem) + + setPVSystems((prevSystems) => [...prevSystems, newPVSystem]) + setPVPoints([]) +} + +const PVSystem = ({ geometry, annualYield, area }) => { + const textRef = useRef() - setPVSystems((prevSystems) => [...prevSystems, newPVSystem]) - setPVPoints([]) - }, [visiblePVSystems]) + const center = calculateCenter(geometry.attributes.position.array) + + useFrame(({ camera }) => { + if (textRef.current) { + textRef.current.quaternion.copy(camera.quaternion) + } + }) return ( <> - {pvSystems.map((system, index) => ( - - ))} + + + ) } -export default PVSystems +const calculateCenter = (points) => { + const length = points.length / 3 + const sum = points.reduce( + (acc, value, index) => { + acc[index % 3] += value + return acc + }, + [0, 0, 0] + ) + return new THREE.Vector3(sum[0] / length, sum[1] / length, sum[2] / length) +} function subdivideTriangle(triangle, threshold) { const distance = (p1, p2) => diff --git a/src/components/ThreeViewer/Overlay.js b/src/components/ThreeViewer/Overlay.js index f53889cc..dc58db82 100644 --- a/src/components/ThreeViewer/Overlay.js +++ b/src/components/ThreeViewer/Overlay.js @@ -21,13 +21,13 @@ import { UnorderedList, useDisclosure, } from "@chakra-ui/react" +import React from "react" import { useTranslation } from "react-i18next" import { simulationForNewBuilding } from "../../simulation/main" +import SavingCalculation from "../PVSimulation/SavingsCalculation" +import ButtonWithHoverHelp from "../Template/ButtonWithHoverHelp" import HoverHelp from "../Template/HoverHelp" import SliderWithLabel from "../Template/SliderWithLabel" - -import React from "react" -import ButtonWithHoverHelp from "../Template/ButtonWithHoverHelp" import OverlayDrawPV from "./OverlayDrawPV" function Overlay({ @@ -39,8 +39,8 @@ function Overlay({ setSelectedMesh, geometries, geoLocation, - visiblePVSystems, - setvisiblePVSystems, + pvSystems, + setPVSystems, pvPoints, setPVPoints, simulationMeshes, @@ -60,72 +60,81 @@ function Overlay({ const btnRef = React.useRef() return ( - - {frontendState == "Results" && ( - <> + <> + + {frontendState == "Results" && ( + <> + + { + setFrontendState("DrawPV") + onCloseDrawer() + }} + hoverText={ + "PV-Anlage in der Karte einzeichnen und Jahresbetrag berechnen." + } + /> + + )} + {frontendState == "DrawPV" && ( + + )} + {selectedMesh.length > 0 && ( - { - setFrontendState("DrawPV") - onCloseDrawer() - }} - hoverText={ - "PV-Anlage in der Karte einzeichnen und Jahresbetrag berechnen." - } - /> - - )} - {frontendState == "DrawPV" && ( - - )} - {selectedMesh.length > 0 && ( + )} - )} - - - - + + + + + + + ) } @@ -167,6 +176,45 @@ const OverlayWrapper = ({ children }) => { ) } +const HighPrioWrapper = ({ children }) => { + return ( + <> + *": { + pointerEvents: "auto", + }, + }} + > + + {children} + + + + ) +} + const CustomDrawer = ({ isOpen, onClose, showTerrain, setShowTerrain }) => { const { t } = useTranslation() const [sliderValue, setSliderValue] = React.useState(window.numSimulations) diff --git a/src/components/ThreeViewer/OverlayDrawPV.js b/src/components/ThreeViewer/OverlayDrawPV.js index 3eb02be0..b01ff422 100644 --- a/src/components/ThreeViewer/OverlayDrawPV.js +++ b/src/components/ThreeViewer/OverlayDrawPV.js @@ -1,18 +1,23 @@ import { Button } from "@chakra-ui/react" import React from "react" import { useTranslation } from "react-i18next" +import { createPVSystem } from "./Meshes/PVSystems" export default function OverlayDrawPV({ - visiblePVSystems, - setvisiblePVSystems, + setPVSystems, pvPoints, setPVPoints, setFrontendState, + simulationMeshes, }) { const { t } = useTranslation() const handleCreatePVButtonClick = () => { - const nextIndex = visiblePVSystems.length - setvisiblePVSystems([...visiblePVSystems, nextIndex]) + createPVSystem({ + setPVSystems, + pvPoints, + setPVPoints, + simulationMeshes, + }) setFrontendState("Results") } diff --git a/src/components/ThreeViewer/Scene.js b/src/components/ThreeViewer/Scene.js index acdaac7e..e9fc9779 100644 --- a/src/components/ThreeViewer/Scene.js +++ b/src/components/ThreeViewer/Scene.js @@ -4,7 +4,7 @@ import { Canvas } from "react-three-fiber" import CustomMapControl from "./Controls/CustomMapControl" import DrawPVControl from "./Controls/DrawPVControl" import { HighlightedMesh } from "./Meshes/HiglightedMesh" -import PVSystems from "./Meshes/PVSystems" +import { PVSystems } from "./Meshes/PVSystems" import SimulationMesh from "./Meshes/SimulationMesh" import SurroundingMesh from "./Meshes/SurroundingMesh" import Points from "./Points" @@ -15,7 +15,7 @@ const Scene = ({ simulationMeshes, showTerrain, frontendState, - visiblePVSystems, + pvSystems, selectedMesh, setSelectedMesh, pvPoints, @@ -68,12 +68,7 @@ const Scene = ({ )} {frontendState == "DrawPV" && } - + {pvSystems.length > 0 && } {simulationMeshes.length > 0 && } diff --git a/src/pages/Simulation.js b/src/pages/Simulation.js index d6ff12f7..fcbff248 100644 --- a/src/pages/Simulation.js +++ b/src/pages/Simulation.js @@ -19,7 +19,7 @@ function Index() { // simulationProgress is used for the loading bar const [simulationProgress, setSimulationProgress] = useState(0) // A list of visible PV Systems - they get visible after they are drawn on a building and calculated - const [visiblePVSystems, setvisiblePVSystems] = useState([]) + const [pvSystems, setPVSystems] = useState([]) // pvPoints are the red points that appear when drawing PV systems const [pvPoints, setPVPoints] = useState([]) @@ -70,8 +70,8 @@ function Index() { setSelectedMesh={setSelectedMesh} geometries={geometries} geoLocation={location} - setvisiblePVSystems={setvisiblePVSystems} - visiblePVSystems={visiblePVSystems} + setPVSystems={setPVSystems} + pvSystems={pvSystems} pvPoints={pvPoints} setPVPoints={setPVPoints} simulationMeshes={simulationMeshes} @@ -86,7 +86,8 @@ function Index() { simulationMeshes={simulationMeshes} showTerrain={showTerrain} frontendState={frontendState} - visiblePVSystems={visiblePVSystems} + pvSystems={pvSystems} + setPVSystems={setPVSystems} selectedMesh={selectedMesh} setSelectedMesh={setSelectedMesh} pvPoints={pvPoints} From 7eb36a2f68b47027074e21947e3f0b29aa8a8270 Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:29:56 +0200 Subject: [PATCH 02/10] Add calculation of savings #242 --- .../PVSimulation/SavingsCalculation.js | 210 +++++++++++++----- 1 file changed, 155 insertions(+), 55 deletions(-) diff --git a/src/components/PVSimulation/SavingsCalculation.js b/src/components/PVSimulation/SavingsCalculation.js index 959ae626..c3c17102 100644 --- a/src/components/PVSimulation/SavingsCalculation.js +++ b/src/components/PVSimulation/SavingsCalculation.js @@ -1,13 +1,9 @@ import { - Box, Button, - Checkbox, - CheckboxGroup, - Circle, - Flex, FormControl, FormLabel, Input, + ListItem, Modal, ModalBody, ModalCloseButton, @@ -15,66 +11,170 @@ import { ModalFooter, ModalHeader, ModalOverlay, - Radio, - RadioGroup, - Stack, + UnorderedList, useDisclosure, } from "@chakra-ui/react" - import React, { useState } from "react" import { useTranslation } from "react-i18next" +import HoverHelp from "../Template/HoverHelp" + +function SavingCalculation({ PVSystems }) { + const { isOpen, onOpen, onClose } = useDisclosure({ defaultIsOpen: false }) + const { t } = useTranslation() + const [annualConsumption, setAnnualConsumption] = useState("") + const [storageCapacity, setStorageCapacity] = useState("") + const [electricityPrice, setElectricityPrice] = useState(0.25) + const [selfConsumption, setSelfConsumption] = useState(0) + const [annualSavings, setAnnualSavings] = useState(0) + + async function handleCalculateSaving() { + async function calculateSaving({ + consumptionHousehold, + storageCapacity, + electricityPrice, + setSelfConsumption, + setAnnualSavings, + }) { + const pvProduction = 6000 + const response = await fetch( + "https://www.openpv.de/data/savings_calculation/cons_prod.json" + ) + const data = await response.json() + + const normalizedConsumption = data["Consumption"] + const normalizedProduction = data["Production"] + + const result = {} + let currentStorageLevel = 0 + for (const timestamp in normalizedConsumption) { + const consumptionValue = + (normalizedConsumption[timestamp] * consumptionHousehold) / 1000 + const productionValue = + (normalizedProduction[timestamp] * pvProduction) / 1000 + + let selfConsumption = 0 + let excessProduction = 0 + + if (productionValue > consumptionValue) { + selfConsumption = consumptionValue + excessProduction = productionValue - consumptionValue + + // Charge the storage + const availableStorageSpace = storageCapacity - currentStorageLevel + const chargedAmount = Math.min( + excessProduction, + availableStorageSpace + ) + currentStorageLevel += chargedAmount + } else { + const productionDeficit = consumptionValue - productionValue -function SavingCalculation() { - const { isOpen, onOpen, onClose } = useDisclosure({ defaultIsOpen: true }) - const [currentPage, setCurrentPage] = useState(1) - const { t, i18n } = useTranslation() + // Use storage if available + const usedFromStorage = Math.min( + productionDeficit, + currentStorageLevel + ) + currentStorageLevel -= usedFromStorage - const calculateSaving = () => { - console.log("Savings") + selfConsumption = productionValue + usedFromStorage + } + + result[timestamp] = selfConsumption + } + + let selfConsumedElectricity = Object.values(result).reduce( + (acc, val) => acc + val, + 0 + ) + + console.log( + selfConsumedElectricity, + "kWh are self consumed in the household" + ) + + setSelfConsumption(Math.round(selfConsumedElectricity)) + setAnnualSavings(Math.round(selfConsumedElectricity * electricityPrice)) + } + + await calculateSaving({ + consumptionHousehold: parseFloat(annualConsumption), + storageCapacity: storageCapacity, + electricityPrice: electricityPrice, + setSelfConsumption: setSelfConsumption, + setAnnualSavings: setAnnualSavings, + }) } + const initialRef = React.useRef(null) - const finalRef = React.useRef(null) - const [value, setValue] = React.useState("1") + console.log("PVSystems", PVSystems) return ( - - - - {"Wirtschaftlichkeit berechnen"} - - - <> - - Jährlicher Stromverbrauch - - -
- Wann verbrauche ich meinen Strom? - - - Morgens und Abends - Morgens, Mittags und Abends - - -
- Ich besitze oder plane den Kauf - - einer Wärmepumpe - eines Elektroautos - - -
- - - - -
-
+ <> + {PVSystems.length > 0 && ( + + )} + + + + {"Wirtschaftlichkeit berechnen"} + + + <> + + + Jährlicher Stromverbrauch{" "} + + + setAnnualConsumption(e.target.value)} + /> + +
+ + Stromspeicher + setStorageCapacity(e.target.value)} + /> + +
+ + Preis pro kWh in € + setElectricityPrice(e.target.value)} + /> + + +
+ + Eigenverbrauch: {selfConsumption} kWh + Jährliche Einsparungen: {annualSavings} € + + +
+ + + + +
+
+ ) } From 4311205971ec00e530e4c5d8508c1565b1a91dc8 Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:41:29 +0200 Subject: [PATCH 03/10] Use yield from pvSystem objects #242 --- .../PVSimulation/SavingsCalculation.js | 18 ++++++++++++++---- src/components/ThreeViewer/Overlay.js | 2 +- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/PVSimulation/SavingsCalculation.js b/src/components/PVSimulation/SavingsCalculation.js index c3c17102..adbae402 100644 --- a/src/components/PVSimulation/SavingsCalculation.js +++ b/src/components/PVSimulation/SavingsCalculation.js @@ -18,7 +18,7 @@ import React, { useState } from "react" import { useTranslation } from "react-i18next" import HoverHelp from "../Template/HoverHelp" -function SavingCalculation({ PVSystems }) { +function SavingCalculation({ pvSystems }) { const { isOpen, onOpen, onClose } = useDisclosure({ defaultIsOpen: false }) const { t } = useTranslation() const [annualConsumption, setAnnualConsumption] = useState("") @@ -26,16 +26,23 @@ function SavingCalculation({ PVSystems }) { const [electricityPrice, setElectricityPrice] = useState(0.25) const [selfConsumption, setSelfConsumption] = useState(0) const [annualSavings, setAnnualSavings] = useState(0) + let pvProduction + console.log("pvSystems", pvSystems) + if (pvSystems.length > 0) { + pvProduction = Math.round( + pvSystems.reduce((previous, current) => previous + current.annualYield, 0) + ) + } async function handleCalculateSaving() { async function calculateSaving({ + pvProduction, consumptionHousehold, storageCapacity, electricityPrice, setSelfConsumption, setAnnualSavings, }) { - const pvProduction = 6000 const response = await fetch( "https://www.openpv.de/data/savings_calculation/cons_prod.json" ) @@ -97,6 +104,7 @@ function SavingCalculation({ PVSystems }) { } await calculateSaving({ + pvProduction: pvProduction, consumptionHousehold: parseFloat(annualConsumption), storageCapacity: storageCapacity, electricityPrice: electricityPrice, @@ -106,11 +114,10 @@ function SavingCalculation({ PVSystems }) { } const initialRef = React.useRef(null) - console.log("PVSystems", PVSystems) return ( <> - {PVSystems.length > 0 && ( + {pvSystems.length > 0 && ( @@ -161,6 +168,9 @@ function SavingCalculation({ PVSystems }) {
+ + Jährliche Stromerzeugung durch PV: {pvProduction} kWh + Eigenverbrauch: {selfConsumption} kWh Jährliche Einsparungen: {annualSavings} € diff --git a/src/components/ThreeViewer/Overlay.js b/src/components/ThreeViewer/Overlay.js index dc58db82..3873c4f5 100644 --- a/src/components/ThreeViewer/Overlay.js +++ b/src/components/ThreeViewer/Overlay.js @@ -132,7 +132,7 @@ function Overlay({ /> - + ) From efe166ca98c6960b2c9ca7c94b850b72e8427c99 Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:43:05 +0200 Subject: [PATCH 04/10] Delete unnecessary logging #242 --- src/components/PVSimulation/SavingsCalculation.js | 6 ------ src/components/ThreeViewer/Meshes/PVSystems.js | 4 ---- src/simulation/main.js | 2 -- 3 files changed, 12 deletions(-) diff --git a/src/components/PVSimulation/SavingsCalculation.js b/src/components/PVSimulation/SavingsCalculation.js index adbae402..fb6daf15 100644 --- a/src/components/PVSimulation/SavingsCalculation.js +++ b/src/components/PVSimulation/SavingsCalculation.js @@ -27,7 +27,6 @@ function SavingCalculation({ pvSystems }) { const [selfConsumption, setSelfConsumption] = useState(0) const [annualSavings, setAnnualSavings] = useState(0) let pvProduction - console.log("pvSystems", pvSystems) if (pvSystems.length > 0) { pvProduction = Math.round( pvSystems.reduce((previous, current) => previous + current.annualYield, 0) @@ -94,11 +93,6 @@ function SavingCalculation({ pvSystems }) { 0 ) - console.log( - selfConsumedElectricity, - "kWh are self consumed in the household" - ) - setSelfConsumption(Math.round(selfConsumedElectricity)) setAnnualSavings(Math.round(selfConsumedElectricity * electricityPrice)) } diff --git a/src/components/ThreeViewer/Meshes/PVSystems.js b/src/components/ThreeViewer/Meshes/PVSystems.js index 85f28508..f1036c0d 100644 --- a/src/components/ThreeViewer/Meshes/PVSystems.js +++ b/src/components/ThreeViewer/Meshes/PVSystems.js @@ -5,7 +5,6 @@ import * as BufferGeometryUtils from "three/addons/utils/BufferGeometryUtils.js" import TextSprite from "../TextSprite" export const PVSystems = ({ pvSystems }) => { - console.log("PVSystems in three module", pvSystems) return ( <> {pvSystems.map((system, index) => ( @@ -145,7 +144,6 @@ export function createPVSystem({ annualYield: annualYield, area: polygonArea, } - console.log("newPVSystem", newPVSystem) setPVSystems((prevSystems) => [...prevSystems, newPVSystem]) setPVPoints([]) @@ -341,8 +339,6 @@ function filterPolygonsByDistance(geometry, points, threshold) { } } - console.log("Filtered polygons:", filteredPolygons) - return filteredPolygons } diff --git a/src/simulation/main.js b/src/simulation/main.js index a77aac78..d17f3f1f 100644 --- a/src/simulation/main.js +++ b/src/simulation/main.js @@ -48,7 +48,6 @@ export async function mainSimulation(location) { ? (numSimulations = window.numSimulations) : (numSimulations = 80) function loadingBarWrapperFunction(progress, total = 100) { - // console.log("Simulation Progress is ", progress) return window.setSimulationProgress(progress) } @@ -126,7 +125,6 @@ export async function simulationForNewBuilding(props) { progressCallback: (progress, total) => console.log("Simulation Progress is ", progress), }) - console.log("SimulationMesh", simulationMesh) const material = new THREE.MeshLambertMaterial({ vertexColors: true, side: THREE.DoubleSide, From 5351b05fc4bc5ce35abe253aabfc6d6837a47ded Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:56:07 +0200 Subject: [PATCH 05/10] Delete outdated comment #242 --- src/pages/Simulation.js | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/pages/Simulation.js b/src/pages/Simulation.js index fcbff248..139c7c23 100644 --- a/src/pages/Simulation.js +++ b/src/pages/Simulation.js @@ -33,12 +33,9 @@ function Index() { surrounding: [], background: [], }) - + // highlighted meshes for resimulation const [selectedMesh, setSelectedMesh] = useState([]) - - // When a building is selected from the Surrounding to be simulated, it needs to be deleted - // from the surrounding mesh. This state collects a list of names that should not be rendered - // Elements are for example "SurroundingMesh-37" + // meshes that were simulated const [simulationMeshes, setSimulationMeshes] = useState([]) window.setGeometries = setGeometries From 19cbddefb522890a763ee51fd7b6f783dd8e9ca8 Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 14:57:36 +0200 Subject: [PATCH 06/10] Move OverlayDrawPV to Overlay #242 --- src/components/ThreeViewer/Overlay.js | 55 +++++++++++++++++++ src/components/ThreeViewer/OverlayDrawPV.js | 58 --------------------- 2 files changed, 55 insertions(+), 58 deletions(-) delete mode 100644 src/components/ThreeViewer/OverlayDrawPV.js diff --git a/src/components/ThreeViewer/Overlay.js b/src/components/ThreeViewer/Overlay.js index 3873c4f5..d05e5d4c 100644 --- a/src/components/ThreeViewer/Overlay.js +++ b/src/components/ThreeViewer/Overlay.js @@ -28,6 +28,7 @@ import SavingCalculation from "../PVSimulation/SavingsCalculation" import ButtonWithHoverHelp from "../Template/ButtonWithHoverHelp" import HoverHelp from "../Template/HoverHelp" import SliderWithLabel from "../Template/SliderWithLabel" +import { createPVSystem } from "./Meshes/PVSystems" import OverlayDrawPV from "./OverlayDrawPV" function Overlay({ @@ -295,3 +296,57 @@ const ModalControls = ({ isOpen, onClose }) => { ) } + +function OverlayDrawPV({ + setPVSystems, + pvPoints, + setPVPoints, + setFrontendState, + simulationMeshes, +}) { + const { t } = useTranslation() + const handleCreatePVButtonClick = () => { + createPVSystem({ + setPVSystems, + pvPoints, + setPVPoints, + simulationMeshes, + }) + setFrontendState("Results") + } + + const handleAbortButtonClick = () => { + setFrontendState("Results") + } + + return ( + <> + + {pvPoints.length > 0 && ( + + )} + + + ) +} diff --git a/src/components/ThreeViewer/OverlayDrawPV.js b/src/components/ThreeViewer/OverlayDrawPV.js deleted file mode 100644 index b01ff422..00000000 --- a/src/components/ThreeViewer/OverlayDrawPV.js +++ /dev/null @@ -1,58 +0,0 @@ -import { Button } from "@chakra-ui/react" -import React from "react" -import { useTranslation } from "react-i18next" -import { createPVSystem } from "./Meshes/PVSystems" - -export default function OverlayDrawPV({ - setPVSystems, - pvPoints, - setPVPoints, - setFrontendState, - simulationMeshes, -}) { - const { t } = useTranslation() - const handleCreatePVButtonClick = () => { - createPVSystem({ - setPVSystems, - pvPoints, - setPVPoints, - simulationMeshes, - }) - setFrontendState("Results") - } - - const handleAbortButtonClick = () => { - setFrontendState("Results") - } - - return ( - <> - - {pvPoints.length > 0 && ( - - )} - - - ) -} From 9b3d63f12510dc07f4ad9306e3485a547ecd6475 Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 15:01:56 +0200 Subject: [PATCH 07/10] Delete import of moved component #242 --- src/components/ThreeViewer/Overlay.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/components/ThreeViewer/Overlay.js b/src/components/ThreeViewer/Overlay.js index d05e5d4c..b5729615 100644 --- a/src/components/ThreeViewer/Overlay.js +++ b/src/components/ThreeViewer/Overlay.js @@ -29,7 +29,6 @@ import ButtonWithHoverHelp from "../Template/ButtonWithHoverHelp" import HoverHelp from "../Template/HoverHelp" import SliderWithLabel from "../Template/SliderWithLabel" import { createPVSystem } from "./Meshes/PVSystems" -import OverlayDrawPV from "./OverlayDrawPV" function Overlay({ frontendState, From 98e0f082acada179bf57bd53da92cc97bf6b7802 Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 17:08:31 +0200 Subject: [PATCH 08/10] Change color schema again #242 --- src/simulation/main.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/simulation/main.js b/src/simulation/main.js index d17f3f1f..8689d8e5 100644 --- a/src/simulation/main.js +++ b/src/simulation/main.js @@ -4,6 +4,9 @@ import { mergeGeometries } from "three/examples/jsm/utils/BufferGeometryUtils.js import { downloadBuildings } from "./download" import { processGeometries } from "./preprocessing" +const c0 = [0, 0.05, 0.2] +const c1 = [1, 0.1, 0.1] + export async function mainSimulation(location) { // Clear previous attributions if any if (window.setAttribution) { @@ -39,9 +42,7 @@ export async function mainSimulation(location) { scene.addShadingGeometry(geom) }) - scene.addColorMap( - colormaps.interpolateTwoColors({ c0: [0.1, 0.2, 1], c1: [1, 1, 0.1] }) - ) + scene.addColorMap(colormaps.interpolateTwoColors({ c0: c0, c1: c1 })) let numSimulations window.numSimulations @@ -99,9 +100,7 @@ export async function simulationForNewBuilding(props) { parseFloat(props.geoLocation.lat), parseFloat(props.geoLocation.lon) ) - shadingScene.addColorMap( - colormaps.interpolateTwoColors({ c0: [0.1, 0.2, 1], c1: [1, 1, 0.1] }) - ) + shadingScene.addColorMap(colormaps.interpolateTwoColors({ c0: c0, c1: c1 })) shadingScene.addSimulationGeometry(newSimulationGeometries) geometries.surrounding.forEach((geom) => { shadingScene.addShadingGeometry(geom) From 6a2d403dbf83e91274465df2dd4d8a9863d6c995 Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 17:12:52 +0200 Subject: [PATCH 09/10] Change color of PV points #242 --- src/components/ThreeViewer/Points.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/ThreeViewer/Points.js b/src/components/ThreeViewer/Points.js index a9f5c0aa..2f69f44a 100644 --- a/src/components/ThreeViewer/Points.js +++ b/src/components/ThreeViewer/Points.js @@ -8,7 +8,7 @@ const Points = ({ points }) => { point.point, ]) const pointMaterial = new THREE.PointsMaterial({ - color: 0xff0000, + color: "#333333", size: 5, sizeAttenuation: false, }) From 599b57ef90696da8f4d589de4535c89fe4280568 Mon Sep 17 00:00:00 2001 From: Florian Kotthoff <74312290+FlorianK13@users.noreply.github.com> Date: Sat, 31 Aug 2024 17:16:44 +0200 Subject: [PATCH 10/10] Add disclaimer and translations #242 --- public/locales/de/translation.json | 17 +++++++ public/locales/en/translation.json | 17 +++++++ .../PVSimulation/SavingsCalculation.js | 46 ++++++++++++------- 3 files changed, 63 insertions(+), 17 deletions(-) diff --git a/public/locales/de/translation.json b/public/locales/de/translation.json index 4dbee1b1..0226e631 100644 --- a/public/locales/de/translation.json +++ b/public/locales/de/translation.json @@ -94,5 +94,22 @@ "wheel": "Zwei Finger: Vergrößern und Verkleinern", "doubleClick": "Zweimal kurz auf Gebäude tippen: Weiteres Gebäude für Simulation auswählen" } + }, + "savingsCalculation": { + "button": "Wirtschaftlichkeit der Anlage berechnen", + "consumptionTitle": "Jährlicher Stromverbrauch", + "consumptionHelper": "Als grober Schätzwert gilt: Rechne pro Person im Haushalt mit 800 kWh, für eine Wärmepumpe 2000 kWh und pro Elektroauto weitere 2000 kWh.", + "consumptionPlaceholder": "Jährlicher Stromverbrauch in kWh", + "storageTitle": "Stromspeicher", + "storagePlaceholder": "Speicherkapazität in kWh", + "electricityPriceTitle": "Strompreis in cent", + "electricityPricePlaceholder": "Preis pro kWh in cent", + "disclaimer": "Die berechneten Erträge und Einsparungen dienen nur als grobe Orientierung. Die Angaben sind ohne Gewähr und ersetzen keine individuelle Berechnung und Beratung vor Ort!", + "results": { + "production": "Jährliche Stromerzeugung der Solaranlage: ", + "consumption": "Jährlicher Eigenverbrauch: ", + "savings": "Jährliche Einsparungen: " + }, + "calculate": "Berechnen" } } diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index a7e50a28..ba0c8941 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -76,5 +76,22 @@ "wheel": "Two fingers: Zoom in and out", "doubleClick": "Double-tap on a building: Select another building for simulation" } + }, + "savingsCalculation": { + "button": "Calculate Earnings", + "consumptionTitle": "Annual electricity consumption", + "consumptionHelper": "As a rough estimate: Calculate 800 kWh per person in the household, 2000 kWh for a heat pump, and an additional 2000 kWh per electric car.", + "consumptionPlaceholder": "Annual electricity consumption in kWh", + "storageTitle": "Electricity storage", + "storagePlaceholder": "Storage capacity in kWh", + "electricityPriceTitle": "Electricity price in cents", + "electricityPricePlaceholder": "Price per kWh in cents", + "disclaimer": "The calculated yields and savings are only for rough guidance. The information is without guarantee and does not replace individual calculation and on-site consultation!", + "results": { + "production": "Annual electricity generation of the solar system: ", + "consumption": "Annual self-consumption: ", + "savings": "Annual savings: " + }, + "calculate": "Calculate" } } diff --git a/src/components/PVSimulation/SavingsCalculation.js b/src/components/PVSimulation/SavingsCalculation.js index fb6daf15..4bb93f35 100644 --- a/src/components/PVSimulation/SavingsCalculation.js +++ b/src/components/PVSimulation/SavingsCalculation.js @@ -11,6 +11,7 @@ import { ModalFooter, ModalHeader, ModalOverlay, + Text, UnorderedList, useDisclosure, } from "@chakra-ui/react" @@ -23,7 +24,7 @@ function SavingCalculation({ pvSystems }) { const { t } = useTranslation() const [annualConsumption, setAnnualConsumption] = useState("") const [storageCapacity, setStorageCapacity] = useState("") - const [electricityPrice, setElectricityPrice] = useState(0.25) + const [electricityPrice, setElectricityPrice] = useState(25) const [selfConsumption, setSelfConsumption] = useState(0) const [annualSavings, setAnnualSavings] = useState(0) let pvProduction @@ -94,7 +95,9 @@ function SavingCalculation({ pvSystems }) { ) setSelfConsumption(Math.round(selfConsumedElectricity)) - setAnnualSavings(Math.round(selfConsumedElectricity * electricityPrice)) + setAnnualSavings( + Math.round((selfConsumedElectricity * electricityPrice) / 100) + ) } await calculateSaving({ @@ -113,7 +116,7 @@ function SavingCalculation({ pvSystems }) { <> {pvSystems.length > 0 && ( )} @@ -125,55 +128,64 @@ function SavingCalculation({ pvSystems }) { <> - Jährlicher Stromverbrauch{" "} + {t("savingsCalculation.consumptionTitle")} setAnnualConsumption(e.target.value)} />
- Stromspeicher + {t("savingsCalculation.storageTitle")} setStorageCapacity(e.target.value)} />
- Preis pro kWh in € + + {t("savingsCalculation.electricityPriceTitle")} + setElectricityPrice(e.target.value)} />
+ {t("savingsCalculation.disclaimer")} - Jährliche Stromerzeugung durch PV: {pvProduction} kWh + {t("savingsCalculation.results.production")} + {pvProduction} kWh + + + {t("savingsCalculation.results.consumption")}{" "} + {selfConsumption} kWh + + + {t("savingsCalculation.results.savings")} {annualSavings} € - Eigenverbrauch: {selfConsumption} kWh - Jährliche Einsparungen: {annualSavings} € -