Add icon collection class.

This commit is contained in:
Sergey Vartanov 2021-06-10 00:07:52 +03:00
parent 9fd2d869ff
commit 3bb6439d7b
4 changed files with 138 additions and 121 deletions

View file

@ -14,7 +14,7 @@ import svgwrite
from roentgen.constructor import Constructor from roentgen.constructor import Constructor
from roentgen.flinger import Flinger from roentgen.flinger import Flinger
from roentgen.grid import draw_all_icons from roentgen.grid import IconCollection
from roentgen.icon import ShapeExtractor from roentgen.icon import ShapeExtractor
from roentgen.mapper import ( from roentgen.mapper import (
AUTHOR_MODE, CREATION_TIME_MODE, ICONS_FILE_NAME, Painter, TAGS_FILE_NAME, AUTHOR_MODE, CREATION_TIME_MODE, ICONS_FILE_NAME, Painter, TAGS_FILE_NAME,
@ -158,22 +158,25 @@ def draw_element(target: str, tags_description: str):
svg.write(open("test_icon.svg", "w+")) svg.write(open("test_icon.svg", "w+"))
def draw_grid() -> None: def draw_icons() -> None:
""" """
Draw all possible icon shapes combinations as grid. Draw all possible icon shapes combinations as grid in one SVG file and as
individual SVG files.
""" """
os.makedirs("icon_set", exist_ok=True) os.makedirs("icon_set", exist_ok=True)
scheme: Scheme = Scheme(Path("scheme/default.yml")) scheme: Scheme = Scheme(Path("scheme/default.yml"))
extractor: ShapeExtractor = ShapeExtractor( extractor: ShapeExtractor = ShapeExtractor(
Path("icons/icons.svg"), Path("icons/config.json") Path("icons/icons.svg"), Path("icons/config.json")
) )
draw_all_icons(scheme, extractor, "icon_grid.svg", "icon_set") collection: IconCollection = IconCollection.from_scheme(scheme, extractor)
collection.draw_grid(Path("icon_grid.svg"))
collection.draw_icons(Path("icon_set"))
if __name__ == "__main__": if __name__ == "__main__":
if len(sys.argv) == 3 and sys.argv[1] in ["node", "way", "area"]: if len(sys.argv) == 3 and sys.argv[1] in ["node", "way", "area"]:
draw_element(sys.argv[1], sys.argv[2]) draw_element(sys.argv[1], sys.argv[2])
elif len(sys.argv) == 2 and sys.argv[1] == "grid": elif len(sys.argv) == 2 and sys.argv[1] == "icons":
draw_grid() draw_icons()
else: else:
main(sys.argv) main(sys.argv)

View file

@ -1,7 +1,7 @@
""" """
Icon grid drawing. Icon grid drawing.
""" """
from os.path import join from pathlib import Path
from typing import List, Set from typing import List, Set
import numpy as np import numpy as np
@ -15,125 +15,130 @@ __author__ = "Sergey Vartanov"
__email__ = "me@enzet.ru" __email__ = "me@enzet.ru"
def draw_all_icons( class IconCollection:
scheme: Scheme, extractor: ShapeExtractor, def __init__(self, icons):
output_file_name: str, output_directory: str, columns: int = 16, self.icons: List[Icon] = icons
step: float = 24, background_color: Color = Color("white"),
color: Color = Color("black")
) -> None:
"""
Draw all possible icon combinations in grid.
:param scheme: tag specification @classmethod
:param extractor: shape extractor for icon creation def from_scheme(
:param output_file_name: output SVG file name for icon grid cls,
:param output_directory: path to the directory to store individual SVG files scheme: Scheme,
for icons extractor: ShapeExtractor,
:param columns: the number of columns in grid background_color: Color = Color("white"),
:param step: horizontal and vertical distance between icons color: Color = Color("black")
:param background_color: background color ) -> "IconCollection":
:param color: icon color
"""
icons: List[Icon] = []
def add() -> None:
""" """
Construct icon and add it to the list. Draw all possible icon combinations in grid.
"""
specifications = [
ShapeSpecification.from_structure(x, extractor, scheme)
for x in current_set
]
constructed_icon: Icon = Icon(specifications)
constructed_icon.recolor(color, white=background_color)
if constructed_icon not in icons:
icons.append(constructed_icon)
for matcher in scheme.node_matchers: :param scheme: tag specification
if matcher.shapes: :param extractor: shape extractor for icon creation
current_set = matcher.shapes :param background_color: background color
add() :param color: icon color
if matcher.add_shapes: """
current_set = matcher.add_shapes icons: List[Icon] = []
add()
if not matcher.over_icon: def add() -> None:
continue """
if matcher.under_icon: Construct icon and add it to the list.
"""
specifications = [
ShapeSpecification.from_structure(x, extractor, scheme)
for x in current_set
]
constructed_icon: Icon = Icon(specifications)
constructed_icon.recolor(color, white=background_color)
if constructed_icon not in icons:
icons.append(constructed_icon)
for matcher in scheme.node_matchers:
if matcher.shapes:
current_set = matcher.shapes
add()
if matcher.add_shapes:
current_set = matcher.add_shapes
add()
if not matcher.over_icon:
continue
if matcher.under_icon:
for icon_id in matcher.under_icon:
current_set = [icon_id] + matcher.over_icon
add()
if not (matcher.under_icon and matcher.with_icon):
continue
for icon_id in matcher.under_icon: for icon_id in matcher.under_icon:
current_set = [icon_id] + matcher.over_icon for icon_2_id in matcher.with_icon:
add() current_set: List[str] = (
if not (matcher.under_icon and matcher.with_icon): [icon_id] + [icon_2_id] + matcher.over_icon
continue
for icon_id in matcher.under_icon:
for icon_2_id in matcher.with_icon:
current_set: List[str] = (
[icon_id] + [icon_2_id] + matcher.over_icon
)
add()
for icon_2_id in matcher.with_icon:
for icon_3_id in matcher.with_icon:
current_set = (
[icon_id] + [icon_2_id] + [icon_3_id] +
matcher.over_icon
) )
if (icon_2_id != icon_3_id and icon_2_id != icon_id and add()
icon_3_id != icon_id): for icon_2_id in matcher.with_icon:
add() for icon_3_id in matcher.with_icon:
current_set = (
[icon_id] + [icon_2_id] + [icon_3_id] +
matcher.over_icon
)
if (icon_2_id != icon_3_id and icon_2_id != icon_id and
icon_3_id != icon_id):
add()
specified_ids: Set[str] = set() specified_ids: Set[str] = set()
for icon in icons: for icon in icons:
specified_ids |= set(icon.get_shape_ids()) specified_ids |= set(icon.get_shape_ids())
print( print(
"Icons with no tag specification: \n " + "Icons with no tag specification: \n " +
", ".join(sorted(extractor.shapes.keys() - specified_ids)) + "." ", ".join(sorted(extractor.shapes.keys() - specified_ids)) + "."
) )
return cls(icons)
for icon in icons: def draw_icons(self, output_directory: Path):
icon.draw_to_file(join( """
output_directory, f"{' + '.join(icon.get_names())}.svg" :param output_directory: path to the directory to store individual SVG files
)) for icons
"""
for icon in self.icons:
icon.draw_to_file(
output_directory / f"{'___'.join(icon.get_shape_ids())}.svg"
)
draw_grid( def draw_grid(
output_file_name, sorted(icons), columns, step, self,
background_color=background_color file_name: Path,
) columns: int = 16,
step: float = 24,
background_color: Color = Color("white"),
):
"""
Draw icons in the form of table.
:param file_name: output SVG file name
:param columns: number of columns in grid
:param step: horizontal and vertical distance between icons in grid
:param background_color: background color
"""
point: np.array = np.array((step / 2, step / 2))
width: float = step * columns
def draw_grid( height: int = int(int(len(self.icons) / (width / step) + 1) * step)
file_name: str, icons: List[Icon], columns: int = 16, step: float = 24, svg: Drawing = Drawing(str(file_name), (width, height))
background_color: Color = Color("white") svg.add(svg.rect((0, 0), (width, height), fill=background_color.hex))
):
"""
Draw icons in the form of table
:param file_name: output SVG file name for icon in self.icons:
:param icons: list of icons icon: Icon
:param columns: number of columns in grid rectangle = svg.rect(
:param step: horizontal and vertical distance between icons in grid point - np.array((10, 10)), (20, 20),
:param background_color: background color fill=background_color.hex
""" )
point: np.array = np.array((step / 2, step / 2)) svg.add(rectangle)
width: float = step * columns icon.draw(svg, point)
point += np.array((step, 0))
if point[0] > width - 8:
point[0] = step / 2
point += np.array((0, step))
height += step
height: int = int(int(len(icons) / (width / step) + 1) * step) with open(file_name, "w") as output_file:
svg: Drawing = Drawing(file_name, (width, height)) svg.write(output_file)
svg.add(svg.rect((0, 0), (width, height), fill=background_color.hex))
for icon in icons: def __len__(self) -> int:
icon: Icon return len(self.icons)
svg.add(svg.rect(
point - np.array((10, 10)), (20, 20),
fill=background_color.hex
))
icon.draw(svg, point)
point += np.array((step, 0))
if point[0] > width - 8:
point[0] = step / 2
point += np.array((0, step))
height += step
print(f"Icons: {len(icons)}.")
with open(file_name, "w") as output_file:
svg.write(output_file)

View file

@ -323,13 +323,13 @@ class Icon:
for shape_specification in self.shape_specifications: for shape_specification in self.shape_specifications:
shape_specification.draw(svg, point, tags, outline) shape_specification.draw(svg, point, tags, outline)
def draw_to_file(self, file_name: str): def draw_to_file(self, file_name: Path):
""" """
Draw icon to the SVG file. Draw icon to the SVG file.
:param file_name: output SVG file name :param file_name: output SVG file name
""" """
svg: Drawing = Drawing(file_name, (16, 16)) svg: Drawing = Drawing(str(file_name), (16, 16))
for shape_specification in self.shape_specifications: for shape_specification in self.shape_specifications:
shape_specification.draw(svg, (8, 8)) shape_specification.draw(svg, (8, 8))

View file

@ -1,11 +1,11 @@
""" """
Test icon generation for nodes. Test icon generation for nodes.
""" """
from os import makedirs from pathlib import Path
from typing import Dict from typing import Dict
from roentgen.icon import IconSet from roentgen.icon import IconSet
from roentgen.grid import draw_all_icons from roentgen.grid import IconCollection
from test import SCHEME, SHAPE_EXTRACTOR from test import SCHEME, SHAPE_EXTRACTOR
__author__ = "Sergey Vartanov" __author__ = "Sergey Vartanov"
@ -16,8 +16,17 @@ def test_icons() -> None:
""" """
Test grid drawing. Test grid drawing.
""" """
makedirs("icon_set", exist_ok=True) temp_directory: Path = Path("temp")
draw_all_icons(SCHEME, SHAPE_EXTRACTOR, "temp.svg", "icon_set") temp_directory.mkdir(exist_ok=True)
set_directory: Path = temp_directory / "icon_set"
set_directory.mkdir(exist_ok=True)
collection: IconCollection = IconCollection.from_scheme(
SCHEME, SHAPE_EXTRACTOR
)
collection.draw_grid(temp_directory / "grid.svg")
collection.draw_icons(set_directory)
def get_icon(tags: Dict[str, str]) -> IconSet: def get_icon(tags: Dict[str, str]) -> IconSet: