Repository navigation
Open
Description
Thanks for this nice port to python, here there is a version of your code ported to numpy and using matplotlib for plotting
#!/usr/bin/python3
import numpy as np
from time import time
import matplotlib.pyplot as plt
PI = np.pi
# increase this number for larger tilings.
N_ITERATIONS = 4
IDENTITY = np.array([[1,0,0],
[0,1,0]], 'float32')
TILE_NAMES = ["Gamma", "Delta", "Theta", "Lambda", "Xi", "Pi", "Sigma", "Phi", "Psi"]
COLOR_MAP = {"Gamma": np.array((211, 95, 95),'f')/255.,
"Gamma1": np.array((200, 55, 55),'f')/255.,
"Gamma2": np.array((222, 135, 135),'f')/255.,
"Delta": np.array(( 0, 255, 255),'f')/255.,
"Theta": np.array((255, 170, 238),'f')/255.,
"Lambda": np.array((128, 128, 128),'f')/255.,
"Xi": np.array((145, 95, 211),'f')/255.,
"Pi": np.array(( 95, 95, 211),'f')/255.,
"Sigma": np.array(( 85, 212, 0),'f')/255.,
"Phi": np.array((255, 179, 128),'f')/255.,
"Psi": np.array((255, 221, 85),'f')/255.}
SPECTRE_POINTS = np.array([(0.0, 0.0),
(1.0, 0.0),
(1.5, -np.sqrt(3)/2),
(1.5+np.sqrt(3)/2, 0.5-np.sqrt(3)/2),
(1.5+np.sqrt(3)/2, 1.5-np.sqrt(3)/2),
(2.5+np.sqrt(3)/2, 1.5-np.sqrt(3)/2),
(3+np.sqrt(3)/2, 1.5),
(3.0, 2.0),
(3-np.sqrt(3)/2, 1.5),
(2.5-np.sqrt(3)/2, 1.5+np.sqrt(3)/2),
(1.5-np.sqrt(3)/2, 1.5+np.sqrt(3)/2),
(0.5-np.sqrt(3)/2, 1.5+np.sqrt(3)/2),
(-np.sqrt(3)/2, 1.5),
(0.0, 1.0)], 'float32')
SPECTRE_QUAD = SPECTRE_POINTS[[3,5,7,11],:]
def mul(A, B):
AB = A.copy()
AB[:,:2] = A[:,:2].dot(B[:,:2])
AB[:,2] += A[:,:2].dot(B[:,2])
return AB
class Tile:
def __init__(self, label):
self.label = label
self.quad = SPECTRE_QUAD.copy()
def draw(self, polygons, tile_transformation=IDENTITY.copy()):
vertices = SPECTRE_POINTS.dot(tile_transformation[:,:2].T) + tile_transformation[:,2]
polygons.append((vertices, COLOR_MAP[self.label]))
class MetaTile:
def __init__(self, tiles=[], transformations=[], quad=SPECTRE_QUAD.copy()):
self.tiles = tiles
self.transformations = transformations
self.quad = quad
def draw(self, polygons, transformation=IDENTITY.copy()):
for tile, trsf in zip(self.tiles, self.transformations):
tile.draw(polygons, mul(transformation, trsf))
def buildSpectreBase():
ttrans = np.array([[1,0,SPECTRE_POINTS[8,0]],
[0,1,SPECTRE_POINTS[8,1]]])
trot = np.array([[np.cos(PI/6),-np.sin(PI/6),0.],
[np.sin(PI/6), np.cos(PI/6),0.]],'float32')
trsf = mul(ttrans, trot)
tiles = {}
tiles["Gamma"] = MetaTile(tiles=[Tile("Gamma1"),Tile("Gamma2")],
transformations=[IDENTITY.copy(),trsf],
quad=SPECTRE_QUAD.copy())
for label in TILE_NAMES:
if label != "Gamma":
tiles[label] = Tile(label)
return tiles
def buildSupertiles(input_tiles):
# First, use any of the nine-unit tiles in "tiles" to obtain a
# list of transformation matrices for placing tiles within supertiles.
quad = input_tiles["Delta"].quad
transformations = [IDENTITY.copy()]
total_angle = 0
trot = IDENTITY.copy()
transformed_quad = quad
for _angle, _from, _to in (( PI/3, 3, 1),
( 0., 2, 0),
( PI/3, 3, 1),
( PI/3, 3, 1),
( 0., 2, 0),
( PI/3, 3, 1),
(-2*PI/3, 3, 3)):
if _angle != 0:
total_angle += _angle
trot = np.array([[1, 0,0],[0,1,0]])*np.cos(total_angle) \
+np.array([[0,-1,0],[1,0,0]])*np.sin(total_angle)
transformed_quad = quad.dot(trot[:,:2].T) # + trot[:,2]
last_trsf = transformations[-1]
ttrans = IDENTITY.copy()
ttrans[:,2] = last_trsf[:,:2].dot(quad[_from,:]) + last_trsf[:,2] \
-transformed_quad[_to,:]
transformations.append(mul(ttrans, trot))
R = np.array([[-1,0,0],[ 0,1,0]], 'float32')
transformations = [ mul(R, trsf) for trsf in transformations ]
# Now build the actual supertiles, labeling appropriately.
super_quad = quad[[2,1,2,1],:]
for i,itrsf in enumerate([6,5,3,0]):
trsf = transformations[itrsf]
super_quad[i,:] = trsf[:,:2].dot(super_quad[i,:]) + trsf[:,2]
tiles = {}
for label, substitutions in (("Gamma", ("Pi", "Delta", None, "Theta", "Sigma", "Xi", "Phi", "Gamma")),
("Delta", ("Xi", "Delta", "Xi", "Phi", "Sigma", "Pi", "Phi", "Gamma")),
("Theta", ("Psi", "Delta", "Pi", "Phi", "Sigma", "Pi", "Phi", "Gamma")),
("Lambda", ("Psi", "Delta", "Xi", "Phi", "Sigma", "Pi", "Phi", "Gamma")),
("Xi", ("Psi", "Delta", "Pi", "Phi", "Sigma", "Psi", "Phi", "Gamma")),
("Pi", ("Psi", "Delta", "Xi", "Phi", "Sigma", "Psi", "Phi", "Gamma")),
("Sigma", ("Xi", "Delta", "Xi", "Phi", "Sigma", "Pi", "Lambda", "Gamma")),
("Phi", ("Psi", "Delta", "Psi", "Phi", "Sigma", "Pi", "Phi", "Gamma")),
("Psi", ("Psi", "Delta", "Psi", "Phi", "Sigma", "Psi", "Phi", "Gamma"))):
tiles[label] =\
MetaTile(tiles=[input_tiles[subst] for subst in substitutions if subst],
transformations=[trsf for subst, trsf in zip(substitutions, transformations) if subst],
quad=super_quad)
return tiles
start = time()
tiles = buildSpectreBase()
for _ in range(N_ITERATIONS):
tiles = buildSupertiles(tiles)
time1 = time()-start
print(f"supertiling loop took {round(time1, 4)} seconds")
start = time()
polygons = []
tiles["Delta"].draw(polygons)
time2 = time()-start
print(f"tile recursion loop took {round(time2, 4)} seconds, generated {len(polygons)} tiles")
plt.figure(figsize=(8, 8))
plt.axis('equal')
for pts,color in polygons:
plt.fill(pts[:,0],pts[:,1],facecolor=color)
plt.show()
Metadata
Metadata
Assignees
Labels
No labels
Activity
logari81 commentedon Nov 7, 2023
and here a dictionary-free version of the same code
shrx commentedon Nov 7, 2023
Hello, thanks for your contribution! Feel free to open a pull request.
reversi-fun commentedon Feb 5, 2024
Hi.
It's probably a good thing that we stopped keeping all the vertex coordinates of the spectre shape, as it allows us to draw larger shapes.
@logari81 Your version, which held the information for transform as a label in string format, was several times faster than the original version. but dictionary-free version is not good.
I also make Python code for more faster and more greater spectre tiles.
and It made any ration of Spectre tile(a,b)
Prease see my Pullrequest.
The comparison results are shown below. (drowsvg is faster 30Times, file size shoter 5Times).
Prerequisites
N_ITERATIONS = 5 (generates 34649 tiles)
matplotlib outputs
matplotlib.pyplot SVG drawing took 21.1542 seconds
matplotlib.pyplot: file save to spectre_tile10.0-10.0_5-34649pts.svg FILE-SIZE = 34,312,828 bytes.
matplotlib.pyplot total processing time 21.3502 seconds, 616.1845 μs/tile
drowsvg outputs
drowsvg: SVG drawing took 0.7256 seconds, generated 34649 tiles
drowsvg: drawPolygon save to spectre_tile10.0-10.0_5-34649useRef.svg FILE-SIZE= 6,692,354 bytes.
drowsvg: total processing time 0.7266 seconds, 20.9705 μs/tile