В процессе. Карта отображается. Ошибка: накапливаются запросы на получение карты.

This commit is contained in:
sasha80
2023-11-13 10:21:17 +03:00
parent c067e36e6f
commit 892cfabfda
11 changed files with 213 additions and 121 deletions

View File

@@ -2,12 +2,14 @@ extends Node
## Веб-утилиты для работы с меркаторскими XYZ-плитками.
const R2D: = 180.0 / PI
const RE: = 6378137.0
const CE: = 2.0 * PI * RE
const EPSILON: = 1e-14
const LL_EPSILON: = 1e-11
const MAX_ZOOM: = 28
const R2D: = 180.0 / PI
const RE: = 6378137.0 ## Радиус Земли в метрах
const CE: = 2.0 * PI * RE ## Длина окружности Земли в метрах
const EPSILON: = 1e-14
const LL_EPSILON: = 1e-11
const MAX_ZOOM: = 20
const MAX_NORTH = 85.051129
const MAX_SOUTH = -85.051129
## XYZ-плитка веб-меркатора [param x], [param y], [param z] индексы
@@ -16,15 +18,19 @@ class Tile:
var x: int
var y: int
var z: int
var lng: float ## Координаты, которые плитка должна покрывать, долгота, градусы
var lat: float ## Широта, градусы
var is_root: bool ## Признак, что плитка корневая (покрывает координаты)
func as_array(): return [self.x, self.y, self.z]
func _to_string() -> String: return '[%d, %d, %d]' % [self.x, self.y, self.z]
func _init(x0: int = 0, y0: int = 0, z0: int = 0):
func _init(x0: int = 0, y0: int = 0, z0: int = 0, is_root0: bool = true):
self.x = x0
self.y = y0
self.z = z0
self.is_root = is_root0
func is_valid() -> bool:
if (self.z >= 0) and (self.z < MAX_ZOOM):
@@ -38,8 +44,12 @@ class Tile:
class LngLat:
var lng: float = 0.0 ## Долгота в десятичных градусах восточной долготы.
var lat: float = 0.0 ## Широта в десятичных градусах северной широты.
## Возвращает в виде массива
func as_array() -> Array: return [self.lng, self.lat]
func _to_string() -> String: return '[%f, %f, %f]' % [self.x, self.y, self.z]
func _init(lng0, lat0):
self.lng = lng0
self.lat = lat0
@@ -51,8 +61,12 @@ class LngLatBbox:
var south: float ## Юг
var east: float ## Восток
var north: float ## Север
## Возвращает в виде массива
func as_array() -> Array: return [self.west, self.south, self.east, self.north]
func _to_string() -> String: return '[%f, %f, %f, %f]' % [self.west, self.south, self.east, self.north]
func _init(w: float = 0.0, s: float = 0.0, e: float = 0.0, n: float = 0.0):
self.west = w
self.south = s
@@ -83,6 +97,21 @@ func radians(v: float) -> float: return (v * PI) / 180.0
func rshift(val: int, n: int) -> int: return (val % 0x100000000) >> n
## Расстояние по горизонтали в метрах, представленное одним пикселем
## [paramn lat] - Широта, градусы.[br]
## [paramn zoom] - Уровень детализации.[br]
## [paramn size] - Размер плитки в пикселях.[br]
func dist_per_pixel(lat: float, zoom: int, size: int = 256) -> float:
return (CE / float(size)) * cos(radians(lat)) / float(2 ** zoom)
## Расстояние по горизонтали в метрах, представленное одной плиткой
## [paramn lat] - Широта, градусы.[br]
## [paramn zoom] - Уровень детализации.[br]
func dist_per_tile(lat: float, zoom: int) -> float:
return CE * cos(radians(lat)) / float(2 ** zoom)
## Возвращает плитки и занимаемый ими размер области в пикселях:
## ширина, высота, левая граница, верхняя граница, плитки.[br]
## [param west] - Западная граница области.[br]
@@ -130,6 +159,7 @@ func get_degrees_bounds(m: float, lng: float, lat: float) -> Array[float]:
return [x_y[0] - m, x_y[1] - m, x_y[0] + m, x_y[1] + m]
## Возвращает границы плиток в градусах
func get_tiles_bounds(tiles: Array[Tile]) -> Array:
var mm = []
for t in tiles: mm.append(bounds(t).west)
@@ -182,17 +212,17 @@ func ul2(tile: Tile) -> Array[float]:
## Возвращает граничную область плитки.[br]
## [param tile] - Плитка.[br]
func bounds(tile: Tile) -> LngLatBbox:
var Z2: = pow(2, tile.z)
var ul_lon_deg = tile.x / Z2 * 360.0 - 180.0
var ul_lat_rad = atan(sinh(PI * (1 - 2 * tile.y / Z2)))
var z2: = pow(2, tile.z)
var ul_lon_deg = tile.x / z2 * 360.0 - 180.0
var lr_lon_deg = (tile.x + 1) / z2 * 360.0 - 180.0
var ul_lat_rad = atan(sinh(PI * (1 - 2 * tile.y / z2)))
var ul_lat_deg = degrees(ul_lat_rad)
var lr_lon_deg = (tile.x + 1) / Z2 * 360.0 - 180.0
var lr_lat_rad = atan(sinh(PI * (1 - 2 * (tile.y + 1) / Z2)))
var lr_lat_rad = atan(sinh(PI * (1 - 2 * (tile.y + 1) / z2)))
var lr_lat_deg = degrees(lr_lat_rad)
return LngLatBbox.new(ul_lon_deg, lr_lat_deg, lr_lon_deg, ul_lat_deg)
func truncate_lnglat(lng: float, lat: float) -> Array:
func truncate_lnglat(lng: float, lat: float) -> Array[float]:
if lng > 180.0: lng = 180.0
elif lng < -180.0: lng = -180.0
if lat > 90.0: lat = 90.0
@@ -200,7 +230,7 @@ func truncate_lnglat(lng: float, lat: float) -> Array:
return [lng, lat]
## Преобразование долготы и широты в веб-меркатор x, y.[br]
## Преобразование долготы и широты в веб-меркатор x, y в метрах.[br]
## [param lng] - Долгота в десятичных градусах.[br]
## [param lat] - Широта в десятичных градусах.[br]
## [param truncate] - Нужно ли усекать входные данные до пределов веб-меркатора.[br]
@@ -234,14 +264,17 @@ func lnglat(x: float, y: float, truncate: bool = false) -> LngLat:
## >>> neighbors(Tile(486, 332, 10))
## [Tile(x=485, y=331, z=10), Tile(x=485, y=332, z=10), Tile(x=485, y=333, z=10), Tile(x=486, y=331, z=10), Tile(x=486, y=333, z=10), Tile(x=487, y=331, z=10), Tile(x=487, y=332, z=10), Tile(x=487, y=333, z=10)]
## [/codeblock]
func neighbors(tile: Tile) -> Array[Tile]:
var tiles: = Array()
var lo_hi = [0, 2 ** tile.z - 1]
func neighbors(tile: Tile) -> Array:
var tiles: = []
var hi = 2 ** tile.z - 1
for i in [-1, 0, 1]:
for j in [-1, 0, 1]:
if i == 0 and j == 0: continue
elif tile.x + i < 0 or tile.y + j < 0: continue
elif tile.x + i > lo_hi[1] or tile.y + j > lo_hi[i]: continue
if i == 0 and j == 0:
continue
elif (tile.x + i) < 0 or (tile.y + j) < 0:
continue
elif (tile.x + i) > hi or (tile.y + j) > hi:
continue
var t = Tile.new(tile.x + i, tile.y + j, tile.z)
if t.is_valid():
tiles.append(t)
@@ -260,9 +293,9 @@ func xy_bounds(tile: Tile, zoom: int) -> Bbox:
return Bbox.new(left, bottom, right, top)
func _xy(lng, lat, truncate=false) -> Array:
func _xy(lng, lat, truncate=false) -> Array[float]:
var ll: = [lng, lat] if not truncate else truncate_lnglat(lng, lat)
var x = ll[0] / 360.0 + 0.5
var x: float = ll[0] / 360.0 + 0.5
var sinlat: = sin(radians(ll[1]))
var y: = 0.5 - 0.25 * log((1.0 + sinlat) / (1.0 - sinlat)) / PI
return [x, y]
@@ -274,25 +307,27 @@ func _xy(lng, lat, truncate=false) -> Array:
## [param truncate] - Нужно ли усекать вводимые данные до границ веб-меркатора.[br]
func create_tile(lng: float, lat: float, zoom: int, truncate: bool=false) -> Tile:
var xy0: = _xy(lng, lat, truncate)
var Z2 = pow(2, zoom)
var z2 = pow(2, zoom)
# Чтобы устранить потерю точности при переходе от одной плитки к другой
# и lng/lat, точки в пределах EPSILON от правой стороны тайла
# и lng/lat, точки в пределах EPSILON от правой стороны плитки
# считаются в следующей за ней плитке.
var tile: = Tile.new()
if xy0[0] <= 0: tile.x = 0
elif xy0[0] >= 1: tile.x = int(Z2 - 1)
else: tile.x = int(floor((xy0[0] + EPSILON) * Z2))
elif xy0[0] >= 1: tile.x = int(z2 - 1)
else: tile.x = int(floor((xy0[0] + EPSILON) * z2))
if xy0[1] <= 0: tile.y = 0
elif xy0[1] >= 1: tile.y = int(Z2 - 1)
else: tile.y = int(floor((xy0[1] + EPSILON) * Z2))
elif xy0[1] >= 1: tile.y = int(z2 - 1)
else: tile.y = int(floor((xy0[1] + EPSILON) * z2))
tile.z = zoom
tile.lng = lng
tile.lat = lat
return tile
## Получение четверного ключа плитки.[br]
## [param tile] Плитка
## [param tile] - Плитка
func quadkey(tile: Tile, zoom: int) -> String:
var rs: = ''
for z in range(zoom, 0, -1):
@@ -337,9 +372,7 @@ func quadkey_to_tile(qk: Array) -> Tile:
## [param truncate] [bool] - Нужно ли усекать вводимые данные до границ веб-меркатора.[br]
## [i]В параметрах south и east используется небольшой эпсилон, чтобы
## функция выдавала ровно одну плитку при задании границ этой же плитки.[/i]
func create_tiles(west: float, south: float, east: float, north: float, zooms, truncate: bool=false) -> Array[Tile]:
var west_south = [west, south] if truncate else truncate_lnglat(west, south)
var east_north = [east, north] if truncate else truncate_lnglat(east, north)
func create_tiles(west: float, south: float, east: float, north: float, zooms) -> Array[Tile]:
var bboxes = [[west, south, east, north]] if west <= east else [[-180.0, south, east, north], [west, south, 180.0, north]]
var tiles = []
if not is_instance_of(zooms, TYPE_ARRAY):
@@ -351,7 +384,7 @@ func create_tiles(west: float, south: float, east: float, north: float, zooms, t
var n = box[3]
# Зажим граничных значений.
w = max(-180.0, w)
s = max(-85.051129, s)
s = max(MAX_SOUTH, s)
e = min(180.0, e)
n = min(85.051129, n)
for z in zooms:
@@ -412,8 +445,7 @@ func parent(tile: Tile, zoom=null) -> Tile:
## >>> children(Tile(0, 0, 0), zoom=2)
## [Tile(x=0, y=0, z=2), Tile(x=0, y=1, z=2), Tile(x=0, y=2, z=2), Tile(x=0, y=3, z=2), ...]
## [/codeblock]
func children(tile, zoom) -> Array:
assert((tile.z <= zoom) and zoom == int(zoom), 'Масштаб (zoom) должен быть целым числом и превышать масштаб входной плитки (tile)')
func children(tile: Tile, zoom: int) -> Array:
var target_zoom = zoom if zoom != null else tile.z + 1
var tiles: Array[Tile] = [tile]
while tiles[0].z >= target_zoom:
@@ -484,33 +516,26 @@ func simplify(tiles: Array) -> Array:
## Tile(x=0, y=0, z=0).
## [param bbox] последовательность [float] значений границ запада, юга, востока,
## севера в десятичных градусах.
func bounding_tile(bbox, truncate: bool = false) -> Tile:
if len(bbox) == 2:
bbox += bbox
var w = bbox[0]
var s = bbox[1]
var e = bbox[2]
var n = bbox[3]
func bounding_tile(bbox: Bbox, truncate: bool = false) -> Tile:
if truncate:
var w_s = truncate_lnglat(w, s)
w = w_s[0]
s = w_s[1]
var e_n = truncate_lnglat(e, n)
n = e_n[0]
e = e_n[1]
var w_s = truncate_lnglat(bbox.left, bbox.bottom)
bbox.left = w_s[0]
bbox.bottom = w_s[1]
var e_n = truncate_lnglat(bbox.right, bbox.north)
bbox.right = e_n[0]
bbox.top = e_n[1]
e -= LL_EPSILON
s += LL_EPSILON
bbox.right -= LL_EPSILON
bbox.bottom += LL_EPSILON
var tmin = create_tile(w, n, 32)
var tmax = create_tile(e, s, 32)
var tmin = create_tile(bbox.left, bbox.top, 32)
var tmax = create_tile(bbox.right, bbox.bottom, 32)
assert(tmin.is_valid())
assert(tmax.is_valid())
var cell = [tmin.x, tmin.y, tmax.x, tmax.y]
var z = _getBboxZoom(cell)
var z = _get_bbox_zoom(cell)
if z == 0:
return Tile.new()
@@ -521,7 +546,7 @@ func bounding_tile(bbox, truncate: bool = false) -> Tile:
return Tile.new(x, y, z)
func _getBboxZoom(bbox: Array):
func _get_bbox_zoom(bbox: Array):
for z in MAX_ZOOM:
var mask: int = 1 << (32 - (z + 1))
if (bbox[0] & mask) != (bbox[2] & mask) or (bbox[1] & mask) != (bbox[3] & mask):

View File

@@ -20,3 +20,8 @@ signal threat_unselected(threats: Dictionary, th)
## Вызывается, когда пользователь переключает режим окна программы полный экран - оконный
## [param id] - Идентификатор окна. Присваевается вручную
signal full_screen(id: int)
## Вызывается при изменении уровня детализации карты
## [param zoom] - Вновь установленный уровень детализации
signal zoom_changed(zoom: int)

View File

@@ -54,7 +54,6 @@ func _ready() -> void:
timer_check_lost.start(repsettings.ThreatParams.time_lost / 1000.0)
## Периодически удаляет устаревшие цели
func on_timer_check_lost(time_lost: int, threats: Dictionary):
var tick = Time.get_ticks_msec()

View File

@@ -1,6 +1,6 @@
extends Node
##
##
const INPUT_ROWS1 = [
[12,['283333 МР-231S, Строб ЭМС', 'X52', '0.00', '0.00']],
[13,['29НРЛС МР-231-3, УИЗП', 'X54', '0.00', '0.00']],