Skip to content

Instantly share code, notes, and snippets.

@99991
Created March 2, 2020 19:57
Show Gist options
  • Save 99991/4fcf3093321ebe29d73bd34cbdb707a2 to your computer and use it in GitHub Desktop.
Save 99991/4fcf3093321ebe29d73bd34cbdb707a2 to your computer and use it in GitHub Desktop.
A python code snippet to generate a hexagonal svg grid
import math
class Line:
def __init__(self, x1, y1, x2, y2):
self.x1 = x1
self.y1 = y1
self.x2 = x2
self.y2 = y2
def to_svg(self, style):
return f'<line x1="{self.x1}" y1="{self.y1}" x2="{self.x2}" y2="{self.y2}" style="{style}" vector-effect="non-scaling-stroke" />'
class Circle:
def __init__(self, x, y, radius):
self.x = x
self.y = y
self.radius = radius
def to_svg(self, style):
return f'<circle cx="{self.x}" cy="{self.y}" r="{self.radius}" style="{style}" vector-effect="non-scaling-stroke" />'
class NGon:
def __init__(self, x, y, radius, n):
self.x = x
self.y = y
self.radius = radius
self.n = n
def to_svg(self, style):
n = self.n
starting_angle = 0.5 * 2.0 * math.pi / n
points = []
for i in range(n):
angle = 2.0 * math.pi * i / n + starting_angle
x = self.x + self.radius * math.cos(angle)
y = self.y + self.radius * math.sin(angle)
points.append(f"{x},{y}")
points = " ".join(points)
return f'<polygon points="{points}" style="{style}" vector-effect="non-scaling-stroke" />'
class Ring:
def __init__(self, x, y, inner_radius, outer_radius):
self.x = x
self.y = y
self.inner_radius = inner_radius
self.outer_radius = outer_radius
def to_svg(self, style):
r0 = self.inner_radius
r1 = self.outer_radius
path = f'''
M {self.x} {self.y - r1}
A {r1} {r1} 0 1 0 {self.x} {self.y + r1}
A {r1} {r1} 0 1 0 {self.x} {self.y - r1}
Z
M {self.x} {self.y - r0}
A {r0} {r0} 0 1 1 {self.x} {self.y + r0}
A {r0} {r0} 0 1 1 {self.x} {self.y - r0}
Z
'''
path = " ".join(path.split())
return f'<path d="{path}" style="{style}" vector-effect="non-scaling-stroke" />'
def make_svg_header(width, height):
return f'''<svg version="1.1"
baseProfile="full"
width="{width}" height="{height}"
xmlns="http://www.w3.org/2000/svg">'''
def draw_walls(
filename,
walls,
nx,
ny,
padding,
scale,
stroke_width,
):
# squish vertically to make triangles equilateral
squish = math.sqrt(1 - 0.5**2)
width = (nx + 2 * padding) * scale
height = (ny + 2 * padding) * scale * squish
svg = []
svg.append(make_svg_header(width, height))
svg.append(f'<g transform="scale({scale} {scale})">')
svg.append('<g transform="translate(0.5, 0.5)">')
def draw_line(ax, ay, bx, by):
style = f'stroke: rgb(0,0,0); stroke-width: {stroke_width}'
svg.append(Line(ax, ay, bx, by).to_svg(style))
# draw horizontal lines
for y in range(ny + 1):
shift = 0.0 if y % 2 == 0 else 0.5
draw_line(shift, y * squish, shift + nx - 1, y * squish)
# draw diagonal lines which start at 0
for x2 in range(nx):
x3 = min(nx - 0.5, x2 + 0.5 * ny)
draw_line(x2, 0, x3, (x3 - x2) * 2 * squish)
x4 = max(0, x2 - 0.5 * ny)
draw_line(x2, 0, x4, (x2 - x4) * 2 * squish)
# draw diagonal lines that don't start at 0
for y2 in range(1, ny):
shift = 0.0 if y2 % 2 == 0 else 0.5
y3 = min(ny, y2 + ny)
draw_line(shift, y2 * squish, shift + 0.5 * (y3 - y2), y3 * squish)
x = shift + nx - 1
draw_line(x, y2 * squish, x - 0.5 * (y3 - y2), y3 * squish)
# draw circles at intersection points
for y in range(ny + 1):
shift = 0.0 if y % 2 == 0 else 0.5
for x in range(nx):
style = f'stroke: rgb(0,0,0); stroke-width: {stroke_width}'
svg.append(Circle(x + shift, y * squish, 0.05).to_svg(style))
# draw walls
for x, y, has_green_circle in walls:
shift = 0.0 if y % 2 == 0 else 0.5
style = f'fill:rgb(52, 174, 235); stroke:black;stroke-width: {stroke_width}'
svg.append(NGon(x + shift, y * squish, 0.5, 6).to_svg(style))
# draw green ring
if has_green_ring:
style = f'fill:rgb(3, 252, 40); stroke:black;stroke-width: {stroke_width}'
svg.append(Ring(x + shift, y * squish, 0.3, 0.5 * squish).to_svg(style))
svg.append('</g>')
svg.append('</g>')
svg.append('</svg>\n')
svg = "\n".join(svg)
with open(filename, "w") as f:
f.write(svg)
def main():
# format: (x, y, has_green_ring)
walls = [
(1, 1, True),
(2, 1, False),
(3, 1, True),
(4, 1, False),
(5, 1, True),
(6, 1, False),
(7, 2, True),
(7, 3, False),
(7, 4, True),
(6, 5, False),
(6, 6, True),
(5, 6, False),
(4, 6, True),
(3, 6, False),
(2, 6, True),
]
draw_walls(
walls=walls,
nx=10,
ny=10,
scale=60,
padding=0.5,
stroke_width=1.5,
filename="test.svg")
if __name__ == "__main__":
main()
Display the source blob
Display the rendered blob
Raw
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment