fix(geom9 ch2): R, r и катеты в реальных единицах вместо пикселей

§7 IV1 «Описанная и вписанная окружности»:
- было: R ≈ 73.8, r ≈ 21.5 — числа в SVG-пикселях
- стало: коэффициент px/единица = 17 (twoR=170px → 2R=10),
  выводятся R ≈ 4.34, r ≈ 1.26 в учебных единицах

§8 IV1 «Окружности прямоугольного треугольника»:
- было: слайдеры катетов 40..160, подписи a=120, b=90,
  гипотенуза c=150 — пиксели, выглядит как абсурдные длины
- стало: слайдеры 2..8 ед. с шагом 0.1, K=30 px/ед.,
  всё показывается в единицах. Формулы $c = \sqrt{6^2+4.5^2}$
  и $R, r$ — нормальные геометрические числа

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
Maxim Dolgolyov
2026-05-29 10:57:58 +03:00
parent 4652f9a73d
commit 8b8616e1de
+32 -21
View File
@@ -652,7 +652,11 @@ function buildP7(){
svg.innerHTML = s;
const place = P.kind==='in' ? 'внутри треугольника' : (P.kind==='hyp' ? 'на гипотенузе' : 'снаружи треугольника');
out.innerHTML = 'Углы: '+Ad+'°, '+Bd+'°, '+Cd+'° &nbsp;·&nbsp; $R \\approx '+R.toFixed(1)+'$ &nbsp;·&nbsp; $r \\approx '+r.toFixed(1)+'$<br>Центр $O$ находится <b>'+place+'</b>.';
// twoR = 170 px соответствует 2R = 10 ед. → коэффициент px / ед. = 17
const pxPerUnit = 17;
const Ru = R / pxPerUnit;
const ru = r / pxPerUnit;
out.innerHTML = 'Углы: '+Ad+'°, '+Bd+'°, '+Cd+'° &nbsp;·&nbsp; $R \\approx '+Ru.toFixed(2)+'$ &nbsp;·&nbsp; $r \\approx '+ru.toFixed(2)+'$<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'); }
@@ -805,8 +809,8 @@ function buildP8(){
<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>
<label>Катет $a$<b id="p8-iv1-aval">6</b><input type="range" id="p8-iv1-a" min="2" max="8" step="0.1" value="6"></label>
<label>Катет $b$<b id="p8-iv1-bval">4.5</b><input type="range" id="p8-iv1-b" min="2" max="8" step="0.1" value="4.5"></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>
@@ -873,30 +877,38 @@ function buildP8(){
const out=document.getElementById('p8-iv1-out');
const seen=new Set();
function draw(){
// a, b — катеты в единицах (диапазон 2..8). Для отрисовки умножаем на K.
const a=+aS.value, b=+bS.value;
aL.textContent=a; bL.textContent=b;
// Вершины: C = прямой угол (нижний-левый), B = (a, 0) — катет a по горизонтали, A = (0, -b)
aL.textContent=a.toFixed(1); bL.textContent=b.toFixed(1);
const K=30; // px на единицу
const aPx=a*K, bPx=b*K;
// Вершины (в SVG-координатах):
// C — прямой угол, нижний-левый.
// B — нижний-правый (горизонтальный катет от C, длиной a).
// A — верхний-левый (вертикальный катет от C, длиной b).
const margin=40;
const C={x:margin, y:margin+b};
const B={x:margin+a, y:margin+b};
const C={x:margin, y:margin+bPx};
const B={x:margin+aPx, y:margin+bPx};
const A={x:margin, y:margin};
const c=Math.hypot(a,b);
const R=c/2;
const r=(a+b-c)/2;
const c=Math.hypot(a,b); // в единицах
const cPx=Math.hypot(aPx,bPx); // в пикселях
const R=c/2; // в единицах
const r=(a+b-c)/2; // в единицах
const RPx=cPx/2;
const rPx=(aPx+bPx-cPx)/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};
// Центр вписанной на (r, r) от прямого угла C внутрь треугольника
const I={x:C.x+rPx, y:C.y-rPx};
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="'+O.x.toFixed(2)+'" cy="'+O.y.toFixed(2)+'" r="'+RPx.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 += '<circle cx="'+I.x.toFixed(2)+'" cy="'+I.y.toFixed(2)+'" r="'+rPx.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
@@ -913,15 +925,14 @@ function buildP8(){
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>';
// Гипотенуза
// Подписи сторон — в единицах
s += '<text x="'+((B.x+C.x)/2)+'" y="'+(C.y+24)+'" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="12" font-weight="700" fill="#047857">a='+a.toFixed(1)+'</text>';
s += '<text x="'+(C.x-22)+'" y="'+((A.y+C.y)/2)+'" text-anchor="middle" font-family="JetBrains Mono,monospace" font-size="12" font-weight="700" fill="#047857">b='+b.toFixed(1)+'</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>';
s += '<text x="'+(midAB.x+12)+'" y="'+(midAB.y-6)+'" font-family="JetBrains Mono,monospace" font-size="12" font-weight="700" fill="#047857">c='+c.toFixed(2)+'</text>';
svg.innerHTML = s;
out.innerHTML = '$c = \\sqrt{'+(a*a)+'+'+(b*b)+'} \\approx '+c.toFixed(2)+'$ &nbsp;·&nbsp; $R = c/2 \\approx '+R.toFixed(2)+'$ &nbsp;·&nbsp; $r = (a+b-c)/2 \\approx '+r.toFixed(2)+'$<br><b>Диаметр</b> описанной = гипотенуза $c$.';
out.innerHTML = '$c = \\sqrt{'+a.toFixed(1)+'^2+'+b.toFixed(1)+'^2} \\approx '+c.toFixed(2)+'$ &nbsp;·&nbsp; $R = c/2 \\approx '+R.toFixed(2)+'$ &nbsp;·&nbsp; $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'); }