map-machine/roentgen/mapcss.py
2021-08-15 06:33:42 +03:00

131 lines
4.1 KiB
Python

"""
MapCSS scheme creation.
"""
from pathlib import Path
from typing import List, Optional, Dict
import logging
from colour import Color
from roentgen.workspace import workspace
from roentgen.grid import IconCollection
from roentgen.icon import ShapeExtractor
from roentgen.osm_reader import STAGES_OF_DECAY
from roentgen.scheme import Scheme, Matcher
__author__ = "Sergey Vartanov"
__email__ = "me@enzet.ru"
class MapCSSWriter:
def __init__(
self,
scheme: Scheme,
icon_directory_name: str,
add_icons_for_lifecycle: bool,
):
self.add_icons_for_lifecycle = add_icons_for_lifecycle
self.icon_directory_name = icon_directory_name
self.point_matchers: List[Matcher] = scheme.node_matchers
self.line_matchers: List[Matcher] = scheme.way_matchers
def add_selector(
self,
target: str,
matcher: Matcher,
prefix: str = "",
opacity: Optional[float] = None,
) -> str:
elements: Dict[str, str] = {}
clean_shapes = matcher.get_clean_shapes()
if clean_shapes:
elements["icon-image"] = (
f'"{self.icon_directory_name}/'
+ "___".join(clean_shapes)
+ '.svg"'
)
if opacity is not None:
elements["icon-opacity"] = f"{opacity:.2f}"
style = matcher.get_style()
if style:
if "fill" in style:
elements["fill-color"] = style["fill"]
if "stroke" in style:
elements["color"] = style["stroke"]
if "stroke-width" in style:
elements["width"] = style["stroke-width"]
if "stroke-dasharray" in style:
elements["dashes"] = style["stroke-dasharray"]
if "opacity" in style:
elements["fill-opacity"] = style["opacity"]
elements["opacity"] = style["opacity"]
if not elements:
return ""
selector: str = target + matcher.get_mapcss_selector(prefix) + " {\n"
for element in elements:
selector += f" {element}: {elements[element]};\n"
selector += "}\n"
return selector
def write(self, output_file: Path) -> None:
"""
Construct icon selectors for MapCSS 0.2 scheme.
"""
with workspace.MAPCSS_PART_FILE_PATH.open() as input_file:
output_file.write(input_file.read())
output_file.write("\n")
for line_matcher in self.line_matchers:
for target in ["way", "relation"]:
output_file.write(self.add_selector(target, line_matcher))
for matcher in self.point_matchers:
for target in ["node", "area"]:
output_file.write(self.add_selector(target, matcher))
if not self.add_icons_for_lifecycle:
return
for index, stage_of_decay in enumerate(STAGES_OF_DECAY):
opacity: float = 0.6 - 0.4 * index / (len(STAGES_OF_DECAY) - 1)
for matcher in self.point_matchers:
if len(matcher.tags) > 1:
continue
for target in ["node", "area"]:
output_file.write(
self.add_selector(
target, matcher, stage_of_decay, opacity
)
)
def write_mapcss() -> None:
"""
Write MapCSS 0.2 scheme.
"""
directory: Path = workspace.get_mapcss_path()
icons_with_outline_path: Path = workspace.get_mapcss_icons_path()
scheme: Scheme = Scheme(workspace.DEFAULT_SCHEME_PATH)
extractor: ShapeExtractor = ShapeExtractor(
workspace.ICONS_PATH, workspace.ICONS_CONFIG_PATH
)
collection: IconCollection = IconCollection.from_scheme(scheme, extractor)
collection.draw_icons(
icons_with_outline_path, color=Color("black"), outline=True
)
mapcss_writer: MapCSSWriter = MapCSSWriter(
scheme, workspace.MAPCSS_ICONS_DIRECTORY_NAME, True
)
with workspace.get_mapcss_file_path().open("w+") as output_file:
mapcss_writer.write(output_file)
logging.info(f"MapCSS 0.2 scheme is written to {directory}.")