164 lines
5.2 KiB
Python
164 lines
5.2 KiB
Python
|
#!/usr/bin/env python
|
||
|
# -*- coding: utf-8 -*-
|
||
|
"""
|
||
|
This module can be used to create and display Mini-Lycacodes
|
||
|
|
||
|
(C) 2022 Louis Heredero louis.heredero@edu.vs.ch
|
||
|
"""
|
||
|
|
||
|
import pygame
|
||
|
import numpy as np
|
||
|
import hamming
|
||
|
|
||
|
S = 600
|
||
|
|
||
|
class LycacodeError(Exception):
|
||
|
pass
|
||
|
|
||
|
class LycacodeMini:
|
||
|
BLACK = (158,17,26)
|
||
|
#BLACK = (0,0,0)
|
||
|
WHITE = (255,255,255)
|
||
|
|
||
|
OFFSETS = [(0,-1), (1,0), (0,1), (-1,0)]
|
||
|
|
||
|
FRAME = True
|
||
|
CIRCLES = True
|
||
|
DOTS = True
|
||
|
DB_SQUARES = False
|
||
|
|
||
|
def __init__(self, id_):
|
||
|
self.id = id_
|
||
|
self.encode()
|
||
|
self.create_matrix()
|
||
|
|
||
|
def encode(self):
|
||
|
self.bits = f"{self.id:020b}"
|
||
|
|
||
|
self.bits = list(map(int, self.bits))
|
||
|
parity = [sum(self.bits[i*5:i*5+5])%2 for i in range(4)]
|
||
|
for i in range(4):
|
||
|
self.bits.insert((4-i)*5, parity[3-i])
|
||
|
|
||
|
|
||
|
def create_matrix(self):
|
||
|
self.matrix = np.zeros([9, 9])-1
|
||
|
self.matrix[4:5, :] = 0
|
||
|
self.matrix[:, 4:5] = 0
|
||
|
self.matrix[1:2, 3:6] = 0
|
||
|
self.matrix[3:6, 1:2] = 0
|
||
|
self.matrix[-2:-1, -6:-3] = 0
|
||
|
self.matrix[-6:-3, -2:-1] = 0
|
||
|
self.matrix[4,4] = -1
|
||
|
|
||
|
for y in range(9):
|
||
|
for x in range(9):
|
||
|
if self.matrix[y,x] == 0:
|
||
|
self.matrix[y,x] = self.bits.pop(0)
|
||
|
|
||
|
if len(self.bits) == 0:
|
||
|
break
|
||
|
|
||
|
if len(self.bits) == 0:
|
||
|
break
|
||
|
|
||
|
def display(self, surf):
|
||
|
S = min(surf.get_size())
|
||
|
s = int(S/12/3)*3
|
||
|
O = (S-s*9)/2
|
||
|
|
||
|
surf.fill(self.WHITE)
|
||
|
|
||
|
# Frame
|
||
|
if self.FRAME:
|
||
|
pygame.draw.rect(surf, self.BLACK, [O-s, O-s, s*11, s*11])
|
||
|
pygame.draw.rect(surf, self.WHITE, [O-s*0.5, O-s*0.5, s*10, s*10])
|
||
|
|
||
|
# Cross
|
||
|
for i in range(4):
|
||
|
dx, dy = self.OFFSETS[i]
|
||
|
X, Y = S/2 + dx*s*3, S/2 + dy*s*3
|
||
|
if self.CIRCLES:
|
||
|
for j in range(3):
|
||
|
dx2, dy2 = self.OFFSETS[(i+j-1)%4]
|
||
|
pygame.draw.circle(surf, self.BLACK, [X+dx2*s, Y+dy2*s], 0.75*s)
|
||
|
|
||
|
pygame.draw.rect(surf, self.BLACK, [X-(1.5-abs(dx))*s, Y-(1.5-abs(dy))*s, s*(3-abs(dx)*2), s*(3-abs(dy)*2)])
|
||
|
|
||
|
pygame.draw.rect(surf, self.BLACK, [O, S/2-s/2, 9*s, s])
|
||
|
pygame.draw.rect(surf, self.BLACK, [S/2-s/2, O, s, 9*s])
|
||
|
|
||
|
# Dots
|
||
|
if self.DOTS:
|
||
|
for y in range(9):
|
||
|
for x in range(9):
|
||
|
if self.matrix[y, x] == 1:
|
||
|
pygame.draw.circle(surf, self.WHITE, [O+(x+0.5)*s, O+(y+0.5)*s], s/3)
|
||
|
|
||
|
# Center
|
||
|
pygame.draw.circle(surf, self.WHITE, [O+4.5*s, O+4.25*s], s/6)
|
||
|
pygame.draw.circle(surf, self.WHITE, [O+4.25*s, O+4.75*s], s/6)
|
||
|
|
||
|
def save(self, path):
|
||
|
S = 600
|
||
|
s = int(S/12)
|
||
|
O = (S-s*9)/2
|
||
|
|
||
|
BLACK = "#9E111A"
|
||
|
WHITE = "#FFFFFF"
|
||
|
|
||
|
with open(path, "w") as f:
|
||
|
f.write(f"<svg width='{S}px' height='{S}px' viewbox='0 0 {S} {S}'>\n")
|
||
|
# Background
|
||
|
f.write(f"<rect x='0' y='0' width='{S}' height='{S}' fill='{WHITE}' />\n")
|
||
|
|
||
|
# Frame
|
||
|
f.write(f"<rect x='{O-s*0.75}' y='{O-s*0.75}' width='{s*10.5}' height='{s*10.5}' style='fill:none;stroke:{BLACK};stroke-width:{0.5*s};' />\n")
|
||
|
|
||
|
# Cross
|
||
|
for i in range(4):
|
||
|
dx, dy = self.OFFSETS[i]
|
||
|
X, Y = S/2 + dx*s*3, S/2 + dy*s*3
|
||
|
if self.CIRCLES:
|
||
|
for j in range(3):
|
||
|
dx2, dy2 = self.OFFSETS[(i+j-1)%4]
|
||
|
f.write(f"<circle cx='{X+dx2*s}' cy='{Y+dy2*s}' r='{0.75*s}' style='fill:{BLACK};stroke:none;stroke-width:0;' />\n")
|
||
|
|
||
|
f.write(f"<rect x='{X-(1.5-abs(dx))*s}' y='{Y-(1.5-abs(dy))*s}' width='{s*(3-abs(dx)*2)}' height='{s*(3-abs(dy)*2)}' style='fill:{BLACK};stroke:none;stroke-width:0;' />\n")
|
||
|
|
||
|
# Cross
|
||
|
f.write(f"<rect x='{O}' y='{S/2-s/2}' width='{9*s}' height='{s}' style='fill:{BLACK};stroke:none;stroke-width:0;' />\n")
|
||
|
f.write(f"<rect x='{S/2-s/2}' y='{O}' width='{s}' height='{9*s}' style='fill:{BLACK};stroke:none;stroke-width:0;' />\n")
|
||
|
|
||
|
# Dots
|
||
|
if self.DOTS:
|
||
|
for y in range(9):
|
||
|
for x in range(9):
|
||
|
if self.matrix[y, x] == 1:
|
||
|
f.write(f"<circle cx='{O+(x+0.5)*s}' cy='{O+(y+0.5)*s}' r='{s/3}' style='fill:{WHITE};stroke:none;stroke-width:0;' />\n")
|
||
|
|
||
|
# Center
|
||
|
f.write(f"<circle cx='{O+4.5*s}' cy='{O+4.25*s}' r='{s/6}' style='fill:{WHITE};stroke:none;stroke-width:0;' />\n")
|
||
|
f.write(f"<circle cx='{O+4.25*s}' cy='{O+4.75*s}' r='{s/6}' style='fill:{WHITE};stroke:none;stroke-width:0;' />\n")
|
||
|
|
||
|
f.write("</svg>")
|
||
|
|
||
|
def save(self):
|
||
|
path = input("Save as (.png or .svg): ")
|
||
|
|
||
|
if path.endswith(".svg"):
|
||
|
code.save(path)
|
||
|
|
||
|
else:
|
||
|
pygame.image.save(w, path)
|
||
|
|
||
|
if __name__ == "__main__":
|
||
|
import base
|
||
|
|
||
|
b = base.Base(S, S, "Mini-Lycacode generator")
|
||
|
|
||
|
code = LycacodeMini(16048)
|
||
|
code.display(b.w)
|
||
|
|
||
|
b.save = save
|
||
|
b.main()
|