Правильний шестикутник побудова – як намалювати шестикутник. Як побудувати правильний шестикутник Як малювати шестикутник олівцем

Чи є поблизу Вас олівець? Погляньте на його перетин - воно є правильним шестикутником або, як його ще називають, гексагоном. Таку форму має також переріз гайки, поле гексагональних шахів, деяких складних молекул вуглецю (наприклад, графіт), сніжинка, бджолині стільники та інші об'єкти. Чи не здається дивним таке часте використання природою для своїх творінь конструкцій саме цієї форми? Давайте розглянемо докладніше.

Правильний шестикутник є багатокутником з шістьма однаковими сторонами і рівними кутами. Зі шкільного курсу нам відомо, що він має такі властивості:

  • Довжина його сторін відповідає радіусу описаного кола. З усіх це властивість має лише правильний шестикутник.
  • Кути рівні між собою, і величина кожного становить 120 °.
  • Периметр гексагону можна знайти за формулою Р=6*R, якщо відомий радіус описаного навколо нього кола, або Р=4*√(3)*r, якщо коло вписано. R і r - радіуси описаного та вписаного кола.
  • Площа, яку займає правильний шестикутник, визначається так: S=(3*√(3)*R 2)/2. Якщо радіус невідомий, замість нього підставляємо довжину однієї зі сторін - як відомо, вона відповідає довжині радіусу описаного кола.

У правильного шестикутника є одна цікава особливість, завдяки якій він отримав у природі таке широке поширення, - він здатний заповнити будь-яку поверхню площини без накладень та прогалин. Існує навіть так звана лема Пала, згідно з якою правильний гексагон, сторона якого дорівнює 1/√(3), є універсальною покришкою, тобто може покрити будь-яку множину з діаметром в одну одиницю.

Тепер розглянемо побудову правильного шестикутника. Є кілька способів, найпростіший з яких передбачає використання циркуля, олівця та лінійки. Спочатку малюємо циркулем довільне коло, потім у довільному місці на цьому колі робимо крапку. Не змінюючи розчину циркуля, ставимо вістря в цю точку, відзначаємо на колі наступне насічення, продовжуємо так доти, поки не отримаємо всі 6 точок. Тепер залишається лише з'єднати їх між собою прямими відрізками, і вийде шукана фігура.

Насправді бувають випадки, коли потрібно намалювати шестикутник великого розміру. Наприклад, на дворівневій стелі гіпсокартону, навколо місця кріплення центральної люстри, потрібно встановити на нижньому рівні шість невеликих світильників. Циркуль таких розмірів знайти буде дуже складно. Як вчинити у цьому випадку? Як взагалі намалювати велике коло? Дуже просто. Потрібно взяти міцну нитку потрібної довжини та обв'язати один із її кінців навпроти олівця. Тепер залишилося лише знайти помічника, який притиснув би до стелі в потрібній точці другий кінець нитки. Звісно, ​​у разі можливі незначні похибки, але навряд вони взагалі будуть помітні сторонній людині.

Вміст:

Звичайний шестикутник, також званий ідеальним шестикутником, має шість рівних сторін та шість рівних кутів. Ви можете намалювати шестикутник за допомогою рулетки та транспортира, грубий шестикутник – за допомогою круглого предмета та лінійки або ще грубіший шестикутник - за допомогою тільки олівця та трохи інтуїції. Якщо ви хочете знати, як намалювати шестикутник у різний спосіб – просто читайте далі.

Кроки

1 Малюємо ідеальний шестикутник за допомогою циркуля

  1. 1 За допомогою циркулю малюємо коло.Вставте олівець у циркуль. Розширте циркуль на бажану ширину радіусу вашого кола. Радіус може бути від пари до десятка сантиметрів завширшки. Далі поставте циркуль із олівцем на папір і намалюйте коло.
    • Іноді легше спочатку намалювати півкола, а потім другу половину.
  2. 2 Пересуньте голку циркуля до краю кола.Поставте її на вершину кола. Не змінюйте кут та розташування циркуля.
  3. 3 Зробіть невелику позначку олівцем на краю кола.Зробіть її виразною, але не дуже темною, тому що пізніше ви її зітрете. Не забудьте зберігати кут, який ви встановили для циркуля.
  4. 4 Пересуньте голку циркуля на ту позначку, яку ви щойно зробили.Поставте голку прямо на позначку.
  5. 5 Зробіть ще одну позначку олівцем на краю кола.Таким чином, ви зробите другу позначку на певній дистанції від першої позначки. Продовжуйте рухатися в одному напрямку.
  6. 6 У такий же спосіб зробіть ще чотири позначки.Ви повинні повернутися назад на початкову позначку. Якщо ні, тоді швидше за все кут, під яким ви тримали циркуль і робили позначки, змінився. Можливо, це сталося через те, що ви стиснули його надто сильно або навпаки, трохи послабили.
  7. 7 З'єднайте позначки за допомогою лінійки.Шість місць, де ваші позначки перетинаються з краєм кола - це шість вершин шестикутника. За допомогою лінійки та олівця намалюйте прямі лінії, поєднуючи сусідні позначки.
  8. 8 Зітріть і коло, і позначки на краях кола, і інші позначки, які ви зробили. Після того, як ви стерли всі свої допоміжні лінії, ваш ідеальний шестикутник має бути готовим.

