mirror of
https://github.com/enzet/map-machine.git
synced 2025-08-06 10:09:52 +02:00
Refactor flinger.
Element drawing module was using flinger for Mercator projection, which is not exactly what is wanted.
This commit is contained in:
parent
77c8ec0044
commit
c0879bff36
9 changed files with 90 additions and 62 deletions
|
@ -55,7 +55,7 @@ TIME_COLOR_SCALE: list[Color] = [
|
||||||
|
|
||||||
def line_center(
|
def line_center(
|
||||||
nodes: list[OSMNode], flinger: Flinger
|
nodes: list[OSMNode], flinger: Flinger
|
||||||
) -> (np.ndarray, np.ndarray):
|
) -> tuple[np.ndarray, np.ndarray]:
|
||||||
"""
|
"""
|
||||||
Get geometric center of nodes set.
|
Get geometric center of nodes set.
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ import svgwrite
|
||||||
|
|
||||||
from map_machine.constructor import Constructor
|
from map_machine.constructor import Constructor
|
||||||
from map_machine.geometry.boundary_box import BoundaryBox
|
from map_machine.geometry.boundary_box import BoundaryBox
|
||||||
from map_machine.geometry.flinger import Flinger
|
from map_machine.geometry.flinger import MercatorFlinger
|
||||||
from map_machine.map_configuration import (
|
from map_machine.map_configuration import (
|
||||||
BuildingMode,
|
BuildingMode,
|
||||||
DrawingMode,
|
DrawingMode,
|
||||||
|
@ -21,16 +21,16 @@ from map_machine.osm.osm_getter import get_osm
|
||||||
from map_machine.osm.osm_reader import OSMData
|
from map_machine.osm.osm_reader import OSMData
|
||||||
from map_machine.pictogram.icon import ShapeExtractor
|
from map_machine.pictogram.icon import ShapeExtractor
|
||||||
from map_machine.scheme import Scheme
|
from map_machine.scheme import Scheme
|
||||||
|
from map_machine.workspace import workspace
|
||||||
|
|
||||||
doc_path: Path = Path("doc")
|
doc_path: Path = Path("doc")
|
||||||
|
|
||||||
cache: Path = Path("cache")
|
cache: Path = Path("cache")
|
||||||
cache.mkdir(exist_ok=True)
|
cache.mkdir(exist_ok=True)
|
||||||
|
|
||||||
SCHEME: Scheme = Scheme.from_file(Path("map_machine/scheme/default.yml"))
|
SCHEME: Scheme = Scheme.from_file(workspace.DEFAULT_SCHEME_PATH)
|
||||||
EXTRACTOR: ShapeExtractor = ShapeExtractor(
|
EXTRACTOR: ShapeExtractor = ShapeExtractor(
|
||||||
Path("map_machine/icons/icons.svg"),
|
workspace.ICONS_PATH, workspace.ICONS_CONFIG_PATH
|
||||||
Path("map_machine/icons/config.json"),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ def draw(
|
||||||
|
|
||||||
osm_data: OSMData = OSMData()
|
osm_data: OSMData = OSMData()
|
||||||
osm_data.parse_osm_file(input_file_name)
|
osm_data.parse_osm_file(input_file_name)
|
||||||
flinger: Flinger = Flinger(
|
flinger: MercatorFlinger = MercatorFlinger(
|
||||||
boundary_box, configuration.zoom_level, osm_data.equator_length
|
boundary_box, configuration.zoom_level, osm_data.equator_length
|
||||||
)
|
)
|
||||||
constructor: Constructor = Constructor(
|
constructor: Constructor = Constructor(
|
||||||
|
|
|
@ -6,7 +6,7 @@ from map_machine.osm.osm_reader import Tags, OSMNode
|
||||||
|
|
||||||
|
|
||||||
def draw_node(tags: Tags, path: Path):
|
def draw_node(tags: Tags, path: Path):
|
||||||
grid: Grid = Grid(x_step=0.0003, show_credit=False, margin=0.5)
|
grid: Grid = Grid(show_credit=False, margin=0.5)
|
||||||
grid.add_node(tags, 0, 0)
|
grid.add_node(tags, 0, 0)
|
||||||
grid.draw(path)
|
grid.draw(path)
|
||||||
|
|
||||||
|
@ -16,7 +16,7 @@ def draw_way():
|
||||||
|
|
||||||
|
|
||||||
def draw_area(tags: Tags, path: Path):
|
def draw_area(tags: Tags, path: Path):
|
||||||
grid: Grid = Grid(x_step=0.0003, show_credit=False, margin=0.5)
|
grid: Grid = Grid(show_credit=False, margin=0.5)
|
||||||
node: OSMNode = grid.add_node({}, 0, 0)
|
node: OSMNode = grid.add_node({}, 0, 0)
|
||||||
nodes: list[OSMNode] = [
|
nodes: list[OSMNode] = [
|
||||||
node,
|
node,
|
||||||
|
|
|
@ -6,8 +6,7 @@ from svgwrite import Drawing
|
||||||
from svgwrite.text import Text
|
from svgwrite.text import Text
|
||||||
|
|
||||||
from map_machine.constructor import Constructor
|
from map_machine.constructor import Constructor
|
||||||
from map_machine.geometry.boundary_box import BoundaryBox
|
from map_machine.geometry.flinger import Flinger, TranslateFlinger
|
||||||
from map_machine.geometry.flinger import Flinger
|
|
||||||
from map_machine.map_configuration import MapConfiguration
|
from map_machine.map_configuration import MapConfiguration
|
||||||
from map_machine.mapper import Map
|
from map_machine.mapper import Map
|
||||||
from map_machine.osm.osm_reader import (
|
from map_machine.osm.osm_reader import (
|
||||||
|
@ -36,8 +35,8 @@ class Grid:
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
x_step: float = 0.0002,
|
x_step: float = 20.0,
|
||||||
y_step: float = 0.0003,
|
y_step: float = 20.0,
|
||||||
show_credit: bool = True,
|
show_credit: bool = True,
|
||||||
margin: float = 1.5,
|
margin: float = 1.5,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -49,8 +48,8 @@ class Grid:
|
||||||
self.index: int = 0
|
self.index: int = 0
|
||||||
self.nodes: dict[OSMNode, tuple[int, int]] = {}
|
self.nodes: dict[OSMNode, tuple[int, int]] = {}
|
||||||
|
|
||||||
self.max_j: float = 0
|
self.max_j: float = 0.0
|
||||||
self.max_i: float = 0
|
self.max_i: float = 0.0
|
||||||
|
|
||||||
self.way_id: int = 0
|
self.way_id: int = 0
|
||||||
self.relation_id: int = 0
|
self.relation_id: int = 0
|
||||||
|
@ -61,15 +60,11 @@ class Grid:
|
||||||
def add_node(self, tags: Tags, i: int, j: int) -> OSMNode:
|
def add_node(self, tags: Tags, i: int, j: int) -> OSMNode:
|
||||||
"""Add OSM node to the grid."""
|
"""Add OSM node to the grid."""
|
||||||
self.index += 1
|
self.index += 1
|
||||||
node: OSMNode = OSMNode(
|
node: OSMNode = OSMNode(tags, self.index, np.array((i, j)))
|
||||||
tags,
|
|
||||||
self.index,
|
|
||||||
np.array((-i * self.y_step, j * self.x_step)),
|
|
||||||
)
|
|
||||||
self.nodes[node] = (j, i)
|
self.nodes[node] = (j, i)
|
||||||
self.osm_data.add_node(node)
|
self.osm_data.add_node(node)
|
||||||
self.max_j = max(self.max_j, j * self.x_step)
|
self.max_j = max(self.max_j, j)
|
||||||
self.max_i = max(self.max_i, i * self.y_step)
|
self.max_i = max(self.max_i, i)
|
||||||
return node
|
return node
|
||||||
|
|
||||||
def add_way(self, tags: Tags, nodes: list[OSMNode]) -> OSMWay:
|
def add_way(self, tags: Tags, nodes: list[OSMNode]) -> OSMWay:
|
||||||
|
@ -90,24 +85,22 @@ class Grid:
|
||||||
"""Add simple text label to the grid."""
|
"""Add simple text label to the grid."""
|
||||||
self.texts.append((text, i, j))
|
self.texts.append((text, i, j))
|
||||||
|
|
||||||
def get_boundary_box(self) -> BoundaryBox:
|
def draw(self, output_path: Path) -> None:
|
||||||
"""Compute resulting boundary box with margin of one grid step."""
|
|
||||||
return BoundaryBox(
|
|
||||||
-self.x_step * self.margin,
|
|
||||||
-self.max_i - self.y_step * self.margin,
|
|
||||||
self.max_j + self.x_step * self.margin,
|
|
||||||
self.y_step * self.margin,
|
|
||||||
)
|
|
||||||
|
|
||||||
def draw(self, output_path: Path, zoom: float = DEFAULT_ZOOM) -> None:
|
|
||||||
"""Draw grid."""
|
"""Draw grid."""
|
||||||
configuration: MapConfiguration = MapConfiguration(
|
configuration: MapConfiguration = MapConfiguration(
|
||||||
SCHEME, level="all", credit=None, show_credit=self.show_credit
|
SCHEME, level="all", credit=None, show_credit=self.show_credit
|
||||||
)
|
)
|
||||||
flinger: Flinger = Flinger(
|
size = (
|
||||||
self.get_boundary_box(), zoom, self.osm_data.equator_length
|
(self.max_i + self.margin * 2.0) * self.x_step,
|
||||||
|
(self.max_j + self.margin * 2.0) * self.y_step,
|
||||||
)
|
)
|
||||||
svg: Drawing = Drawing(output_path.name, flinger.size)
|
|
||||||
|
flinger: Flinger = TranslateFlinger(
|
||||||
|
size,
|
||||||
|
np.array((self.x_step, self.y_step)),
|
||||||
|
np.array((self.margin, self.margin)),
|
||||||
|
)
|
||||||
|
svg: Drawing = Drawing(output_path.name, size)
|
||||||
constructor: Constructor = Constructor(
|
constructor: Constructor = Constructor(
|
||||||
self.osm_data, flinger, SHAPE_EXTRACTOR, configuration
|
self.osm_data, flinger, SHAPE_EXTRACTOR, configuration
|
||||||
)
|
)
|
||||||
|
@ -119,7 +112,7 @@ class Grid:
|
||||||
svg.add(
|
svg.add(
|
||||||
Text(
|
Text(
|
||||||
text,
|
text,
|
||||||
flinger.fling((-i * self.y_step, j * self.x_step)) + (0, 3),
|
flinger.fling((i, j)) + (0, 3),
|
||||||
font_family="JetBrains Mono",
|
font_family="JetBrains Mono",
|
||||||
font_size=12,
|
font_size=12,
|
||||||
)
|
)
|
||||||
|
|
|
@ -67,17 +67,17 @@ def draw_overlapped_ways(types: list[dict[str, str]], path: Path) -> None:
|
||||||
|
|
||||||
The goal is to show check priority.
|
The goal is to show check priority.
|
||||||
"""
|
"""
|
||||||
grid: Grid = Grid(0.00012, 0.00012)
|
grid: Grid = Grid()
|
||||||
|
|
||||||
for index, tags in enumerate(types):
|
for index, tags in enumerate(types):
|
||||||
node_1: OSMNode = grid.add_node({}, index + 1, 8)
|
node_1: OSMNode = grid.add_node({}, 8, index + 1)
|
||||||
node_2: OSMNode = grid.add_node({}, index + 1, len(types) + 9)
|
node_2: OSMNode = grid.add_node({}, len(types) + 9, index + 1)
|
||||||
grid.add_way(tags, [node_1, node_2])
|
grid.add_way(tags, [node_1, node_2])
|
||||||
grid.add_text(", ".join(f"{k}={tags[k]}" for k in tags), index + 1, 0)
|
grid.add_text(", ".join(f"{k}={tags[k]}" for k in tags), 0, index + 1)
|
||||||
|
|
||||||
for index, tags in enumerate(types):
|
for index, tags in enumerate(types):
|
||||||
node_1: OSMNode = grid.add_node({}, 0, index + 9)
|
node_1: OSMNode = grid.add_node({}, index + 9, 0)
|
||||||
node_2: OSMNode = grid.add_node({}, len(types) + 1, index + 9)
|
node_2: OSMNode = grid.add_node({}, index + 9, len(types) + 1)
|
||||||
grid.add_way(tags, [node_1, node_2])
|
grid.add_way(tags, [node_1, node_2])
|
||||||
|
|
||||||
grid.draw(path)
|
grid.draw(path)
|
||||||
|
@ -106,7 +106,7 @@ def draw_road_features(
|
||||||
|
|
||||||
def draw_multipolygon(path: Path) -> None:
|
def draw_multipolygon(path: Path) -> None:
|
||||||
"""Draw simple multipolygon with one outer and one inner way."""
|
"""Draw simple multipolygon with one outer and one inner way."""
|
||||||
grid: Grid = Grid(y_step=0.0002)
|
grid: Grid = Grid()
|
||||||
|
|
||||||
outer_node: OSMNode = grid.add_node({}, 0, 0)
|
outer_node: OSMNode = grid.add_node({}, 0, 0)
|
||||||
outer_nodes: list[OSMNode] = [
|
outer_nodes: list[OSMNode] = [
|
||||||
|
|
|
@ -13,15 +13,19 @@ def pseudo_mercator(coordinates: np.ndarray) -> np.ndarray:
|
||||||
"""
|
"""
|
||||||
Use spherical pseudo-Mercator projection to convert geo coordinates.
|
Use spherical pseudo-Mercator projection to convert geo coordinates.
|
||||||
|
|
||||||
|
The result is (x, y), where x is a longitude value, so x is in [-180, 180],
|
||||||
|
and y is a stretched latitude and may have any real value:
|
||||||
|
(-infinity, +infinity).
|
||||||
|
|
||||||
:param coordinates: geo positional in the form of (latitude, longitude)
|
:param coordinates: geo positional in the form of (latitude, longitude)
|
||||||
:return: position on the plane in the form of (x, y)
|
:return: position on the plane in the form of (x, y)
|
||||||
"""
|
"""
|
||||||
|
latitude, longitude = coordinates
|
||||||
|
|
||||||
y: float = (
|
y: float = (
|
||||||
180.0
|
180.0 / np.pi * np.log(np.tan(np.pi / 4.0 + latitude * np.pi / 360.0))
|
||||||
/ np.pi
|
|
||||||
* np.log(np.tan(np.pi / 4.0 + coordinates[0] * np.pi / 360.0))
|
|
||||||
)
|
)
|
||||||
return np.array((coordinates[1], y))
|
return np.array((longitude, y))
|
||||||
|
|
||||||
|
|
||||||
def osm_zoom_level_to_pixels_per_meter(
|
def osm_zoom_level_to_pixels_per_meter(
|
||||||
|
@ -40,7 +44,21 @@ def osm_zoom_level_to_pixels_per_meter(
|
||||||
|
|
||||||
|
|
||||||
class Flinger:
|
class Flinger:
|
||||||
"""Convert geo coordinates into SVG position points."""
|
"""Interface for flinger that converts coordinates."""
|
||||||
|
|
||||||
|
def __init__(self, size: np.ndarray) -> None:
|
||||||
|
self.size: np.ndarray = size
|
||||||
|
|
||||||
|
def fling(self, coordinates: np.ndarray) -> np.ndarray:
|
||||||
|
"""Do nothing but return coordinates unchanged."""
|
||||||
|
return coordinates
|
||||||
|
|
||||||
|
def get_scale(self, coordinates: Optional[np.ndarray] = None) -> float:
|
||||||
|
return 1.0
|
||||||
|
|
||||||
|
|
||||||
|
class MercatorFlinger(Flinger):
|
||||||
|
"""Convert geographical coordinates into (x, y) points on the plane."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -57,24 +75,28 @@ class Flinger:
|
||||||
"""
|
"""
|
||||||
self.geo_boundaries: BoundaryBox = geo_boundaries
|
self.geo_boundaries: BoundaryBox = geo_boundaries
|
||||||
self.ratio: float = 2.0**zoom_level * 256.0 / 360.0
|
self.ratio: float = 2.0**zoom_level * 256.0 / 360.0
|
||||||
self.size: np.ndarray = self.ratio * (
|
size: np.ndarray = self.ratio * (
|
||||||
pseudo_mercator(self.geo_boundaries.max_())
|
pseudo_mercator(self.geo_boundaries.max_())
|
||||||
- pseudo_mercator(self.geo_boundaries.min_())
|
- pseudo_mercator(self.geo_boundaries.min_())
|
||||||
)
|
)
|
||||||
self.pixels_per_meter: float = osm_zoom_level_to_pixels_per_meter(
|
self.pixels_per_meter: float = osm_zoom_level_to_pixels_per_meter(
|
||||||
zoom_level, equator_length
|
zoom_level, equator_length
|
||||||
)
|
)
|
||||||
self.size: np.ndarray = self.size.astype(int).astype(float)
|
size = size.astype(int).astype(float)
|
||||||
|
|
||||||
|
super().__init__(size)
|
||||||
|
|
||||||
|
self.min_ = self.ratio * pseudo_mercator(self.geo_boundaries.min_())
|
||||||
|
|
||||||
def fling(self, coordinates: np.ndarray) -> np.ndarray:
|
def fling(self, coordinates: np.ndarray) -> np.ndarray:
|
||||||
"""
|
"""
|
||||||
Convert geo coordinates into SVG position points.
|
Convert geo coordinates into (x, y) position points on the plane.
|
||||||
|
|
||||||
:param coordinates: vector to fling
|
:param coordinates: geographical coordinates to fling in the form of
|
||||||
|
(latitude, longitude)
|
||||||
"""
|
"""
|
||||||
result: np.ndarray = self.ratio * (
|
result: np.ndarray = (
|
||||||
pseudo_mercator(coordinates)
|
self.ratio * pseudo_mercator(coordinates) - self.min_
|
||||||
- pseudo_mercator(self.geo_boundaries.min_())
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Invert y axis on coordinate plane.
|
# Invert y axis on coordinate plane.
|
||||||
|
@ -86,7 +108,8 @@ class Flinger:
|
||||||
"""
|
"""
|
||||||
Return pixels per meter ratio for the given geo coordinates.
|
Return pixels per meter ratio for the given geo coordinates.
|
||||||
|
|
||||||
:param coordinates: geo coordinates
|
:param coordinates: geographical coordinates in the form of
|
||||||
|
(latitude, longitude)
|
||||||
"""
|
"""
|
||||||
if coordinates is None:
|
if coordinates is None:
|
||||||
# Get pixels per meter ratio for the center of the boundary box.
|
# Get pixels per meter ratio for the center of the boundary box.
|
||||||
|
@ -94,3 +117,15 @@ class Flinger:
|
||||||
|
|
||||||
scale_factor: float = abs(1.0 / np.cos(coordinates[0] / 180.0 * np.pi))
|
scale_factor: float = abs(1.0 / np.cos(coordinates[0] / 180.0 * np.pi))
|
||||||
return self.pixels_per_meter * scale_factor
|
return self.pixels_per_meter * scale_factor
|
||||||
|
|
||||||
|
|
||||||
|
class TranslateFlinger(Flinger):
|
||||||
|
def __init__(
|
||||||
|
self, size: np.ndarray, scale: np.ndarray, offset: np.ndarray
|
||||||
|
) -> None:
|
||||||
|
super().__init__(size)
|
||||||
|
self.scale: np.ndarray = scale
|
||||||
|
self.offset: np.ndarray = offset
|
||||||
|
|
||||||
|
def fling(self, coordinates: np.ndarray) -> np.ndarray:
|
||||||
|
return self.scale * (coordinates + self.offset)
|
||||||
|
|
|
@ -19,7 +19,7 @@ from map_machine.feature.building import Building, draw_walls, BUILDING_SCALE
|
||||||
from map_machine.feature.road import Intersection, Road, RoadPart
|
from map_machine.feature.road import Intersection, Road, RoadPart
|
||||||
from map_machine.figure import StyledFigure
|
from map_machine.figure import StyledFigure
|
||||||
from map_machine.geometry.boundary_box import BoundaryBox
|
from map_machine.geometry.boundary_box import BoundaryBox
|
||||||
from map_machine.geometry.flinger import Flinger
|
from map_machine.geometry.flinger import Flinger, MercatorFlinger
|
||||||
from map_machine.geometry.vector import Segment
|
from map_machine.geometry.vector import Segment
|
||||||
from map_machine.map_configuration import LabelMode, MapConfiguration
|
from map_machine.map_configuration import LabelMode, MapConfiguration
|
||||||
from map_machine.osm.osm_getter import NetworkError, get_osm
|
from map_machine.osm.osm_getter import NetworkError, get_osm
|
||||||
|
@ -345,7 +345,7 @@ def render_map(arguments: argparse.Namespace) -> None:
|
||||||
|
|
||||||
# Render the map.
|
# Render the map.
|
||||||
|
|
||||||
flinger: Flinger = Flinger(
|
flinger: MercatorFlinger = MercatorFlinger(
|
||||||
boundary_box, arguments.zoom, osm_data.equator_length
|
boundary_box, arguments.zoom, osm_data.equator_length
|
||||||
)
|
)
|
||||||
size: np.ndarray = flinger.size
|
size: np.ndarray = flinger.size
|
||||||
|
|
|
@ -17,7 +17,7 @@ from PIL import Image
|
||||||
|
|
||||||
from map_machine.constructor import Constructor
|
from map_machine.constructor import Constructor
|
||||||
from map_machine.geometry.boundary_box import BoundaryBox
|
from map_machine.geometry.boundary_box import BoundaryBox
|
||||||
from map_machine.geometry.flinger import Flinger
|
from map_machine.geometry.flinger import MercatorFlinger
|
||||||
from map_machine.map_configuration import MapConfiguration
|
from map_machine.map_configuration import MapConfiguration
|
||||||
from map_machine.mapper import Map
|
from map_machine.mapper import Map
|
||||||
from map_machine.osm.osm_getter import NetworkError, get_osm
|
from map_machine.osm.osm_getter import NetworkError, get_osm
|
||||||
|
@ -158,7 +158,7 @@ class Tile:
|
||||||
self.x + 1, self.y + 1, self.zoom_level
|
self.x + 1, self.y + 1, self.zoom_level
|
||||||
).get_coordinates()
|
).get_coordinates()
|
||||||
|
|
||||||
flinger: Flinger = Flinger(
|
flinger: MercatorFlinger = MercatorFlinger(
|
||||||
BoundaryBox(left, bottom, right, top),
|
BoundaryBox(left, bottom, right, top),
|
||||||
self.zoom_level,
|
self.zoom_level,
|
||||||
osm_data.equator_length,
|
osm_data.equator_length,
|
||||||
|
@ -381,7 +381,7 @@ class Tiles:
|
||||||
self.zoom_level,
|
self.zoom_level,
|
||||||
).get_coordinates()
|
).get_coordinates()
|
||||||
|
|
||||||
flinger: Flinger = Flinger(
|
flinger: MercatorFlinger = MercatorFlinger(
|
||||||
BoundaryBox(left, bottom, right, top),
|
BoundaryBox(left, bottom, right, top),
|
||||||
self.zoom_level,
|
self.zoom_level,
|
||||||
osm_data.equator_length,
|
osm_data.equator_length,
|
||||||
|
|
|
@ -9,7 +9,7 @@ import numpy as np
|
||||||
from map_machine.constructor import Constructor
|
from map_machine.constructor import Constructor
|
||||||
from map_machine.figure import Figure
|
from map_machine.figure import Figure
|
||||||
from map_machine.geometry.boundary_box import BoundaryBox
|
from map_machine.geometry.boundary_box import BoundaryBox
|
||||||
from map_machine.geometry.flinger import Flinger
|
from map_machine.geometry.flinger import MercatorFlinger
|
||||||
from map_machine.map_configuration import MapConfiguration
|
from map_machine.map_configuration import MapConfiguration
|
||||||
from map_machine.osm.osm_reader import OSMData, OSMWay, OSMNode, Tags
|
from map_machine.osm.osm_reader import OSMData, OSMWay, OSMNode, Tags
|
||||||
from tests import SCHEME, SHAPE_EXTRACTOR
|
from tests import SCHEME, SHAPE_EXTRACTOR
|
||||||
|
@ -22,7 +22,7 @@ def get_constructor(osm_data: OSMData) -> Constructor:
|
||||||
Get custom constructor for bounds (-0.01, -0.01, 0.01, 0.01) and zoom level
|
Get custom constructor for bounds (-0.01, -0.01, 0.01, 0.01) and zoom level
|
||||||
18.
|
18.
|
||||||
"""
|
"""
|
||||||
flinger: Flinger = Flinger(
|
flinger: MercatorFlinger = MercatorFlinger(
|
||||||
BoundaryBox(-0.01, -0.01, 0.01, 0.01), 18, osm_data.equator_length
|
BoundaryBox(-0.01, -0.01, 0.01, 0.01), 18, osm_data.equator_length
|
||||||
)
|
)
|
||||||
constructor: Constructor = Constructor(
|
constructor: Constructor = Constructor(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue