Use colour; add text structure.

This commit is contained in:
Sergey Vartanov 2020-09-19 14:43:47 +03:00
parent 54b88f05d2
commit 963fb12496
9 changed files with 139 additions and 259 deletions

View file

@ -1,147 +0,0 @@
aliceblue: 'F0F8FF'
antiquewhite: 'FAEBD7'
aqua: '00FFFF'
aquamarine: '7FFFD4'
azure: 'F0FFFF'
beige: 'F5F5DC'
bisque: 'FFE4C4'
black: '000000'
blanchedalmond: 'FFEBCD'
blue: '0000FF'
blueviolet: '8A2BE2'
brown: 'A52A2A'
burlywood: 'DEB887'
cadetblue: '5F9EA0'
chartreuse: '7FFF00'
chocolate: 'D2691E'
coral: 'FF7F50'
cornflowerblue: '6495ED'
cornsilk: 'FFF8DC'
crimson: 'DC143C'
cyan: '00FFFF'
darkblue: '00008B'
darkcyan: '008B8B'
darkgoldenrod: 'B8860B'
darkgray: 'A9A9A9'
darkgreen: '006400'
darkgrey: 'A9A9A9'
darkkhaki: 'BDB76B'
darkmagenta: '8B008B'
darkolivegreen: '556B2F'
darkorange: 'FF8C00'
darkorchid: '9932CC'
darkred: '8B0000'
darksalmon: 'E9967A'
darkseagreen: '8FBC8F'
darkslateblue: '483D8B'
darkslategray: '2F4F4F'
darkslategrey: '2F4F4F'
darkturquoise: '00CED1'
darkviolet: '9400D3'
deeppink: 'FF1493'
deepskyblue: '00BFFF'
dimgray: '696969'
dimgrey: '696969'
dodgerblue: '1E90FF'
firebrick: 'B22222'
floralwhite: 'FFFAF0'
forestgreen: '228B22'
fuchsia: 'FF00FF'
gainsboro: 'DCDCDC'
ghostwhite: 'F8F8FF'
gold: 'FFD700'
goldenrod: 'DAA520'
gray: '808080'
green: '008000'
greenyellow: 'ADFF2F'
grey: '808080'
honeydew: 'F0FFF0'
hotpink: 'FF69B4'
indianred: 'CD5C5C'
indigo: '4B0082'
ivory: 'FFFFF0'
khaki: 'F0E68C'
lavender: 'E6E6FA'
lavenderblush: 'FFF0F5'
lawngreen: '7CFC00'
lemonchiffon: 'FFFACD'
lightblue: 'ADD8E6'
lightcoral: 'F08080'
lightcyan: 'E0FFFF'
lightgoldenrodyellow: 'FAFAD2'
lightgray: 'D3D3D3'
lightgreen: '90EE90'
lightgrey: 'D3D3D3'
lightpink: 'FFB6C1'
lightsalmon: 'FFA07A'
lightseagreen: '20B2AA'
lightskyblue: '87CEFA'
lightslategray: '778899'
lightslategrey: '778899'
lightsteelblue: 'B0C4DE'
lightyellow: 'FFFFE0'
lime: '00FF00'
limegreen: '32CD32'
linen: 'FAF0E6'
magenta: 'FF00FF'
maroon: '800000'
mediumaquamarine: '66CDAA'
mediumblue: '0000CD'
mediumorchid: 'BA55D3'
mediumpurple: '9370DB'
mediumseagreen: '3CB371'
mediumslateblue: '7B68EE'
mediumspringgreen: '00FA9A'
mediumturquoise: '48D1CC'
mediumvioletred: 'C71585'
midnightblue: '191970'
mintcream: 'F5FFFA'
mistyrose: 'FFE4E1'
moccasin: 'FFE4B5'
navajowhite: 'FFDEAD'
navy: '000080'
oldlace: 'FDF5E6'
olive: '808000'
olivedrab: '6B8E23'
orange: 'FFA500'
orangered: 'FF4500'
orchid: 'DA70D6'
palegoldenrod: 'EEE8AA'
palegreen: '98FB98'
paleturquoise: 'AFEEEE'
palevioletred: 'DB7093'
papayawhip: 'FFEFD5'
peachpuff: 'FFDAB9'
peru: 'CD853F'
pink: 'FFC0CB'
plum: 'DDA0DD'
powderblue: 'B0E0E6'
purple: '800080'
red: 'FF0000'
rosybrown: 'BC8F8F'
royalblue: '4169E1'
saddlebrown: '8B4513'
salmon: 'FA8072'
sandybrown: 'F4A460'
seagreen: '2E8B57'
seashell: 'FFF5EE'
sienna: 'A0522D'
silver: 'C0C0C0'
skyblue: '87CEEB'
slateblue: '6A5ACD'
slategray: '708090'
slategrey: '708090'
snow: 'FFFAFA'
springgreen: '00FF7F'
steelblue: '4682B4'
tan: 'D2B48C'
teal: '008080'
thistle: 'D8BFD8'
tomato: 'FF6347'
turquoise: '40E0D0'
violet: 'EE82EE'
wheat: 'F5DEB3'
white: 'FFFFFF'
whitesmoke: 'F5F5F5'
yellow: 'FFFF00'
yellowgreen: '9ACD32'

View file

@ -69,7 +69,7 @@ colors:
"rose": "FF007F" # Wikipedia
"slate_blue": "6A5ACD" # W3C slateblue
tags:
nodes:
# No draw
@ -120,7 +120,6 @@ tags:
- tags: {amenity: waste_basket}
icon: [waste_basket]
# Emergency
- tags: {emergency: defibrillator}
@ -148,6 +147,10 @@ tags:
icon: [cross]
- tags: {man_made: flagpole}
icon: [flagpole]
- tags: {man_made: manhole}
icon: [manhole]
- tags: {manhole: drain}
icon: [manhole_drain]
- tags: {man_made: pole}
icon: [pole]
- tags: {man_made: pole, highway: street_lamp}
@ -173,10 +176,12 @@ tags:
- tags: {power: tower}
icon: [power_tower]
- tags: {tourism: "*"}
icon: [historic]
# Information
- tags: {information: "*"}
icon: [information]
- tags: {tourism: "*"}
icon: [historic]
- tags: {tourism: information}
icon: [information]
- tags: {information: guidepost}
@ -186,6 +191,8 @@ tags:
- tags: {information: board}
icon: [information_board]
# Vending
- tags: {vending: admission_tickets}
icon: [vending_tickets]
- tags: {vending: candles}
@ -596,11 +603,6 @@ tags:
- tags: {traffic_calming: cushion}
icon: [traffic_cushion]
- tags: {man_made: manhole}
icon: [manhole]
- tags: {manhole: drain}
icon: [manhole_drain]
# Historic
- tags: {historic: "*"}

View file

@ -1,5 +1,6 @@
numpy>=1.18.1
portolan
portolan~=1.0.1
pyyaml>=4.2b1
svgwrite
svgwrite~=1.4
urllib3>=1.25.6
colour~=0.1.5

View file

