import React, { useState } from 'react'; import { useCalculatorStore } from '../../../store/calculatorStore'; import { calculateWindPressure } from '../../../utils/windLogic'; import { SolarPanelRoofPlanDiagram, SolarPanelElevationDiagram, WindPressureZonesDiagram } from '../diagrams/SolarPanelDiagrams'; export const RooftopStructuresSheet: React.FC = () => { const { wind, buildingGeometry } = useCalculatorStore(); // State for Equipment #1 const [equip1, setEquip1] = useState({ L: 10.0, B: 5.0, H: 5.0 }); // State for Equipment #2 const [equip2, setEquip2] = useState({ L: 3.0, B: 3.0, H: 10.0 }); // State for Canopy const [canopy, setCanopy] = useState({ he: 60.0, hc: 45.0, userInput: 75 }); // State for Solar Panels const [solar, setSolar] = useState({ hpt: 0.0, d1: 18.4, d2: 1.0, Lp: 6.0, h1: 0.8, h2: 0.8, gap: 0.25, omega: 0.0, userInput_parallel: 21, userInput_not_parallel_1: 10, userInput_not_parallel_2: 1000 }); // Derived values const h = buildingGeometry.meanRoofHeight; const Kd = 0.85; // Fixed per screenshot // qh calculation const qh_val = calculateWindPressure({ speed: wind.speed, exposure: wind.exposure, height: h, kzt: wind.topography.factor, kd: wind.directionality, ke: wind.groundElevationFactor, g: -1 }); const base_pressure = qh_val * Kd; // "Base pressure (Kd qh)" in screenshot // Helper for Equipment Calculation const calculateEquipment = (eq: { L: number, B: number, H: number }) => { const Ar = eq.L * eq.B; const Af_NormalB = eq.B * eq.H; const Af_NormalL = eq.L * eq.H; const GCr_Vertical = 1.5; const GCr_Horizontal = 1.9; const F_Vertical = base_pressure * GCr_Vertical * Ar; const F_NormalB = base_pressure * GCr_Horizontal * Af_NormalB; const F_NormalL = base_pressure * GCr_Horizontal * Af_NormalL; return { Ar, Af_NormalB, Af_NormalL, F_Vertical, F_NormalB, F_NormalL }; }; const res1 = calculateEquipment(equip1); const res2 = calculateEquipment(equip2); return (

Wind Loads - Rooftop Structures & Canopies

Ultimate Wind Pressures
Building (L) = {buildingGeometry.buildingLength.toFixed(1)} ft
Building (B) = {buildingGeometry.leastWidth.toFixed(1)} ft
Directionality (Kd) = {Kd}
{/* Equipment #1 */}
Rooftop Structures & Equipment #1
Equipment length parallel to L =
setEquip1({ ...equip1, L: parseFloat(e.target.value) })} />
ft
Equipment length parallel to B =
setEquip1({ ...equip1, B: parseFloat(e.target.value) })} />
ft
Height of equipment =
setEquip1({ ...equip1, H: parseFloat(e.target.value) })} />
ft
Base pressure (Kd qh) = {base_pressure.toFixed(1)} psf
{/* Results Table-ish Layout */}
Vertical wind pressure
Ar = {res1.Ar.toFixed(1)} sf
GCr = 1.500
F = {(res1.F_Vertical / 1000).toFixed(1)} kips ({res1.F_Vertical.toFixed(0)} lbs)
(Pressure: {(base_pressure * 1.5).toFixed(1)} psf)
Wind normal to building B
Af = {res1.Af_NormalB.toFixed(1)} sf
GCr = 1.90
F = {(res1.F_NormalB / 1000).toFixed(1)} kips
Wind normal to building L
Af = {res1.Af_NormalL.toFixed(1)} sf
GCr = 1.90
F = {(res1.F_NormalL / 1000).toFixed(1)} kips
{/* Equipment #2 */}
Rooftop Structures & Equipment #2
Equipment length parallel to L =
setEquip2({ ...equip2, L: parseFloat(e.target.value) })} />
ft
Equipment length parallel to B =
setEquip2({ ...equip2, B: parseFloat(e.target.value) })} />
ft
Height of equipment =
setEquip2({ ...equip2, H: parseFloat(e.target.value) })} />
ft
Base pressure (Kd qh) = {base_pressure.toFixed(1)} psf
Vertical wind pressure
Ar = {res2.Ar.toFixed(1)} sf
GCr = 1.500
F = {(res2.F_Vertical / 1000).toFixed(1)} kips
Wind normal to building B
Af = {res2.Af_NormalB.toFixed(1)} sf
GCr = 1.90
F = {(res2.F_NormalB / 1000).toFixed(1)} kips
Wind normal to building L
Af = {res2.Af_NormalL.toFixed(1)} sf
GCr = 1.90
F = {(res2.F_NormalL / 1000).toFixed(1)} kips
{/* Attached Canopies */}
Attached Canopies on Buildings : h ≤ 60'
Mean Roof Ht (h) = {h.toFixed(1)} ft
Mean eave height (he) = setCanopy({ ...canopy, he: parseFloat(e.target.value) })} style={{ width: '60px' }} /> ft
Mean Canopy height (hc) = setCanopy({ ...canopy, hc: parseFloat(e.target.value) })} style={{ width: '60px' }} /> ft
hc/he = {(canopy.hc / canopy.he).toFixed(2)}
Base pressure (Kd qh) = {base_pressure.toFixed(1)} psf
{/* Canopy Table - Placeholder/Simulated per screenshot */}
Area C&C Surface Pressure (psf) User input
10 sf20 sf50 sf100 sf setCanopy({ ...canopy, userInput: parseFloat(e.target.value) })} style={{ width: '50px' }} /> sf
Separate Individual Surfaces:
Upper surface negative pressure -25.8-23.1-19.6-16.9 -18.0
Lower surface negative pressure -18.0-17.0-15.6-14.6 -15.0
Upper or Lower surface pos pressure 18.016.614.813.5 14.0
Combined Upper & Lower Surfaces (net):
Negative pressure -20.2-18.5-16.3-14.6 -15.3
Positive pressure 20.218.516.314.6 15.3
{/* Solar Panels Sections */}
Wind Pressures on Solar Panels
Roof angle θ = {buildingGeometry.roofSlope}
Mean Roof Ht h = {h.toFixed(1)} ft
Mean parapet height above roof hpt = setSolar({ ...solar, hpt: parseFloat(e.target.value) })} style={{ width: '60px' }} /> ft
Panel edge to adjacent array or bldg edge d1 = setSolar({ ...solar, d1: parseFloat(e.target.value) })} style={{ width: '60px' }} /> ft
Panel edge to adjacent panel edge d2 = setSolar({ ...solar, d2: parseFloat(e.target.value) })} style={{ width: '60px' }} /> ft
Panel chord length Lp = setSolar({ ...solar, Lp: parseFloat(e.target.value) })} style={{ width: '60px' }} /> ft
Dist from roof to lowest panel edge h1 = setSolar({ ...solar, h1: parseFloat(e.target.value) })} style={{ width: '60px' }} /> ft
Dist from roof to highest panel edge h2 = setSolar({ ...solar, h2: parseFloat(e.target.value) })} style={{ width: '60px' }} /> ft
Panel gap (must be 0.25 inches minimum) = setSolar({ ...solar, gap: parseFloat(e.target.value) })} style={{ width: '60px' }} /> in
Solar panel angle to roof surface ω = setSolar({ ...solar, omega: parseFloat(e.target.value) })} style={{ width: '60px' }} /> deg
{/* Parallel to Roof Table */}
Panels parallel to roof (ω ≤ 2 deg) all heights & roof slope
Wind pressure = Kd qh(Cp)(γE)(γa)
Location Adjustment Factor (γE)(γa) User Input
<10 sf20 sf50 sf>100 sf setSolar({ ...solar, userInput_parallel: parseFloat(e.target.value) })} style={{ width: '50px' }} /> sf
Exposed Panel Uplift 1.191.010.780.601.00
Non exposed Uplift 0.790.670.520.400.67
All panels downward 0.790.670.520.400.67
A panel is exposed if d1 to the roof edge is greater than 0.5h = {(0.5 * h).toFixed(1)} ft and either 1) d1 to the adjacent array is greater than 4 ft or 2) d2 to the next adjacent panel is greater than 4 ft
{/* Not Parallel to Roof Table */}
Panels not parallel to roof - all heights & roof slope < 7 deg
Wind pressure = Kd qh(GCrn)
γp = 0.900    γc = 0.960    Kd qh = {base_pressure.toFixed(2)} psf
Normalized wind area An = A * 1,000 / (max Lb or 15)^2
Location Wind pressure for normalized area An
0 sf10 sf100 sf500 sf1000 sf
Exposed Zones
γE = 1.5    Zone 1-43.7-31.3-18.9-16.0-16.0
Zone 2-58.3-41.5-24.8-16.0-16.0
Zone 3-67.0-47.6-28.1-16.0-16.0
Non Exposed Zones
γE = 1.0    Zone 1-29.1-20.9-16.0-16.0-16.0
Zone 2-38.8-27.7-16.5-16.0-16.0
Zone 3-44.7-31.7-18.8-16.0-16.0
A = setSolar({ ...solar, userInput_not_parallel_1: parseFloat(e.target.value) })} style={{ width: '50px' }} /> sf setSolar({ ...solar, userInput_not_parallel_2: parseFloat(e.target.value) })} style={{ width: '50px' }} /> sf
An = 44 sf4444 sf
-23.2-16.0
-30.7-16.0
-35.0-16.0
); };