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$).
-
`);
@@ -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;