@ -5,6 +5,7 @@ Author: Sergey Vartanov (me@enzet.ru).
"""
import numpy as np
from colour import Color
from datetime import datetime
from hashlib import sha256
from typing import Any, Dict, List, Optional, Set
@ -103,6 +104,13 @@ class Way:
return path
class TextStruct:
def __init__(
self, text: str, fill: Color = Color("#444444"), size: float = 10):
self.text = text
self.fill = fill
self.size = size
def line_center(nodes: List[OSMNode], flinger: Flinger) -> np.array:
"""
@ -121,12 +129,12 @@ def line_center(nodes: List[OSMNode], flinger: Flinger) -> np.array:
return flinger.fling(center_coordinates), center_coordinates
def get_user_color(text: str, seed: str):
def get_user_color(text: str, seed: str) -> Color:
"""
Generate random color based on text.
"""
if text == "":
return "#000000"
return Color("black")
rgb = sha256((seed + text).encode("utf-8")).hexdigest()[-6:]
r = int(rgb[0:2], 16)
g = int(rgb[2:4], 16)
@ -137,15 +145,15 @@ def get_user_color(text: str, seed: str):
g = g * (1 - cc) + c * cc
b = b * (1 - cc) + c * cc
h = hex(int(r))[2:] + hex(int(g))[2:] + hex(int(b))[2:]
return "#" + "0" * (6 - len(h)) + h
return Color("#" + "0" * (6 - len(h)) + h)
def get_time_color(time: Optional[datetime]):
def get_time_color(time: Optional[datetime]) -> Color:
"""
Generate color based on time.
"""
if time is None:
return "000000"
return Color("black")
delta = (datetime.now() - time).total_seconds()
time_color = hex(0xFF - min(0xFF, int(delta / 500000.)))[2:]
i_time_color = hex(min(0xFF, int(delta / 500000.)))[2:]
@ -153,7 +161,7 @@ def get_time_color(time: Optional[datetime]):
time_color = "0" + time_color
if len(i_time_color) == 1:
i_time_color = "0" + i_time_color
return "#" + time_color + "AA" + i_time_color
return Color("#" + time_color + "AA" + i_time_color)
def glue(ways: List[OSMWay]) -> List[List[OSMNode]]:
@ -214,12 +222,12 @@ class Constructor:
Röntgen node and way constructor.
"""
def __init__(
self, check_level, mode, seed, map_, flinger: Flinger,
self, check_level, mode: str, seed: str, map_, flinger: Flinger,
scheme: Scheme):
self.check_level = check_level
self.mode = mode
self.seed = seed
self.mode: str = mode
self.seed: str = seed
self.map_ = map_
self.flinger: Flinger = flinger
self.scheme: Scheme = scheme
@ -282,7 +290,7 @@ class Constructor:
user_color = get_user_color(way.user, self.seed)
self.ways.append(
Way("way", inners, outers,
{"fill": "none", "stroke": user_color,
{"fill": "none", "stroke": user_color.hex,
"stroke-width": 1}))
return
@ -292,14 +300,14 @@ class Constructor:
time_color = get_time_color(way.timestamp)
self.ways.append(
Way("way", inners, outers,
{"fill": "none", "stroke": time_color,
{"fill": "none", "stroke": time_color.hex,
"stroke-width": 1}))
return
if not tags:
return
appended = False
appended: bool = False
kind: str = "way"
levels = None
@ -323,9 +331,9 @@ class Constructor:
break
if "no_tags" in element:
for config_tag_key in element["no_tags"]: # type: str
if config_tag_key in tags and \
tags[config_tag_key] == \
element["no_tags"][config_tag_key]:
if (config_tag_key in tags and
tags[config_tag_key] ==
element["no_tags"][config_tag_key]):
matched = False
break
if matched:
@ -360,7 +368,8 @@ class Constructor:
if not appended:
if DEBUG:
style: Dict[str, Any] = {
"fill": "none", "stroke": "#FF0000", "stroke-width": 1}
"fill": "none", "stroke": Color("red").hex,
"stroke-width": 1}
self.ways.append(Way(
kind, inners, outers, style, layer, levels))
if center_point is not None and (way.is_cycle() or

View file

@ -58,6 +58,7 @@ class Sector:
"""
Sector described by two vectors.
"""
def __init__(self, text: str, angle: Optional[float] = None):
"""
:param text: sector text representation. E.g. "70-210", "N-NW"
@ -107,11 +108,12 @@ class DirectionSet:
"""
Describes direction, set of directions.
"""
def __init__(self, text: str):
"""
:param text: direction tag value
"""
self.sectors = list(map(Sector, text.split(";")))
self.sectors: Iterator[Optional[Sector]] = map(Sector, text.split(";"))
def __str__(self):
return ", ".join(map(str, self.sectors))

View file

@ -31,7 +31,7 @@ def draw_grid(step: float = 24, columns: int = 16):
to_draw = []
for element in scheme["tags"]:
for element in scheme["nodes"]:
if "icon" in element:
if set(element["icon"]) not in to_draw:
to_draw.append(set(element["icon"]))

View file

