Conversión perfecta de cuadrado a hexágono

23

Para muchos juegos jugados en una grilla, los hexágonos son Clearly Superior Choice ™. Desafortunadamente, muchos sitios de arte de juegos gratuitos solo tienen conjuntos de mosaicos sin costura para mapas cuadrados. En un proyecto anterior, usé algunos de estos y los convertí manualmente en hexágonos.

Sin embargo , me he vuelto perezoso en mi vejez. Debería ser fácil automatizar el proceso con un pequeño script.

Sin embargo , me he vuelto perezoso en mi vejez. Así que te lo estoy subcontratando y disfrazándolo como un desafío de código de golf 1 .


Entrada

La entrada es una imagen cuadrada en cualquier formato de imagen común capaz de color RGB de 24 bits. También puede tomar un nombre de archivo como entrada en lugar de los datos de la imagen en sí.

Puede suponer que la imagen es cuadrada y que la longitud lateral es un múltiplo de cuatro.

Salida

La salida es el mosaico de entrada, pero se convierte en un hexágono (la imagen en sí será cuadrada, con áreas transparentes). Puede guardarlo en un archivo o mostrarlo en la pantalla.

De nuevo, cualquier formato de imagen común servirá. Si el formato que está utilizando admite la transparencia, las áreas de fondo deben ser transparentes. Si no es así, puede usar el color # FF00FF (ese horrible fucsia) como sustituto.

Método

Entonces, ¿Cómo lo hacemos? El método que uso 2 aplasta la imagen un poco verticalmente, pero en general se ve bastante bien para la mayoría de las cosas. Haremos un ejemplo con esta imagen de entrada:

entrada

  • Escala: escala la imagen a una proporción de 3: 2. Dado que nuestras imágenes serán cuadradas, esto significa que simplemente las escala al 75% de ancho y 50% de altura. Nuestro ejemplo de entrada es 200x200, por lo que terminamos con esta imagen de 150x100:

aplastado

  • Mosaico: coloque copias de su imagen escalada en una cuadrícula de 2x2:

cuadrícula

  • Recortar: agarra un hexágono del tamaño adecuado desde cualquier lugar de esta cuadrícula de 2x2. Ahora, para facilitar el mosaico, este hexágono no es exactamente regular. Después de recortar un cuadrado del tamaño original (aquí 200x200), recorta las esquinas. Las líneas de recorte deben ir desde (aproximadamente) el centro de cada lado izquierdo / derecho hasta un cuarto desde el borde en la parte superior / inferior:

maleficio

¡Y esa es tu salida!

Aquí hay un ejemplo de cómo se vería cuando esté en mosaico (alejado aquí):

embaldosado

Este es el código de golf, por lo que gana el código más corto en bytes. Se aplican lagunas estándar, etc., etc.


1 Siéntase libre de creer esto o no.
2 Método uno de este útil sitio.

Geobits
fuente
13
Esta pregunta está pidiendo una respuesta de Hexagony.
Sanchises
22
@sanchises Buena suerte.
Martin Ender
17
Ahí es donde la segunda parte de Hex Agony se vuelve importante.
falla
2
@ mbomb007 Probablemente, aunque el verde # 00FF00 que a veces se usa no es tan malo. Aún así, siento que usan fucsia con más frecuencia porque nadie en su sano juicio querría ese color exacto en sus sprites, por lo que es bastante universal: P
Geobits
3
# 3 - Espero pacientemente para ver los algoritmos geniales generados ... luego los "presto" con cuidado y amor para mis usos ;-)
scunliffe

Respuestas:

10

Matlab, 223 215 209 184 163 bytes

El cambio de escala es bastante sencillo. Para recortar las esquinas, superpongo un sistema de coordenadas sobre los píxeles y hago una máscara a través de cuatro desigualdades lineales, que determinan el área del hexágono.

​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)

ingrese la descripción de la imagen aquí

PD: Esto se convirtió en un juego de codegolf nim con la presentación de @ MartinBüttner: alternativamente, debes hacer tu código más corto (al tiempo que proporcionas la misma funcionalidad), el que puede hacer que el último 'acortamiento' gane =)

falla
fuente
Puede guardar 5 bytes cambiando el cálculo de la escala de cambio de tamaño a [k.*[2 3]/4].
vaso de precipitados
44
¿No deberían las áreas de fondo ser fucsias, no negras?
Blackhole
@Blackhole Gracias por avisarme, lo arreglé ahora, incluso me ahorró un montón de bytes =)
error
12

Mathematica, 231 211 209 208 201 188 173 bytes

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

Esta es una función sin nombre que toma un objeto de imagen y devuelve un objeto de imagen:

ingrese la descripción de la imagen aquí

No creo que haya mucho que explicar aquí, pero algunos detalles que son notables:

  • Normalmente, para enlosar una imagen 2x2, usarías, es ImageAssemble[{{#,#},{#,#}}]decir, tu manoImageAssemble una matriz 2x2 con copias de la imagen. Sin embargo, hayImageCollage una especie de función mágica que trata de organizar un montón de imágenes lo más "posible" (lo que sea que eso signifique ... incluso puede darles peso a las imágenes individuales y esas cosas). De todos modos, si le das cuatro imágenes de igual tamaño y con igual (o sin) peso, también las organizará en una cuadrícula de 2x2. Eso me permite guardar algunos bytes para el anidamiento de la matriz, así como el nombre de la función.
  • El hexágono se representa como un único polígono a través de Graphics. Estoy usando el incorporado RegularPolygon@6, pero impongo una relación de aspecto de 1estirarlo según sea necesario. Desafortunadamente, Graphicsnecesita un par de opciones costosas para evitar el relleno y demás, y también se vuelve negro sobre blanco en lugar de lo contrario. El resultado se fija con ColorNegatey luego se adjunta a los canales originales de la imagen con SetAlphaChannel.
  • Graphicscoloca una pequeña cantidad de relleno alrededor del hexágono, pero queremos que el hexágono alfa cubra el tamaño completo del recorte. Sin embargo, SetAlphaChannelpuede combinar imágenes de diferentes tamaños al centrarlas una encima de la otra y recortarlas al tamaño más pequeño. Eso significa que, en lugar de configurarlo manualmente PlotRangePadding->0, simplemente podemos escalar un poco la imagen del hexágono ImageSize->1.05e(y necesitamos la opción `ImageSize de todos modos).
Martin Ender
fuente
5

HTML5 + Javascript, 562 bytes

<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>

Toma la entrada como una URL de imagen a través de un cuadro de texto (es de esperar que la URL cuente como un nombre de archivo). Emite los datos al lienzo.

Versión que funciona en todos los navegadores (580 bytes):

<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>

Pruébelo con la imagen de "bloques" de antes a través de esta URL: http://i.stack.imgur.com/gQAZh.png

adroitwhiz
fuente
¡Buen trabajo! Puede guardar bastantes bytes agregando id=Aa <form>y id=Bal <canvas>, luego reemplazando l[0]con Ay l[1]con By eliminando l=document.body.children;. (Funciona en Firefox 41; no estoy seguro de qué otros navegadores admiten esto). Además, creo que hay un par de puntos y coma innecesarios al lado de las llaves y algunos espacios adicionales.
ETHproductions
Más consejos: creo que podría agregar id=Cal <input>, y luego reemplazar e.target.children[0]con C. 0.75es igual a 3/4, 1/0.75es igual a 4/3, d/4+d/2es igual a d*3/4, y los ceros a la izquierda en los otros decimales no son necesarios. También creo que podría reemplazar el primero c.drawImagecon c[p="drawImage"], luego cada uno con c[p]; podrías hacer lo mismo con c.lineTo.
ETHproductions
4

Python 2 + PIL, 320

Lee el nombre del archivo de imagen de 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()
dieter
fuente
Es cierto, lo siento, no tuve PILque intentarlo y no lo pensé lo suficiente. Sin embargo, todavía mantengo mi declaración de nueva línea: P
FryAmTheEggman
2

PHP, 293 bytes

He agregado algunas líneas nuevas para facilitar la lectura:

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;}

Aquí está la versión sin golf:

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);
Agujero negro
fuente