2 Малюємо грубий шестикутник за допомогою круглого предмета та лінійки

  1. 1 Обведіть обідок склянки олівцем.Таким чином, ви намалюєте коло. Дуже важливо малювати саме олівцем, тому що пізніше вам потрібно буде стерти всі допоміжні лінії. Ви також можете обвести перевернуту склянку, банку або ще щось, що має круглу основу.
  2. 2 Намалюйте горизонтальні лінії через центр кола.Можете скористатися лінійкою, книгою – чим завгодно з прямим краєм. Якщо у вас все ж таки є лінійка, ви можете відзначити середину, розрахувавши вертикальну довжину кола і розділивши його навпіл.
  3. 3 Намалюйте "Х" над половиною кола, поділяючи його на шість рівних секцій.Так як ви вже провели лінію через середину кола, Х має бути більше завширшки, ніж у висоту, щоб частини були рівні. Уявіть, що ділите піцу на шість частин.
  4. 4 Зробіть із кожної секції трикутники.Щоб зробити це, за допомогою лінійки намалюйте пряму лінію під вигнутою частиною кожної секції, з'єднуючи її з іншими двома лініями, утворюючи трикутник. Зробіть це з п'ятьма секціями, що залишилися. Думайте про це як про виготовлення скоринки навколо ваших шматків піци.
  5. 5 Зітріть всі допоміжні лінії.До допоміжних ліній належать ваше коло, три лінії, які розділили ваше коло на секції та інші позначки, які ви робили в процесі.

3 Малюємо грубий шестикутник за допомогою одного олівця

  1. 1 Намалюйте горизонтальну лінію.Щоб намалювати пряму лінію без лінійки, просто намалюйте початкову та кінцеву точку горизонтальної лінії. Потім помістіть олівець у початкову точку та простягайте лінію до кінця. Довжина цієї лінії може бути всього кілька сантиметрів.
  2. 2 Намалюйте дві діагональні лінії із кінців горизонтальної.Діагональна лінія зліва повинна бути спрямована назовні так само, як і діагональна лінія справа. Ви можете уявити, що ці лінії формують кут 120 градусів по відношенню до горизонтальної лінії.
  3. 3 Намалюйте ще дві горизонтальні лінії, що виходять із перших горизонтальних прямих, намальованих усередину.Таким чином, буде створено дзеркальне відображення перших двох діагональних ліній. Нижня ліва лінія має бути відображенням верхньої лівої лінії, а нижня права - відображенням верхньої правої лінії. У той час як верхні горизонтальні лінії повинні дивитися назовні, нижні повинні дивитися всередину основи.
  4. 4 Намалюйте ще одну горизонтальну лінію, з'єднуючи дві нижні діагональні лінії.Таким чином, ви намалюєте основу свого шестикутника. В ідеалі ця лінія має бути паралельною до верхньої горизонтальної лінії. Ось ви й завершили свій шестикутник.
  • Олівець та циркуль мають бути гострими, щоб мінімізувати помилки від надто широких позначок.
  • Якщо при використанні методу з циркулем ви з'єднали кожну позначку замість усіх шести, отримайте рівносторонній трикутник.

Попередження

  • Циркуль – досить гострий предмет, будьте з ним дуже обережні.

Принцип роботи

  • Кожен метод допоможе намалювати шестикутник, утворений шістьма рівносторонніми трикутниками з радіусом, що дорівнює довжині всіх сторін. Шість намальованих радіусів однакової довжини та всі лінії для створення шестикутника теж однієї довжини, оскільки ширина циркуля не змінювалася. Завдяки тому, що шість трикутників рівносторонні, кути між їхніми вершинами дорівнюють 60 градусів.

Що вам знадобиться

  • Папір
  • Олівець
  • Лінійка
  • Пара циркулів
  • Щось, що можна підкласти під папір, щоб голка циркуля не зісковзувала.
  • Ластик

Правильний описаний трикутник будують в такий спосіб(Малюнок 38). З центру заданого кола радіусу R 1 проводять коло радіусом R 2 = 2R 1 і поділяють її на три рівні частини. Точки поділу А, В, С є вершинами правильного трикутника, описаного біля кола радіусу R 1 .

Малюнок 38

Правильний описаний чотирикутник (квадрат)можна побудувати за допомогою циркуля та лінійки (рисунок 39). У заданому колі проводять два взаємно перпендикулярні діаметри. Прийнявши точки перетину діаметрів з колом за центри, радіусом кола R описують дуги до взаємного їхнього перетину в точках А, В, С, D . Крапки A , B , C , D і є вершинами квадрата, описаного біля цього кола.

Малюнок 39

Для побудови правильного описаного шестикутниканеобхідно спочатку побудувати вершини описаного квадрата вказаним вище способом (рисунок 40 а). Одночасно з визначенням вершин квадрата задане коло радіусу R ділять на шість рівних частин у точках 1, 2, 3, 4, 5, 6 та проводять вертикальні сторони квадрата. Провівши через точки поділу кола 2–5 і 3–6 прямі до перетину їх з вертикальними сторонами квадрата (рисунок 40 б) отримують вершини А, В, D, Е описаного правильного шестикутника

Малюнок 40

Інші вершини Cі Fвизначають за допомогою дуги кола радіусу OAяка проводиться до перетину її з продовженням вертикального діаметра заданого кола.
3 СПОРУЖЕННЯ

Навчимося зображати шестигранну призму у різних положеннях.

Вивчіть різні способи побудови правильного шестикутника, зробіть малюнки шестикутників, перевірте правильність їх побудови. На основі шестикутників побудуйте шестигранні призми.

Розгляньте шестигранну призму на рис. 3.52 та її ортогональні проекції на рис. 3.53. На підставі шестигранної призми (шестигранника) лежать правильні шестикутники, бічні грані — однакові прямокутники. Для того, щоб правильно зобразити шестигранник у перспективі, необхідно спочатку навчитися грамотно зображувати у перспективі його основу (рис. 3.54). У шестикутнику на рис. 3.55 вершини позначені цифрами від одного до шести. Якщо з'єднати точки 1 і 3, 4 і 6 вертикальними прямими, можна помітити, що ці прямі разом з точкою центру кола ділять діаметр 5 - 2 на чотири рівні відрізки (ці відрізки позначені дугами). Протилежні сторони шестикутника паралельні один одному і прямий, що проходить через його центр і з'єднує дві вершини (наприклад, сторони 6 - 1 і 4 - 3 паралельні прямій 5 - 2). Ці спостереження допоможуть вам побудувати шестикутник у перспективі, а також перевірити правильність цієї побудови. Побудувати правильний шестикутник за поданням можна двома способами: на основі описаного кола і на основі квадрата.

