Refactor text generation.

This commit is contained in:
Sergey Vartanov 2021-05-06 03:20:38 +03:00
parent f317eba64b
commit 958a85fe0a
13 changed files with 129 additions and 126 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 86 KiB

Before After
Before After

Binary file not shown.

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Before After
Before After

View file

@ -19,7 +19,7 @@ To get SVG map, just run
\code {python roentgen.py -b <lon1>,<lat1>,<lon2>,<lat2>} {bash}
(e.g. \tt {python roentgen.py -b 2.284,48.86,2.29,48.865}). It will automatically download OSM data and write output map to \tt {map.svg}. For more options see \href {#map-generation} {Map Generation section}.
(e.g. \tt {python roentgen.py -b 2.284,48.86,2.29,48.865}). It will automatically download OSM data and write output map to \tt {map.svg}. For more options see \href {#map-generation} {Map Generation}.
\2 {Map features} {features}
@ -94,7 +94,7 @@ Every way and node displayed with the random color picked for each author with \
\image {doc/user.png} {Author mode}
\2 {Map generation} {map_generation}
\2 {Map generation} {map-generation}
\b {Requirements}\: Python (at least 3.8) and Python libraries (install everything using \tt {pip install -r requirements.txt}).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Before After
Before After

View file

@ -21,7 +21,7 @@ To get SVG map, just run
python roentgen.py -b <lon1>,<lat1>,<lon2>,<lat2>
```
(e.g. `python roentgen.py -b 2.284,48.86,2.29,48.865`). It will automatically download OSM data and write output map to `map.svg`. For more options see [Map Generation section](#map-generation).
(e.g. `python roentgen.py -b 2.284,48.86,2.29,48.865`). It will automatically download OSM data and write output map to `map.svg`. For more options see [Map Generation](#map-generation).
Map features
------------

View file

@ -128,10 +128,11 @@ def draw_element(target: str, tags_description: str):
tags = dict([x.split("=") for x in tags_description.split(",")])
scheme = Scheme("data/tags.yml")
icon_extractor = IconExtractor("icons/icons.svg")
icon_set, priority = scheme.get_icon(icon_extractor, tags)
icon, priority = scheme.get_icon(icon_extractor, tags)
is_for_node: bool = target == "node"
labels = scheme.construct_text(tags, True)
point = Point(
icon_set, tags, np.array((32, 32)), None, is_for_node=is_for_node,
icon, labels, tags, np.array((32, 32)), None, is_for_node=is_for_node,
draw_outline=is_for_node
)
print(point.is_for_node)
@ -143,7 +144,7 @@ def draw_element(target: str, tags_description: str):
svg.add(path)
point.draw_main_shapes(svg)
point.draw_extra_shapes(svg)
point.draw_texts(svg, scheme, None, True)
point.draw_texts(svg, None)
svg.write(open("test_icon.svg", "w+"))

View file

@ -360,8 +360,10 @@ class Constructor:
icon, priority = self.scheme.get_icon(
self.icon_extractor, line.tags, for_="line"
)
labels = self.scheme.construct_text(line.tags, True)
self.nodes.append(Point(
icon, line.tags, center_point, center_coordinates,
icon, labels, line.tags, center_point, center_coordinates,
is_for_node=False, priority=priority
))
@ -377,9 +379,10 @@ class Constructor:
icon_set: Icon
icon_set, priority = self.scheme.get_icon(
self.icon_extractor, line.tags)
labels = self.scheme.construct_text(line.tags, True)
self.nodes.append(Point(
icon_set, line.tags, center_point, center_coordinates,
icon_set, labels, line.tags, center_point, center_coordinates,
is_for_node=False, priority=priority))
def construct_relations(self) -> None:
@ -448,14 +451,16 @@ class Constructor:
icon_set = Icon([dot], [], color, set(), True)
priority = 0
draw_outline = False
labels = []
else:
icon_set, priority = self.scheme.get_icon(
self.icon_extractor, tags
)
labels = self.scheme.construct_text(tags, True)
self.nodes.append(Point(
icon_set, tags, flung, node.coordinates, priority=priority,
draw_outline=draw_outline
icon_set, labels, tags, flung, node.coordinates,
priority=priority, draw_outline=draw_outline
))
missing_tags.update(

View file

@ -71,7 +71,8 @@ def draw_all_icons(
specified_ids |= icons_to_draw
print(
"Icons with no tag specification: \n " +
", ".join(sorted(extractor.icons.keys() - specified_ids)) + ".")
", ".join(sorted(extractor.icons.keys() - specified_ids)) + "."
)
draw_grid(
output_file_name, to_draw, extractor, output_directory, columns, step
@ -82,7 +83,7 @@ def draw_grid(
file_name: str, combined_icon_ids: List[Set[str]],
extractor: IconExtractor, output_directory: str, columns: int = 16,
step: float = 24, color=Color("#444444")
) -> List[List[Shape]]:
) -> List[List[Shape]]:
"""
Draw icons in the form of table

View file

@ -244,20 +244,19 @@ class Painter:
)
node.draw_main_shapes(self.svg, occupied)
for index, node in enumerate(nodes): # type: int, Point
for index, point in enumerate(nodes): # type: int, Point
ui.progress_bar(
steps + index, steps * 3, step=10, text="Drawing extra icons"
)
node.draw_extra_shapes(self.svg, occupied)
point.draw_extra_shapes(self.svg, occupied)
for index, node in enumerate(nodes): # type: int, Point
for index, point in enumerate(nodes): # type: int, Point
ui.progress_bar(
steps * 2 + index, steps * 3, step=10, text="Drawing texts"
)
if (self.mode not in [CREATION_TIME_MODE, AUTHOR_MODE] and
self.draw_captions != "no"):
node.draw_texts(
self.svg, self.scheme, occupied, self.draw_captions)
point.draw_texts(self.svg, occupied)
ui.progress_bar(-1, len(nodes), step=10, text="Drawing nodes")

View file

@ -8,22 +8,10 @@ from colour import Color
from roentgen.color import is_bright
from roentgen.icon import Shape
from roentgen.osm_reader import Tagged
from roentgen.scheme import Icon, Scheme
from roentgen.text import get_address, get_text
from roentgen.scheme import Icon
from roentgen.text import Label
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
class Occupied:
@ -44,87 +32,6 @@ class Occupied:
assert self.matrix[point[0], point[1]] == True
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 += "ex " + 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
for text in get_text(tags): # type: str
if text:
texts.append(TextStruct(text))
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
def in_range(position, points) -> bool:
return 0 <= position[0] < len(points) and 0 <= position[1] < len(points[0])
@ -137,8 +44,8 @@ class Point(Tagged):
"""
def __init__(
self, icon: Icon, tags: Dict[str, str], point: np.array,
coordinates: np.array, priority: float = 0,
self, icon: Icon, labels: List[Label], tags: Dict[str, str],
point: np.array, coordinates: np.array, priority: float = 0,
is_for_node: bool = True, draw_outline: bool = True
):
super().__init__()
@ -146,6 +53,7 @@ class Point(Tagged):
assert point is not None
self.icon: Icon = icon
self.labels: List[Label] = labels
self.tags: Dict[str, str] = tags
self.point: np.array = point
self.coordinates: np.array = coordinates
@ -241,16 +149,11 @@ class Point(Tagged):
return True
def draw_texts(
self, svg: svgwrite.Drawing, scheme: Scheme, occupied: Occupied,
draw_captions):
def draw_texts(self, svg: svgwrite.Drawing, occupied: Occupied) -> None:
"""
Draw all labels.
"""
text_structures: List[TextStruct] = construct_text(
self.tags, self.icon.processed, scheme, draw_captions)
for text_struct in text_structures: # type: TextStruct
for text_struct in self.labels: # type: Label
text = text_struct.text
text = text.replace("&quot;", '"')
text = text.replace("&amp;", '&')

View file

@ -12,6 +12,7 @@ import yaml
from colour import Color
from roentgen.icon import DEFAULT_SHAPE_ID, Shape, IconExtractor
from roentgen.text import Label, get_address, get_text
DEFAULT_COLOR: Color = Color("#444444")
@ -299,6 +300,85 @@ class Scheme:
return line_styles
def construct_text(self, tags, draw_captions) -> List[Label]:
"""
Construct labels for not processed tags.
"""
texts: List[Label] = []
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 += "ex " + tags["old_name"]
address: List[str] = get_address(tags, draw_captions)
if name:
texts.append(Label(name, Color("black")))
if alt_name:
texts.append(Label(f"({alt_name})"))
if address:
texts.append(Label(", ".join(address)))
if draw_captions == "main":
return texts
for text in get_text(tags): # type: str
if text:
texts.append(Label(text))
if "route_ref" in tags:
texts.append(Label(tags["route_ref"].replace(";", " ")))
tags.pop("route_ref", None)
if "cladr:code" in tags:
texts.append(Label(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(Label(link, Color("#000088")))
tags.pop("website", None)
for k in ["phone"]:
if k in tags:
texts.append(Label(tags[k], Color("#444444")))
tags.pop(k)
for tag in tags:
if self.is_writable(tag):
texts.append(Label(tags[tag]))
return texts
def is_area(self, tags: Dict[str, str]) -> bool:
for matcher in self.area_tags:
if is_matched(matcher, tags):

View file

@ -3,8 +3,22 @@ OSM address tag processing.
Author: Sergey Vartanov (me@enzet.ru).
"""
from dataclasses import dataclass
from typing import Any, Dict, List
from colour import Color
DEFAULT_COLOR: Color = Color("#444444")
@dataclass
class Label:
"""
Text label.
"""
text: str
fill: Color = DEFAULT_COLOR
size: float = 10.0
def get_address(tags: Dict[str, Any], draw_captions_mode: str) -> List[str]:
"""

View file

@ -61,7 +61,7 @@ def test_icon_2_extra() -> None:
def __test_no_icon_1_extra() -> None:
"""
Tags that should be visualized with defult main icon and single extra icon.
Tags that should be visualized with default main icon and single extra icon.
"""
icon = get_icon({"access": "private"})
assert icon.main_icon[0].is_default()
@ -70,7 +70,7 @@ def __test_no_icon_1_extra() -> None:
def __test_no_icon_2_extra() -> None:
"""
Tags that should be visualized with defult main icon and two extra icons.
Tags that should be visualized with default main icon and two extra icons.
"""
icon = get_icon({"access": "private", "bicycle": "yes"})
assert icon.main_icon[0].is_default()