mirror of
https://github.com/enzet/map-machine.git
synced 2025-04-30 18:57:49 +02:00
169 lines
5.8 KiB
Python
169 lines
5.8 KiB
Python
"""
|
|
Icon grid drawing.
|
|
|
|
Author: Sergey Vartanov (me@enzet.ru).
|
|
"""
|
|
from os.path import join
|
|
from typing import Any, Dict, List, Set
|
|
|
|
import numpy as np
|
|
from colour import Color
|
|
from svgwrite import Drawing
|
|
|
|
from roentgen.icon import IconExtractor, Shape
|
|
from roentgen.scheme import Scheme
|
|
|
|
|
|
def draw_all_icons(
|
|
output_file_name: str, output_directory: str, columns: int = 16,
|
|
step: float = 24
|
|
) -> None:
|
|
"""
|
|
Draw all possible icon combinations in grid.
|
|
|
|
:param output_file_name: output SVG file name for icon grid
|
|
:param output_directory: path to the directory to store individual SVG files
|
|
for icons
|
|
:param columns: the number of columns in grid
|
|
:param step: horizontal and vertical distance between icons
|
|
"""
|
|
tags_file_name: str = "data/tags.yml"
|
|
scheme: Scheme = Scheme(tags_file_name)
|
|
|
|
to_draw: List[Set[str]] = []
|
|
|
|
for element in scheme.icons: # type: Dict[str, Any]
|
|
if "icon" in element and set(element["icon"]) not in to_draw:
|
|
to_draw.append(set(element["icon"]))
|
|
if "add_icon" in element and set(element["add_icon"]) not in to_draw:
|
|
to_draw.append(set(element["add_icon"]))
|
|
if "over_icon" not in element:
|
|
continue
|
|
if "under_icon" in element:
|
|
for icon_id in element["under_icon"]: # type: str
|
|
current_set = set([icon_id] + element["over_icon"])
|
|
if current_set not in to_draw:
|
|
to_draw.append(current_set)
|
|
if not ("under_icon" in element and "with_icon" in element):
|
|
continue
|
|
for icon_id in element["under_icon"]: # type: str
|
|
for icon_2_id in element["with_icon"]: # type: str
|
|
current_set: Set[str] = set(
|
|
[icon_id] + [icon_2_id] + element["over_icon"])
|
|
if current_set not in to_draw:
|
|
to_draw.append(current_set)
|
|
for icon_2_id in element["with_icon"]: # type: str
|
|
for icon_3_id in element["with_icon"]: # type: str
|
|
current_set = set(
|
|
[icon_id] + [icon_2_id] + [icon_3_id] +
|
|
element["over_icon"])
|
|
if (icon_2_id != icon_3_id and icon_2_id != icon_id and
|
|
icon_3_id != icon_id and
|
|
current_set not in to_draw):
|
|
to_draw.append(current_set)
|
|
|
|
icons_file_name: str = "icons/icons.svg"
|
|
extractor: IconExtractor = IconExtractor(icons_file_name)
|
|
|
|
specified_ids: Set[str] = set()
|
|
|
|
for icons_to_draw in to_draw: # type: List[str]
|
|
specified_ids |= icons_to_draw
|
|
print(
|
|
"Icons with no tag specification: \n " +
|
|
", ".join(sorted(extractor.icons.keys() - specified_ids)) + "."
|
|
)
|
|
|
|
draw_grid(
|
|
output_file_name, to_draw, extractor, output_directory, columns, step
|
|
)
|
|
|
|
|
|
def draw_grid(
|
|
file_name: str, combined_icon_ids: List[Set[str]],
|
|
extractor: IconExtractor, output_directory: str, columns: int = 16,
|
|
step: float = 24, color=Color("#444444")
|
|
) -> List[List[Shape]]:
|
|
"""
|
|
Draw icons in the form of table
|
|
|
|
:param file_name: output SVG file name
|
|
:param combined_icon_ids: list of set of icon string identifiers
|
|
:param extractor: icon extractor that generates icon SVG path commands using
|
|
its string identifier
|
|
:param output_directory: path to the directory to store individual SVG files
|
|
for icons
|
|
:param columns: number of columns in grid
|
|
:param step: horizontal and vertical distance between icons in grid
|
|
:param color: icon foreground color
|
|
"""
|
|
point: np.array = np.array((step / 2, step / 2))
|
|
width: float = step * columns
|
|
number: int = 0
|
|
icons: List[List[Shape]] = []
|
|
|
|
for icons_to_draw in combined_icon_ids: # type: Set[str]
|
|
found: bool = False
|
|
icon_set: List[Shape] = []
|
|
names = []
|
|
for icon_id in icons_to_draw: # type: str
|
|
icon, extracted = extractor.get_path(icon_id) # type: Shape, bool
|
|
assert extracted, f"no icon with ID {icon_id}"
|
|
icon_set.append(icon)
|
|
found = True
|
|
if icon.name:
|
|
names.append(icon.name)
|
|
if found:
|
|
icons.append(icon_set)
|
|
number += 1
|
|
draw_icon(
|
|
join(output_directory, f"Röntgen {' + '.join(names)}.svg"),
|
|
icons_to_draw, extractor
|
|
)
|
|
|
|
height: int = int(int(number / (width / step) + 1) * step)
|
|
svg: Drawing = Drawing(file_name, (width, height))
|
|
svg.add(svg.rect((0, 0), (width, height), fill="#FFFFFF"))
|
|
|
|
for combined_icon in icons: # type: List[Shape]
|
|
background_color = "#FFFFFF"
|
|
svg.add(svg.rect(
|
|
point - np.array((-10, -10)), (20, 20),
|
|
fill=background_color))
|
|
for icon in combined_icon: # type: Shape
|
|
path = icon.get_path(svg, point)
|
|
path.update({"fill": color.hex})
|
|
svg.add(path)
|
|
point += np.array((step, 0))
|
|
if point[0] > width - 8:
|
|
point[0] = step / 2
|
|
point += np.array((0, step))
|
|
height += step
|
|
|
|
print(f"Icons: {number}.")
|
|
|
|
with open(file_name, "w") as output_file:
|
|
svg.write(output_file)
|
|
|
|
return icons
|
|
|
|
|
|
def draw_icon(
|
|
file_name: str, icon_ids: Set[str], extractor: IconExtractor
|
|
) -> None:
|
|
|
|
icon_set: List[Shape] = []
|
|
for icon_id in icon_ids: # type: str
|
|
icon, extracted = extractor.get_path(icon_id) # type: Shape, bool
|
|
assert extracted, f"no icon with ID {icon_id}"
|
|
icon_set.append(icon)
|
|
|
|
svg: Drawing = Drawing(file_name, (16, 16))
|
|
|
|
for icon in icon_set: # type: Shape
|
|
path = icon.get_path(svg, (8, 8))
|
|
path.update({"fill": "black"})
|
|
svg.add(path)
|
|
|
|
with open(file_name, "w") as output_file:
|
|
svg.write(output_file)
|