mirror of
https://github.com/enzet/map-machine.git
synced 2025-04-29 02:08:03 +02:00
Fix floating point numbers.
This commit is contained in:
parent
6e20668e24
commit
ed0e0384b7
23 changed files with 358 additions and 332 deletions
|
@ -35,7 +35,7 @@ def get_gradient_color(
|
|||
scale: list[Color] = colors + [Color("black")]
|
||||
|
||||
range_coefficient: float = (
|
||||
0 if bounds.is_empty() else (value - bounds.min_) / bounds.delta()
|
||||
0.0 if bounds.is_empty() else (value - bounds.min_) / bounds.delta()
|
||||
)
|
||||
# If value is out of range, set it to boundary value.
|
||||
range_coefficient = min(1.0, max(0.0, range_coefficient))
|
||||
|
|
|
@ -189,7 +189,7 @@ class Constructor:
|
|||
self.craters: list[Crater] = []
|
||||
self.direction_sectors: list[DirectionSector] = []
|
||||
|
||||
self.heights: set[float] = {2, 4}
|
||||
self.heights: set[float] = {2.0, 4.0}
|
||||
|
||||
def add_building(self, building: Building) -> None:
|
||||
"""Add building and update levels."""
|
||||
|
@ -327,10 +327,10 @@ class Constructor:
|
|||
style: dict[str, Any] = {
|
||||
"fill": "none",
|
||||
"stroke": Color("red").hex,
|
||||
"stroke-width": 1,
|
||||
"stroke-width": 1.0,
|
||||
}
|
||||
figure: StyledFigure = StyledFigure(
|
||||
line.tags, inners, outers, LineStyle(style, 1000)
|
||||
line.tags, inners, outers, LineStyle(style, 1000.0)
|
||||
)
|
||||
self.figures.append(figure)
|
||||
|
||||
|
@ -453,6 +453,7 @@ class Constructor:
|
|||
)
|
||||
if icon_set is None:
|
||||
return
|
||||
|
||||
labels: list[Label] = self.scheme.construct_text(
|
||||
tags, processed, self.configuration.label_mode
|
||||
)
|
||||
|
@ -498,7 +499,7 @@ def check_level_overground(tags: Tags) -> bool:
|
|||
if "level" in tags:
|
||||
try:
|
||||
for level in map(float, tags["level"].replace(",", ".").split(";")):
|
||||
if level < 0:
|
||||
if level < 0.0:
|
||||
return False
|
||||
except ValueError:
|
||||
pass
|
||||
|
|
|
@ -206,7 +206,7 @@ class MapMachineHTML(MapMachineMoire, DefaultHTML):
|
|||
|
||||
def icon(self, arg: Arguments) -> str:
|
||||
"""Image with Röntgen icon."""
|
||||
size: str = self.clear(arg[1]) if len(arg) > 1 else 16
|
||||
size: str = self.clear(arg[1]) if len(arg) > 1 else "16"
|
||||
return (
|
||||
f'<img class="icon" style="width: {size}px; height: {size}px;" '
|
||||
f'src="out/icons_by_id/{self.clear(arg[0])}.svg" />'
|
||||
|
@ -261,7 +261,7 @@ class MapMachineOSMWiki(MapMachineMoire, DefaultWiki):
|
|||
|
||||
def icon(self, arg: Arguments) -> str:
|
||||
"""Image with Röntgen icon."""
|
||||
size: str = self.clear(arg[1]) if len(arg) > 1 else 16
|
||||
size: str = self.clear(arg[1]) if len(arg) > 1 else "16"
|
||||
shape_id: str = self.clear(arg[0])
|
||||
name: str = self.extractor.get_shape(shape_id).name
|
||||
return f"[[File:Röntgen {name}.svg|{size}px]]"
|
||||
|
|
|
@ -27,7 +27,7 @@ class Style:
|
|||
|
||||
fill: Optional[Color] = None
|
||||
stroke: Optional[Color] = None
|
||||
width: float = 1
|
||||
width: float = 1.0
|
||||
|
||||
def update_svg_element(self, element: BaseElement) -> None:
|
||||
"""Set style for SVG element."""
|
||||
|
@ -41,7 +41,7 @@ class Style:
|
|||
def draw_png_fill(self, context: Context) -> None:
|
||||
"""Set style for context and draw fill."""
|
||||
context.set_source_rgba(
|
||||
self.fill.get_red(), self.fill.get_green(), self.fill.get_blue(), 1
|
||||
self.fill.get_red(), self.fill.get_green(), self.fill.get_blue()
|
||||
)
|
||||
context.fill()
|
||||
|
||||
|
@ -51,7 +51,6 @@ class Style:
|
|||
self.stroke.get_red(),
|
||||
self.stroke.get_green(),
|
||||
self.stroke.get_blue(),
|
||||
1,
|
||||
)
|
||||
context.set_line_width(self.width)
|
||||
context.stroke()
|
||||
|
@ -176,7 +175,7 @@ class PNGDrawing(Drawing):
|
|||
|
||||
def _do_path(self, commands: PathCommands) -> None:
|
||||
"""Draw path."""
|
||||
current: np.ndarray = np.array((0, 0))
|
||||
current: np.ndarray = np.array((0.0, 0.0))
|
||||
start_point: Optional[np.ndarray] = None
|
||||
command: str = "M"
|
||||
is_absolute: bool = True
|
||||
|
@ -231,14 +230,14 @@ class PNGDrawing(Drawing):
|
|||
point: np.ndarray
|
||||
if is_absolute:
|
||||
if command == "v":
|
||||
point = np.array((0, commands[index]))
|
||||
point = np.array((0.0, commands[index]))
|
||||
else:
|
||||
point = np.array((commands[index], 0))
|
||||
point = np.array((commands[index], 0.0))
|
||||
else:
|
||||
if command == "v":
|
||||
point = current + np.array((0, commands[index]))
|
||||
point = current + np.array((0.0, commands[index]))
|
||||
else:
|
||||
point = current + np.array((commands[index], 0))
|
||||
point = current + np.array((commands[index], 0.0))
|
||||
current = point
|
||||
self.context.line_to(point[0], point[1])
|
||||
if start_point is None:
|
||||
|
|
|
@ -51,13 +51,13 @@ def draw_element(options: argparse.Namespace) -> None:
|
|||
labels,
|
||||
tags,
|
||||
processed,
|
||||
np.array((32, 32)),
|
||||
np.array((32.0, 32.0)),
|
||||
is_for_node=is_for_node,
|
||||
draw_outline=is_for_node,
|
||||
)
|
||||
border: np.ndarray = np.array((16, 16))
|
||||
border: np.ndarray = np.array((16.0, 16.0))
|
||||
size: np.ndarray = point.get_size() + border
|
||||
point.point = np.array((size[0] / 2, 16 / 2 + border[1] / 2))
|
||||
point.point = np.array((size[0] / 2.0, 16.0 / 2.0 + border[1] / 2.0))
|
||||
|
||||
output_file_path: Path = workspace.output_path / "element.svg"
|
||||
svg: svgwrite.Drawing = svgwrite.Drawing(
|
||||
|
|
|
@ -11,9 +11,9 @@ from map_machine.drawing import PathCommands
|
|||
__author__ = "Sergey Vartanov"
|
||||
__email__ = "me@enzet.ru"
|
||||
|
||||
SHIFT: float = -np.pi / 2
|
||||
SMALLEST_ANGLE: float = np.pi / 15
|
||||
DEFAULT_ANGLE: float = np.pi / 30
|
||||
SHIFT: float = -np.pi / 2.0
|
||||
SMALLEST_ANGLE: float = np.pi / 15.0
|
||||
DEFAULT_ANGLE: float = np.pi / 30.0
|
||||
|
||||
|
||||
def parse_vector(text: str) -> Optional[np.ndarray]:
|
||||
|
@ -66,13 +66,13 @@ class Sector:
|
|||
parts: list[str] = text.split("-")
|
||||
self.start = parse_vector(parts[0])
|
||||
self.end = parse_vector(parts[1])
|
||||
self.main_direction = (self.start + self.end) / 2
|
||||
self.main_direction = (self.start + self.end) / 2.0
|
||||
else:
|
||||
result_angle: float
|
||||
if angle is None:
|
||||
result_angle = DEFAULT_ANGLE
|
||||
else:
|
||||
result_angle = max(SMALLEST_ANGLE, np.radians(angle) / 2)
|
||||
result_angle = max(SMALLEST_ANGLE, np.radians(angle) / 2.0)
|
||||
|
||||
vector: Optional[np.ndarray] = parse_vector(text)
|
||||
self.main_direction = vector
|
||||
|
@ -105,9 +105,9 @@ class Sector:
|
|||
None otherwise.
|
||||
"""
|
||||
if self.main_direction is not None:
|
||||
if np.allclose(self.main_direction[0], 0):
|
||||
if np.allclose(self.main_direction[0], 0.0):
|
||||
return None
|
||||
if self.main_direction[0] > 0:
|
||||
if self.main_direction[0] > 0.0:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
|
|
@ -435,7 +435,7 @@ class Road(Tagged):
|
|||
lane.get_width(self.scale)
|
||||
for lane in self.lanes[: lane_number - 1]
|
||||
)
|
||||
- self.width * self.scale / 2
|
||||
- self.width * self.scale / 2.0
|
||||
)
|
||||
if place == "left_of":
|
||||
pass
|
||||
|
@ -525,7 +525,7 @@ class Road(Tagged):
|
|||
"""Get road main color."""
|
||||
color: Color = self.matcher.color
|
||||
if self.tags.get("tunnel") == "yes":
|
||||
color = Color(color, luminance=min(1, color.luminance + 0.2))
|
||||
color = Color(color, luminance=min(1.0, color.luminance + 0.2))
|
||||
return color
|
||||
|
||||
def get_border_color(self) -> Color:
|
||||
|
@ -546,7 +546,7 @@ class Road(Tagged):
|
|||
|
||||
for index in range(1, len(self.lanes)):
|
||||
lane_offset: float = self.scale * (
|
||||
-self.width / 2 + index * self.width / len(self.lanes)
|
||||
-self.width / 2.0 + index * self.width / len(self.lanes)
|
||||
)
|
||||
path: Path = Path(
|
||||
d=self.line.get_path(self.placement_offset + lane_offset)
|
||||
|
@ -555,7 +555,7 @@ class Road(Tagged):
|
|||
"fill": "none",
|
||||
"stroke": color.hex,
|
||||
"stroke-linejoin": "round",
|
||||
"stroke-width": 1,
|
||||
"stroke-width": 1.0,
|
||||
"opacity": 0.5,
|
||||
}
|
||||
path.update(style)
|
||||
|
@ -568,7 +568,7 @@ class Road(Tagged):
|
|||
return
|
||||
|
||||
path: Path = svg.path(
|
||||
d=self.line.get_path(self.placement_offset + 3), fill="none"
|
||||
d=self.line.get_path(self.placement_offset + 3.0), fill="none"
|
||||
)
|
||||
svg.add(path)
|
||||
|
||||
|
@ -580,7 +580,7 @@ class Road(Tagged):
|
|||
method="align",
|
||||
spacing="exact",
|
||||
font_family="Roboto",
|
||||
font_size=10,
|
||||
font_size=10.0,
|
||||
)
|
||||
text.add(text_path)
|
||||
|
||||
|
@ -668,7 +668,7 @@ class SimpleConnector(Connector):
|
|||
"""Draw connection fill."""
|
||||
circle: Circle = svg.circle(
|
||||
self.point,
|
||||
self.road_1.width * self.scale / 2,
|
||||
self.road_1.width * self.scale / 2.0,
|
||||
fill=self.road_1.get_color().hex,
|
||||
)
|
||||
svg.add(circle)
|
||||
|
@ -677,7 +677,7 @@ class SimpleConnector(Connector):
|
|||
"""Draw connection outline."""
|
||||
circle: Circle = svg.circle(
|
||||
self.point,
|
||||
self.road_1.width * self.scale / 2 + 1,
|
||||
self.road_1.width * self.scale / 2.0 + 1.0,
|
||||
fill=self.road_1.matcher.border_color.hex,
|
||||
)
|
||||
svg.add(circle)
|
||||
|
@ -706,7 +706,7 @@ class ComplexConnector(Connector):
|
|||
point_1: np.ndarray = flinger.fling(node_1.coordinates)
|
||||
node_2: OSMNode = self.road_2.nodes[self.index_2]
|
||||
point_2: np.ndarray = flinger.fling(node_2.coordinates)
|
||||
point = (point_1 + point_2) / 2
|
||||
point = (point_1 + point_2) / 2.0
|
||||
|
||||
points_1: list[np.ndarray] = get_curve_points(
|
||||
self.road_1,
|
||||
|
@ -765,7 +765,9 @@ class SimpleIntersection(Connector):
|
|||
node: OSMNode = self.road_1.nodes[self.index_1]
|
||||
point: np.ndarray = self.flinger.fling(node.coordinates)
|
||||
circle: Circle = svg.circle(
|
||||
point, road.width * self.scale / 2, fill=road.matcher.color.hex
|
||||
point,
|
||||
road.width * self.scale / 2.0,
|
||||
fill=road.matcher.color.hex,
|
||||
)
|
||||
svg.add(circle)
|
||||
|
||||
|
@ -776,7 +778,7 @@ class SimpleIntersection(Connector):
|
|||
point: np.ndarray = self.flinger.fling(node.coordinates)
|
||||
circle: Circle = svg.circle(
|
||||
point,
|
||||
road.width * self.scale / 2 + 1,
|
||||
road.width * self.scale / 2.0 + 1.0,
|
||||
fill=road.matcher.border_color.hex,
|
||||
)
|
||||
svg.add(circle)
|
||||
|
|
|
@ -42,7 +42,7 @@ class Figure(Tagged):
|
|||
)
|
||||
|
||||
def get_path(
|
||||
self, flinger: Flinger, offset: np.ndarray = np.array((0, 0))
|
||||
self, flinger: Flinger, offset: np.ndarray = np.array((0.0, 0.0))
|
||||
) -> str:
|
||||
"""
|
||||
Get SVG path commands.
|
||||
|
@ -365,13 +365,13 @@ def is_clockwise(polygon: list[OSMNode]) -> bool:
|
|||
|
||||
:param polygon: list of OpenStreetMap nodes
|
||||
"""
|
||||
count: float = 0
|
||||
count: float = 0.0
|
||||
for index, node in enumerate(polygon):
|
||||
next_index: int = 0 if index == len(polygon) - 1 else index + 1
|
||||
count += (polygon[next_index].coordinates[0] - node.coordinates[0]) * (
|
||||
polygon[next_index].coordinates[1] + node.coordinates[1]
|
||||
)
|
||||
return count >= 0
|
||||
return count >= 0.0
|
||||
|
||||
|
||||
def make_clockwise(polygon: list[OSMNode]) -> list[OSMNode]:
|
||||
|
|
|
@ -95,15 +95,15 @@ class BoundaryBox:
|
|||
n: float = 2.0 ** (zoom_level + 8.0)
|
||||
|
||||
x: int = int((coordinates[1] + 180.0) / 360.0 * n)
|
||||
left: float = (x - width / 2) / n * 360.0 - 180.0
|
||||
right: float = (x + width / 2) / n * 360.0 - 180.0
|
||||
left: float = (x - width / 2.0) / n * 360.0 - 180.0
|
||||
right: float = (x + width / 2.0) / n * 360.0 - 180.0
|
||||
|
||||
y: int = (1.0 - np.arcsinh(np.tan(lat_rad)) / np.pi) / 2.0 * n
|
||||
bottom_radians = np.arctan(
|
||||
np.sinh((1.0 - (y + height / 2) * 2.0 / n) * np.pi)
|
||||
np.sinh((1.0 - (y + height / 2.0) * 2.0 / n) * np.pi)
|
||||
)
|
||||
top_radians = np.arctan(
|
||||
np.sinh((1.0 - (y - height / 2) * 2.0 / n) * np.pi)
|
||||
np.sinh((1.0 - (y - height / 2.0) * 2.0 / n) * np.pi)
|
||||
)
|
||||
|
||||
return cls(
|
||||
|
@ -131,17 +131,17 @@ class BoundaryBox:
|
|||
|
||||
def round(self) -> "BoundaryBox":
|
||||
"""Round boundary box."""
|
||||
self.left = round(self.left * 1000) / 1000 - 0.001
|
||||
self.bottom = round(self.bottom * 1000) / 1000 - 0.001
|
||||
self.right = round(self.right * 1000) / 1000 + 0.001
|
||||
self.top = round(self.top * 1000) / 1000 + 0.001
|
||||
self.left = round(self.left * 1000.0) / 1000.0 - 0.001
|
||||
self.bottom = round(self.bottom * 1000.0) / 1000.0 - 0.001
|
||||
self.right = round(self.right * 1000.0) / 1000.0 + 0.001
|
||||
self.top = round(self.top * 1000.0) / 1000.0 + 0.001
|
||||
|
||||
return self
|
||||
|
||||
def center(self) -> np.ndarray:
|
||||
"""Return center point of boundary box."""
|
||||
return np.array(
|
||||
((self.top + self.bottom) / 2, (self.left + self.right) / 2)
|
||||
((self.top + self.bottom) / 2.0, (self.left + self.right) / 2.0)
|
||||
)
|
||||
|
||||
def get_format(self) -> str:
|
||||
|
@ -150,10 +150,10 @@ class BoundaryBox:
|
|||
<longitude 1>,<latitude 1>,<longitude 2>,<latitude 2>. Coordinates are
|
||||
rounded to three digits after comma.
|
||||
"""
|
||||
left: float = np.floor(self.left * 1000) / 1000
|
||||
bottom: float = np.floor(self.bottom * 1000) / 1000
|
||||
right: float = np.ceil(self.right * 1000) / 1000
|
||||
top: float = np.ceil(self.top * 1000) / 1000
|
||||
left: float = np.floor(self.left * 1000.0) / 1000.0
|
||||
bottom: float = np.floor(self.bottom * 1000.0) / 1000.0
|
||||
right: float = np.ceil(self.right * 1000.0) / 1000.0
|
||||
top: float = np.ceil(self.top * 1000.0) / 1000.0
|
||||
|
||||
return f"{left:.3f},{bottom:.3f},{right:.3f},{top:.3f}"
|
||||
|
||||
|
|
|
@ -20,7 +20,9 @@ def pseudo_mercator(coordinates: np.ndarray) -> np.ndarray:
|
|||
:return: position on the plane in the form of (x, y)
|
||||
"""
|
||||
y: float = (
|
||||
180 / np.pi * np.log(np.tan(np.pi / 4 + coordinates[0] * np.pi / 360))
|
||||
180.0
|
||||
/ np.pi
|
||||
* np.log(np.tan(np.pi / 4.0 + coordinates[0] * np.pi / 360.0))
|
||||
)
|
||||
return np.array((coordinates[1], y))
|
||||
|
||||
|
@ -36,7 +38,7 @@ def osm_zoom_level_to_pixels_per_meter(
|
|||
function allows any non-negative float value
|
||||
:param equator_length: celestial body equator length in meters
|
||||
"""
|
||||
return 2 ** zoom_level / equator_length * 256
|
||||
return 2.0 ** zoom_level / equator_length * 256.0
|
||||
|
||||
|
||||
class Flinger:
|
||||
|
@ -54,7 +56,7 @@ class Flinger:
|
|||
:param equator_length: celestial body equator length in meters
|
||||
"""
|
||||
self.geo_boundaries: BoundaryBox = geo_boundaries
|
||||
self.ratio: float = 2 ** zoom_level * 256 / 360
|
||||
self.ratio: float = 2.0 ** zoom_level * 256.0 / 360.0
|
||||
self.size: np.ndarray = self.ratio * (
|
||||
pseudo_mercator(self.geo_boundaries.max_())
|
||||
- pseudo_mercator(self.geo_boundaries.min_())
|
||||
|
@ -90,5 +92,5 @@ class Flinger:
|
|||
# Get pixels per meter ratio for the center of the boundary box.
|
||||
coordinates = self.geo_boundaries.center()
|
||||
|
||||
scale_factor: float = abs(1 / np.cos(coordinates[0] / 180 * np.pi))
|
||||
scale_factor: float = abs(1.0 / np.cos(coordinates[0] / 180.0 * np.pi))
|
||||
return self.pixels_per_meter * scale_factor
|
||||
|
|
|
@ -14,14 +14,14 @@ def compute_angle(vector: np.ndarray) -> float:
|
|||
For the given vector compute an angle between it and (1, 0) vector. The
|
||||
result is in [0, 2π].
|
||||
"""
|
||||
if vector[0] == 0:
|
||||
if vector[1] > 0:
|
||||
return np.pi / 2
|
||||
return np.pi + np.pi / 2
|
||||
if vector[0] < 0:
|
||||
if vector[0] == 0.0:
|
||||
if vector[1] > 0.0:
|
||||
return np.pi / 2.0
|
||||
return np.pi + np.pi / 2.0
|
||||
if vector[0] < 0.0:
|
||||
return np.arctan(vector[1] / vector[0]) + np.pi
|
||||
if vector[1] < 0:
|
||||
return np.arctan(vector[1] / vector[0]) + 2 * np.pi
|
||||
if vector[1] < 0.0:
|
||||
return np.arctan(vector[1] / vector[0]) + 2.0 * np.pi
|
||||
return np.arctan(vector[1] / vector[0])
|
||||
|
||||
|
||||
|
@ -46,10 +46,10 @@ class Polyline:
|
|||
def __init__(self, points: list[np.ndarray]) -> None:
|
||||
self.points: list[np.ndarray] = points
|
||||
|
||||
def get_path(self, parallel_offset: float = 0) -> str:
|
||||
def get_path(self, parallel_offset: float = 0.0) -> str:
|
||||
"""Construct SVG path commands."""
|
||||
points: list[np.ndarray]
|
||||
if np.allclose(parallel_offset, 0):
|
||||
if np.allclose(parallel_offset, 0.0):
|
||||
points = self.points
|
||||
else:
|
||||
try:
|
||||
|
@ -98,12 +98,12 @@ class Line:
|
|||
|
||||
def is_parallel(self, other: "Line") -> bool:
|
||||
"""If lines are parallel or equal."""
|
||||
return np.allclose(other.a * self.b - self.a * other.b, 0)
|
||||
return np.allclose(other.a * self.b - self.a * other.b, 0.0)
|
||||
|
||||
def get_intersection_point(self, other: "Line") -> np.ndarray:
|
||||
"""Get point of intersection current line with other."""
|
||||
if other.a * self.b - self.a * other.b == 0:
|
||||
return np.array((0, 0))
|
||||
if other.a * self.b - self.a * other.b == 0.0:
|
||||
return np.array((0.0, 0.0))
|
||||
|
||||
x: float = -(self.b * other.c - other.b * self.c) / (
|
||||
other.a * self.b - self.a * other.b
|
||||
|
|
|
@ -166,7 +166,7 @@ class MapCSSWriter:
|
|||
return
|
||||
|
||||
for index, stage_of_decay in enumerate(STAGES_OF_DECAY):
|
||||
opacity: float = 0.6 - 0.4 * index / (len(STAGES_OF_DECAY) - 1)
|
||||
opacity: float = 0.6 - 0.4 * index / (len(STAGES_OF_DECAY) - 1.0)
|
||||
for matcher in self.point_matchers:
|
||||
if len(matcher.tags) > 1:
|
||||
continue
|
||||
|
|
|
@ -54,7 +54,7 @@ class Map:
|
|||
def draw(self, constructor: Constructor) -> None:
|
||||
"""Draw map."""
|
||||
self.svg.add(
|
||||
Rect((0, 0), self.flinger.size, fill=self.background_color)
|
||||
Rect((0.0, 0.0), self.flinger.size, fill=self.background_color)
|
||||
)
|
||||
ways: list[StyledFigure] = sorted(
|
||||
constructor.figures, key=lambda x: x.line_style.priority
|
||||
|
@ -130,7 +130,7 @@ class Map:
|
|||
building.draw_shade(building_shade, self.flinger)
|
||||
self.svg.add(building_shade)
|
||||
|
||||
previous_height: float = 0
|
||||
previous_height: float = 0.0
|
||||
for height in sorted(constructor.heights):
|
||||
for building in constructor.buildings:
|
||||
if building.height < height or building.min_height > height:
|
||||
|
|
|
@ -93,8 +93,8 @@ class Shape:
|
|||
def get_path(
|
||||
self,
|
||||
point: np.ndarray,
|
||||
offset: np.ndarray = np.array((0, 0)),
|
||||
scale: np.ndarray = np.array((1, 1)),
|
||||
offset: np.ndarray = np.array((0.0, 0.0)),
|
||||
scale: np.ndarray = np.array((1.0, 1.0)),
|
||||
) -> SVGPath:
|
||||
"""
|
||||
Draw icon into SVG file.
|
||||
|
@ -108,7 +108,7 @@ class Shape:
|
|||
|
||||
transformations.append(f"translate({shift[0]},{shift[1]})")
|
||||
|
||||
if not np.allclose(scale, np.array((1, 1))):
|
||||
if not np.allclose(scale, np.array((1.0, 1.0))):
|
||||
transformations.append(f"scale({scale[0]},{scale[1]})")
|
||||
|
||||
transformations.append(f"translate({self.offset[0]},{self.offset[1]})")
|
||||
|
@ -221,7 +221,7 @@ class ShapeExtractor:
|
|||
def get_offset(value: str) -> float:
|
||||
"""Get negated icon offset from the origin."""
|
||||
return (
|
||||
-int(float(value) / GRID_STEP) * GRID_STEP - GRID_STEP / 2
|
||||
-int(float(value) / GRID_STEP) * GRID_STEP - GRID_STEP / 2.0
|
||||
)
|
||||
|
||||
point: np.ndarray = np.array(
|
||||
|
@ -259,7 +259,7 @@ class ShapeSpecification:
|
|||
|
||||
shape: Shape
|
||||
color: Color = DEFAULT_COLOR
|
||||
offset: np.ndarray = np.array((0, 0))
|
||||
offset: np.ndarray = np.array((0.0, 0.0))
|
||||
flip_horizontally: bool = False
|
||||
flip_vertically: bool = False
|
||||
use_outline: bool = True
|
||||
|
@ -401,7 +401,7 @@ class Icon:
|
|||
shape_specification.color = color
|
||||
shape_specification.draw(
|
||||
svg,
|
||||
np.array((8, 8)),
|
||||
np.array((8.0, 8.0)),
|
||||
outline=outline,
|
||||
outline_opacity=outline_opacity,
|
||||
)
|
||||
|
@ -409,7 +409,7 @@ class Icon:
|
|||
for shape_specification in self.shape_specifications:
|
||||
if color:
|
||||
shape_specification.color = color
|
||||
shape_specification.draw(svg, np.array((8, 8)))
|
||||
shape_specification.draw(svg, np.array((8.0, 8.0)))
|
||||
|
||||
with file_name.open("w", encoding="utf-8") as output_file:
|
||||
svg.write(output_file)
|
||||
|
|
|
@ -161,7 +161,7 @@ class IconCollection:
|
|||
self,
|
||||
file_name: Path,
|
||||
columns: int = 16,
|
||||
step: float = 24,
|
||||
step: float = 24.0,
|
||||
background_color: Color = Color("white"),
|
||||
scale: float = 1.0,
|
||||
) -> None:
|
||||
|
@ -174,19 +174,19 @@ class IconCollection:
|
|||
:param background_color: background color
|
||||
:param scale: scale icon by the magnitude
|
||||
"""
|
||||
point: np.ndarray = np.array((step / 2 * scale, step / 2 * scale))
|
||||
point: np.ndarray = np.array((step / 2.0 * scale, step / 2.0 * scale))
|
||||
width: float = step * columns * scale
|
||||
|
||||
height: int = int(int(len(self.icons) / columns + 1) * step * scale)
|
||||
height: int = int(int(len(self.icons) / columns + 1.0) * step * scale)
|
||||
svg: Drawing = Drawing(str(file_name), (width, height))
|
||||
svg.add(svg.rect((0, 0), (width, height), fill=background_color.hex))
|
||||
|
||||
for icon in self.icons:
|
||||
icon.draw(svg, point, scale=scale)
|
||||
point += np.array((step * scale, 0))
|
||||
if point[0] > width - 8:
|
||||
point[0] = step / 2 * scale
|
||||
point += np.array((0, step * scale))
|
||||
point += np.array((step * scale, 0.0))
|
||||
if point[0] > width - 8.0:
|
||||
point[0] = step / 2.0 * scale
|
||||
point += np.array((0.0, step * scale))
|
||||
height += step * scale
|
||||
|
||||
with file_name.open("w", encoding="utf-8") as output_file:
|
||||
|
|
|
@ -32,13 +32,13 @@ class Occupied:
|
|||
|
||||
def check(self, point: np.ndarray) -> bool:
|
||||
"""Check whether point is already occupied by other elements."""
|
||||
if 0 <= point[0] < self.width and 0 <= point[1] < self.height:
|
||||
if 0.0 <= point[0] < self.width and 0.0 <= point[1] < self.height:
|
||||
return self.matrix[point[0], point[1]]
|
||||
return True
|
||||
|
||||
def register(self, point: np.ndarray) -> None:
|
||||
"""Register that point is occupied by an element."""
|
||||
if 0 <= point[0] < self.width and 0 <= point[1] < self.height:
|
||||
if 0.0 <= point[0] < self.width and 0.0 <= point[1] < self.height:
|
||||
self.matrix[point[0], point[1]] = True
|
||||
assert self.matrix[point[0], point[1]]
|
||||
|
||||
|
@ -57,7 +57,7 @@ class Point(Tagged):
|
|||
tags: dict[str, str],
|
||||
processed: set[str],
|
||||
point: np.ndarray,
|
||||
priority: float = 0,
|
||||
priority: float = 0.0,
|
||||
is_for_node: bool = True,
|
||||
draw_outline: bool = True,
|
||||
add_tooltips: bool = False,
|
||||
|
@ -71,12 +71,12 @@ class Point(Tagged):
|
|||
self.processed: set[str] = processed
|
||||
self.point: np.ndarray = point
|
||||
self.priority: float = priority
|
||||
self.layer: float = 0
|
||||
self.layer: float = 0.0
|
||||
self.is_for_node: bool = is_for_node
|
||||
self.draw_outline: bool = draw_outline
|
||||
self.add_tooltips: bool = add_tooltips
|
||||
|
||||
self.y = 0
|
||||
self.y: float = 0.0
|
||||
self.main_icon_painted: bool = False
|
||||
|
||||
def draw_main_shapes(
|
||||
|
@ -91,7 +91,7 @@ class Point(Tagged):
|
|||
):
|
||||
return
|
||||
|
||||
position: np.ndarray = self.point + np.array((0, self.y))
|
||||
position: np.ndarray = self.point + np.array((0.0, self.y))
|
||||
tags: Optional[dict[str, str]] = (
|
||||
self.tags if self.add_tooltips else None
|
||||
)
|
||||
|
@ -99,7 +99,7 @@ class Point(Tagged):
|
|||
svg, self.icon_set.main_icon, position, occupied, tags=tags
|
||||
)
|
||||
if self.main_icon_painted:
|
||||
self.y += 16
|
||||
self.y += 16.0
|
||||
|
||||
def draw_extra_shapes(
|
||||
self, svg: svgwrite.Drawing, occupied: Optional[Occupied] = None
|
||||
|
@ -110,7 +110,7 @@ class Point(Tagged):
|
|||
|
||||
is_place_for_extra: bool = True
|
||||
if occupied:
|
||||
left: float = -(len(self.icon_set.extra_icons) - 1) * 8
|
||||
left: float = -(len(self.icon_set.extra_icons) - 1.0) * 8.0
|
||||
for _ in self.icon_set.extra_icons:
|
||||
point: np.ndarray = np.array(
|
||||
(int(self.point[0] + left), int(self.point[1] + self.y))
|
||||
|
@ -118,16 +118,16 @@ class Point(Tagged):
|
|||
if occupied.check(point):
|
||||
is_place_for_extra = False
|
||||
break
|
||||
left += 16
|
||||
left += 16.0
|
||||
|
||||
if is_place_for_extra:
|
||||
left: float = -(len(self.icon_set.extra_icons) - 1) * 8
|
||||
left: float = -(len(self.icon_set.extra_icons) - 1.0) * 8.0
|
||||
for icon in self.icon_set.extra_icons:
|
||||
point: np.ndarray = self.point + np.array((left, self.y))
|
||||
self.draw_point_shape(svg, icon, point, occupied=occupied)
|
||||
left += 16
|
||||
left += 16.0
|
||||
if self.icon_set.extra_icons:
|
||||
self.y += 16
|
||||
self.y += 16.0
|
||||
|
||||
def draw_point_shape(
|
||||
self,
|
||||
|
@ -180,7 +180,7 @@ class Point(Tagged):
|
|||
text = text.replace(""", '"')
|
||||
text = text.replace("&", "&")
|
||||
text = text[:26] + ("..." if len(text) > 26 else "")
|
||||
point = self.point + np.array((0, self.y + 2))
|
||||
point = self.point + np.array((0.0, self.y + 2.0))
|
||||
self.draw_text(
|
||||
svg, text, point, occupied, label.fill, size=label.size
|
||||
)
|
||||
|
@ -212,9 +212,9 @@ class Point(Tagged):
|
|||
|
||||
if occupied:
|
||||
is_occupied: bool = False
|
||||
for i in range(-int(length / 2), int(length / 2)):
|
||||
for i in range(-int(length / 2.0), int(length / 2.0)):
|
||||
text_position: np.ndarray = np.array(
|
||||
(int(point[0] + i), int(point[1] - 4))
|
||||
(int(point[0] + i), int(point[1] - 4.0))
|
||||
)
|
||||
if occupied.check(text_position):
|
||||
is_occupied = True
|
||||
|
@ -223,7 +223,7 @@ class Point(Tagged):
|
|||
if is_occupied:
|
||||
return
|
||||
|
||||
for i in range(-int(length / 2), int(length / 2)):
|
||||
for i in range(-int(length / 2.0), int(length / 2.0)):
|
||||
for j in range(-12, 5):
|
||||
occupied.register(
|
||||
np.array((int(point[0] + i), int(point[1] + j)))
|
||||
|
@ -233,24 +233,40 @@ class Point(Tagged):
|
|||
|
||||
if out_fill_2:
|
||||
text_element = svg.text(
|
||||
text, point, font_size=size, text_anchor="middle",
|
||||
font_family=DEFAULT_FONT, fill=out_fill_2.hex,
|
||||
stroke_linejoin="round", stroke_width=5, stroke=out_fill_2.hex,
|
||||
opacity=out_opacity_2
|
||||
) # fmt: skip
|
||||
text,
|
||||
point,
|
||||
font_size=size,
|
||||
text_anchor="middle",
|
||||
font_family=DEFAULT_FONT,
|
||||
fill=out_fill_2.hex,
|
||||
stroke_linejoin="round",
|
||||
stroke_width=5.0,
|
||||
stroke=out_fill_2.hex,
|
||||
opacity=out_opacity_2,
|
||||
)
|
||||
svg.add(text_element)
|
||||
if out_fill:
|
||||
text_element = svg.text(
|
||||
text, point, font_size=size, text_anchor="middle",
|
||||
font_family=DEFAULT_FONT, fill=out_fill.hex,
|
||||
stroke_linejoin="round", stroke_width=3, stroke=out_fill.hex,
|
||||
text,
|
||||
point,
|
||||
font_size=size,
|
||||
text_anchor="middle",
|
||||
font_family=DEFAULT_FONT,
|
||||
fill=out_fill.hex,
|
||||
stroke_linejoin="round",
|
||||
stroke_width=3.0,
|
||||
stroke=out_fill.hex,
|
||||
opacity=out_opacity,
|
||||
) # fmt: skip
|
||||
)
|
||||
svg.add(text_element)
|
||||
text_element = svg.text(
|
||||
text, point, font_size=size, text_anchor="middle",
|
||||
font_family=DEFAULT_FONT, fill=fill.hex,
|
||||
) # fmt: skip
|
||||
text,
|
||||
point,
|
||||
font_size=size,
|
||||
text_anchor="middle",
|
||||
font_family=DEFAULT_FONT,
|
||||
fill=fill.hex,
|
||||
)
|
||||
svg.add(text_element)
|
||||
|
||||
self.y += 11
|
||||
|
@ -264,7 +280,9 @@ class Point(Tagged):
|
|||
width: int = icon_size * (
|
||||
1 + max(2, len(self.icon_set.extra_icons) - 1)
|
||||
)
|
||||
height: int = icon_size * (1 + int(len(self.icon_set.extra_icons) / 3))
|
||||
height: int = icon_size * (
|
||||
1 + np.ceil(len(self.icon_set.extra_icons) / 3.0)
|
||||
)
|
||||
if len(self.labels):
|
||||
height += 4 + 11 * len(self.labels)
|
||||
return np.array((width, height))
|
||||
|
|
|
@ -289,16 +289,16 @@ class RoadMatcher(Matcher):
|
|||
if "color" in structure:
|
||||
self.color = Color(scheme.get_color(structure["color"]))
|
||||
self.default_width: float = structure["default_width"]
|
||||
self.priority: float = 0
|
||||
self.priority: float = 0.0
|
||||
if "priority" in structure:
|
||||
self.priority = structure["priority"]
|
||||
|
||||
def get_priority(self, tags: Tags) -> float:
|
||||
"""Get priority for drawing order."""
|
||||
layer: float = 0
|
||||
layer: float = 0.0
|
||||
if "layer" in tags:
|
||||
layer = float(tags.get("layer"))
|
||||
return 1000 * layer + self.priority
|
||||
return 1000.0 * layer + self.priority
|
||||
|
||||
|
||||
class Scheme:
|
||||
|
@ -598,7 +598,7 @@ class Scheme:
|
|||
"""
|
||||
shape: Shape = extractor.get_shape(DEFAULT_SHAPE_ID)
|
||||
color: Color = color
|
||||
offset: np.ndarray = np.array((0, 0))
|
||||
offset: np.ndarray = np.array((0.0, 0.0))
|
||||
flip_horizontally: bool = False
|
||||
flip_vertically: bool = False
|
||||
use_outline: bool = True
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -9,7 +9,7 @@ from typing import Optional
|
|||
|
||||
import cairosvg
|
||||
|
||||
from map_configuration import MapConfiguration
|
||||
from map_machine.map_configuration import MapConfiguration
|
||||
from map_machine.slippy.tile import Tile
|
||||
from map_machine.workspace import workspace
|
||||
|
||||
|
|
|
@ -151,7 +151,7 @@ def construct_text(
|
|||
processed.add("route_ref")
|
||||
|
||||
if "cladr:code" in tags:
|
||||
texts.append(Label(tags["cladr:code"], size=7))
|
||||
texts.append(Label(tags["cladr:code"], size=7.0))
|
||||
processed.add("cladr:code")
|
||||
|
||||
if "website" in tags:
|
||||
|
|
|
@ -293,7 +293,7 @@ def add_render_arguments(parser: argparse.ArgumentParser) -> None:
|
|||
type=float,
|
||||
metavar="<float>",
|
||||
help="OSM zoom level",
|
||||
default=18,
|
||||
default=18.0,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
|
@ -354,6 +354,7 @@ def progress_bar(
|
|||
fill_length: int = int(parts / BOXES_LENGTH)
|
||||
box: str = BOXES[int(parts - fill_length * BOXES_LENGTH)]
|
||||
sys.stdout.write(
|
||||
f"{str(int(int(ratio * 1000) / 10)):>3} % {fill_length * '█'}{box}"
|
||||
f"{str(int(int(ratio * 1000.0) / 10.0)):>3} % "
|
||||
f"{fill_length * '█'}{box}"
|
||||
f"{int(length - fill_length - 1) * ' '}▏{text}\n\033[F"
|
||||
)
|
||||
|
|
|
@ -26,7 +26,7 @@ class MinMax:
|
|||
|
||||
def center(self) -> Any:
|
||||
"""Get middle point between minimum and maximum."""
|
||||
return (self.min_ + self.max_) / 2
|
||||
return (self.min_ + self.max_) / 2.0
|
||||
|
||||
def is_empty(self) -> bool:
|
||||
"""Check if interval is empty."""
|
||||
|
|
|
@ -5,5 +5,6 @@ from map_machine.ui.completion import completion_commands
|
|||
|
||||
|
||||
def test_completion() -> None:
|
||||
"""Test Fish shell completion generation."""
|
||||
commands: str = completion_commands()
|
||||
assert commands.startswith("set -l")
|
||||
|
|
Loading…
Add table
Reference in a new issue