Каждый раз, изобретая один и тот же велосипед,
мы изобретаем ещё что-то новое.
Древнегреческий философ (нет).
Эта запись в блоге — просто на свою «тригонометрическую память». Ничего особо полезного тут не будет, наверно. Я даже не могу выгрузить этот скрипт отдельным файлом, потому что он сильно встроен в экстеншен.
В начале — несколько просто красивых картинок и скрины на память:
В проекте «Генератор дорожных указателей» встречается шаблон с наклонной правой стороной — это указатель направления съезда. В гайде по этому знаку указан угол наклона — 70 градусов. Определив ширину знака по его содержимому, можно без проблем рассчитать точки будущей трапеции. И после этого необходимо скруглить углы.
Казалось бы — такая простая задача: скруглить углы у многоугольника. Тем более, что производить это надо в таком мощном графическом редакторе, как Иллюстратор. Но проблема кроется в том, что скругления углов нет в скриптах для Адоба Иллюстратора 🤓.
Вернее в скриптовании Иллюстратора есть скругление углов, но только при создании прямоугольника. Но так как у нас трапеция, то придётся заниматься этим в коде уже после создания формы. Вариант с созданием прямоугольника (с скруглениями) и последующим переносом точек не подходит, потому что тогда управляющие точки — «усики» — изменили бы форму углов.
Задача по шаблону состояла из 2 частей: рассчитать точки трапеции и потом уже скруглить углы.
Инструмент должен быть гибким, поэтому я принял наклон в 70 градусов за переменную. Если вдруг дизайнер поменяет гайд, система должна работать и при 70, и при 72 и даже при 89, если вдруг такое понадобится. Значение угла наклона я вынес в параметр элемента вёрстки шаблона, то есть менеджер проекта без привлечения программиста может поменять настройки конкретного знака:
Рассчитать трапецию — простая геометрическая задача. Зная высоту и ширину знака, мы просто смещаем нижнюю точку на нужный угол. Единственная сложность была — это то, что правую сторону нужно считать от наклонённой стрелки. Но это тоже небольшая тригонометрическая проблема.
Конечно, в интернете есть скрипты, которые отлично скругляют углы. Тем более, что это очень простая форма — трапеция. Но не хотелось запихивать в экстеншен огромный скрипт для Иллюстратора. Поэтому решил сделать свой мини-скрипт.
Знак в форме трапеции — это единичный случай, поэтому не зацикливался на этой задаче и возвращался к ней периодически для смены деятельности, так сказать.
Принципиально не хотел лезть в параметрические уравнения (которые описывают кривые Безье), потому что для этой задачи я был уверен, что это не нужно. Так оно и вышло: взяв один случай (радиус и угол из шаблона), обсчитал его и ввёл константы для моего диапазона. «Тригонометрия» получилась такая:
К сожалению не смог найти бумажку, на которой все эти отрезки подписаны: dD, dY и так далее.
Потом вывел значения отрезков. Получилась такая «кухня»:
var dD = cornerRadius / Math.sin(ANGLE_RAD), dY = cornerRadius * Math.sin(ANGLE_RAD), dH = cornerRadius * Math.cos(ANGLE_RAD), dAY = cornerRadius + dH, dCX = dAY * Math.tan(ANTI_ANGLE_RAD), dKX = cornerRadius * Math.sin(ANGLE_RAD), dAX = dCX + dKX, dXC2 = cornerRadius * Math.tan(ANTI_ANGLE_RAD), dAX2 = cornerRadius / Math.sin(ANGLE_RAD), dDK2 = cornerRadius * Math.tan(ANTI_ANGLE_RAD), dYK2 = dDK2 * Math.sin(ANGLE_RAD), dYC2 = cornerRadius - dYK2, dXK2 = dDK2 * Math.cos(ANGLE_RAD), dXCH2 = dAX2 - dXC2
И вот у нас 8 точек будущей трапеции:
const pathPoints = [ // 0 [ this.point[0] + cornerRadius, this.point[1], ], // 1 [ this.point[0] + width - dAX, this.point[1], ], // 2 [ this.point[0] + width - dCX, this.point[1] - dAY, ], // 3 [ this.point[0] + width - dWidth + (dXC2 - dXK2), this.point[1] - height + dYC2, ], // 4 [ this.point[0] + width - dWidth - dXCH2, this.point[1] - height, ], // 5 [ this.point[0] + cornerRadius, this.point[1] - height, ], // 6 [ this.point[0], this.point[1] - height + cornerRadius, ], // 7 [ this.point[0], this.point[1] - cornerRadius, ], ];
Для расчёта координат управляющих точек (усиков) уже пришлось прибегать к константам. В процессе расчета выяснилось, что там всего 2 коэффициента: для острого и тупого угла. После проверки на разных радиусах и углах я убедился, что точность высокая и задача решена. Я не буду тут показывать этот код, потому что это не имеет смысла.
Получился инструмент, готовый к изменениям шаблонов: и по углу наклона, и по радиусу скругления. В диапазоне от 0 до 40 градусов от вертикали получается отличный результат — этого хватает с запасом на возможные изменения. При 50 градусах появляется артефакт в остром угле (зелёным отмечен целевой контур), а при 60 — уже совсем вытягивается верх и «тупится» низ:
Так как угол наклона вынесен в параметры, можно экспериментировать. И оказалось, что можно наклонять сторону знака и в другую сторону. Проверка тоже прошла удачно — скрипт отлично наклонил знак и в другую сторону. Искажения заметны стали так же на 50º от вертикали:
Размеры трапеций разные, потому что её размер зависит от верха знака — там размещается стрелка направления.
В результате «изобретения этого велосипеда» получились красивые картинки и удобный инструмент для примерки угла наклона.