Войти
Исаев ВикторСтатьи

Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.

Автор:

Добрый день. Недавно я столкнулся с проблемой генерации шестиугольной сетки из центра. Есть методы генерации строками. Они годны для чего-угодно. А такого метода я не нашел. Может плохо искал, кто знает. На форуме мне предложили три кривых решения:
1.  Костыли (вариант, который самый плохой).
2.  Генерация построчно и выкидывание ненужного. В принципе самое правильное решение, но увы, мне нужно чтобы именно из центра. Потом удобно добавлять нужные ячейки будет.
3.  Косые координаты. Это сложная мегажесть, на которую можно убить тучу времени. Я ее не смог осилить.
А теперь, перейдем к нашему алгоритму.

Суть на пальцах


Нам нужно получить ячеистую структуру аля эта.
1 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.
Первым шагом будет генерация первого, центрального гексагона.
2 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.
Если наш зритель достаточно прозорлив, то он заметит, что прилегающие по сторонам ячейки образуют оси матрицы.
3 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.
С первым рядом проблем не возникнет, если знать радиус и угол, то все шестиугольники лягут как надо. Проблемы идут со вторым рядом. Некоторые ячейки не будут лежать где надо. А причина в следующем. В нашей структуре, есть периодичность. Но она не круговая, а гексагональная. Просто в первом ряду они сходятся.
4 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.
На рисунке видно, что центры шестиугольников лежать и на окружности, и на матричном шестиугольнике. Однако на втором ряду проблема видна четко.
5 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.
Видно, что на лишь осевые шестиугольники (зеленые) лежат на окружности. Центры остальных смещены к центру и лежат на матричном шестиугольнике. Поэтому, через радиальную симметрию такую сетку не задать.
Отсюда следует следующее решение.
Строим сначала лишь осевые шестиугольники.
Затем вычисляем векторы. На рисунке указано направление векторов. Оно может быть обратным.
6 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.
Но нам нужен не этот вектор. Точнее не он сам, а его часть.
7 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.
Нам нужен синий вектор. Это смещение, которое прибавляется к осевому шестиугольнику для получения точных координат. Желтый вектор делится на число частей, равное количество шестиугольников между осевыми шестиугольниками + 1 (или номер слоя).
После этого, можно генерировать сколь угодно большие матрицы из центра.

Алгоритм-часть


А теперь приведу код, этого безобразия. Я программировал на Xors3D, но думаю, что кому надо, тот поймет как эта штука работает (тем более, код простой, а суть объяснил выше). Нам нужна всего одна функция – функция создания ячейки.
Вот ее код.
Function CreateCell(X#,Z#,Order%)
  Limit% = 6
  If Order = 0 Then Limit = 1
  For i = 0 To Limit-1    
    Angle# = 360/Limit*i
    Cell.Cell = New Cell
    Cell\X = X + CellRadius*Sin(Angle)*Order 
    Cell\Z = Z + CellRadius*Cos(Angle)*Order  
    Cell\Sprite = xCopyEntity(Cell_Image)
    xSpriteViewMode Cell\Sprite,2
    xRotateEntity Cell\Sprite,90,0,0
    xPositionEntity Cell\Sprite,Cell\X,0,Cell\Z
    ;Vector calculating
    If Order > 0 Then 
      Vector(i,0) =((CellRadius*Sin(Angle+60)*Order-CellRadius*Sin(Angle)*Order))/(Order)
      Vector(i,1) =((CellRadius*Cos(Angle+60)*Order-CellRadius*Cos(Angle)*Order))/(Order)
    End If
  Next
  
  For i = 0 To Limit-1 
    Angle# = 360/Limit*i
    For j = 0 To Order-2
      Cell.Cell = New Cell
      Cell\X = X + CellRadius*Sin(Angle)*Order + Vector(i,0)*(j+1)
      Cell\Z = Z + CellRadius*Cos(Angle)*Order + Vector(i,1)*(j+1)
      Cell\Sprite = xCopyEntity(Cell_Image)
      xSpriteViewMode Cell\Sprite,2
      xRotateEntity Cell\Sprite,90,0,0
      xPositionEntity Cell\Sprite,Cell\X,0,Cell\Z
    Next
  Next
End Function

Разберем его.

X#, Z# - координаты центра
Order% - порядок создаваемого слоя
CellRadius – расстояние между шестиугольниками
Limit% = 6 – количество осевых шестиугольников.
If Order = 0 Then Limit = 1 – если слой первый, то шестиугольник 1.
For i = 0 To Limit-1  - создаем осевые шестиугольники 
    Angle# = 360/Limit*i – вычисляем угол для каждого осевого шестиугольника
    Cell.Cell = New Cell – создаем шестиугольник
    Cell\X = X + CellRadius*Sin(Angle)*Order
    Cell\Z = Z + CellRadius*Cos(Angle)*Order  - задаем его координаты
    Cell\Sprite = xCopyEntity(Cell_Image) – это спрайт, не важно для кода
    xSpriteViewMode Cell\Sprite,2
    xRotateEntity Cell\Sprite,90,0,0
    xPositionEntity Cell\Sprite,Cell\X,0,Cell\Z – задаем позицию
   
    ;Vector calculating
    If Order > 0 Then – вычисляем вектора, если ряд не нулевой (где центральный гексагон)
      Vector(i,0) =((CellRadius*Sin(Angle+60)*Order-CellRadius*Sin(Angle)*Order))/(Order) – 0 = X, первая координата вектора
      Vector(i,1) =((CellRadius*Cos(Angle+60)*Order-CellRadius*Cos(Angle)*Order))/(Order) – 1 = Z, вторая координата вектора
    End If
  Next

For i = 0 To Limit-1 – строим остальные шестиугольники
    Angle# = 360/Limit*i – угол осевого шестиугольника
    For j = 0 To Order-2 – строим шестиугольники в каждой стороне.
      Cell.Cell = New Cell – новый шестиугольник
      Cell\X = X + CellRadius*Sin(Angle)*Order + Vector(i,0)*(j+1)
      Cell\Z = Z + CellRadius*Cos(Angle)*Order + Vector(i,1)*(j+1) –добавляем к координатам смещение (вектор) умноженный на порядок добавляемого шестиугольника (в 3 и последующих рядах их больше 1)
      Cell\Sprite = xCopyEntity(Cell_Image)
      xSpriteViewMode Cell\Sprite,2
      xRotateEntity Cell\Sprite,90,0,0
      xPositionEntity Cell\Sprite,Cell\X,0,Cell\Z
    Next
  Next

Что имеем на выходе:
8 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.

Апгрейд 1.0 - Поворот на любой угол матрицы


Могут возникнуть ситуации, когда нашу гексагональную сетку надо куда-то примкнуть под нужным углом. Я подумал над этим, и модернизовал функцию - теперь можно поворачивать всю матрицу на произвольный угол!
Итак, код:
Function CreateCell(X#,Z#,Order%,AddAngle%)
  Limit% = 6
  If Order = 0 Then Limit = 1
  For i = 0 To Limit-1 
    Angle# = 360/Limit*i+AddAngle
    Cell.Cell = New Cell
    Cell\X = X + CellRadius*Sin(Angle)*Order 
    Cell\Z = Z + CellRadius*Cos(Angle)*Order  
    Cell\Sprite = xCopyEntity(Cell_Image)
    xPositionEntity Cell\Sprite,Cell\X,0,Cell\Z
    Cell\Cyl = xCreateCylinder(16,1,Cell\Sprite)
    Cell\KPD = Rnd(0.01,1)
    xRotateEntity Cell\Sprite,90,-AddAngle,0
    ;Vector calculating
    If Order > 0 Then 
      Vector(i,0) =((CellRadius*Sin(Angle+60)*Order-CellRadius*Sin(Angle)*Order))/(Order)
      Vector(i,1) =((CellRadius*Cos(Angle+60)*Order-CellRadius*Cos(Angle)*Order))/(Order)
    End If
  Next
  
  For i = 0 To Limit-1 
    Angle# = 360/Limit*i+AddAngle
    For j = 0 To Order-2
      Cell.Cell = New Cell
      Cell\X = X + CellRadius*Sin(Angle)*Order + Vector(i,0)*(j+1)
      Cell\Z = Z + CellRadius*Cos(Angle)*Order + Vector(i,1)*(j+1)
      Cell\Sprite = xCopyEntity(Cell_Image)
      Cell\Cyl = xCreateCylinder(16,1,Cell\Sprite)
      Cell\KPD = Rnd(0.01,1)
      xPositionEntity Cell\Sprite,Cell\X,0,Cell\Z
      xRotateEntity Cell\Sprite,90,-AddAngle,0
    Next
  Next
End Function

Важные отличия:
Function CreateCell(X#,Z#,Order%,AddAngle%) - появился новый аргумент, это и есть произвольный угол - AddAngle.
Angle# = 360/Limit*i+AddAngle - добавляем смещение для расчета углов и векторов.
xRotateEntity Cell\Sprite,90,-AddAngle,0 - поворот спрайта вокруг вертикальной оси в противоположную сторону.

Что имеем на выходе:
17 градусов.
9 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.
30 градусов.
10 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.
10 градусов.
11 | Простая генерация гексагональной (шестиугольной) сетки из центра + поворот матрицы на любой угол. Апгрейд 2019 года.

Спасибо за внимание. Надеюсь, эта статья будет полезной.

Страницы: 1 2 Следующая »

#программирование, #Xors3D, #алгоритмы, #гексагоны, #шестиугольники

10 января 2014 (Обновление: 26 мар 2019)

Комментарии [28]