Довольно вычурные «Начала» Евклида в TeX-е

b9xjsqwlk_6vlrkagvbpb2yfej0.jpeg

«какая-то странная антикварная х██ня, написанная ирландским кулибиным в 1847 ну, хорошо, что и такая бывает, конечно» Миша Вербицкий

В 16-м году мне на глаза попались «Начала» Евклида в интерпретации Оливера Бирна. Фишка этой книги в том, что вместо буквенных обозначений навроде «треугольник ABC» там прямо в текст помещаются миниатюры частей построения, то есть, например, картинка с соответствующим треугольником. Насколько сделать такую книгу, как можно представить, было адовой работой в середине XIX века, настолько же легко, с правильными инструментами, это должно бы быть теперь. И, в общем, решил я в этом убедиться наверняка.


btd1vz7zw34dp1uyd8met_b87q0.jpeg

Вариант попросту отрисовать в иллюстраторе иллюстрации и сверстать в индизайне верстку был быстро отметен как упаднический. Геометрические построения делать и редактировать в иллюстраторе не сказать чтобы страшно удобно, а красивого способа автоматически связать миниатюры с основным построением мне и вовсе в голову не пришло. Индизайн, хоть и хорошо подходит для такого рода верстки, обещал удручать видом панели ссылок при таком количестве картинок. Так что, ничтоже сумняшеся, я обратился к уже знакомому мне MetaPost-у, в котором геометрические построения делать довольно легко (но не как в геогебре, конечно) и латеху, в котором относительно понятно, как всё сверстать. Латех, правда, из-за непоняток с библиотеками для метапоста был заменен ConTeXt-ом, который хорошо ладит с метапостом прямо из коробки.

Как это работает в целом


«Начал» вообще 13 частей — книг, но Бирн обработал только первые 6. Книги в основном состоят из «предложений» — теорем и задач. Каждое сделано из построения (чаще одного) и текста, который на это построение ссылается.

Для описания построений я завел в ConTeXt-е макрос, который создает новый инстанс метапоста. В метапосте же — всякие функции для описания построений. Выглядит это следующим образом:

\defineNewPicture{ % Внутри этой штуки описывается построение
    pair A, B, C, D; % В метапосте есть тип переменных для координат
    numeric d;
    d := 2u;
    A := (0, 0);                %
    B := A shifted (d, 0);      % Здесь задаются координаты точек
    C := A shifted (0, -d);     %
    D := A shifted (d, -d);     %
    byAngleDefine(B, A, C, byblack, 0);     % Здесь описываются углы
    byAngleDefine(D, B, A, byblue, 0);      % сначала точки,
    byAngleDefine(C, D, B, byred, 0);       % потом цвет,
    byAngleDefine(A, C, D, byyellow, 0);    % потом стиль
    draw byNamedAngleResized();     % Эта штука рисует все углы
    byLineDefine(A, B, byred, 0, 0);        % Здесь описываются отрезки
    byLineDefine(B, D, byyellow, 0, 0);     % сначала концы,
    byLineDefine(D, C, byblack, 0, 0);      % потом цвет, потом стиль
    byLineDefine(C, A, byblue, 0, 0);       % потом толщина
    draw byNamedLineSeq(0)(AB,BD,DC,CA);    % Здесь рисуется цепочка отрезков
}
\drawCurrentPicture % Эта штука выводит получившуюся картинку


juubu7bnipox8simoy8i971stus.png

Для текстов предложений написал макросы, которые рисуют и выводят картинки в том же инстансе, что и основное построение. Они выполняют, в общем случае, произвольный метапост-код, но чаще всего принимают в качестве аргументов имена нужных элементов — углов, отрезков и пр. Например, так:

% Имена отрезкам даются автоматически, но можно назначить и вручную
Draw $\drawUnitLine{CA} \perp \mbox{ and } = \drawUnitLine{DC}$.\\
Draw $\drawUnitLine{AB} \parallel \drawUnitLine{DC}$,\\
and meeting \drawUnitLine{BD} drawn $\parallel \drawUnitLine{CA}$.


ezfguvegpy6qw7rliclzmhhgh1q.png

Вот как то и другое работает вместе:

hl6pufc9f-0syxk8q3amrur1xze.png

Кое-какие фичи


Картинки в книге незатейливые, но некоторые вещи потребовали особого внимания.

Если отрезки касаются друг друга концами, это надо как-то симпатично обставить. Сейчас особо обрабатываются соединения только двух отрезков, остальные можно класть под такое соединение. В оригинале встречается минимум два способа соединения линий, но воспроизводить их мне показалось излишним.

27iv6kwqw5bj369z5cmzzv3cm0i.png

Углы изображаются с помощью секторов. Если угол достаточно маленький, то при одинаковом радиусе сектор будет выглядеть слишком куцым, и есть смысл его увеличить. Сейчас радиус остается постоянным при углах от 60 градусов, а для меньших углов формула такая: $r\sqrt{a/60}$.

xnvq0awkzqfidnukagrvxmozusu.gif

Штриховые линии, чтобы было красиво, должны начинаться и оканчиваться залитыми частями, так что штриховка слегка масштабируется, чтобы влезать целое число раз в отрезок (подобная штука есть в иллюстраторе, но там в начале и в конце линии получаются штрихи половинной длины).

82kchmpkrh6zbsku_jt21yf_qz8.gif

Отображать отрезки в тексте можно по-разному: можно делать их все одной длины, меняя только цвет, а можно воспроизводить так или иначе и длину. У Бирна встречается и так и эдак. У меня для этого такая формула: $L'=L^{a}l^{1-a}$, где $L'$ — длина отрезка в тексте, $L$ — длина исходного отрезка, $l$ — желаемая длина отрезка и $a$ — некое число от 0 до 1. Если $a=0$, то $L' = l$, то есть любой отрезок будет изображен с длиной $l$. Если $a=1$, $L' = L$. Если $0<а<1$, то при $L<l$, $L'>L$» /> и при <img src=, то есть короткие отрезки удлиняются, а длинные — укорачиваются. Это нужно, если хочется сохранить относительные размеры отрезков, но не хочется получить отрезки в полмиллиметра рядом с отрезками в два сантиметра. (На самом деле все чуть сложнее, но смысл такой).

bsdcez--c23k6zz-5espheo1gpq.png

Хотя Бирн и отказался от буквенных обозначений, известный зануда Эдвард Тафти в одной из своих книг высказался на этот счет в том духе, что всё у Бирна хорошо, но буковки неплохо бы вернуть. А раз всё равно почти всё автоматически, то и буквочкам место нашлось. По умолчанию точки называются так же, как и переменные, где хранятся их координаты. Метки можно располагать по вершинам многоугольников, или на концах отрезков, или как-нибудь еще. Их, само собой, можно включать и выключать по желанию (верстка при этом, конечно же, ползет).

znzte030dz5iik2fb0ltt5afhue.gif

Но большая часть кода все-таки посвящена штукам, больше заметным автору/редактору, чем читателю. Это, например, правильное распознавание синонимичных названий углов и отрезков, автоматическая расстановка букв вокруг нескольких многоугольников, автоматическая отрисовка кусков отрезков при некоторых углах в тексте и все такое прочее.

В оригинале есть буквицы и виньетки. С одной стороны, их без особого труда (умственного, по крайней мере) можно было отрисовать, но я решил взяться за более интересную (пусть и безнадежную) задачу — производить буквицы и виньетки со случайным узором автоматически. Во-первых, это просто весело, а во-вторых, перевод на русский (о котором ниже) потребовал бы адаптации исходного стиля буквиц под кириллицу, каковая деятельность в мои планы не входила. Так что при сборке книги создается список всех буквиц и виньеток, и по этому списку отдельный метапост-скрипт рисует (очень неспешно) полный комплект всего этого добра. Буквицы все разные и узоры не повторяются.

lkifenehn0rvy0myliwn0zxf5nc.jpeg

Принцип простой: на частях литеры и на рамке размещаются завитушки, настолько крупные, насколько возможно. Это происходит несколько раз, и уже нарисованные завитушки включаются в следующие итерации. Затем таким же образом появляются «листья». Форму и свойства разных видов отростков можно менять.

lugy6ofh977hz8yibvqht-xuec0.gif

Не могу сказать, что вполне доволен результатом, но постепенно совершенствую алгоритм и надеюсь на лучшее (впрочем, можно плюнуть и подсунуть картинки с любыми буквицами вместо сгенерированных). В качестве бонуса скрипт умеет генерить из завитушек случайные тайлы.

5aee1jei7ok-d82p8by0ytr6sbw.jpeg

Перевод


Чтобы выловить ошибки, да и вообще, я стал делать перевод на русский. Ориентиром у меня был перевод «Начал» Мордухай-Болтовского, но довольно быстро стало понятно, что Бирн слишком многое поменял в доказательствах, чтобы это сильно помогло. Признаться честно, поначалу перевел я всё совсем спустя рукава, особенно введение, просто чтобы было, и только недавно дошли руки сгладить немного шероховатости.

Если не считать неприятной пятой книги (которая, как оказалось, была оформлена отдельно от остальных и несколько раньше), было не особенно сложно. Перевод (сам процесс) действительно помог выловить много разных косяков, как моих, так и автора. Скажем, построение к предложению 9 из шестой книги у Бирна не соответствует тексту, отчего доказательство не работает, так что пришлось там всё переделать.

Из курьезов: во введении, где автор нахваливает свой метод, вначале он сослался на Горация, приведя его стихи про превосходство зрения над другими чувствами в качестве аргумента. А несколькими страницами позже решил приплести для пущей убедительности еще и «современного поэта», стихи которого также процитировал. На поверку «стихи современного поэта» оказались другим переводом тех же самых строчек Горация. Тут, конечно, надо было оставить всё как есть и в сноске указать на ошибку автора, но на счастье жена нашла подходящие стихи английского и действительно намного более современного Бирну автора, которые и пошли в дело (пусть и говорят, что так делать нельзя). В английской версии оставил как было.

bk9pku5d9p4dp__o2qs2fepjmdi.jpeg

Русская версия отличается еще и тем, что маленькие буквочки в ней включены по умолчанию и вообще больше мелких изменений по сравнению с оригиналом, чем в английской. Правда, тут вот кто-то попросил сделать английскую версию тоже с буковками, и я подумываю включить их и там тоже: без них-то эта книжка и так есть.

Еще один товарищ начал переводить книжку на польский и очень много ценного по дороге в issues написал (к примеру, про масштабирование углов — это его предложение). Здорово, если допереведет.

Промежуточные итоги


Повозившись с этой книжкой, имею сказать следующее. Картинки в тексте действительно легко читаются, теперь использую этот прием и в других местах. Учитывая, что занимался я проектом вечерами после основной работы на полный день, получилось довольно быстро: примерно полгода на первую английскую версию, со всем планированием и программированием, три месяца на первую редакцию русского перевода. Правда, косяки исправляю до сих пор и там и там (а еще недавно жена начала вычитывать русский на предмет опечаток, и я краснею, почти как от первого пулл реквеста).

С момента публикации первой версии на гитхабе началась и закончилась кампания на кикстартере по сбору средств на «завершение работы Бирна», то есть, как понимают это авторы, оформление всех 13 книг «Начал» в том же духе. Судя по всему, верстают в индизайне, в чем рисуют, непонятно. Пока книги вроде не разослали, но скоро должны. Надеюсь, получится хорошо. А совсем недавно один американский дизайнер выпустил няшную веб-версию первых шести книг. Он, судя по статье с рассказом о работе, рисовал всё вручную в иллюстраторе.

Планы


У Бирна совсем не было стереометрии, так что и инструментов для нее я с самого начала не предусмотрел, но теперь решил потихоньку бирнифицировать книги «Начал» с 11 по 13, чтобы инструментарий отработать на них. Пока вчерне готово чуть больше половины 11-й книги и, соответственно, уже есть кое-какие функции для описания объемных построений и их проекции на плоскость. Впрочем, объемные построения в среднем намного сложнее плоских, и пока у меня нет четкого представления ни о том, насколько будет работать для них подход Бирна, ни о том, получится ли достаточно удобно создавать их в метапосте.

qitdcs3zeb0nja5ifual2bc3xg4.gif

Картинки в тексте часто требуют кернинга. Аналогичное, но сложнее: картинки большого размера на соседних строках раздвигают строки очень широко, что оправдано, только если они друг на друга налезают. Как автоматизировать эти вещи, я пока не придумал, а вручную это всё вылавливать очень скучно.

mfwzphlyl3wubidktj_qflccg_e.jpeg

Метапост можно запускать и из латеха, и отдельно. Так что в будущем планирую сделать макросы для латеха, такие же, как для ConTeXt-а, чтобы можно было делать то же самое в более распространенной среде. В теории никто не мешает использовать метапост, например, с индизайном. Это можно делать и сейчас, просто собирая картинки отдельно и линкуя их вручную, но напрашивается написать для ID пару скриптов, чтобы это происходило само. Последнее выглядит совсем уж как какая-то перверсия, но слишком часто приходит на ум, чтобы не рассмотреть такую возможность.

Ну и главное — хочется попробовать применить всю эту машинерию к чему-нибудь более современному и практичному, чем «Начала».

Всё добро лежит тут, готовые pdf-ки есть в релизах.

© Habrahabr.ru