Solar & Acoustics
Solar Vector Calculations & Shadow Envelopes: In bioclimatic architecture, passive solar heating and daylighting require precise geometric tracking of the sun's path. Given geographic latitude and time of year, solar altitude $\theta$ and azimuth $\phi$ yield a unit ray vector. Projecting building roof cornices along this vector reveals shadow polygons cast onto neighboring structures and streets.
Solar Projection Invariant:
1import numpy as np23def compute_solar_vector(altitude_deg, azimuth_deg):4 """5 Computes unit sun vector pointing towards the sun.6 Altitude: angle above horizon [0, 90].7 Azimuth: clockwise angle from North [0, 360].8 """9 alt = np.radians(altitude_deg)10 az = np.radians(azimuth_deg)1112 # Coordinates in East-North-Up frame:13 sx = np.cos(alt) * np.sin(az) # East14 sy = np.cos(alt) * np.cos(az) # North15 sz = np.sin(alt) # Up (Zenith)16 return np.array([sx, sy, sz])1718def project_shadow_polygon(roof_polygon, sun_vec, ground_z=0.0):19 """20 Projects shadow of 3D roof vertices onto ground plane along solar vector.21 P_ground = P - (P_z - ground_z) / sun_vec_z * sun_vec22 """23 shadow = []24 for pt in roof_polygon:25 t = (pt[2] - ground_z) / sun_vec[2]26 shadow_pt = pt - t * sun_vec27 shadow.append(shadow_pt)28 return shadow
Architectural Acoustics & Specular Ray Tracing: In symphony halls and auditoriums, sound waves travel through air and reflect off curved ceiling canopies. Under high-frequency geometric acoustics (where wavelength is small relative to panel dimensions), sound behaves like optical rays: the angle of incidence equals the angle of reflection ($\theta_r = \theta_i$). Tuning ceiling curvature ensures even sound dispersion to rear balcony seats without acoustic flutter echoes or caustic focal hotspots.
Acoustic Ray Invariant:
1import numpy as np23def reflect_acoustic_ray(ray_origin, ray_dir, surface_normal):4 """5 Computes specular sound ray reflection vector (Snell's Law of Acoustics).6 Angle of incidence theta_i equals angle of reflection theta_r.7 r = d - 2 * (d . n) * n8 """9 n = surface_normal / np.linalg.norm(surface_normal)10 d = ray_dir / np.linalg.norm(ray_dir)11 r = d - 2.0 * np.dot(d, n) * n12 return r