MetaPost

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск
MetaPost
MPlogo.svg
Класс языка

императивный

Появился в

1994

Автор

Джон Хобби

Выпуск

1.212 (19 октября 2010)

Тестовая версия

1.902 (23 апреля 2014)

Система типов

неявная, динамическая, строгая

Испытал влияние

METAFONT

Повлиял на

Asymptote

Лицензия

GNU LGPL

Сайт

foundry.supelec.fr/projects/metapost/

MetaPost — интерпретатор языка программирования META, который можно использовать для создания графических иллюстраций. MetaPost был создан Джоном Хобби в то время, когда он был аспирантом у Дональда Кнута. В качестве основы была взята система создания шрифтов METAFONT[1].

На входе интерпретатору подаётся текст на META, а на выходе получается графический файл в формате PostScript[2]. Начиная с версии 1.200 MetaPost поддерживает в качестве выходного формата SVG-графику[3].

Язык META, унаследованный от METAFONT, позволяет оперировать геометрическими объектами, такими как: точка, путь, картинка и выполнять над ними различные алгебраические действия, например, сдвиг, вращение и другие линейные преобразования.

Основными отличиями MetaPost от METAFONT кроме выходного формата является наличие поддержки цвета и возможность делать текстовые вставки. Текстовые вставки создаются с помощью LaTeX, таким образом, любая конструкция, которая может быть создана в LaTeX, также может быть вставлена в картинку MetaPost. Кроме этого изначально автор MetaPost Джон Хобби разработал библиотеку для визуализации двумерных графиков[4].

Интерпретатор MetaPost (исполняемый файл mpost) вместе со стандартными макро-библиотеками распространяется как открытое программное обеспечение, обычно, в составе дистрибутивов LaTeX.

MetaPost-конвейер[править | править вики-текст]

MetaPost-конвейер

На вход программы mpost подаётся «META-картинка». «META-картинка» — это текстовый файл с расширением .mp (далее для краткости mp-файл) с инструкциями на языке META. В одном mp-файле можно хранить несколько описаний картинок. При компиляции с помощью mpost создаются файлы с тем же именем, что и у исходного файла, но с расширениями в виде чисел, которые указываются в декларации beginfig. Результирующие файлы сразу можно вставлять в LaTeX-тексты с помощью обычного \includegraphics. Для этого достаточно в заголовок tex-файла добавить команду из LaTeX-пакета graphicx:

\DeclareGraphicsRule{*}{eps}{*}{}

От «правильных» eps-файлов они отличаются только тем, что в них не «внедрены» шрифты, поэтому просмотреть их без дополнительной обработки не удастся.

Шрифты можно внедрить посредством программ latex и dvips с результатом в виде eps-файла или скрипта mptopdf с результатом в виде pdf-файла. Эти картинки уже можно использовать независимо любой программой, которая поддерживает эти векторные форматы.

Кириллица и MetaPost[править | править вики-текст]

Внедрить кириллицу в метки MetaPost можно только с помощью LaTeX. Для этого mp-файл должен иметь примерно следующий заголовок:

verbatimtex 
\documentclass[12pt]{minimal} 
%простейшая кириллизация
\usepackage[koi8-r]{inputenc}
\usepackage[english,russian]{babel}
\begin{document}
etex;

Этот заголовок будет использоваться каждый раз, когда MetaPost доходит до текста, находящегося между метками btex и etex. Если для создание метки требуется какой-либо пакет LaTeX, то, соответственно, необходимо добавить этот пакет в заголовок стандартным образом.

Для того, чтобы при создании надписи использовался именно latex, интерпретатор mpost должен запускаться с опцией -tex=latex. Если эта опция отсутствует, то информацию о том, что следует запускать, mpost ищет в переменной окружения TEX. По умолчанию вместо latex запускается tex.

Если в тексте определяется переменная prologues, то она должна быть равна 0. В этом случае все необходимые шрифты «подшиваются» к картинке в момент, когда создаются eps и pdf-файлы.

Структура mp-файла[править | править вики-текст]

После заголовка идут описания картинок. Каждая картинка заключается между командами beginfig и endfig. В качестве параметра beginfig указывается порядковый номер картинки. При компиляции этот номер будет добавляться к картинке как расширение. Пример:

