diff --git a/project.godot b/project.godot index 5f21f7d..6cd4b05 100644 --- a/project.godot +++ b/project.godot @@ -19,8 +19,11 @@ boot_splash/show_image=false boot_splash/fullsize=false boot_splash/use_filter=false config/icon="res://data/icon.png" -config/map_addr="https://a.tile.openstreetmap.org" -config/map_bcs=Vector3(0.5, 1.8, 0.3) +config/map_server_addr="https://a.tile.openstreetmap.org" +config/map_bcs=Vector3(0.5, 1.5, 0.3) +config/map_tile_size=256 +config/map_image_hight=512 +config/map_image_width=512 [autoload] @@ -38,7 +41,7 @@ yemsboards="*res://scripts/yemsboards.gd" yemsconsts="*res://scripts/yems-consts.gd" interfer="*res://scripts/interfer.gd" hotkeys="*res://scripts/hotkeys.gd" -mercantile="*res://scripts/mercator.gd" +mercator="*res://scripts/mercator.gd" [debug] @@ -71,6 +74,10 @@ version_control/autoload_on_startup=true enabled=PackedStringArray() +[global] + +map_server_addr=false + [gui] common/text_edit_undo_stack_max_size=10 diff --git a/scenes/btn_scale.tscn b/scenes/btn_scale.tscn index 9611706..1d6c58e 100644 --- a/scenes/btn_scale.tscn +++ b/scenes/btn_scale.tscn @@ -11,9 +11,9 @@ action_mode = 0 texture_normal = ExtResource("1_r871k") ignore_texture_size = true stretch_mode = 0 -metadata/i_scale = 0 -metadata/prefix = "Масштаб:" -metadata/scales = [10.0, 20.0, 50.0, 100.0, 250.0] +metadata/prefix = "Детализация:" +metadata/i_zoom = 0 +metadata/zooms = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] [node name="lbl" type="Label" parent="."] layout_mode = 0 diff --git a/scenes/tilemap.gd b/scenes/tilemap.gd index 03f36bd..888be87 100644 --- a/scenes/tilemap.gd +++ b/scenes/tilemap.gd @@ -1,62 +1,119 @@ extends Sprite2D -## Состояния КА карты -enum TILE_STATE { - IDLE, ## Покой - WAIT, ## Ожидание - DONE, ## Выполнено - ERROR ## Ошибка +## Возможные состояния конечного автомата заданий +enum TASK_STATE { + DONE, ## Выполнено + WAIT, ## Ожидание плитки + RUN, ## Запуск выполнения + CHECK, ## Проверка пустого места + ERROR ## Ошибка } -var curent_map_tile: Vector3i ## Текущая запрошенная плитка -var curent_state: TILE_STATE = TILE_STATE.IDLE ## Текущее состояние КА карты -var image: Image ## Изображение с картой -var map_bcs: Vector3 ## Яркость, контраст насыщенность + +## Координаты для проверок [lng, lat] +var TEST_DATA: = { + 'Калиниград': [ 20.51095, 54.70649 ], + 'Москва': [ 37.6156, 55.7522 ], + 'Нью-Йорк': [ -74.006, 40.7143 ], + 'Сидней': [ 151.20732, -33.8678500 ], + 'Таганрог': [ 38.8969, 47.2362 ], + 'Хельсинки': [ 24.9354, 60.1695 ], + 'Азорские о-ва': [ 28.3996582, 38.5397568 ], + 'Мехико': [ -99.12766, 19.42847 ], + 'Белое море': [ 68.136606, 42.045546 ], + 'море Беллинсгаузена': [ -72.406587, -74.857997 ], + 'Море' : [ 19.4, 54.91 ] } + + +var map_image: Image ## Изображение с картой +var map_tile_state: TASK_STATE ## Текущее состояние конечного автомата плитки +var map_bcs: Vector3 ## Яркость, контраст насыщенность +var map_server_addr: String ## Адрес сервера изображений карт в проекции Меркатора +var map_tile_stack: Array ## Стек для хранения плиток карты +var map_request: HTTPRequest ## Обработчик запросов http +var map_zoom: int ## Уровень детализации карты +var map_rects: Array[Rect2i] ## Занятые плиткой области изображения карты +var map_tile: Rect2i ## Область одной плитки: [x-координата области, y-координата области, x-индекс плитки, y-индекс плитки] func _ready(): - # Create an HTTP request node and connect its completion signal. - var tile = mercantile.Tile.new() - print_debug('Плитка: %s %s' % [tile, tile.is_valid()]) - var http_request = HTTPRequest.new() - add_child(http_request) - http_request.request_completed.connect(self._http_request_completed) - curent_map_tile = Vector3i(0, 0, 0) - - image = Image.create(512, 512, true, Image.FORMAT_RGB8) + map_tile_state = TASK_STATE.DONE + map_request = HTTPRequest.new() + add_child(map_request) + map_request.request_completed.connect(self._map_request_completed) + var map_image_width = ProjectSettings.get_setting('application/config/map_image_width', 512) + var map_image_hight = ProjectSettings.get_setting('application/config/map_image_hight', 512) + map_image = Image.create(map_image_width, map_image_hight, true, Image.FORMAT_RGB8) map_bcs = ProjectSettings.get_setting('application/config/map_bcs', Vector3(1.0, 1.0, 1.0)) + map_server_addr = ProjectSettings.get_setting('application/config/map_server_addr') + var map_tile_size = ProjectSettings.get_setting('application/config/map_tile_size', 256) + map_tile = Rect2i(0, 0, map_tile_size, map_tile_size) + signaller.connect('zoom_changed', Callable(self, '_on_zoom_changed')) - var error = http_request.request('https://a.tile.openstreetmap.org/0/0/0.png') - if error == OK: - curent_state = TILE_STATE.WAIT - else: - push_error('Ошибка: Не возможно сформировать запрос HTTP') - curent_state = TILE_STATE.ERROR + +func _on_zoom_changed(zoom: int): + map_zoom = zoom + var tile: = mercator.create_tile(TEST_DATA['Таганрог'][0], TEST_DATA['Таганрог'][1], zoom) + map_tile_stack.push_front(tile) + + +func request_tile(tile: mercator.Tile, server_addr: String) -> Error: + var tile_addr: = '%s/%d/%d/%d.png' % [server_addr, tile.z, tile.x , tile.y] + return map_request.request(tile_addr) func _process(delta: float): - pass + if (map_tile_state == TASK_STATE.DONE) and map_tile_stack.size(): + var tile: mercator.Tile = map_tile_stack[-1] + if request_tile(tile, map_server_addr) == OK: + map_tile_state = TASK_STATE.WAIT + else: + push_error('Ошибка: Невозможно сформировать запрос HTTP') + map_tile_state = TASK_STATE.ERROR + elif map_tile_state == TASK_STATE.CHECK: + var root_rect: Rect2i = map_rects[0] + var root_tile: = mercator.Tile.new(root_rect.size.x, root_rect.size.y, map_zoom) + var neighbors_tiles = mercator.neighbors(root_tile) + for tile in neighbors_tiles: + tile.is_root = false + map_tile_stack.push_front(tile) + map_tile_state = TASK_STATE.DONE -func _http_request_completed(result, response_code, headers, data): +func _map_request_completed(result, response_code, headers, data): if result != HTTPRequest.RESULT_SUCCESS: - push_error('Ошибка: запрос не обработан: %s' % result) - curent_state = TILE_STATE.ERROR + log.error('Запрос не обработан. result:\"%s\" response_code:\"%s\", headers:\"%s\"' % [result, response_code, headers]) + map_tile_state = TASK_STATE.ERROR return - var image0 = Image.new() - var error = image0.load_png_from_buffer(data) + var img_tile = Image.new() + var error = img_tile.load_png_from_buffer(data) if error != OK: - push_error('Ошибка: Полученые данные невозможно использовать для формироания изображения') - curent_state = TILE_STATE.ERROR + log.error('Полученые данные невозможно использовать для формироания изображения. result:\"%s\" response_code:\"%s\", headers:\"%s\"' % [result, response_code, headers]) + map_tile_state = TASK_STATE.ERROR return - curent_state = TILE_STATE.DONE - var tile_size = image0.get_size() - - image.blit_rect(image0, Rect2i(0, 0, tile_size.x, tile_size.y), Vector2i( 0, 0)) - image.blit_rect(image0, Rect2i(0, 0, tile_size.x, tile_size.y), Vector2i(tile_size.x, 0)) - image.blit_rect(image0, Rect2i(0, 0, tile_size.x, tile_size.y), Vector2i( 0, tile_size.y)) - image.blit_rect(image0, Rect2i(0, 0, tile_size.x, tile_size.y), Vector2i(tile_size.y, tile_size.y)) - image.adjust_bcs(map_bcs.x, map_bcs.y, map_bcs.z) - texture = ImageTexture.create_from_image(image) + print_debug(map_tile_stack) + var tile = map_tile_stack.pop_back() + map_tile_state = TASK_STATE.CHECK + if tile.is_root: + # Отображение корневой плитки + map_image.fill(Color(0, 0, 0, 0)) + map_rects.clear() # очистить список занятых областей изображения карты + var bounds: = mercator.bounds(tile) + var lng_c = (bounds.east + bounds.west) / 2.0 + var lat_c = (bounds.north + bounds.south) / 2.0 + var sx = map_tile.size.x / (bounds.east - bounds.west) * (lng_c - tile.lng) + map_tile.size.x / 2.0 # смещение в пискселях центра плитки от заданной точки по горизонтали + var sy = map_tile.size.y / (bounds.north - bounds.south) * (lat_c - tile.lat) - map_tile.size.y / 2.0 # смещение в пискселях центра плитки от заданной точки по вертикали + var dst_pos = Vector2i(sx, -sy) + map_image.blit_rect(img_tile, map_tile, dst_pos) + map_rects.append(Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y)) # сохранить корневую плитку + else: + # Отображение соседних плиток + var root_rect: Rect2i = map_rects[0] # Получить корневую плитку + var dx: int = tile.x - root_rect.size.x # Вычислить положение дочерней плитки относительно корневой + var dy: int = tile.y - root_rect.size.y + var dst_pos: Vector2i = root_rect.position + Vector2i(dx, dy) * map_tile.size + map_image.blit_rect(img_tile, map_tile, dst_pos) + map_rects.append(Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y)) + texture = ImageTexture.create_from_image(map_image) diff --git a/scenes/tilemap.tscn b/scenes/tilemap.tscn index 9f96ab8..b3f8e22 100644 --- a/scenes/tilemap.tscn +++ b/scenes/tilemap.tscn @@ -6,9 +6,7 @@ [sub_resource type="ShaderMaterial" id="ShaderMaterial_pmqvj"] resource_local_to_scene = true shader = ExtResource("1_tsdui") -shader_parameter/center = Vector2(0.5, 0.5) shader_parameter/radius = 0.4 -shader_parameter/rotation = 0.0 [node name="tilemap" type="Sprite2D"] material = SubResource("ShaderMaterial_pmqvj") diff --git a/scenes/работа.gd b/scenes/работа.gd index 44858fa..8abb380 100644 --- a/scenes/работа.gd +++ b/scenes/работа.gd @@ -64,6 +64,7 @@ func _ready(): threats.connect('threat_lost', Callable(self, 'on_threat_lost')) threats.connect('threats_resized', Callable(self, 'on_threats_resized')) threats.connect('threat_update', Callable(self, 'on_threat_update')) + signaller.emit_signal('zoom_changed', 0) ## Производит отображение цели на диаграмму @@ -175,12 +176,11 @@ func _input(event) -> void: shift_pressed = event.pressed -## Изменяет масштаб +## Изменяет детализацию func _on_btn_scale_pressed() -> void: - var i_scale = $btn_scale.get_meta('i_scale') + var zoom = $btn_scale.get_meta('zoom') var prefix = $btn_scale.get_meta('prefix') - var scales = $btn_scale.get_meta('scales') - i_scale += 1 - i_scale %= scales.size() - $btn_scale.set_meta('i_scale', i_scale) - $btn_scale/lbl.text = '%s %.0f км' % [prefix, scales[i_scale]] + zoom = (zoom + 1) % 20 + $btn_scale.set_meta('zoom', zoom) + $btn_scale/lbl.text = '%s %d' % [prefix, zoom] + signaller.emit_signal('zoom_changed', zoom) diff --git a/scenes/работа.tscn b/scenes/работа.tscn index 7f8d630..78e60e7 100644 --- a/scenes/работа.tscn +++ b/scenes/работа.tscn @@ -12,10 +12,10 @@ [ext_resource type="PackedScene" uid="uid://bbq6nklh36yij" path="res://scenes/tilemap.tscn" id="10_wpi4s"] [ext_resource type="Shader" path="res://shaders/tilemap.gdshader" id="11_7ohqv"] -[sub_resource type="ShaderMaterial" id="ShaderMaterial_whr8j"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_6tiyy"] resource_local_to_scene = true shader = ExtResource("11_7ohqv") -shader_parameter/radius = 0.4 +shader_parameter/radius = 0.39 [node name="Работа" type="Panel"] script = ExtResource("1_vmjjl") @@ -44,6 +44,9 @@ offset_right = 1594.0 offset_bottom = 1170.0 metadata/_edit_lock_ = true +[node name="tilemap" parent="." instance=ExtResource("10_wpi4s")] +material = SubResource("ShaderMaterial_6tiyy") + [node name="canvas" parent="." instance=ExtResource("7_pvt8f")] metadata/_edit_lock_ = true @@ -131,9 +134,7 @@ offset_left = 952.0 offset_top = 1038.0 offset_right = 1104.0 offset_bottom = 1056.0 - -[node name="tilemap" parent="." instance=ExtResource("10_wpi4s")] -material = SubResource("ShaderMaterial_whr8j") +metadata/zoom = 0 [connection signal="drag_begin" from="." to="." method="_on_drag_begin"] [connection signal="drag_continue" from="." to="." method="_on_drag_continue"] diff --git a/scripts/mercator.gd b/scripts/mercator.gd index ce60f10..df0d804 100644 --- a/scripts/mercator.gd +++ b/scripts/mercator.gd @@ -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): diff --git a/scripts/signaller.gd b/scripts/signaller.gd index 03383b8..0f40ac1 100644 --- a/scripts/signaller.gd +++ b/scripts/signaller.gd @@ -20,3 +20,8 @@ signal threat_unselected(threats: Dictionary, th) ## Вызывается, когда пользователь переключает режим окна программы полный экран - оконный ## [param id] - Идентификатор окна. Присваевается вручную signal full_screen(id: int) + + +## Вызывается при изменении уровня детализации карты +## [param zoom] - Вновь установленный уровень детализации +signal zoom_changed(zoom: int) diff --git a/scripts/threats.gd b/scripts/threats.gd index ed2c9af..5bafd72 100644 --- a/scripts/threats.gd +++ b/scripts/threats.gd @@ -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() diff --git a/scripts/yems-consts.gd b/scripts/yems-consts.gd index 378cb86..ac333c6 100644 --- a/scripts/yems-consts.gd +++ b/scripts/yems-consts.gd @@ -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']], diff --git a/shaders/tilemap.gdshader b/shaders/tilemap.gdshader index d9daad9..2b502ea 100644 --- a/shaders/tilemap.gdshader +++ b/shaders/tilemap.gdshader @@ -4,11 +4,11 @@ shader_type canvas_item; /* Рисует текстуру по маске в форме окружности */ -uniform float radius: hint_range(0.0, 1.0) = 0.4; /* Радиус */ +uniform float radius: hint_range(0.0, 1.0) = 0.8; /* Радиус */ const vec2 center = vec2(0.5, 0.5); void fragment() { - COLOR = texture(TEXTURE, UV) * smooth_px(length(UV - center), radius, DS); + COLOR = texture(TEXTURE, UV);// * smooth_px(length(UV - center), radius, DS); }