mirror of
https://github.com/enzet/map-machine.git
synced 2025-08-06 10:09:52 +02:00
Issue #75: add filter for icons by zoom level.
This commit is contained in:
parent
9c4873c5ae
commit
39428cad19
13 changed files with 147 additions and 62 deletions
|
@ -251,21 +251,25 @@ class Constructor:
|
||||||
priority: int
|
priority: int
|
||||||
icon_set: IconSet
|
icon_set: IconSet
|
||||||
icon_set, priority = self.scheme.get_icon(
|
icon_set, priority = self.scheme.get_icon(
|
||||||
self.extractor, line.tags, processed
|
self.extractor,
|
||||||
)
|
|
||||||
labels: list[Label] = self.scheme.construct_text(
|
|
||||||
line.tags, "all", processed
|
|
||||||
)
|
|
||||||
point: Point = Point(
|
|
||||||
icon_set,
|
|
||||||
labels,
|
|
||||||
line.tags,
|
line.tags,
|
||||||
processed,
|
processed,
|
||||||
center_point,
|
self.configuration.zoom_level,
|
||||||
is_for_node=False,
|
)
|
||||||
priority=priority,
|
if icon_set is not None:
|
||||||
) # fmt: skip
|
labels: list[Label] = self.scheme.construct_text(
|
||||||
self.points.append(point)
|
line.tags, "all", processed
|
||||||
|
)
|
||||||
|
point: Point = Point(
|
||||||
|
icon_set,
|
||||||
|
labels,
|
||||||
|
line.tags,
|
||||||
|
processed,
|
||||||
|
center_point,
|
||||||
|
is_for_node=False,
|
||||||
|
priority=priority,
|
||||||
|
)
|
||||||
|
self.points.append(point)
|
||||||
|
|
||||||
if not line_styles:
|
if not line_styles:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
|
@ -284,16 +288,25 @@ class Constructor:
|
||||||
priority: int
|
priority: int
|
||||||
icon_set: IconSet
|
icon_set: IconSet
|
||||||
icon_set, priority = self.scheme.get_icon(
|
icon_set, priority = self.scheme.get_icon(
|
||||||
self.extractor, line.tags, processed
|
self.extractor,
|
||||||
|
line.tags,
|
||||||
|
processed,
|
||||||
|
self.configuration.zoom_level,
|
||||||
)
|
)
|
||||||
labels: list[Label] = self.scheme.construct_text(
|
if icon_set is not None:
|
||||||
line.tags, "all", processed
|
labels: list[Label] = self.scheme.construct_text(
|
||||||
)
|
line.tags, "all", processed
|
||||||
point: Point = Point(
|
)
|
||||||
icon_set, labels, line.tags, processed, center_point,
|
point: Point = Point(
|
||||||
is_for_node=False, priority=priority,
|
icon_set,
|
||||||
) # fmt: skip
|
labels,
|
||||||
self.points.append(point)
|
line.tags,
|
||||||
|
processed,
|
||||||
|
center_point,
|
||||||
|
is_for_node=False,
|
||||||
|
priority=priority,
|
||||||
|
)
|
||||||
|
self.points.append(point)
|
||||||
|
|
||||||
def draw_special_mode(
|
def draw_special_mode(
|
||||||
self,
|
self,
|
||||||
|
@ -385,8 +398,10 @@ class Constructor:
|
||||||
return
|
return
|
||||||
|
|
||||||
icon_set, priority = self.scheme.get_icon(
|
icon_set, priority = self.scheme.get_icon(
|
||||||
self.extractor, tags, processed
|
self.extractor, tags, processed, self.configuration.zoom_level
|
||||||
)
|
)
|
||||||
|
if icon_set is None:
|
||||||
|
return
|
||||||
labels: list[Label] = self.scheme.construct_text(tags, "all", processed)
|
labels: list[Label] = self.scheme.construct_text(tags, "all", processed)
|
||||||
self.scheme.process_ignored(tags, processed)
|
self.scheme.process_ignored(tags, processed)
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,8 @@ from typing import Optional, Union
|
||||||
import cairo
|
import cairo
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import svgwrite
|
import svgwrite
|
||||||
from colour import Color
|
|
||||||
from cairo import Context, ImageSurface
|
from cairo import Context, ImageSurface
|
||||||
|
from colour import Color
|
||||||
from svgwrite.base import BaseElement
|
from svgwrite.base import BaseElement
|
||||||
from svgwrite.path import Path as SVGPath
|
from svgwrite.path import Path as SVGPath
|
||||||
from svgwrite.shapes import Rect
|
from svgwrite.shapes import Rect
|
||||||
|
|
|
@ -41,7 +41,7 @@ def draw_element(options: argparse.Namespace) -> None:
|
||||||
workspace.ICONS_PATH, workspace.ICONS_CONFIG_PATH
|
workspace.ICONS_PATH, workspace.ICONS_CONFIG_PATH
|
||||||
)
|
)
|
||||||
processed: set[str] = set()
|
processed: set[str] = set()
|
||||||
icon, priority = scheme.get_icon(extractor, tags, processed)
|
icon, priority = scheme.get_icon(extractor, tags, processed, 18)
|
||||||
is_for_node: bool = target == "node"
|
is_for_node: bool = target == "node"
|
||||||
labels: list[Label] = scheme.construct_text(tags, "all", processed)
|
labels: list[Label] = scheme.construct_text(tags, "all", processed)
|
||||||
point: Point = Point(
|
point: Point = Point(
|
||||||
|
|
|
@ -19,6 +19,9 @@ from roentgen.scheme import LineStyle, RoadMatcher, Scheme
|
||||||
__author__ = "Sergey Vartanov"
|
__author__ = "Sergey Vartanov"
|
||||||
__email__ = "me@enzet.ru"
|
__email__ = "me@enzet.ru"
|
||||||
|
|
||||||
|
BUILDING_HEIGHT_SCALE: float = 2.5
|
||||||
|
BUILDING_MINIMAL_HEIGHT: float = 8.0
|
||||||
|
|
||||||
|
|
||||||
class Figure(Tagged):
|
class Figure(Tagged):
|
||||||
"""
|
"""
|
||||||
|
@ -34,13 +37,10 @@ class Figure(Tagged):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.tags: dict[str, str] = tags
|
self.tags: dict[str, str] = tags
|
||||||
self.inners: list[list[OSMNode]] = []
|
self.inners: list[list[OSMNode]] = list(map(make_clockwise, inners))
|
||||||
self.outers: list[list[OSMNode]] = []
|
self.outers: list[list[OSMNode]] = list(
|
||||||
|
map(make_counter_clockwise, outers)
|
||||||
for inner_nodes in inners:
|
)
|
||||||
self.inners.append(make_clockwise(inner_nodes))
|
|
||||||
for outer_nodes in outers:
|
|
||||||
self.outers.append(make_counter_clockwise(outer_nodes))
|
|
||||||
|
|
||||||
def get_path(
|
def get_path(
|
||||||
self, flinger: Flinger, shift: np.ndarray = np.array((0, 0))
|
self, flinger: Flinger, shift: np.ndarray = np.array((0, 0))
|
||||||
|
@ -92,16 +92,16 @@ class Building(Figure):
|
||||||
|
|
||||||
self.parts = sorted(self.parts)
|
self.parts = sorted(self.parts)
|
||||||
|
|
||||||
self.height: float = 8.0
|
self.height: float = BUILDING_MINIMAL_HEIGHT
|
||||||
self.min_height: float = 0.0
|
self.min_height: float = 0.0
|
||||||
|
|
||||||
levels: Optional[str] = self.get_float("building:levels")
|
levels: Optional[str] = self.get_float("building:levels")
|
||||||
if levels:
|
if levels:
|
||||||
self.height = float(levels) * 2.5
|
self.height = float(levels) * BUILDING_HEIGHT_SCALE
|
||||||
|
|
||||||
levels: Optional[str] = self.get_float("building:min_level")
|
levels: Optional[str] = self.get_float("building:min_level")
|
||||||
if levels:
|
if levels:
|
||||||
self.min_height = float(levels) * 2.5
|
self.min_height = float(levels) * BUILDING_HEIGHT_SCALE
|
||||||
|
|
||||||
height: Optional[float] = self.get_length("height")
|
height: Optional[float] = self.get_length("height")
|
||||||
if height:
|
if height:
|
||||||
|
|
|
@ -48,6 +48,7 @@ class MapConfiguration:
|
||||||
drawing_mode: DrawingMode = DrawingMode.NORMAL
|
drawing_mode: DrawingMode = DrawingMode.NORMAL
|
||||||
building_mode: BuildingMode = BuildingMode.FLAT
|
building_mode: BuildingMode = BuildingMode.FLAT
|
||||||
label_mode: LabelMode = LabelMode.MAIN
|
label_mode: LabelMode = LabelMode.MAIN
|
||||||
|
zoom_level: int = 18
|
||||||
overlap: int = 12
|
overlap: int = 12
|
||||||
level: str = "overground"
|
level: str = "overground"
|
||||||
seed: str = ""
|
seed: str = ""
|
||||||
|
@ -59,6 +60,7 @@ class MapConfiguration:
|
||||||
DrawingMode(options.mode),
|
DrawingMode(options.mode),
|
||||||
BuildingMode(options.buildings),
|
BuildingMode(options.buildings),
|
||||||
LabelMode(options.label_mode),
|
LabelMode(options.label_mode),
|
||||||
|
options.zoom,
|
||||||
options.overlap,
|
options.overlap,
|
||||||
options.level,
|
options.level,
|
||||||
options.seed,
|
options.seed,
|
||||||
|
|
|
@ -94,13 +94,19 @@ class Matcher:
|
||||||
Tag matching.
|
Tag matching.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, structure: dict[str, Any]) -> None:
|
def __init__(
|
||||||
|
self, structure: dict[str, Any], group: Optional[dict[str, Any]] = None
|
||||||
|
) -> None:
|
||||||
self.tags: dict[str, str] = structure["tags"]
|
self.tags: dict[str, str] = structure["tags"]
|
||||||
|
|
||||||
self.exception: dict[str, str] = {}
|
self.exception: dict[str, str] = {}
|
||||||
if "exception" in structure:
|
if "exception" in structure:
|
||||||
self.exception = structure["exception"]
|
self.exception = structure["exception"]
|
||||||
|
|
||||||
|
self.start_zoom_level: Optional[int] = None
|
||||||
|
if group is not None and "start_zoom_level" in group:
|
||||||
|
self.start_zoom_level = group["start_zoom_level"]
|
||||||
|
|
||||||
self.replace_shapes: bool = True
|
self.replace_shapes: bool = True
|
||||||
if "replace_shapes" in structure:
|
if "replace_shapes" in structure:
|
||||||
self.replace_shapes = structure["replace_shapes"]
|
self.replace_shapes = structure["replace_shapes"]
|
||||||
|
@ -109,6 +115,13 @@ class Matcher:
|
||||||
if "location_restrictions" in structure:
|
if "location_restrictions" in structure:
|
||||||
self.location_restrictions = structure["location_restrictions"]
|
self.location_restrictions = structure["location_restrictions"]
|
||||||
|
|
||||||
|
def check_zoom_level(self, zoom_level: int):
|
||||||
|
"""Check whether zoom level is matching."""
|
||||||
|
return (
|
||||||
|
self.start_zoom_level is None
|
||||||
|
or zoom_level >= self.start_zoom_level
|
||||||
|
)
|
||||||
|
|
||||||
def is_matched(self, tags: dict[str, str]) -> bool:
|
def is_matched(self, tags: dict[str, str]) -> bool:
|
||||||
"""
|
"""
|
||||||
Check whether element tags matches tag matcher.
|
Check whether element tags matches tag matcher.
|
||||||
|
@ -118,8 +131,6 @@ class Matcher:
|
||||||
if self.location_restrictions:
|
if self.location_restrictions:
|
||||||
return False # FIXME: implement
|
return False # FIXME: implement
|
||||||
|
|
||||||
matched: bool = True
|
|
||||||
|
|
||||||
for config_tag_key in self.tags:
|
for config_tag_key in self.tags:
|
||||||
config_tag_key: str
|
config_tag_key: str
|
||||||
tag_matcher = self.tags[config_tag_key]
|
tag_matcher = self.tags[config_tag_key]
|
||||||
|
@ -127,8 +138,7 @@ class Matcher:
|
||||||
is_matched_tag(config_tag_key, tag_matcher, tags)
|
is_matched_tag(config_tag_key, tag_matcher, tags)
|
||||||
== MatchingType.NOT_MATCHED
|
== MatchingType.NOT_MATCHED
|
||||||
):
|
):
|
||||||
matched = False
|
return False
|
||||||
break
|
|
||||||
|
|
||||||
if self.exception:
|
if self.exception:
|
||||||
for config_tag_key in self.exception:
|
for config_tag_key in self.exception:
|
||||||
|
@ -138,10 +148,9 @@ class Matcher:
|
||||||
is_matched_tag(config_tag_key, tag_matcher, tags)
|
is_matched_tag(config_tag_key, tag_matcher, tags)
|
||||||
!= MatchingType.NOT_MATCHED
|
!= MatchingType.NOT_MATCHED
|
||||||
):
|
):
|
||||||
matched = False
|
return False
|
||||||
break
|
|
||||||
|
|
||||||
return matched
|
return True
|
||||||
|
|
||||||
def get_mapcss_selector(self, prefix: str = "") -> str:
|
def get_mapcss_selector(self, prefix: str = "") -> str:
|
||||||
"""
|
"""
|
||||||
|
@ -167,9 +176,11 @@ class NodeMatcher(Matcher):
|
||||||
Tag specification matcher.
|
Tag specification matcher.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, structure: dict[str, Any]) -> None:
|
def __init__(
|
||||||
|
self, structure: dict[str, Any], group: dict[str, Any]
|
||||||
|
) -> None:
|
||||||
# Dictionary with tag keys and values, value lists, or "*"
|
# Dictionary with tag keys and values, value lists, or "*"
|
||||||
super().__init__(structure)
|
super().__init__(structure, group)
|
||||||
|
|
||||||
self.draw: bool = True
|
self.draw: bool = True
|
||||||
if "draw" in structure:
|
if "draw" in structure:
|
||||||
|
@ -268,7 +279,7 @@ class Scheme:
|
||||||
self.node_matchers: list[NodeMatcher] = []
|
self.node_matchers: list[NodeMatcher] = []
|
||||||
for group in content["node_icons"]:
|
for group in content["node_icons"]:
|
||||||
for element in group["tags"]:
|
for element in group["tags"]:
|
||||||
self.node_matchers.append(NodeMatcher(element))
|
self.node_matchers.append(NodeMatcher(element, group))
|
||||||
|
|
||||||
self.colors: dict[str, str] = content["colors"]
|
self.colors: dict[str, str] = content["colors"]
|
||||||
self.material_colors: dict[str, str] = content["material_colors"]
|
self.material_colors: dict[str, str] = content["material_colors"]
|
||||||
|
@ -341,13 +352,15 @@ class Scheme:
|
||||||
extractor: ShapeExtractor,
|
extractor: ShapeExtractor,
|
||||||
tags: dict[str, Any],
|
tags: dict[str, Any],
|
||||||
processed: set[str],
|
processed: set[str],
|
||||||
) -> tuple[IconSet, int]:
|
zoom_level: int,
|
||||||
|
) -> tuple[Optional[IconSet], int]:
|
||||||
"""
|
"""
|
||||||
Construct icon set.
|
Construct icon set.
|
||||||
|
|
||||||
:param extractor: extractor with icon specifications
|
:param extractor: extractor with icon specifications
|
||||||
:param tags: OpenStreetMap element tags dictionary
|
:param tags: OpenStreetMap element tags dictionary
|
||||||
:param processed: set of already processed tag keys
|
:param processed: set of already processed tag keys
|
||||||
|
:param zoom_level: zoom level in current context
|
||||||
:return (icon set, icon priority)
|
:return (icon set, icon priority)
|
||||||
"""
|
"""
|
||||||
tags_hash: str = (
|
tags_hash: str = (
|
||||||
|
@ -365,9 +378,10 @@ class Scheme:
|
||||||
for matcher in self.node_matchers:
|
for matcher in self.node_matchers:
|
||||||
if not matcher.replace_shapes and main_icon:
|
if not matcher.replace_shapes and main_icon:
|
||||||
continue
|
continue
|
||||||
matched: bool = matcher.is_matched(tags)
|
if not matcher.is_matched(tags):
|
||||||
if not matched:
|
|
||||||
continue
|
continue
|
||||||
|
if not matcher.check_zoom_level(zoom_level):
|
||||||
|
return None, 0
|
||||||
matcher_tags: set[str] = set(matcher.tags.keys())
|
matcher_tags: set[str] = set(matcher.tags.keys())
|
||||||
priority = len(self.node_matchers) - index
|
priority = len(self.node_matchers) - index
|
||||||
if not matcher.draw:
|
if not matcher.draw:
|
||||||
|
|
|
@ -42,14 +42,14 @@ class _Handler(SimpleHTTPRequestHandler):
|
||||||
zoom_level: int = int(parts[2])
|
zoom_level: int = int(parts[2])
|
||||||
x: int = int(parts[3])
|
x: int = int(parts[3])
|
||||||
y: int = int(parts[4])
|
y: int = int(parts[4])
|
||||||
|
tile: Tile = Tile(x, y, zoom_level)
|
||||||
tile_path: Path = workspace.get_tile_path()
|
tile_path: Path = workspace.get_tile_path()
|
||||||
png_path: Path = tile_path / f"tile_{zoom_level}_{x}_{y}.png"
|
svg_path: Path = tile.get_file_name(tile_path)
|
||||||
|
png_path: Path = svg_path.with_suffix(".png")
|
||||||
|
|
||||||
if self.update_cache:
|
if self.update_cache:
|
||||||
svg_path: Path = png_path.with_suffix(".svg")
|
|
||||||
if not png_path.exists():
|
if not png_path.exists():
|
||||||
if not svg_path.exists():
|
if not svg_path.exists():
|
||||||
tile = Tile(x, y, zoom_level)
|
|
||||||
tile.draw(tile_path, self.cache, self.options)
|
tile.draw(tile_path, self.cache, self.options)
|
||||||
with svg_path.open() as input_file:
|
with svg_path.open() as input_file:
|
||||||
cairosvg.svg2png(
|
cairosvg.svg2png(
|
||||||
|
|
|
@ -9,6 +9,7 @@ from colour import Color
|
||||||
__author__ = "Sergey Vartanov"
|
__author__ = "Sergey Vartanov"
|
||||||
__email__ = "me@enzet.ru"
|
__email__ = "me@enzet.ru"
|
||||||
|
|
||||||
|
DEFAULT_FONT_SIZE: float = 10.0
|
||||||
DEFAULT_COLOR: Color = Color("#444444")
|
DEFAULT_COLOR: Color = Color("#444444")
|
||||||
|
|
||||||
|
|
||||||
|
@ -20,7 +21,7 @@ class Label:
|
||||||
|
|
||||||
text: str
|
text: str
|
||||||
fill: Color = DEFAULT_COLOR
|
fill: Color = DEFAULT_COLOR
|
||||||
size: float = 10.0
|
size: float = DEFAULT_FONT_SIZE
|
||||||
|
|
||||||
|
|
||||||
def get_address(
|
def get_address(
|
||||||
|
|
|
@ -15,15 +15,15 @@ import numpy as np
|
||||||
import svgwrite
|
import svgwrite
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
from roentgen.boundary_box import BoundaryBox
|
||||||
from roentgen.constructor import Constructor
|
from roentgen.constructor import Constructor
|
||||||
from roentgen.flinger import Flinger
|
from roentgen.flinger import Flinger
|
||||||
from roentgen.icon import ShapeExtractor
|
from roentgen.icon import ShapeExtractor
|
||||||
from roentgen.mapper import Map
|
|
||||||
from roentgen.map_configuration import MapConfiguration
|
from roentgen.map_configuration import MapConfiguration
|
||||||
|
from roentgen.mapper import Map
|
||||||
from roentgen.osm_getter import NetworkError, get_osm
|
from roentgen.osm_getter import NetworkError, get_osm
|
||||||
from roentgen.osm_reader import OSMData, OSMReader
|
from roentgen.osm_reader import OSMData, OSMReader
|
||||||
from roentgen.scheme import Scheme
|
from roentgen.scheme import Scheme
|
||||||
from roentgen.boundary_box import BoundaryBox
|
|
||||||
from roentgen.workspace import workspace
|
from roentgen.workspace import workspace
|
||||||
|
|
||||||
__author__ = "Sergey Vartanov"
|
__author__ = "Sergey Vartanov"
|
||||||
|
@ -398,8 +398,6 @@ def parse_zoom_level(zoom_level_specification: str) -> list[int]:
|
||||||
def parse(zoom_level: str) -> int:
|
def parse(zoom_level: str) -> int:
|
||||||
"""Parse zoom level."""
|
"""Parse zoom level."""
|
||||||
parsed_zoom_level: int = int(zoom_level)
|
parsed_zoom_level: int = int(zoom_level)
|
||||||
if parsed_zoom_level <= 0:
|
|
||||||
raise ScaleConfigurationException("Non positive zoom level.")
|
|
||||||
if parsed_zoom_level > 20:
|
if parsed_zoom_level > 20:
|
||||||
raise ScaleConfigurationException("Scale is too big.")
|
raise ScaleConfigurationException("Scale is too big.")
|
||||||
return parsed_zoom_level
|
return parsed_zoom_level
|
||||||
|
|
|
@ -97,7 +97,8 @@ node_icons:
|
||||||
- tags: {building: "yes"}
|
- tags: {building: "yes"}
|
||||||
draw: false
|
draw: false
|
||||||
|
|
||||||
- group: "Transport hubs"
|
- group: "Huge transport hubs"
|
||||||
|
start_zoom_level: 10
|
||||||
tags:
|
tags:
|
||||||
- tags: {amenity: ferry_terminal}
|
- tags: {amenity: ferry_terminal}
|
||||||
shapes: [anchor]
|
shapes: [anchor]
|
||||||
|
@ -111,6 +112,10 @@ node_icons:
|
||||||
shapes: [h]
|
shapes: [h]
|
||||||
- tags: {aeroway: spaceport}
|
- tags: {aeroway: spaceport}
|
||||||
shapes: [rocket_on_launch_pad]
|
shapes: [rocket_on_launch_pad]
|
||||||
|
|
||||||
|
- group: "Normal transport hubs"
|
||||||
|
start_zoom_level: 11
|
||||||
|
tags:
|
||||||
- tags: {aeroway: launchpad}
|
- tags: {aeroway: launchpad}
|
||||||
shapes: [rocket_flying]
|
shapes: [rocket_flying]
|
||||||
- tags: {aeroway: landingpad}
|
- tags: {aeroway: landingpad}
|
||||||
|
@ -157,6 +162,7 @@ node_icons:
|
||||||
shapes: [taxi]
|
shapes: [taxi]
|
||||||
|
|
||||||
- group: "Big territory"
|
- group: "Big territory"
|
||||||
|
start_zoom_level: 12
|
||||||
tags:
|
tags:
|
||||||
- tags: {leisure: fishing}
|
- tags: {leisure: fishing}
|
||||||
shapes: [fishing_angle]
|
shapes: [fishing_angle]
|
||||||
|
@ -198,6 +204,7 @@ node_icons:
|
||||||
shapes: [{shape: pear, color: orchard_border_color}]
|
shapes: [{shape: pear, color: orchard_border_color}]
|
||||||
|
|
||||||
- group: "Bigger objects"
|
- group: "Bigger objects"
|
||||||
|
start_zoom_level: 13
|
||||||
tags:
|
tags:
|
||||||
- tags: {waterway: waterfall}
|
- tags: {waterway: waterfall}
|
||||||
shapes: [{shape: waterfall, color: water_border_color}]
|
shapes: [{shape: waterfall, color: water_border_color}]
|
||||||
|
@ -281,6 +288,7 @@ node_icons:
|
||||||
shapes: [slide_and_water]
|
shapes: [slide_and_water]
|
||||||
|
|
||||||
- group: "Important big objects"
|
- group: "Important big objects"
|
||||||
|
start_zoom_level: 14
|
||||||
tags:
|
tags:
|
||||||
- tags: {amenity: pharmacy}
|
- tags: {amenity: pharmacy}
|
||||||
shapes: [medicine_bottle]
|
shapes: [medicine_bottle]
|
||||||
|
@ -349,6 +357,7 @@ node_icons:
|
||||||
location_restrictions: {include: jp}
|
location_restrictions: {include: jp}
|
||||||
|
|
||||||
- group: "Normal big objects"
|
- group: "Normal big objects"
|
||||||
|
start_zoom_level: 15
|
||||||
tags:
|
tags:
|
||||||
- tags: {shop: supermarket}
|
- tags: {shop: supermarket}
|
||||||
shapes: [supermarket_cart]
|
shapes: [supermarket_cart]
|
||||||
|
@ -529,6 +538,7 @@ node_icons:
|
||||||
shapes: [table]
|
shapes: [table]
|
||||||
|
|
||||||
- group: "Big objects not for all"
|
- group: "Big objects not for all"
|
||||||
|
start_zoom_level: 15
|
||||||
tags:
|
tags:
|
||||||
- tags: {building: apartments}
|
- tags: {building: apartments}
|
||||||
shapes: [apartments]
|
shapes: [apartments]
|
||||||
|
@ -551,6 +561,7 @@ node_icons:
|
||||||
shapes: [telephone]
|
shapes: [telephone]
|
||||||
|
|
||||||
- group: "Not important big objects"
|
- group: "Not important big objects"
|
||||||
|
start_zoom_level: 15
|
||||||
tags:
|
tags:
|
||||||
- tags: {man_made: communications_tower}
|
- tags: {man_made: communications_tower}
|
||||||
location_restrictions: {include: jp}
|
location_restrictions: {include: jp}
|
||||||
|
@ -571,6 +582,7 @@ node_icons:
|
||||||
shapes: [garages]
|
shapes: [garages]
|
||||||
|
|
||||||
- group: "Emergency"
|
- group: "Emergency"
|
||||||
|
start_zoom_level: 15
|
||||||
tags:
|
tags:
|
||||||
- tags: {emergency: defibrillator}
|
- tags: {emergency: defibrillator}
|
||||||
shapes: [{shape: defibrillator, color: emergency_color}]
|
shapes: [{shape: defibrillator, color: emergency_color}]
|
||||||
|
@ -584,6 +596,7 @@ node_icons:
|
||||||
shapes: [{shape: sos_phone, color: emergency_color}]
|
shapes: [{shape: sos_phone, color: emergency_color}]
|
||||||
|
|
||||||
- group: "Transport-important middle objects"
|
- group: "Transport-important middle objects"
|
||||||
|
start_zoom_level: 16
|
||||||
tags:
|
tags:
|
||||||
- tags: {ford: "yes"}
|
- tags: {ford: "yes"}
|
||||||
shapes: [ford]
|
shapes: [ford]
|
||||||
|
@ -625,6 +638,7 @@ node_icons:
|
||||||
shapes: [bump]
|
shapes: [bump]
|
||||||
|
|
||||||
- group: "Important middle objects"
|
- group: "Important middle objects"
|
||||||
|
start_zoom_level: 16
|
||||||
tags:
|
tags:
|
||||||
- tags: {tourism: attraction, attraction: amusement_ride}
|
- tags: {tourism: attraction, attraction: amusement_ride}
|
||||||
shapes: [amusement_ride]
|
shapes: [amusement_ride]
|
||||||
|
@ -634,6 +648,7 @@ node_icons:
|
||||||
shapes: [shelter]
|
shapes: [shelter]
|
||||||
|
|
||||||
- group: "Normal middle objects"
|
- group: "Normal middle objects"
|
||||||
|
start_zoom_level: 17
|
||||||
tags:
|
tags:
|
||||||
- tags: {shop: kiosk}
|
- tags: {shop: kiosk}
|
||||||
shapes: [kiosk]
|
shapes: [kiosk]
|
||||||
|
@ -653,6 +668,7 @@ node_icons:
|
||||||
shapes: [pipeline]
|
shapes: [pipeline]
|
||||||
|
|
||||||
- group: "Not important middle objects"
|
- group: "Not important middle objects"
|
||||||
|
start_zoom_level: 17
|
||||||
tags:
|
tags:
|
||||||
- tags: {building: ventilation_shaft}
|
- tags: {building: ventilation_shaft}
|
||||||
shapes: [ventilation]
|
shapes: [ventilation]
|
||||||
|
@ -915,6 +931,7 @@ node_icons:
|
||||||
add_shapes: [phone]
|
add_shapes: [phone]
|
||||||
|
|
||||||
- group: "Important small objects"
|
- group: "Important small objects"
|
||||||
|
start_zoom_level: 17
|
||||||
tags:
|
tags:
|
||||||
- tags: {historic: cannon}
|
- tags: {historic: cannon}
|
||||||
shapes: [cannon]
|
shapes: [cannon]
|
||||||
|
@ -999,6 +1016,7 @@ node_icons:
|
||||||
shapes: {christmas_tree}
|
shapes: {christmas_tree}
|
||||||
|
|
||||||
- group: "Normal small objects"
|
- group: "Normal small objects"
|
||||||
|
start_zoom_level: 18
|
||||||
tags:
|
tags:
|
||||||
- tags: {amenity: binoculars}
|
- tags: {amenity: binoculars}
|
||||||
shapes: [binoculars_on_pole]
|
shapes: [binoculars_on_pole]
|
||||||
|
@ -1044,6 +1062,7 @@ node_icons:
|
||||||
shapes: [golf_pin]
|
shapes: [golf_pin]
|
||||||
|
|
||||||
- group: "Entrances"
|
- group: "Entrances"
|
||||||
|
start_zoom_level: 18
|
||||||
tags:
|
tags:
|
||||||
- tags: {amenity: parking_entrance}
|
- tags: {amenity: parking_entrance}
|
||||||
shapes:
|
shapes:
|
||||||
|
@ -1073,6 +1092,7 @@ node_icons:
|
||||||
shapes: [no_door]
|
shapes: [no_door]
|
||||||
|
|
||||||
- group: "Not important small objects"
|
- group: "Not important small objects"
|
||||||
|
start_zoom_level: 18
|
||||||
tags:
|
tags:
|
||||||
- tags: {amenity: bench}
|
- tags: {amenity: bench}
|
||||||
shapes: [bench]
|
shapes: [bench]
|
||||||
|
@ -1228,6 +1248,7 @@ node_icons:
|
||||||
shapes: [bollard]
|
shapes: [bollard]
|
||||||
|
|
||||||
- group: "Indoor"
|
- group: "Indoor"
|
||||||
|
start_zoom_level: 18
|
||||||
tags:
|
tags:
|
||||||
- tags: {door: "yes"}
|
- tags: {door: "yes"}
|
||||||
shapes: [entrance]
|
shapes: [entrance]
|
||||||
|
|
|
@ -24,7 +24,7 @@ def test_grid(init_collection: IconCollection) -> None:
|
||||||
|
|
||||||
def test_icons_by_id(init_collection: IconCollection) -> None:
|
def test_icons_by_id(init_collection: IconCollection) -> None:
|
||||||
"""Test individual icons drawing."""
|
"""Test individual icons drawing."""
|
||||||
init_collection.draw_icons(workspace.get_icons_by_id_path(), by_name=False)
|
init_collection.draw_icons(workspace.get_icons_by_id_path())
|
||||||
|
|
||||||
|
|
||||||
def test_icons_by_name(init_collection: IconCollection) -> None:
|
def test_icons_by_name(init_collection: IconCollection) -> None:
|
||||||
|
@ -35,7 +35,7 @@ def test_icons_by_name(init_collection: IconCollection) -> None:
|
||||||
def get_icon(tags: dict[str, str]) -> IconSet:
|
def get_icon(tags: dict[str, str]) -> IconSet:
|
||||||
"""Construct icon from tags."""
|
"""Construct icon from tags."""
|
||||||
processed: set[str] = set()
|
processed: set[str] = set()
|
||||||
icon, _ = SCHEME.get_icon(SHAPE_EXTRACTOR, tags, processed)
|
icon, _ = SCHEME.get_icon(SHAPE_EXTRACTOR, tags, processed, 18)
|
||||||
return icon
|
return icon
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ def test_mapcss() -> None:
|
||||||
"""Test MapCSS generation."""
|
"""Test MapCSS generation."""
|
||||||
writer: MapCSSWriter = MapCSSWriter(SCHEME, "icons")
|
writer: MapCSSWriter = MapCSSWriter(SCHEME, "icons")
|
||||||
matcher: NodeMatcher = NodeMatcher(
|
matcher: NodeMatcher = NodeMatcher(
|
||||||
{"tags": {"natural": "tree"}, "shapes": ["tree"]}
|
{"tags": {"natural": "tree"}, "shapes": ["tree"]}, {}
|
||||||
)
|
)
|
||||||
selector = writer.add_selector("node", matcher)
|
selector = writer.add_selector("node", matcher)
|
||||||
assert (
|
assert (
|
||||||
|
|
|
@ -1,23 +1,57 @@
|
||||||
"""
|
"""
|
||||||
Test zoom level specification parsing.
|
Test zoom level specification parsing.
|
||||||
"""
|
"""
|
||||||
from roentgen.tile import parse_zoom_level
|
from roentgen.tile import ScaleConfigurationException, parse_zoom_level
|
||||||
|
|
||||||
|
|
||||||
def test_zoom_level_1() -> None:
|
def test_zoom_level_1() -> None:
|
||||||
|
"""Test one zoom level."""
|
||||||
assert parse_zoom_level("18") == [18]
|
assert parse_zoom_level("18") == [18]
|
||||||
|
|
||||||
|
|
||||||
def test_zoom_level_list() -> None:
|
def test_zoom_level_list() -> None:
|
||||||
|
"""Test list of zoom levels."""
|
||||||
assert parse_zoom_level("17,18") == [17, 18]
|
assert parse_zoom_level("17,18") == [17, 18]
|
||||||
assert parse_zoom_level("16,17,18") == [16, 17, 18]
|
assert parse_zoom_level("16,17,18") == [16, 17, 18]
|
||||||
|
|
||||||
|
|
||||||
def test_zoom_level_range() -> None:
|
def test_zoom_level_range() -> None:
|
||||||
|
"""Test range of zoom levels."""
|
||||||
assert parse_zoom_level("16-18") == [16, 17, 18]
|
assert parse_zoom_level("16-18") == [16, 17, 18]
|
||||||
assert parse_zoom_level("18-18") == [18]
|
assert parse_zoom_level("18-18") == [18]
|
||||||
|
|
||||||
|
|
||||||
def test_zoom_level_mixed() -> None:
|
def test_zoom_level_mixed() -> None:
|
||||||
|
"""Test zoom level specification with list of numbers and ranges."""
|
||||||
assert parse_zoom_level("15,16-18") == [15, 16, 17, 18]
|
assert parse_zoom_level("15,16-18") == [15, 16, 17, 18]
|
||||||
assert parse_zoom_level("15,16-18,20") == [15, 16, 17, 18, 20]
|
assert parse_zoom_level("15,16-18,20") == [15, 16, 17, 18, 20]
|
||||||
|
|
||||||
|
|
||||||
|
def test_zoom_level_too_big() -> None:
|
||||||
|
"""Test too big zoom level."""
|
||||||
|
try:
|
||||||
|
parse_zoom_level("21")
|
||||||
|
except ScaleConfigurationException:
|
||||||
|
return
|
||||||
|
|
||||||
|
assert False
|
||||||
|
|
||||||
|
|
||||||
|
def test_zoom_level_negative() -> None:
|
||||||
|
"""Test negative zoom level."""
|
||||||
|
try:
|
||||||
|
parse_zoom_level("-1")
|
||||||
|
except ValueError:
|
||||||
|
return
|
||||||
|
|
||||||
|
assert False
|
||||||
|
|
||||||
|
|
||||||
|
def test_zoom_level_wrong() -> None:
|
||||||
|
"""Test too big zoom level."""
|
||||||
|
try:
|
||||||
|
parse_zoom_level(",")
|
||||||
|
except ValueError:
|
||||||
|
return
|
||||||
|
|
||||||
|
assert False
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue