extends Sprite2D ## Возможные состояния конечного автомата заданий enum TASK_STATE { DONE, ## Выполнено WAIT, ## Ожидание плитки RUN, ## Запуск выполнения CHECK, ## Проверка пустого места ERROR ## Ошибка } ## Координаты для проверок [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 ], 'Фиджи': [ 178.065032, -17.713371 ], 'Ноль': [ 0.0, 0.0 ], 'Точка1': [ 170.0, 0.0 ], 'Точка2': [-170.0, 0.0 ], 'Море' : [ 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-индекс плитки] var prev_tiles_dic = {} ## func _ready(): 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')) log.info('Модуль географической карты готов') 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 ll = TEST_DATA['Фиджи'] var tile: = mercator.create_tile(ll[0], ll[1], zoom) map_tile_stack.clear() map_tile_stack.append(tile) prev_tiles_dic.clear() 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 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] if request_tile(tile, map_server_addr) == OK: map_tile_state = TASK_STATE.WAIT else: log.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.get_perimetr_tiles(root_tile, (map_image.get_size().x / map_tile.size.x) / 1) # = mercator.neighbors(root_tile) 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) print_debug('zoom_complete: %s' % [map_rects]) map_tile_state = TASK_STATE.DONE func _map_request_completed(result, response_code, headers, data): if result != HTTPRequest.RESULT_SUCCESS: log.error('Запрос не обработан. result:\"%s\" response_code:\"%s\", headers:\"%s\"' % [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('Полученые данные невозможно использовать для формироания изображения. result:\"%s\" response_code:\"%s\", headers:\"%s\"' % [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)) 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: float = float(map_tile.size.x) / (bounds.east - bounds.west) * (lng_c - tile.lng) + map_tile.size.x / 2 # Cмещение в пискселях центра плитки от заданной точки по горизонтали. var sy: float = float(map_tile.size.y) / (bounds.north - bounds.south) * (lat_c - tile.lat) - map_tile.size.y / 2 # Cмещение в пискселях центра плитки от заданной точки по вертикали. var dst_pos: Vector2i = Vector2i(sx, -sy) img_tile_to_map_image(img_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 img_tile_to_map_image(img_tile, dst_pos) map_rects.append(Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y)) mark_image_center(map_image) texture = ImageTexture.create_from_image(map_image)