mirror of
https://github.com/enzet/map-machine.git
synced 2025-05-22 21:46:24 +02:00
Use colour; add text structure.
This commit is contained in:
parent
54b88f05d2
commit
963fb12496
9 changed files with 139 additions and 259 deletions
147
data/colors.yml
147
data/colors.yml
|
@ -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'
|
|
|
@ -69,7 +69,7 @@ colors:
|
||||||
"rose": "FF007F" # Wikipedia
|
"rose": "FF007F" # Wikipedia
|
||||||
"slate_blue": "6A5ACD" # W3C slateblue
|
"slate_blue": "6A5ACD" # W3C slateblue
|
||||||
|
|
||||||
tags:
|
nodes:
|
||||||
|
|
||||||
# No draw
|
# No draw
|
||||||
|
|
||||||
|
@ -120,7 +120,6 @@ tags:
|
||||||
- tags: {amenity: waste_basket}
|
- tags: {amenity: waste_basket}
|
||||||
icon: [waste_basket]
|
icon: [waste_basket]
|
||||||
|
|
||||||
|
|
||||||
# Emergency
|
# Emergency
|
||||||
|
|
||||||
- tags: {emergency: defibrillator}
|
- tags: {emergency: defibrillator}
|
||||||
|
@ -148,6 +147,10 @@ tags:
|
||||||
icon: [cross]
|
icon: [cross]
|
||||||
- tags: {man_made: flagpole}
|
- tags: {man_made: flagpole}
|
||||||
icon: [flagpole]
|
icon: [flagpole]
|
||||||
|
- tags: {man_made: manhole}
|
||||||
|
icon: [manhole]
|
||||||
|
- tags: {manhole: drain}
|
||||||
|
icon: [manhole_drain]
|
||||||
- tags: {man_made: pole}
|
- tags: {man_made: pole}
|
||||||
icon: [pole]
|
icon: [pole]
|
||||||
- tags: {man_made: pole, highway: street_lamp}
|
- tags: {man_made: pole, highway: street_lamp}
|
||||||
|
@ -173,10 +176,12 @@ tags:
|
||||||
- tags: {power: tower}
|
- tags: {power: tower}
|
||||||
icon: [power_tower]
|
icon: [power_tower]
|
||||||
|
|
||||||
- tags: {tourism: "*"}
|
# Information
|
||||||
icon: [historic]
|
|
||||||
- tags: {information: "*"}
|
- tags: {information: "*"}
|
||||||
icon: [information]
|
icon: [information]
|
||||||
|
- tags: {tourism: "*"}
|
||||||
|
icon: [historic]
|
||||||
- tags: {tourism: information}
|
- tags: {tourism: information}
|
||||||
icon: [information]
|
icon: [information]
|
||||||
- tags: {information: guidepost}
|
- tags: {information: guidepost}
|
||||||
|
@ -186,6 +191,8 @@ tags:
|
||||||
- tags: {information: board}
|
- tags: {information: board}
|
||||||
icon: [information_board]
|
icon: [information_board]
|
||||||
|
|
||||||
|
# Vending
|
||||||
|
|
||||||
- tags: {vending: admission_tickets}
|
- tags: {vending: admission_tickets}
|
||||||
icon: [vending_tickets]
|
icon: [vending_tickets]
|
||||||
- tags: {vending: candles}
|
- tags: {vending: candles}
|
||||||
|
@ -596,11 +603,6 @@ tags:
|
||||||
- tags: {traffic_calming: cushion}
|
- tags: {traffic_calming: cushion}
|
||||||
icon: [traffic_cushion]
|
icon: [traffic_cushion]
|
||||||
|
|
||||||
- tags: {man_made: manhole}
|
|
||||||
icon: [manhole]
|
|
||||||
- tags: {manhole: drain}
|
|
||||||
icon: [manhole_drain]
|
|
||||||
|
|
||||||
# Historic
|
# Historic
|
||||||
|
|
||||||
- tags: {historic: "*"}
|
- tags: {historic: "*"}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
numpy>=1.18.1
|
numpy>=1.18.1
|
||||||
portolan
|
portolan~=1.0.1
|
||||||
pyyaml>=4.2b1
|
pyyaml>=4.2b1
|
||||||
svgwrite
|
svgwrite~=1.4
|
||||||
urllib3>=1.25.6
|
urllib3>=1.25.6
|
||||||
|
colour~=0.1.5
|
|
@ -5,6 +5,7 @@ Author: Sergey Vartanov (me@enzet.ru).
|
||||||
"""
|
"""
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
from colour import Color
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from typing import Any, Dict, List, Optional, Set
|
from typing import Any, Dict, List, Optional, Set
|
||||||
|
@ -103,6 +104,13 @@ class Way:
|
||||||
|
|
||||||
return path
|
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:
|
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
|
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.
|
Generate random color based on text.
|
||||||
"""
|
"""
|
||||||
if text == "":
|
if text == "":
|
||||||
return "#000000"
|
return Color("black")
|
||||||
rgb = sha256((seed + text).encode("utf-8")).hexdigest()[-6:]
|
rgb = sha256((seed + text).encode("utf-8")).hexdigest()[-6:]
|
||||||
r = int(rgb[0:2], 16)
|
r = int(rgb[0:2], 16)
|
||||||
g = int(rgb[2:4], 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
|
g = g * (1 - cc) + c * cc
|
||||||
b = b * (1 - cc) + c * cc
|
b = b * (1 - cc) + c * cc
|
||||||
h = hex(int(r))[2:] + hex(int(g))[2:] + hex(int(b))[2:]
|
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.
|
Generate color based on time.
|
||||||
"""
|
"""
|
||||||
if time is None:
|
if time is None:
|
||||||
return "000000"
|
return Color("black")
|
||||||
delta = (datetime.now() - time).total_seconds()
|
delta = (datetime.now() - time).total_seconds()
|
||||||
time_color = hex(0xFF - min(0xFF, int(delta / 500000.)))[2:]
|
time_color = hex(0xFF - min(0xFF, int(delta / 500000.)))[2:]
|
||||||
i_time_color = hex(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
|
time_color = "0" + time_color
|
||||||
if len(i_time_color) == 1:
|
if len(i_time_color) == 1:
|
||||||
i_time_color = "0" + i_time_color
|
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]]:
|
def glue(ways: List[OSMWay]) -> List[List[OSMNode]]:
|
||||||
|
@ -214,12 +222,12 @@ class Constructor:
|
||||||
Röntgen node and way constructor.
|
Röntgen node and way constructor.
|
||||||
"""
|
"""
|
||||||
def __init__(
|
def __init__(
|
||||||
self, check_level, mode, seed, map_, flinger: Flinger,
|
self, check_level, mode: str, seed: str, map_, flinger: Flinger,
|
||||||
scheme: Scheme):
|
scheme: Scheme):
|
||||||
|
|
||||||
self.check_level = check_level
|
self.check_level = check_level
|
||||||
self.mode = mode
|
self.mode: str = mode
|
||||||
self.seed = seed
|
self.seed: str = seed
|
||||||
self.map_ = map_
|
self.map_ = map_
|
||||||
self.flinger: Flinger = flinger
|
self.flinger: Flinger = flinger
|
||||||
self.scheme: Scheme = scheme
|
self.scheme: Scheme = scheme
|
||||||
|
@ -282,7 +290,7 @@ class Constructor:
|
||||||
user_color = get_user_color(way.user, self.seed)
|
user_color = get_user_color(way.user, self.seed)
|
||||||
self.ways.append(
|
self.ways.append(
|
||||||
Way("way", inners, outers,
|
Way("way", inners, outers,
|
||||||
{"fill": "none", "stroke": user_color,
|
{"fill": "none", "stroke": user_color.hex,
|
||||||
"stroke-width": 1}))
|
"stroke-width": 1}))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -292,14 +300,14 @@ class Constructor:
|
||||||
time_color = get_time_color(way.timestamp)
|
time_color = get_time_color(way.timestamp)
|
||||||
self.ways.append(
|
self.ways.append(
|
||||||
Way("way", inners, outers,
|
Way("way", inners, outers,
|
||||||
{"fill": "none", "stroke": time_color,
|
{"fill": "none", "stroke": time_color.hex,
|
||||||
"stroke-width": 1}))
|
"stroke-width": 1}))
|
||||||
return
|
return
|
||||||
|
|
||||||
if not tags:
|
if not tags:
|
||||||
return
|
return
|
||||||
|
|
||||||
appended = False
|
appended: bool = False
|
||||||
kind: str = "way"
|
kind: str = "way"
|
||||||
levels = None
|
levels = None
|
||||||
|
|
||||||
|
@ -323,9 +331,9 @@ class Constructor:
|
||||||
break
|
break
|
||||||
if "no_tags" in element:
|
if "no_tags" in element:
|
||||||
for config_tag_key in element["no_tags"]: # type: str
|
for config_tag_key in element["no_tags"]: # type: str
|
||||||
if config_tag_key in tags and \
|
if (config_tag_key in tags and
|
||||||
tags[config_tag_key] == \
|
tags[config_tag_key] ==
|
||||||
element["no_tags"][config_tag_key]:
|
element["no_tags"][config_tag_key]):
|
||||||
matched = False
|
matched = False
|
||||||
break
|
break
|
||||||
if matched:
|
if matched:
|
||||||
|
@ -360,7 +368,8 @@ class Constructor:
|
||||||
if not appended:
|
if not appended:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
style: Dict[str, Any] = {
|
style: Dict[str, Any] = {
|
||||||
"fill": "none", "stroke": "#FF0000", "stroke-width": 1}
|
"fill": "none", "stroke": Color("red").hex,
|
||||||
|
"stroke-width": 1}
|
||||||
self.ways.append(Way(
|
self.ways.append(Way(
|
||||||
kind, inners, outers, style, layer, levels))
|
kind, inners, outers, style, layer, levels))
|
||||||
if center_point is not None and (way.is_cycle() or
|
if center_point is not None and (way.is_cycle() or
|
||||||
|
|
|
@ -58,6 +58,7 @@ class Sector:
|
||||||
"""
|
"""
|
||||||
Sector described by two vectors.
|
Sector described by two vectors.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, text: str, angle: Optional[float] = None):
|
def __init__(self, text: str, angle: Optional[float] = None):
|
||||||
"""
|
"""
|
||||||
:param text: sector text representation. E.g. "70-210", "N-NW"
|
:param text: sector text representation. E.g. "70-210", "N-NW"
|
||||||
|
@ -107,11 +108,12 @@ class DirectionSet:
|
||||||
"""
|
"""
|
||||||
Describes direction, set of directions.
|
Describes direction, set of directions.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, text: str):
|
def __init__(self, text: str):
|
||||||
"""
|
"""
|
||||||
:param text: direction tag value
|
:param text: direction tag value
|
||||||
"""
|
"""
|
||||||
self.sectors = list(map(Sector, text.split(";")))
|
self.sectors: Iterator[Optional[Sector]] = map(Sector, text.split(";"))
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return ", ".join(map(str, self.sectors))
|
return ", ".join(map(str, self.sectors))
|
||||||
|
|
|
@ -31,7 +31,7 @@ def draw_grid(step: float = 24, columns: int = 16):
|
||||||
|
|
||||||
to_draw = []
|
to_draw = []
|
||||||
|
|
||||||
for element in scheme["tags"]:
|
for element in scheme["nodes"]:
|
||||||
if "icon" in element:
|
if "icon" in element:
|
||||||
if set(element["icon"]) not in to_draw:
|
if set(element["icon"]) not in to_draw:
|
||||||
to_draw.append(set(element["icon"]))
|
to_draw.append(set(element["icon"]))
|
||||||
|
|
|
@ -8,15 +8,16 @@ import os
|
||||||
import svgwrite
|
import svgwrite
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from colour import Color
|
||||||
from svgwrite.container import Group
|
from svgwrite.container import Group
|
||||||
from svgwrite.path import Path
|
from svgwrite.path import Path
|
||||||
from svgwrite.shapes import Rect
|
from svgwrite.shapes import Rect
|
||||||
from svgwrite.text import Text
|
from svgwrite.text import Text
|
||||||
from typing import Any, Dict, List
|
from typing import Any, Dict, List, Optional
|
||||||
|
|
||||||
from roentgen import ui
|
from roentgen import ui
|
||||||
from roentgen.address import get_address
|
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.flinger import Flinger
|
||||||
from roentgen.grid import draw_grid
|
from roentgen.grid import draw_grid
|
||||||
from roentgen.extract_icon import Icon, IconExtractor
|
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.osm_reader import Map, OSMReader
|
||||||
from roentgen.scheme import Scheme
|
from roentgen.scheme import Scheme
|
||||||
from roentgen.direction import DirectionSet, Sector
|
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"
|
ICONS_FILE_NAME: str = "icons/icons.svg"
|
||||||
TAGS_FILE_NAME: str = "data/tags.yml"
|
TAGS_FILE_NAME: str = "data/tags.yml"
|
||||||
COLORS_FILE_NAME: str = "data/colors.yml"
|
|
||||||
MISSING_TAGS_FILE_NAME: str = "missing_tags.yml"
|
MISSING_TAGS_FILE_NAME: str = "missing_tags.yml"
|
||||||
|
|
||||||
AUTHOR_MODE = "user-coloring"
|
AUTHOR_MODE = "user-coloring"
|
||||||
CREATION_TIME_MODE = "time"
|
CREATION_TIME_MODE = "time"
|
||||||
|
|
||||||
|
DEFAULT_FONT = "Roboto"
|
||||||
|
|
||||||
|
|
||||||
class Painter:
|
class Painter:
|
||||||
"""
|
"""
|
||||||
Map drawing.
|
Map drawing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, show_missing_tags: bool, overlap: int, draw_nodes: bool,
|
self, show_missing_tags: bool, overlap: int, draw_nodes: bool,
|
||||||
mode: str, draw_captions: str, map_: Map, flinger: Flinger,
|
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)
|
write_tags = self.construct_text(node.tags, node.icon_set.processed)
|
||||||
|
|
||||||
for text_struct in write_tags:
|
for text_struct in write_tags: # type: TextStruct
|
||||||
fill = text_struct["fill"] if "fill" in text_struct else "#444444"
|
text_y += text_struct.size + 1
|
||||||
size = text_struct["size"] if "size" in text_struct else 10
|
text = text_struct.text
|
||||||
text_y += size + 1
|
|
||||||
text = text_struct["text"]
|
|
||||||
text = text.replace(""", '"')
|
text = text.replace(""", '"')
|
||||||
text = text.replace("&", '&')
|
text = text.replace("&", '&')
|
||||||
text = text[:26] + ("..." if len(text) > 26 else "")
|
text = text[:26] + ("..." if len(text) > 26 else "")
|
||||||
self.draw_text(
|
self.draw_text(
|
||||||
text, (node.point[0], node.point[1] + text_y + 8),
|
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:
|
if self.show_missing_tags:
|
||||||
for tag in node.tags: # type: str
|
for tag in node.tags: # type: str
|
||||||
|
@ -116,12 +117,13 @@ class Painter:
|
||||||
text = f"{tag}: {node.tags[tag]}"
|
text = f"{tag}: {node.tags[tag]}"
|
||||||
self.draw_text(
|
self.draw_text(
|
||||||
text, (node.point[0], node.point[1] + text_y + 18),
|
text, (node.point[0], node.point[1] + text_y + 18),
|
||||||
"#734A08")
|
Color("#734A08"))
|
||||||
text_y += 10
|
text_y += 10
|
||||||
|
|
||||||
def draw_text(
|
def draw_text(
|
||||||
self, text: str, point, fill, size=10, out_fill="#FFFFFF",
|
self, text: str, point, fill: Color, size: float = 10,
|
||||||
out_opacity=1.0, out_fill_2=None, out_opacity_2=1.0):
|
out_fill=Color("white"), out_opacity=1.0,
|
||||||
|
out_fill_2: Optional[Color] = None, out_opacity_2=1.0):
|
||||||
"""
|
"""
|
||||||
Drawing text.
|
Drawing text.
|
||||||
|
|
||||||
|
@ -134,24 +136,25 @@ class Painter:
|
||||||
if out_fill_2:
|
if out_fill_2:
|
||||||
self.svg.add(Text(
|
self.svg.add(Text(
|
||||||
text, point, font_size=size, text_anchor="middle",
|
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_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:
|
if out_fill:
|
||||||
self.svg.add(Text(
|
self.svg.add(Text(
|
||||||
text, point, font_size=size, text_anchor="middle",
|
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_linejoin="round", stroke_width=3,
|
||||||
stroke=out_fill, opacity=out_opacity))
|
stroke=out_fill.hex, opacity=out_opacity))
|
||||||
self.svg.add(Text(
|
self.svg.add(Text(
|
||||||
text, point, font_size=size, text_anchor="middle",
|
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):
|
def construct_text(self, tags, processed):
|
||||||
"""
|
"""
|
||||||
Construct labels for not processed tags.
|
Construct labels for not processed tags.
|
||||||
"""
|
"""
|
||||||
texts = []
|
texts: List[TextStruct] = []
|
||||||
|
|
||||||
name = None
|
name = None
|
||||||
alt_name = None
|
alt_name = None
|
||||||
if "name" in tags:
|
if "name" in tags:
|
||||||
|
@ -184,20 +187,20 @@ class Painter:
|
||||||
address = get_address(tags, self.draw_captions)
|
address = get_address(tags, self.draw_captions)
|
||||||
|
|
||||||
if name:
|
if name:
|
||||||
texts.append({"text": name, "fill": "#000000"})
|
texts.append(TextStruct(name, Color("black")))
|
||||||
if alt_name:
|
if alt_name:
|
||||||
texts.append({"text": "(" + alt_name + ")"})
|
texts.append(TextStruct("(" + alt_name + ")"))
|
||||||
if address:
|
if address:
|
||||||
texts.append({"text": ", ".join(address)})
|
texts.append(TextStruct(", ".join(address)))
|
||||||
|
|
||||||
if self.draw_captions == "main":
|
if self.draw_captions == "main":
|
||||||
return texts
|
return texts
|
||||||
|
|
||||||
if "route_ref" in tags:
|
if "route_ref" in tags:
|
||||||
texts.append({"text": tags["route_ref"].replace(";", " ")})
|
texts.append(TextStruct(tags["route_ref"].replace(";", " ")))
|
||||||
tags.pop("route_ref", None)
|
tags.pop("route_ref", None)
|
||||||
if "cladr:code" in tags:
|
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)
|
tags.pop("cladr:code", None)
|
||||||
if "website" in tags:
|
if "website" in tags:
|
||||||
link = tags["website"]
|
link = tags["website"]
|
||||||
|
@ -210,18 +213,18 @@ class Painter:
|
||||||
if link[-1] == "/":
|
if link[-1] == "/":
|
||||||
link = link[:-1]
|
link = link[:-1]
|
||||||
link = link[:25] + ("..." if len(tags["website"]) > 25 else "")
|
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)
|
tags.pop("website", None)
|
||||||
for k in ["phone"]:
|
for k in ["phone"]:
|
||||||
if k in tags:
|
if k in tags:
|
||||||
texts.append({"text": tags[k], "fill": "#444444"})
|
texts.append(TextStruct(tags[k], Color("#444444")))
|
||||||
tags.pop(k)
|
tags.pop(k)
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
if self.scheme.is_writable(tag) and not (tag in processed):
|
if self.scheme.is_writable(tag) and not (tag in processed):
|
||||||
texts.append({"text": tags[tag]})
|
texts.append(TextStruct(tags[tag]))
|
||||||
return texts
|
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.
|
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",
|
d=("M", np.add(flung_1, shift_1), "L",
|
||||||
np.add(flung_2, shift_1), np.add(flung_2, shift_2),
|
np.add(flung_2, shift_1), np.add(flung_2, shift_2),
|
||||||
np.add(flung_1, shift_2), "Z"),
|
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):
|
def draw(self, nodes: List[Node], ways: List[Way], points):
|
||||||
"""
|
"""
|
||||||
|
@ -289,9 +292,9 @@ class Painter:
|
||||||
|
|
||||||
# Building walls
|
# Building walls
|
||||||
|
|
||||||
self.draw_building_walls(1, "#AAAAAA", ways)
|
self.draw_building_walls(1, Color("#AAAAAA"), ways)
|
||||||
self.draw_building_walls(2, "#C3C3C3", ways)
|
self.draw_building_walls(2, Color("#C3C3C3"), ways)
|
||||||
self.draw_building_walls(3, "#DDDDDD", ways)
|
self.draw_building_walls(3, Color("#DDDDDD"), ways)
|
||||||
|
|
||||||
# Building roof
|
# Building roof
|
||||||
|
|
||||||
|
@ -321,7 +324,7 @@ class Painter:
|
||||||
# Trees
|
# Trees
|
||||||
|
|
||||||
for node in nodes:
|
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
|
("diameter_crown" in node.tags or
|
||||||
"circumference" in node.tags)):
|
"circumference" in node.tags)):
|
||||||
continue
|
continue
|
||||||
|
@ -359,7 +362,7 @@ class Painter:
|
||||||
direction = node.get_tag("direction")
|
direction = node.get_tag("direction")
|
||||||
direction_radius: float = \
|
direction_radius: float = \
|
||||||
25 * self.flinger.get_scale(node.coordinates)
|
25 * self.flinger.get_scale(node.coordinates)
|
||||||
direction_color: str = "#FF0000"
|
direction_color: str = Color("red")
|
||||||
else:
|
else:
|
||||||
direction = node.get_tag("direction")
|
direction = node.get_tag("direction")
|
||||||
direction_radius: float = \
|
direction_radius: float = \
|
||||||
|
@ -384,12 +387,12 @@ class Painter:
|
||||||
gradientUnits="userSpaceOnUse"))
|
gradientUnits="userSpaceOnUse"))
|
||||||
if is_revert_gradient:
|
if is_revert_gradient:
|
||||||
gradient \
|
gradient \
|
||||||
.add_stop_color(0, direction_color, opacity=0) \
|
.add_stop_color(0, direction_color.hex, opacity=0) \
|
||||||
.add_stop_color(1, direction_color, opacity=0.7)
|
.add_stop_color(1, direction_color.hex, opacity=0.7)
|
||||||
else:
|
else:
|
||||||
gradient \
|
gradient \
|
||||||
.add_stop_color(0, direction_color, opacity=0.4) \
|
.add_stop_color(0, direction_color.hex, opacity=0.4) \
|
||||||
.add_stop_color(1, direction_color, opacity=0)
|
.add_stop_color(1, direction_color.hex, opacity=0)
|
||||||
self.svg.add(self.svg.path(
|
self.svg.add(self.svg.path(
|
||||||
d=["M", point] + path + ["L", point, "Z"],
|
d=["M", point] + path + ["L", point, "Z"],
|
||||||
fill=gradient.get_paint_server()))
|
fill=gradient.get_paint_server()))
|
||||||
|
@ -413,7 +416,8 @@ class Painter:
|
||||||
if self.mode not in [CREATION_TIME_MODE, AUTHOR_MODE]:
|
if self.mode not in [CREATION_TIME_MODE, AUTHOR_MODE]:
|
||||||
self.draw_texts(node)
|
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.
|
Draw one icon.
|
||||||
"""
|
"""
|
||||||
|
@ -426,37 +430,34 @@ class Painter:
|
||||||
self.draw_point(icon, point, fill, tags=tags)
|
self.draw_point(icon, point, fill, tags=tags)
|
||||||
|
|
||||||
def draw_point(
|
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:
|
tags: Dict[str, str] = None) -> None:
|
||||||
|
|
||||||
point = np.array(list(map(lambda x: int(x), point)))
|
point = np.array(list(map(lambda x: int(x), point)))
|
||||||
title: str = "\n".join(map(lambda x: x + ": " + tags[x], tags))
|
title: str = "\n".join(map(lambda x: x + ": " + tags[x], tags))
|
||||||
|
|
||||||
path: svgwrite.path.Path = icon.get_path(self.svg, point)
|
path: svgwrite.path.Path = icon.get_path(self.svg, point)
|
||||||
path.update({"fill": fill})
|
path.update({"fill": fill.hex})
|
||||||
path.set_desc(title=title)
|
path.set_desc(title=title)
|
||||||
self.svg.add(path)
|
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)))
|
point = np.array(list(map(lambda x: int(x), point)))
|
||||||
|
|
||||||
opacity = 0.5
|
opacity: float = 0.5
|
||||||
stroke_width = 2.2
|
stroke_width: float = 2.2
|
||||||
outline_fill = self.scheme.get_color("outline_color")
|
outline_fill: Color = self.scheme.get_color("outline_color")
|
||||||
if mode not in [AUTHOR_MODE, CREATION_TIME_MODE]:
|
|
||||||
r = int(fill[1:3], 16)
|
if mode not in [AUTHOR_MODE, CREATION_TIME_MODE] and is_bright(fill):
|
||||||
g = int(fill[3:5], 16)
|
outline_fill = Color("black")
|
||||||
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 = 0.7
|
||||||
|
|
||||||
path = icon.get_path(self.svg, point)
|
path = icon.get_path(self.svg, point)
|
||||||
path.update({
|
path.update({
|
||||||
"fill": outline_fill, "opacity": opacity,
|
"fill": outline_fill.hex, "opacity": opacity,
|
||||||
"stroke": outline_fill, "stroke-width": stroke_width,
|
"stroke": outline_fill.hex, "stroke-width": stroke_width,
|
||||||
"stroke-linejoin": "round"})
|
"stroke-linejoin": "round"})
|
||||||
self.svg.add(path)
|
self.svg.add(path)
|
||||||
|
|
||||||
|
@ -510,9 +511,9 @@ def main(argv):
|
||||||
if not options:
|
if not options:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
background_color = "#EEEEEE"
|
background_color: Color = Color("#EEEEEE")
|
||||||
if options.mode in [AUTHOR_MODE, CREATION_TIME_MODE]:
|
if options.mode in [AUTHOR_MODE, CREATION_TIME_MODE]:
|
||||||
background_color = "#111111"
|
background_color: Color = Color("#111111")
|
||||||
|
|
||||||
if options.input_file_name:
|
if options.input_file_name:
|
||||||
input_file_name = options.input_file_name
|
input_file_name = options.input_file_name
|
||||||
|
@ -546,7 +547,7 @@ def main(argv):
|
||||||
missing_tags = {}
|
missing_tags = {}
|
||||||
points = []
|
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]))
|
min1: np.array = np.array((boundary_box[1], boundary_box[0]))
|
||||||
max1: np.array = np.array((boundary_box[3], boundary_box[2]))
|
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):
|
if (0 <= i < lat_number) and (0 <= j < lon_number):
|
||||||
matrix[i][j] += 1
|
matrix[i][j] += 1
|
||||||
if "tags" in node:
|
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
|
for way_id in map_.way_map: # type: int
|
||||||
way = map_.way_map[way_id]
|
way = map_.way_map[way_id]
|
||||||
if "tags" in way:
|
if "tags" in way:
|
||||||
|
@ -635,7 +636,7 @@ def draw_index(flinger, map_, max1, min1, svg):
|
||||||
i = int((node[0] - min1[0]) / lat_step)
|
i = int((node[0] - min1[0]) / lat_step)
|
||||||
j = int((node[1] - min1[1]) / lon_step)
|
j = int((node[1] - min1[1]) / lon_step)
|
||||||
if (0 <= i < lat_number) and (0 <= j < lon_number):
|
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))
|
len(way.nodes))
|
||||||
for i in range(lat_number):
|
for i in range(lat_number):
|
||||||
for j in range(lon_number):
|
for j in range(lon_number):
|
||||||
|
|
|
@ -6,11 +6,12 @@ Author: Sergey Vartanov (me@enzet.ru).
|
||||||
import copy
|
import copy
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from colour import Color
|
||||||
from typing import Any, Dict, List, Optional, Set
|
from typing import Any, Dict, List, Optional, Set
|
||||||
|
|
||||||
from roentgen.extract_icon import DEFAULT_SHAPE_ID
|
from roentgen.extract_icon import DEFAULT_SHAPE_ID
|
||||||
|
|
||||||
DEFAULT_COLOR: str = "#444444"
|
DEFAULT_COLOR: Color = Color("#444444")
|
||||||
|
|
||||||
|
|
||||||
class IconSet:
|
class IconSet:
|
||||||
|
@ -18,7 +19,7 @@ class IconSet:
|
||||||
Node representation: icons and color.
|
Node representation: icons and color.
|
||||||
"""
|
"""
|
||||||
def __init__(
|
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):
|
is_default: bool):
|
||||||
"""
|
"""
|
||||||
:param icons: list of lists of shape identifiers
|
:param icons: list of lists of shape identifiers
|
||||||
|
@ -27,7 +28,7 @@ class IconSet:
|
||||||
tag keys should be displayed by text or ignored)
|
tag keys should be displayed by text or ignored)
|
||||||
"""
|
"""
|
||||||
self.icons: List[List[str]] = icons
|
self.icons: List[List[str]] = icons
|
||||||
self.color: str = color
|
self.color: Color = color
|
||||||
self.processed: Set[str] = processed
|
self.processed: Set[str] = processed
|
||||||
self.is_default = is_default
|
self.is_default = is_default
|
||||||
|
|
||||||
|
@ -38,23 +39,18 @@ class Scheme:
|
||||||
|
|
||||||
Specifies map colors and rules to draw icons for OpenStreetMap tags.
|
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
|
:param file_name: scheme file name with tags, colors, and tag key
|
||||||
specification
|
specification
|
||||||
:param color_file_name: additional color scheme
|
|
||||||
"""
|
"""
|
||||||
content: Dict[str, Any] = \
|
content: Dict[str, Any] = \
|
||||||
yaml.load(open(file_name).read(), Loader=yaml.FullLoader)
|
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.ways: List[Dict[str, Any]] = content["ways"]
|
||||||
|
|
||||||
self.colors: Dict[str, str] = content["colors"]
|
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.tags_to_write: List[str] = content["tags_to_write"]
|
||||||
self.prefix_to_write: List[str] = content["prefix_to_write"]
|
self.prefix_to_write: List[str] = content["prefix_to_write"]
|
||||||
|
@ -64,18 +60,20 @@ class Scheme:
|
||||||
# Storage for created icon sets.
|
# Storage for created icon sets.
|
||||||
self.cache: Dict[str, IconSet] = {}
|
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 color if the color is in scheme, otherwise return default color.
|
||||||
|
|
||||||
:return: 6-digit color specification with "#"
|
:return: 6-digit color specification with "#"
|
||||||
"""
|
"""
|
||||||
if color in self.colors:
|
if color in self.colors:
|
||||||
return "#" + self.colors[color]
|
return Color("#" + self.colors[color])
|
||||||
if color.lower() in self.colors:
|
if color.lower() in self.colors:
|
||||||
return "#" + self.colors[color.lower()]
|
return Color("#" + self.colors[color.lower()])
|
||||||
if color.startswith("#"):
|
try:
|
||||||
return color
|
return Color(color)
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
return DEFAULT_COLOR
|
return DEFAULT_COLOR
|
||||||
|
|
||||||
|
@ -124,12 +122,12 @@ class Scheme:
|
||||||
|
|
||||||
main_icon: Optional[List[str]] = None
|
main_icon: Optional[List[str]] = None
|
||||||
extra_icons: List[List[str]] = []
|
extra_icons: List[List[str]] = []
|
||||||
processed = set()
|
processed: Set[str] = set()
|
||||||
fill = DEFAULT_COLOR
|
fill: Color = DEFAULT_COLOR
|
||||||
|
|
||||||
for matcher in self.tags:
|
for matcher in self.nodes: # type: Dict[str, Any]
|
||||||
matched = True
|
matched: bool = True
|
||||||
for key in matcher["tags"]:
|
for key in matcher["tags"]: # type: str
|
||||||
if key not in tags:
|
if key not in tags:
|
||||||
matched = False
|
matched = False
|
||||||
break
|
break
|
||||||
|
@ -173,10 +171,12 @@ class Scheme:
|
||||||
else:
|
else:
|
||||||
result_set: List[List[str]] = extra_icons
|
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
|
is_default: bool = False
|
||||||
if not result_set and \
|
if not result_set and keys_left:
|
||||||
list(filter(lambda x: x not in processed and
|
|
||||||
not self.is_no_drawable(x), tags.keys())):
|
|
||||||
result_set = [[DEFAULT_SHAPE_ID]]
|
result_set = [[DEFAULT_SHAPE_ID]]
|
||||||
is_default = True
|
is_default = True
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
from colour import Color
|
||||||
|
|
||||||
|
|
||||||
class MinMax:
|
class MinMax:
|
||||||
"""
|
"""
|
||||||
Minimum and maximum.
|
Minimum and maximum.
|
||||||
|
@ -21,3 +24,12 @@ class MinMax:
|
||||||
|
|
||||||
def center(self):
|
def center(self):
|
||||||
return (self.min_ + self.max_) / 2
|
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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue