mirror of
https://github.com/enzet/map-machine.git
synced 2025-05-22 05:26:24 +02:00
Get use of map configuration.
This commit is contained in:
parent
56fdf9709e
commit
4c5209dabc
15 changed files with 160 additions and 130 deletions
|
@ -36,7 +36,7 @@ Röntgen features\:
|
||||||
|
|
||||||
\3 {Isometric building shapes} {levels}
|
\3 {Isometric building shapes} {levels}
|
||||||
|
|
||||||
Isometric shapes for walls and shade in proportion to \osm {building:levels}, \osm {building:min_level}, \osm {height} and \osm {min_height} values.
|
With \m {--buildings isometric} or \m {--buildings isometric-no-parts} (not set by default), buildings are drawn using isometric shapes for walls and shade in proportion to \osm {building:levels}, \osm {building:min_level}, \osm {height} and \osm {min_height} values.
|
||||||
|
|
||||||
\image {doc/buildings.png} {3D buildings}
|
\image {doc/buildings.png} {3D buildings}
|
||||||
|
|
||||||
|
@ -265,5 +265,5 @@ To enable / disable Röntgen map paint style go to \kbd {View} → \kbd {Map Pai
|
||||||
|
|
||||||
Example of using Röntgen icons on top of Mapnik style. Map Paint Styles\:
|
Example of using Röntgen icons on top of Mapnik style. Map Paint Styles\:
|
||||||
\list
|
\list
|
||||||
{✓ Mapnik}
|
{✓ Mapnik (true)}
|
||||||
{✓ Röntgen}
|
{✓ Röntgen}
|
||||||
|
|
|
@ -7,6 +7,9 @@ from dataclasses import dataclass
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
__author__ = "Sergey Vartanov"
|
||||||
|
__email__ = "me@enzet.ru"
|
||||||
|
|
||||||
LATITUDE_MAX_DIFFERENCE: float = 0.5
|
LATITUDE_MAX_DIFFERENCE: float = 0.5
|
||||||
LONGITUDE_MAX_DIFFERENCE: float = 0.5
|
LONGITUDE_MAX_DIFFERENCE: float = 0.5
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Color utility.
|
Color utility.
|
||||||
"""
|
"""
|
||||||
from typing import Any, List
|
from typing import Any
|
||||||
|
|
||||||
from colour import Color
|
from colour import Color
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ def is_bright(color: Color) -> bool:
|
||||||
|
|
||||||
|
|
||||||
def get_gradient_color(
|
def get_gradient_color(
|
||||||
value: Any, bounds: MinMax, colors: List[Color]
|
value: Any, bounds: MinMax, colors: list[Color]
|
||||||
) -> Color:
|
) -> Color:
|
||||||
"""
|
"""
|
||||||
Get color from the color scale for the value.
|
Get color from the color scale for the value.
|
||||||
|
@ -32,7 +32,7 @@ def get_gradient_color(
|
||||||
:param colors: color scale
|
:param colors: color scale
|
||||||
"""
|
"""
|
||||||
color_length: int = len(colors) - 1
|
color_length: int = len(colors) - 1
|
||||||
scale: List[Color] = colors + [Color("black")]
|
scale: list[Color] = colors + [Color("black")]
|
||||||
|
|
||||||
range_coefficient: float = (
|
range_coefficient: float = (
|
||||||
0 if bounds.is_empty() else (value - bounds.min_) / bounds.delta()
|
0 if bounds.is_empty() else (value - bounds.min_) / bounds.delta()
|
||||||
|
|
|
@ -13,6 +13,7 @@ from roentgen import ui
|
||||||
from roentgen.color import get_gradient_color
|
from roentgen.color import get_gradient_color
|
||||||
from roentgen.figure import Building, DirectionSector, Road, StyledFigure, Tree
|
from roentgen.figure import Building, DirectionSector, Road, StyledFigure, Tree
|
||||||
from roentgen.flinger import Flinger
|
from roentgen.flinger import Flinger
|
||||||
|
from roentgen.map_configuration import DrawingMode, MapConfiguration
|
||||||
|
|
||||||
# fmt: off
|
# fmt: off
|
||||||
from roentgen.icon import (
|
from roentgen.icon import (
|
||||||
|
@ -21,9 +22,8 @@ from roentgen.icon import (
|
||||||
from roentgen.osm_reader import OSMData, OSMNode, OSMRelation, OSMWay
|
from roentgen.osm_reader import OSMData, OSMNode, OSMRelation, OSMWay
|
||||||
from roentgen.point import Point
|
from roentgen.point import Point
|
||||||
from roentgen.scheme import DEFAULT_COLOR, LineStyle, Scheme
|
from roentgen.scheme import DEFAULT_COLOR, LineStyle, Scheme
|
||||||
from roentgen.ui import AUTHOR_MODE, BuildingMode, TIME_MODE
|
from roentgen.ui import BuildingMode
|
||||||
from roentgen.util import MinMax
|
from roentgen.util import MinMax
|
||||||
|
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
|
||||||
__author__ = "Sergey Vartanov"
|
__author__ = "Sergey Vartanov"
|
||||||
|
@ -113,7 +113,7 @@ def glue(ways: list[OSMWay]) -> list[list[OSMNode]]:
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def is_cycle(nodes) -> bool:
|
def is_cycle(nodes: list[OSMNode]) -> bool:
|
||||||
"""Is way a cycle way or an area boundary."""
|
"""Is way a cycle way or an area boundary."""
|
||||||
return nodes[0] == nodes[-1]
|
return nodes[0] == nodes[-1]
|
||||||
|
|
||||||
|
@ -129,22 +129,22 @@ class Constructor:
|
||||||
flinger: Flinger,
|
flinger: Flinger,
|
||||||
scheme: Scheme,
|
scheme: Scheme,
|
||||||
icon_extractor: ShapeExtractor,
|
icon_extractor: ShapeExtractor,
|
||||||
options,
|
configuration: MapConfiguration,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.osm_data: OSMData = osm_data
|
self.osm_data: OSMData = osm_data
|
||||||
self.flinger: Flinger = flinger
|
self.flinger: Flinger = flinger
|
||||||
self.scheme: Scheme = scheme
|
self.scheme: Scheme = scheme
|
||||||
self.icon_extractor = icon_extractor
|
self.icon_extractor = icon_extractor
|
||||||
self.options = options
|
self.configuration = configuration
|
||||||
|
|
||||||
if options.level:
|
if self.configuration.level:
|
||||||
if options.level == "overground":
|
if self.configuration.level == "overground":
|
||||||
self.check_level = check_level_overground
|
self.check_level = check_level_overground
|
||||||
elif options.level == "underground":
|
elif self.configuration.level == "underground":
|
||||||
self.check_level = lambda x: not check_level_overground(x)
|
self.check_level = lambda x: not check_level_overground(x)
|
||||||
else:
|
else:
|
||||||
self.check_level = lambda x: not check_level_number(
|
self.check_level = lambda x: not check_level_number(
|
||||||
x, float(options.level)
|
x, float(self.configuration.level)
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.check_level = lambda x: True
|
self.check_level = lambda x: True
|
||||||
|
@ -203,10 +203,10 @@ class Constructor:
|
||||||
return
|
return
|
||||||
|
|
||||||
center_point, center_coordinates = line_center(outers[0], self.flinger)
|
center_point, center_coordinates = line_center(outers[0], self.flinger)
|
||||||
if self.options.mode in [AUTHOR_MODE, TIME_MODE]:
|
if self.configuration.is_wireframe():
|
||||||
color: Color
|
color: Color
|
||||||
if self.options.mode == AUTHOR_MODE:
|
if self.configuration.drawing_mode == DrawingMode.AUTHOR:
|
||||||
color = get_user_color(line.user, self.options.seed)
|
color = get_user_color(line.user, self.configuration.seed)
|
||||||
else: # self.mode == TIME_MODE
|
else: # self.mode == TIME_MODE
|
||||||
color = get_time_color(line.timestamp, self.osm_data.time)
|
color = get_time_color(line.timestamp, self.osm_data.time)
|
||||||
self.draw_special_mode(inners, line, outers, color)
|
self.draw_special_mode(inners, line, outers, color)
|
||||||
|
@ -215,7 +215,7 @@ class Constructor:
|
||||||
if not line.tags:
|
if not line.tags:
|
||||||
return
|
return
|
||||||
|
|
||||||
building_mode: BuildingMode = BuildingMode(self.options.buildings)
|
building_mode: BuildingMode = self.configuration.building_mode
|
||||||
if "building" in line.tags or (
|
if "building" in line.tags or (
|
||||||
building_mode == BuildingMode.ISOMETRIC
|
building_mode == BuildingMode.ISOMETRIC
|
||||||
and "building:part" in line.tags
|
and "building:part" in line.tags
|
||||||
|
@ -352,13 +352,13 @@ class Constructor:
|
||||||
icon_set: IconSet
|
icon_set: IconSet
|
||||||
draw_outline: bool = True
|
draw_outline: bool = True
|
||||||
|
|
||||||
if self.options.mode in [TIME_MODE, AUTHOR_MODE]:
|
if self.configuration.is_wireframe():
|
||||||
if not tags:
|
if not tags:
|
||||||
return
|
return
|
||||||
color: Color = DEFAULT_COLOR
|
color: Color = DEFAULT_COLOR
|
||||||
if self.options.mode == AUTHOR_MODE:
|
if self.configuration.drawing_mode == DrawingMode.AUTHOR:
|
||||||
color = get_user_color(node.user, self.options.seed)
|
color = get_user_color(node.user, self.configuration.seed)
|
||||||
if self.options.mode == TIME_MODE:
|
if self.configuration.drawing_mode == DrawingMode.TIME:
|
||||||
color = get_time_color(node.timestamp, self.osm_data.time)
|
color = get_time_color(node.timestamp, self.osm_data.time)
|
||||||
dot = self.icon_extractor.get_shape(DEFAULT_SMALL_SHAPE_ID)
|
dot = self.icon_extractor.get_shape(DEFAULT_SMALL_SHAPE_ID)
|
||||||
icon_set = IconSet(
|
icon_set = IconSet(
|
||||||
|
|
|
@ -3,7 +3,7 @@ Drawing utility.
|
||||||
"""
|
"""
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import List, Optional, Union
|
from typing import Optional, Union
|
||||||
|
|
||||||
import cairo
|
import cairo
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -73,7 +73,7 @@ class Drawing:
|
||||||
"""Draw rectangle."""
|
"""Draw rectangle."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
def line(self, points: List[np.ndarray], style: Style) -> None:
|
def line(self, points: list[np.ndarray], style: Style) -> None:
|
||||||
"""Draw line."""
|
"""Draw line."""
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ class SVGDrawing(Drawing):
|
||||||
style.update_svg_element(rectangle)
|
style.update_svg_element(rectangle)
|
||||||
self.image.add(rectangle)
|
self.image.add(rectangle)
|
||||||
|
|
||||||
def line(self, points: List[np.ndarray], style: Style) -> None:
|
def line(self, points: list[np.ndarray], style: Style) -> None:
|
||||||
"""Draw line."""
|
"""Draw line."""
|
||||||
commands: PathCommands = ["M"]
|
commands: PathCommands = ["M"]
|
||||||
for point in points:
|
for point in points:
|
||||||
|
@ -159,7 +159,7 @@ class PNGDrawing(Drawing):
|
||||||
self.context.rectangle(point_1[0], point_1[1], size[0], size[1])
|
self.context.rectangle(point_1[0], point_1[1], size[0], size[1])
|
||||||
style.draw_png_stroke(self.context)
|
style.draw_png_stroke(self.context)
|
||||||
|
|
||||||
def line(self, points: List[np.ndarray], style: Style) -> None:
|
def line(self, points: list[np.ndarray], style: Style) -> None:
|
||||||
"""Draw line."""
|
"""Draw line."""
|
||||||
if style.fill is not None:
|
if style.fill is not None:
|
||||||
self.context.move_to(float(points[0][0]), float(points[0][1]))
|
self.context.move_to(float(points[0][0]), float(points[0][1]))
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
"""
|
"""
|
||||||
Drawing separate map elements.
|
Drawing separate map elements.
|
||||||
"""
|
"""
|
||||||
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -13,15 +13,18 @@ from roentgen.point import Point
|
||||||
from roentgen.scheme import LineStyle, Scheme
|
from roentgen.scheme import LineStyle, Scheme
|
||||||
from roentgen.workspace import workspace
|
from roentgen.workspace import workspace
|
||||||
|
|
||||||
|
__author__ = "Sergey Vartanov"
|
||||||
|
__email__ = "me@enzet.ru"
|
||||||
|
|
||||||
def draw_element(options) -> None:
|
|
||||||
|
def draw_element(options: argparse.Namespace) -> None:
|
||||||
"""Draw single node, line, or area."""
|
"""Draw single node, line, or area."""
|
||||||
if options.node:
|
if options.node:
|
||||||
target: str = "node"
|
target: str = "node"
|
||||||
tags_description = options.node
|
tags_description = options.node
|
||||||
else:
|
else:
|
||||||
# Not implemented yet.
|
# Not implemented yet.
|
||||||
sys.exit(1)
|
exit(1)
|
||||||
|
|
||||||
tags: dict[str, str] = dict(
|
tags: dict[str, str] = dict(
|
||||||
[x.split("=") for x in tags_description.split(",")]
|
[x.split("=") for x in tags_description.split(",")]
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Figures displayed on the map.
|
Figures displayed on the map.
|
||||||
"""
|
"""
|
||||||
from typing import Any, Dict, List, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from colour import Color
|
from colour import Color
|
||||||
|
@ -25,15 +25,15 @@ class Figure(Tagged):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
tags: Dict[str, str],
|
tags: dict[str, str],
|
||||||
inners: List[List[OSMNode]],
|
inners: list[list[OSMNode]],
|
||||||
outers: List[List[OSMNode]],
|
outers: list[list[OSMNode]],
|
||||||
) -> None:
|
) -> None:
|
||||||
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]] = []
|
||||||
self.outers: List[List[OSMNode]] = []
|
self.outers: list[list[OSMNode]] = []
|
||||||
|
|
||||||
for inner_nodes in inners:
|
for inner_nodes in inners:
|
||||||
self.inners.append(make_clockwise(inner_nodes))
|
self.inners.append(make_clockwise(inner_nodes))
|
||||||
|
@ -67,15 +67,15 @@ class Building(Figure):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
tags: Dict[str, str],
|
tags: dict[str, str],
|
||||||
inners: List[List[OSMNode]],
|
inners: list[list[OSMNode]],
|
||||||
outers: List[List[OSMNode]],
|
outers: list[list[OSMNode]],
|
||||||
flinger: Flinger,
|
flinger: Flinger,
|
||||||
scheme: Scheme,
|
scheme: Scheme,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(tags, inners, outers)
|
super().__init__(tags, inners, outers)
|
||||||
|
|
||||||
style: Dict[str, Any] = {
|
style: dict[str, Any] = {
|
||||||
"fill": scheme.get_color("building_color").hex,
|
"fill": scheme.get_color("building_color").hex,
|
||||||
"stroke": scheme.get_color("building_border_color").hex,
|
"stroke": scheme.get_color("building_border_color").hex,
|
||||||
}
|
}
|
||||||
|
@ -195,9 +195,9 @@ class StyledFigure(Figure):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
tags: Dict[str, str],
|
tags: dict[str, str],
|
||||||
inners: List[List[OSMNode]],
|
inners: list[list[OSMNode]],
|
||||||
outers: List[List[OSMNode]],
|
outers: list[list[OSMNode]],
|
||||||
line_style: LineStyle,
|
line_style: LineStyle,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(tags, inners, outers)
|
super().__init__(tags, inners, outers)
|
||||||
|
@ -211,16 +211,16 @@ class Road(Figure):
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
tags: Dict[str, str],
|
tags: dict[str, str],
|
||||||
inners: List[List[OSMNode]],
|
inners: list[list[OSMNode]],
|
||||||
outers: List[List[OSMNode]],
|
outers: list[list[OSMNode]],
|
||||||
matcher: RoadMatcher,
|
matcher: RoadMatcher,
|
||||||
) -> None:
|
) -> None:
|
||||||
super().__init__(tags, inners, outers)
|
super().__init__(tags, inners, outers)
|
||||||
self.matcher: RoadMatcher = matcher
|
self.matcher: RoadMatcher = matcher
|
||||||
|
|
||||||
self.width: Optional[float] = None
|
self.width: Optional[float] = None
|
||||||
self.lanes: List[Lane] = []
|
self.lanes: list[Lane] = []
|
||||||
|
|
||||||
if "lanes" in tags:
|
if "lanes" in tags:
|
||||||
try:
|
try:
|
||||||
|
@ -359,7 +359,7 @@ class Segment:
|
||||||
) # fmt: skip
|
) # fmt: skip
|
||||||
|
|
||||||
|
|
||||||
def is_clockwise(polygon: List[OSMNode]) -> bool:
|
def is_clockwise(polygon: list[OSMNode]) -> bool:
|
||||||
"""
|
"""
|
||||||
Return true if polygon nodes are in clockwise order.
|
Return true if polygon nodes are in clockwise order.
|
||||||
|
|
||||||
|
@ -374,7 +374,7 @@ def is_clockwise(polygon: List[OSMNode]) -> bool:
|
||||||
return count >= 0
|
return count >= 0
|
||||||
|
|
||||||
|
|
||||||
def make_clockwise(polygon: List[OSMNode]) -> List[OSMNode]:
|
def make_clockwise(polygon: list[OSMNode]) -> list[OSMNode]:
|
||||||
"""
|
"""
|
||||||
Make polygon nodes clockwise.
|
Make polygon nodes clockwise.
|
||||||
|
|
||||||
|
@ -383,7 +383,7 @@ def make_clockwise(polygon: List[OSMNode]) -> List[OSMNode]:
|
||||||
return polygon if is_clockwise(polygon) else list(reversed(polygon))
|
return polygon if is_clockwise(polygon) else list(reversed(polygon))
|
||||||
|
|
||||||
|
|
||||||
def make_counter_clockwise(polygon: List[OSMNode]) -> List[OSMNode]:
|
def make_counter_clockwise(polygon: list[OSMNode]) -> list[OSMNode]:
|
||||||
"""
|
"""
|
||||||
Make polygon nodes counter-clockwise.
|
Make polygon nodes counter-clockwise.
|
||||||
|
|
||||||
|
@ -392,7 +392,7 @@ def make_counter_clockwise(polygon: List[OSMNode]) -> List[OSMNode]:
|
||||||
return polygon if not is_clockwise(polygon) else list(reversed(polygon))
|
return polygon if not is_clockwise(polygon) else list(reversed(polygon))
|
||||||
|
|
||||||
|
|
||||||
def get_path(nodes: List[OSMNode], shift: np.array, flinger: Flinger) -> str:
|
def get_path(nodes: list[OSMNode], shift: np.array, flinger: Flinger) -> str:
|
||||||
"""Construct SVG path commands from nodes."""
|
"""Construct SVG path commands from nodes."""
|
||||||
path: str = ""
|
path: str = ""
|
||||||
prev_node: Optional[OSMNode] = None
|
prev_node: Optional[OSMNode] = None
|
||||||
|
|
|
@ -34,6 +34,7 @@ class IconCollection:
|
||||||
background_color: Color = Color("white"),
|
background_color: Color = Color("white"),
|
||||||
color: Color = Color("black"),
|
color: Color = Color("black"),
|
||||||
add_unused: bool = False,
|
add_unused: bool = False,
|
||||||
|
add_all: bool = False,
|
||||||
) -> "IconCollection":
|
) -> "IconCollection":
|
||||||
"""
|
"""
|
||||||
Collect all possible icon combinations in grid.
|
Collect all possible icon combinations in grid.
|
||||||
|
@ -44,6 +45,7 @@ class IconCollection:
|
||||||
:param color: icon color
|
:param color: icon color
|
||||||
:param add_unused: create icons from shapes that have no corresponding
|
:param add_unused: create icons from shapes that have no corresponding
|
||||||
tags
|
tags
|
||||||
|
:param add_all: create icons from all possible shapes including parts
|
||||||
"""
|
"""
|
||||||
icons: list[Icon] = []
|
icons: list[Icon] = []
|
||||||
|
|
||||||
|
@ -111,6 +113,13 @@ class IconCollection:
|
||||||
icon.recolor(color)
|
icon.recolor(color)
|
||||||
icons.append(icon)
|
icons.append(icon)
|
||||||
|
|
||||||
|
if add_all:
|
||||||
|
for shape_id in extractor.shapes.keys():
|
||||||
|
shape: Shape = extractor.get_shape(shape_id)
|
||||||
|
icon: Icon = Icon([ShapeSpecification(shape)])
|
||||||
|
icon.recolor(color)
|
||||||
|
icons.append(icon)
|
||||||
|
|
||||||
return cls(icons)
|
return cls(icons)
|
||||||
|
|
||||||
def draw_icons(
|
def draw_icons(
|
||||||
|
@ -204,8 +213,9 @@ def draw_icons() -> None:
|
||||||
extractor: ShapeExtractor = ShapeExtractor(
|
extractor: ShapeExtractor = ShapeExtractor(
|
||||||
workspace.ICONS_PATH, workspace.ICONS_CONFIG_PATH
|
workspace.ICONS_PATH, workspace.ICONS_CONFIG_PATH
|
||||||
)
|
)
|
||||||
collection: IconCollection = IconCollection.from_scheme(scheme, extractor)
|
collection: IconCollection = IconCollection.from_scheme(
|
||||||
|
scheme, extractor, add_all=True
|
||||||
|
)
|
||||||
icon_grid_path: Path = workspace.get_icon_grid_path()
|
icon_grid_path: Path = workspace.get_icon_grid_path()
|
||||||
collection.draw_grid(icon_grid_path)
|
collection.draw_grid(icon_grid_path)
|
||||||
logging.info(f"Icon grid is written to {icon_grid_path}.")
|
logging.info(f"Icon grid is written to {icon_grid_path}.")
|
||||||
|
|
|
@ -322,7 +322,7 @@ class ShapeSpecification:
|
||||||
|
|
||||||
def draw(
|
def draw(
|
||||||
self,
|
self,
|
||||||
svg,
|
svg: Drawing,
|
||||||
point: np.array,
|
point: np.array,
|
||||||
tags: dict[str, Any] = None,
|
tags: dict[str, Any] = None,
|
||||||
outline: bool = False,
|
outline: bool = False,
|
||||||
|
@ -372,7 +372,7 @@ class ShapeSpecification:
|
||||||
and np.allclose(self.offset, other.offset)
|
and np.allclose(self.offset, other.offset)
|
||||||
)
|
)
|
||||||
|
|
||||||
def __lt__(self, other) -> bool:
|
def __lt__(self, other: "ShapeSpecification") -> bool:
|
||||||
return self.shape.id_ < other.shape.id_
|
return self.shape.id_ < other.shape.id_
|
||||||
|
|
||||||
|
|
||||||
|
@ -471,12 +471,12 @@ class Icon:
|
||||||
"""Add shape specifications to the icon."""
|
"""Add shape specifications to the icon."""
|
||||||
self.shape_specifications += specifications
|
self.shape_specifications += specifications
|
||||||
|
|
||||||
def __eq__(self, other) -> bool:
|
def __eq__(self, other: "Icon") -> bool:
|
||||||
return sorted(self.shape_specifications) == sorted(
|
return sorted(self.shape_specifications) == sorted(
|
||||||
other.shape_specifications
|
other.shape_specifications
|
||||||
)
|
)
|
||||||
|
|
||||||
def __lt__(self, other) -> bool:
|
def __lt__(self, other: "Icon") -> bool:
|
||||||
return "".join(
|
return "".join(
|
||||||
[x.shape.id_ for x in self.shape_specifications]
|
[x.shape.id_ for x in self.shape_specifications]
|
||||||
) < "".join([x.shape.id_ for x in other.shape_specifications])
|
) < "".join([x.shape.id_ for x in other.shape_specifications])
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
MapCSS scheme creation.
|
MapCSS scheme creation.
|
||||||
"""
|
"""
|
||||||
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Optional, TextIO
|
from typing import Optional, TextIO
|
||||||
|
@ -175,7 +176,7 @@ class MapCSSWriter:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def ui(options) -> None:
|
def ui(options: argparse.Namespace) -> None:
|
||||||
"""Write MapCSS 0.2 scheme."""
|
"""Write MapCSS 0.2 scheme."""
|
||||||
directory: Path = workspace.get_mapcss_path()
|
directory: Path = workspace.get_mapcss_path()
|
||||||
icons_with_outline_path: Path = workspace.get_mapcss_icons_path()
|
icons_with_outline_path: Path = workspace.get_mapcss_icons_path()
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Simple OpenStreetMap renderer.
|
Simple OpenStreetMap renderer.
|
||||||
"""
|
"""
|
||||||
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Any, Iterator
|
from typing import Any, Iterator
|
||||||
|
@ -17,12 +18,13 @@ from roentgen.constructor import Constructor
|
||||||
from roentgen.figure import Road
|
from roentgen.figure import Road
|
||||||
from roentgen.flinger import Flinger
|
from roentgen.flinger import Flinger
|
||||||
from roentgen.icon import ShapeExtractor
|
from roentgen.icon import ShapeExtractor
|
||||||
|
from roentgen.map_configuration import LabelMode, MapConfiguration
|
||||||
from roentgen.osm_getter import NetworkError, get_osm
|
from roentgen.osm_getter import NetworkError, get_osm
|
||||||
from roentgen.osm_reader import OSMData, OSMNode, OSMReader, OverpassReader
|
from roentgen.osm_reader import OSMData, OSMNode, OSMReader, OverpassReader
|
||||||
from roentgen.point import Occupied
|
from roentgen.point import Occupied
|
||||||
from roentgen.road import Intersection, RoadPart
|
from roentgen.road import Intersection, RoadPart
|
||||||
from roentgen.scheme import Scheme
|
from roentgen.scheme import Scheme
|
||||||
from roentgen.ui import AUTHOR_MODE, BuildingMode, TIME_MODE, progress_bar
|
from roentgen.ui import BuildingMode, progress_bar
|
||||||
from roentgen.workspace import workspace
|
from roentgen.workspace import workspace
|
||||||
|
|
||||||
__author__ = "Sergey Vartanov"
|
__author__ = "Sergey Vartanov"
|
||||||
|
@ -35,15 +37,19 @@ class Map:
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self, flinger: Flinger, svg: svgwrite.Drawing, scheme: Scheme, options
|
self,
|
||||||
|
flinger: Flinger,
|
||||||
|
svg: svgwrite.Drawing,
|
||||||
|
scheme: Scheme,
|
||||||
|
configuration: MapConfiguration,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.flinger: Flinger = flinger
|
self.flinger: Flinger = flinger
|
||||||
self.svg: svgwrite.Drawing = svg
|
self.svg: svgwrite.Drawing = svg
|
||||||
self.scheme: Scheme = scheme
|
self.scheme: Scheme = scheme
|
||||||
self.options = options
|
self.configuration = configuration
|
||||||
|
|
||||||
self.background_color: Color = self.scheme.get_color("background_color")
|
self.background_color: Color = self.scheme.get_color("background_color")
|
||||||
if self.options.mode in [AUTHOR_MODE, TIME_MODE]:
|
if self.configuration.is_wireframe():
|
||||||
self.background_color: Color = Color("#111111")
|
self.background_color: Color = Color("#111111")
|
||||||
|
|
||||||
def draw(self, constructor: Constructor) -> None:
|
def draw(self, constructor: Constructor) -> None:
|
||||||
|
@ -80,11 +86,13 @@ class Map:
|
||||||
|
|
||||||
# All other points
|
# All other points
|
||||||
|
|
||||||
if self.options.overlap == 0:
|
if self.configuration.overlap == 0:
|
||||||
occupied = None
|
occupied = None
|
||||||
else:
|
else:
|
||||||
occupied = Occupied(
|
occupied = Occupied(
|
||||||
self.flinger.size[0], self.flinger.size[1], self.options.overlap
|
self.flinger.size[0],
|
||||||
|
self.flinger.size[1],
|
||||||
|
self.configuration.overlap,
|
||||||
)
|
)
|
||||||
|
|
||||||
nodes = sorted(constructor.points, key=lambda x: -x.priority)
|
nodes = sorted(constructor.points, key=lambda x: -x.priority)
|
||||||
|
@ -105,18 +113,18 @@ class Map:
|
||||||
steps * 2 + index, steps * 3, step=10, text="Drawing texts"
|
steps * 2 + index, steps * 3, step=10, text="Drawing texts"
|
||||||
)
|
)
|
||||||
if (
|
if (
|
||||||
self.options.mode not in [TIME_MODE, AUTHOR_MODE]
|
not self.configuration.is_wireframe()
|
||||||
and self.options.label_mode != "no"
|
and self.configuration.label_mode != LabelMode.NO
|
||||||
):
|
):
|
||||||
point.draw_texts(self.svg, occupied, self.options.label_mode)
|
point.draw_texts(
|
||||||
|
self.svg, occupied, self.configuration.label_mode
|
||||||
|
)
|
||||||
|
|
||||||
progress_bar(-1, len(nodes), step=10, text="Drawing nodes")
|
progress_bar(-1, len(nodes), step=10, text="Drawing nodes")
|
||||||
|
|
||||||
def draw_buildings(self, constructor: Constructor) -> None:
|
def draw_buildings(self, constructor: Constructor) -> None:
|
||||||
"""Draw buildings: shade, walls, and roof."""
|
"""Draw buildings: shade, walls, and roof."""
|
||||||
building_mode: BuildingMode = BuildingMode(self.options.buildings)
|
if self.configuration.building_mode == BuildingMode.FLAT:
|
||||||
|
|
||||||
if building_mode == BuildingMode.FLAT:
|
|
||||||
for building in constructor.buildings:
|
for building in constructor.buildings:
|
||||||
building.draw(self.svg, self.flinger)
|
building.draw(self.svg, self.flinger)
|
||||||
return
|
return
|
||||||
|
@ -197,12 +205,14 @@ class Map:
|
||||||
intersection.draw(self.svg, True)
|
intersection.draw(self.svg, True)
|
||||||
|
|
||||||
|
|
||||||
def ui(options) -> None:
|
def ui(options: argparse.Namespace) -> None:
|
||||||
"""
|
"""
|
||||||
Röntgen entry point.
|
Röntgen entry point.
|
||||||
|
|
||||||
:param options: command-line arguments
|
:param options: command-line arguments
|
||||||
"""
|
"""
|
||||||
|
configuration: MapConfiguration = MapConfiguration.from_options(options)
|
||||||
|
|
||||||
if not options.boundary_box and not options.input_file_name:
|
if not options.boundary_box and not options.input_file_name:
|
||||||
logging.fatal("Specify either --boundary-box, or --input.")
|
logging.fatal("Specify either --boundary-box, or --input.")
|
||||||
exit(1)
|
exit(1)
|
||||||
|
@ -241,8 +251,7 @@ def ui(options) -> None:
|
||||||
osm_data = reader.osm_data
|
osm_data = reader.osm_data
|
||||||
view_box = boundary_box
|
view_box = boundary_box
|
||||||
else:
|
else:
|
||||||
is_full: bool = options.mode in [AUTHOR_MODE, TIME_MODE]
|
osm_reader = OSMReader(is_full=configuration.is_wireframe())
|
||||||
osm_reader = OSMReader(is_full=is_full)
|
|
||||||
|
|
||||||
for file_name in input_file_names:
|
for file_name in input_file_names:
|
||||||
if not file_name.is_file():
|
if not file_name.is_file():
|
||||||
|
@ -273,11 +282,13 @@ def ui(options) -> None:
|
||||||
flinger=flinger,
|
flinger=flinger,
|
||||||
scheme=scheme,
|
scheme=scheme,
|
||||||
icon_extractor=icon_extractor,
|
icon_extractor=icon_extractor,
|
||||||
options=options,
|
configuration=configuration,
|
||||||
)
|
)
|
||||||
constructor.construct()
|
constructor.construct()
|
||||||
|
|
||||||
painter: Map = Map(flinger=flinger, svg=svg, scheme=scheme, options=options)
|
painter: Map = Map(
|
||||||
|
flinger=flinger, svg=svg, scheme=scheme, configuration=configuration
|
||||||
|
)
|
||||||
painter.draw(constructor)
|
painter.draw(constructor)
|
||||||
|
|
||||||
logging.info(f"Writing output SVG to {options.output_file_name}...")
|
logging.info(f"Writing output SVG to {options.output_file_name}...")
|
||||||
|
|
|
@ -8,6 +8,7 @@ import svgwrite
|
||||||
from colour import Color
|
from colour import Color
|
||||||
|
|
||||||
from roentgen.icon import Icon, IconSet
|
from roentgen.icon import Icon, IconSet
|
||||||
|
from roentgen.map_configuration import LabelMode
|
||||||
from roentgen.osm_reader import Tagged
|
from roentgen.osm_reader import Tagged
|
||||||
from roentgen.text import Label
|
from roentgen.text import Label
|
||||||
|
|
||||||
|
@ -161,14 +162,14 @@ class Point(Tagged):
|
||||||
self,
|
self,
|
||||||
svg: svgwrite.Drawing,
|
svg: svgwrite.Drawing,
|
||||||
occupied: Optional[Occupied] = None,
|
occupied: Optional[Occupied] = None,
|
||||||
label_mode: str = "main",
|
label_mode: LabelMode = LabelMode.MAIN,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Draw all labels."""
|
"""Draw all labels."""
|
||||||
labels: list[Label]
|
labels: list[Label]
|
||||||
|
|
||||||
if label_mode == "main":
|
if label_mode == LabelMode.MAIN:
|
||||||
labels = self.labels[:1]
|
labels = self.labels[:1]
|
||||||
elif label_mode == "all":
|
elif label_mode == LabelMode.ALL:
|
||||||
labels = self.labels
|
labels = self.labels
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
"""
|
"""
|
||||||
Röntgen tile server for slippy maps.
|
Röntgen tile server for slippy maps.
|
||||||
"""
|
"""
|
||||||
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
from http.server import HTTPServer, SimpleHTTPRequestHandler
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
@ -62,7 +63,7 @@ class _Handler(SimpleHTTPRequestHandler):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def ui(options) -> None:
|
def ui(options: argparse.Namespace) -> None:
|
||||||
"""Command-line interface for tile server."""
|
"""Command-line interface for tile server."""
|
||||||
server: Optional[HTTPServer] = None
|
server: Optional[HTTPServer] = None
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -3,6 +3,7 @@ Tile generation.
|
||||||
|
|
||||||
See https://wiki.openstreetmap.org/wiki/Tiles
|
See https://wiki.openstreetmap.org/wiki/Tiles
|
||||||
"""
|
"""
|
||||||
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import sys
|
import sys
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
|
@ -18,6 +19,7 @@ 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.mapper import Map
|
||||||
|
from roentgen.map_configuration import MapConfiguration
|
||||||
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
|
||||||
|
@ -115,23 +117,31 @@ class Tile:
|
||||||
f"https://tile.openstreetmap.org/{self.scale}/{self.x}/{self.y}.png"
|
f"https://tile.openstreetmap.org/{self.scale}/{self.x}/{self.y}.png"
|
||||||
)
|
)
|
||||||
|
|
||||||
def draw(self, directory_name: Path, cache_path: Path, options) -> None:
|
def draw(
|
||||||
|
self,
|
||||||
|
directory_name: Path,
|
||||||
|
cache_path: Path,
|
||||||
|
configuration: MapConfiguration,
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Draw tile to SVG and PNG files.
|
Draw tile to SVG and PNG files.
|
||||||
|
|
||||||
:param directory_name: output directory to storing tiles
|
:param directory_name: output directory to storing tiles
|
||||||
:param cache_path: directory to store SVG and PNG tiles
|
:param cache_path: directory to store SVG and PNG tiles
|
||||||
:param options: drawing configuration
|
:param configuration: drawing configuration
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
osm_data: OSMData = self.load_osm_data(cache_path)
|
osm_data: OSMData = self.load_osm_data(cache_path)
|
||||||
except NetworkError as e:
|
except NetworkError as e:
|
||||||
raise NetworkError(f"Map is not loaded. {e.message}")
|
raise NetworkError(f"Map is not loaded. {e.message}")
|
||||||
|
|
||||||
self.draw_with_osm_data(osm_data, directory_name, options)
|
self.draw_with_osm_data(osm_data, directory_name, configuration)
|
||||||
|
|
||||||
def draw_with_osm_data(
|
def draw_with_osm_data(
|
||||||
self, osm_data: OSMData, directory_name: Path, options
|
self,
|
||||||
|
osm_data: OSMData,
|
||||||
|
directory_name: Path,
|
||||||
|
configuration: MapConfiguration,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Draw SVG and PNG tile using OpenStreetMap data."""
|
"""Draw SVG and PNG tile using OpenStreetMap data."""
|
||||||
top, left = self.get_coordinates()
|
top, left = self.get_coordinates()
|
||||||
|
@ -154,12 +164,12 @@ class Tile:
|
||||||
)
|
)
|
||||||
scheme: Scheme = Scheme(workspace.DEFAULT_SCHEME_PATH)
|
scheme: Scheme = Scheme(workspace.DEFAULT_SCHEME_PATH)
|
||||||
constructor: Constructor = Constructor(
|
constructor: Constructor = Constructor(
|
||||||
osm_data, flinger, scheme, icon_extractor, options
|
osm_data, flinger, scheme, icon_extractor, configuration
|
||||||
)
|
)
|
||||||
constructor.construct()
|
constructor.construct()
|
||||||
|
|
||||||
painter: Map = Map(
|
painter: Map = Map(
|
||||||
flinger=flinger, svg=svg, scheme=scheme, options=options
|
flinger=flinger, svg=svg, scheme=scheme, configuration=configuration
|
||||||
)
|
)
|
||||||
painter.draw(constructor)
|
painter.draw(constructor)
|
||||||
|
|
||||||
|
@ -216,7 +226,7 @@ class Tiles:
|
||||||
return cls(tiles, tile_1, tile_2, scale, extended_boundary_box)
|
return cls(tiles, tile_1, tile_2, scale, extended_boundary_box)
|
||||||
|
|
||||||
def draw_separately(
|
def draw_separately(
|
||||||
self, directory: Path, cache_path: Path, options
|
self, directory: Path, cache_path: Path, configuration: MapConfiguration
|
||||||
) -> None:
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Draw set of tiles as SVG file separately and rasterize them into a set
|
Draw set of tiles as SVG file separately and rasterize them into a set
|
||||||
|
@ -224,7 +234,7 @@ class Tiles:
|
||||||
|
|
||||||
:param directory: directory for tiles
|
:param directory: directory for tiles
|
||||||
:param cache_path: directory for temporary OSM files
|
:param cache_path: directory for temporary OSM files
|
||||||
:param options: drawing configuration
|
:param configuration: drawing configuration
|
||||||
"""
|
"""
|
||||||
cache_file_path: Path = (
|
cache_file_path: Path = (
|
||||||
cache_path / f"{self.boundary_box.get_format()}.osm"
|
cache_path / f"{self.boundary_box.get_format()}.osm"
|
||||||
|
@ -235,7 +245,7 @@ class Tiles:
|
||||||
for tile in self.tiles:
|
for tile in self.tiles:
|
||||||
file_path: Path = tile.get_file_name(directory)
|
file_path: Path = tile.get_file_name(directory)
|
||||||
if not file_path.exists():
|
if not file_path.exists():
|
||||||
tile.draw_with_osm_data(osm_data, directory, options)
|
tile.draw_with_osm_data(osm_data, directory, configuration)
|
||||||
else:
|
else:
|
||||||
logging.debug(f"File {file_path} already exists.")
|
logging.debug(f"File {file_path} already exists.")
|
||||||
|
|
||||||
|
@ -253,19 +263,21 @@ class Tiles:
|
||||||
"""Check whether all tiles are drawn."""
|
"""Check whether all tiles are drawn."""
|
||||||
return all(x.exists(directory_name) for x in self.tiles)
|
return all(x.exists(directory_name) for x in self.tiles)
|
||||||
|
|
||||||
def draw(self, directory: Path, cache_path: Path, options) -> None:
|
def draw(
|
||||||
|
self, directory: Path, cache_path: Path, configuration: MapConfiguration
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Draw one PNG image with all tiles and split it into a set of separate
|
Draw one PNG image with all tiles and split it into a set of separate
|
||||||
PNG file with Pillow.
|
PNG file with Pillow.
|
||||||
|
|
||||||
:param directory: directory for tiles
|
:param directory: directory for tiles
|
||||||
:param cache_path: directory for temporary OSM files
|
:param cache_path: directory for temporary OSM files
|
||||||
:param options: drawing configuration
|
:param configuration: drawing configuration
|
||||||
"""
|
"""
|
||||||
if self.tiles_exist(directory):
|
if self.tiles_exist(directory):
|
||||||
return
|
return
|
||||||
|
|
||||||
self.draw_image(cache_path, options)
|
self.draw_image(cache_path, configuration)
|
||||||
|
|
||||||
input_path: Path = self.get_file_path(cache_path).with_suffix(".png")
|
input_path: Path = self.get_file_path(cache_path).with_suffix(".png")
|
||||||
with input_path.open("rb") as input_file:
|
with input_path.open("rb") as input_file:
|
||||||
|
@ -290,12 +302,14 @@ class Tiles:
|
||||||
"""Get path of the output SVG file."""
|
"""Get path of the output SVG file."""
|
||||||
return cache_path / f"{self.boundary_box.get_format()}_{self.scale}.svg"
|
return cache_path / f"{self.boundary_box.get_format()}_{self.scale}.svg"
|
||||||
|
|
||||||
def draw_image(self, cache_path: Path, options) -> None:
|
def draw_image(
|
||||||
|
self, cache_path: Path, configuration: MapConfiguration
|
||||||
|
) -> None:
|
||||||
"""
|
"""
|
||||||
Draw all tiles as one picture.
|
Draw all tiles as one picture.
|
||||||
|
|
||||||
:param cache_path: directory for temporary SVG file and OSM files
|
:param cache_path: directory for temporary SVG file and OSM files
|
||||||
:param options: drawing configuration
|
:param configuration: drawing configuration
|
||||||
"""
|
"""
|
||||||
output_path: Path = self.get_file_path(cache_path)
|
output_path: Path = self.get_file_path(cache_path)
|
||||||
|
|
||||||
|
@ -319,16 +333,14 @@ class Tiles:
|
||||||
)
|
)
|
||||||
scheme: Scheme = Scheme(workspace.DEFAULT_SCHEME_PATH)
|
scheme: Scheme = Scheme(workspace.DEFAULT_SCHEME_PATH)
|
||||||
constructor: Constructor = Constructor(
|
constructor: Constructor = Constructor(
|
||||||
osm_data, flinger, scheme, extractor, options=options
|
osm_data, flinger, scheme, extractor, configuration
|
||||||
)
|
)
|
||||||
constructor.construct()
|
constructor.construct()
|
||||||
|
|
||||||
svg: svgwrite.Drawing = svgwrite.Drawing(
|
svg: svgwrite.Drawing = svgwrite.Drawing(
|
||||||
str(output_path), size=flinger.size
|
str(output_path), size=flinger.size
|
||||||
)
|
)
|
||||||
map_: Map = Map(
|
map_: Map = Map(flinger, svg, scheme, configuration)
|
||||||
flinger=flinger, svg=svg, scheme=scheme, options=options
|
|
||||||
)
|
|
||||||
map_.draw(constructor)
|
map_.draw(constructor)
|
||||||
|
|
||||||
logging.info(f"Writing output SVG {output_path}...")
|
logging.info(f"Writing output SVG {output_path}...")
|
||||||
|
@ -346,9 +358,10 @@ class Tiles:
|
||||||
logging.debug(f"File {png_path} already exists.")
|
logging.debug(f"File {png_path} already exists.")
|
||||||
|
|
||||||
|
|
||||||
def ui(options) -> None:
|
def ui(options: argparse.Namespace) -> None:
|
||||||
"""Simple user interface for tile generation."""
|
"""Simple user interface for tile generation."""
|
||||||
directory: Path = workspace.get_tile_path()
|
directory: Path = workspace.get_tile_path()
|
||||||
|
configuration: MapConfiguration = MapConfiguration.from_options(options)
|
||||||
|
|
||||||
if options.coordinates:
|
if options.coordinates:
|
||||||
coordinates: list[float] = list(
|
coordinates: list[float] = list(
|
||||||
|
@ -356,13 +369,13 @@ def ui(options) -> None:
|
||||||
)
|
)
|
||||||
tile: Tile = Tile.from_coordinates(np.array(coordinates), options.scale)
|
tile: Tile = Tile.from_coordinates(np.array(coordinates), options.scale)
|
||||||
try:
|
try:
|
||||||
tile.draw(directory, Path(options.cache), options)
|
tile.draw(directory, Path(options.cache), configuration)
|
||||||
except NetworkError as e:
|
except NetworkError as e:
|
||||||
logging.fatal(e.message)
|
logging.fatal(e.message)
|
||||||
elif options.tile:
|
elif options.tile:
|
||||||
scale, x, y = map(int, options.tile.split("/"))
|
scale, x, y = map(int, options.tile.split("/"))
|
||||||
tile: Tile = Tile(x, y, scale)
|
tile: Tile = Tile(x, y, scale)
|
||||||
tile.draw(directory, Path(options.cache), options)
|
tile.draw(directory, Path(options.cache), configuration)
|
||||||
elif options.boundary_box:
|
elif options.boundary_box:
|
||||||
boundary_box: Optional[BoundaryBox] = BoundaryBox.from_text(
|
boundary_box: Optional[BoundaryBox] = BoundaryBox.from_text(
|
||||||
options.boundary_box
|
options.boundary_box
|
||||||
|
@ -370,7 +383,7 @@ def ui(options) -> None:
|
||||||
if boundary_box is None:
|
if boundary_box is None:
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
tiles: Tiles = Tiles.from_boundary_box(boundary_box, options.scale)
|
tiles: Tiles = Tiles.from_boundary_box(boundary_box, options.scale)
|
||||||
tiles.draw(directory, Path(options.cache), options)
|
tiles.draw(directory, Path(options.cache), configuration)
|
||||||
else:
|
else:
|
||||||
logging.fatal(
|
logging.fatal(
|
||||||
"Specify either --coordinates, --boundary-box, or --tile."
|
"Specify either --coordinates, --boundary-box, or --tile."
|
||||||
|
|
|
@ -4,29 +4,15 @@ Command-line user interface.
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from roentgen.map_configuration import BuildingMode, DrawingMode, LabelMode
|
||||||
|
from roentgen.osm_reader import STAGES_OF_DECAY
|
||||||
|
|
||||||
__author__ = "Sergey Vartanov"
|
__author__ = "Sergey Vartanov"
|
||||||
__email__ = "me@enzet.ru"
|
__email__ = "me@enzet.ru"
|
||||||
|
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
from roentgen.osm_reader import STAGES_OF_DECAY
|
|
||||||
|
|
||||||
BOXES: str = " ▏▎▍▌▋▊▉"
|
BOXES: str = " ▏▎▍▌▋▊▉"
|
||||||
BOXES_LENGTH: int = len(BOXES)
|
BOXES_LENGTH: int = len(BOXES)
|
||||||
|
|
||||||
AUTHOR_MODE: str = "author"
|
|
||||||
TIME_MODE: str = "time"
|
|
||||||
|
|
||||||
|
|
||||||
class BuildingMode(Enum):
|
|
||||||
"""
|
|
||||||
Building drawing mode.
|
|
||||||
"""
|
|
||||||
|
|
||||||
FLAT = "flat"
|
|
||||||
ISOMETRIC = "isometric"
|
|
||||||
ISOMETRIC_NO_PARTS = "isometric-no-parts"
|
|
||||||
|
|
||||||
|
|
||||||
def parse_options(args) -> argparse.Namespace:
|
def parse_options(args) -> argparse.Namespace:
|
||||||
"""Parse Röntgen command-line options."""
|
"""Parse Röntgen command-line options."""
|
||||||
|
@ -68,8 +54,9 @@ def add_map_arguments(parser: argparse.ArgumentParser) -> None:
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--mode",
|
"--mode",
|
||||||
default="normal",
|
default="normal",
|
||||||
help="map drawing mode",
|
|
||||||
metavar="<string>",
|
metavar="<string>",
|
||||||
|
choices=(x.value for x in DrawingMode),
|
||||||
|
help="map drawing mode: " + ", ".join(x.value for x in DrawingMode),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--overlap",
|
"--overlap",
|
||||||
|
@ -81,10 +68,11 @@ def add_map_arguments(parser: argparse.ArgumentParser) -> None:
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"--labels",
|
"--labels",
|
||||||
help="label drawing mode: `no`, `main`, or `all`",
|
|
||||||
dest="label_mode",
|
dest="label_mode",
|
||||||
default="main",
|
default="main",
|
||||||
metavar="<string>",
|
metavar="<string>",
|
||||||
|
choices=(x.value for x in LabelMode),
|
||||||
|
help="label drawing mode: " + ", ".join(x.value for x in LabelMode),
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
"-s",
|
"-s",
|
||||||
|
@ -99,6 +87,12 @@ def add_map_arguments(parser: argparse.ArgumentParser) -> None:
|
||||||
default="overground",
|
default="overground",
|
||||||
help="display only this floor level",
|
help="display only this floor level",
|
||||||
)
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--seed",
|
||||||
|
default="",
|
||||||
|
help="seed for random",
|
||||||
|
metavar="<string>",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def add_tile_arguments(parser: argparse.ArgumentParser) -> None:
|
def add_tile_arguments(parser: argparse.ArgumentParser) -> None:
|
||||||
|
@ -179,12 +173,6 @@ def add_render_arguments(parser: argparse.ArgumentParser) -> None:
|
||||||
default="cache",
|
default="cache",
|
||||||
metavar="<path>",
|
metavar="<path>",
|
||||||
)
|
)
|
||||||
parser.add_argument(
|
|
||||||
"--seed",
|
|
||||||
default="",
|
|
||||||
help="seed for random",
|
|
||||||
metavar="<string>",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def add_mapcss_arguments(parser: argparse.ArgumentParser) -> None:
|
def add_mapcss_arguments(parser: argparse.ArgumentParser) -> None:
|
||||||
|
@ -225,14 +213,13 @@ def progress_bar(
|
||||||
:param text: short description
|
:param text: short description
|
||||||
"""
|
"""
|
||||||
if number == -1:
|
if number == -1:
|
||||||
print(f"100 % {length * '█'}▏{text}")
|
sys.stdout.write(f"100 % {length * '█'}▏{text}\n")
|
||||||
elif number % step == 0:
|
elif number % step == 0:
|
||||||
ratio: float = number / total
|
ratio: float = number / total
|
||||||
parts: int = int(ratio * length * BOXES_LENGTH)
|
parts: int = int(ratio * length * BOXES_LENGTH)
|
||||||
fill_length: int = int(parts / BOXES_LENGTH)
|
fill_length: int = int(parts / BOXES_LENGTH)
|
||||||
box: str = BOXES[int(parts - fill_length * BOXES_LENGTH)]
|
box: str = BOXES[int(parts - fill_length * BOXES_LENGTH)]
|
||||||
print(
|
sys.stdout.write(
|
||||||
f"{str(int(int(ratio * 1000) / 10)):>3} % {fill_length * '█'}{box}"
|
f"{str(int(int(ratio * 1000) / 10)):>3} % {fill_length * '█'}{box}"
|
||||||
f"{int(length - fill_length - 1) * ' '}▏{text}"
|
f"{int(length - fill_length - 1) * ' '}▏{text}\n\033[F"
|
||||||
)
|
)
|
||||||
sys.stdout.write("\033[F")
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue