diff --git a/frontend/textbooks/geometry_9_ch1.html b/frontend/textbooks/geometry_9_ch1.html
index 25a986b..18b4a25 100644
--- a/frontend/textbooks/geometry_9_ch1.html
+++ b/frontend/textbooks/geometry_9_ch1.html
@@ -644,69 +644,77 @@ function buildP1(){
box.innerHTML = html;
renderMath(box);
- /* IV1 — слайдер + SVG */
+ /* IV1 — слайдер + SVG (стандартное расположение: прямой угол справа-снизу, угол α при A) */
(function(){
const sl = document.getElementById('p1-iv1-a');
const lab = document.getElementById('p1-iv1-aval');
const svg = document.getElementById('p1-iv1-svg');
const out = document.getElementById('p1-iv1-out');
const seen = new Set();
+ // Цвета сторон: гипотенуза — фиолетовая, противолежащий α — красный, прилежащий — синий.
+ const COL_HYP = '#7c3aed', COL_OPP = '#dc2626', COL_ADJ = '#2563eb';
function draw(){
const aDeg = +sl.value;
lab.textContent = aDeg;
const aRad = deg2rad(aDeg);
- const c = 220; // гипотенуза в пикселях
- // Геометрические вершины: A (внизу слева), B (верх — прямой угол), C (внизу справа).
- // Прямой угол при B. Угол α при C.
- // BC = c·cos α (горизонтальный катет, прилежащий к α)
- // AB = c·sin α (вертикальный катет, противолежащий α)
- const BCpx = c * Math.cos(aRad);
- const ABpx = c * Math.sin(aRad);
- const cx = 60, cyBase = 270; // позиция A
- const A = {x: cx, y: cyBase};
- const C = {x: cx + BCpx, y: cyBase};
- const B = {x: cx, y: cyBase - ABpx};
- // Внутренние векторы в B (прямой угол): по BA — вниз, по BC — вправо-вниз
- const uBA = unitVec(B, A);
- const uBC = unitVec(B, C);
- const uCA = unitVec(C, A); // вдоль гипотенузы из C
- const uCB = unitVec(C, B); // вдоль катета из C
+ // Целые «единицы» для подписи: гипотенуза c = 10.
+ const cUnits = 10;
+ const aUnits = +(cUnits * Math.sin(aRad)).toFixed(2); // противолежащий α
+ const bUnits = +(cUnits * Math.cos(aRad)).toFixed(2); // прилежащий α
+ // Масштаб px на единицу подбираем так, чтобы прилежащий катет вписался в ~300 px.
+ const px = 26;
+ // Стандартное расположение:
+ // A — нижний левый угол (вершина с углом α).
+ // C — нижний правый угол (прямой угол).
+ // B — верхний правый угол.
+ // Гипотенуза = AB (диагональ), прилежащий к α = AC (горизонталь), противолежащий = BC (вертикаль).
+ const A = {x: 60, y: 280};
+ const C = {x: 60 + bUnits * px, y: 280};
+ const B = {x: C.x, y: 280 - aUnits * px};
+ // Векторы внутрь треугольника
+ const uCA = unitVec(C, A), uCB = unitVec(C, B); // прямой угол в C
+ const uAC = unitVec(A, C), uAB = unitVec(A, B); // острый α в A
let s = '';
- // фон
- s += '';
- // треугольник
- s += '';
- // маркер прямого угла в B (внутренние векторы — uBA и uBC)
- s += '';
- // дуга угла α при C (от CA к CB)
- s += '';
+ // Стороны как отдельные линии разных цветов
+ s += '';
+ s += '';
+ s += '';
+ s += '';
+ // маркер прямого угла в C
+ s += '';
+ // дуга угла α при A
+ s += '';
// подпись α
- const aMid = {x: C.x + 44*Math.cos(Math.atan2((uCA.y+uCB.y)/2,(uCA.x+uCB.x)/2)), y: C.y + 44*Math.sin(Math.atan2((uCA.y+uCB.y)/2,(uCA.x+uCB.x)/2))};
- s += 'α';
+ const midDir = {x:(uAC.x+uAB.x)/2, y:(uAC.y+uAB.y)/2};
+ const midLen = Math.sqrt(midDir.x*midDir.x+midDir.y*midDir.y) || 1;
+ const aLab = {x: A.x + 50*midDir.x/midLen, y: A.y + 50*midDir.y/midLen};
+ s += 'α';
// вершины
- s += '';
- s += '';
- s += '';
- s += 'A';
- s += 'B';
- s += 'C';
- // подписи сторон
- const labBC = 'BC='+(BCpx/22).toFixed(2);
- const labAB = 'AB='+(ABpx/22).toFixed(2);
- const labAC = 'AC='+(c/22).toFixed(2);
- s += ''+labBC+'';
- s += ''+labAB+'';
- // подпись гипотенузы — поднимем над линией AC
- const midAC = {x:(A.x+C.x)/2, y:(A.y+C.y)/2};
- const nAC = {x:-(C.y-A.y), y:(C.x-A.x)};
- const nL = Math.sqrt(nAC.x*nAC.x+nAC.y*nAC.y)||1;
- const labP = {x: midAC.x + 16*nAC.x/nL, y: midAC.y + 16*nAC.y/nL};
- s += ''+labAC+'';
+ [A,B,C].forEach(P=>{ s+=''; });
+ s += 'A';
+ s += 'B';
+ s += 'C';
+ // длина прилежащего катета AC
+ s += 'b = '+bUnits.toFixed(2)+'';
+ // длина противолежащего BC
+ s += 'a = '+aUnits.toFixed(2)+'';
+ // длина гипотенузы AB — над линией
+ const midAB = {x:(A.x+B.x)/2, y:(A.y+B.y)/2};
+ const nAB = {x:-(B.y-A.y), y:(B.x-A.x)};
+ const nL = Math.sqrt(nAB.x*nAB.x+nAB.y*nAB.y)||1;
+ const labHyp = {x: midAB.x - 22*nAB.x/nL, y: midAB.y - 22*nAB.y/nL};
+ s += 'c = '+cUnits+'';
+ // легенда
+ s += '';
+ s += 'гипотенуза c';
+ s += 'противолежащий a';
+ s += 'прилежащий b';
+ s += '';
svg.innerHTML = s;
// числовые значения
const sn = Math.sin(aRad), cs = Math.cos(aRad), tn = Math.tan(aRad), ct = 1/Math.tan(aRad);
- out.innerHTML = '$\\sin '+aDeg+'^\\circ \\approx '+sn.toFixed(3)+'$ · $\\cos '+aDeg+'^\\circ \\approx '+cs.toFixed(3)+'$ '
- + '$\\tan '+aDeg+'^\\circ \\approx '+tn.toFixed(3)+'$ · $\\cot '+aDeg+'^\\circ \\approx '+ct.toFixed(3)+'$';
+ out.innerHTML = '$\\sin '+aDeg+'^\\circ = \\dfrac{a}{c} \\approx '+sn.toFixed(3)+'$ · $\\cos '+aDeg+'^\\circ = \\dfrac{b}{c} \\approx '+cs.toFixed(3)+'$ '
+ + '$\\tan '+aDeg+'^\\circ = \\dfrac{a}{b} \\approx '+tn.toFixed(3)+'$ · $\\cot '+aDeg+'^\\circ = \\dfrac{b}{a} \\approx '+ct.toFixed(3)+'$';
renderMath(out);
seen.add(aDeg);
if(seen.size >= 6 && !seen.has('done')){ addXp(10,'p1-iv1'); bumpProgress('p1', 15); seen.add('done'); }
@@ -1231,8 +1239,8 @@ function buildP3(){
/* IV1 — Три эталонных треугольника */
html += `
-
ИНТЕРАКТИВ 1
Три эталонных треугольника
-
Слева — треугольник $30^\\circ\\text{-}60^\\circ\\text{-}90^\\circ$ (катеты $1$ и $\\sqrt{3}$, гипотенуза $2$). Справа — равнобедренный $45^\\circ\\text{-}45^\\circ\\text{-}90^\\circ$ (катеты $1$, гипотенуза $\\sqrt{2}$).
+
ИНТЕРАКТИВ 1
Два эталонных треугольника
+
Слева — треугольник $30^\\circ\\text{-}60^\\circ\\text{-}90^\\circ$ (катеты $1$ и $\\sqrt{3}$, гипотенуза $2$): из него читаются значения для $30^\\circ$ и $60^\\circ$. Справа — равнобедренный $45^\\circ\\text{-}45^\\circ\\text{-}90^\\circ$ (катеты $1$, гипотенуза $\\sqrt{2}$): из него — значения для $45^\\circ$.
@@ -1304,82 +1312,77 @@ function buildP3(){
box.innerHTML = html;
renderMath(box);
- /* IV1 — рисуем три эталонных треугольника */
+ /* IV1 — Два эталонных треугольника (стандартное расположение: прямой угол справа-снизу) */
(function(){
const svg = document.getElementById('p3-iv1-svg');
if(!svg) return;
- let s = '';
- // Треугольник 30-60-90: катеты 1 и sqrt(3), гипотенуза 2. Используем масштаб 60 px = 1 ед.
- // Левый: BC = sqrt(3) (горизонт., прилежащий 30°), AB = 1 (вертикальный, противолежащий 30°)
- // Вершины: A слева внизу, B слева вверху (прямой угол), C справа внизу.
- // Угол 30° при C, угол 60° при A.
- (function(){
- const u = 60;
- const Ax = 40, Ay = 180;
- const A = {x: Ax, y: Ay};
- const B = {x: Ax, y: Ay - u}; // катет AB = 1
- const C = {x: Ax + Math.sqrt(3)*u, y: Ay}; // катет BC = sqrt(3)
- const uBA = unitVec(B, A);
- const uBC = unitVec(B, C);
- const uCA = unitVec(C, A);
- const uCB = unitVec(C, B);
- const uAB = unitVec(A, B);
- const uAC = unitVec(A, C);
- s += '';
- s += '';
- s += '';
- s += '';
- // подписи углов
- s += '30°';
- s += '60°';
- // вершины и подписи
- ['A','B','C'].forEach((nm,i)=>{ const P=[A,B,C][i]; s+=''; });
- s += 'A';
- s += 'B';
- s += 'C';
- // длины сторон
- s += '1';
- s += '√3';
- const midAC={x:(A.x+C.x)/2, y:(A.y+C.y)/2};
- const nAC={x:-(C.y-A.y), y:(C.x-A.x)};
- const nL=Math.sqrt(nAC.x*nAC.x+nAC.y*nAC.y)||1;
- const labP={x: midAC.x + 16*nAC.x/nL, y: midAC.y + 16*nAC.y/nL};
- s += '2';
+ // Стандартная схема для обоих треугольников:
+ // A — нижний левый угол (острый, на нём показываем основной интересующий нас угол).
+ // C — нижний правый угол (прямой).
+ // B — верхний правый угол (второй острый).
+ // Прилежащий катет = AC (горизонтальный), противолежащий = BC (вертикальный), гипотенуза = AB.
+ function drawTri(opts){
+ const { Ax, Ay, b, a, angAname, angBname, sideAdjLab, sideOppLab, hypLab, title } = opts;
+ const A = {x: Ax, y: Ay};
+ const C = {x: Ax + b, y: Ay};
+ const B = {x: C.x, y: Ay - a};
+ const uCA = unitVec(C, A), uCB = unitVec(C, B);
+ const uAC = unitVec(A, C), uAB = unitVec(A, B);
+ const uBA = unitVec(B, A), uBC = unitVec(B, C);
+ let s = '';
+ // заполнение и контур треугольника
+ s += '';
+ // маркер прямого угла в C
+ s += '';
+ // дуга и подпись угла при A (основной)
+ s += '';
+ const midA = {x:(uAC.x+uAB.x)/2, y:(uAC.y+uAB.y)/2};
+ const mAlen = Math.sqrt(midA.x*midA.x+midA.y*midA.y)||1;
+ s += ''+angAname+'';
+ // дуга и подпись угла при B
+ s += '';
+ const midB = {x:(uBA.x+uBC.x)/2, y:(uBA.y+uBC.y)/2};
+ const mBlen = Math.sqrt(midB.x*midB.x+midB.y*midB.y)||1;
+ s += ''+angBname+'';
+ // вершины
+ [A,B,C].forEach(P=>{ s+=''; });
+ s += 'A';
+ s += 'B';
+ s += 'C';
+ // длина прилежащего AC
+ s += ''+sideAdjLab+'';
+ // длина противолежащего BC
+ s += ''+sideOppLab+'';
+ // длина гипотенузы AB — над линией
+ const midAB = {x:(A.x+B.x)/2, y:(A.y+B.y)/2};
+ const nAB = {x:-(B.y-A.y), y:(B.x-A.x)};
+ const nL = Math.sqrt(nAB.x*nAB.x+nAB.y*nAB.y)||1;
+ const labP = {x: midAB.x - 18*nAB.x/nL, y: midAB.y - 18*nAB.y/nL};
+ s += ''+hypLab+'';
// заголовок
- s += '30\xb0-60\xb0-90\xb0';
- })();
- // Треугольник 45-45-90: оба катета 1, гипотенуза sqrt(2). Масштаб тот же.
- (function(){
- const u = 90; // покрупнее
- const Ax = 360, Ay = 180;
- const A = {x: Ax, y: Ay};
- const B = {x: Ax, y: Ay - u};
- const C = {x: Ax + u, y: Ay};
- const uBA = unitVec(B, A);
- const uBC = unitVec(B, C);
- const uCA = unitVec(C, A);
- const uCB = unitVec(C, B);
- const uAB = unitVec(A, B);
- const uAC = unitVec(A, C);
- s += '';
- s += '';
- s += '';
- s += '';
- s += '45°';
- s += '45°';
- ['A','B','C'].forEach((nm,i)=>{ const P=[A,B,C][i]; s+=''; });
- s += 'A';
- s += 'B';
- s += 'C';
- s += '1';
- s += '1';
- const midAC={x:(A.x+C.x)/2, y:(A.y+C.y)/2};
- const nAC={x:-(C.y-A.y), y:(C.x-A.x)};
- const nL=Math.sqrt(nAC.x*nAC.x+nAC.y*nAC.y)||1;
- const labP={x: midAC.x + 16*nAC.x/nL, y: midAC.y + 16*nAC.y/nL};
- s += '√2';
- s += '45\xb0-45\xb0-90\xb0';
- })();
+ s += ''+title+'';
+ return s;
+ }
+ let s = '';
+ // 30-60-90 (слева): катет AC = √3 (прилежащий 30°), катет BC = 1 (противолежащий 30°), гипотенуза AB = 2.
+ // Острый угол A = 30°, острый B = 60°.
+ s += drawTri({
+ Ax: 30, Ay: 180,
+ b: Math.sqrt(3)*70, // прилежащий к 30° (длинный)
+ a: 70, // противолежащий 30° (короткий)
+ angAname: '30°', angBname: '60°',
+ sideAdjLab: '√3', sideOppLab: '1', hypLab: '2',
+ title: '30°–60°–90°'
+ });
+ // 45-45-90 (справа): оба катета = 1, гипотенуза = √2.
+ s += drawTri({
+ Ax: 380, Ay: 180,
+ b: 95,
+ a: 95,
+ angAname: '45°', angBname: '45°',
+ sideAdjLab: '1', sideOppLab: '1', hypLab: '√2',
+ title: '45°–45°–90°'
+ });
svg.innerHTML = s;
addXp(10,'p3-iv1'); bumpProgress('p3', 15);
})();