155 lines
8.0 KiB
GDScript
155 lines
8.0 KiB
GDScript
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)
|