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