Как сделать внешнюю обводку у полигона

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

a2e857e2f2327e49c35a96e7cb62f709.png

Теория

Полигон — замкнутая фигура, состоящая из вершин и ребер. Для прорисовки обводки полигона требуется найти точки, которые равноудалены от вершин полигона и соединить их линиями. В нахождении точек нам поможет линейная алгебра. Для демонстрации алгоритма по поиску точек обводки у полигона представим произвольный полигон:

2aac03ef923a725041790718f35c47fb.png

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

74fd515f374578c21e270be33a752074.png

Получившиеся нормализованные вектора отстояния могут иметь неправильные направления. Быть направленными внутрь контура или из вне:

a739edfed8eb140b90a02e5a29850005.png

При сложении векторов с вершинами полигона, получившиеся точки обводки могут быть внутри контура или снаружи. И в следствии получается неправильная обводка. Для того чтобы этого избежать для начала нужно определить, как точки полигона обходят контур по часовой стрелки или против часовой стрелки. Это даст возможность сделать обводку либо внутри полигона, либо снаружи. Чтобы определять направление обхода контура у полигона находим его крайнюю левую вершину по координате x. И представляем два ребра вершины векторами. Вектора направлены по следованию точек на контуре. Над векторами производим векторное умножение. Знак получившегося результата умножения покажет, как задается контур. Если число положительное, то против часовой стрелки, если отрицательное — по часовой стрелке:

3256a6fe9f4b245e0e6249f6e6984d0f.png

Теперь осталось определить направление у нормализованных векторов отстояния. Для этого у каждой вершины надо взять два ребра направленные по направлению обхода контура и векторно их умножить. У получившегося результата узнаем арифметический знак. Арифметический знак покажет менять направление у вектора отстояния или оставить прежним. Пусть у нас точки полигона задают контур против часовой стрелки. Тогда если знак у результата векторного умножения положительный, то направление у вектора отстояния меняется, если отрицательный, то направление остается прежним. Для изменения направления вектора достаточно его координаты умножить на -1. Если точки полигона задают контур по часовой стрелки, то алгоритм определения направления вектора отстояния меняется. У положительного результата умножения, вектор не меняет направления, а у отрицательного меняет.

0f8916d3e194e38477aead916da0c570.png

Получившиеся направленные вектора надо сложить с вершинами полигона, чтобы получить точки обводки:

023320038601dce010db7c57c7c1fb57.png

Практика

Работоспособность алгоритма приведу кодом на js. Не буду голословным и приведу код с комментариями:



  
    
    
  
  
    
  











  
  
    
  
    
  

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

© Habrahabr.ru