diff --git a/frontend/textbooks/geometry_11_ch2.html b/frontend/textbooks/geometry_11_ch2.html index a157435..1b9e8f8 100644 --- a/frontend/textbooks/geometry_11_ch2.html +++ b/frontend/textbooks/geometry_11_ch2.html @@ -392,7 +392,7 @@ function buildParaSelector(){ } const BUILT=new Set(); -const BUILDERS = { p3:()=>buildStub('p3'), p4:()=>buildStub('p4'), final2:()=>buildStub('final2') }; +const BUILDERS = { p3:buildP3, p4:()=>buildStub('p4'), final2:()=>buildStub('final2') }; function ensureBuilt(id){ if(BUILT.has(id)) return; const fn=BUILDERS[id]; if(fn){ fn(); BUILT.add(id); } } function goTo(id){ STATE.current=id; ensureBuilt(id); @@ -407,13 +407,22 @@ function goTo(id){ } const SIDEBARS = { - p3:{title:"Шпаргалка § 3", rows:[["Тема", "Пирамида"],["Формула","$V=\\\\frac{1}{3}S_{осн}h$"]]}, + p3:{title:"Шпаргалка § 3", rows:[ + ["Пирамида", "основание + апекс"], + ["Правильная","основание — правильный многоугольник; высота в центре основания"], + ["Апофема $l$","высота боковой грани"], + ["Объём","$V=\\\\dfrac{1}{3}S_{осн}\\\\cdot h$"], + ["$S_{бок}$ (правильной)","$\\\\dfrac{1}{2}P_{осн}\\\\cdot l$"], + ["Боковое ребро","$b=\\\\sqrt{R^2+h^2}$"], + ["Апофема","$l=\\\\sqrt{r^2+h^2}$"], + ["Усечённая","$V=\\\\dfrac{h}{3}(S_1+S_2+\\\\sqrt{S_1 S_2})$"] + ]}, p4:{title:"Шпаргалка § 4", rows:[["Тема", "Конус"],["Формула","$S_{бок}=\\\\pi Rl$"]]}, final2:{title:"Финал раздела 2", rows:[["§ 3–§ 4","теория раздела 2"],["Награда","+50 XP"]]} }; const TIPS=[ - {sec:'p3',html:"§ 3 «Пирамида» — содержание в разработке. $V=\\\\\\\\frac{1}{3}S_{осн}h$"}, + {sec:'p3',html:"Главное правило: $V=\\\\\\\\dfrac{1}{3}S_{осн}h$ для любой пирамиды. А для правильной — $S_{бок}=\\\\\\\\dfrac{1}{2}P_{осн}l$, где $l$ — апофема."}, {sec:'p4',html:"§ 4 «Конус» — содержание в разработке. $S_{бок}=\\\\\\\\pi Rl$"}, {sec:'final2',html:"Финал раздела 2 — интегрированные задачи по разделу."} ]; @@ -619,6 +628,364 @@ function wireReadBtn(paraId){ }); } +/* ===== § 3 «Пирамида» — Wave 1 ===== */ + +function buildP3(){ + const box = document.getElementById('p3-body'); + if(!box) return; + let html = ''; + + /* === ТЕОРИЯ === */ + + html += makeCard('theory', 'Определение и виды', '§ 3.1', + '

Пирамида — многогранник, у которого одна грань (основание) — многоугольник, а остальные грани (боковые) — треугольники с общей вершиной.

' + + '

Элементы пирамиды:

' + + '' + + '

Правильная пирамида — пирамида, у которой:

' + + '' + + '

Тогда автоматически выполняются следствия: все боковые рёбра равны, а боковые грани — равные равнобедренные треугольники.

' + + '

Апофема $l$ — высота боковой грани, опущенная из апекса к середине стороны основания. У правильной пирамиды все апофемы равны.

'); + + html += makeCard('rule', 'Площадь и объём', '§ 3.2', + '

Объём (для любой пирамиды):

' + + '

$$V=\\dfrac{1}{3}\\,S_{осн}\\cdot h$$

' + + '

Боковая поверхность правильной пирамиды:

' + + '

$$S_{бок}=\\dfrac{1}{2}\\,P_{осн}\\cdot l$$

' + + '

где $l$ — апофема, $P_{осн}$ — периметр основания.

' + + '

Полная поверхность: $S_{полн}=S_{бок}+S_{осн}$.

' + + '

Связь между элементами правильной $n$-угольной пирамиды. Пусть $R$ — радиус описанной около основания окружности, $r$ — радиус вписанной, $b$ — боковое ребро, $l$ — апофема, $h$ — высота. Тогда:

' + + '' + + '
Пример: правильная 4-угольная пирамида $a=6$, $h=4$
' + + '

Основание — квадрат, $r=a/2=3$.

' + + '' + + '
'); + + html += makeCard('example', 'Усечённая пирамида', '§ 3.3', + '

Усечённая пирамида — часть пирамиды, заключённая между основанием и плоскостью, параллельной основанию.

' + + '

У неё два основания — подобные многоугольники в параллельных плоскостях. Боковые грани — трапеции.

' + + '

Объём усечённой пирамиды:

' + + '

$$V=\\dfrac{1}{3}\\,h\\bigl(S_1+S_2+\\sqrt{S_1 S_2}\\bigr)$$

' + + '

где $S_1,\\,S_2$ — площади оснований, $h$ — высота (расстояние между плоскостями оснований).

' + + '

Боковая поверхность правильной усечённой пирамиды:

' + + '

$$S_{бок}=\\dfrac{1}{2}(P_1+P_2)\\cdot l$$

' + + '

где $l$ — апофема (высота боковой трапеции), $P_1,\\,P_2$ — периметры оснований.

' + + '
Пример: правильная 4-угольная усечённая, $a_1=6$, $a_2=4$, $h=3$
' + + '

$S_1=36$, $S_2=16$.

' + + '

Апофема: $l=\\sqrt{h^2+\\left(\\dfrac{a_1-a_2}{2}\\right)^2}=\\sqrt{9+1}=\\sqrt{10}$.

' + + '

$V=\\dfrac{1}{3}\\cdot 3\\cdot(36+16+\\sqrt{576})=36+16+24=76$.

' + + '
'); + + /* === ИНТЕРАКТИВ 1 — 3D-конструктор === */ + html += '
' + + '
3D · конструктор
Правильная $n$-угольная пирамида
' + + '
Меняй число сторон основания $n$, радиус описанной окружности $R$ и высоту $h$. Вращай мышью или выбирай вид. После 4 разных конфигураций — +10 XP.
' + + '
' + + '' + + '' + + '' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '$a=$' + + '$r=$' + + '$P_{осн}=$' + + '$S_{осн}=$' + + '$l=$' + + '$b=$' + + '$S_{бок}=$' + + '$S_{полн}=$' + + '$V=$' + + '
' + + '
Конфигураций изучено: 0 / 4
' + + '
'; + + /* === ИНТЕРАКТИВ 2 — Калькулятор V и S === */ + html += '
' + + '
калькулятор
$V$ и $S_{бок}$ правильной пирамиды
' + + '
Введи $n$ (число сторон основания, $3..8$), сторону $a$ и высоту $h$. Калькулятор покажет пошаговый разбор.
' + + '
' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '
'; + + /* === ИНТЕРАКТИВ 3 — «Найди элемент» (квикфайр) === */ + html += '
' + + '
квикфайр · 6 заданий
Найди элемент пирамиды
' + + '
Читай описание отрезка — выбирай, какой это элемент: высота $h$, апофема $l$ или боковое ребро $b$.
' + + '
' + + '
Верно: 0 / 6
' + + '
'; + + /* === ИНТЕРАКТИВ 4 — Тренажёр V и S === */ + html += '
' + + '
тренажёр · 6 задач
$V$, $l$, $S_{бок}$ и усечённая
' + + '
Введи числовой ответ. Допуск $\\pm 0{,}05$ для дробных значений.
' + + '
' + + '
Решено: 0 / 6
' + + '
'; + + html += secNav(null, 'p4'); + html += readButton('p3'); + + box.innerHTML = html; + renderMath(box); + + /* ====== JS-логика интерактивов ====== */ + + /* IV1 — 3D-конструктор */ + (function(){ + if(!window.G3D) return; + const svg = document.getElementById('p3-iv1-svg'); + const elN = document.getElementById('p3-iv1-n'); + const elR = document.getElementById('p3-iv1-R'); + const elH = document.getElementById('p3-iv1-h'); + const vN = document.getElementById('p3-iv1-n-v'); + const vR = document.getElementById('p3-iv1-R-v'); + const vH = document.getElementById('p3-iv1-h-v'); + const oA = document.getElementById('p3-iv1-a'); + const oR = document.getElementById('p3-iv1-r'); + const oP = document.getElementById('p3-iv1-P'); + const oSo = document.getElementById('p3-iv1-So'); + const oL = document.getElementById('p3-iv1-l'); + const oB = document.getElementById('p3-iv1-b'); + const oSb = document.getElementById('p3-iv1-Sb'); + const oSt = document.getElementById('p3-iv1-St'); + const oV = document.getElementById('p3-iv1-V'); + const oCnt = document.getElementById('p3-iv1-cnt'); + if(!svg) return; + const scene = G3D.createScene({W:480, H:400, scale:50, camDist:8, rotX:-0.35, rotY:0.7}); + const seen = new Set(); + let xpGiven = false; + + function draw(){ + const n = +elN.value, R = +elR.value, h = +elH.value; + vN.textContent = n; + vR.textContent = R.toFixed(1); + vH.textContent = h.toFixed(1); + const mesh = G3D.pyramidMesh(n, R, h); + const M = G3D.buildRotMatrix(scene); + svg.innerHTML = G3D.renderMesh(mesh, M, scene, { + fillBase:'rgba(252,231,243,.55)', + fillSide:'rgba(219,234,254,.55)', + strokeVisible:'#0f172a', + strokeHidden:'#94a3b8' + }); + const a = 2*R*Math.sin(Math.PI/n); + const r = R*Math.cos(Math.PI/n); + const P = n*a; + const So = 0.5*n*R*R*Math.sin(2*Math.PI/n); + const l = Math.sqrt(r*r + h*h); + const bs = Math.sqrt(R*R + h*h); + const Sb = 0.5*P*l; + const St = Sb + So; + const V = So*h/3; + oA.textContent = a.toFixed(2); + oR.textContent = r.toFixed(2); + oP.textContent = P.toFixed(2); + oSo.textContent = So.toFixed(2); + oL.textContent = l.toFixed(2); + oB.textContent = bs.toFixed(2); + oSb.textContent = Sb.toFixed(2); + oSt.textContent = St.toFixed(2); + oV.textContent = V.toFixed(2); + const key = n+'|'+R.toFixed(1)+'|'+h.toFixed(1); + seen.add(key); + oCnt.textContent = Math.min(seen.size, 4); + if(seen.size >= 4 && !xpGiven){ + xpGiven = true; + addXp(10, 'p3-iv1'); + bumpProgress('p3', 15); + const note = document.createElement('div'); + note.className = 'feedback ok'; + note.innerHTML = '✓ +10 XP за изучение 4 разных пирамид!'; + note.style.cssText = 'display:block;margin-top:8px'; + const host = document.getElementById('p3-iv1'); + if(host) host.appendChild(note); + setTimeout(function(){ try{ note.remove(); }catch(e){} }, 3000); + } + } + draw(); + G3D.attachOrbit(svg, scene, draw); + [elN, elR, elH].forEach(function(el){ el.addEventListener('input', draw); }); + document.querySelectorAll('#p3-iv1 .g3d-tools .btn').forEach(function(b){ + b.addEventListener('click', function(){ G3D.presetView(scene, b.dataset.view, draw); }); + }); + })(); + + /* IV2 — Калькулятор */ + (function(){ + const elN = document.getElementById('p3-iv2-n'); + const elA = document.getElementById('p3-iv2-a'); + const elH = document.getElementById('p3-iv2-h'); + const labels = {'p3-iv2-n':'p3-iv2-n-v','p3-iv2-a':'p3-iv2-a-v','p3-iv2-h':'p3-iv2-h-v'}; + Object.keys(labels).forEach(function(k){ + const el = document.getElementById(k), lab = document.getElementById(labels[k]); + if(!el || !lab) return; + const upd = function(){ lab.textContent = el.step === '1' ? el.value : (+el.value).toFixed(1); }; + el.addEventListener('input', upd); upd(); + }); + let xpGiven = false; + document.getElementById('p3-iv2-calc').addEventListener('click', function(){ + const out = document.getElementById('p3-iv2-out'); + const n = +elN.value, a = +elA.value, h = +elH.value; + const r = a / (2*Math.tan(Math.PI/n)); + const P = n*a; + const So = 0.5*P*r; + const l = Math.sqrt(r*r + h*h); + const Sb = 0.5*P*l; + const St = Sb + So; + const V = So*h/3; + const html2 = '
' + + '

Правильная '+n+'-угольная пирамида: $a='+a.toFixed(2)+'$, $h='+h.toFixed(2)+'$

' + + '

$r=\\dfrac{a}{2\\tan(\\pi/n)}\\approx '+r.toFixed(3)+'$ — радиус вписанной окружности основания.

' + + '

$P_{осн}=n\\cdot a='+n+'\\cdot '+a.toFixed(2)+'='+P.toFixed(2)+'$

' + + '

$S_{осн}=\\dfrac{1}{2}P\\cdot r\\approx '+So.toFixed(2)+'$

' + + '

$l=\\sqrt{r^2+h^2}=\\sqrt{'+(r*r).toFixed(2)+'+'+(h*h).toFixed(2)+'}\\approx '+l.toFixed(3)+'$ — апофема.

' + + '

$S_{бок}=\\dfrac{1}{2}P_{осн}\\cdot l\\approx '+Sb.toFixed(2)+'$

' + + '

$S_{полн}=S_{бок}+S_{осн}\\approx '+St.toFixed(2)+'$

' + + '

$V=\\dfrac{1}{3}S_{осн}\\cdot h\\approx '+V.toFixed(2)+'$

' + + '
'; + out.innerHTML = html2; + renderMath(out); + if(!xpGiven){ + xpGiven = true; + addXp(10, 'p3-iv2'); + bumpProgress('p3', 15); + } + }); + })(); + + /* IV3 — «Найди элемент» (квикфайр) */ + (function(){ + const tasks = [ + { q:'Отрезок от апекса к центру основания.', a:'h' }, + { q:'Отрезок от апекса к середине стороны основания.', a:'l' }, + { q:'Отрезок от апекса к вершине основания.', a:'b' }, + { q:'В равнобедренном треугольнике боковой грани — высота к стороне основания.', a:'l' }, + { q:'Отрезок из апекса перпендикулярно плоскости основания.', a:'h' }, + { q:'Длина отрезка апекс — вершина основания.', a:'b' } + ]; + const list = document.getElementById('p3-iv3-list'); + const scoreEl = document.getElementById('p3-iv3-score'); + const solved = new Set(); + let xpGiven = false; + const NAMES = {h:'Высота $h$', l:'Апофема $l$', b:'Боковое ребро $b$'}; + list.innerHTML = tasks.map(function(t, i){ + return '
' + + '
Задание '+(i+1)+'. '+t.q+'
' + + '
' + + '' + + '' + + '' + + '
' + + '
' + + '
'; + }).join(''); + renderMath(list); + list.querySelectorAll('button[data-i]').forEach(function(b){ + b.addEventListener('click', function(){ + const i = +b.dataset.i, v = b.dataset.v, t = tasks[i]; + const fb = document.getElementById('p3-iv3-fb-'+i); + if(solved.has(i)) return; + if(v === t.a){ + feedback(fb, true, '✓ Верно — это '+NAMES[t.a]+'.'); + solved.add(i); + scoreEl.textContent = solved.size; + if(solved.size === tasks.length && !xpGiven){ + xpGiven = true; + addXp(15, 'p3-iv3'); + bumpProgress('p3', 25); + } + } else { + feedback(fb, false, '✗ Не то. Подумай ещё раз.'); + } + }); + }); + })(); + + /* IV4 — Тренажёр V и S */ + (function(){ + const tasks = [ + { q:'Правильная 4-угольная пирамида: $a=6$, $h=4$. $V=\\,?$', a:48, tol:0.05 }, + { q:'Та же пирамида ($a=6$, $h=4$). Апофема $l=\\,?$', a:5, tol:0.05 }, + { q:'Та же пирамида. $S_{бок}=\\,?$', a:60, tol:0.05 }, + { q:'Правильная 3-угольная пирамида: $a=6$, $h=4$. $V=\\,?$ (точность 0,01)', a:20.78, tol:0.05 }, + { q:'Правильная 6-угольная пирамида: $a=4$, $h=3$. $V=\\,?$ (точность 0,01)', a:41.57, tol:0.05 }, + { q:'Правильная 4-угольная усечённая: $a_1=6$, $a_2=4$, $h=3$. $V=\\,?$', a:76, tol:0.05 } + ]; + const list = document.getElementById('p3-iv4-list'); + const scoreEl = document.getElementById('p3-iv4-score'); + const solved = new Set(); + let xpGiven = false; + list.innerHTML = tasks.map(function(t, i){ + return '
' + + '
Задача '+(i+1)+'. '+t.q+'
' + + '
' + + '' + + '' + + '
' + + '
' + + '
'; + }).join(''); + renderMath(list); + list.querySelectorAll('button[data-i]').forEach(function(b){ + b.addEventListener('click', function(){ + const i = +b.dataset.i, t = tasks[i]; + const inp = document.getElementById('p3-iv4-inp-'+i); + const fb = document.getElementById('p3-iv4-fb-'+i); + const raw = (inp.value || '').replace(',', '.').trim(); + const val = parseFloat(raw); + if(!isFinite(val)){ feedback(fb, false, '✗ Введи число'); return; } + if(Math.abs(val - t.a) <= t.tol){ + feedback(fb, true, '✓ Верно!'); + if(!solved.has(i)){ + solved.add(i); + scoreEl.textContent = solved.size; + if(solved.size === tasks.length && !xpGiven){ + xpGiven = true; + addXp(15, 'p3-iv4'); + bumpProgress('p3', 25); + setTimeout(function(){ achievement('p3_done'); }, 400); + } + } + } else { + feedback(fb, false, '✗ Не точно. Пересчитай аккуратно.'); + } + }); + }); + })(); + + wireReadBtn('p3'); +} + /* ===== STUB BUILDER — единый для всех параграфов раздела (Phase 0) ===== */ function buildStub(id){