add: MapView template
This commit is contained in:
147
MapView/lineMapLayer.py
Normal file
147
MapView/lineMapLayer.py
Normal file
@@ -0,0 +1,147 @@
|
||||
from kivy_garden.mapview import MapLayer, MapMarker
|
||||
from kivy.graphics import Color, Line
|
||||
from kivy.graphics.context_instructions import Translate, Scale, PushMatrix, PopMatrix
|
||||
from kivy_garden.mapview.utils import clamp
|
||||
from kivy_garden.mapview.constants import (MIN_LONGITUDE, MAX_LONGITUDE, MIN_LATITUDE, MAX_LATITUDE)
|
||||
from math import radians, log, tan, cos, pi
|
||||
|
||||
|
||||
class LineMapLayer(MapLayer):
|
||||
def __init__(self, coordinates=None, color=[0, 0, 1, 1], width=2, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
# if coordinates is None:
|
||||
# coordinates = [[0, 0], [0, 0]]
|
||||
self._coordinates = coordinates
|
||||
self.color = color
|
||||
self._line_points = None
|
||||
self._line_points_offset = (0, 0)
|
||||
self.zoom = 0
|
||||
self.lon = 0
|
||||
self.lat = 0
|
||||
self.ms = 0
|
||||
self._width = width
|
||||
|
||||
@property
|
||||
def coordinates(self):
|
||||
return self._coordinates
|
||||
|
||||
@coordinates.setter
|
||||
def coordinates(self, coordinates):
|
||||
self._coordinates = coordinates
|
||||
self.invalidate_line_points()
|
||||
self.clear_and_redraw()
|
||||
|
||||
def add_point(self, point):
|
||||
if self._coordinates is None:
|
||||
#self._coordinates = [point]
|
||||
self._coordinates = []
|
||||
self._coordinates.append(point)
|
||||
# self._coordinates = [self._coordinates[-1], point]
|
||||
self.invalidate_line_points()
|
||||
self.clear_and_redraw()
|
||||
|
||||
@property
|
||||
def line_points(self):
|
||||
if self._line_points is None:
|
||||
self.calc_line_points()
|
||||
return self._line_points
|
||||
|
||||
@property
|
||||
def line_points_offset(self):
|
||||
if self._line_points is None:
|
||||
self.calc_line_points()
|
||||
return self._line_points_offset
|
||||
|
||||
def calc_line_points(self):
|
||||
# Offset all points by the coordinates of the first point,
|
||||
# to keep coordinates closer to zero.
|
||||
# (and therefore avoid some float precision issues when drawing lines)
|
||||
self._line_points_offset = (self.get_x(self.coordinates[0][1]),
|
||||
self.get_y(self.coordinates[0][0]))
|
||||
# Since lat is not a linear transform we must compute manually
|
||||
self._line_points = [(self.get_x(lon) - self._line_points_offset[0],
|
||||
self.get_y(lat) - self._line_points_offset[1])
|
||||
for lat, lon in self.coordinates]
|
||||
|
||||
def invalidate_line_points(self):
|
||||
self._line_points = None
|
||||
self._line_points_offset = (0, 0)
|
||||
|
||||
def get_x(self, lon):
|
||||
"""Get the x position on the map using this map source's projection
|
||||
(0, 0) is located at the top left.
|
||||
"""
|
||||
return clamp(lon, MIN_LONGITUDE, MAX_LONGITUDE) * self.ms / 360.0
|
||||
|
||||
def get_y(self, lat):
|
||||
"""Get the y position on the map using this map source's projection
|
||||
(0, 0) is located at the top left.
|
||||
"""
|
||||
lat = radians(clamp(-lat, MIN_LATITUDE, MAX_LATITUDE))
|
||||
return (1.0 - log(tan(lat) + 1.0 / cos(lat)) / pi) * self.ms / 2.0
|
||||
|
||||
# Function called when the MapView is moved
|
||||
def reposition(self):
|
||||
map_view = self.parent
|
||||
|
||||
# Must redraw when the zoom changes
|
||||
# as the scatter transform resets for the new tiles
|
||||
if self.zoom != map_view.zoom or \
|
||||
self.lon != round(map_view.lon, 7) or \
|
||||
self.lat != round(map_view.lat, 7):
|
||||
map_source = map_view.map_source
|
||||
self.ms = pow(2.0, map_view.zoom) * map_source.dp_tile_size
|
||||
self.invalidate_line_points()
|
||||
self.clear_and_redraw()
|
||||
|
||||
def clear_and_redraw(self, *args):
|
||||
with self.canvas:
|
||||
# Clear old line
|
||||
self.canvas.clear()
|
||||
|
||||
self._draw_line()
|
||||
|
||||
def _draw_line(self, *args):
|
||||
if self._coordinates is None:
|
||||
return
|
||||
map_view = self.parent
|
||||
self.zoom = map_view.zoom
|
||||
self.lon = map_view.lon
|
||||
self.lat = map_view.lat
|
||||
|
||||
# When zooming we must undo the current scatter transform
|
||||
# or the animation distorts it
|
||||
scatter = map_view._scatter
|
||||
sx, sy, ss = scatter.x, scatter.y, scatter.scale
|
||||
|
||||
# Account for map source tile size and map view zoom
|
||||
vx, vy, vs = map_view.viewport_pos[0], map_view.viewport_pos[1], map_view.scale
|
||||
|
||||
with self.canvas:
|
||||
self.opacity = 0.5
|
||||
# Save the current coordinate space context
|
||||
PushMatrix()
|
||||
|
||||
# Offset by the MapView's position in the window (always 0,0 ?)
|
||||
Translate(*map_view.pos)
|
||||
|
||||
# Undo the scatter animation transform
|
||||
Scale(1 / ss, 1 / ss, 1)
|
||||
Translate(-sx, -sy)
|
||||
|
||||
# Apply the get window xy from transforms
|
||||
Scale(vs, vs, 1)
|
||||
Translate(-vx, -vy)
|
||||
|
||||
# Apply what we can factor out of the mapsource long, lat to x, y conversion
|
||||
Translate(self.ms / 2, 0)
|
||||
|
||||
# Translate by the offset of the line points
|
||||
# (this keeps the points closer to the origin)
|
||||
Translate(*self.line_points_offset)
|
||||
|
||||
Color(*self.color)
|
||||
Line(points=self.line_points, width=self._width)
|
||||
|
||||
# Retrieve the last saved coordinate space context
|
||||
PopMatrix()
|
||||
Reference in New Issue
Block a user