Refactor point drawing.

Draw extra icons under main icon.
This commit is contained in:
Sergey Vartanov 2020-09-27 00:45:18 +03:00
parent 81199551a1
commit 7b58dae764
5 changed files with 320 additions and 285 deletions

View file

@ -4,7 +4,6 @@ Construct Röntgen nodes and ways.
Author: Sergey Vartanov (me@enzet.ru).
"""
from collections import Counter
from dataclasses import dataclass
from datetime import datetime
from hashlib import sha256
from typing import Any, Dict, List, Optional, Set
@ -14,14 +13,15 @@ import numpy as np
from roentgen import ui
from roentgen.color import get_gradient_color
from roentgen.icon import DEFAULT_SMALL_SHAPE_ID
from roentgen.icon import DEFAULT_SMALL_SHAPE_ID, IconExtractor
from roentgen.flinger import Flinger
from roentgen.osm_reader import (
Map, OSMMember, OSMRelation, OSMWay, OSMNode, Tagged)
from roentgen.point import Point
from roentgen.scheme import IconSet, Scheme, LineStyle
from roentgen.util import MinMax
DEBUG: bool = True
DEBUG: bool = False
TIME_COLOR_SCALE: List[Color] = [
Color("#581845"), Color("#900C3F"), Color("#C70039"), Color("#FF5733"),
Color("#FFC300"), Color("#DAF7A6")]
@ -60,27 +60,6 @@ def make_counter_clockwise(polygon: List[OSMNode]) -> List[OSMNode]:
return polygon if not is_clockwise(polygon) else list(reversed(polygon))
class Point(Tagged):
"""
Object on the map with no dimensional attributes.
"""
def __init__(
self, icon_set: IconSet, tags: Dict[str, str], point: np.array,
coordinates: np.array, priority: float = 0,
is_for_node: bool = True):
super().__init__()
assert point is not None
self.icon_set: IconSet = icon_set
self.tags: Dict[str, str] = tags
self.point: np.array = point
self.coordinates: np.array = coordinates
self.priority: float = priority
self.layer: float = 0
self.is_for_node: bool = is_for_node
class Figure(Tagged):
"""
Some figure on the map: way or area.
@ -168,16 +147,6 @@ class Building(Figure):
return 3
@dataclass
class TextStruct:
"""
Some label on the map with attributes.
"""
text: str
fill: Color = Color("#444444")
size: float = 10
def line_center(nodes: List[OSMNode], flinger: Flinger) -> np.array:
"""
Get geometric center of nodes set.
@ -280,7 +249,7 @@ class Constructor:
"""
def __init__(
self, check_level, mode: str, seed: str, map_: Map,
flinger: Flinger, scheme: Scheme):
flinger: Flinger, scheme: Scheme, icon_extractor: IconExtractor):
self.check_level = check_level
self.mode: str = mode
@ -288,6 +257,7 @@ class Constructor:
self.map_: Map = map_
self.flinger: Flinger = flinger
self.scheme: Scheme = scheme
self.icon_extractor = icon_extractor
self.nodes: List[Point] = []
self.figures: List[Figure] = []
@ -331,8 +301,6 @@ class Constructor:
"""
assert len(outers) >= 1
line_is_cycle: bool = is_cycle(outers[0])
center_point, center_coordinates = (
line_center(outers[0], self.flinger))
@ -368,7 +336,8 @@ class Constructor:
else:
self.figures.append(
Figure(line.tags, inners, outers, line_style))
icon_set: IconSet = self.scheme.get_icon(line.tags, for_="line")
icon_set: IconSet = self.scheme.get_icon(
self.icon_extractor, line.tags, for_="line")
self.nodes.append(Point(
icon_set, line.tags, center_point, center_coordinates,
is_for_node=False))
@ -380,7 +349,8 @@ class Constructor:
"stroke-width": 1}
self.figures.append(Figure(
line.tags, inners, outers, LineStyle(style, 1000)))
icon_set: IconSet = self.scheme.get_icon(line.tags)
icon_set: IconSet = self.scheme.get_icon(
self.icon_extractor, line.tags)
self.nodes.append(Point(
icon_set, line.tags, center_point, center_coordinates,
is_for_node=False))
@ -433,7 +403,7 @@ class Constructor:
if not self.check_level(tags):
continue
icon_set: IconSet = self.scheme.get_icon(tags)
icon_set: IconSet = self.scheme.get_icon(self.icon_extractor, tags)
if self.mode in ["time", "user-coloring"]:
if not tags:
@ -450,7 +420,4 @@ class Constructor:
f"{key}: {tags[key]}" for key in tags
if key not in icon_set.processed)
for t in missing_tags.most_common():
print(t)
ui.progress_bar(-1, len(self.map_.node_map), text="Constructing nodes")

View file

@ -6,10 +6,12 @@ Author: Sergey Vartanov (me@enzet.ru).
import re
import xml.dom.minidom
from dataclasses import dataclass
from typing import Dict
from typing import Dict, Any
from xml.dom.minidom import Document, Element, Node
import numpy as np
import svgwrite
from colour import Color
from svgwrite import Drawing
from roentgen import ui
@ -49,6 +51,36 @@ class Icon:
return svg.path(
d=self.path, transform=f"translate({shift[0]},{shift[1]})")
def draw(
self, svg: svgwrite.Drawing, point: np.array, color: Color,
opacity=1.0, tags: Dict[str, Any] = None, outline: bool = False):
"""
Draw icon shape into SVG file.
:param svg: output SVG file
:param point: icon position
:param color: fill color
:param opacity: icon opacity
:param tags: tags to be displayed as hint
:param outline: draw outline for the icon
"""
point = np.array(list(map(int, point)))
path: svgwrite.path.Path = self.get_path(svg, point)
path.update({"fill": color.hex})
if outline:
opacity: float = 0.5
path.update({
"fill": color.hex, "stroke": color.hex, "stroke-width": 2.2,
"stroke-linejoin": "round"})
if opacity != 1.0:
path.update({"opacity": opacity})
if tags:
title: str = "\n".join(map(lambda x: x + ": " + tags[x], tags))
path.set_desc(title=title)
svg.add(path)
class IconExtractor:
"""