Hello World
%Математический HelloWorld
beginfig(3) ;
 for alpha:=90 step -9 until 0:
  label(btex \(f(x)=
  \frac{1}{\sqrt{2\pi}\,\sigma}
    \int\limits_{-\infty}^{\infty}
      e^{-\frac{x^2}{2\sigma^2}}dx\) etex
    scaled (5*(1-alpha/100)) rotated alpha,(0,0))
 withcolor(max(1-alpha/45,0)*red+min(alpha/45,2-alpha/45)*green+max(alpha/45-1,0)*blue);
 endfor;
endfig ;

Файл должен закончиться командой end. или bye. Эти команды дают понять интерпретатору mpost, что обработка закончена.

Автоматизация[править | править вики-текст]

Для автоматизации получения картинок с помощью MetaPost можно использовать следующий Makefile:

#временный файл
tmp_file := tmp_file
#программы
LATEX := latex 
MPOST := mpost -tex=latex 
DVIPS := dvips
MPTOPDF := mptopdf
MV := mv
all:
	@echo "run: make mpfile.n.[eps|pdf] - where n is the picture number"
%.eps: % 
	@echo  "\documentclass[12pt]{minimal}">$(tmp_file).tex
	@echo  "\usepackage[koi8-r]{inputenc}">>$(tmp_file).tex
	@echo  "\usepackage[english,russian]{babel}">>$(tmp_file).tex
	@echo  "\usepackage{graphicx}">>$(tmp_file).tex
	@echo  "\DeclareGraphicsRule{*}{eps}{*}{}">> $(tmp_file).tex
	@echo  "\nofiles">>$(tmp_file).tex
	@echo  "\begin{document}">> $(tmp_file).tex
	@echo  "\thispagestyle{empty}">> $(tmp_file).tex
	@echo  "\includegraphics{$(basename $@)}">> $(tmp_file).tex
	@echo  "\end{document}">> $(tmp_file).tex
	@$(LATEX) $(tmp_file)
	@$(DVIPS) -E -o $@ $(tmp_file)
	@rm $(tmp_file).*
%.pdf: % 
	@$(MPTOPDF) $<
	@$(MV) `echo $< | sed -e "s/\.\([0-9]\+\)$$/-\1.pdf/"` $<.pdf
clean:
	@rm  -f mpx* *~ *.log *.mpx
	@rm -f $(tmp_file).* 
#Зависимости для mpost-картинок.
#По одной для каждого числа из beginfig
%.1:%.mp 
	$(MPOST) $<
 …
%.64:%.mp 
	$(MPOST) $<

Чтобы на выходе получить готовую eps-картинку с уже «внедрёнными» шрифтами, которую можно вставить уже куда угодно, достаточно выполнить следующую команду:

make <имя mp-файла>.<номер картинки>.[eps|pdf]

Обычно mp-файлам даются короткие имена.

Как вариант, предлагается shell-скрипт (mp2pdf.sh), который делает практически то же самое. Предполагается использование GNU/Linux (или подобной ОС).

Скрипт для каждого beginfig(n)-блока сделает файлы filen.eps и filen.pdf, где file — имя исходного MetaPost-файла, n — номер блока. В скрипте предусмотрено размещения полученных файлов в отдельных каталогах. Имена каталогов задаются переменными EPS_DIR и PDF_DIR. Если каталогов с такими именами не существуют, то скрипт автоматически создаёт их.

#!/bin/sh
# Скрипт для превращения MetaPost файла в EPS и PDF рисунки

# каталоги для хранения eps- и  pdf-файлов
EPS_DIR=./eps
PDF_DIR=./pdf
TMP_FILE=tmp

if [[ "$@" == ""]];
then
  echo 
  echo Скрипт обрабатывает mp-файл, создает eps- и pdf-файлы и
  echo перемещает их соответственно в каталоги $EPS_DIR и $PDF_DIR
  echo Использование: ./mp2pdf.sh file.mp
  echo
  exit
fi

if [ ! -d $EPS_DIR ]; then
  echo ======== Создание каталога для eps-файлов 
  mkdir $EPS_DIR
fi
if [ ! -d $PDF_DIR ]; then
  echo ======== Создание каталога для pdf-файлов
  mkdir $PDF_DIR
fi

echo ======== Исходный файл: $@

list=`grep beginfig $1 | sed -e 's/beginfig(//' -e 's/);//'`
echo ======== Список блоков:  $list

echo ======== Запуск mpost...
mpost -tex=latex $1

