diff --git a/frontend/textbooks/geometry_11_ch3.html b/frontend/textbooks/geometry_11_ch3.html index d5e6632..b1a705d 100644 --- a/frontend/textbooks/geometry_11_ch3.html +++ b/frontend/textbooks/geometry_11_ch3.html @@ -396,7 +396,7 @@ function buildParaSelector(){ } const BUILT=new Set(); -const BUILDERS = { p5:()=>buildStub('p5'), p6:()=>buildStub('p6'), p7:()=>buildStub('p7'), final3:()=>buildStub('final3') }; +const BUILDERS = { p5:buildP5, p6:()=>buildStub('p6'), p7:()=>buildStub('p7'), final3:()=>buildStub('final3') }; 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); @@ -411,14 +411,24 @@ function goTo(id){ } const SIDEBARS = { - p5:{title:"Шпаргалка § 5", rows:[["Тема", "Сфера"],["Формула","$(x-a)^2+(y-b)^2+(z-c)^2=R^2$"]]}, + p5:{title:"Шпаргалка § 5", rows:[ + ["Тема", "Сфера"], + ["Сфера", "множество точек, $|OM|=R$"], + ["Шар", "множество точек, $|OM|\\\\le R$"], + ["Уравнение", "$(x-a)^2+(y-b)^2+(z-c)^2=R^2$"], + ["Касательная", "плоскость $\\\\perp$ радиусу $OM$"], + ["Сечение", "окружность $r=\\\\sqrt{R^2-d^2}$"], + ["Большой круг", "$d=0$, $r=R$"], + ["Площадь", "$S=4\\\\pi R^2$"], + ["Объём шара", "$V=\\\\tfrac{4}{3}\\\\pi R^3$"] + ]}, p6:{title:"Шпаргалка § 6", rows:[["Тема", "Шар"],["Формула","$S=4\\\\pi R^2$, $V=\\\\frac{4}{3}\\\\pi R^3$"]]}, p7:{title:"Шпаргалка § 7", rows:[["Тема", "Правильные многогранники"],["Формула","5 платоновых тел"]]}, final3:{title:"Финал раздела 3", rows:[["§ 5–§ 7","теория раздела 3"],["Награда","+50 XP"]]} }; const TIPS=[ - {sec:'p5',html:"§ 5 «Сфера» — содержание в разработке. $(x-a)^2+(y-b)^2+(z-c)^2=R^2$"}, + {sec:'p5',html:"Сфера: $|OM|=R$. Уравнение $(x-a)^2+(y-b)^2+(z-c)^2=R^2$. Сечение плоскостью — окружность $r=\\\\sqrt{R^2-d^2}$."}, {sec:'p6',html:"§ 6 «Шар» — содержание в разработке. $S=4\\\\\\\\pi R^2$, $V=\\\\\\\\frac{4}{3}\\\\\\\\pi R^3$"}, {sec:'p7',html:"§ 7 «Правильные многогранники» — содержание в разработке. 5 платоновых тел"}, {sec:'final3',html:"Финал раздела 3 — интегрированные задачи по разделу."} @@ -625,6 +635,357 @@ function wireReadBtn(paraId){ }); } +/* ===== § 5 «Сфера» — Wave 1 ===== */ + +function buildP5(){ + const box = document.getElementById('p5-body'); + if(!box) return; + let html = ''; + + /* === ТЕОРИЯ === */ + + html += makeCard('theory', 'Определение и элементы', '§ 5.1', + '

Сфера — множество всех точек пространства, равноудалённых от заданной точки $O$ (центра).

' + + '

Шар — множество точек, для которых $|OM|\\le R$, где $O$ — центр, $R$ — радиус. Шар ограничен сферой; сфера — поверхность шара.

' + + '

Элементы:

' + + '' + + '

Уравнение сферы в декартовой системе координат. Для центра $C(a,b,c)$ и радиуса $R$:

' + + '

$$(x-a)^2+(y-b)^2+(z-c)^2=R^2$$

' + + '

Если центр в начале координат:

' + + '

$$x^2+y^2+z^2=R^2$$

' + + '

Уравнение выражает то, что квадрат расстояния от точки $(x,y,z)$ до центра $C$ равен $R^2$.

'); + + html += makeCard('rule', 'Касательная плоскость', '§ 5.2', + '

Касательная плоскость к сфере — плоскость, имеющая со сферой ровно одну общую точку. Эту точку называют точкой касания.

' + + '

Признак касания (необходимый и достаточный):

' + + '

Плоскость касается сферы в точке $M$ тогда и только тогда, когда она перпендикулярна радиусу $OM$, проведённому в точку касания.

' + + '

Через каждую точку сферы можно провести единственную касательную плоскость.

' + + '

Расстояние от центра сферы до касательной плоскости равно радиусу $R$.

' + + '
Пример: касательная к сфере $x^2+y^2+z^2=25$ в точке $M(3;4;0)$
' + + '

Центр $O(0;0;0)$, радиус-вектор $\\overrightarrow{OM}=(3;4;0)$ направлен из центра в точку касания.

' + + '

Значит нормаль касательной плоскости $\\vec{n}=(3;4;0)$. Уравнение плоскости в точке $M$:

' + + '

$3(x-3)+4(y-4)+0\\cdot(z-0)=0$, то есть $3x+4y=25$.

' + + '
'); + + html += makeCard('example', 'Сечения сферы и большой круг', '§ 5.3', + '

Сечение сферы плоскостью, пересекающей её — всегда окружность. Это следует из того, что точки сечения равноудалены от проекции центра сферы на эту плоскость.

' + + '

Связь радиуса сечения $r$, радиуса сферы $R$ и расстояния $d$ от центра сферы до секущей плоскости:

' + + '

$$r=\\sqrt{R^2-d^2}$$

' + + '

Три случая:

' + + '' + + '

Большой круг — сечение, проходящее через центр сферы ($d=0$). Радиус большого круга максимален и равен $R$.

' + + '

Любые два больших круга пересекаются по диаметру сферы.

' + + '
Пример: $R=5$, $d=3$
' + + '

$r=\\sqrt{R^2-d^2}=\\sqrt{25-9}=\\sqrt{16}=4$.

' + + '

Сечение — окружность радиуса $4$ в секущей плоскости.

' + + '
'); + + /* === ИНТЕРАКТИВ 1 — 3D-визуализатор сферы === */ + html += '
' + + '
3D · сфера
Визуализатор сферы (каркас)
' + + '
Меняй радиус $R$ ползунком, вращай мышью или выбирай вид. После 4 разных значений $R$ — +10 XP.
' + + '
' + + '' + + '
' + + '
' + + '' + + '' + + '' + + '' + + '
' + + '
' + + '
' + + '$R=$' + + '$d=2R=$' + + '$S=4\\pi R^2\\approx$' + + '$V=\\tfrac{4}{3}\\pi R^3\\approx$' + + '
' + + '
Разных $R$ изучено: 0 / 4
' + + '
'; + + /* === ИНТЕРАКТИВ 2 — Уравнение сферы и проверка точки === */ + html += '
' + + '
уравнение
Уравнение сферы и проверка точки
' + + '
Введи центр $C(a;b;c)$ и радиус $R$ — получи уравнение. Затем введи точку $M(x_0;y_0;z_0)$ — узнай, лежит ли она на сфере, внутри шара или вне.
' + + '
' + + '

Параметры сферы

' + + '
' + + '$a=$' + + '$b=$' + + '$c=$' + + '$R=$' + + '' + + '
' + + '
' + + '
' + + '
' + + '

Проверка точки $M(x_0;y_0;z_0)$

' + + '
' + + '$x_0=$' + + '$y_0=$' + + '$z_0=$' + + '' + + '
' + + '
' + + '
' + + '
'; + + /* === ИНТЕРАКТИВ 3 — Сечение сферы (квикфайр 6) === */ + html += '
' + + '
квикфайр · 6 заданий
Сечение сферы плоскостью
' + + '
Сравни $d$ и $R$. Выбери, что получится при пересечении: окружность, точка (касание) или ничего.
' + + '
' + + '
Верно: 0 / 6
' + + '
'; + + /* === ИНТЕРАКТИВ 4 — Тренажёр === */ + html += '
' + + '
тренажёр · 6 задач
Сечения, расстояния и уравнения
' + + '
Введи числовой ответ. Допуск $\\pm 0{,}05$ для дробных значений.
' + + '
' + + '
Решено: 0 / 6
' + + '
'; + + html += secNav(null, 'p6'); + html += readButton('p5'); + + box.innerHTML = html; + renderMath(box); + + /* ====== JS-логика интерактивов ====== */ + + /* IV1 — 3D-визуализатор */ + (function(){ + if(!window.G3D) return; + const svg = document.getElementById('p5-iv1-svg'); + const elR = document.getElementById('p5-iv1-R'); + const vR = document.getElementById('p5-iv1-R-v'); + const oR = document.getElementById('p5-iv1-R-o'); + const oD = document.getElementById('p5-iv1-d-o'); + const oS = document.getElementById('p5-iv1-S-o'); + const oV = document.getElementById('p5-iv1-V-o'); + const oCnt = document.getElementById('p5-iv1-cnt'); + if(!svg) return; + const scene = G3D.createScene({W:480, H:400, scale:60, camDist:8, rotX:-0.35, rotY:0.7}); + const seen = new Set(); + let xpGiven = false; + const PI = 3.14; + + function draw(){ + const R = +elR.value; + vR.textContent = R.toFixed(1); + const sph = G3D.sphereWireframe(R, 6, 12); + const M = G3D.buildRotMatrix(scene); + svg.innerHTML = G3D.renderSphereWireframe(sph, M, scene); + oR.textContent = R.toFixed(1); + oD.textContent = (2*R).toFixed(1); + oS.textContent = (4*PI*R*R).toFixed(2); + oV.textContent = ((4/3)*PI*R*R*R).toFixed(2); + const key = R.toFixed(1); + seen.add(key); + oCnt.textContent = Math.min(seen.size, 4); + if(seen.size >= 4 && !xpGiven){ + xpGiven = true; + addXp(10, 'p5-iv1'); + bumpProgress('p5', 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('p5-iv1'); + if(host) host.appendChild(note); + setTimeout(function(){ try{ note.remove(); }catch(e){} }, 3000); + } + } + draw(); + G3D.attachOrbit(svg, scene, draw); + elR.addEventListener('input', draw); + document.querySelectorAll('#p5-iv1 .g3d-tools .btn').forEach(function(b){ + b.addEventListener('click', function(){ G3D.presetView(scene, b.dataset.view, draw); }); + }); + })(); + + /* IV2 — Уравнение сферы + проверка точки */ + (function(){ + let xpGiven = false, eqShown = false, ptChecked = false; + function parseNum(id){ const v = (document.getElementById(id).value||'').replace(',', '.').trim(); const x = parseFloat(v); return isFinite(x) ? x : NaN; } + function fmtSign(v, useVar){ + // возвращает строку для "(x - a)" с учётом знака + if(v === 0) return useVar; + if(v > 0) return '('+useVar+' - '+fmt(v)+')'; + return '('+useVar+' + '+fmt(-v)+')'; + } + function maybeXp(){ + if(eqShown && ptChecked && !xpGiven){ + xpGiven = true; + addXp(10, 'p5-iv2'); + bumpProgress('p5', 15); + } + } + document.getElementById('p5-iv2-show').addEventListener('click', function(){ + const a = parseNum('p5-iv2-a'), b = parseNum('p5-iv2-b'), c = parseNum('p5-iv2-c'), R = parseNum('p5-iv2-R'); + const out = document.getElementById('p5-iv2-eq'); + if(!isFinite(a)||!isFinite(b)||!isFinite(c)||!isFinite(R)||R<=0){ + out.innerHTML = '✗ Введи корректные числа ($R>0$).'; + renderMath(out); + return; + } + const fx = fmtSign(a, 'x'); + const fy = fmtSign(b, 'y'); + const fz = fmtSign(c, 'z'); + const R2 = R*R; + const eq = '$$' + fx + '^2 + ' + fy + '^2 + ' + fz + '^2 = ' + fmt(R2) + '$$'; + out.innerHTML = '

Центр $C('+fmt(a)+';'+fmt(b)+';'+fmt(c)+')$, радиус $R='+fmt(R)+'$.

' + + '

Уравнение сферы:

' + eq; + renderMath(out); + eqShown = true; + maybeXp(); + }); + document.getElementById('p5-iv2-check').addEventListener('click', function(){ + const a = parseNum('p5-iv2-a'), b = parseNum('p5-iv2-b'), c = parseNum('p5-iv2-c'), R = parseNum('p5-iv2-R'); + const x0 = parseNum('p5-iv2-x0'), y0 = parseNum('p5-iv2-y0'), z0 = parseNum('p5-iv2-z0'); + const out = document.getElementById('p5-iv2-pt'); + if(!isFinite(a)||!isFinite(b)||!isFinite(c)||!isFinite(R)||R<=0||!isFinite(x0)||!isFinite(y0)||!isFinite(z0)){ + out.innerHTML = '✗ Введи корректные числа.'; + renderMath(out); + return; + } + const dx = x0 - a, dy = y0 - b, dz = z0 - c; + const lhs = dx*dx + dy*dy + dz*dz; + const R2 = R*R; + const dist = Math.sqrt(lhs); + let verdict = '', color = ''; + if(Math.abs(lhs - R2) < 1e-6){ verdict = 'лежит на сфере'; color = 'var(--ok)'; } + else if(lhs < R2){ verdict = 'лежит внутри шара'; color = '#2563eb'; } + else { verdict = 'лежит вне шара'; color = 'var(--warn)'; } + out.innerHTML = '

Подставляем $M('+fmt(x0)+';'+fmt(y0)+';'+fmt(z0)+')$:

' + + '

$('+fmt(x0)+'-'+fmt(a)+')^2+('+fmt(y0)+'-'+fmt(b)+')^2+('+fmt(z0)+'-'+fmt(c)+')^2 = ' + + fmt(dx*dx)+'+'+fmt(dy*dy)+'+'+fmt(dz*dz)+' = '+fmt(lhs)+'$

' + + '

Сравниваем с $R^2='+fmt(R2)+'$. Расстояние $|CM|='+fmt(+dist.toFixed(4))+'$.

' + + '

✓ Точка $M$ '+verdict+'.

'; + renderMath(out); + ptChecked = true; + maybeXp(); + }); + })(); + + /* IV3 — Сечение сферы (квикфайр) */ + (function(){ + const tasks = [ + { R:5, d:3, a:'circle' }, + { R:5, d:5, a:'point' }, + { R:5, d:6, a:'none' }, + { R:10, d:0, a:'circle' }, + { R:3, d:3.5, a:'none' }, + { R:7, d:7, a:'point' } + ]; + const NAMES = {circle:'Окружность', point:'Точка', none:'Нет общих точек'}; + const HINTS = { + circle: function(t){ const r = Math.sqrt(t.R*t.R - t.d*t.d); return '$dR='+t.R+'$, плоскость не пересекает сферу.'; } + }; + const list = document.getElementById('p5-iv3-list'); + const scoreEl = document.getElementById('p5-iv3-score'); + const solved = new Set(); + let xpGiven = false; + list.innerHTML = tasks.map(function(t, i){ + return '
' + + '
Задание '+(i+1)+'. Сфера $R='+t.R+'$, расстояние от центра до плоскости $d='+t.d+'$. Что получится?
' + + '
' + + '' + + '' + + '' + + '
' + + '' + + '
'; + }).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('p5-iv3-fb-'+i); + if(solved.has(i)) return; + if(v === t.a){ + feedback(fb, true, '✓ Верно — '+NAMES[t.a]+'. '+HINTS[t.a](t)); + solved.add(i); + scoreEl.textContent = solved.size; + if(solved.size === tasks.length && !xpGiven){ + xpGiven = true; + addXp(15, 'p5-iv3'); + bumpProgress('p5', 25); + } + } else { + feedback(fb, false, '✗ Не то. Сравни $d$ и $R$ внимательнее.'); + } + }); + }); + })(); + + /* IV4 — Тренажёр */ + (function(){ + const tasks = [ + { q:'Сфера $R=5$. Радиус сечения плоскостью на расстоянии $d=3$ от центра: $r=\\,?$', a:4, tol:0.05 }, + { q:'Сфера с центром $C(2;3;-1)$, точка $M(5;7;3)$. Расстояние $|CM|=\\,?$ (точность 0,01)', a:6.40, tol:0.05 }, + { q:'Сфера $R=13$. Сечение — окружность радиуса $12$. Найти $d$ (расстояние от центра до плоскости).', a:5, tol:0.05 }, + { q:'К сфере $R=5$ построена касательная плоскость. Расстояние от центра до плоскости: $d=\\,?$', a:5, tol:0.05 }, + { q:'Точка $A(3;4;0)$ принадлежит сфере с центром в начале координат. Найти $R$.', a:5, tol:0.05 }, + { q:'Сфера $x^2+y^2+z^2=100$. Радиус большого круга: $R=\\,?$', a:10, tol:0.05 } + ]; + const list = document.getElementById('p5-iv4-list'); + const scoreEl = document.getElementById('p5-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('p5-iv4-inp-'+i); + const fb = document.getElementById('p5-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, 'p5-iv4'); + bumpProgress('p5', 25); + setTimeout(function(){ achievement('p5_done'); }, 400); + } + } + } else { + feedback(fb, false, '✗ Не точно. Пересчитай аккуратно.'); + } + }); + }); + })(); + + wireReadBtn('p5'); +} + /* ===== STUB BUILDER — единый для всех параграфов раздела (Phase 0) ===== */ function buildStub(id){ @@ -706,6 +1067,10 @@ function buildStub(id){ const SEARCH_INDEX = (function(){ const arr=[]; PARAS.forEach(p=>arr.push({kind:'Параграф',title:p.num+' '+p.name,desc:p.sub||'',sec:p.id})); + arr.push({kind:'Теория',title:'Сфера и шар: определение',desc:'центр, радиус, диаметр, хорда',sec:'p5'}); + arr.push({kind:'Теория',title:'Уравнение сферы',desc:'(x-a)^2+(y-b)^2+(z-c)^2=R^2',sec:'p5'}); + arr.push({kind:'Теория',title:'Касательная плоскость к сфере',desc:'перпендикулярна радиусу в точке касания',sec:'p5'}); + arr.push({kind:'Теория',title:'Сечение сферы плоскостью',desc:'r = sqrt(R^2 - d^2), большой круг',sec:'p5'}); return arr; })(); function initSearch(){