На основі описаного кола. Розгляньте рис. 3.56. Всі вершини правильного шестикутника належать описаному колу, радіус якого дорівнює стороні шестикутника.


Горизонтальний шестикутник. Зобразіть горизонтальний еліпс довільного розкриття, тобто описане коло у перспективі. Тепер потрібно знайти на ній шість точок, які є вершинами шестикутника. Проведіть будь-який діаметр даного кола через його центр (рис. 3.57). Крайні точки діаметра – 5 і 2, що лежать на еліпсі, є вершинами шестикутника. Для знаходження інших вершин необхідно розділити цей діаметр на чотири однакові відрізки. Діаметр вже розділений точкою центру кола на два радіуси, залишається розділити кожен радіус навпіл. На перспективному малюнку всі чотири відрізки поступово скорочуються при віддаленні від глядача (рис. 3.58). Тепер проведіть через середини радіусів — точки А і В — прямі, перпендикулярні до прямої 5 — 2. Знайти їх напрямок можна за допомогою дотичних до еліпса в точках 5 і 2 (рис. 3.59). Ці дотичні перпендикулярні діаметру 5 - 2, а прямі, проведені через точки А і В паралельно цим дотичним, будуть також перпендикулярні прямий 5 - 2. Позначте точки, отримані на перетині цих прямих з еліпсом, як 1, 3, 4, 6 ( 3.60). З'єднайте усі шість вершин прямими лініями (рис. 3.61).

Перевірте правильність вашої побудови у різний спосіб. Якщо побудова вірна, то лінії, що з'єднують протилежні вершини шестикутника, перетинаються в центрі кола (рис. 3.62), а протилежні сторони шестикутника паралельні відповідним діаметрам (рис. 3.63). Ще один спосіб перевірки показано на рис. 3.64.

Вертикальний шестикутник. У такому шестикутнику прямі, що з'єднують точки 7 і 3, б і 4, а також дотичні до описаного кола в точках 5 і 2 мають вертикальний напрямок і зберігають його на перспективному малюнку. Таким чином, провівши дві вертикальні дотичні до еліпса, знайдемо точки 5 та 2 (точки торкання). З'єднайте їх прямою лінією, а потім розділіть отриманий діаметр 5 - 2 на 4 рівні відрізки, враховуючи їх перспективні скорочення (рис. 3.65). Проведіть вертикальні прямі через точки А і Б, а на їхньому перетині з еліпсом знайдіть точки 1,3,6л4. Потім послідовно з'єднайте точки 1 - 6 прямими (рис. 3.66). Правильність побудови шестикутника перевірте аналогічно до попереднього прикладу.

Описаний спосіб побудови шестикутника дозволяє отримати цю фігуру на основі кола, зобразити яку у перспективі простіше, ніж квадрат заданих пропорцій. Тому даний спосіб побудови шестикутника є найбільш точним та універсальним. Спосіб побудови на основі квадрата дозволяє легко зобразити шестигранник у тому випадку, коли на малюнку вже є куб, іншими словами коли пропорції квадрата і напрямок його сторін визначені.

З урахуванням квадрата. Розгляньте рис. 3.67. Вписаний у квадрат шестикутник по горизонтальному напрямку 5 - 2 дорівнює стороні квадрата, а по вертикалі - менше її довжини.

Вертикальний шестикутник. Намалюйте вертикальний квадрат у перспективі. Проведіть через перетин діагоналі пряму, паралельну його горизонтальним сторонам. Розділіть отриманий відрізок 5 — 2 на чотири рівні частини та проведіть через точки А та В вертикальні прямі (рис. 3.68). Лінії, що обмежують шестикутник зверху та знизу, не збігаються зі сторонами квадрата. Зобразіть їх на деякій відстані (1114 а) від горизонтальних сторін квадрата та паралельно їм. З'єднавши знайдені таким чином точки 1 і 3 з точкою 2, а точки 6 і 4 - з точкою 5 отримаємо шестикутник (рис. 3.69).

Горизонтальний шестикутник будується у тій самій послідовності (рис. 3.70 та 3.71).

Цей спосіб побудови доречний лише шестикутників з достатнім розкриттям. Якщо розкриття шестикутника незначне, краще скористатися способом на основі описаного кола. Для перевірки шестикутника, побудованого через квадрат, можна використовувати відомі вам методи.

Крім того, існує ще один — описати навколо отриманого шестикутника коло (на вашому малюнку — еліпс). Усі вершини шестикутника мають належати цьому еліпсу.

Опанувавши навички зображення шестикутника, ви вільно перейдете до зображення шестигранної призми. Уважно розгляньте схему на рис. 3.72, а також схеми побудови шестигранних призм на основі описаного кола (рис. 3.73; 3.74 та 3.75) та на основі квадрата (рис. 3.76; 3.77 та 3.78). Зобразіть вертикальні та горизонтальні шестигранники різними способами. На малюнку вертикального шестигранника довгі сторони бічних граней будуть паралельними один одному вертикальними прямими, а шестикутник основи тим більше розкритий, що далі він знаходиться від лінії горизонту. На малюнку горизонтального шестигранника довгі сторони бічних граней сходитимуться в точці сходу на горизонті, а розкриття шестикутника основи буде тим більше, чим далі від глядача він знаходиться. Зображуючи шестигранник, слідкуйте також за тим, щоб паралельні грані обох основ сходилися у перспективі (рис. 3.79; 3.80).

Сітки шестикутників (гексагональні сітки) використовуються в деяких іграх, але вони не такі прості і поширені, як сітки прямокутників. Я колекціоную ресурси про сітки шестикутників вже майже 20 років, і написав цей посібник з найелегантніших підходів, що реалізуються в найпростішому коді. У статті часто використовуються керівництва Чарльза Фу (Charles Fu) та Кларка Вербрюгге (Clark Verbrugge). Я опишу різні способи створення сіток шестикутників, їхній взаємозв'язок, а також найзагальніші алгоритми. Багато частин цієї статті інтерактивні: вибір типу сітки змінює відповідні схеми, код та тексти. (Прим. пров.: це стосується лише оригіналу, раджу його вивчити. У перекладі вся інформація оригіналу збережена, але без інтерактивності.).

Приклади коду в статті написані псевдокодом, тому їх легше читати і розуміти, щоб написати свою реалізацію.

Геометрія

Шестикутники – це шестигранні багатокутники. У правильних шестикутників усі сторони (грані) мають однакову довжину. Ми будемо працювати лише з правильними шестикутниками. Зазвичай у сітках шестикутників використовуються горизонтальна (з гострим верхом) та вертикальна (з плоским верхом) орієнтації.


Шестикутники з плоским (ліворуч) та гострим (праворуч) верхом

У шестикутників по 6 граней. Кожна грань загальна для двох шестикутників. У шестикутників по 6 кутових точок. Кожна кутова точка загальна для трьох шестикутників. Докладніше про центри, грані та кутові точки можна прочитати в моїй статті про частини сіток (квадрати, шестикутники та трикутники).

Кути

У правильному шестикутнику внутрішні кути дорівнюють 120°. Є шість «клинів», кожен із яких є рівностороннім трикутником із внутрішніми кутами 60°. Кутова точка iзнаходиться на відстані (60 ° * i) + 30 °, на size одиниць від центру center. У коді:

Function hex_corner(center, size, i): var angle_deg = 60 * i + 30 var angle_rad = PI / 180 * angle_deg return Point(center.x + size * cos(angle_rad), center.y + size * sin(angle_rad) )
Для заповнення шестикутника потрібно отримати вершини багатокутника з hex_corner(…, 0) до hex_corner(…, 5) . Для малювання контуру шестикутника потрібно використовувати ці вершини, а потім намалювати лінію знову hex_corner(…, 0) .

Різниця між двома орієнтаціями в тому, що x і y змінюються місцями, що призводить до зміни кутів: кути шестикутників з плоским верхом дорівнюють 0°, 60°, 120°, 180°, 240°, 300°, а з гострим верхом - 30 °, 90 °, 150 °, 210 °, 270 °, 330 °.


Кути шестикутників з плоским та гострим верхом

Розмір та розташування

Тепер ми хочемо розмістити кілька шестикутників разом. У горизонтальній орієнтації висота шестикутника height=size*2. Вертикальна відстань між сусідніми шестикутниками vert=height*3/4.

Ширина шестикутника width = sqrt (3) / 2 * height. Горизонтальна відстань між сусідніми шестикутниками horiz=width.

У деяких іграх для шестикутників використовується піксель-арт, який не відповідає правильним шестикутникам. Формули кутів і розташувань, описані в цьому розділі, не збігатимуться з розмірами шестикутників. Решта статті, що описує алгоритми сіток шестикутників, застосовна навіть якщо шестикутники трохи розтягнуті або стиснуті.



Системи координат

Давайте приступимо до складання шестикутників у сітку. У разі сіток квадратів існує лише один очевидний спосіб збирання. Для шестикутників є безліч підходів. Я рекомендую використовувати як первинне уявлення кубічні координати. Осьові координати або координати зсувів слід використовувати для зберігання карток та відображення координат для користувача.

Координати зміщень

Найчастіший підхід - усунення кожного наступного стовпця чи рядка. Стовпці позначаються col або q. Рядки позначаються row або r. Можна зміщувати непарні або парні стовпці/рядки, тому горизонтальні і вертикальні шестикутники мають два варіанти.


Горизонтальне розташування «непар-r»


Горизонтальне розташування «чет-r»


Вертикальне розташування «непар-q»


Вертикальне розташування «чет-q»

Кубічні координати

Ще один спосіб розгляду сіток шестикутників - бачити в них триосновні осі, а не двіяк у сітках квадратів. Вони проявляється елегантна симетрія.

Візьмемо сітку кубів та виріжемодіагональну площину x + y + z = 0 . Це дивна думка, але допоможе нам спростити алгоритми сіток шестикутників. Зокрема, ми зможемо скористатися стандартними операціями з декартових координат: підсумовуванням та відніманням координат, множенням та розподілом на скалярну величину, а також відстанями.

Зауважте три основні осі на сітці кубів та їх співвідношення з шістьма діагональниминапрямками сітки шестикутників. Діагональні осі сітки відповідають основному напрямку сітки шестикутників.


Шестикутники


Куби

Оскільки ми вже маємо алгоритми для сіток квадратів і кубів, використання кубічних координат дозволяє нам адаптувати ці алгоритми під сітки шестикутників. я використовуватиму цю систему для більшості алгоритмів статті. Для використання алгоритмів з іншою системою координат я перетворю кубічні координати, виконаю алгоритм, а потім перетворюю їх назад.