View file

@ -14,13 +14,12 @@ from colour import Color
from svgwrite.container import Group
from svgwrite.path import Path
from svgwrite.shapes import Rect
from svgwrite.text import Text
from typing import Any, Dict, List, Optional
from typing import Any, Dict
from roentgen import ui
from roentgen.address import get_address
from roentgen.constructor import (
Constructor, Point, Figure, TextStruct, Building, Segment)
Constructor, Figure, Building, Segment)
from roentgen.point import Point
from roentgen.flinger import Flinger
from roentgen.grid import draw_grid
from roentgen.icon import Icon, IconExtractor
@ -29,7 +28,6 @@ from roentgen.osm_reader import Map, OSMReader
from roentgen.scheme import Scheme
from roentgen.direction import DirectionSet, Sector
from roentgen.util import MinMax
from roentgen.color import is_bright
ICONS_FILE_NAME: str = "icons/icons.svg"
TAGS_FILE_NAME: str = "data/tags.yml"
@ -38,8 +36,6 @@ MISSING_TAGS_FILE_NAME: str = "missing_tags.yml"
AUTHOR_MODE = "user-coloring"
CREATION_TIME_MODE = "time"
DEFAULT_FONT = "Roboto"
class Painter:
"""
@ -64,160 +60,6 @@ class Painter:
self.icon_extractor = icon_extractor
self.scheme: Scheme = scheme
def draw_shapes(self, node: Point, points: List[List[float]]):
"""
Draw shapes for one node.
"""
if node.icon_set.is_default and not node.is_for_node:
return
left: float = -(len(node.icon_set.icons) - 1) * 8
if self.overlap != 0:
for shape_ids in node.icon_set.icons:
has_space = True
for p in points[-1000:]:
if node.point[0] + left - self.overlap <= p[0] \
<= node.point[0] + left + self.overlap and \
node.point[1] - self.overlap <= p[1] \
<= node.point[1] + self.overlap:
has_space = False
break
if has_space:
self.draw_point_shape(
shape_ids, (node.point[0] + left, node.point[1]),
node.icon_set.color, tags=node.tags)
points.append([node.point[0] + left, node.point[1]])
left += 16
else:
for shape_ids in node.icon_set.icons:
self.draw_point_shape(
shape_ids, (node.point[0] + left, node.point[1]),
node.icon_set.color, tags=node.tags)
left += 16
def draw_texts(self, node: Point):
"""
Draw all labels.
"""
text_y: float = 0
write_tags = self.construct_text(node.tags, node.icon_set.processed)
for text_struct in write_tags: # type: TextStruct
text_y += text_struct.size + 1
text = text_struct.text
text = text.replace("&quot;", '"')
text = text.replace("&amp;", '&')
text = text[:26] + ("..." if len(text) > 26 else "")
self.draw_text(
text, (node.point[0], node.point[1] + text_y + 8),
text_struct.fill, size=text_struct.size)
def draw_text(
self, text: str, point, fill: Color, size: float = 10,
out_fill=Color("white"), out_opacity=1.0,
out_fill_2: Optional[Color] = None, out_opacity_2=1.0):
"""
Drawing text.
###### ### outline 2
#------# --- outline 1
#| Text |#
#------#
######
"""
if out_fill_2:
self.svg.add(Text(
text, point, font_size=size, text_anchor="middle",
font_family=DEFAULT_FONT, fill=out_fill_2.hex,
stroke_linejoin="round", stroke_width=5,
stroke=out_fill_2.hex, opacity=out_opacity_2))
if out_fill:
self.svg.add(Text(
text, point, font_size=size, text_anchor="middle",
font_family=DEFAULT_FONT, fill=out_fill.hex,
stroke_linejoin="round", stroke_width=3,
stroke=out_fill.hex, opacity=out_opacity))
self.svg.add(Text(
text, point, font_size=size, text_anchor="middle",
font_family=DEFAULT_FONT, fill=fill.hex))
def construct_text(self, tags, processed) -> List[TextStruct]:
"""
Construct labels for not processed tags.
"""
texts: List[TextStruct] = []
name = None
alt_name = None
if "name" in tags:
name = tags["name"]
tags.pop("name", None)
if "name:ru" in tags:
if not name:
name = tags["name:ru"]
tags.pop("name:ru", None)
tags.pop("name:ru", None)
if "name:en" in tags:
if not name:
name = tags["name:en"]
tags.pop("name:en", None)
tags.pop("name:en", None)
if "alt_name" in tags:
if alt_name:
alt_name += ", "
else:
alt_name = ""
alt_name += tags["alt_name"]
tags.pop("alt_name")
if "old_name" in tags:
if alt_name:
alt_name += ", "
else:
alt_name = ""
alt_name += "бывш. " + tags["old_name"]
address: List[str] = get_address(tags, self.draw_captions)
if name:
texts.append(TextStruct(name, Color("black")))
if alt_name:
texts.append(TextStruct("(" + alt_name + ")"))
if address:
texts.append(TextStruct(", ".join(address)))
if self.draw_captions == "main":
return texts
if "route_ref" in tags:
texts.append(TextStruct(tags["route_ref"].replace(";", " ")))
tags.pop("route_ref", None)
if "cladr:code" in tags:
texts.append(TextStruct(tags["cladr:code"], size=7))
tags.pop("cladr:code", None)
if "website" in tags:
link = tags["website"]
if link[:7] == "http://":
link = link[7:]
if link[:8] == "https://":
link = link[8:]
if link[:4] == "www.":
link = link[4:]
if link[-1] == "/":
link = link[:-1]
link = link[:25] + ("..." if len(tags["website"]) > 25 else "")
texts.append(TextStruct(link, Color("#000088")))
tags.pop("website", None)
for k in ["phone"]:
if k in tags:
texts.append(TextStruct(tags[k], Color("#444444")))
tags.pop(k)
for tag in tags:
if self.scheme.is_writable(tag) and not (tag in processed):
texts.append(TextStruct(tags[tag]))
return texts
def draw(self, constructor: Constructor, points):
"""
Draw map.
@ -332,21 +174,21 @@ class Painter:
angle = float(node.get_tag("camera:angle"))
if "angle" in node.tags:
angle = float(node.get_tag("angle"))
direction_radius: float = \
25 * self.flinger.get_scale(node.coordinates)
direction_color: Color = \
self.scheme.get_color("direction_camera_color")
direction_radius: float = (
25 * self.flinger.get_scale(node.coordinates))
direction_color: Color = (
self.scheme.get_color("direction_camera_color"))
elif node.get_tag("traffic_sign") == "stop":
direction = node.get_tag("direction")
direction_radius: float = \
25 * self.flinger.get_scale(node.coordinates)
direction_radius: float = (
25 * self.flinger.get_scale(node.coordinates))
direction_color: Color = Color("red")
else:
direction = node.get_tag("direction")
direction_radius: float = \
50 * self.flinger.get_scale(node.coordinates)
direction_color: Color = \
self.scheme.get_color("direction_view_color")
direction_radius: float = (
50 * self.flinger.get_scale(node.coordinates))
direction_color: Color = (
self.scheme.get_color("direction_view_color"))
is_revert_gradient = True
if not direction:
@ -375,16 +217,16 @@ class Painter:
d=["M", point] + path + ["L", point, "Z"],
fill=gradient.get_paint_server()))
# All other nodes
# All other points
nodes = sorted(constructor.nodes, key=lambda x: x.layer)
for index, node in enumerate(nodes): # type: int, Point
if node.get_tag("natural") == "tree" and \
if (node.get_tag("natural") == "tree" and
("diameter_crown" in node.tags or
"circumference" in node.tags):
"circumference" in node.tags)):
continue
ui.progress_bar(index, len(nodes), step=10, text="Drawing nodes")
self.draw_shapes(node, points)
node.draw_shapes(self.svg)
ui.progress_bar(-1, len(nodes), step=10, text="Drawing nodes")
if self.draw_captions == "no":
@ -392,52 +234,7 @@ class Painter:
for node in nodes: # type: Point
if self.mode not in [CREATION_TIME_MODE, AUTHOR_MODE]:
self.draw_texts(node)
def draw_point_shape(
self, shape_ids: List[str], point, fill: Color, tags=None):
"""
Draw one icon.
"""
if self.mode not in [CREATION_TIME_MODE, AUTHOR_MODE]:
for shape_id in shape_ids: # type: str
icon, _ = self.icon_extractor.get_path(shape_id)
self.draw_point_outline(icon, point, fill, mode=self.mode)
for shape_id in shape_ids: # type: str
icon, _ = self.icon_extractor.get_path(shape_id)
self.draw_point(icon, point, fill, tags=tags)
def draw_point(
self, icon: Icon, point: (float, float), fill: Color,
tags: Dict[str, str] = None) -> None:
point = np.array(list(map(int, point)))
title: str = "\n".join(map(lambda x: x + ": " + tags[x], tags))
path: svgwrite.path.Path = icon.get_path(self.svg, point)
path.update({"fill": fill.hex})
path.set_desc(title=title)
self.svg.add(path)
def draw_point_outline(
self, icon: Icon, point, fill: Color, mode="default"):
point = np.array(list(map(int, point)))
opacity: float = 0.5
stroke_width: float = 2.2
outline_fill: Color = self.scheme.get_color("outline_color")
if mode not in [AUTHOR_MODE, CREATION_TIME_MODE] and is_bright(fill):
outline_fill = Color("black")
opacity = 0.7
path = icon.get_path(self.svg, point)
path.update({
"fill": outline_fill.hex, "opacity": opacity,
"stroke": outline_fill.hex, "stroke-width": stroke_width,
"stroke-linejoin": "round"})
self.svg.add(path)
node.draw_texts(self.svg, self.scheme, self.draw_captions)
def check_level_number(tags: Dict[str, Any], level: float):
@ -479,6 +276,11 @@ def check_level_overground(tags: Dict[str, Any]) -> bool:
def main(argv) -> None:
"""
Röntgen entry point.
:param argv: command-line arguments
"""
if len(argv) == 2:
if argv[1] == "grid":
draw_grid()
@ -532,8 +334,8 @@ def main(argv) -> None:
flinger: Flinger = Flinger(MinMax(min1, max1), options.scale)
size: np.array = flinger.size
svg: svgwrite.Drawing = \
svgwrite.Drawing(options.output_file_name, size=size)
svg: svgwrite.Drawing = (
svgwrite.Drawing(options.output_file_name, size=size))
svg.add(Rect((0, 0), size, fill=background_color))
icon_extractor: IconExtractor = IconExtractor(ICONS_FILE_NAME)
@ -555,7 +357,8 @@ def main(argv) -> None:
return not check_level_number(x, float(options.level))
constructor: Constructor = Constructor(
check_level, options.mode, options.seed, map_, flinger, scheme)
check_level, options.mode, options.seed, map_, flinger, scheme,
icon_extractor)
if options.draw_ways:
constructor.construct_ways()
constructor.construct_relations()

