diff --git a/frontend/textbooks/geometry_8_ch4.html b/frontend/textbooks/geometry_8_ch4.html index 746e77c..e5df4fc 100644 --- a/frontend/textbooks/geometry_8_ch4.html +++ b/frontend/textbooks/geometry_8_ch4.html @@ -1239,24 +1239,42 @@ function buildP3(){
  • Биссектриса: прямая $OA$ является биссектрисой угла $T_1AT_2$ (и угла $T_1OT_2$).
  • - - - - - - - - - - - - O - T₁ - T₂ - A - AT₁ - AT₂ - AT₁ = AT₂ + + + + + + + + + + + + + + + + + + + + + + + + + + O + A + + T₂ + + T₁ + + AT₂ + + AT₁ + AT₁ = AT₂
    `); @@ -1362,22 +1380,26 @@ function buildP3(){ const oaVal=document.getElementById('p3-oa-val'); const svgWrap=document.getElementById('p3-two-svg'); const info=document.getElementById('p3-two-info'); - const R=65, cx=100, cy=130, W=280, H=240; + const R=65, cx=90, cy=130, W=320, H=245; function draw(){ const OA=+sl.value; oaVal.textContent=OA; const Ax=cx+OA, Ay=cy; const AT=Math.sqrt(OA*OA-R*R); + /* sinA=R/OA is sin(∠OAT); cosA=AT/OA is cos(∠OAT). + Tangent point: T_x=O_x+R*(R/OA)=O_x+R*sinA; T_y=O_y∓R*(AT/OA)=O_y∓R*cosA */ const sinA=R/OA, cosA=AT/OA; - const T1x=cx+R*cosA, T1y=cy-R*sinA; - const T2x=cx+R*cosA, T2y=cy+R*sinA; - // right angle markers - const ur1x=(T1x-cx)/R, ur1y=(T1y-cy)/R; + const T1x=cx+R*sinA, T1y=cy-R*cosA; + const T2x=cx+R*sinA, T2y=cy+R*cosA; + // right angle markers — ut must point TOWARD A from each tangent point + const ur1x=(T1x-cx)/R, ur1y=(T1y-cy)/R; // T1 is upper; radius points upper-right + // CCW perp of upper-right radius = lower-right = toward A ✓ const ut1x=-(ur1y), ut1y=ur1x; const s=8; const rm1=`${(T1x+ur1x*s).toFixed(1)},${(T1y+ur1y*s).toFixed(1)} ${(T1x+ur1x*s+ut1x*s).toFixed(1)},${(T1y+ur1y*s+ut1y*s).toFixed(1)} ${(T1x+ut1x*s).toFixed(1)},${(T1y+ut1y*s).toFixed(1)}`; - const ur2x=(T2x-cx)/R, ur2y=(T2y-cy)/R; - const ut2x=-(ur2y), ut2y=ur2x; + const ur2x=(T2x-cx)/R, ur2y=(T2y-cy)/R; // T2 is lower; radius points lower-right + // CW perp of lower-right radius = upper-right = toward A ✓ + const ut2x=ur2y, ut2y=-ur2x; const rm2=`${(T2x+ur2x*s).toFixed(1)},${(T2y+ur2y*s).toFixed(1)} ${(T2x+ur2x*s+ut2x*s).toFixed(1)},${(T2y+ur2y*s+ut2y*s).toFixed(1)} ${(T2x+ut2x*s).toFixed(1)},${(T2y+ut2y*s).toFixed(1)}`; /* Position T₁ label OUTSIDE circle, above-left of T₁ (away from upper tangent) */ const T1lx=(T1x-cx)/R, T1ly=(T1y-cy)/R; /* outward unit */ @@ -1439,12 +1461,13 @@ function buildP3(){ const txtEl=document.getElementById('p3-proof-text'); const nextBtn=document.getElementById('p3-proof-next'); const resetBtn=document.getElementById('p3-proof-reset'); - const R=55, cx=100, cy=105; - const OA=130; + const R=55, cx=90, cy=110; + const OA=140; const AT=Math.sqrt(OA*OA-R*R); const sinA=R/OA, cosA=AT/OA; - const T1x=cx+R*cosA, T1y=cy-R*sinA; - const T2x=cx+R*cosA, T2y=cy+R*sinA; + /* T_x=cx+R*sinA=cx+R²/OA, T_y=cy∓R*cosA=cy∓R*AT/OA */ + const T1x=cx+R*sinA, T1y=cy-R*cosA; + const T2x=cx+R*sinA, T2y=cy+R*cosA; const Ax=cx+OA, Ay=cy; function drawProof(ph){ let tri1='',tri2='',equal=''; @@ -1452,11 +1475,11 @@ function buildP3(){ tri1=``; tri2=``; const s=7; - const ur1x=(T1x-cx)/R, ur1y=(T1y-cy)/R; - const ut1x=-(ur1y), ut1y=ur1x; + const ur1x=(T1x-cx)/R, ur1y=(T1y-cy)/R; // T1 upper + const ut1x=-(ur1y), ut1y=ur1x; // CCW perp → toward A ✓ const rm1=`${(T1x+ur1x*s).toFixed(1)},${(T1y+ur1y*s).toFixed(1)} ${(T1x+ur1x*s+ut1x*s).toFixed(1)},${(T1y+ur1y*s+ut1y*s).toFixed(1)} ${(T1x+ut1x*s).toFixed(1)},${(T1y+ut1y*s).toFixed(1)}`; - const ur2x=(T2x-cx)/R, ur2y=(T2y-cy)/R; - const ut2x=-(ur2y), ut2y=ur2x; + const ur2x=(T2x-cx)/R, ur2y=(T2y-cy)/R; // T2 lower + const ut2x=ur2y, ut2y=-ur2x; // CW perp → toward A ✓ const rm2=`${(T2x+ur2x*s).toFixed(1)},${(T2y+ur2y*s).toFixed(1)} ${(T2x+ur2x*s+ut2x*s).toFixed(1)},${(T2y+ur2y*s+ut2y*s).toFixed(1)} ${(T2x+ut2x*s).toFixed(1)},${(T2y+ut2y*s).toFixed(1)}`; equal=``; } @@ -1644,24 +1667,38 @@ function buildP4(){ html+=makeCard('theory','Задача построения касательной','4.1',`

    Задача. Дана окружность с центром $O$ радиусом $R$ и точка $A$ вне окружности ($|OA|>R$). Построить касательную из точки $A$ к окружности.

    - - - - O - - A - - M - - - T₁ - T₂ - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + O + A + M + + T₂ + + T₁
    `); @@ -1682,21 +1719,32 @@ function buildP4(){ $$AT_1 = \\sqrt{|OA|^2 - R^2}$$

    Условие существования: $|OA| > R$ (точка $A$ вне окружности).

    - - - - - - - - - - O - A - T - R - AT - |OA| + + + + + + + + + + + + + + + + + O + A + + T + + R + + AT + + |OA|
    `); @@ -1784,12 +1832,13 @@ function buildP4(){ /* === INIT 1: пошаговое построение === */ (function(){ - const OX=80,OY=110,AX=230,AY=110,R=55; + const OX=80,OY=110,AX=240,AY=110,R=55; const MX=(OX+AX)/2, MY=(OY+AY)/2, MR=(AX-OX)/2; - const sinA=R/Math.sqrt((AX-OX)*(AX-OX)+(AY-OY)*(AY-OY)); - const cosA=Math.sqrt(1-sinA*sinA); - const T1X=OX+R*cosA, T1Y=OY-R*sinA; - const T2X=OX+R*cosA, T2Y=OY+R*sinA; + const OA=Math.sqrt((AX-OX)**2+(AY-OY)**2); + const sinA=R/OA, cosA=Math.sqrt(1-sinA*sinA); + /* T_x=OX+R*sinA=OX+R²/OA, T_y=OY∓R*cosA=OY∓R*AT/OA */ + const T1X=OX+R*sinA, T1Y=OY-R*cosA; + const T2X=OX+R*sinA, T2Y=OY+R*cosA; const steps=[ {title:'Шаг 0 / 5',text:'Дано: окружность с центром $O$, радиусом $R$, и точка $A$ вне окружности. Нужно провести касательную из $A$.'}, {title:'Шаг 1 / 5',text:'Шаг 1. Соединяем $O$ и $A$ — строим отрезок $OA$.'}, @@ -1810,13 +1859,23 @@ function buildP4(){ if(step>=2) extras+=`M`; if(step>=3) extras+=``; if(step>=4){ - extras+=``; - extras+=``; - extras+=`T₁`; - extras+=`T₂`; - const u1x=T1Y-OY, u1y=-(T1X-OX); const u1n=Math.sqrt(u1x*u1x+u1y*u1y); - const pu1x=u1x/u1n*9, pu1y=u1y/u1n*9; - extras+=``; + extras+=``; + extras+=``; + /* T labels in outward radial direction */ + const ur1x=(T1X-OX)/R, ur1y=(T1Y-OY)/R; + const ur2x=(T2X-OX)/R, ur2y=(T2Y-OY)/R; + extras+=`T₁`; + extras+=`T₂`; + /* right-angle markers: ut must point TOWARD A from each tangent point */ + /* T1 is upper (ur1y<0): CCW perp = down-right = toward A ✓ */ + const ut1x=-ur1y, ut1y=ur1x; + const s=8; + const rm1=`${(T1X+ur1x*s).toFixed(1)},${(T1Y+ur1y*s).toFixed(1)} ${(T1X+ur1x*s+ut1x*s).toFixed(1)},${(T1Y+ur1y*s+ut1y*s).toFixed(1)} ${(T1X+ut1x*s).toFixed(1)},${(T1Y+ut1y*s).toFixed(1)}`; + /* T2 is lower (ur2y>0): CW perp = up-right = toward A ✓ */ + const ut2x=ur2y, ut2y=-ur2x; + const rm2=`${(T2X+ur2x*s).toFixed(1)},${(T2Y+ur2y*s).toFixed(1)} ${(T2X+ur2x*s+ut2x*s).toFixed(1)},${(T2Y+ur2y*s+ut2y*s).toFixed(1)} ${(T2X+ut2x*s).toFixed(1)},${(T2Y+ut2y*s).toFixed(1)}`; + extras+=``; + extras+=``; } if(step>=5){ extras+=``; @@ -1850,27 +1909,31 @@ function buildP4(){ rVal.textContent=R; oaVal.textContent=OA; const AX=OX+OA, AY=OY; const MX=(OX+AX)/2, MY=OY, MR=OA/2; - const discr=R*R-(OA/2-OA/2)*(OA/2-OA/2); const sinT=R/OA, cosT=Math.sqrt(Math.max(0,1-sinT*sinT)); - const T1X=OX+R*cosT, T1Y=OY-R*sinT; - const T2X=OX+R*cosT, T2Y=OY+R*sinT; + /* T_x=OX+R*sinT=OX+R²/OA, T_y=OY∓R*cosT=OY∓R*AT/OA */ + const T1X=OX+R*sinT, T1Y=OY-R*cosT; + const T2X=OX+R*sinT, T2Y=OY+R*cosT; const AT=Math.sqrt(Math.max(0,OA*OA-R*R)); + const AXc=Math.min(AX,W-14); lenEl.textContent='Длина касательной AT = √('+OA+'²−'+R+'²) = '+AT.toFixed(2); + /* T labels: outward from O */ + const ur1x=(T1X-OX)/R, ur1y=(T1Y-OY)/R; + const ur2x=(T2X-OX)/R, ur2y=(T2Y-OY)/R; svgWrap.innerHTML=` - O - - A - + O + + A + - - - - - T₁ - T₂ + + + + + T₁ + T₂ `; } rSl.addEventListener('input',()=>{if(+rSl.value>=+oaSl.value-5)oaSl.value=+rSl.value+10;draw();}); @@ -1999,22 +2062,41 @@ function buildP5(){

    Определение. Окружность называется вписанной в угол, если она касается обеих сторон этого угла.

    Теорема. Центр окружности, вписанной в угол, лежит на биссектрисе этого угла.

    - - - - - - - O - - B - - - T₁ - T₂ - - - биссектриса + + + + + + + + + + + + + + + + + + + + + + + + + + + + B + + O + + T₁ + + T₂ + биссектриса
    `); @@ -2033,18 +2115,27 @@ function buildP5(){ $$|BT_1| = |BT_2|, \\quad |BT_3| = |BT_4|$$

    Формула радиуса: $r = d\\cdot\\sin\\dfrac{\\alpha}{2}$, где $d = |BO|$ — расстояние от вершины до центра, $\\alpha$ — угол.

    - - - - - - - - - - B - O₁ - O₂ + + + + + + + + + + + + + + + + + + B + + O₁ + O₂
    `); @@ -2152,21 +2243,32 @@ function buildP5(){ const proj=((OX-BX)*side2DX+(OY-BY)*side2DY); const T2X=BX+proj*side2DX, T2Y=BY+proj*side2DY; infoEl.textContent='r = d·sin(α/2) = '+d+'·sin('+ang2/2+'°) = '+r.toFixed(2); + /* right-angle at T₂ on side 2 */ + const s2x=Math.cos(ang2*Math.PI/180), s2y=-Math.sin(ang2*Math.PI/180); + const ot2ux=(OX-T2X)/r, ot2uy=(OY-T2Y)/r; + const rs=8; + const rm2pts=`${(T2X+s2x*rs).toFixed(1)},${(T2Y+s2y*rs).toFixed(1)} ${(T2X+s2x*rs+ot2ux*rs).toFixed(1)},${(T2Y+s2y*rs+ot2uy*rs).toFixed(1)} ${(T2X+ot2ux*rs).toFixed(1)},${(T2Y+ot2uy*rs).toFixed(1)}`; + /* T₂ label: perpendicular outward from side 2 (left when going along side 2) = (-s2y, s2x) = (sin(ang2), cos(ang2)) */ + const t2labX=(T2X+Math.sin(ang2*Math.PI/180)*(-14)-4).toFixed(1); + const t2labY=(T2Y+Math.cos(ang2*Math.PI/180)*(-14)+4).toFixed(1); + /* T₁ label: below T₁ (off horizontal side) */ + /* O label: to the right of O, offset away from radius to T₁ */ svgWrap.innerHTML=` - - - - - - - - - + + + + + + + + + + B - O - T₂ - T₁ + O + T₂ + T₁ `; } dSl.addEventListener('input',draw); @@ -2195,9 +2297,20 @@ function buildP5(){ function draw(){ const s=steps[step]; let extras=''; - if(step>=1){extras+=``;extras+=``;extras+=``;extras+=`T₂T₁`;} - if(step>=2){extras+=`rr`;} - if(step>=3){extras+=``;extras+=``;} + /* right-angle at T₂: side2 dir=(cos60°,-sin60°), radius-toward-O dir=((OX-T2X)/r,(OY-T2Y)/r) */ + const s2x=Math.cos(ang2*Math.PI/180), s2y=-Math.sin(ang2*Math.PI/180); + const ot2ux=(OX-T2X)/r, ot2uy=(OY-T2Y)/r; + const rs=8; + const rm2p=`${(T2X+s2x*rs).toFixed(1)},${(T2Y+s2y*rs).toFixed(1)} ${(T2X+s2x*rs+ot2ux*rs).toFixed(1)},${(T2Y+s2y*rs+ot2uy*rs).toFixed(1)} ${(T2X+ot2ux*rs).toFixed(1)},${(T2Y+ot2uy*rs).toFixed(1)}`; + /* T₂ label outward from angle (perpendicular left of side2 direction = (-s2y, s2x) rotated outward) */ + /* outward from angle interior: perpendicular to side2 pointing away = (sin(ang2), cos(ang2)) i.e. left-perp */ + const t2lx=(T2X+Math.sin(ang2*Math.PI/180)*(-13)-4).toFixed(1); + const t2ly=(T2Y+Math.cos(ang2*Math.PI/180)*(-13)+4).toFixed(1); + /* r label: midpoint of OT₂, offset perpendicular */ + const rOT2mx=((OX+T2X)/2).toFixed(1), rOT2my=((OY+T2Y)/2).toFixed(1); + if(step>=1){extras+=``;extras+=``;extras+=``;extras+=``;extras+=`T₂T₁`;} + if(step>=2){extras+=`rr`;} + if(step>=3){extras+=``;extras+=``;} svgEl.innerHTML=` @@ -2208,7 +2321,7 @@ function buildP5(){ B - O + O ${extras} `; txtEl.innerHTML=s.text;