@ -8,15 +8,16 @@ import os
import svgwrite
import sys
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
from typing import Any, Dict, List, Optional
from roentgen import ui
from roentgen.address import get_address
from roentgen.constructor import Constructor, Node, Way
from roentgen.constructor import Constructor, Node, Way, TextStruct
from roentgen.flinger import Flinger
from roentgen.grid import draw_grid
from roentgen.extract_icon import Icon, IconExtractor
@ -24,21 +25,23 @@ from roentgen.osm_getter import get_osm
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.util import MinMax, is_bright
ICONS_FILE_NAME: str = "icons/icons.svg"
TAGS_FILE_NAME: str = "data/tags.yml"
COLORS_FILE_NAME: str = "data/colors.yml"
MISSING_TAGS_FILE_NAME: str = "missing_tags.yml"
AUTHOR_MODE = "user-coloring"
CREATION_TIME_MODE = "time"
DEFAULT_FONT = "Roboto"
class Painter:
"""
Map drawing.
"""
def __init__(
self, show_missing_tags: bool, overlap: int, draw_nodes: bool,
mode: str, draw_captions: str, map_: Map, flinger: Flinger,
@ -97,17 +100,15 @@ class Painter:
write_tags = self.construct_text(node.tags, node.icon_set.processed)
for text_struct in write_tags:
fill = text_struct["fill"] if "fill" in text_struct else "#444444"
size = text_struct["size"] if "size" in text_struct else 10
text_y += size + 1
text = text_struct["text"]
for text_struct in write_tags: # type: TextStruct
text_y += text_struct.size + 1
text = text_struct.text
text = text.replace(""", '"')
text = text.replace("&", '&')
text = text[:26] + ("..." if len(text) > 26 else "")
self.draw_text(
text, (node.point[0], node.point[1] + text_y + 8),
fill, size=size)
text_struct.fill, size=text_struct.size)
if self.show_missing_tags:
for tag in node.tags: # type: str
@ -116,12 +117,13 @@ class Painter:
text = f"{tag}: {node.tags[tag]}"
self.draw_text(
text, (node.point[0], node.point[1] + text_y + 18),
"#734A08")
Color("#734A08"))
text_y += 10
def draw_text(
self, text: str, point, fill, size=10, out_fill="#FFFFFF",
out_opacity=1.0, out_fill_2=None, out_opacity_2=1.0):
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.
@ -134,24 +136,25 @@ class Painter:
if out_fill_2:
self.svg.add(Text(
text, point, font_size=size, text_anchor="middle",
font_family="Roboto", fill=out_fill_2,
font_family=DEFAULT_FONT, fill=out_fill_2.hex,
stroke_linejoin="round", stroke_width=5,
stroke=out_fill_2, opacity=out_opacity_2))
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="Roboto", fill=out_fill,
font_family=DEFAULT_FONT, fill=out_fill.hex,
stroke_linejoin="round", stroke_width=3,
stroke=out_fill, opacity=out_opacity))
stroke=out_fill.hex, opacity=out_opacity))
self.svg.add(Text(
text, point, font_size=size, text_anchor="middle",
font_family="Roboto", fill=fill))
font_family=DEFAULT_FONT, fill=fill.hex))
def construct_text(self, tags, processed):
"""
Construct labels for not processed tags.
"""
texts = []
texts: List[TextStruct] = []
name = None
alt_name = None
if "name" in tags:
@ -184,20 +187,20 @@ class Painter:
address = get_address(tags, self.draw_captions)
if name:
texts.append({"text": name, "fill": "#000000"})
texts.append(TextStruct(name, Color("black")))
if alt_name:
texts.append({"text": "(" + alt_name + ")"})
texts.append(TextStruct("(" + alt_name + ")"))
if address:
texts.append({"text": ", ".join(address)})
texts.append(TextStruct(", ".join(address)))
if self.draw_captions == "main":
return texts
if "route_ref" in tags:
texts.append({"text": tags["route_ref"].replace(";", " ")})
texts.append(TextStruct(tags["route_ref"].replace(";", " ")))
tags.pop("route_ref", None)
if "cladr:code" in tags:
texts.append({"text": tags["cladr:code"], "size": 7})
texts.append(TextStruct(tags["cladr:code"], size=7))
tags.pop("cladr:code", None)
if "website" in tags:
link = tags["website"]
@ -210,18 +213,18 @@ class Painter:
if link[-1] == "/":
link = link[:-1]
link = link[:25] + ("..." if len(tags["website"]) > 25 else "")
texts.append({"text": link, "fill": "#000088"})
texts.append(TextStruct(link, Color("#000088")))
tags.pop("website", None)
for k in ["phone"]:
if k in tags:
texts.append({"text": tags[k], "fill": "#444444"})
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({"text": tags[tag]})
texts.append(TextStruct(tags[tag]))
return texts
def draw_building_walls(self, stage, color, ways):
def draw_building_walls(self, stage, color: Color, ways):
"""
Draw area between way and way shifted by the vector.
"""
@ -251,7 +254,7 @@ class Painter:
d=("M", np.add(flung_1, shift_1), "L",
np.add(flung_2, shift_1), np.add(flung_2, shift_2),
np.add(flung_1, shift_2), "Z"),
fill=color, stroke=color, stroke_width=1))
fill=color.hex, stroke=color.hex, stroke_width=1))
def draw(self, nodes: List[Node], ways: List[Way], points):
"""
@ -289,9 +292,9 @@ class Painter:
# Building walls
self.draw_building_walls(1, "#AAAAAA", ways)
self.draw_building_walls(2, "#C3C3C3", ways)
self.draw_building_walls(3, "#DDDDDD", ways)
self.draw_building_walls(1, Color("#AAAAAA"), ways)
self.draw_building_walls(2, Color("#C3C3C3"), ways)
self.draw_building_walls(3, Color("#DDDDDD"), ways)
# Building roof
@ -321,7 +324,7 @@ class Painter:
# Trees
for node in nodes:
if not(node.get_tag("natural") == "tree" and
if not (node.get_tag("natural") == "tree" and
("diameter_crown" in node.tags or
"circumference" in node.tags)):
continue
@ -359,7 +362,7 @@ class Painter:
direction = node.get_tag("direction")
direction_radius: float = \
25 * self.flinger.get_scale(node.coordinates)
direction_color: str = "#FF0000"
direction_color: str = Color("red")
else:
direction = node.get_tag("direction")
direction_radius: float = \
@ -384,12 +387,12 @@ class Painter:
gradientUnits="userSpaceOnUse"))
if is_revert_gradient:
gradient \
.add_stop_color(0, direction_color, opacity=0) \
.add_stop_color(1, direction_color, opacity=0.7)
.add_stop_color(0, direction_color.hex, opacity=0) \
.add_stop_color(1, direction_color.hex, opacity=0.7)
else:
gradient \
.add_stop_color(0, direction_color, opacity=0.4) \
.add_stop_color(1, direction_color, opacity=0)
.add_stop_color(0, direction_color.hex, opacity=0.4) \
.add_stop_color(1, direction_color.hex, opacity=0)
self.svg.add(self.svg.path(
d=["M", point] + path + ["L", point, "Z"],
fill=gradient.get_paint_server()))
@ -413,7 +416,8 @@ class Painter:
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, tags=None):
def draw_point_shape(
self, shape_ids: List[str], point, fill: Color, tags=None):
"""
Draw one icon.
"""
@ -426,37 +430,34 @@ class Painter:
self.draw_point(icon, point, fill, tags=tags)
def draw_point(
self, icon: Icon, point: (float, float), fill: str,
self, icon: Icon, point: (float, float), fill: Color,
tags: Dict[str, str] = None) -> None:
point = np.array(list(map(lambda x: int(x), 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})
path.update({"fill": fill.hex})
path.set_desc(title=title)
self.svg.add(path)
def draw_point_outline(self, icon: Icon, point, fill, mode="default"):
def draw_point_outline(
self, icon: Icon, point, fill: Color, mode="default"):
point = np.array(list(map(lambda x: int(x), point)))
opacity = 0.5
stroke_width = 2.2
outline_fill = self.scheme.get_color("outline_color")
if mode not in [AUTHOR_MODE, CREATION_TIME_MODE]:
r = int(fill[1:3], 16)
g = int(fill[3:5], 16)
b = int(fill[5:7], 16)
Y = 0.2126 * r + 0.7152 * g + 0.0722 * b
if Y > 200:
outline_fill = "#000000"
opacity = 0.7
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, "opacity": opacity,
"stroke": outline_fill, "stroke-width": stroke_width,
"fill": outline_fill.hex, "opacity": opacity,
"stroke": outline_fill.hex, "stroke-width": stroke_width,
"stroke-linejoin": "round"})
self.svg.add(path)
@ -510,9 +511,9 @@ def main(argv):
if not options:
sys.exit(1)
background_color = "#EEEEEE"
background_color: Color = Color("#EEEEEE")
if options.mode in [AUTHOR_MODE, CREATION_TIME_MODE]:
background_color = "#111111"
background_color: Color = Color("#111111")
if options.input_file_name:
input_file_name = options.input_file_name
@ -546,7 +547,7 @@ def main(argv):
missing_tags = {}
points = []
scheme: Scheme = Scheme(TAGS_FILE_NAME, COLORS_FILE_NAME)
scheme: Scheme = Scheme(TAGS_FILE_NAME)
min1: np.array = np.array((boundary_box[1], boundary_box[0]))
max1: np.array = np.array((boundary_box[3], boundary_box[2]))
@ -626,7 +627,7 @@ def draw_index(flinger, map_, max1, min1, svg):
if (0 <= i < lat_number) and (0 <= j < lon_number):
matrix[i][j] += 1
if "tags" in node:
matrix[i][j] += len(node.tags)
matrix[i][j] += len(node.nodes)
for way_id in map_.way_map: # type: int
way = map_.way_map[way_id]
if "tags" in way:
@ -635,7 +636,7 @@ def draw_index(flinger, map_, max1, min1, svg):
i = int((node[0] - min1[0]) / lat_step)
j = int((node[1] - min1[1]) / lon_step)
if (0 <= i < lat_number) and (0 <= j < lon_number):
matrix[i][j] += len(way.tags) / float(
matrix[i][j] += len(way.nodes) / float(
len(way.nodes))
for i in range(lat_number):
for j in range(lon_number):

View file

@ -6,11 +6,12 @@ Author: Sergey Vartanov (me@enzet.ru).
import copy
import yaml
from colour import Color
from typing import Any, Dict, List, Optional, Set
from roentgen.extract_icon import DEFAULT_SHAPE_ID
DEFAULT_COLOR: str = "#444444"
DEFAULT_COLOR: Color = Color("#444444")
class IconSet:
@ -18,7 +19,7 @@ class IconSet:
Node representation: icons and color.
"""
def __init__(
self, icons: List[List[str]], color: str, processed: Set[str],
self, icons: List[List[str]], color: Color, processed: Set[str],
is_default: bool):
"""
:param icons: list of lists of shape identifiers
@ -27,7 +28,7 @@ class IconSet:
tag keys should be displayed by text or ignored)
"""
self.icons: List[List[str]] = icons
self.color: str = color
self.color: Color = color
self.processed: Set[str] = processed
self.is_default = is_default
@ -38,23 +39,18 @@ class Scheme:
Specifies map colors and rules to draw icons for OpenStreetMap tags.
"""
def __init__(self, file_name: str, color_file_name: str):
def __init__(self, file_name: str):
"""
:param file_name: scheme file name with tags, colors, and tag key
specification
:param color_file_name: additional color scheme
"""
content: Dict[str, Any] = \
yaml.load(open(file_name).read(), Loader=yaml.FullLoader)
self.tags: List[Dict[str, Any]] = content["tags"]
self.nodes: List[Dict[str, Any]] = content["nodes"]
self.ways: List[Dict[str, Any]] = content["ways"]
self.colors: Dict[str, str] = content["colors"]
w3c_colors: Dict[str, str] = \
yaml.load(open(color_file_name), Loader=yaml.FullLoader)
self.colors.update(w3c_colors)
self.tags_to_write: List[str] = content["tags_to_write"]
self.prefix_to_write: List[str] = content["prefix_to_write"]
@ -64,18 +60,20 @@ class Scheme:
# Storage for created icon sets.
self.cache: Dict[str, IconSet] = {}
def get_color(self, color: str) -> str:
def get_color(self, color: str) -> Color:
"""
Return color if the color is in scheme, otherwise return default color.
:return: 6-digit color specification with "#"
"""
if color in self.colors:
return "#" + self.colors[color]
return Color("#" + self.colors[color])
if color.lower() in self.colors:
return "#" + self.colors[color.lower()]
if color.startswith("#"):
return color
return Color("#" + self.colors[color.lower()])
try:
return Color(color)
except ValueError:
pass
return DEFAULT_COLOR
@ -124,12 +122,12 @@ class Scheme:
main_icon: Optional[List[str]] = None
extra_icons: List[List[str]] = []
processed = set()
fill = DEFAULT_COLOR
processed: Set[str] = set()
fill: Color = DEFAULT_COLOR
for matcher in self.tags:
matched = True
for key in matcher["tags"]:
for matcher in self.nodes: # type: Dict[str, Any]
matched: bool = True
for key in matcher["tags"]: # type: str
if key not in tags:
matched = False
break
@ -173,10 +171,12 @@ class Scheme:
else:
result_set: List[List[str]] = extra_icons
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 \
list(filter(lambda x: x not in processed and
not self.is_no_drawable(x), tags.keys())):
if not result_set and keys_left:
result_set = [[DEFAULT_SHAPE_ID]]
is_default = True

View file

@ -1,3 +1,6 @@
from colour import Color
class MinMax:
"""
Minimum and maximum.
@ -21,3 +24,12 @@ class MinMax:
def center(self):
return (self.min_ + self.max_) / 2
def is_bright(color: Color) -> bool:
"""
Is color bright enough to have black outline instead of white.
"""
return (
0.2126 * color.red * 256 +
0.7152 * color.green * 256 +
0.0722 * color.blue * 256 > 200)