Безшовне перетворення від квадрата до шестикутника


23

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

Однак я лінивий літ. Автоматизувати процес слід невеликим сценарієм.

Однак я лінивий літ. Тож я передаю це на аутсорсинг для вас і маскую його як кодове завдання для гольфу 1 .


Вхідні дані

Вхід - це квадратне зображення у будь-якому загальному форматі зображення, здатне до 24-бітового RGB кольору. Ви також можете взяти ім'я файлу як вхідне замість самих даних зображення.

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

Вихід

Вихід - це вхідна плитка, але перетворена на шестикутник (саме зображення буде квадратним, з прозорими ділянками). Ви можете зберегти його у файл або відобразити на екрані.

Знову ж, будь-який загальний формат зображення буде робити. Якщо формат, який ви використовуєте, підтримує прозорість, фонові області повинні бути прозорими. Якщо це не так, ви можете використовувати колір # FF00FF (той жахливий фуксія) як резервний.

Метод

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

вхід

  • Масштаб: масштабуйте зображення до співвідношення 3: 2. Оскільки наші зображення будуть квадратними, це означає, що ви просто масштабуєте їх до 75% ширини та 50% висоти. Наш приклад 200x200, тож ми закінчуємо цим зображенням розміром 150x100:

розчавлений

  • Плитка: розмістіть копії масштабованого зображення в сітці 2x2:

сітка

  • Обрізка: візьміть шестикутник відповідного розміру з будь-якої точки цієї 2х2 сітки. Тепер для зручності плитки цей шестикутник не зовсім регулярний. Після обрізання квадрата оригінального розміру (тут 200х200) ви обрізаєте кути. Лінії обрізання повинні проходити (приблизно) від центру кожного лівого / правого боку до однієї чверті від краю вгорі / внизу:

шестигранний

І це ваш вихід!

Ось приклад того, як це може виглядати, коли викладено плитку (зменшено тут):

кахельна плитка

Це код гольфу, тому найкоротший код у байтах виграє. Застосовуються стандартні лазівки тощо тощо.


1 Ви можете вірити цьому чи ні.
2 Спосіб один із цього корисного сайту.


13
На це питання випрошується відповідь Гексагонії.
Санчіз

22
@sanchises Удачі.
Мартін Ендер

17
Саме тут друга частина Хекс Агонії стає важливою.
flawr

2
@ mbomb007 Можливо, хоча зелений № 00FF00, який іноді використовується, не є настільки поганим. Тим не менш, я відчуваю, що вони використовують фуксію частіше, тому що ніхто з
належних

3
# 3 - Я терпляче чекаю на це, щоб побачити створені круті алгоритми ... потім обережно і з любов'ю "запозичую" їх для моїх використання ;-)
scunliffe

Відповіді:


10

Матлаб, 223 215 209 184 163 байт

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

​l=imread(input(''));
u=size(l,1);
L=imresize(l,u*[2 3]/4);
L=[L,L;L,L];L=L(1:u,1:u,:);
[x,y]=meshgrid(1:u);
r=u/2;x=x*2;
set(imshow(L),'Al',y<x+r&y+x>r&y+x<5*r&y>x-3*r)

введіть тут опис зображення

PS: Це перетворилося в codegolf NIM гри з @ подачами MartinBüttner: ви чергується повинні зробити код коротше (забезпечуючи при цьому такий же функціональності) - той , який може зробити останню «вкорочення» перемогу =)


Ви можете зберегти 5 байт, змінивши розрахунок масштабу розміру на [k.*[2 3]/4].
стакан

4
Чи не повинні фонові ділянки бути фуксіями, не чорними?
Blackhole

@Blackhole Спасибі за те, що ви дали мені знати, я це виправив зараз, навіть врятував мені досить багато байтів =)
flawr

12

Mathematica, 231 211 209 208 201 188 173 байт

