{
    "version": "https:\/\/jsonfeed.org\/version\/1",
    "title": "Математик среди биологов: заметки с тегом кривая Безье",
    "_rss_description": "Я немного умею складывать, но от вычитания у меня всегда кружится голова",
    "_rss_language": "ru",
    "_itunes_email": "",
    "_itunes_categories_xml": "",
    "_itunes_image": "",
    "_itunes_explicit": "",
    "home_page_url": "https:\/\/antonlyakh.ru\/blog\/tags\/krivaya-bezye\/",
    "feed_url": "https:\/\/antonlyakh.ru\/blog\/tags\/krivaya-bezye\/json\/",
    "icon": false,
    "author": {
        "name": "Антон Лях",
        "url": "https:\/\/antonlyakh.ru\/blog\/",
        "avatar": false
    },
    "items": [
        {
            "id": "12",
            "url": "https:\/\/antonlyakh.ru\/blog\/all\/koordinaty-krivyh-iz-svg-fayla\/",
            "title": "Координаты кривых из СВГ файла",
            "content_html": "<p><span style=\"display: inline-block; font-weight: bold; padding: 6px; background-color: #7fC\"><a href=\"http:\/\/antonlyakh.ru\/download\/?svg2txt\">Скачать конвертер<\/a><\/span><\/p>\n<p>Для работы мне необходимы контуры микроорганизмов, которые я использую для сравнения форм. Я получаю контуры из фотографий, очерчивая объект в векторном редакторе. Программа сохраняет результат в СВГ файле, а мне нужны живые координаты точек. Чтобы получить координаты, я анализирую СВГ файл.<\/p>\n<p>СВГ файл состоит из тегов. Я разберу только один — <abbr>path<\/abbr>, — остальные мне не нужны. Он хранит описание криволинейных и замкнутых траекторий. Траектория — это и есть тот самый контур микроорганизма.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/trajectory.jpg\" width=\"600\" height=\"505\" alt=\"\" \/>\n<\/div>\n<h2>Учим синтаксис тега <abbr>path<\/abbr><\/h2>\n<p>Описание траектории вложено в тег <abbr>svg<\/abbr>. Примерно так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">Заголовок подтверждающий, что это СВГ\r\n&lt;svg&gt;\r\n  &lt;path ... \/&gt;\r\n&lt;\/svg&gt;<\/code><\/pre><p>Тег <abbr>path<\/abbr> содержит один атрибут <abbr>d<\/abbr> с алгоритмом рисования траектории.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;path d=&quot;алгоритм рисования&quot; \/&gt;<\/code><\/pre><p>Алгоритм состоит из <i>букв-команд<\/i> и <i>цифр-координат,<\/i> которые разделенны <i>пробелом, запятой<\/i> или <i>знаком минус.<\/i> Траекторию рисует перо, буквы-команды управляют, цифры-координаты показывают куда или как сместить перо, а разделители отделяют одно от другого.<\/p>\n<h3>Разделители разделяют<\/h3>\n<p>Пробел — это стандартный разделитель. Его можно ставить везде между командами и координатами. Спецификация СВГ разрешает не писать пробел, когда из контекста понятно, что здесь две разные сущности. Это сокращает объем СВГ-файла.<\/p>\n<p>Запомним:<\/p>\n<ul>\n<li>пробел не нужен между командой и числом;<\/li>\n<li>пробел не нужен после запятой;<\/li>\n<li>пробел не нужен перед знаком минус.<\/li>\n<\/ul>\n<p>Запятая тоже разделяет два числа, но вместо нее можно написать пробел. Что именно написать — дело вкуса.<\/p>\n<p>Следующие три записи эквивалентны, но последняя компактнее.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;path d=&quot;M 15 17 L 18 -23 Z&quot; \/&gt;\r\n&lt;path d=&quot;M 15, 17 L 18, -23 Z&quot; \/&gt;\r\n&lt;path d=&quot;M15,17L18-23Z&quot; \/&gt;<\/code><\/pre><p>Теперь о цифрах.<\/p>\n<h3>Цифры хранят координаты<\/h3>\n<p>СВГ предназначен для хранения двумерной графики. Поэтому цифры задают координаты точек на плоскости. Для каждой точки используется два числа — первое для <i>x<\/i>, второе для <i>y<\/i>.<\/p>\n<p>Координаты бывают абсолютными и относительными. Абсолютные координаты отсчитываются от нуля, относительные — от конечной точки предыдущей команды. Относительные — это шаг, на который надо сдвинуть перо относительно последней позиции.<\/p>\n<p>Тип координат определяет регистр буквы-команды: большая буква обозначает абсолютную позицию, маленькая — относительную.<\/p>\n<blockquote>\n<blockquote>\n<p>Заглавная буква-команда — для абсолютных координат, прописная — для относительных<\/p>\n<\/blockquote>\n<\/blockquote>\n<p>Точка является десятичным разделителем вещественных чисел. Запись <abbr>12,75<\/abbr> — это два числа: 12 и 75, тогда как <abbr>12.75<\/abbr> — это одно вещественное число.<\/p>\n<blockquote>\n<blockquote>\n<p>Точка — десятичный разделитель, запятая отделяет два числа.<\/p>\n<\/blockquote>\n<\/blockquote>\n<p>Цифры еще описывают дополнительные параметры команды <b>A<\/b>, которая рисует дуги.<\/p>\n<h3>Буквы управляют пером<\/h3>\n<p>Буквы — это команды, которые управляют пером. За каждой командой следуют пары координат, которые показывают, куда сместить перо или как закруглить линию. Тег <abbr>path<\/abbr> использует следующие команды:<\/p>\n<ul>\n<li><b>M<\/b> — начать новую траекторию: переместить перо в заданную точку без рисования.<\/li>\n<li><b>Z<\/b> — замкнуть траекторию: переместить перо в начальную точку и нарисовать линию.<\/li>\n<li><b>С<\/b>, <b>S<\/b> — нарисовать кубическую кривую Безье.<\/li>\n<li><b>Q<\/b>, <b>T<\/b> — нарисовать квадратную кривую Безье.<\/li>\n<li><b>L<\/b>, <b>Н<\/b> и <b>V<\/b> — нарисовать произвольную, вертикальную или горизонтальную прямую.<\/li>\n<li><b>A<\/b> — нарисовать дугу окружности или эллипса.<\/li>\n<\/ul>\n<p>Команду <b>A<\/b> я пропущу, но рассмотрю остальные.<\/p>\n<h5><i>M x y<\/i><\/h5>\n<p><b>М<\/b> или <b>m<\/b> начинает новую траекторию. Команда перемещает перо в заданную точку и ничего не рисует. Большое <b>М<\/b> — первая обязательная команда тега <abbr>path<\/abbr>.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;path d=&quot;M20 50...&quot; \/&gt;<\/code><\/pre><h5><i><b>Z<\/b><\/i><\/h5>\n<p><b>Z<\/b> или <b>z<\/b> замыкает траекторию — проводит прямую линию от последней позиции пера к первой точке траектории. Регистр буквы не важен. Обычно это последняя команда тега. Если нет, тогда после <b>z<\/b> опять стоит большое <b>M<\/b>, которое начинает новую траекторию. Если <b>z<\/b> не написано, траектория незамкнута.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;path d=&quot;M20 50 L 10 10, 140 10, 110 50z&quot; \/&gt;<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/open-path.gif\" width=\"384\" height=\"132\" alt=\"\" \/>\n<\/div>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;path d=&quot;M20 50 L 10 10, 140 10, 110 50z&quot; \/&gt;<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/closed-path.gif\" width=\"374\" height=\"132\" alt=\"\" \/>\n<\/div>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;path d=&quot;M20 50 L 10 10, 140 10z M110 50, 80 60, 95 90z&quot; \/&gt;<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/two-closed-path.gif\" width=\"374\" height=\"234\" alt=\"\" \/>\n<\/div>\n<h5><i><b>L<\/b> x y<\/i><\/h5>\n<p><b>L<\/b> или <b>l<\/b> рисует прямую линию от последней позиции пера до заданной точки. Несколько следующих друг за другом команд описывают ломаную. В такой записи, для краткости, все <b>L<\/b>, кроме первой, не пишут. Если <b>L<\/b> стоит после <b>M<\/b>, ее тоже не пишут. Вот так:<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;path d=&quot;M 70,12 L 24,30 L 60,70 L 120,50&quot; \/&gt;\r\n&lt;path d=&quot;M 70,12 L 24,30 60,70 120,50&quot; \/&gt;\r\n&lt;path d=&quot;M 70,12 24,30 60,70 120,50&quot; \/&gt;<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/polyline.gif\" width=\"266\" height=\"172\" alt=\"\" \/>\n<\/div>\n<h5><i><b>H<\/b> x<\/i><\/h5>\n<p><b>H<\/b> или <b>h<\/b> рисует горизонтальную линию от последней позиции пера до указанной точки. Координата <i>у<\/i> не меняется.<\/p>\n<h5><i><b>V<\/b> x<\/i><\/h5>\n<p><b>V<\/b> или <b>v<\/b> рисует вертикальную линию от последней позиции пера до указанной точки. Координата <i>x<\/i> не меняется.<\/p>\n<h5><i><b>C<\/b> cx<sub>1<\/sub> cy<sub>1<\/sub> cx<sub>2<\/sub> cy<sub>2<\/sub> x<sub>2<\/sub> y<sub>2<\/sub><\/i><\/h5>\n<p><b>С<\/b> или <b>с<\/b> строит кубическую кривую Безье. Она состоит из четырех точек: первая и последняя задают начало и конец кривой, две промежуточные управляют формой. Так как первая точка совпадает с текущим положением пера, то после команды <b>C<\/b> указывают только три точки: две управляющие вершины (<i>cx<sub>1<\/sub> cy<sub>1<\/sub><\/i>), (<i>cx<sub>2<\/sub> cy<sub>2<\/sub><\/i>) и последнюю точку кривой (<i>x<sub>2<\/sub> y<sub>2<\/sub><\/i>).<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;path d=&quot;M40 50 C 60 10, 90 90, 110 50&quot; \/&gt;<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/bezier.gif\" width=\"314\" height=\"118\" alt=\"\" \/>\n<\/div>\n<p><i>Поликривая Безье<\/i> — это несколько соприкасающихся кривых Безье, где конец одной кривой становится началом следующей. Последовательные команды <b>C<\/b> описывают поликривую. Для экономии байтов все команды, кроме первой <b>C<\/b>, не пишут.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">&lt;path d=&quot;M30 100C50 50,70 20,100 100,110 130,45 150,65 100&quot; \/&gt;<\/code><\/pre><div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/bezier-polyline.gif\" width=\"270\" height=\"302\" alt=\"\" \/>\n<\/div>\n<p>Обычно в месте соприкосновения кривых Безье гладкость поликривой нарушается. Чтобы поликривая оставалась гладкой, используют команду <b>S<\/b>.<\/p>\n<h5><i><b>S<\/b> cx<sub>2<\/sub> cy<sub>2<\/sub> x<sub>2<\/sub> y<sub>2<\/sub><\/i><\/h5>\n<p><b>S<\/b> или <b>s<\/b> строит гладкую кубическую кривую Безье так, что ее первая управляющая вершина является зеркальным отражением второй управляющей вершины предыдущей кривой Безье. Отражение относительно начальной точки данной кривой.<\/p>\n<h5><i><b>Q<\/b> cx<sub>1<\/sub> cy<sub>1<\/sub> x<sub>2<\/sub> y<sub>2<\/sub><\/i><\/h5>\n<p><b>Q<\/b> или <b>q<\/b> строит квадратную кривую Безье. Синтаксис команды аналогичен <b>C<\/b>, только здесь используется одна управляющая вершина.<\/p>\n<p>Несколько команд <b>Q<\/b> описывают квадратную поликривую Безье. Для краткости все команды, кроме первой <b>Q<\/b>, не пишут. Чтобы квадратная поликривая получилась гладкой, используют команду <b>T<\/b>.<\/p>\n<h5><i><b>T<\/b> x<sub>2<\/sub> y<sub>2<\/sub><\/i><\/h5>\n<p><b>T<\/b> или <b>t<\/b> строит гладкую квадратную кривую Безье так, что ее единственная управляющая вершина является зеркальным отражением управляющей вершины предыдущей кривой Безье.<\/p>\n<p>Со структурой файла разобрались.<\/p>\n<p><a name=\"svg-converter\"><\/a><\/p>\n<h3>Пишем конвертер СВГ в текст<\/h3>\n<p>Конвертер готов. Это экзешник. Инсталировать не нужно. Сохраните на диск и запустите.<\/p>\n<div class=\"e2-text-picture\">\n<img src=\"https:\/\/antonlyakh.ru\/blog\/pictures\/svg-converter.gif\" width=\"645\" height=\"446\" alt=\"\" \/>\n<\/div>\n<p><span style=\"display: inline-block; font-weight: bold; padding: 6px; background-color: #7fC\"><a href=\"http:\/\/antonlyakh.ru\/download\/?svg2txt\">Скачать конвертер<\/a><\/span><\/p>\n<p>Для описания любого контура достаточно трех команд: <abbr>M<\/abbr>, <abbr>C<\/abbr> и <abbr>Z<\/abbr>. Конвертер понимает еще и четвертую: <abbr>L<\/abbr>, остальные — нет.<\/p>\n<p>Конвертер выбирает из СВГ-файла теги <abbr>path<\/abbr>, вычисляет координаты точек траектории и сохраняет их в текстовом файле.<\/p>\n<p>Конвертер не проверяет валидность СВГ-файла. Ему все равно, какая информация находится вокруг тега <abbr>path<\/abbr>. На вход конвертера можно подать любой мусор с корректными данными только в теге <abbr>path<\/abbr>.<\/p>\n<p>Конвертер поддерживает пропорциональное и произвольное масштабирование координат: перед сохранением он спрашивает размер области, в которую надо вписать траекторию.<\/p>\n<p>Конвертер позволяет задать позицию начала координат: в одном из углов, на середине стороны или в центре прямоугольника, ограничивающего контур.<\/p>\n<p>Конвертер сохраняет в текстовом файле пары чисел — двумерные координаты точек контура. Десятичный разделитель — точка. Числа разделены пробелом.<\/p>\n<p><abbr>12.3 15.6 78.4 24.1 15 123<\/abbr><\/p>\n<h3>Детали<\/h3>\n<p>Конвертер написан на Дельфи 7.<\/p>\n<p>Пары чисел вырезаю из СВГ-файла с помощью регулярного выражения. Понимает числа разделенные пробелом, запятой или минусом.<\/p>\n<pre class=\"e2-text-code\"><code class=\"\">\/(-?\\d+(\\.\\d+)?)[,|\\s]?(-?\\d+(\\.\\d+)?)\\s?\/<\/code><\/pre><p>Для построения кубической кривой Безье применяю <a href=\"https:\/\/rsdn.ru\/article\/multimedia\/Bezier.xml\">адаптивное разбиение<\/a>.<\/p>\n<p>Полученные данные анализирую методами геометрической морфометрии. Но это уже другая история.<\/p>\n<p>С Новым годом!<\/p>\n",
            "date_published": "2015-12-30T19:29:28+03:00",
            "date_modified": "2016-03-14T19:42:28+03:00",
            "image": "https:\/\/antonlyakh.ru\/blog\/pictures\/trajectory.jpg",
            "_date_published_rfc2822": "Wed, 30 Dec 2015 19:29:28 +0300",
            "_rss_guid_is_permalink": "true",
            "_rss_guid": "https:\/\/antonlyakh.ru\/blog\/all\/koordinaty-krivyh-iz-svg-fayla\/",
            "_e2_data": {
                "is_favourite": false,
                "links_required": [
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css",
                    "system\/library\/highlight\/highlight.js",
                    "system\/library\/highlight\/highlight.css"
                ],
                "og_images": [
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/trajectory.jpg",
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/open-path.gif",
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/closed-path.gif",
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/two-closed-path.gif",
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/polyline.gif",
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/bezier.gif",
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/bezier-polyline.gif",
                    "https:\/\/antonlyakh.ru\/blog\/pictures\/svg-converter.gif"
                ]
            }
        }
    ],
    "_e2_version": 3559,
    "_e2_ua_string": "E2 (v3559; Aegea)"
}