Бесшовное преобразование из квадрата в шестиугольник


23

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

Тем не менее , я стал ленивым в старости. Должно быть легко автоматизировать процесс с помощью небольшого сценария.

Тем не менее , я стал ленивым в старости. Так что я передаю его вам и маскирую под кодовый гольф 1 .


вход

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

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

Выход

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

Опять же, подойдет любой обычный формат изображения. Если используемый вами формат поддерживает прозрачность, фоновые области должны быть прозрачными. Если это не так, вы можете использовать цвет # FF00FF (этот ужасный фуксия) в качестве замены.

метод

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

вход

  • Масштаб: масштабировать изображение до соотношения 3: 2. Поскольку наши изображения будут квадратными, это означает, что вы просто масштабируете их до ширины 75% и высоты 50%. Наш пример ввода - 200x200, поэтому мы получаем изображение 150x100:

раздавленный

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

сетка

  • Урожай: возьмите шестиугольник подходящего размера из любой точки сетки 2x2. Теперь, для простоты мозаики, этот шестиугольник не совсем обычный. После обрезки квадрата оригинального размера (здесь 200x200) вы затем обрезаете углы. Линии обрезки должны проходить от (примерно) центра каждой левой / правой стороны до одной четверти от края сверху / снизу:

наговор

И это ваш выход!

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

черепичные

Это код гольф, поэтому выигрывает самый короткий код в байтах. Применяются стандартные лазейки и тд и тп.


1 Не стесняйтесь верить этому или нет.
2 Способ один из этого полезного сайта.


13
Этот вопрос попрошайничество для ответа Hexagony.
Sanchises

22
@sanchises Удачи.
Мартин Эндер

17
Вот где вторая часть Hex Agony становится важной.
flawr

2
@ mbomb007 Вероятно, хотя зеленый # 00FF00, который иногда используется вместо этого, не так уж и плох. Тем не менее, я чувствую, что они используют фуксию чаще, потому что никто в здравом уме не хотел бы иметь такой точный цвет в своих спрайтах, поэтому он довольно универсален: P
Geobits

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

Ответы:


10

Matlab, 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какая-то магическая функция, которая пытается упорядочить кучу картинок настолько «хорошо», насколько это возможно (что бы это ни значило ... вы можете даже дать весы и прочее отдельным изображениям). В любом случае, если вы дадите ему четыре изображения одинакового размера и с одинаковыми (или нет) весами, он также разместит их в сетке 2х2. Это позволяет мне сохранить несколько байтов для вложения матрицы, а также имя функции.
  • Шестиугольник отображается как один многоугольник через 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

Читает имя файла изображения из стандартного ввода.

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.