for i in $list          # цикл по блокам beginfig()
do
 epsi=${1%mp}$i
 eps=${1%.mp}${i}.eps
 pdf=${1%.mp}${i}.pdf
 echo Блок ${i}: ' >> ' $epsi ' >> ' $eps ' >> ' $pdf

if [ ! -e $epsi ]; then
  echo
  echo Ошибки при обработке mp-файла!
  echo
  exit
else
  echo ======== MetaPost ===== Ok!
fi

echo ======== Генерация временного LaTeX-файла...
echo \\documentclass[12pt]{article} > ${TMP_FILE}.tex
echo \\usepackage{mathtext} >> ${TMP_FILE}.tex
echo \\usepackage{amsmath} >> ${TMP_FILE}.tex
echo \\usepackage[T2A]{fontenc} >> ${TMP_FILE}.tex
echo \\usepackage[koi8-r]{inputenc} >> ${TMP_FILE}.tex
echo \\usepackage[english,russian]{babel} >> ${TMP_FILE}.tex
echo \\usepackage{graphics} >> ${TMP_FILE}.tex
echo \\begin{document} >> ${TMP_FILE}.tex
echo \\pagestyle{empty} >> ${TMP_FILE}.tex
echo \\includegraphics{${epsi}} >> ${TMP_FILE}.tex
echo \\end{document} >> ${TMP_FILE}.tex

echo ======== Запуск LaTeX...
latex ${TMP_FILE}

if [ ! -e ${TMP_FILE}.dvi ]; then
  echo
  echo ======== Не найден dvi-файл!
  echo
  exit
else
  echo ======== LaTeX ===== Ok!
fi
echo ======== Запуск dvips...
dvips -E ${TMP_FILE} -o $eps

echo ======== Запуск epstopdf...
epstopdf $eps

if [[ -e $pdf]]; then
 mv $eps $EPS_DIR 
 mv $pdf $PDF_DIR
 echo ======== Перенос $eps и $pdf в нужное место...
fi

echo ======== Зачистка...
rm *.log *.mpx ${TMP_FILE}.* *.aux *.dvi *.tex $epsi 2>>/dev/null

done

Скрипт надо сделать исполняемым:

chmod +x ./mp2pdf.sh

Использование:

./mp2pdf.sh file.mp

Пример MetaPost-файла для тестирования:

%% Шаблон для mp-файлов
prologues:=0;

% LaTeX; работает вместе с "mpost -tex=latex file.mp" (см. скрипт выше)
verbatimtex \documentclass[12pt]{article}
\usepackage{mathtext}
\usepackage{amsmath}
\usepackage[T2A]{fontenc}
\usepackage[koi8-r]{inputenc}
\usepackage[english,russian]{babel}
\begin{document}
etex;

beginfig(1);
draw (0,0)--(0,100)--(100,100)--(100,0)--cycle;
label(btex Метка: $\alpha_1$ etex, (50,50));
endfig;

end.

Язык META[править | править вики-текст]

В качестве базового языка, инструкции которого подаются на вход программы MetaPost, используется язык META[5].

В MetaPost можно оперировать следующими типами данных:

  • boolean — логический (Истина/Ложь)
  • numeric — обычные числа
  • pen (перо) — то, чем компьютер рисует (в подавляющем большинстве случаев используется круглое перо pencircle)
  • pair (точка) — пара чисел (x, y) в случае декартовых координат или R*dir(α) в случае полярных координат
  • path (путь) — набор точек с описанием типа соединений между ними
  • color (цвет) — тройка чисел (r, g, b) соответствует цветовой модели RGB
  • picture (картинка) — совокупность путей и точек
  • string (строка) — ASCII строка,
  • transform (линейные преобразования) — линейные преобразования, которые можно применять к объектам типа pair, pen, path и picture.

Имена переменных в META могут состоять из нескольких лексем. Лексемы могут быть либо буквенными, либо числовыми. Например, переменная x1l состоит из трёх лексем. Её можно переписать более понятным способом x[1].l, то есть числовая лексема по сути указывает на номер элемента в массиве, а следующая за ней буква уточняет элемент структуры. Возможность опускать «[].» в написании имён переменных упрощает в некоторых случаях восприятие кода (например,  — это x-координата границы линии слева по направлению движения для первой точки пути z[]) и сокращает объём программы. Взамен, если нужны просто переменные без подобных особенностей, то придётся ограничиться только буквенными комбинациями.

