Files
uarep-ctl/scenes/tilemap/tilemap.gd

155 lines
8.0 KiB
GDScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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)