<?xml version="1.0" encoding="utf-8"?> 
<rss version="2.0"
  xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"
  xmlns:atom="http://www.w3.org/2005/Atom">

<channel>

<title>Математик среди биологов: заметки с тегом кривая Безье</title>
<link>https://antonlyakh.ru/blog/tags/krivaya-bezye/</link>
<description>Я немного умею складывать, но от вычитания у меня всегда кружится голова</description>
<author>Антон Лях</author>
<language>ru</language>
<generator>E2 (v3559; Aegea)</generator>

<itunes:owner>
<itunes:name>Антон Лях</itunes:name>
<itunes:email></itunes:email>
</itunes:owner>
<itunes:subtitle>Я немного умею складывать, но от вычитания у меня всегда кружится голова</itunes:subtitle>
<itunes:image href="" />
<itunes:explicit></itunes:explicit>

<item>
<title>Координаты кривых из СВГ файла</title>
<guid isPermaLink="true">https://antonlyakh.ru/blog/all/koordinaty-krivyh-iz-svg-fayla/</guid>
<link>https://antonlyakh.ru/blog/all/koordinaty-krivyh-iz-svg-fayla/</link>
<pubDate>Wed, 30 Dec 2015 19:29:28 +0300</pubDate>
<author>Антон Лях</author>
<comments>https://antonlyakh.ru/blog/all/koordinaty-krivyh-iz-svg-fayla/</comments>
<description>
&lt;p&gt;&lt;span style="display: inline-block; font-weight: bold; padding: 6px; background-color: #7fC"&gt;&lt;a href="http://antonlyakh.ru/download/?svg2txt"&gt;Скачать конвертер&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Для работы мне необходимы контуры микроорганизмов, которые я использую для сравнения форм. Я получаю контуры из фотографий, очерчивая объект в векторном редакторе. Программа сохраняет результат в СВГ файле, а мне нужны живые координаты точек. Чтобы получить координаты, я анализирую СВГ файл.&lt;/p&gt;
&lt;p&gt;СВГ файл состоит из тегов. Я разберу только один — &lt;abbr&gt;path&lt;/abbr&gt;, — остальные мне не нужны. Он хранит описание криволинейных и замкнутых траекторий. Траектория — это и есть тот самый контур микроорганизма.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/trajectory.jpg" width="600" height="505" alt="" /&gt;
&lt;/div&gt;
&lt;h2&gt;Учим синтаксис тега &lt;abbr&gt;path&lt;/abbr&gt;&lt;/h2&gt;
&lt;p&gt;Описание траектории вложено в тег &lt;abbr&gt;svg&lt;/abbr&gt;. Примерно так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;Заголовок подтверждающий, что это СВГ
&amp;lt;svg&amp;gt;
  &amp;lt;path ... /&amp;gt;
&amp;lt;/svg&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Тег &lt;abbr&gt;path&lt;/abbr&gt; содержит один атрибут &lt;abbr&gt;d&lt;/abbr&gt; с алгоритмом рисования траектории.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;path d=&amp;quot;алгоритм рисования&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Алгоритм состоит из &lt;i&gt;букв-команд&lt;/i&gt; и &lt;i&gt;цифр-координат,&lt;/i&gt; которые разделенны &lt;i&gt;пробелом, запятой&lt;/i&gt; или &lt;i&gt;знаком минус.&lt;/i&gt; Траекторию рисует перо, буквы-команды управляют, цифры-координаты показывают куда или как сместить перо, а разделители отделяют одно от другого.&lt;/p&gt;
&lt;h3&gt;Разделители разделяют&lt;/h3&gt;
&lt;p&gt;Пробел — это стандартный разделитель. Его можно ставить везде между командами и координатами. Спецификация СВГ разрешает не писать пробел, когда из контекста понятно, что здесь две разные сущности. Это сокращает объем СВГ-файла.&lt;/p&gt;
&lt;p&gt;Запомним:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;пробел не нужен между командой и числом;&lt;/li&gt;
&lt;li&gt;пробел не нужен после запятой;&lt;/li&gt;
&lt;li&gt;пробел не нужен перед знаком минус.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Запятая тоже разделяет два числа, но вместо нее можно написать пробел. Что именно написать — дело вкуса.&lt;/p&gt;
&lt;p&gt;Следующие три записи эквивалентны, но последняя компактнее.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;path d=&amp;quot;M 15 17 L 18 -23 Z&amp;quot; /&amp;gt;
&amp;lt;path d=&amp;quot;M 15, 17 L 18, -23 Z&amp;quot; /&amp;gt;
&amp;lt;path d=&amp;quot;M15,17L18-23Z&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Теперь о цифрах.&lt;/p&gt;
&lt;h3&gt;Цифры хранят координаты&lt;/h3&gt;
&lt;p&gt;СВГ предназначен для хранения двумерной графики. Поэтому цифры задают координаты точек на плоскости. Для каждой точки используется два числа — первое для &lt;i&gt;x&lt;/i&gt;, второе для &lt;i&gt;y&lt;/i&gt;.&lt;/p&gt;
&lt;p&gt;Координаты бывают абсолютными и относительными. Абсолютные координаты отсчитываются от нуля, относительные — от конечной точки предыдущей команды. Относительные — это шаг, на который надо сдвинуть перо относительно последней позиции.&lt;/p&gt;
&lt;p&gt;Тип координат определяет регистр буквы-команды: большая буква обозначает абсолютную позицию, маленькая — относительную.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Заглавная буква-команда — для абсолютных координат, прописная — для относительных&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Точка является десятичным разделителем вещественных чисел. Запись &lt;abbr&gt;12,75&lt;/abbr&gt; — это два числа: 12 и 75, тогда как &lt;abbr&gt;12.75&lt;/abbr&gt; — это одно вещественное число.&lt;/p&gt;
&lt;blockquote&gt;
&lt;blockquote&gt;
&lt;p&gt;Точка — десятичный разделитель, запятая отделяет два числа.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/blockquote&gt;
&lt;p&gt;Цифры еще описывают дополнительные параметры команды &lt;b&gt;A&lt;/b&gt;, которая рисует дуги.&lt;/p&gt;
&lt;h3&gt;Буквы управляют пером&lt;/h3&gt;
&lt;p&gt;Буквы — это команды, которые управляют пером. За каждой командой следуют пары координат, которые показывают, куда сместить перо или как закруглить линию. Тег &lt;abbr&gt;path&lt;/abbr&gt; использует следующие команды:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;M&lt;/b&gt; — начать новую траекторию: переместить перо в заданную точку без рисования.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Z&lt;/b&gt; — замкнуть траекторию: переместить перо в начальную точку и нарисовать линию.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;С&lt;/b&gt;, &lt;b&gt;S&lt;/b&gt; — нарисовать кубическую кривую Безье.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;Q&lt;/b&gt;, &lt;b&gt;T&lt;/b&gt; — нарисовать квадратную кривую Безье.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;L&lt;/b&gt;, &lt;b&gt;Н&lt;/b&gt; и &lt;b&gt;V&lt;/b&gt; — нарисовать произвольную, вертикальную или горизонтальную прямую.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;A&lt;/b&gt; — нарисовать дугу окружности или эллипса.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Команду &lt;b&gt;A&lt;/b&gt; я пропущу, но рассмотрю остальные.&lt;/p&gt;
&lt;h5&gt;&lt;i&gt;M x y&lt;/i&gt;&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;М&lt;/b&gt; или &lt;b&gt;m&lt;/b&gt; начинает новую траекторию. Команда перемещает перо в заданную точку и ничего не рисует. Большое &lt;b&gt;М&lt;/b&gt; — первая обязательная команда тега &lt;abbr&gt;path&lt;/abbr&gt;.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;path d=&amp;quot;M20 50...&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;h5&gt;&lt;i&gt;&lt;b&gt;Z&lt;/b&gt;&lt;/i&gt;&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;Z&lt;/b&gt; или &lt;b&gt;z&lt;/b&gt; замыкает траекторию — проводит прямую линию от последней позиции пера к первой точке траектории. Регистр буквы не важен. Обычно это последняя команда тега. Если нет, тогда после &lt;b&gt;z&lt;/b&gt; опять стоит большое &lt;b&gt;M&lt;/b&gt;, которое начинает новую траекторию. Если &lt;b&gt;z&lt;/b&gt; не написано, траектория незамкнута.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;path d=&amp;quot;M20 50 L 10 10, 140 10, 110 50z&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/open-path.gif" width="384" height="132" alt="" /&gt;
&lt;/div&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;path d=&amp;quot;M20 50 L 10 10, 140 10, 110 50z&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/closed-path.gif" width="374" height="132" alt="" /&gt;
&lt;/div&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;path d=&amp;quot;M20 50 L 10 10, 140 10z M110 50, 80 60, 95 90z&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/two-closed-path.gif" width="374" height="234" alt="" /&gt;
&lt;/div&gt;
&lt;h5&gt;&lt;i&gt;&lt;b&gt;L&lt;/b&gt; x y&lt;/i&gt;&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;L&lt;/b&gt; или &lt;b&gt;l&lt;/b&gt; рисует прямую линию от последней позиции пера до заданной точки. Несколько следующих друг за другом команд описывают ломаную. В такой записи, для краткости, все &lt;b&gt;L&lt;/b&gt;, кроме первой, не пишут. Если &lt;b&gt;L&lt;/b&gt; стоит после &lt;b&gt;M&lt;/b&gt;, ее тоже не пишут. Вот так:&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;path d=&amp;quot;M 70,12 L 24,30 L 60,70 L 120,50&amp;quot; /&amp;gt;
&amp;lt;path d=&amp;quot;M 70,12 L 24,30 60,70 120,50&amp;quot; /&amp;gt;
&amp;lt;path d=&amp;quot;M 70,12 24,30 60,70 120,50&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/polyline.gif" width="266" height="172" alt="" /&gt;
&lt;/div&gt;
&lt;h5&gt;&lt;i&gt;&lt;b&gt;H&lt;/b&gt; x&lt;/i&gt;&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;H&lt;/b&gt; или &lt;b&gt;h&lt;/b&gt; рисует горизонтальную линию от последней позиции пера до указанной точки. Координата &lt;i&gt;у&lt;/i&gt; не меняется.&lt;/p&gt;
&lt;h5&gt;&lt;i&gt;&lt;b&gt;V&lt;/b&gt; x&lt;/i&gt;&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;V&lt;/b&gt; или &lt;b&gt;v&lt;/b&gt; рисует вертикальную линию от последней позиции пера до указанной точки. Координата &lt;i&gt;x&lt;/i&gt; не меняется.&lt;/p&gt;
&lt;h5&gt;&lt;i&gt;&lt;b&gt;C&lt;/b&gt; cx&lt;sub&gt;1&lt;/sub&gt; cy&lt;sub&gt;1&lt;/sub&gt; cx&lt;sub&gt;2&lt;/sub&gt; cy&lt;sub&gt;2&lt;/sub&gt; x&lt;sub&gt;2&lt;/sub&gt; y&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt;&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;С&lt;/b&gt; или &lt;b&gt;с&lt;/b&gt; строит кубическую кривую Безье. Она состоит из четырех точек: первая и последняя задают начало и конец кривой, две промежуточные управляют формой. Так как первая точка совпадает с текущим положением пера, то после команды &lt;b&gt;C&lt;/b&gt; указывают только три точки: две управляющие вершины (&lt;i&gt;cx&lt;sub&gt;1&lt;/sub&gt; cy&lt;sub&gt;1&lt;/sub&gt;&lt;/i&gt;), (&lt;i&gt;cx&lt;sub&gt;2&lt;/sub&gt; cy&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt;) и последнюю точку кривой (&lt;i&gt;x&lt;sub&gt;2&lt;/sub&gt; y&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt;).&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;path d=&amp;quot;M40 50 C 60 10, 90 90, 110 50&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/bezier.gif" width="314" height="118" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;i&gt;Поликривая Безье&lt;/i&gt; — это несколько соприкасающихся кривых Безье, где конец одной кривой становится началом следующей. Последовательные команды &lt;b&gt;C&lt;/b&gt; описывают поликривую. Для экономии байтов все команды, кроме первой &lt;b&gt;C&lt;/b&gt;, не пишут.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;&amp;lt;path d=&amp;quot;M30 100C50 50,70 20,100 100,110 130,45 150,65 100&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/bezier-polyline.gif" width="270" height="302" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;Обычно в месте соприкосновения кривых Безье гладкость поликривой нарушается. Чтобы поликривая оставалась гладкой, используют команду &lt;b&gt;S&lt;/b&gt;.&lt;/p&gt;
&lt;h5&gt;&lt;i&gt;&lt;b&gt;S&lt;/b&gt; cx&lt;sub&gt;2&lt;/sub&gt; cy&lt;sub&gt;2&lt;/sub&gt; x&lt;sub&gt;2&lt;/sub&gt; y&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt;&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;S&lt;/b&gt; или &lt;b&gt;s&lt;/b&gt; строит гладкую кубическую кривую Безье так, что ее первая управляющая вершина является зеркальным отражением второй управляющей вершины предыдущей кривой Безье. Отражение относительно начальной точки данной кривой.&lt;/p&gt;
&lt;h5&gt;&lt;i&gt;&lt;b&gt;Q&lt;/b&gt; cx&lt;sub&gt;1&lt;/sub&gt; cy&lt;sub&gt;1&lt;/sub&gt; x&lt;sub&gt;2&lt;/sub&gt; y&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt;&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;Q&lt;/b&gt; или &lt;b&gt;q&lt;/b&gt; строит квадратную кривую Безье. Синтаксис команды аналогичен &lt;b&gt;C&lt;/b&gt;, только здесь используется одна управляющая вершина.&lt;/p&gt;
&lt;p&gt;Несколько команд &lt;b&gt;Q&lt;/b&gt; описывают квадратную поликривую Безье. Для краткости все команды, кроме первой &lt;b&gt;Q&lt;/b&gt;, не пишут. Чтобы квадратная поликривая получилась гладкой, используют команду &lt;b&gt;T&lt;/b&gt;.&lt;/p&gt;
&lt;h5&gt;&lt;i&gt;&lt;b&gt;T&lt;/b&gt; x&lt;sub&gt;2&lt;/sub&gt; y&lt;sub&gt;2&lt;/sub&gt;&lt;/i&gt;&lt;/h5&gt;
&lt;p&gt;&lt;b&gt;T&lt;/b&gt; или &lt;b&gt;t&lt;/b&gt; строит гладкую квадратную кривую Безье так, что ее единственная управляющая вершина является зеркальным отражением управляющей вершины предыдущей кривой Безье.&lt;/p&gt;
&lt;p&gt;Со структурой файла разобрались.&lt;/p&gt;
&lt;p&gt;&lt;a name="svg-converter"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Пишем конвертер СВГ в текст&lt;/h3&gt;
&lt;p&gt;Конвертер готов. Это экзешник. Инсталировать не нужно. Сохраните на диск и запустите.&lt;/p&gt;
&lt;div class="e2-text-picture"&gt;
&lt;img src="https://antonlyakh.ru/blog/pictures/svg-converter.gif" width="645" height="446" alt="" /&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style="display: inline-block; font-weight: bold; padding: 6px; background-color: #7fC"&gt;&lt;a href="http://antonlyakh.ru/download/?svg2txt"&gt;Скачать конвертер&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Для описания любого контура достаточно трех команд: &lt;abbr&gt;M&lt;/abbr&gt;, &lt;abbr&gt;C&lt;/abbr&gt; и &lt;abbr&gt;Z&lt;/abbr&gt;. Конвертер понимает еще и четвертую: &lt;abbr&gt;L&lt;/abbr&gt;, остальные — нет.&lt;/p&gt;
&lt;p&gt;Конвертер выбирает из СВГ-файла теги &lt;abbr&gt;path&lt;/abbr&gt;, вычисляет координаты точек траектории и сохраняет их в текстовом файле.&lt;/p&gt;
&lt;p&gt;Конвертер не проверяет валидность СВГ-файла. Ему все равно, какая информация находится вокруг тега &lt;abbr&gt;path&lt;/abbr&gt;. На вход конвертера можно подать любой мусор с корректными данными только в теге &lt;abbr&gt;path&lt;/abbr&gt;.&lt;/p&gt;
&lt;p&gt;Конвертер поддерживает пропорциональное и произвольное масштабирование координат: перед сохранением он спрашивает размер области, в которую надо вписать траекторию.&lt;/p&gt;
&lt;p&gt;Конвертер позволяет задать позицию начала координат: в одном из углов, на середине стороны или в центре прямоугольника, ограничивающего контур.&lt;/p&gt;
&lt;p&gt;Конвертер сохраняет в текстовом файле пары чисел — двумерные координаты точек контура. Десятичный разделитель — точка. Числа разделены пробелом.&lt;/p&gt;
&lt;p&gt;&lt;abbr&gt;12.3 15.6 78.4 24.1 15 123&lt;/abbr&gt;&lt;/p&gt;
&lt;h3&gt;Детали&lt;/h3&gt;
&lt;p&gt;Конвертер написан на Дельфи 7.&lt;/p&gt;
&lt;p&gt;Пары чисел вырезаю из СВГ-файла с помощью регулярного выражения. Понимает числа разделенные пробелом, запятой или минусом.&lt;/p&gt;
&lt;pre class="e2-text-code"&gt;&lt;code class=""&gt;/(-?\d+(\.\d+)?)[,|\s]?(-?\d+(\.\d+)?)\s?/&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Для построения кубической кривой Безье применяю &lt;a href="https://rsdn.ru/article/multimedia/Bezier.xml"&gt;адаптивное разбиение&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Полученные данные анализирую методами геометрической морфометрии. Но это уже другая история.&lt;/p&gt;
&lt;p&gt;С Новым годом!&lt;/p&gt;
</description>
</item>


</channel>
</rss>