class_name main_tilemap extends Sprite2D ## Возможные состояния конечного автомата заданий. enum TASK_STATE { DONE, ## Выполнено. WAIT, ## Ожидание плитки. RUN, ## Запуск выполнения. CHECK, ## Проверка пустого места. ERROR ## Ошибка. } ## Координаты для проверок [lng, lat]. const 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 ], 'Фиджи': [ 178.065032, -17.713371 ], 'Ноль': [ 0.0, 0.0 ], 'Точка1': [ 170.0, 0.0 ], 'Точка2': [-170.0, 0.0 ], 'Море' : [ 19.4, 54.91 ] } const MAP_MODES: = { 0: 'application/config/map_image_size_rto', 1: 'application/config/map_image_size_rls' } const MAP_RELATIVE_RADIUSES: = { 0: 0.39, 1: 0.466 } var map_image: Image ## Изображение с картой. var map_tile_state: TASK_STATE ## Текущее состояние конечного автомата плитки. var map_bcs: Vector3 ## Яркость, контраст насыщенность. var map_server_addr: String ## Адрес сервера изображений карт в проекции Меркатора. var map_tile_format: String ## var map_tile_stack: Array ## Стек для хранения плиток карты. var map_request: HTTPRequest ## Обработчик запросов http. var map_zoom: int ## Уровень детализации карты. var map_tile: Rect2i ## Область одной плитки: [x-координата области, y-координата области, x-индекс плитки, y-индекс плитки]. var map_mode: int ## Режим карты: 0 - приоритет РТО, 1 - приоритет РЛС. var prev_tiles_dic: Dictionary ## var lnglat: Array ## Текущие координаты. var root_rect: Rect2i func _ready(): lnglat = TEST_DATA['Таганрог'] map_tile_state = TASK_STATE.DONE map_request = HTTPRequest.new() add_child(map_request) map_request.request_completed.connect(self._map_request_completed) 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') map_tile_format = ProjectSettings.get_setting('application/config/map_tile_format', '%s/%d/%d/%d.png') var map_image_size = ProjectSettings.get_setting(MAP_MODES[0], Vector2i(512, 512)) var map_tile_size = ProjectSettings.get_setting('application/config/map_tile_size', 256) map_image = Image.create(map_image_size.x, map_image_size.y, true, Image.FORMAT_RGB8) map_tile = Rect2i(0, 0, map_tile_size, map_tile_size) signaller.connect('zoom_changed', Callable(self, '_on_zoom_changed')) signaller.connect('map_mode_changed', Callable(self, '_on_map_mode_changed')) log.info('Адрес сервера поставщика карт: \"%s\"' % map_server_addr) log.info('Модуль географической карты готов') func _on_map_mode_changed(mode: int) -> void: var map_image_size = ProjectSettings.get_setting(MAP_MODES[mode]) material.set('shader_parameter/radius', MAP_RELATIVE_RADIUSES[mode]) map_image.fill(Color(0, 0, 0, 0)) map_image.resize(map_image_size.x, map_image_size.y) map_tile_state = TASK_STATE.DONE map_mode = mode var tile: = mercator.create_tile(lnglat[0], lnglat[1], map_zoom) map_tile_stack.clear() map_tile_stack.append(tile) prev_tiles_dic.clear() func mark_image_center(image: Image, color: Color = Color.RED): var c = image.get_size() / 2 map_image.set_pixel(c.x - 1, c.y - 1, color) map_image.set_pixel(c.x - 1, c.y, color) map_image.set_pixel(c.x, c.y - 1, color) map_image.set_pixel(c.x, c.y, color) func _on_zoom_changed(zoom: int): if map_tile_stack.size() != 0: return map_zoom = zoom var tile: = mercator.create_tile(lnglat[0], lnglat[1], zoom) map_tile_stack.clear() map_tile_stack.append(tile) prev_tiles_dic.clear() func img_tile_to_map_image(image: Image, dst_pos: Vector2i): image.adjust_bcs(map_bcs.x, map_bcs.y, map_bcs.z) map_image.blit_rect(image, map_tile, dst_pos) func _process(_delta: float): if (map_tile_state == TASK_STATE.DONE) and map_tile_stack.size(): var tile: mercator.Tile = map_tile_stack[-1] var tile_addr: = map_tile_format % [map_server_addr, tile.z, tile.x , tile.y] var rc = map_request.request(tile_addr) if rc == OK: map_tile_state = TASK_STATE.WAIT else: log.error('%s: Невозможно сформировать запрос HTTP' % self) map_tile_state = TASK_STATE.ERROR elif map_tile_state == TASK_STATE.CHECK: var root_tile: = mercator.Tile.new(root_rect.size.x, root_rect.size.y, map_zoom) var neighbors_tiles = mercator.get_perimetr_tiles(root_tile, (map_image.get_size().x / map_tile.size.x) / 2) var neighbors_tiles_dic = {} for tile in neighbors_tiles: neighbors_tiles_dic[[tile.x, tile.y]] = false if neighbors_tiles_dic != prev_tiles_dic: for tile in neighbors_tiles: tile.is_root = false map_tile_stack.push_front(tile) prev_tiles_dic[[tile.x, tile.y]] = false else: if map_tile_stack.size() == 0: signaller.emit_signal('zoom_complete', map_zoom) map_tile_state = TASK_STATE.DONE func _map_request_completed(result, response_code, headers, data): if result != HTTPRequest.RESULT_SUCCESS: log.error('%s: Запрос не обработан. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers]) map_tile_state = TASK_STATE.ERROR return var img_tile = Image.new() var error = img_tile.load_png_from_buffer(data) if error != OK: log.error('%s: Полученые данные невозможно использовать для формироания изображения. result: \"%s\", response_code: \"%s\", headers: \"%s\"' % [self, result, response_code, headers]) map_tile_state = TASK_STATE.ERROR return 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)) 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: float = float(map_tile.size.x) / (bounds.east - bounds.west) * (lng_c - tile.lng) + map_tile.size.x / 2.0 # Cмещение в пискселях центра плитки от заданной точки по горизонтали. var sy: float = float(map_tile.size.y) / (bounds.north - bounds.south) * (lat_c - tile.lat) - map_tile.size.y / 2.0 # Cмещение в пискселях центра плитки от заданной точки по вертикали. var dst_pos: Vector2i = Vector2i(int(sx), int(-sy)) + map_tile.size * map_mode img_tile_to_map_image(img_tile, dst_pos) root_rect = Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y) else: # Отображение соседних плиток var delta: = Vector2i(tile.x - root_rect.size.x, tile.y - root_rect.size.y) var dst_pos: Vector2i = root_rect.position + delta * map_tile.size img_tile_to_map_image(img_tile, dst_pos) mark_image_center(map_image) texture = ImageTexture.create_from_image(map_image)