Все переменные необходимо объявлять перед использованием. Исключением являются переменные типа numeric. Массивы объявляются и используются следующим образом:

 pair w[];
 w:=(10,5);
 w[2]=w[1];

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

В META можно опускать некоторые из операторов для сокращения записей, например, 2*x соответствует записи 2x. Но, так как 1/2x — это 0.5x, что более естественно с точки зрения математики, но не программирования. В META сначала обрабатываются числовые лексемы.

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

В языке присутствуют операторы цикла, условных переходов и тому подобное. Отличительной особенностью META является возможность решать линейные уравнения. Например, выражение вида , означает, что точка C находится ровно посередине между точками А и B.

Программу mpost можно использовать в режиме калькулятора для вычислений на языке META. Это позволяет проверить правильность ваших предположений относительно языка. Пример сеанса представлен ниже:

 baldin@evgueni:~$ mpost
 This is MetaPost, Version 0.901 (Web2C 7.5.5)
 **\relax
 *a:=10;
 *b:=8;
 *c:=a+-+b;
 *show c;
 >> 6
 *show (3-sqrt 5)/2;
 >> 0.38197
 *show angle(1,sqrt 3);
 >> 60.00008
 *show 2**10;
 >> 1024.00003
 *show infinity;
 >> 4095.99998
 *show epsilon;
 >> 0.00002
 *show infinity-infinity;
 >> 0
 *end
 Transcript written on mpout.log.

После вывода приглашения ** следует набрать команду \relax. Далее можно вводить команды MetaPost. Делать это надо аккуратно, так как этот режим не поддерживает «истории команд». В начале не предполагалось, что MetaPost можно использовать и так тоже. С помощью команды show можно вывести результат на экран. Закончить сеанс можно с помощью команды end. Обратите внимание, что на просьбу вывести бесконечность (infinity) MetaPost выдал 4095.99998 — это максимальное значение, которое может принимать переменная типа numeric. Причём в процессе вычисления результат может превышать «бесконечность», но ответ должен быть меньше или равен ей, иначе будет выдана ошибка. Минимальный шаг изменения типа numeric равен epsilon, или, точнее, 1/256/256. При создании рисунка эти ограничения не существенны, так как диапазон изменения чисел вполне велик, чтобы вместить все элементы. Но в любом случае это тоже необходимо учитывать.

Если необходимо вычислить однострочное выражение, то на первоначальное приглашение ** можно ввести expr. В этом случае mpost считает файл expr.mf и на любое действие будет выдаваться ответ:

 baldin@evgueni:~$ mpost
 This is MetaPost, Version 0.901 (Web2C 7.5.5)
 **expr
 (/usr/local/texlive/2005/texmf-dist/metafont/base/expr.mf
 gimme an expr: 2(a+3b)-2b
 >> 4b+2a
 gimme an expr: 1/3[a,b]
 >> 0.33333b+0.66667a

Примеры[править | править вики-текст]

Код каждого примера приведён в описании соответствующей картинки.

Аналоги[править | править вики-текст]

MetaPost имеет некоторое количество ограничений, доставшихся ему в наследство от METAFONT. Попытка обойти эти ограничения легла в основу создания программного интерпретатора Asymptote[6]. Язык, используемый Asymptote, похож на META, но вследствие перехода от синтаксиса макро-языка к синтаксису C++ гораздо более многословен и сложен. Основное преимущество Asymptote заключается в лучшей поддержке возможностей PostScript.

Functional MetaPost — DSL для графики встроенный в Haskell, который генерирует код MetaPost.[7]

METAGRAF — графический интерфейс над MetaPost. Написан на Java. По возможностям напоминает xfig. Картинки сохраняет в формате MetaPost.[8]

Среди программного окружения LaTeX аналогичной MetaPost функциональностью также обладают пакеты PSTricks и PGF/TikZ.

На основе программной базы MetaPost был создан инструмент METATYPE1 для разработки Type1 шрифтов.

Примечания[править | править вики-текст]

Ссылки[править | править вики-текст]

Литература[править | править вики-текст]

  • Дональд Кнут. Всё про METAFONT = The METAFONTbook. — М.: Вильямс, 2003. — 384 с. — ISBN 5-8459-0442-0.
  • М. Гуссенс, С. Ратц, Ф. Миттельбах. Путеводитель по пакетам LaTeX и его графическим расширениям = The LaTeX Graphics Companion. — М.: Мир, 2002. — 621 с. — ISBN 5-03-003388-2.