219
roentgen/point.py Normal file
View file

@ -0,0 +1,219 @@
from dataclasses import dataclass
from typing import Dict, Optional, List
import numpy as np
import svgwrite
from colour import Color
from roentgen.address import get_address
from roentgen.color import is_bright
from roentgen.icon import Icon
from roentgen.osm_reader import Tagged
from roentgen.scheme import IconSet
DEFAULT_FONT: str = "Roboto"
DEFAULT_COLOR: Color = Color("#444444")
@dataclass
class TextStruct:
"""
Some label on the map with attributes.
"""
text: str
fill: Color = DEFAULT_COLOR
size: float = 10.0
def draw_point_shape(
svg: svgwrite.Drawing, icons: List[Icon], point, fill: Color,
tags=None):
"""
Draw one combined icon and its outline.
"""
# Down-cast floats to integers to make icons pixel-perfect.
point = np.array(list(map(int, point)))
# Draw outlines.
for icon in icons: # type: Icon
bright: bool = is_bright(fill)
color: Color = Color("black") if bright else Color("white")
opacity: float = 0.7 if bright else 0.5
icon.draw(svg, point, color, opacity=opacity, outline=True)
# Draw icons.
for icon in icons: # type: Icon
icon.draw(svg, point, fill, tags=tags)
def draw_text(
svg: svgwrite.Drawing, text: str, point, fill: Color,
size: float = 10.0, out_fill=Color("white"), out_opacity=1.0,
out_fill_2: Optional[Color] = None, out_opacity_2=1.0):
"""
Drawing text.
###### ### outline 2
#------# --- outline 1
#| Text |#
#------#
######
"""
if out_fill_2:
svg.add(svg.text(
text, point, font_size=size, text_anchor="middle",
font_family=DEFAULT_FONT, fill=out_fill_2.hex,
stroke_linejoin="round", stroke_width=5,
stroke=out_fill_2.hex, opacity=out_opacity_2))
if out_fill:
svg.add(svg.text(
text, point, font_size=size, text_anchor="middle",
font_family=DEFAULT_FONT, fill=out_fill.hex,
stroke_linejoin="round", stroke_width=3,
stroke=out_fill.hex, opacity=out_opacity))
svg.add(svg.text(
text, point, font_size=size, text_anchor="middle",
font_family=DEFAULT_FONT, fill=fill.hex))
def construct_text(
tags, processed, scheme, draw_captions) -> List["TextStruct"]:
"""
Construct labels for not processed tags.
"""
texts: List[TextStruct] = []
name = None
alt_name = None
if "name" in tags:
name = tags["name"]
tags.pop("name", None)
if "name:ru" in tags:
if not name:
name = tags["name:ru"]
tags.pop("name:ru", None)
tags.pop("name:ru", None)
if "name:en" in tags:
if not name:
name = tags["name:en"]
tags.pop("name:en", None)
tags.pop("name:en", None)
if "alt_name" in tags:
if alt_name:
alt_name += ", "
else:
alt_name = ""
alt_name += tags["alt_name"]
tags.pop("alt_name")
if "old_name" in tags:
if alt_name:
alt_name += ", "
else:
alt_name = ""
alt_name += "бывш. " + tags["old_name"]
address: List[str] = get_address(tags, draw_captions)
if name:
texts.append(TextStruct(name, Color("black")))
if alt_name:
texts.append(TextStruct(f"({alt_name})"))
if address:
texts.append(TextStruct(", ".join(address)))
if draw_captions == "main":
return texts
if "route_ref" in tags:
texts.append(TextStruct(tags["route_ref"].replace(";", " ")))
tags.pop("route_ref", None)
if "cladr:code" in tags:
texts.append(TextStruct(tags["cladr:code"], size=7))
tags.pop("cladr:code", None)
if "website" in tags:
link = tags["website"]
if link[:7] == "http://":
link = link[7:]
if link[:8] == "https://":
link = link[8:]
if link[:4] == "www.":
link = link[4:]
if link[-1] == "/":
link = link[:-1]
link = link[:25] + ("..." if len(tags["website"]) > 25 else "")
texts.append(TextStruct(link, Color("#000088")))
tags.pop("website", None)
for k in ["phone"]:
if k in tags:
texts.append(TextStruct(tags[k], Color("#444444")))
tags.pop(k)
for tag in tags:
if scheme.is_writable(tag) and not (tag in processed):
texts.append(TextStruct(tags[tag]))
return texts
class Point(Tagged):
"""
Object on the map with no dimensional attributes.
It may have icons and text.
"""
def __init__(
self, icon_set: IconSet, tags: Dict[str, str], point: np.array,
coordinates: np.array, priority: float = 0,
is_for_node: bool = True):
super().__init__()
assert point is not None
self.icon_set: IconSet = icon_set
self.tags: Dict[str, str] = tags
self.point: np.array = point
self.coordinates: np.array = coordinates
self.priority: float = priority
self.layer: float = 0
self.is_for_node: bool = is_for_node
self.y = 0
def draw_shapes(self, svg: svgwrite.Drawing):
"""
Draw shapes for one node.
"""
if self.icon_set.main_icon and (not self.icon_set.main_icon[0].is_default() or self.is_for_node):
draw_point_shape(
svg, self.icon_set.main_icon,
self.point + np.array((0, self.y)), self.icon_set.color,
tags=self.tags)
self.y += 16
left: float = -(len(self.icon_set.extra_icons) - 1) * 8
for shape_ids in self.icon_set.extra_icons:
draw_point_shape(
svg, shape_ids, self.point + np.array((left, self.y)),
Color("#888888"))
left += 16
if self.icon_set.extra_icons:
self.y += 16
def draw_texts(self, svg: svgwrite.Drawing, scheme, draw_captions):
"""
Draw all labels.
"""
write_tags = construct_text(
self.tags, self.icon_set.processed, scheme, draw_captions)
for text_struct in write_tags: # type: TextStruct
self.y += text_struct.size + 1
text = text_struct.text
text = text.replace("&quot;", '"')
text = text.replace("&amp;", '&')
text = text[:26] + ("..." if len(text) > 26 else "")
draw_text(
svg, text, self.point + np.array((0, self.y - 8)),
text_struct.fill, size=text_struct.size)

View file

@ -10,7 +10,7 @@ from colour import Color
from dataclasses import dataclass
from typing import Any, Dict, List, Optional, Set, Union
from roentgen.icon import DEFAULT_SHAPE_ID
from roentgen.icon import DEFAULT_SHAPE_ID, IconExtractor, Icon
DEFAULT_COLOR: Color = Color("#444444")
@ -20,7 +20,8 @@ class IconSet:
"""
Node representation: icons and color.
"""
icons: List[List[str]] # list of lists of shape identifiers
main_icon: List[Icon] # list of icons
extra_icons: List[List[Icon]] # list of lists of icons
color: Color # fill color of all icons
# tag keys that were processed to create icon set (other
# tag keys should be displayed by text or ignored)
@ -111,7 +112,9 @@ class Scheme:
return True
return False
def get_icon(self, tags: Dict[str, Any], for_: str = "node") -> IconSet:
def get_icon(
self, icon_extractor: IconExtractor, tags: Dict[str, Any],
for_: str = "node") -> IconSet:
"""
Construct icon set.
@ -123,8 +126,8 @@ class Scheme:
if tags_hash in self.cache:
return self.cache[tags_hash]
main_icon: Optional[List[str]] = None
extra_icons: List[List[str]] = []
main_icon_id: Optional[List[str]] = None
extra_icon_ids: List[List[str]] = []
processed: Set[str] = set()
fill: Color = DEFAULT_COLOR
@ -150,15 +153,15 @@ class Scheme:
if "draw" in matcher and not matcher["draw"]:
processed |= set(matcher["tags"].keys())
if "icon" in matcher:
main_icon = copy.deepcopy(matcher["icon"])
main_icon_id = copy.deepcopy(matcher["icon"])
processed |= set(matcher["tags"].keys())
if "over_icon" in matcher:
if main_icon: # TODO: check main icon in under icons
main_icon += matcher["over_icon"]
if main_icon_id: # TODO: check main icon in under icons
main_icon_id += matcher["over_icon"]
for key in matcher["tags"].keys():
processed.add(key)
if "add_icon" in matcher:
extra_icons += [matcher["add_icon"]]
extra_icon_ids += [matcher["add_icon"]]
for key in matcher["tags"].keys():
processed.add(key)
if "color" in matcher:
@ -167,26 +170,37 @@ class Scheme:
processed.add(key)
for tag_key in tags: # type: str
if (tag_key in ["color", "colour"] or tag_key.endswith(":color") or
if (tag_key.endswith(":color") or
tag_key.endswith(":colour")):
fill = self.get_color(tags[tag_key])
processed.add(tag_key)
if main_icon:
result_set: List[List[str]] = [main_icon] + extra_icons
else:
result_set: List[List[str]] = extra_icons
for tag_key in tags: # type: str
if tag_key in ["color", "colour"]:
fill = self.get_color(tags[tag_key])
processed.add(tag_key)
keys_left = list(filter(
lambda x: x not in processed and
not self.is_no_drawable(x), tags.keys()))
is_default: bool = False
if not result_set and keys_left:
result_set = [[DEFAULT_SHAPE_ID]]
if not main_icon_id and not extra_icon_ids and keys_left:
main_icon_id = [DEFAULT_SHAPE_ID]
is_default = True
returned: IconSet = IconSet(result_set, fill, processed, is_default)
main_icon: List[Icon] = []
if main_icon_id:
main_icon = list(map(
lambda x: icon_extractor.get_path(x)[0], main_icon_id))
extra_icons: List[List[Icon]] = []
for icon_id in extra_icon_ids:
extra_icons.append(list(map(
lambda x: icon_extractor.get_path(x)[0], icon_id)))
returned: IconSet = IconSet(
main_icon, extra_icons, fill, processed, is_default)
self.cache[tags_hash] = returned