Вивчіть, як кубічні координати працюють для сітки шестикутників. При виборі шестикутників виділяються кубічні координати, що відповідають трьом осям.

  1. Кожен напрямок сітки кубів відповідає лініїна сітці шестикутників. Спробуйте виділити шестикутник з z , що дорівнює 0, 1, 2, 3, щоб побачити зв'язок. Рядок відзначений синім. Спробуйте те ж саме для x (зелений) та y (бузковий).
  2. Кожен напрямок сітки шестикутника - це поєднання двох напрямків сітки кубів. Наприклад, "північ" сітки шестикутників лежить між +y і -z, тому кожен крок на "північ" збільшує y на 1 і зменшує z на 1.
Кубічні координати - розумний вибір системи координат сітки шестикутників. Умовою є x + y + z = 0 тому у алгоритмах воно повинно зберігатися. Умова гарантує, що для кожного шестикутника завжди буде канонічна координата.

Існує безліч різних систем координат для кубів та шестикутників. У деяких умов умова відрізняється від x + y + z = 0 . Я показав лише одну з багатьох систем. Можна також створити кубічні координати з x-y, y-z, z-x, у яких буде свій набір цікавих властивостей, але я не їх тут розглядатиму.

Але ви можете заперечити, що не хочете зберігати 3 числа координат, тому що не знаєте, як зберігати карту в такому вигляді.

Осьові координати

Осьова система координат, іноді звана «трапецеїдальна», будується на основі двох або трьох координат з кубічної системи координат. Оскільки ми маємо умову x + y + z = 0 , третя координата не потрібна. Осьові координати корисні для зберігання карт та відображення координат користувачеві. Як і у випадку з кубічними координатами, з ними можна використовувати стандартні операції підсумовування, віднімання, множення та поділу декартових координат.

Існує безліч кубічних систем координат та безліч осьових. У цьому посібнику я не розглядатиму всі поєднання. Я виберу дві змінні, q (стовпець) і r (рядок). У схемах цієї статті відповідає q , а r відповідає z , але така відповідність довільно, тому що можна обертати і повертати схеми, отримуючи різні відповідності.

Перевага цієї системи перед сітками зміщень у більшій зрозумілості алгоритмів. Недоліком системи є те, що зберігання прямокутної картки виконується трохи дивно; див. розділ збереження карт. Деякі алгоритми ще зрозуміліші в кубічних координатах, але оскільки ми маємо умову x + y + z = 0 , ми можемо обчислити третю координату, що розуміється, і використовувати її в цих алгоритмах. У своїх проектах я називаю осі q, r, s, тому умова виглядає як q + r + s = 0, і я, коли потрібно, можу обчислити s = -q - r.

Осі

Координати усунення - це перше, про що думає більшість людей, тому що вони збігаються зі стандартними декартовими координатами, які використовуються для сіток квадратів. На жаль, одна з двох осей повинна проходити «проти вовни», і це все ускладнює. Кубічна та осьова система йдуть «по шерсті» і у них простіші алгоритми, але зберігання карт трохи складніше. Існує ще одна система, звана "чергується" або "подвійний", але тут ми не будемо її розглядати; деякі вважають, що з нею простіше працювати, ніж з кубічною чи осьовою.


Координати зміщення, кубічні та осьові.

Ось- це напрямок, у якому відповідна координата збільшується. Перпендикуляр до осі - це лінія, де координата залишається постійної. На схемах сіток вище показано лінії перпендикулярів.

Перетворення координат

Ймовірно, що ви використовуватимете у своєму проекті осьові координати або координати зміщення, але багато алгоритмів простіше виражаються в кубічних координатах. Тому нам потрібно вміти перетворювати координати між системами.

Осьові координати близько пов'язані з кубічними, тому перетворення робиться просто:

перетворення кубічних в осьові координати q = x r = z # перетворення осьових в кубічні координати x = q z = ry = -x-z
У коді ці дві функції можуть бути записані таким чином:

Function cube_to_hex(h): # осьова var q = h.x var r = h.z return , z)
Координати усунення зовсім трохи складніше:

Сусідні шестикутники

Дано один шестикутник, з якими шістьма шестикутниками він знаходиться поряд? Як і очікується, найлегше дати відповідь у кубічних координатах, досить просто в осьових координатах, і трохи складніше в координатах зміщення. Також може знадобитися розрахувати шість діагональних шестикутників.

Кубічні координати

Переміщення на один простір у координатах шестикутників призводить до зміни однієї з трьох кубічних координат на +1 та інший на -1 (сума повинна залишатися 0). На +1 можуть змінюватися три можливі координати, а на -1 - дві. Це дає нам шість можливих змін. Кожен відповідає одному з напрямків шестикутника. Найпростіший та найшвидший спосіб - попередньо обчислити зміни та помістити їх у таблицю кубічних координат Cube(dx, dy, dz) під час компіляції:

Var directions = Cube(+1, -1, 0), Cube(+1, 0, -1), Cube(0, +1, -1), Cube(-1, +1, 0), Cube( -1, 0, +1), Cube(0, -1, +1)

Осьові координати

Як і раніше, ми використовуємо спочатку кубічну систему. Візьмемо таблицю Cube(dx, dy, dz) і перетворимо на таблицю Hex(dq, dr) :

Var directions = [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, 0), Hex(-1, +1), Hex(0, +1) ] функція hex_direction(direction): return directions функція hex_neighbor(hex, direction): var dir = hex_direction(direction) return Hex(hex.q + dir.q, hex.r + dir.r)

Координати усунення

В осьових координатах ми вносимо зміни залежно від того, де сітки знаходимося. Якщо ми в стовпці/рядку усунення, правило відрізняється від випадку стовпця/рядка без зміщення.

Як і раніше ми створюємо таблицю чисел, які потрібно додати до col and row . Однак цього разу у нас буде два масиви, один для непарних стовпців/рядків, а інший – для парних. Подивіться на (1,1) на малюнку карти сітки вище та зауважте, як змінюються col і row змінюються при переміщенні в кожному із шести напрямків. Тепер повторимо процес для (2,2). Таблиці та код будуть різними для кожного з чотирьох типів сіток усунення, наводимо відповідний код для кожного типу сітки.

Нечет-r
var directions = [ [ Hex(+1, 0), Hex(0, -1), Hex(-1, -1), Hex(-1, 0), Hex(-1, +1), Hex(0 , +1) ], [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, 0), Hex(0, +1), Hex( +1, +1) ] ] function offset_neighbor(hex, direction): var parity = hex.row & 1 var dir = directions return Hex(hex.col + dir.col, hex.row + dir.row)


Чіт-r
var directions = [ [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, 0), Hex(0, +1), Hex(+1) , +1) ], [ Hex(+1, 0), Hex(0, -1), Hex(-1, -1), Hex(-1, 0), Hex(-1, +1), Hex (0, +1) ] ] function offset_neighbor(hex, direction): var parity = hex.row & 1 var dir = directions return Hex(hex.col + dir.col, hex.row + dir.row)


Сітка для парної (EVEN) та непарної (ODD) рядків

Нечет-q
var directions = [ [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, -1), Hex(-1, 0), Hex(0 , +1) ], [ Hex(+1, +1), Hex(+1, 0), Hex(0, -1), Hex(-1, 0), Hex(-1, +1), Hex (0, +1) ] ] function offset_neighbor(hex, direction): var parity = hex.col & 1 var dir = directions return Hex(hex.col + dir.col, hex.row + dir.row)


Чет-q
var directions = [ [ Hex(+1, +1), Hex(+1, 0), Hex(0, -1), Hex(-1, 0), Hex(-1, +1), Hex(0 , +1) ], [ Hex(+1, 0), Hex(+1, -1), Hex(0, -1), Hex(-1, -1), Hex(-1, 0), Hex (0, +1) ] ] function offset_neighbor(hex, direction): var parity = hex.col & 1 var dir = directions return Hex(hex.col + dir.col, hex.row + dir.row)


Сітка для парного (EVEN) та непарного (ODD) стовпців

Діагоналі

Переміщення в «діагональному» просторі в координатах шестикутників змінює одну з трьох кубічних координат на ±2 та дві інші на ∓1 (сума повинна залишатися 0).

Var diagonals = Cube(+2, -1, -1), Cube(+1, +1, -2), Cube(-1, +2, -1), Cube(-2, +1, +1 ), Cube(-1, -1, +2), Cube(+1, -2, +1) ] Function cube_diagonal_neighbor(hex, direction): return
Як і раніше, ми можемо перетворити ці координати на осьові, відкинувши одну з трьох координат, або перетворити на координати зміщення, попередньо обчисливши результати.


відстані

Кубічні координати

У кубічній системі координат кожен шестикутник є кубом у тривимірному просторі. Сусідні шестикутники знаходяться у сітці шестикутників на відстані 1 один від одного, але на відстані 2 у сітці кубів. Це робить розрахунок відстаней простим. У сітці квадратів манхеттенські відстані рівні abs(dx) + abs(dy). У сітці кубів манхеттенські відстані рівні abs(dx) + abs(dy) + abs(dz). Відстань у сітці шестикутників дорівнює їх половині:

Function cube_distance(a, b): return (abs(a.x - b.x) + abs(a.y - b.y) + abs(a.z - b.z)) / 2
Еквівалентом цього запису буде вираз того, що одна з трьох координат має бути сумою двох інших, а потім отримання її як відстань. Можна вибрати форму поділу навпіл або форму максимального значення, наведену нижче, але вони дають однаковий результат:

Function cube_distance(a, b): return max(abs(a.x - b.x), abs(a.y - b.y), abs(a.z - b.z))
На малюнку максимальні значення виділені кольором. Зауважте також, що кожен колір позначає один із шести «діагональних» напрямків.

GIF


Осьові координати

В осьовій системі третя координата виражена неявно. Давайте перетворимо з осьової в кубічну систему для розрахунку відстані:

Function hex_distance(a, b): var ac = hex_to_cube(a) var bc = hex_to_cube(b) return cube_distance(ac, bc)
Якщо компілятор у вашому випадку вбудовує (inline) hex_to_cube і cube_distance , він згенерує такий код:

Function hex_distance(a, b): return (abs(a.q - b.q) + abs(a.q + a.r - b.q - b.r) + abs(a.r - b.r)) / 2
Існує безліч різних способів запису відстаней між шестикутниками в осьових координатах, але незалежно від способу запису відстань між шестикутниками в осьовій системі витягується з манхеттенської відстані в кубічній системі. Наприклад, описана «різниця різниць» виходить із запису a.q + a.r - b.q - b.r як a.q - b.q + a.r - b.r і з використанням форми максимального значення замість форми поділу навпіл cube_distance . Усі вони аналогічні, якщо побачити зв'язок із кубічними координатами.

Координати усунення

Як і у випадку з осьовими координатами, ми перетворимо координати зміщення на кубічні координати, а потім використовуємо відстань кубічної системи.

Function offset_distance(a, b): var ac = offset_to_cube(a) var bc = offset_to_cube(b) return cube_distance(ac, bc)
Ми будемо використовувати той самий шаблон для багатьох алгоритмів: перетворимо з шестикутників на куби, виконуємо кубічну версію алгоритму і перетворимо кубічні результати на координати шестикутників (осьові або координати зміщення).

Відображення ліній

Як намалювати лінію від одного шестикутника до іншого? Я використовую лінійну інтерполяцію для малювання ліній. Лінія поступово семплюється в N+1 точках і обчислюється, у яких шестикутниках перебувають ці семпли.

GIF


  1. Спочатку ми обчислюємо N, яка буде відстанню в шестикутниках між кінцевими точками.
  2. Потім рівномірно семплюємо N+1 точок між точками A і B. За допомогою лінійної інтерполяції визначаємо, що для значень i від 0 до N, включаючи їх, кожна точка буде A + (B - A) * 1.0/N * i . На малюнку ці контрольні точки показано синім. В результаті виходять координати з плаваючою комою.
  3. Перетворимо кожну контрольну точку (float) у шестикутники (int). Алгоритм називається cube_round (див. нижче).
З'єднуємо все разом для малювання лінії від A до B:

Function lerp(a, b, t): // для float return a + (b - a) * t function cube_lerp(a, b, t): // для шестикутників return Cube(lerp(a.x, b.x, t), lerp(a.y, b.y, t), lerp(a.z, b.z, t)) function cube_linedraw(a, b): var N = cube_distance(a, b) var results = for each 0 ≤ i ≤ N: results.append( cube_round(cube_lerp(a, b, 1.0/N * i))) return results
Примітки:

  • Трапляються випадки, коли cube_lerp повертає точку, що знаходиться точно на межі між двома шестикутниками. Потім cube_round зрушує їх у той чи інший бік. Лінії виглядають краще, якщо їх зсувають в одному напрямку. Це можна зробити, додавши «епсілон»-шестикутний Cube(1e-6, 1e-6, -2e-6) до однієї або обох кінцевих точок перед початком циклу. Це підштовхне лінію в одному напрямку, щоб вона не потрапляла на межі граней.
  • Алгоритм DDA-лінії у сітках квадратів прирівнює N до максимуму відстані по кожній осі. Ми робимо те саме в кубічному просторі, що аналогічно відстані в сітці шестикутників.
  • Функція cube_lerp повинна повертати куб з координатами у float. Якщо ви програмуєте мовою зі статичною типізацією, не зможете використовувати тип Cube . Замість нього можна визначити тип FloatCube або вбудувати (inline) функцію в код відтворення ліній, якщо ви не хочете визначати ще один тип.
  • Можна оптимізувати код, вбудувавши (inline) cube_lerp , а потім розрахувавши B.x-A.x, B.x-A.y та 1.0/N за межами циклу. Множення можна перетворити на повторюване підсумовування. В результаті вийде щось на кшталт алгоритму DDA-лінії.
  • Для відтворення ліній я використовую осьові або кубічні координати, але якщо ви хочете працювати з координатами зміщення, то вивчіть .
  • Існує багато варіантів відтворення ліній. Іноді потрібно «надпокриття». Мені надіслали код відображення ліній із надпокриттям у шестикутниках, але я поки що не вивчав його.

Діапазон переміщення

Діапазон координат

Для заданого центру шестикутника та діапазону N які шестикутники знаходяться в межах N кроків від нього?

Ми можемо виконати зворотну роботу з формули відстані між шестикутниками distance = max(abs(dx), abs(dy), abs(dz)) . Щоб знайти всі шестикутники в межах N, нам потрібні max(abs(dx), abs(dy), abs(dz)) ≤ N. Це означає, що потрібні всі три значення: abs(dx) ≤ N і abs(dy) ≤ N і abs(dz) ≤ N . Прибравши абсолютне значення, ми отримаємо -N ≤ dx ≤ N та -N ≤ dy ≤ N та -N ≤ dz ≤ N . У коді це буде вкладений цикл:

Var results = for each -N ≤ dx ≤ N: for each -N ≤ dy ≤ N: for each -N ≤ dz ≤ N: if dx + dy + dz = 0: results.append(cube_add(center, Cube(dx) , dy, dz)))
Цей цикл спрацює, але буде досить неефективним. З усіх значень dz, які ми перебираємо в циклі, тільки одне дійсно задовольняє умову кубів dx + dy + dz = 0. Натомість ми безпосередньо обчислимо значення dz , що задовольняє умові:

Var results = for each -N ≤ dx ≤ N: for each max(-N, -dx-N) ≤ dy ≤ min(N, -dx+N): var dz = -dx-dy results.append(cube_add( center, Cube(dx, dy, dz))))
Цей цикл проходить лише за потрібними координатами. На малюнку кожен діапазон є парою ліній. Кожна лінія – це нерівність. Ми беремо всі шестикутники, які задовольняють шість нерівностей.

GIF


Перетинаються діапазони

Якщо потрібно знайти шестикутники, що знаходяться в декількох діапазонах, перед генеруванням списку шестикутників можна перетнути діапазони.

Можна підійти до цієї проблеми з погляду алгебри чи геометрії. Алгебраїчно кожна область виражається як умови нерівностей у формі -N ≤ dx ≤ N , і нам потрібно знайти перетин цих умов. Геометрично кожна область є кубом у тривимірному просторі, і ми перетнемо два куби у тривимірному просторі для отримання прямокутного паралелепіпеда у тривимірному просторі. Потім ми проектуємо його назад на площину x + y + z = 0 щоб отримати шестикутники. Я вирішуватиму це завдання алгебраїчно.

По-перше, ми перепишемо умову -N ≤ dx ≤ N у більш загальній формі x min ≤ x ≤ x max і приймемо x min = center.x - N і x max = center.x + N . Зробимо те саме для y і z, в результаті отримавши загальний вигляд коду з попереднього розділу:

Var results = for each xmin ≤ x ≤ xmax: for each max(ymin, -x-zmax) ≤ y ≤ min(ymax, -x-zmin): var z = -x-y results.append(Cube(x, y, z))
Перетином двох діапазонів a ≤ x ≤ b і c ≤ x ≤ d є max(a, c) ≤ x ≤ min(b, d) . Оскільки область шестикутників виражена як діапазони над x, y, z, ми можемо окремо перетнути кожен з діапазонів x, y, z, а потім використовувати вкладений цикл для генерування списку шестикутників у перетині. Для однієї області шестикутників ми приймаємо x min = H.x-N and x max = H.x + N, аналогічно для y та z. Для перетину двох областей шестикутників ми приймаємо x min = max(H1.x - N, H2.x - N) та x max = min(H1.x + N, H2.x + N), аналогічно для y та z. Той самий шаблон працює для перетину трьох або більше областей.

GIF


Перешкоди

За наявності перешкод найпростіше виконати заливку з обмеженням на відстані (пошук завширшки). На малюнку нижче ми обмежуємось чотирма ходами. У коді fringes [k] - це масив всіх шестикутників, яких можна досягти за кроків. При кожному проході за основним циклом ми розширюємо рівень k-1 до k .

Function cube_reachable(start, movement): var visited = set() add start to visited var fringes = fringes.append() for each 1< k ≤ movement: fringes.append() for each cube in fringes: for each 0 ≤ dir < 6: var neighbor = cube_neighbor(cube, dir) if neighbor not in visited, not blocked: add neighbor to visited fringes[k].append(neighbor) return visited

Повороти

Для заданого вектора шестикутника (різницю між двома шестикутниками) може знадобитися повернути його, щоб він вказував на інший шестикутник. Це просто зробити, маючи кубічні координати, якщо дотримуватися повороту на 1/6 кола.

Поворот на 60° праворуч зсуває кожну координату на одну позицію праворуч:

[ x, y, z] до [-z, -x, -y]
Поворот на 60° вліво зсуває кожну координату на одну позицію вліво:

[ x, y, z] to [-y, -z, -x]



"Погравши" [в оригіналі статті] зі схемою, можна помітити, що кожен поворот на 60 ° змінюєзнаки та фізично «повертає» координати. Після повороту на 120° знаки знову стають тими самими. Поворот на 180 ° змінює знаки, але координати повертаються у своє початкове становище.

Ось повна послідовність повороту положення P навколо центрального положення C, що призводить до нового положення R:

  1. Перетворення положень P і C кубічні координати.
  2. Обчислення вектора віднімання центру: P_from_C = P - C = Cube (P.x - C.x, P.y - C.y, P.z - C.z) .
  3. Поворот вектора P_from_C як описано вище і надання підсумковому вектору позначення R_from_C .
  4. Перетворення вектора назад у положення додаванням центру: R = R_from_C + C = Cube (R_from_C.x + C.x, R_from_C.y + C.y, R_from_C.z + C.z) .
  5. Перетворення кубічного положення R назад у необхідну систему координат.
Тут кілька етапів перетворень, але кожен із них досить простий. Можна скоротити деякі з цих етапів, визначивши поворот безпосередньо в осьових координатах, але вектори шестикутників не працюють з координатами усунення, і я не знаю, як скоротити етапи для координат усунення. також обговорення інших способів обчислення повороту на stackexchange.

Кільця

Просте кільце

Щоб з'ясувати, чи належить заданий шестикутник до кільця заданого радіуса radius , потрібно обчислити відстань від цього шестикутника до центру, і дізнатися, чи воно radius . Для отримання списку всіх таких шестикутників потрібно зробити radius кроків від центру, а потім слідувати за векторами, що повертаються, по шляху вздовж кільця.

Function cube_ring(center, radius): var results = # цей код не працює для radius == 0; ви розумієте чому? var cube = cube_add(center, cube_scale(cube_direction(4), radius)) для кожного 0 ≤ i< 6: for each 0 ≤ j < radius: results.append(cube) cube = cube_neighbor(cube, i) return results
У цьому коді cube починається на кільці, показаному великою стрілкою від центру до кута схеми. Я вибрав спочатку кут 4, тому що він відповідає шляху, в якому рухаються мої числа напрямків. Вам може знадобитися інший початковий кут. На кожному етапі внутрішнього циклу cube рухається однією шестикутник по кільцю. Через 6 * radius кроків він завершує там, де почав.


Спіральні кільця

Проходячи по кільцях спіральним патерном, ми можемо заповнити внутрішні частини кілець:

Function cube_spiral(center, radius): var results = for each 1 ≤ k ≤ radius: results = results + cube_ring(center, k) return results



Площа великого шестикутника дорівнює сумі всіх кіл плюс 1 для центру. Для обчислення площі використовуйте цю формулу.

Обхід шестикутників у такий спосіб також можна використовувати для обчислення діапазону переміщення (див. вище).

Область видимості

Що видно із заданого положення із заданою відстанню, і не перекривається перешкодами? Найпростіший спосіб визначити це – намалювати лінію до кожного шестикутника в заданому діапазоні. Якщо лінія не зустрічається зі стінами, ви бачите шестикутник. Переміщуйте мишу по шестикутниках [на схемі в оригіналі статті], щоб побачити малювання ліній до цих шестикутників та стіни, з якими лінії зустрічаються.

Цей алгоритм може бути повільним на великих майданах, але його легко реалізувати, тому рекомендую почати з нього.

GIF



Існує багато різних визначень видимості. Чи хочете ви бачити центр другого шестикутника з початкового центру? Чи хочете ви бачити будь-яку частину іншого шестикутника з початкового центру? Може, будь-яку частину іншого шестикутника з будь-якої початкової точки? Перешкоди, що заважають погляду менше повного шестикутника? Область видимості - це більш хитре та різноманітне поняття, ніж здається здавалося б. Почнемо з найпростішого алгоритму, але чекайте, що він обов'язково правильно обчислить відповідь у вашому проекті. Бувають випадки, коли простий алгоритм дає нелогічні результати.

Я хочу надалі розширювати це керівництво. У мене є