// phys.js — модуль физических хелперов для учебника Физика 10 // Экспорт в window.PHYS = { ... } (function(){ 'use strict'; // === Стрелка вектора (2D) === function drawArrow(x1, y1, x2, y2, color, width, headSize) { width = width || 2; headSize = headSize || 10; const dx = x2 - x1, dy = y2 - y1; const len = Math.sqrt(dx*dx + dy*dy); if (len < 1e-6) return ''; const ux = dx / len, uy = dy / len; const px = -uy, py = ux; const h = headSize, w = headSize * 0.6; const bx = x2 - ux*h, by = y2 - uy*h; const lx = bx + px*w, ly = by + py*w; const rx = bx - px*w, ry = by - py*w; return `` + ``; } // === Линии электрического поля от точечного заряда === function fieldLinesPointCharge(cx, cy, sign, scale, numLines) { numLines = numLines || 16; scale = scale || 80; let s = ''; const color = sign > 0 ? '#dc2626' : '#2563eb'; for (let i = 0; i < numLines; i++) { const a = 2 * Math.PI * i / numLines; const r1 = 18, r2 = scale; const x1 = cx + r1*Math.cos(a), y1 = cy + r1*Math.sin(a); const x2 = cx + r2*Math.cos(a), y2 = cy + r2*Math.sin(a); if (sign > 0) s += drawArrow(x1, y1, x2, y2, color, 1.4, 7); else s += drawArrow(x2, y2, x1, y1, color, 1.4, 7); } return s; } // === Обозначение заряда (кружок с +/-) === function chargeMark(cx, cy, sign, r, label) { r = r || 14; const color = sign > 0 ? '#dc2626' : '#2563eb'; const fill = sign > 0 ? '#fecaca' : '#bfdbfe'; let s = ''; s += ``; if (sign > 0) { s += ``; s += ``; } else { s += ``; } if (label) { s += `${label}`; } return s; } // === Магнитное поле сквозь экран (сетка крестиков или точек) === function magneticFieldGrid(x0, y0, w, h, cols, rows, direction) { // direction: 'in' = крест (× — вошло в плоскость), 'out' = точка (• — вышло) let s = ''; const dx = w / (cols - 1), dy = h / (rows - 1); const color = '#7c3aed'; for (let i = 0; i < cols; i++) { for (let j = 0; j < rows; j++) { const cx = x0 + i * dx, cy = y0 + j * dy; s += ``; if (direction === 'in') { s += ``; s += ``; } else { s += ``; } } } return s; } // === Молекула газа (частица) === function molecule(x, y, r, color) { r = r || 4; color = color || '#2563eb'; return ``; } // === Симуляция газа (упругое столкновение со стенками) === function createGasSim(opts) { opts = opts || {}; const N = opts.N || 30; const W = opts.W || 320; const H = opts.H || 220; const baseSpeed = opts.speed || 60; // px/s const r = opts.r || 4; const particles = []; for (let i = 0; i < N; i++) { particles.push({ x: r + Math.random() * (W - 2*r), y: r + Math.random() * (H - 2*r), vx: (Math.random() - 0.5) * 2 * baseSpeed, vy: (Math.random() - 0.5) * 2 * baseSpeed }); } return { W: W, H: H, r: r, particles: particles, step(dt) { for (const p of particles) { p.x += p.vx * dt; p.y += p.vy * dt; if (p.x < r) { p.x = r; p.vx = -p.vx; } if (p.x > W - r) { p.x = W - r; p.vx = -p.vx; } if (p.y < r) { p.y = r; p.vy = -p.vy; } if (p.y > H - r) { p.y = H - r; p.vy = -p.vy; } } }, render(color) { color = color || '#2563eb'; return particles.map(p => molecule(p.x, p.y, r, color)).join(''); }, setSpeed(scale) { for (const p of particles) { p.vx *= scale; p.vy *= scale; } } }; } // === Электрические схемы: компоненты === // orientation: 'h' (горизонтально, по умолчанию) или 'v' (вертикально) function batteryEMF(x, y, EMF, orientation) { orientation = orientation || 'h'; let s = ''; if (orientation === 'h') { s += ``; s += ``; s += `+`; s += ``; if (EMF !== undefined) s += `ε = ${EMF}`; } else { s += ``; s += ``; if (EMF !== undefined) s += `ε = ${EMF}`; } return s; } function resistor(x, y, R, orientation) { orientation = orientation || 'h'; let s = ''; if (orientation === 'h') { s += ``; if (R !== undefined) s += `R = ${R}`; } else { s += ``; if (R !== undefined) s += `R = ${R}`; } return s; } function capacitorSymbol(x, y, C, orientation) { orientation = orientation || 'h'; let s = ''; if (orientation === 'h') { s += ``; s += ``; if (C !== undefined) s += `C = ${C}`; } return s; } function ammeterSymbol(x, y, r) { r = r || 14; return `` + `A`; } function voltmeterSymbol(x, y, r) { r = r || 14; return `` + `V`; } function lightbulbSymbol(x, y, r) { r = r || 14; let s = ''; s += ``; s += ``; s += ``; return s; } function inductorSymbol(x, y, L, orientation) { orientation = orientation || 'h'; let s = ''; if (orientation === 'h') { for (let i = 0; i < 4; i++) { const cx = x - 15 + i * 10; s += ``; } if (L !== undefined) s += `L = ${L}`; } return s; } function wire(x1, y1, x2, y2) { return ``; } // === Эталонные константы === const CONST = { k: 9e9, // Кулона e: 1.6e-19, // элементарный заряд eps0: 8.85e-12, // электрическая постоянная kB: 1.38e-23, // Больцмана NA: 6.022e23, // Авогадро R: 8.314, // универсальная газовая c: 3e8, // скорость света g: 9.8, // ускорение свободного падения atm: 101325, // 1 атм в Па T0: 273.15 // ноль Цельсия в К }; // === Конвертеры единиц === function celsiusToKelvin(t) { return t + 273.15; } function kelvinToCelsius(T) { return T - 273.15; } function atmToPa(p) { return p * 101325; } function paToAtm(p) { return p / 101325; } function litersToM3(V) { return V / 1000; } function m3ToLiters(V) { return V * 1000; } // === Расширения для Физики 8 (тепловые явления) === // === Цвет по температуре: 240° (синий) → 0° (красный) === function tempColor(t, tMin, tMax) { const u = Math.max(0, Math.min(1, (t - tMin) / (tMax - tMin))); const hue = 240 * (1 - u); return `hsl(${hue.toFixed(0)},72%,52%)`; } // === Термометр (вертикальная шкала, столбик ртути по температуре) === function thermometer(x, y, h, tMin, tMax, tValue) { // x, y — верх корпуса; h — высота столбика const reservoirR = 11; const tubeW = 8; const u = Math.max(0, Math.min(1, (tValue - tMin) / (tMax - tMin))); const fillH = h * u; const color = tempColor(tValue, tMin, tMax); let s = ''; // Корпус (стекло) s += ``; // Столбик ртути s += ``; // Резервуар s += ``; // Деления (5) for (let i = 0; i <= 5; i++) { const ty = y + h * i / 5; const tv = tMax - (tMax - tMin) * i / 5; s += ``; s += `${tv.toFixed(0)}`; } // Подпись текущего значения s += `${tValue.toFixed(0)} °C`; return s; } // === Калориметр-стакан с жидкостью === function calorimeter(x, y, w, h, fillFrac, liquidColor) { fillFrac = Math.max(0, Math.min(1, fillFrac || 0.6)); liquidColor = liquidColor || '#60a5fa'; const wall = 4; const innerH = h - wall; const liqH = innerH * fillFrac; let s = ''; // Внешний контур s += ``; // Жидкость s += ``; // Мениск s += ``; return s; } // === Симуляция теплопроводности по стержню (одномерное уравнение тепла) === // Возвращает объект с .step(dt), .render(x, y, w, h), .reset(), .setTHot(t), .setTCold(t) function createHeatBar(opts) { opts = opts || {}; const N = opts.N || 30; const tHot = opts.tHot != null ? opts.tHot : 200; const tCold = opts.tCold != null ? opts.tCold : 0; const alpha = opts.alpha || 0.25; // коэф. диффузии (отн. ед.) const T = new Array(N); for (let i = 0; i < N; i++) T[i] = tCold; return { N: N, alpha: alpha, T: T, _tHot: tHot, _tCold: tCold, setTHot(v) { this._tHot = v; }, setTCold(v) { this._tCold = v; }, reset() { for (let i = 0; i < this.N; i++) this.T[i] = this._tCold; }, step(dt) { // Конечно-разностное уравнение теплопроводности с граничными условиями Дирихле. const Tnew = new Array(this.N); Tnew[0] = this._tHot; Tnew[this.N - 1] = this._tCold; for (let i = 1; i < this.N - 1; i++) { Tnew[i] = this.T[i] + this.alpha * dt * (this.T[i-1] - 2*this.T[i] + this.T[i+1]); } this.T = Tnew; }, render(x, y, w, h) { const segW = w / this.N; const tMin = Math.min(this._tCold, this._tHot); const tMax = Math.max(this._tCold, this._tHot); let s = ''; for (let i = 0; i < this.N; i++) { const c = tempColor(this.T[i], tMin, tMax); s += ``; } // Контур стержня s += ``; return s; } }; } // === График фазовых переходов T(t) с горизонтальными плато === // points: массив сегментов [{tStart, tEnd, Tstart, Tend, label?}] // W, H, pad — размеры графика; tMaxAll, TminAll, TmaxAll — диапазоны function phaseGraphTT(W, H, pad, points, tMaxAll, TminAll, TmaxAll) { const toX = t => pad + (W - 2*pad) * t / tMaxAll; const toY = T => H - pad - (H - 2*pad) * (T - TminAll) / (TmaxAll - TminAll); let s = ''; // Оси s += ``; s += ``; s += `t`; s += `T,°C`; // Сегменты let d = ''; let first = true; for (const seg of points) { if (first) { d += `M ${toX(seg.tStart).toFixed(1)} ${toY(seg.Tstart).toFixed(1)} `; first = false; } d += `L ${toX(seg.tEnd).toFixed(1)} ${toY(seg.Tend).toFixed(1)} `; } s += ``; // Подписи сегментов for (const seg of points) { if (seg.label) { const mx = (toX(seg.tStart) + toX(seg.tEnd)) / 2; const my = (toY(seg.Tstart) + toY(seg.Tend)) / 2 - 8; s += `${seg.label}`; } } return { svg: s, toX: toX, toY: toY }; } // === Анимация конвекции — тороидальный поток частиц === // Используется в §4 Физики 8 (главный визуал «конвекция в жидкости/газе»). // opts: { N — число частиц (default 24), w, h — размеры области, speed (отн. ед., default 1), // tHot, tCold — температуры для окраски (default 100, 20) }. function createConvectionSim(opts) { opts = opts || {}; const N = opts.N || 24; const w = opts.w || 220; const h = opts.h || 140; const speed = opts.speed != null ? opts.speed : 1; const tHot = opts.tHot != null ? opts.tHot : 100; const tCold = opts.tCold != null ? opts.tCold : 20; // Каждая частица движется по фазе вдоль контура прямоугольника: // правая сторона — вверх (нагрев / подъём), верхняя — влево, левая — вниз (охлаждение), нижняя — вправо. const parts = new Array(N); for (let i = 0; i < N; i++) parts[i] = { phase: i / N }; return { N: N, w: w, h: h, speed: speed, _tHot: tHot, _tCold: tCold, setSpeed(v) { this.speed = v; }, setHot(v) { this._tHot = v; }, setCold(v) { this._tCold = v; }, step(dt) { const dPhase = 0.18 * this.speed * dt; for (let i = 0; i < this.N; i++) { parts[i].phase = (parts[i].phase + dPhase) % 1; if (parts[i].phase < 0) parts[i].phase += 1; } }, // Возвращает координаты частицы (cx, cy) и температуру по её положению. // phase ∈ [0,1): 0..0.25 — правая (подъём, t→tHot), 0.25..0.5 — верх (t=tHot), // 0.5..0.75 — левая (опускание, t→tCold), 0.75..1 — низ (t=tCold). _xy(phase, x, y) { const margin = 12; const W = this.w - 2 * margin; const H = this.h - 2 * margin; let lx, ly, t; if (phase < 0.25) { const k = phase / 0.25; lx = W; ly = H * (1 - k); t = this._tCold + (this._tHot - this._tCold) * k; } else if (phase < 0.5) { const k = (phase - 0.25) / 0.25; lx = W * (1 - k); ly = 0; t = this._tHot; } else if (phase < 0.75) { const k = (phase - 0.5) / 0.25; lx = 0; ly = H * k; t = this._tHot - (this._tHot - this._tCold) * k; } else { const k = (phase - 0.75) / 0.25; lx = W * k; ly = H; t = this._tCold; } return { cx: x + margin + lx, cy: y + margin + ly, t: t }; }, render(x, y) { const tMin = Math.min(this._tCold, this._tHot); const tMax = Math.max(this._tCold, this._tHot); let s = ''; // Контур сосуда s += ``; // Нагреватель снизу (красная полоса) s += ``; // Частицы for (let i = 0; i < this.N; i++) { const p = this._xy(parts[i].phase, x, y); const c = tempColor(p.t, tMin, tMax); s += ``; } return s; } }; } // === Электронные хелперы для электрических задач === // Параллельное и последовательное сопротивление function Rseries() { let R = 0; for (let i = 0; i < arguments.length; i++) R += arguments[i]; return R; } function Rparallel() { let inv = 0; for (let i = 0; i < arguments.length; i++) { if (arguments[i] > 0) inv += 1 / arguments[i]; } return inv > 0 ? 1 / inv : Infinity; } // ====================================================================== // PHYSICS 7 HELPERS — силы, давление, гидростатика, барометры, энергия. // Все размеры в SVG-пикселях; физические величины в СИ. // ====================================================================== function forceVector(x, y, F, angleDeg, color, label, scale) { scale = scale || 1.5; const a = -angleDeg * Math.PI / 180; const x2 = x + F * scale * Math.cos(a); const y2 = y + F * scale * Math.sin(a); let s = drawArrow(x, y, x2, y2, color || '#0f172a', 2.5, 9); if (label) { const lx = x2 + 8 * Math.cos(a); const ly = y2 + 8 * Math.sin(a) + 4; s += `${label}`; } return s; } function dynamometer(x, y, h, Fmax, Fcurr) { const w = 30; const springTop = y + 14, springBot = y + h - 28; const stretch = Math.max(0, Math.min(1, Fcurr / Fmax)) * (springBot - springTop); const pointerY = springTop + stretch; let s = ``; const coils = 8; const coilH = (pointerY - springTop) / coils; let path = `M ${x + w/2} ${springTop}`; for (let i = 0; i < coils; i++) { path += ` L ${x + (i%2 ? w-6 : 6)} ${springTop + (i+0.5)*coilH}`; } path += ` L ${x + w/2} ${pointerY}`; s += ``; const ticks = 10; for (let i = 0; i <= ticks; i++) { const ty = springTop + (springBot - springTop) * i / ticks; s += ``; if (i % 2 === 0) { s += `${(Fmax * i / ticks).toFixed(Fmax < 5 ? 1 : 0)}`; } } s += ``; s += ``; s += `F = ${Fcurr.toFixed(1)} Н`; return s; } function blockOnSurface(x, y, w, h, label, weights) { let s = ``; if (label) s += `${label}`; if (weights && weights > 0) { const wH = 10, wW = w * 0.7; for (let i = 0; i < weights; i++) { const wy = y - (i + 1) * (wH + 2); s += ``; } } return s; } function connectedVessels(x, y, kindA, kindB, levelY, fluidColor) { fluidColor = fluidColor || '#60a5fa'; const widths = { cylinder: 60, wide: 100, narrow: 35 }; const wA = widths[kindA] || 60, wB = widths[kindB] || 60; const h = 140, gap = 50; const xA = x, xB = x + wA + gap; let s = ''; s += ``; s += ``; s += ``; s += ``; s += ``; s += ``; s += ``; s += ``; const fillH = (y + h) - levelY; s += ``; s += ``; s += ``; s += ``; return s; } function hydraulicPress(x, y, sSmall, sLarge, fSmall, fluidColor) { fluidColor = fluidColor || '#60a5fa'; const fLarge = fSmall * sLarge / sSmall; const scale = 6; const wSmall = Math.max(20, Math.sqrt(sSmall) * scale); const wLarge = Math.max(40, Math.sqrt(sLarge) * scale); const cylH = 60, baseY = y + 110, gap = 40; const xS = x, xL = x + wSmall + gap; let s = ''; s += ``; s += ``; s += ``; s += ``; s += ``; s += drawArrow(xS + wSmall/2, y + 20, xS + wSmall/2, y + 40, '#dc2626', 2.5, 8); s += drawArrow(xL + wLarge/2, y + 20, xL + wLarge/2, y + 40, '#10b981', 2.5, 8); s += `F_1 = ${fSmall.toFixed(0)} Н`; s += `F_2 = ${fLarge.toFixed(0)} Н`; s += `S_1 = ${sSmall} см²`; s += `S_2 = ${sLarge} см²`; return s; } function mercuryBarometer(x, y, hMm) { hMm = hMm == null ? 760 : hMm; const maxMm = 800, scale = 0.4; const tubeH = maxMm * scale, tubeW = 14; const cupY = y + tubeH + 10, cupW = 70, cupH = 26; const colH = hMm * scale, colTop = y + tubeH - colH; let s = ''; s += ``; s += ``; s += ``; s += ``; s += `вакуум`; for (let mm = 0; mm <= maxMm; mm += 50) { const ty = y + tubeH - mm * scale; s += ``; if (mm % 100 === 0) s += `${mm}`; } s += ``; s += `${hMm} мм`; return s; } function aneroidBarometer(cx, cy, r, pressurePa) { const pMm = pressurePa / 133.322; const pMin = 720, pMax = 800; const angDeg = -210 + 240 * Math.max(0, Math.min(1, (pMm - pMin) / (pMax - pMin))); const angRad = angDeg * Math.PI / 180; let s = ''; s += ``; s += ``; for (let p = pMin; p <= pMax; p += 10) { const a = (-210 + 240 * (p - pMin) / (pMax - pMin)) * Math.PI / 180; const r1 = r - 4, r2 = r - 12; const x1 = cx + r1 * Math.cos(a), y1 = cy + r1 * Math.sin(a); const x2 = cx + r2 * Math.cos(a), y2 = cy + r2 * Math.sin(a); s += ``; if (p % 20 === 0) { const rT = r - 22; const xT = cx + rT * Math.cos(a), yT = cy + rT * Math.sin(a) + 3; s += `${p}`; } } const tipX = cx + (r - 18) * Math.cos(angRad), tipY = cy + (r - 18) * Math.sin(angRad); s += ``; s += ``; s += `${pMm.toFixed(0)} мм рт. ст.`; return s; } function uManometer(x, y, w, h, deltaH, fluidColor) { fluidColor = fluidColor || '#0891b2'; const tube = 14; const xL = x, xR = x + w - tube; const baseY = y + h; let s = ``; s += ``; s += ``; const lLevel = y + h * 0.45 + deltaH / 2; const rLevel = y + h * 0.45 - deltaH / 2; s += ``; s += ``; if (Math.abs(deltaH) > 1) { s += ``; s += `Δh`; } return s; } function rulerWithError(x, y, lenCm, mmPerDiv) { mmPerDiv = mmPerDiv || 1; const pxPerCm = 30; const w = lenCm * pxPerCm, h = 28; let s = ``; const totalDivs = (lenCm * 10) / mmPerDiv; for (let i = 0; i <= totalDivs; i++) { const tx = x + (i * mmPerDiv / 10) * pxPerCm; const mm = i * mmPerDiv; const isCm = mm % 10 === 0, isHalfCm = mm % 5 === 0; const tickH = isCm ? 12 : (isHalfCm ? 8 : 5); s += ``; if (isCm) s += `${mm/10}`; } s += `см`; return s; } function bimetal(x, y, w, h, deltaT) { const ang = Math.max(-30, Math.min(30, deltaT * 0.3)); let s = ``; s += ``; s += ``; s += `ΔT = ${deltaT.toFixed(0)} °C`; s += ``; return s; } function expandingRod(x, y, l0, alpha, deltaT) { const dl = l0 * alpha * deltaT * 1000; const len = l0 + dl; const h = 16; const color = tempColor(deltaT, 0, 100); let s = ``; s += ``; if (dl > 1) { s += drawArrow(x + l0, y + h + 14, x + len, y + h + 14, '#dc2626', 1.8, 6); s += `Δl = ${dl.toFixed(1)} px`; } return s; } // === HillSlideSim — тележка скатывается с горки (для §42, закон сохранения) === class HillSlideSim { constructor(opts) { opts = opts || {}; this.x0 = opts.x0 || 30; this.y0 = opts.y0 || 200; this.hStart = opts.hStart != null ? opts.hStart : 5; this.m = opts.mass || 1; this.g = opts.g || 9.8; this.friction = opts.friction || 0; this.scale = opts.scale || 30; this.reset(); } reset() { // Начальный импульс: тележка стартует с лёгким толчком (1% от L) и небольшой скоростью, // иначе при h=hStart, v=0 — она навсегда останется на вершине (бесконечный нуль). const L = this.hStart * 4; this.t = 0; this.x = L * 0.01; const xRel = this.x / L; this.h = this.hStart * Math.pow(1 - xRel, 2); this.v = Math.sqrt(2 * this.g * (this.hStart - this.h)); } step(dt) { const gEff = this.g * (1 - this.friction); this.t += dt; const L = this.hStart * 4; if (this.h <= 0.001 || this.x >= L) { this.h = 0; // Финальная скорость с учётом потерь на трение. this.v = Math.sqrt(2 * gEff * this.hStart); this.x = L; return; } // Скорость по закону сохранения энергии (с учётом трения). const dropped = Math.max(0.0001, this.hStart - this.h); this.v = Math.sqrt(2 * gEff * dropped); // Скорость по x — это горизонтальная компонента; для наглядного моделирования // используем её напрямую как темп роста x. this.x += this.v * dt; const xRel = Math.min(this.x, L) / L; this.h = this.hStart * Math.pow(1 - xRel, 2); } getEnergies() { return { Ek: 0.5 * this.m * this.v * this.v, Ep: this.m * this.g * this.h, Etot: 0.5 * this.m * this.v * this.v + this.m * this.g * this.h }; } renderProfile() { const L = this.hStart * 4; const pxL = L * this.scale, pxH = this.hStart * this.scale; const baseY = this.y0; let path = `M ${this.x0} ${baseY - pxH}`; const N = 40; for (let i = 1; i <= N; i++) { const xRel = i / N; const yRel = Math.pow(1 - xRel, 2); path += ` L ${(this.x0 + pxL * xRel).toFixed(1)} ${(baseY - pxH * yRel).toFixed(1)}`; } let s = ''; s += ``; s += ``; const cartX = this.x0 + this.x * this.scale; const cartY = baseY - this.h * this.scale; s += ``; s += ``; s += ``; return s; } } // === PendulumSim — математический маятник (для §42) === class PendulumSim { constructor(opts) { opts = opts || {}; this.cx = opts.cx || 150; this.cy = opts.cy || 40; this.L = opts.length || 1.2; this.m = opts.mass || 0.5; this.g = opts.g || 9.8; this.phi0 = (opts.angleDeg || 25) * Math.PI / 180; this.scale = opts.scale || 80; this.reset(); } reset() { this.t = 0; this.phi = this.phi0; this.omega = 0; } step(dt) { const alpha = -(this.g / this.L) * Math.sin(this.phi); this.omega += alpha * dt; this.phi += this.omega * dt; this.t += dt; } getEnergies() { const h = this.L * (1 - Math.cos(this.phi)); const v = Math.abs(this.omega) * this.L; return { Ek: 0.5 * this.m * v * v, Ep: this.m * this.g * h, Etot: 0.5 * this.m * v * v + this.m * this.g * h }; } render() { const pxL = this.L * this.scale; const bx = this.cx + pxL * Math.sin(this.phi); const by = this.cy + pxL * Math.cos(this.phi); let s = ''; s += ``; s += ``; s += ``; s += ``; return s; } } // === Экспорт === window.PHYS = { tempColor: tempColor, thermometer: thermometer, calorimeter: calorimeter, createHeatBar: createHeatBar, createConvectionSim: createConvectionSim, phaseGraphTT: phaseGraphTT, Rseries: Rseries, Rparallel: Rparallel, drawArrow: drawArrow, fieldLinesPointCharge: fieldLinesPointCharge, chargeMark: chargeMark, magneticFieldGrid: magneticFieldGrid, molecule: molecule, createGasSim: createGasSim, batteryEMF: batteryEMF, resistor: resistor, capacitorSymbol: capacitorSymbol, ammeterSymbol: ammeterSymbol, voltmeterSymbol: voltmeterSymbol, lightbulbSymbol: lightbulbSymbol, inductorSymbol: inductorSymbol, wire: wire, CONST: CONST, celsiusToKelvin: celsiusToKelvin, kelvinToCelsius: kelvinToCelsius, atmToPa: atmToPa, paToAtm: paToAtm, litersToM3: litersToM3, m3ToLiters: m3ToLiters, // Physics 7 — Phase 0 forceVector: forceVector, dynamometer: dynamometer, blockOnSurface: blockOnSurface, connectedVessels: connectedVessels, hydraulicPress: hydraulicPress, mercuryBarometer: mercuryBarometer, aneroidBarometer: aneroidBarometer, uManometer: uManometer, rulerWithError: rulerWithError, bimetal: bimetal, expandingRod: expandingRod, HillSlideSim: HillSlideSim, PendulumSim: PendulumSim }; })();