ImageCrop[ImageCollage@{#,#,#,#},e,Left]~SetAlphaChannel~ColorNegate@Graphics[RegularPolygon@6,ImageSize->1.05e,AspectRatio->1]&@ImageResize[#,{3,2}(e=ImageDimensions@#)/4]&

Це неназвана функція, яка бере об’єкт зображення та повертає об’єкт зображення:

введіть тут опис зображення

Я не думаю, що тут можна багато пояснити, але слід зазначити деякі деталі:

  • Зазвичай, щоб викласти зображення 2x2, ви б використовували ImageAssemble[{{#,#},{#,#}}], тобто ви ImageAssembleпередаєте матрицю 2x2 з копіями зображення. Однак ImageCollageє якась магічна функція, яка намагається організувати купу зображень максимально «добре» (що б це не означало ... ви навіть можете надати вагам та іншим зображенням ваги). У будь-якому випадку, якщо ви надаєте йому чотири зображення однакового розміру та з однаковими (або відсутніми) вагами, він також розмістить їх у сітці 2x2. Це дозволяє мені зберегти кілька байт для введення матриці, а також ім'я функції.
  • Шестикутник виводиться у вигляді одного многокутника через Graphics. Я використовую вбудований RegularPolygon@6, але застосовую пропорції, 1щоб розтягнути його за необхідності. На жаль, Graphicsпотрібна пара дорогих варіантів, щоб уникнути прокладки і подібного, а також він робить чорно-білим замість протилежного. Результат фіксується за допомогою, ColorNegateа потім додається до оригінальних каналів зображення за допомогою SetAlphaChannel.
  • Graphicsкладемо невелику кількість прокладки навколо шестикутника, але ми хочемо, щоб альфа-шестикутник покривав повний розмір вирізу. Однак SetAlphaChannelможна комбінувати зображення різних розмірів, центрируючи їх один на одного та обрізаючи до найменшого розміру. Це означає, що замість налаштування вручну PlotRangePadding->0ми можемо просто збільшити масштаб зображення шестикутника ImageSize->1.05e(і в будь-якому випадку нам потрібна опція `ImageSize ').

5

HTML5 + Javascript, 562 байти

<html><form><input type=text></form><canvas><script>l=document.body.children;l[0].addEventListener("submit",e=>{e.preventDefault();c=l[1].getContext("2d");i=new Image();i.onload=q=>{l[1].width=l[1].height=d=i.width;c.scale(0.75,0.5);c.drawImage(i,0,0);c.drawImage(i,d,0);c.drawImage(i,0,d);c.drawImage(i,d,d);c.globalCompositeOperation="destination-in";c.scale(1/0.75,2);c.beginPath();c.moveTo(d/4,0);c.lineTo(d/4+d/2,0);c.lineTo(d, d/2);c.lineTo(d/4+d/2, d);c.lineTo(d/4, d);c.lineTo(0, d/2);c.closePath();c.fill();};i.src=e.target.children[0].value;})</script>

Вводиться як URL-адреса зображення через текстове поле (URL, сподіваємось, вважається назвою файлу). Виводить дані на полотно.

Версія, яка працює в усіх браузерах (580 байт):

<html><form><input type=text></form><canvas><script>l=document.body.children;l[0].addEventListener("submit",function(e){e.preventDefault();c=l[1].getContext("2d");i=new Image();i.onload=function(){l[1].width=l[1].height=d=i.width;c.scale(0.75,0.5);c.drawImage(i,0,0);c.drawImage(i,d,0);c.drawImage(i,0,d);c.drawImage(i,d,d);c.globalCompositeOperation = "destination-in";c.scale(1/0.75,2);c.beginPath();c.moveTo(d/4, 0);c.lineTo(d/4+d/2,0);c.lineTo(d, d/2);c.lineTo(d/4+d/2, d);c.lineTo(d/4, d);c.lineTo(0, d/2);c.closePath();c.fill();};i.src=e.target.children[0].value;})</script>

Перевірте це за допомогою "блоків" зображення раніше за цією URL-адресою: http://i.stack.imgur.com/gQAZh.png


Хороша робота! Ви можете зберегти досить багато байтів, додавши id=Aдо <form>і id=Bдо <canvas>, потім замінивши l[0]на Aі l[1]з B, і видаливши l=document.body.children;. (Працює в Firefox 41; не впевнений, які інші веб-переглядачі підтримують це.) Крім того, я вважаю, що поруч із правими фігурними дужками є пара зайвих крапок та кілька додаткових пробілів.
ETHproductions

Більше порад. Я вважаю, що ви можете додати id=Cдо <input>, а потім замінити e.target.children[0]на C. 0.75дорівнює 3/4, 1/0.75дорівнює 4/3, d/4+d/2дорівнює d*3/4, а провідні нулі на інших десяткових знаках не потрібні. Я також вважаю , ви могли б замінити перший c.drawImageз c[p="drawImage"], то кожний наступний один з c[p]; ви могли б зробити те ж саме і з c.lineTo.
ETHproductions

4

Python 2 + PIL, 320

Читає ім'я файлу зображень із stdin.

from PIL import ImageDraw as D,Image as I
i=I.open(raw_input())
C=A,B=i.size
i,j=i.resize((int(.75*A),B/2)),I.new('RGBA',C)
W,H=i.size
for a,b in[(0,0),(0,H),(W,0),(W,H)]:j.paste(i,(a,b,a+W,b+H))
p,d=[(0,0),(A/4,0),(0,B/2),(A/4,B),(0,B)],lambda p:D.Draw(j).polygon(p,fill=(0,)*4)
d(p)
d([(A-x,B-y)for x,y in p])
j.show()

Правда, вибачте з цього приводу, не було PILзручно спробувати, і я не задумався над цим. Я все ще
тримаюсь у своєму новому рядку,

2

PHP, 293 байти

Я додав нові рядки для читабельності:

function($t){$s=imagesx($t);imagesettile($i=imagecreatetruecolor($s,$s),$t=imagescale
($t,$a=$s*3/4,$b=$s/2));imagefill($i,0,0,IMG_COLOR_TILED);$z=imagefilledpolygon;$z($i,
[0,0,$s/4,0,0,$b,$s/4,$s,0,$s],5,$f=imagecolorallocate($i,255,0,255));$z($i,[$s,0,$a,
0,$s,$b,$a,$s,$s,$s],5,$f);return$i;}

Ось незворушена версія:

function squareToHexagon($squareImage)
{
    $size = imagesx($squareImage);
    $tileImage = imagescale($squareImage, $size * 3/4, $size/2);

    $hexagonImage = imagecreatetruecolor($size, $size);
    imagesettile($hexagonImage, $tileImage);
    imagefill($hexagonImage, 0, 0, IMG_COLOR_TILED);

    $fuchsia = imagecolorallocate($hexagonImage, 255, 0, 255);
    imagefilledpolygon(
        $hexagonImage,
        [
            0,       0,
            $size/4, 0,
            0,       $size/2,
            $size/4, $size,
            0,       $size,
        ],
        5,
        $fuchsia
    );
    imagefilledpolygon(
        $hexagonImage,
        [
            $size,       0,
            $size * 3/4, 0,
            $size,       $size/2,
            $size * 3/4, $size,
            $size,       $size,
        ],
        5,
        $fuchsia
    );

    return $hexagonImage;
}

header('Content-type: image/gif');
$squareImage = imagecreatefrompng('squareImage.png');
$hexagonImage = squareToHexagon($squareImage);
imagegif($hexagonImage);
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.