'use strict'; /* * Уроки блока «Стереометрия» курса «ЦЭ/ЦТ — Математика» (по PILOT_STEREOMETRY.md). * 4 урока: расположение/сечения → многогранники → тела вращения → углы/расстояния. * Форматы блоков — под рендер frontend/lesson.html (text/heading/callout esc-only; * математика $…$/$$…$$; callout.style=info|warning|success|error). Идемпотентно. * node backend/scripts/seed_ctmath_lessons_stereo.js [--dry] */ const db = require('../src/db/db'); const DRY = process.argv.includes('--dry'); const COURSE_TITLE = 'ЦЭ/ЦТ — Математика', SECTION_TITLE = 'Стереометрия'; const course = db.prepare("SELECT id FROM courses WHERE subject_slug='math' AND title=?").get(COURSE_TITLE); if (!course) { console.error('Нет курса. Сначала seed_ctmath_course.js'); process.exit(1); } const section = db.prepare('SELECT id FROM course_sections WHERE course_id=? AND title=?').get(course.id, SECTION_TITLE); if (!section) { console.error('Нет секции «' + SECTION_TITLE + '»'); process.exit(1); } const H = (text, level = 2) => ['heading', { text, level }]; const P = (text) => ['text', { text }]; const F = (tex, label) => ['formula', label ? { label, tex } : { tex }]; const CI = (text) => ['callout', { style: 'info', text }]; const CW = (text) => ['callout', { style: 'warning', text }]; const CS = (text) => ['callout', { style: 'success', text }]; const SIM = (caption) => ['sim', { simId: 'stereo', caption }]; const FC = (front, back) => ['flashcard', { front, back }]; const ORD = (question, items) => ['ordering', { question, items }]; const ACC = (title, content) => ['accordion', { title, content }]; // M26 — расположение, сечения (А2, В1) const L1 = [ H('Прямые и плоскости в пространстве'), P('Две прямые в пространстве: пересекаются, параллельны или скрещиваются. Прямая и плоскость: прямая лежит в плоскости, параллельна ей или пересекает её. Две плоскости: параллельны или пересекаются по прямой.'), SIM('Покрутите фигуру: найдите линию пересечения двух плоскостей и пары скрещивающихся прямых'), CI('Линия пересечения двух плоскостей проходит через их общие точки. В правильной пирамиде плоскости, проходящие через вершину и центр основания, пересекаются по прямой через вершину (например, $SO$).'), F('a\\parallel b,\\ b\\subset\\alpha,\\ a\\not\\subset\\alpha \\Rightarrow a\\parallel\\alpha', 'Признак параллельности прямой и плоскости'), CW('В задании В1 (выбор верных утверждений о расстояниях) проверяйте каждое утверждение отдельно: расстояние между скрещивающимися прямыми — это длина их общего перпендикуляра, а не любого отрезка.'), H('Разбор А2', 3), P('Пример. В правильной четырёхугольной пирамиде $SABCD$ ($O$ — центр основания) найдите прямую пересечения плоскостей $DSO$ и $SCB$.'), P('Решение. Обе плоскости проходят через вершину $S$, значит линия их пересечения проходит через $S$; анализом общих точек получаем прямую $SO$.'), CS('Метод: ищем общие точки двух плоскостей — через них проходит линия пересечения.'), FC('Расстояние между скрещивающимися прямыми', 'Длина их общего перпендикуляра'), FC('Линия пересечения двух плоскостей', 'Проходит через все их общие точки'), CI('Тренажёр: задания А2 и В1 по теме «Стереометрия» в практике модуля /exam-prep/ctmath. Цель: не менее 80%.'), ]; // M27 — многогранники (В13, В17) const L2 = [ H('Многогранники: объёмы, площади, подобие'), F('V_{\\text{призмы}}=S_{\\text{осн}}\\cdot h,\\qquad V_{\\text{пирамиды}}=\\tfrac{1}{3}S_{\\text{осн}}\\cdot h', 'Объёмы'), P('Сечение, параллельное основанию пирамиды, отсекает подобную фигуру. Если высота делится от вершины в отношении $k$, то линейные размеры сечения относятся к основанию как $k$, а площади — как $k^2$.'), F('\\dfrac{S_{\\text{сеч}}}{S_{\\text{осн}}}=k^2,\\quad k=\\dfrac{\\text{высота до сечения}}{\\text{вся высота}}', 'Сечение, параллельное основанию'), SIM('Сечение пирамиды плоскостью, параллельной основанию'), CW('В задании В17 ловят на том, что как $k^2$ относятся именно площади, а не длины. Сначала найдите $k$ из отношения высот, затем возводите в квадрат.'), H('Разбор В17', 3), P('Пример. Плоскость, параллельная основанию треугольной пирамиды, делит высоту в отношении $5:3$ от вершины. Площадь сечения меньше площади основания на $39$. Найдите площадь сечения.'), P('Решение. $k=\\dfrac{5}{5+3}=\\dfrac{5}{8}$, поэтому $\\dfrac{S_{\\text{сеч}}}{S_{\\text{осн}}}=\\dfrac{25}{64}$. Пусть $S_{\\text{осн}}=x$: $x-\\dfrac{25}{64}x=39\\Rightarrow\\dfrac{39}{64}x=39\\Rightarrow x=64$. Тогда $S_{\\text{сеч}}=25$.'), CS('Ответ: $25$.'), FC('$V$ пирамиды', '$\\tfrac{1}{3}S_{\\text{осн}}\\cdot h$'), FC('Отношение площадей сечения и основания (сечение $\\parallel$ основанию)', '$k^2$, где $k$ — отношение высот от вершины'), CI('Тренажёр: В13 и В17 по теме «Стереометрия». Цель: не менее 75%.'), ]; // M28 — тела вращения (А9, В13) const L3 = [ H('Тела вращения: цилиндр, конус, шар'), F('S_{\\text{сферы}}=4\\pi R^2,\\qquad V_{\\text{шара}}=\\tfrac{4}{3}\\pi R^3', 'Шар и сфера'), F('S_{\\text{бок}}=2\\pi R h,\\qquad V=\\pi R^2 h', 'Цилиндр'), F('S_{\\text{бок}}=\\pi R l,\\qquad V=\\tfrac{1}{3}\\pi R^2 h', 'Конус'), SIM('Сечение цилиндра плоскостью, параллельной оси'), CI('Сфера, касающаяся плоскости: радиус в точку касания перпендикулярен плоскости. Расстояние от центра до точки плоскости и радиус образуют прямоугольный треугольник — работает теорема Пифагора.'), H('Разбор А9', 3), P('Пример. Квадрат с диагональю $8$ лежит в плоскости $\\alpha$; сфера касается $\\alpha$ в точке пересечения диагоналей; расстояние от центра сферы до вершины квадрата равно $4\\sqrt2$. Найдите площадь сферы.'), P('Решение. Полудиагональ $=4$. $R^2=(4\\sqrt2)^2-4^2=32-16=16$, $R=4$. Площадь $=4\\pi R^2=64\\pi$.'), CS('Ответ: $64\\pi$.'), H('Разбор В13', 3), P('Пример. Цилиндр рассечён плоскостью, параллельной оси; в сечении квадрат площади $100$; расстояние от оси до плоскости $\\sqrt{39}$. Найдите $\\dfrac{S_{\\text{бок}}}{\\pi}$.'), P('Решение. Сторона квадрата $=10$ (это и высота, и хорда). $R^2=(\\sqrt{39})^2+5^2=39+25=64$, $R=8$. $S_{\\text{бок}}=2\\pi\\cdot8\\cdot10=160\\pi$.'), CS('Ответ: $160$.'), FC('$S$ сферы', '$4\\pi R^2$'), FC('$V$ шара', '$\\tfrac{4}{3}\\pi R^3$'), FC('$S_{\\text{бок}}$ конуса', '$\\pi R l$'), CI('Тренажёр: А9 и В13 по теме «Стереометрия». Цель: не менее 80% (А9) и 70% (В13).'), ]; // M29 — углы и расстояния, координатный метод (В20) const L4 = [ H('Координатный метод: угол между прямыми'), P('Универсальный приём для В20: ввести удобную систему координат (вершину фигуры в начало), выписать координаты нужных точек, составить направляющие векторы прямых и найти угол через косинус скалярного произведения. Если геометрия «не идёт» — считайте координатами.'), F('\\cos\\varphi=\\dfrac{|\\vec a\\cdot\\vec b|}{|\\vec a|\\,|\\vec b|}', 'Угол между прямыми через векторы'), F('\\vec a\\cdot\\vec b=a_xb_x+a_yb_y+a_zb_z,\\qquad |\\vec a|=\\sqrt{a_x^2+a_y^2+a_z^2}', 'Скалярное произведение и длина'), SIM('Угол между скрещивающимися прямыми'), ORD('Расставьте шаги решения В20 координатным методом', [ 'Ввести систему координат', 'Выписать координаты точек (учесть отношения деления рёбер)', 'Составить направляющие векторы прямых', 'Найти cos φ через скалярное произведение и длины', ]), CW('В числителе — модуль скалярного произведения (угол между прямыми не превосходит $90^\\circ$). Частые ошибки В20 — потеря модуля и неверные координаты точек деления рёбер.'), ACC('Альтернативы (раскрыть)', 'Угол между прямой и плоскостью считают через нормаль плоскости; есть также теорема о трёх синусах. Но координатный метод универсален и почти всегда быстрее в задачах ЦТ.'), H('Разбор В20', 3), P('Пример. В кубе $ABCDA_1B_1C_1D_1$ с ребром $1$ найдите $8\\cos^2\\varphi$, где $\\varphi$ — угол между прямыми $AB_1$ и $BC_1$.'), P('Решение. Координаты: $A(0;0;0)$, $B(1;0;0)$, $B_1(1;0;1)$, $C_1(1;1;1)$. Векторы $\\vec{AB_1}=(1;0;1)$, $\\vec{BC_1}=(0;1;1)$. $\\cos\\varphi=\\dfrac{|1|}{\\sqrt2\\cdot\\sqrt2}=\\dfrac{1}{2}$, поэтому $8\\cos^2\\varphi=8\\cdot\\dfrac14=2$.'), CS('Ответ: $2$.'), FC('Угол между прямыми (векторы)', '$\\cos\\varphi=\\dfrac{|\\vec a\\cdot\\vec b|}{|\\vec a||\\vec b|}$'), FC('Скалярное произведение', '$a_xb_x+a_yb_y+a_zb_z$'), FC('Длина вектора', '$\\sqrt{a_x^2+a_y^2+a_z^2}$'), CI('Тренажёр: В20 по теме «Стереометрия» (координатный метод). Цель: не менее 60% — это самые «дорогие» баллы.'), ]; const LESSONS = [ { title: 'Расположение прямых и плоскостей. Сечения', read: 9, blocks: L1 }, { title: 'Многогранники: объёмы, площади, подобие', read: 11, blocks: L2 }, { title: 'Тела вращения: цилиндр, конус, шар', read: 11, blocks: L3 }, { title: 'Углы и расстояния: координатный метод', read: 12, blocks: L4 }, ]; console.log(DRY ? '[DRY-RUN]' : '[APPLY]', `курс id=${course.id}, секция «${SECTION_TITLE}» id=${section.id}`); const insLesson = db.prepare('INSERT INTO lessons (course_id, title, order_index, is_published, section_id, read_time) VALUES (?,?,?,1,?,?)'); const insBlock = db.prepare('INSERT INTO lesson_blocks (lesson_id, type, order_index, data) VALUES (?,?,?,?)'); LESSONS.forEach((L, i) => { const ex = db.prepare('SELECT id FROM lessons WHERE course_id=? AND title=?').get(course.id, L.title); if (ex) { console.log(` есть урок: «${L.title}» (id ${ex.id}) — пропуск`); return; } if (DRY) { console.log(` + урок «${L.title}» (${L.blocks.length} блоков)`); return; } const lid = insLesson.run(course.id, L.title, 10 + i + 1, section.id, L.read).lastInsertRowid; L.blocks.forEach(([type, data], bi) => insBlock.run(lid, type, bi, JSON.stringify(data))); console.log(` + урок «${L.title}» (id ${lid}, ${L.blocks.length} блоков)`); }); console.log(DRY ? 'DRY-RUN: ничего не записано.' : 'Готово. Уроки стереометрии добавлены (черновик курса).');