feat(geom9 ch2 wave1): §7 «Окружности треугольника» + §8 «Окружности прямоугольного»
This commit is contained in:
@@ -103,6 +103,27 @@ a{color:inherit;text-decoration:none}
|
|||||||
.feedback.ok{display:block;background:var(--ok-bg);color:#065f46;border-left:4px solid var(--ok)}
|
.feedback.ok{display:block;background:var(--ok-bg);color:#065f46;border-left:4px solid var(--ok)}
|
||||||
.feedback.fail{display:block;background:var(--fail-bg);color:#7f1d1d;border-left:4px solid var(--fail)}
|
.feedback.fail{display:block;background:var(--fail-bg);color:#7f1d1d;border-left:4px solid var(--fail)}
|
||||||
|
|
||||||
|
.wg{background:linear-gradient(135deg,var(--card),var(--pri-soft));border:1.5px solid var(--pri);border-radius:14px;padding:18px 20px;margin-bottom:18px;box-shadow:var(--sh2);position:relative;z-index:1}
|
||||||
|
.wg-header{display:flex;align-items:center;gap:8px;margin-bottom:14px}
|
||||||
|
.wg-badge{padding:4px 9px;background:var(--pri);color:#fff;border-radius:6px;font-family:'Unbounded',sans-serif;font-size:.68rem;font-weight:800;text-transform:uppercase;letter-spacing:.06em}
|
||||||
|
.wg-title{font-family:'Unbounded',sans-serif;font-size:1.05rem;font-weight:800;color:var(--pri2);flex:1}
|
||||||
|
.wg-help{font-size:.88rem;color:var(--text);margin-bottom:12px;line-height:1.55;background:linear-gradient(135deg,var(--warn-bg),var(--pri-soft));border-left:4px solid var(--warn);padding:9px 14px;border-radius:9px}
|
||||||
|
.tinp{padding:8px 12px;border:1.5px solid var(--border);border-radius:8px;background:var(--card);color:var(--text);transition:border-color .15s;font-family:'JetBrains Mono',monospace}
|
||||||
|
.tinp:focus{outline:0;border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-soft)}
|
||||||
|
.actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
|
||||||
|
.sliders{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:10px;margin-bottom:10px}
|
||||||
|
.sliders label{display:block;font-size:.92rem;color:var(--muted);background:var(--card);padding:8px 12px;border-radius:8px;border:1px solid var(--border);line-height:1.5}
|
||||||
|
.sliders label b{font-family:'JetBrains Mono',monospace;font-size:1.05rem;color:var(--pri2);margin-left:4px}
|
||||||
|
.sliders label input[type="range"]{display:block;width:100%;margin-top:6px;accent-color:var(--pri)}
|
||||||
|
.score-display{display:flex;gap:14px;flex-wrap:wrap;align-items:center;padding:10px 14px;background:var(--pri-soft);border-radius:10px;margin-bottom:12px}
|
||||||
|
.score-display b{color:var(--pri2);font-size:1.15rem}
|
||||||
|
.spoiler{border:1px solid var(--border);border-radius:10px;background:var(--card);margin:10px 0;overflow:hidden}
|
||||||
|
.spoiler summary{padding:8px 14px;background:var(--pri-soft);font-weight:700;cursor:pointer;font-size:.88rem;color:var(--pri2);list-style:none;display:flex;align-items:center;gap:8px}
|
||||||
|
.spoiler summary::-webkit-details-marker{display:none}
|
||||||
|
.spoiler summary::before{content:'+';font-size:1.2rem;font-weight:900;color:var(--pri);width:18px}
|
||||||
|
.spoiler[open] summary::before{content:'\2212'}
|
||||||
|
.spoiler-body{padding:10px 14px;font-size:.92rem;line-height:1.6}
|
||||||
|
|
||||||
.col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto}
|
.col-side{position:sticky;top:14px;align-self:start;height:fit-content;max-height:calc(100vh - 28px);overflow-y:auto}
|
||||||
.sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)}
|
.sidecard{background:var(--card);border:1px solid var(--border);border-radius:14px;padding:16px;margin-bottom:14px;box-shadow:var(--sh)}
|
||||||
.sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}
|
.sidecard h4{font-family:'Unbounded',sans-serif;font-size:.74rem;font-weight:800;color:var(--pri2);text-transform:uppercase;letter-spacing:.07em;margin-bottom:10px;padding-bottom:8px;border-bottom:1px solid var(--border)}
|
||||||
@@ -420,6 +441,29 @@ function wireReadBtn(paraId){
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ===== SVG helpers ===== */
|
||||||
|
function rightAngleMark(V, uIn, wIn, s){
|
||||||
|
s = s || 9;
|
||||||
|
const p1 = {x: V.x + s*uIn.x, y: V.y + s*uIn.y};
|
||||||
|
const c = {x: p1.x + s*wIn.x, y: p1.y + s*wIn.y};
|
||||||
|
const p2 = {x: V.x + s*wIn.x, y: V.y + s*wIn.y};
|
||||||
|
return p1.x+','+p1.y+' '+c.x+','+c.y+' '+p2.x+','+p2.y;
|
||||||
|
}
|
||||||
|
function angleArcAuto(V, uA, uB, R){
|
||||||
|
const sA = {x: V.x + R*uA.x, y: V.y + R*uA.y};
|
||||||
|
const eB = {x: V.x + R*uB.x, y: V.y + R*uB.y};
|
||||||
|
const cross = uA.x*uB.y - uA.y*uB.x;
|
||||||
|
const sweep = cross > 0 ? 1 : 0;
|
||||||
|
return 'M'+sA.x+','+sA.y+' A'+R+','+R+' 0 0,'+sweep+' '+eB.x+','+eB.y;
|
||||||
|
}
|
||||||
|
function unitVec(p1, p2){
|
||||||
|
const dx = p2.x - p1.x, dy = p2.y - p1.y;
|
||||||
|
const len = Math.sqrt(dx*dx + dy*dy) || 1;
|
||||||
|
return {x: dx/len, y: dy/len};
|
||||||
|
}
|
||||||
|
function deg2rad(d){ return d * Math.PI / 180; }
|
||||||
|
function gcd(a,b){ a=Math.abs(a|0); b=Math.abs(b|0); while(b){ const t=b; b=a%b; a=t; } return a||1; }
|
||||||
|
|
||||||
/* ===== STUB BUILDERS — наполнение в Phase 7+ ===== */
|
/* ===== STUB BUILDERS — наполнение в Phase 7+ ===== */
|
||||||
|
|
||||||
function _stubBuilder(paraId, num, name, prev, next){
|
function _stubBuilder(paraId, num, name, prev, next){
|
||||||
@@ -435,8 +479,576 @@ function _stubBuilder(paraId, num, name, prev, next){
|
|||||||
if(window.renderMathInElement) renderMath(body);
|
if(window.renderMathInElement) renderMath(body);
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildP7(){ _stubBuilder('p7', '§7', 'Описанная и вписанная окружности треугольника', null, 'p8'); }
|
/* ===== §7 Описанная и вписанная окружности треугольника ===== */
|
||||||
function buildP8(){ _stubBuilder('p8', '§8', 'Окружности прямоугольного треугольника', 'p7', 'p9'); }
|
function buildP7(){
|
||||||
|
const box = document.getElementById('p7-body');
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
html += makeCard('theory', 'Описанная окружность', '7.1', `
|
||||||
|
<p><b>Описанная</b> около треугольника окружность проходит через все три вершины. Её центр — точка пересечения <b>серединных перпендикуляров</b> к сторонам, обозначается $O$. Радиус $R$.</p>
|
||||||
|
<p>Для любого треугольника <b>существует и единственна</b> описанная окружность.</p>
|
||||||
|
<details class="spoiler"><summary>Почему серединные перпендикуляры?</summary><div class="spoiler-body">
|
||||||
|
Серединный перпендикуляр к отрезку — множество точек, равноудалённых от его концов. Точка $O$ равноудалена от $A$ и $B$ (на серединном перпендикуляре к $AB$) и от $B$ и $C$ (на серединном перпендикуляре к $BC$), значит $OA = OB = OC = R$.
|
||||||
|
</div></details>`);
|
||||||
|
|
||||||
|
html += makeCard('rule', 'Вписанная окружность', '7.2', `
|
||||||
|
<p><b>Вписанная</b> в треугольник окружность касается всех трёх сторон изнутри. Её центр — точка пересечения <b>биссектрис</b> углов, обозначается $I$. Радиус $r$.</p>
|
||||||
|
<p>Также существует и единственна. Формула связи площади и вписанного радиуса:</p>
|
||||||
|
$$S_\\triangle = p \\cdot r$$
|
||||||
|
<p>где $p = \\dfrac{a+b+c}{2}$ — полупериметр.</p>
|
||||||
|
<p>Радиус описанной выражается через стороны и площадь:</p>
|
||||||
|
$$R = \\dfrac{abc}{4S}, \\qquad r = \\dfrac{S}{p}$$`);
|
||||||
|
|
||||||
|
html += makeCard('example', 'Замечательные свойства', '7.3', `
|
||||||
|
<ul style="padding-left:22px;line-height:1.95">
|
||||||
|
<li>Центр $O$ описанной окружности <b>внутри</b> треугольника, если все углы острые; <b>на гипотенузе</b>, если есть прямой угол; <b>снаружи</b>, если есть тупой угол.</li>
|
||||||
|
<li>Центр $I$ вписанной окружности <b>всегда внутри</b> треугольника.</li>
|
||||||
|
<li>Расстояние от центра $I$ до любой стороны равно $r$.</li>
|
||||||
|
</ul>
|
||||||
|
<p><b>Пример.</b> В треугольнике 3-4-5 (прямоугольном): $S = 6$, $p = 6$, $r = S/p = 1$, $R = abc/(4S) = 60/24 = 2{,}5$ — половина гипотенузы.</p>`);
|
||||||
|
|
||||||
|
/* IV1 — Описанная и вписанная окружности */
|
||||||
|
html += `<div class="wg" id="p7-iv1">
|
||||||
|
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Описанная и вписанная окружности</div></div>
|
||||||
|
<div class="wg-help">Выбери тип треугольника — увидишь его описанную ($O$, синяя) и вписанную ($I$, оранжевая) окружности. Заметь, где располагается центр $O$ в каждом случае.</div>
|
||||||
|
<div class="sliders">
|
||||||
|
<label>Тип треугольника<b id="p7-iv1-tval">1</b><input type="range" id="p7-iv1-t" min="1" max="5" step="1" value="1"></label>
|
||||||
|
</div>
|
||||||
|
<div style="background:var(--card);border-radius:10px;padding:10px;overflow-x:auto">
|
||||||
|
<svg id="p7-iv1-svg" viewBox="0 0 420 380" style="width:100%;min-width:340px;height:auto;display:block"></svg>
|
||||||
|
</div>
|
||||||
|
<div id="p7-iv1-out" style="margin-top:10px;padding:10px 14px;background:var(--pri-soft);border-radius:9px;font-size:.95rem;text-align:center;line-height:1.9"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
/* IV2 — Калькулятор R и r */
|
||||||
|
html += `<div class="wg" id="p7-iv2">
|
||||||
|
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор $R$ и $r$</div></div>
|
||||||
|
<div class="wg-help">Введи три стороны треугольника $a$, $b$, $c$ — программа проверит неравенство треугольника и найдёт радиусы по формулам Герона: $S = \\sqrt{p(p-a)(p-b)(p-c)}$, $R = \\tfrac{abc}{4S}$, $r = \\tfrac{S}{p}$.</div>
|
||||||
|
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center;margin-bottom:10px">
|
||||||
|
<span style="font-family:'JetBrains Mono',monospace">$a$ =</span>
|
||||||
|
<input type="number" id="p7-iv2-a" class="tinp" style="width:80px;text-align:center" value="3" min="0.1" step="0.1">
|
||||||
|
<span style="font-family:'JetBrains Mono',monospace">$b$ =</span>
|
||||||
|
<input type="number" id="p7-iv2-b" class="tinp" style="width:80px;text-align:center" value="4" min="0.1" step="0.1">
|
||||||
|
<span style="font-family:'JetBrains Mono',monospace">$c$ =</span>
|
||||||
|
<input type="number" id="p7-iv2-c" class="tinp" style="width:80px;text-align:center" value="5" min="0.1" step="0.1">
|
||||||
|
<button class="btn primary" id="p7-iv2-go">Вычислить</button>
|
||||||
|
</div>
|
||||||
|
<div id="p7-iv2-out" style="padding:12px 14px;background:var(--card);border-radius:9px;text-align:center;font-size:1rem;min-height:50px"></div>
|
||||||
|
<div class="feedback" id="p7-iv2-fb"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
/* IV3 — Quickfire «Внутри или снаружи?» */
|
||||||
|
html += `<div class="wg" id="p7-iv3">
|
||||||
|
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Внутри или снаружи?</div></div>
|
||||||
|
<div class="wg-help">Дан треугольник — определи, где находится центр $O$ описанной окружности.</div>
|
||||||
|
<div class="score-display"><span>Задача <b id="p7-iv3-i">1</b> / 6</span><span>Очки: <b id="p7-iv3-s">0</b> / 6</span></div>
|
||||||
|
<div id="p7-iv3-q" style="padding:14px;background:var(--pri-soft);border-radius:10px;font-size:1.05rem;text-align:center;margin-bottom:10px"></div>
|
||||||
|
<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:8px">
|
||||||
|
<button class="btn primary" data-ans="in" id="p7-iv3-in">Внутри</button>
|
||||||
|
<button class="btn primary" data-ans="hyp" id="p7-iv3-hyp">На гипотенузе</button>
|
||||||
|
<button class="btn primary" data-ans="out" id="p7-iv3-out">Снаружи</button>
|
||||||
|
</div>
|
||||||
|
<div class="feedback" id="p7-iv3-fb"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
/* IV4 — Тренажёр */
|
||||||
|
html += `<div class="wg" id="p7-iv4">
|
||||||
|
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр $R$ и $r$</div></div>
|
||||||
|
<div class="wg-help">Реши задачу и введи число (округли до 2 знаков, если получается дробное).</div>
|
||||||
|
<div class="score-display"><span>Задача <b id="p7-iv4-i">1</b> / 6</span><span>Очки: <b id="p7-iv4-s">0</b> / 6</span></div>
|
||||||
|
<div id="p7-iv4-q" style="padding:14px;background:var(--pri-soft);border-radius:10px;font-size:1.05rem;margin-bottom:10px;text-align:center"></div>
|
||||||
|
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center">
|
||||||
|
<span style="font-family:'JetBrains Mono',monospace">ответ =</span>
|
||||||
|
<input type="number" id="p7-iv4-ans" class="tinp" style="width:110px;text-align:center" step="0.01">
|
||||||
|
<button class="btn primary" id="p7-iv4-go">Проверить</button>
|
||||||
|
<button class="btn" id="p7-iv4-start">Заново</button>
|
||||||
|
</div>
|
||||||
|
<div class="feedback" id="p7-iv4-fb"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
html += secNav(null, 'p8');
|
||||||
|
html += readButton('p7');
|
||||||
|
|
||||||
|
box.innerHTML = html;
|
||||||
|
renderMath(box);
|
||||||
|
|
||||||
|
/* IV1 — визуализатор окружностей */
|
||||||
|
(function(){
|
||||||
|
const sl = document.getElementById('p7-iv1-t');
|
||||||
|
const lab = document.getElementById('p7-iv1-tval');
|
||||||
|
const svg = document.getElementById('p7-iv1-svg');
|
||||||
|
const out = document.getElementById('p7-iv1-out');
|
||||||
|
const seen = new Set();
|
||||||
|
// 5 пресетов: углы A, B, C
|
||||||
|
const PRESETS = [
|
||||||
|
{name:'Равносторонний', angles:[60,60,60], kind:'in'},
|
||||||
|
{name:'Равнобедренный 70-70-40', angles:[70,70,40], kind:'in'},
|
||||||
|
{name:'Прямоугольный 30-60-90', angles:[30,60,90], kind:'hyp'},
|
||||||
|
{name:'Произвольный 40-60-80', angles:[40,60,80], kind:'in'},
|
||||||
|
{name:'Тупоугольный 30-30-120', angles:[30,30,120], kind:'out'}
|
||||||
|
];
|
||||||
|
function draw(){
|
||||||
|
const idx = (+sl.value) - 1;
|
||||||
|
lab.textContent = (idx+1);
|
||||||
|
const P = PRESETS[idx];
|
||||||
|
const [Ad, Bd, Cd] = P.angles;
|
||||||
|
const aR = deg2rad(Ad), bR = deg2rad(Bd);
|
||||||
|
// Сторона BC = a, CA = b, AB = c (закон синусов: a/sinA = 2R)
|
||||||
|
// Зададим масштаб через 2R = 180 (картинка ~ 360 широкая после)
|
||||||
|
const twoR = 170;
|
||||||
|
const a = twoR * Math.sin(aR);
|
||||||
|
const b = twoR * Math.sin(bR);
|
||||||
|
const c = twoR * Math.sin(deg2rad(Cd));
|
||||||
|
// Положим B в (xB, yB) и C в (xB+a, yB) — горизонтально.
|
||||||
|
// Тогда A находится в позиции с углом B при вершине B и c — сторона BA.
|
||||||
|
const cx0 = 210, cy0 = 230; // центр SVG
|
||||||
|
const Bx = -a/2, By = 0;
|
||||||
|
const Cx = a/2, Cy = 0;
|
||||||
|
// A: длина BA = c, угол при B = B (между BA и BC), в SVG y вниз — поднимем A выше
|
||||||
|
const Ax = Bx + c * Math.cos(bR);
|
||||||
|
const Ay = By - c * Math.sin(bR);
|
||||||
|
// Сдвиг так, чтобы центрировать
|
||||||
|
const cxAll = (Ax+Bx+Cx)/3, cyAll = (Ay+By+Cy)/3;
|
||||||
|
const A = {x: cx0 + (Ax - cxAll), y: cy0 + (Ay - cyAll)};
|
||||||
|
const B = {x: cx0 + (Bx - cxAll), y: cy0 + (By - cyAll)};
|
||||||
|
const C = {x: cx0 + (Cx - cxAll), y: cy0 + (Cy - cyAll)};
|
||||||
|
// Длины сторон (в SVG пикселях)
|
||||||
|
function dist(P,Q){ return Math.hypot(P.x-Q.x, P.y-Q.y); }
|
||||||
|
const sa = dist(B,C), sb = dist(C,A), sc = dist(A,B);
|
||||||
|
const p = (sa+sb+sc)/2;
|
||||||
|
const S = Math.sqrt(Math.max(0, p*(p-sa)*(p-sb)*(p-sc)));
|
||||||
|
const R = (sa*sb*sc)/(4*S);
|
||||||
|
const r = S / p;
|
||||||
|
// Центр описанной (через формулы): O = пересечение серединных перпендикуляров.
|
||||||
|
const D = 2 * (A.x*(B.y-C.y) + B.x*(C.y-A.y) + C.x*(A.y-B.y));
|
||||||
|
const Ox = ((A.x*A.x+A.y*A.y)*(B.y-C.y) + (B.x*B.x+B.y*B.y)*(C.y-A.y) + (C.x*C.x+C.y*C.y)*(A.y-B.y)) / D;
|
||||||
|
const Oy = ((A.x*A.x+A.y*A.y)*(C.x-B.x) + (B.x*B.x+B.y*B.y)*(A.x-C.x) + (C.x*C.x+C.y*C.y)*(B.x-A.x)) / D;
|
||||||
|
// Инцентр: I = (sa·A + sb·B + sc·C) / (sa+sb+sc)
|
||||||
|
const Ix = (sa*A.x + sb*B.x + sc*C.x) / (sa+sb+sc);
|
||||||
|
const Iy = (sa*A.y + sb*B.y + sc*C.y) / (sa+sb+sc);
|
||||||
|
|
||||||
|
let s = '';
|
||||||
|
s += '<rect x="0" y="0" width="420" height="380" fill="none"/>';
|
||||||
|
// Описанная окружность
|
||||||
|
s += '<circle cx="'+Ox.toFixed(2)+'" cy="'+Oy.toFixed(2)+'" r="'+R.toFixed(2)+'" fill="none" stroke="#0ea5e9" stroke-width="2" stroke-dasharray="6 4"/>';
|
||||||
|
// Вписанная окружность
|
||||||
|
s += '<circle cx="'+Ix.toFixed(2)+'" cy="'+Iy.toFixed(2)+'" r="'+r.toFixed(2)+'" fill="rgba(245,158,11,.10)" stroke="#f59e0b" stroke-width="2"/>';
|
||||||
|
// Треугольник
|
||||||
|
s += '<polygon points="'+A.x.toFixed(2)+','+A.y.toFixed(2)+' '+B.x.toFixed(2)+','+B.y.toFixed(2)+' '+C.x.toFixed(2)+','+C.y.toFixed(2)+'" fill="rgba(5,150,105,.10)" stroke="#059669" stroke-width="2.2" stroke-linejoin="round"/>';
|
||||||
|
// Центры
|
||||||
|
s += '<circle cx="'+Ox.toFixed(2)+'" cy="'+Oy.toFixed(2)+'" r="4" fill="#0ea5e9"/>';
|
||||||
|
s += '<text x="'+(Ox+8)+'" y="'+(Oy-8)+'" font-family="Inter,sans-serif" font-size="14" font-weight="700" fill="#0ea5e9">O</text>';
|
||||||
|
s += '<circle cx="'+Ix.toFixed(2)+'" cy="'+Iy.toFixed(2)+'" r="4" fill="#f59e0b"/>';
|
||||||
|
s += '<text x="'+(Ix+8)+'" y="'+(Iy+14)+'" font-family="Inter,sans-serif" font-size="14" font-weight="700" fill="#b45309">I</text>';
|
||||||
|
// Вершины
|
||||||
|
s += '<circle cx="'+A.x.toFixed(2)+'" cy="'+A.y.toFixed(2)+'" r="4" fill="#0f172a"/>';
|
||||||
|
s += '<circle cx="'+B.x.toFixed(2)+'" cy="'+B.y.toFixed(2)+'" r="4" fill="#0f172a"/>';
|
||||||
|
s += '<circle cx="'+C.x.toFixed(2)+'" cy="'+C.y.toFixed(2)+'" r="4" fill="#0f172a"/>';
|
||||||
|
s += '<text x="'+(A.x)+'" y="'+(A.y-10)+'" text-anchor="middle" font-family="Inter,sans-serif" font-size="15" font-weight="700" fill="#0f172a">A</text>';
|
||||||
|
s += '<text x="'+(B.x-12)+'" y="'+(B.y+16)+'" text-anchor="end" font-family="Inter,sans-serif" font-size="15" font-weight="700" fill="#0f172a">B</text>';
|
||||||
|
s += '<text x="'+(C.x+12)+'" y="'+(C.y+16)+'" text-anchor="start" font-family="Inter,sans-serif" font-size="15" font-weight="700" fill="#0f172a">C</text>';
|
||||||
|
// Подпись
|
||||||
|
s += '<text x="210" y="22" text-anchor="middle" font-family="Unbounded,sans-serif" font-size="13" font-weight="800" fill="#047857">'+P.name+'</text>';
|
||||||
|
svg.innerHTML = s;
|
||||||
|
|
||||||
|
const place = P.kind==='in' ? 'внутри треугольника' : (P.kind==='hyp' ? 'на гипотенузе' : 'снаружи треугольника');
|
||||||
|
out.innerHTML = 'Углы: '+Ad+'°, '+Bd+'°, '+Cd+'° · $R \\approx '+R.toFixed(1)+'$ · $r \\approx '+r.toFixed(1)+'$<br>Центр $O$ находится <b>'+place+'</b>.';
|
||||||
|
renderMath(out);
|
||||||
|
seen.add(idx);
|
||||||
|
if(seen.size>=4 && !seen.has('done')){ addXp(10,'p7-iv1'); bumpProgress('p7',15); seen.add('done'); }
|
||||||
|
}
|
||||||
|
sl.addEventListener('input', draw);
|
||||||
|
draw();
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* IV2 — Калькулятор */
|
||||||
|
(function(){
|
||||||
|
const aI=document.getElementById('p7-iv2-a');
|
||||||
|
const bI=document.getElementById('p7-iv2-b');
|
||||||
|
const cI=document.getElementById('p7-iv2-c');
|
||||||
|
const go=document.getElementById('p7-iv2-go');
|
||||||
|
const out=document.getElementById('p7-iv2-out');
|
||||||
|
const fb=document.getElementById('p7-iv2-fb');
|
||||||
|
let solved=0;
|
||||||
|
function calc(){
|
||||||
|
const a=parseFloat(aI.value), b=parseFloat(bI.value), c=parseFloat(cI.value);
|
||||||
|
if(!isFinite(a)||!isFinite(b)||!isFinite(c)){ feedback(fb,false,'✗ Введи три числа.'); return; }
|
||||||
|
if(a<=0||b<=0||c<=0){ feedback(fb,false,'✗ Стороны должны быть положительными.'); return; }
|
||||||
|
if(a+b<=c||a+c<=b||b+c<=a){ feedback(fb,false,'✗ Неравенство треугольника не выполняется: сумма любых двух сторон должна быть больше третьей.'); out.innerHTML=''; return; }
|
||||||
|
const p=(a+b+c)/2;
|
||||||
|
const S=Math.sqrt(p*(p-a)*(p-b)*(p-c));
|
||||||
|
const R=(a*b*c)/(4*S);
|
||||||
|
const r=S/p;
|
||||||
|
out.innerHTML='$p = \\tfrac{'+a+'+'+b+'+'+c+'}{2} = '+fmt(p)+'$<br>'
|
||||||
|
+ '$S = \\sqrt{'+fmt(p)+' \\cdot '+fmt(p-a)+' \\cdot '+fmt(p-b)+' \\cdot '+fmt(p-c)+'} \\approx '+S.toFixed(3)+'$<br>'
|
||||||
|
+ '$R = \\dfrac{abc}{4S} = \\dfrac{'+(a*b*c)+'}{'+fmt(4*S)+'} \\approx '+R.toFixed(3)+'$<br>'
|
||||||
|
+ '$r = \\dfrac{S}{p} \\approx '+r.toFixed(3)+'$';
|
||||||
|
renderMath(out);
|
||||||
|
feedback(fb,true,'✓ Готово!');
|
||||||
|
solved++;
|
||||||
|
if(solved===1){ addXp(10,'p7-iv2'); bumpProgress('p7',15); }
|
||||||
|
}
|
||||||
|
go.addEventListener('click', calc);
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* IV3 — Quickfire */
|
||||||
|
(function(){
|
||||||
|
const Q=[
|
||||||
|
{t:'Остроугольный треугольник (все углы меньше 90°). Где центр $O$?', a:'in'},
|
||||||
|
{t:'Прямоугольный треугольник. Где центр $O$?', a:'hyp'},
|
||||||
|
{t:'Тупоугольный треугольник (один угол больше 90°). Где центр $O$?', a:'out'},
|
||||||
|
{t:'Равносторонний треугольник. Где центр $O$?', a:'in'},
|
||||||
|
{t:'Треугольник с углами $90°, 45°, 45°$. Где центр $O$?', a:'hyp'},
|
||||||
|
{t:'Треугольник с углами $30°, 30°, 120°$. Где центр $O$?', a:'out'}
|
||||||
|
];
|
||||||
|
const qBox=document.getElementById('p7-iv3-q');
|
||||||
|
const iEl=document.getElementById('p7-iv3-i');
|
||||||
|
const sEl=document.getElementById('p7-iv3-s');
|
||||||
|
const fb=document.getElementById('p7-iv3-fb');
|
||||||
|
const btns=document.querySelectorAll('#p7-iv3 button[data-ans]');
|
||||||
|
let i=0, score=0, done=false;
|
||||||
|
function show(){
|
||||||
|
if(i>=Q.length){
|
||||||
|
qBox.innerHTML='Завершено! Очки: <b>'+score+'</b> / '+Q.length;
|
||||||
|
if(!done){ done=true; addXp(15,'p7-iv3'); bumpProgress('p7',25); if(score===Q.length) achievement('p7_done'); }
|
||||||
|
btns.forEach(b=>b.disabled=true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qBox.innerHTML=Q[i].t;
|
||||||
|
renderMath(qBox);
|
||||||
|
iEl.textContent=(i+1); sEl.textContent=score;
|
||||||
|
fb.style.display='none';
|
||||||
|
}
|
||||||
|
btns.forEach(b=>b.addEventListener('click', ()=>{
|
||||||
|
const ok = b.dataset.ans===Q[i].a;
|
||||||
|
if(ok) score++;
|
||||||
|
feedback(fb, ok, ok?'✓ Верно!':'✗ Правильный ответ: '+ ({in:'Внутри',hyp:'На гипотенузе',out:'Снаружи'}[Q[i].a]));
|
||||||
|
i++;
|
||||||
|
setTimeout(show, 700);
|
||||||
|
}));
|
||||||
|
show();
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* IV4 — Тренажёр */
|
||||||
|
(function(){
|
||||||
|
const Q=[
|
||||||
|
{t:'В треугольнике стороны $3,4,5$. Найди $R$.', a:2.5},
|
||||||
|
{t:'В треугольнике стороны $3,4,5$. Найди $r$.', a:1},
|
||||||
|
{t:'В равностороннем треугольнике со стороной $6$ найди $R$ (округли до 2 знаков).', a:3.46},
|
||||||
|
{t:'В равностороннем треугольнике со стороной $6$ найди $r$ (округли до 2 знаков).', a:1.73},
|
||||||
|
{t:'В треугольнике стороны $5,12,13$. Найди $R$.', a:6.5},
|
||||||
|
{t:'В треугольнике стороны $6,8,10$. Найди $r$.', a:2}
|
||||||
|
];
|
||||||
|
const qBox=document.getElementById('p7-iv4-q');
|
||||||
|
const ans=document.getElementById('p7-iv4-ans');
|
||||||
|
const go=document.getElementById('p7-iv4-go');
|
||||||
|
const reset=document.getElementById('p7-iv4-start');
|
||||||
|
const iEl=document.getElementById('p7-iv4-i');
|
||||||
|
const sEl=document.getElementById('p7-iv4-s');
|
||||||
|
const fb=document.getElementById('p7-iv4-fb');
|
||||||
|
let i=0, score=0, done=false;
|
||||||
|
function show(){
|
||||||
|
if(i>=Q.length){
|
||||||
|
qBox.innerHTML='Финиш! Очки: <b>'+score+'</b> / '+Q.length;
|
||||||
|
if(!done){ done=true; addXp(15,'p7-iv4'); bumpProgress('p7',25); }
|
||||||
|
go.disabled=true; ans.disabled=true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qBox.innerHTML=Q[i].t; renderMath(qBox);
|
||||||
|
iEl.textContent=(i+1); sEl.textContent=score;
|
||||||
|
ans.value=''; fb.style.display='none'; go.disabled=false; ans.disabled=false;
|
||||||
|
}
|
||||||
|
go.addEventListener('click', ()=>{
|
||||||
|
const v=parseFloat(ans.value);
|
||||||
|
if(!isFinite(v)){ feedback(fb,false,'✗ Введи число.'); return; }
|
||||||
|
const ok=Math.abs(v-Q[i].a)<0.05;
|
||||||
|
if(ok) score++;
|
||||||
|
feedback(fb, ok, ok?'✓ Верно!':'✗ Правильный ответ: $'+Q[i].a+'$');
|
||||||
|
i++;
|
||||||
|
setTimeout(show, 900);
|
||||||
|
});
|
||||||
|
reset.addEventListener('click', ()=>{ i=0; score=0; done=false; show(); });
|
||||||
|
show();
|
||||||
|
})();
|
||||||
|
|
||||||
|
wireReadBtn('p7');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ===== §8 Окружности прямоугольного треугольника ===== */
|
||||||
|
function buildP8(){
|
||||||
|
const box = document.getElementById('p8-body');
|
||||||
|
let html = '';
|
||||||
|
|
||||||
|
html += makeCard('theory', 'Описанная окружность', '8.1', `
|
||||||
|
<p>В прямоугольном треугольнике центр описанной окружности — <b>середина гипотенузы</b>. Радиус:</p>
|
||||||
|
$$R = \\dfrac{c}{2}$$
|
||||||
|
<p>где $c$ — гипотенуза. Это следствие теоремы о вписанном угле: вписанный угол, опирающийся на диаметр, равен $90°$.</p>
|
||||||
|
<p><b>Гипотенуза — диаметр описанной окружности!</b></p>
|
||||||
|
<details class="spoiler"><summary>Почему именно середина гипотенузы?</summary><div class="spoiler-body">
|
||||||
|
В прямоугольном треугольнике медиана к гипотенузе равна её половине. Точка $O$ — середина гипотенузы — равноудалена от трёх вершин на $c/2$, значит это центр описанной окружности.
|
||||||
|
</div></details>`);
|
||||||
|
|
||||||
|
html += makeCard('rule', 'Вписанная окружность', '8.2', `
|
||||||
|
<p>В прямоугольном треугольнике с катетами $a, b$ и гипотенузой $c$ радиус вписанной окружности:</p>
|
||||||
|
$$r = \\dfrac{a + b - c}{2}$$
|
||||||
|
<p>Также верно: $r = \\dfrac{a \\cdot b}{a + b + c}$ (через площадь $S = \\tfrac{ab}{2}$ и полупериметр $p = \\tfrac{a+b+c}{2}$, $r = S/p$).</p>`);
|
||||||
|
|
||||||
|
html += makeCard('example', 'Примеры применения', '8.3', `
|
||||||
|
<ul style="padding-left:22px;line-height:1.95">
|
||||||
|
<li>В треугольнике 3-4-5: $R = 5/2 = 2{,}5$, $r = (3+4-5)/2 = 1$. Проверка: $S = 6, p = 6, r = S/p = 1$. <b>Сошлось.</b></li>
|
||||||
|
<li>В треугольнике 5-12-13: $R = 13/2 = 6{,}5$, $r = (5+12-13)/2 = 2$.</li>
|
||||||
|
<li>В треугольнике 8-15-17: $R = 17/2 = 8{,}5$, $r = (8+15-17)/2 = 3$.</li>
|
||||||
|
</ul>`);
|
||||||
|
|
||||||
|
/* IV1 — SVG */
|
||||||
|
html += `<div class="wg" id="p8-iv1">
|
||||||
|
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 1</span><div class="wg-title">Окружности прямоугольного треугольника</div></div>
|
||||||
|
<div class="wg-help">Меняй катеты ползунками — гипотенуза, $R$ и $r$ пересчитаются. Заметь: центр описанной — посередине гипотенузы.</div>
|
||||||
|
<div class="sliders">
|
||||||
|
<label>Катет $a$<b id="p8-iv1-aval">120</b><input type="range" id="p8-iv1-a" min="40" max="160" step="2" value="120"></label>
|
||||||
|
<label>Катет $b$<b id="p8-iv1-bval">90</b><input type="range" id="p8-iv1-b" min="40" max="160" step="2" value="90"></label>
|
||||||
|
</div>
|
||||||
|
<div style="background:var(--card);border-radius:10px;padding:10px;overflow-x:auto">
|
||||||
|
<svg id="p8-iv1-svg" viewBox="0 0 400 340" style="width:100%;min-width:320px;height:auto;display:block"></svg>
|
||||||
|
</div>
|
||||||
|
<div id="p8-iv1-out" style="margin-top:10px;padding:10px 14px;background:var(--pri-soft);border-radius:9px;font-size:.95rem;text-align:center;line-height:1.9"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
/* IV2 — Калькулятор */
|
||||||
|
html += `<div class="wg" id="p8-iv2">
|
||||||
|
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 2</span><div class="wg-title">Калькулятор $R$ и $r$</div></div>
|
||||||
|
<div class="wg-help">Введи катеты $a$ и $b$ — программа найдёт гипотенузу, радиусы окружностей и проверит $r = S/p$.</div>
|
||||||
|
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center;margin-bottom:10px">
|
||||||
|
<span style="font-family:'JetBrains Mono',monospace">$a$ =</span>
|
||||||
|
<input type="number" id="p8-iv2-a" class="tinp" style="width:90px;text-align:center" value="3" min="0.1" step="0.1">
|
||||||
|
<span style="font-family:'JetBrains Mono',monospace">$b$ =</span>
|
||||||
|
<input type="number" id="p8-iv2-b" class="tinp" style="width:90px;text-align:center" value="4" min="0.1" step="0.1">
|
||||||
|
<button class="btn primary" id="p8-iv2-go">Вычислить</button>
|
||||||
|
</div>
|
||||||
|
<div id="p8-iv2-out" style="padding:12px 14px;background:var(--card);border-radius:9px;text-align:center;font-size:1rem;min-height:50px"></div>
|
||||||
|
<div class="feedback" id="p8-iv2-fb"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
/* IV3 — «Сравни формулы» */
|
||||||
|
html += `<div class="wg" id="p8-iv3">
|
||||||
|
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 3</span><div class="wg-title">Верно или ошибка?</div></div>
|
||||||
|
<div class="wg-help">Утверждение о прямоугольном треугольнике — оцени, верно ли оно.</div>
|
||||||
|
<div class="score-display"><span>Задача <b id="p8-iv3-i">1</b> / 6</span><span>Очки: <b id="p8-iv3-s">0</b> / 6</span></div>
|
||||||
|
<div id="p8-iv3-q" style="padding:14px;background:var(--pri-soft);border-radius:10px;font-size:1.05rem;text-align:center;margin-bottom:10px"></div>
|
||||||
|
<div style="display:grid;grid-template-columns:repeat(2,1fr);gap:8px">
|
||||||
|
<button class="btn primary" data-ans="1" id="p8-iv3-ok">Верно</button>
|
||||||
|
<button class="btn primary" data-ans="0" id="p8-iv3-bad">Ошибка</button>
|
||||||
|
</div>
|
||||||
|
<div class="feedback" id="p8-iv3-fb"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
/* IV4 — Тренажёр */
|
||||||
|
html += `<div class="wg" id="p8-iv4">
|
||||||
|
<div class="wg-header"><span class="wg-badge">ИНТЕРАКТИВ 4</span><div class="wg-title">Тренажёр</div></div>
|
||||||
|
<div class="wg-help">Реши задачу и введи число.</div>
|
||||||
|
<div class="score-display"><span>Задача <b id="p8-iv4-i">1</b> / 6</span><span>Очки: <b id="p8-iv4-s">0</b> / 6</span></div>
|
||||||
|
<div id="p8-iv4-q" style="padding:14px;background:var(--pri-soft);border-radius:10px;font-size:1.05rem;margin-bottom:10px;text-align:center"></div>
|
||||||
|
<div style="display:flex;gap:10px;align-items:center;flex-wrap:wrap;justify-content:center">
|
||||||
|
<span style="font-family:'JetBrains Mono',monospace">ответ =</span>
|
||||||
|
<input type="number" id="p8-iv4-ans" class="tinp" style="width:110px;text-align:center" step="0.01">
|
||||||
|
<button class="btn primary" id="p8-iv4-go">Проверить</button>
|
||||||
|
<button class="btn" id="p8-iv4-start">Заново</button>
|
||||||
|
</div>
|
||||||
|
<div class="feedback" id="p8-iv4-fb"></div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
html += secNav('p7', 'p9');
|
||||||
|
html += readButton('p8');
|
||||||
|
|
||||||
|
box.innerHTML = html;
|
||||||
|
renderMath(box);
|
||||||
|
|
||||||
|
/* IV1 */
|
||||||
|
(function(){
|
||||||
|
const aS=document.getElementById('p8-iv1-a');
|
||||||
|
const bS=document.getElementById('p8-iv1-b');
|
||||||
|
const aL=document.getElementById('p8-iv1-aval');
|
||||||
|
const bL=document.getElementById('p8-iv1-bval');
|
||||||
|
const svg=document.getElementById('p8-iv1-svg');
|
||||||
|
const out=document.getElementById('p8-iv1-out');
|
||||||
|
const seen=new Set();
|
||||||
|
function draw(){
|
||||||
|
const a=+aS.value, b=+bS.value;
|
||||||
|
aL.textContent=a; bL.textContent=b;
|
||||||
|
// Вершины: C = прямой угол (нижний-левый), B = (a, 0) — катет a по горизонтали, A = (0, -b)
|
||||||
|
const margin=40;
|
||||||
|
const C={x:margin, y:margin+b};
|
||||||
|
const B={x:margin+a, y:margin+b};
|
||||||
|
const A={x:margin, y:margin};
|
||||||
|
const c=Math.hypot(a,b);
|
||||||
|
const R=c/2;
|
||||||
|
const r=(a+b-c)/2;
|
||||||
|
// Центр описанной — середина гипотенузы AB
|
||||||
|
const O={x:(A.x+B.x)/2, y:(A.y+B.y)/2};
|
||||||
|
// Центр вписанной: на (r, r) от вершины прямого угла внутрь.
|
||||||
|
// C — нижний-левый; внутрь треугольника направление: +x (к B), -y (к A)
|
||||||
|
const I={x:C.x+r, y:C.y-r};
|
||||||
|
const uCA=unitVec(C,A);
|
||||||
|
const uCB=unitVec(C,B);
|
||||||
|
|
||||||
|
let s='';
|
||||||
|
s += '<rect x="0" y="0" width="400" height="340" fill="none"/>';
|
||||||
|
// Описанная окружность
|
||||||
|
s += '<circle cx="'+O.x.toFixed(2)+'" cy="'+O.y.toFixed(2)+'" r="'+R.toFixed(2)+'" fill="none" stroke="#0ea5e9" stroke-width="2" stroke-dasharray="6 4"/>';
|
||||||
|
// Вписанная
|
||||||
|
s += '<circle cx="'+I.x.toFixed(2)+'" cy="'+I.y.toFixed(2)+'" r="'+r.toFixed(2)+'" fill="rgba(245,158,11,.12)" stroke="#f59e0b" stroke-width="2"/>';
|
||||||
|
// Треугольник
|
||||||
|
s += '<polygon points="'+A.x+','+A.y+' '+B.x+','+B.y+' '+C.x+','+C.y+'" fill="rgba(5,150,105,.10)" stroke="#059669" stroke-width="2.2" stroke-linejoin="round"/>';
|
||||||
|
// Прямой угол в C
|
||||||
|
s += '<polyline points="'+rightAngleMark(C, uCA, uCB, 12)+'" fill="none" stroke="#0f172a" stroke-width="1.8"/>';
|
||||||
|
// Центры
|
||||||
|
s += '<circle cx="'+O.x.toFixed(2)+'" cy="'+O.y.toFixed(2)+'" r="4" fill="#0ea5e9"/>';
|
||||||
|
s += '<text x="'+(O.x+9)+'" y="'+(O.y-7)+'" font-family="Inter,sans-serif" font-size="14" font-weight="700" fill="#0369a1">O</text>';
|
||||||
|
s += '<circle cx="'+I.x.toFixed(2)+'" cy="'+I.y.toFixed(2)+'" r="4" fill="#f59e0b"/>';
|
||||||
|
s += '<text x="'+(I.x+9)+'" y="'+(I.y+14)+'" font-family="Inter,sans-serif" font-size="14" font-weight="700" fill="#b45309">I</text>';
|
||||||
|
// Вершины + подписи
|
||||||
|
s += '<circle cx="'+A.x+'" cy="'+A.y+'" r="4" fill="#0f172a"/>';
|
||||||
|
s += '<circle cx="'+B.x+'" cy="'+B.y+'" r="4" fill="#0f172a"/>';
|
||||||
|
s += '<circle cx="'+C.x+'" cy="'+C.y+'" r="4" fill="#0f172a"/>';
|
||||||
|
s += '<text x="'+(A.x-12)+'" y="'+(A.y-4)+'" text-anchor="end" font-family="Inter,sans-serif" font-size="15" font-weight="700" fill="#0f172a">A</text>';
|
||||||
|
s += '<text x="'+(B.x+10)+'" y="'+(B.y+16)+'" font-family="Inter,sans-serif" font-size="15" font-weight="700" fill="#0f172a">B</text>';
|
||||||
|
s += '<text x="'+(C.x-12)+'" y="'+(C.y+16)+'" text-anchor="end" font-family="Inter,sans-serif" font-size="15" font-weight="700" fill="#0f172a">C</text>';
|
||||||
|
// Подписи сторон
|
||||||
|
s += '<text x="'+((B.x+C.x)/2)+'" y="'+(C.y+24)+'" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="12" fill="#047857">a='+a+'</text>';
|
||||||
|
s += '<text x="'+(C.x-22)+'" y="'+((A.y+C.y)/2)+'" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="12" fill="#047857">b='+b+'</text>';
|
||||||
|
// Гипотенуза
|
||||||
|
const midAB={x:(A.x+B.x)/2, y:(A.y+B.y)/2};
|
||||||
|
s += '<text x="'+(midAB.x+12)+'" y="'+(midAB.y-6)+'" font-family="JetBrains Mono,monospace" font-size="12" fill="#047857">c='+c.toFixed(1)+'</text>';
|
||||||
|
svg.innerHTML = s;
|
||||||
|
|
||||||
|
out.innerHTML = '$c = \\sqrt{'+(a*a)+'+'+(b*b)+'} \\approx '+c.toFixed(2)+'$ · $R = c/2 \\approx '+R.toFixed(2)+'$ · $r = (a+b-c)/2 \\approx '+r.toFixed(2)+'$<br><b>Диаметр</b> описанной = гипотенуза $c$.';
|
||||||
|
renderMath(out);
|
||||||
|
seen.add(a+'-'+b);
|
||||||
|
if(seen.size>=4 && !seen.has('done')){ addXp(10,'p8-iv1'); bumpProgress('p8',15); seen.add('done'); }
|
||||||
|
}
|
||||||
|
aS.addEventListener('input', draw);
|
||||||
|
bS.addEventListener('input', draw);
|
||||||
|
draw();
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* IV2 */
|
||||||
|
(function(){
|
||||||
|
const aI=document.getElementById('p8-iv2-a');
|
||||||
|
const bI=document.getElementById('p8-iv2-b');
|
||||||
|
const go=document.getElementById('p8-iv2-go');
|
||||||
|
const out=document.getElementById('p8-iv2-out');
|
||||||
|
const fb=document.getElementById('p8-iv2-fb');
|
||||||
|
let solved=0;
|
||||||
|
function calc(){
|
||||||
|
const a=parseFloat(aI.value), b=parseFloat(bI.value);
|
||||||
|
if(!isFinite(a)||!isFinite(b)){ feedback(fb,false,'✗ Введи два числа.'); return; }
|
||||||
|
if(a<=0||b<=0){ feedback(fb,false,'✗ Катеты должны быть положительными.'); return; }
|
||||||
|
const c=Math.sqrt(a*a+b*b);
|
||||||
|
const R=c/2;
|
||||||
|
const r=(a+b-c)/2;
|
||||||
|
const S=a*b/2;
|
||||||
|
const p=(a+b+c)/2;
|
||||||
|
const rCheck=S/p;
|
||||||
|
out.innerHTML='$c = \\sqrt{'+a+'^2+'+b+'^2} = \\sqrt{'+(a*a+b*b)+'} \\approx '+c.toFixed(3)+'$<br>'
|
||||||
|
+'$R = \\dfrac{c}{2} \\approx '+R.toFixed(3)+'$<br>'
|
||||||
|
+'$r = \\dfrac{a+b-c}{2} \\approx '+r.toFixed(3)+'$<br>'
|
||||||
|
+'Проверка: $S = \\tfrac{ab}{2} = '+fmt(S)+'$, $p = '+fmt(p)+'$, $r = S/p \\approx '+rCheck.toFixed(3)+'$';
|
||||||
|
renderMath(out);
|
||||||
|
feedback(fb,true,'✓ Готово!');
|
||||||
|
solved++;
|
||||||
|
if(solved===1){ addXp(10,'p8-iv2'); bumpProgress('p8',15); }
|
||||||
|
}
|
||||||
|
go.addEventListener('click', calc);
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* IV3 — Quickfire верно/ошибка */
|
||||||
|
(function(){
|
||||||
|
const Q=[
|
||||||
|
{t:'$R = \\dfrac{c}{2}$, где $c$ — гипотенуза.', a:'1'},
|
||||||
|
{t:'$r = a + b - c$ (без деления на 2).', a:'0'},
|
||||||
|
{t:'Гипотенуза — диаметр описанной окружности.', a:'1'},
|
||||||
|
{t:'Центр описанной окружности лежит вне прямоугольного треугольника.', a:'0'},
|
||||||
|
{t:'$r = \\dfrac{a+b+c}{2}$.', a:'0'},
|
||||||
|
{t:'В треугольнике 6-8-10 радиус описанной окружности равен $5$.', a:'1'}
|
||||||
|
];
|
||||||
|
const fix=['✗ $r = \\dfrac{a+b-c}{2}$ — обязательно делить на 2.',
|
||||||
|
'',
|
||||||
|
'',
|
||||||
|
'✗ Центр $O$ лежит на середине гипотенузы (на самой гипотенузе).',
|
||||||
|
'✗ Это полупериметр $p$, а не радиус. $r = \\dfrac{a+b-c}{2}$.',
|
||||||
|
''];
|
||||||
|
const qBox=document.getElementById('p8-iv3-q');
|
||||||
|
const iEl=document.getElementById('p8-iv3-i');
|
||||||
|
const sEl=document.getElementById('p8-iv3-s');
|
||||||
|
const fb=document.getElementById('p8-iv3-fb');
|
||||||
|
const btns=document.querySelectorAll('#p8-iv3 button[data-ans]');
|
||||||
|
let i=0, score=0, done=false;
|
||||||
|
function show(){
|
||||||
|
if(i>=Q.length){
|
||||||
|
qBox.innerHTML='Завершено! Очки: <b>'+score+'</b> / '+Q.length;
|
||||||
|
if(!done){ done=true; addXp(15,'p8-iv3'); bumpProgress('p8',25); if(score===Q.length) achievement('p8_done'); }
|
||||||
|
btns.forEach(b=>b.disabled=true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qBox.innerHTML=Q[i].t; renderMath(qBox);
|
||||||
|
iEl.textContent=(i+1); sEl.textContent=score;
|
||||||
|
fb.style.display='none';
|
||||||
|
}
|
||||||
|
btns.forEach(b=>b.addEventListener('click', ()=>{
|
||||||
|
const ok = b.dataset.ans===Q[i].a;
|
||||||
|
if(ok) score++;
|
||||||
|
const correctMsg = Q[i].a==='1' ? '✓ Верно — утверждение истинно.' : (fix[i] || '✓ Верно — утверждение ложно.');
|
||||||
|
feedback(fb, ok, ok?correctMsg:('✗ '+(Q[i].a==='1'?'На самом деле — верно.':(fix[i]||'На самом деле — ошибка.'))));
|
||||||
|
i++;
|
||||||
|
setTimeout(show, 900);
|
||||||
|
}));
|
||||||
|
show();
|
||||||
|
})();
|
||||||
|
|
||||||
|
/* IV4 */
|
||||||
|
(function(){
|
||||||
|
const Q=[
|
||||||
|
{t:'В треугольнике $3,4,5$ найди $R$.', a:2.5},
|
||||||
|
{t:'В треугольнике $5,12,13$ найди $r$.', a:2},
|
||||||
|
{t:'В треугольнике $8,15,17$ найди $R$.', a:8.5},
|
||||||
|
{t:'В треугольнике $8,15,17$ найди $r$.', a:3},
|
||||||
|
{t:'В треугольнике $6,8,10$ найди $r$.', a:2},
|
||||||
|
{t:'В треугольнике $9,40,41$ найди $R$.', a:20.5}
|
||||||
|
];
|
||||||
|
const qBox=document.getElementById('p8-iv4-q');
|
||||||
|
const ans=document.getElementById('p8-iv4-ans');
|
||||||
|
const go=document.getElementById('p8-iv4-go');
|
||||||
|
const reset=document.getElementById('p8-iv4-start');
|
||||||
|
const iEl=document.getElementById('p8-iv4-i');
|
||||||
|
const sEl=document.getElementById('p8-iv4-s');
|
||||||
|
const fb=document.getElementById('p8-iv4-fb');
|
||||||
|
let i=0, score=0, done=false;
|
||||||
|
function show(){
|
||||||
|
if(i>=Q.length){
|
||||||
|
qBox.innerHTML='Финиш! Очки: <b>'+score+'</b> / '+Q.length;
|
||||||
|
if(!done){ done=true; addXp(15,'p8-iv4'); bumpProgress('p8',25); }
|
||||||
|
go.disabled=true; ans.disabled=true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
qBox.innerHTML=Q[i].t; renderMath(qBox);
|
||||||
|
iEl.textContent=(i+1); sEl.textContent=score;
|
||||||
|
ans.value=''; fb.style.display='none'; go.disabled=false; ans.disabled=false;
|
||||||
|
}
|
||||||
|
go.addEventListener('click', ()=>{
|
||||||
|
const v=parseFloat(ans.value);
|
||||||
|
if(!isFinite(v)){ feedback(fb,false,'✗ Введи число.'); return; }
|
||||||
|
const ok=Math.abs(v-Q[i].a)<0.05;
|
||||||
|
if(ok) score++;
|
||||||
|
feedback(fb, ok, ok?'✓ Верно!':'✗ Правильный ответ: $'+Q[i].a+'$');
|
||||||
|
i++;
|
||||||
|
setTimeout(show, 900);
|
||||||
|
});
|
||||||
|
reset.addEventListener('click', ()=>{ i=0; score=0; done=false; show(); });
|
||||||
|
show();
|
||||||
|
})();
|
||||||
|
|
||||||
|
wireReadBtn('p8');
|
||||||
|
}
|
||||||
function buildP9(){ _stubBuilder('p9', '§9', 'Вписанные и описанные четырёхугольники', 'p8', 'final2'); }
|
function buildP9(){ _stubBuilder('p9', '§9', 'Вписанные и описанные четырёхугольники', 'p8', 'final2'); }
|
||||||
|
|
||||||
function buildFinal2(){
|
function buildFinal2(){
|
||||||
|
|||||||
Reference in New Issue
Block a user