From 7f3e0f262f7b4e9a0965523d0b7458b4c56b7781 Mon Sep 17 00:00:00 2001 From: sasha80 Date: Thu, 16 Nov 2023 14:25:35 +0300 Subject: [PATCH] =?UTF-8?q?=D0=92=20=D0=BF=D1=80=D0=BE=D1=86=D0=B5=D1=81?= =?UTF-8?q?=D1=81=D0=B5.=20=D0=9A=D0=B0=D1=80=D1=82=D0=B0=20=D0=BE=D1=82?= =?UTF-8?q?=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B0=D0=B5=D1=82=D1=81=D1=8F.?= =?UTF-8?q?=20=D0=9E=D1=82=D0=BE=D0=B1=D1=80=D0=B0=D0=B6=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D0=B5=20=D0=B4=D0=B5=D1=82=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0=D1=86?= =?UTF-8?q?=D0=B8=D0=B8=20=D0=BF=D0=BE=20=D1=84=D0=B0=D0=BA=D1=82=D1=83=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B2=D0=B5=D1=80=D1=88=D0=B5=D0=BD=D0=B8=D1=8F=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B8=20=D0=BA=D0=B0?= =?UTF-8?q?=D1=80=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- project.godot | 2 ++ scenes/btn_scale.tscn | 6 ++-- scenes/tilemap.gd | 73 +++++++++++++++++++++++++++++-------------- scenes/работа.gd | 24 +++++++++----- scenes/работа.tscn | 10 +++--- scripts/mercator.gd | 39 +++++++++++++++++------ scripts/signaller.gd | 10 +++++- 7 files changed, 116 insertions(+), 48 deletions(-) diff --git a/project.godot b/project.godot index 6cd4b05..7777928 100644 --- a/project.godot +++ b/project.godot @@ -24,6 +24,8 @@ config/map_bcs=Vector3(0.5, 1.5, 0.3) config/map_tile_size=256 config/map_image_hight=512 config/map_image_width=512 +config/map_minimum_zoom=5 +config/map_maximum_zoom=19 [autoload] diff --git a/scenes/btn_scale.tscn b/scenes/btn_scale.tscn index 1d6c58e..8508825 100644 --- a/scenes/btn_scale.tscn +++ b/scenes/btn_scale.tscn @@ -1,6 +1,7 @@ [gd_scene load_steps=2 format=3 uid="uid://0uqi1ghf7sma"] -[ext_resource type="Texture2D" uid="uid://c1maea6yhd3k7" path="res://data/кнопка-масштаб.png" id="1_r871k"] +[sub_resource type="CompressedTexture2D" id="CompressedTexture2D_ymtay"] +load_path = "res://.godot/imported/кнопка-масштаб.png-506c26462e59a71e6707c554c495504e.ctex" [node name="btn_scale" type="TextureButton"] self_modulate = Color(1, 1, 1, 0.509804) @@ -8,7 +9,7 @@ offset_right = 152.0 offset_bottom = 18.0 tooltip_text = "Измененяет масштаб" action_mode = 0 -texture_normal = ExtResource("1_r871k") +texture_normal = SubResource("CompressedTexture2D_ymtay") ignore_texture_size = true stretch_mode = 0 metadata/prefix = "Детализация:" @@ -20,5 +21,4 @@ layout_mode = 0 offset_top = -18.0 offset_right = 152.0 offset_bottom = 1.0 -text = "Масштаб: 200 км" vertical_alignment = 1 diff --git a/scenes/tilemap.gd b/scenes/tilemap.gd index 888be87..9a57f19 100644 --- a/scenes/tilemap.gd +++ b/scenes/tilemap.gd @@ -12,17 +12,17 @@ enum TASK_STATE { ## Координаты для проверок [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 ], - 'Море' : [ 19.4, 54.91 ] } + 'Калиниград': [ 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 ], + 'Море' : [ 19.4, 54.91 ] } var map_image: Image ## Изображение с картой @@ -34,6 +34,8 @@ 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 = {} ## +var map_done: bool ## func _ready(): @@ -48,13 +50,27 @@ func _ready(): 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) + map_done = true signaller.connect('zoom_changed', Callable(self, '_on_zoom_changed')) +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(TEST_DATA['Таганрог'][0], TEST_DATA['Таганрог'][1], zoom) - map_tile_stack.push_front(tile) + 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: @@ -62,6 +78,12 @@ func request_tile(tile: mercator.Tile, server_addr: String) -> Error: return map_request.request(tile_addr) +func img_tile_to_map_image(image: Image, dst_pos: Vector2i, tile: mercator.Tile): + image.adjust_bcs(map_bcs.x, map_bcs.y, map_bcs.z) + map_image.blit_rect(image, map_tile, dst_pos) + map_rects.append(Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y)) # сохранить корневую плитку + + func _process(delta: float): if (map_tile_state == TASK_STATE.DONE) and map_tile_stack.size(): var tile: mercator.Tile = map_tile_stack[-1] @@ -74,9 +96,16 @@ func _process(delta: float): 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.neighbors(root_tile) + var neighbors_tiles_dic = {} for tile in neighbors_tiles: - tile.is_root = false - map_tile_stack.push_front(tile) + neighbors_tiles_dic[str(tile)] = 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[str(tile)] = false + else: + signaller.emit_signal('zoom_complete', map_zoom) map_tile_state = TASK_STATE.DONE @@ -93,7 +122,6 @@ func _map_request_completed(result, response_code, headers, data): map_tile_state = TASK_STATE.ERROR return - print_debug(map_tile_stack) var tile = map_tile_stack.pop_back() map_tile_state = TASK_STATE.CHECK if tile.is_root: @@ -101,19 +129,18 @@ func _map_request_completed(result, response_code, headers, data): 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 lng_c = (bounds.east + bounds.west) / 2.0 var lat_c = (bounds.north + bounds.south) / 2.0 - var sx = map_tile.size.x / (bounds.east - bounds.west) * (lng_c - tile.lng) + map_tile.size.x / 2.0 # смещение в пискселях центра плитки от заданной точки по горизонтали - var sy = map_tile.size.y / (bounds.north - bounds.south) * (lat_c - tile.lat) - map_tile.size.y / 2.0 # смещение в пискселях центра плитки от заданной точки по вертикали + var sx = map_tile.size.x / (bounds.east - bounds.west) * (lng_c - tile.lng) + map_tile.size.x / 2.0 # Cмещение в пискселях центра плитки от заданной точки по горизонтали. + var sy = map_tile.size.y / (bounds.north - bounds.south) * (lat_c - tile.lat) - map_tile.size.y / 2.0 # Cмещение в пискселях центра плитки от заданной точки по вертикали. var dst_pos = Vector2i(sx, -sy) - map_image.blit_rect(img_tile, map_tile, dst_pos) - map_rects.append(Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y)) # сохранить корневую плитку + img_tile_to_map_image(img_tile, dst_pos, tile) 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 - map_image.blit_rect(img_tile, map_tile, dst_pos) - map_rects.append(Rect2i(dst_pos.x, dst_pos.y, tile.x, tile.y)) + img_tile_to_map_image(img_tile, dst_pos, tile) + mark_image_center(map_image) texture = ImageTexture.create_from_image(map_image) diff --git a/scenes/работа.gd b/scenes/работа.gd index 8abb380..5fd2f85 100644 --- a/scenes/работа.gd +++ b/scenes/работа.gd @@ -24,6 +24,8 @@ extends Panel var drag_button: MouseButton ## Кнопка мыши нажатая при перетаскивании var drag_fsm: DragFSM = DragFSM.IDLE ## Текущее состояние перетаскивания var drag_pos_begin: Vector2 ## Точка начала перетаскивания +var max_zoom: int ## Максимальный уровень детализации +var min_zoom: int ## Минимальный уровень детализации var shift_pressed: bool ## Кнопка SHIFT нажата var strob_band_begin: float ## Ширина строба в момент начала перетаскивания var strob_dir_begin: float ## Направление антенны в момент начала перетаскивания @@ -52,6 +54,9 @@ func on_threats_resized(threats: Dictionary): $count_all_pad/count_all.text = '% ## Производит инициализацию func _ready(): + min_zoom = ProjectSettings.get_setting('application/config/map_minimum_zoom', 5) + max_zoom = ProjectSettings.get_setting('application/config/map_maximum_zoom', 19) + $btn_zoom.set_meta('zoom', min_zoom - 1) $tilemap.position = $canvas.get_strob_center() $btn_strob.button_connect('pressed', Callable(self, 'on_button_strobe_pressed')) $btn_view.button_connect('toggled', Callable(self, 'on_button_view_toggled')) @@ -64,7 +69,8 @@ func _ready(): threats.connect('threat_lost', Callable(self, 'on_threat_lost')) threats.connect('threats_resized', Callable(self, 'on_threats_resized')) threats.connect('threat_update', Callable(self, 'on_threat_update')) - signaller.emit_signal('zoom_changed', 0) + call_deferred('_on_btn_scale_pressed') + signaller.connect('zoom_complete', Callable(self, '_on_zoom_complete')) ## Производит отображение цели на диаграмму @@ -176,11 +182,15 @@ func _input(event) -> void: shift_pressed = event.pressed -## Изменяет детализацию +## Вызывается по нажатию кнопки "Детализация" func _on_btn_scale_pressed() -> void: - var zoom = $btn_scale.get_meta('zoom') - var prefix = $btn_scale.get_meta('prefix') - zoom = (zoom + 1) % 20 - $btn_scale.set_meta('zoom', zoom) - $btn_scale/lbl.text = '%s %d' % [prefix, zoom] + var zoom = $btn_zoom.get_meta('zoom') + zoom = zoom + 1 if zoom < max_zoom else min_zoom signaller.emit_signal('zoom_changed', zoom) + + +## Вызывается по завершению изменения детализации карты +func _on_zoom_complete(zoom: int) -> void: + var prefix = $btn_zoom.get_meta('prefix') + $btn_zoom/lbl.text = '%s %d' % [prefix, zoom] + $btn_zoom.set_meta('zoom', zoom) diff --git a/scenes/работа.tscn b/scenes/работа.tscn index 78e60e7..15a4159 100644 --- a/scenes/работа.tscn +++ b/scenes/работа.tscn @@ -12,7 +12,7 @@ [ext_resource type="PackedScene" uid="uid://bbq6nklh36yij" path="res://scenes/tilemap.tscn" id="10_wpi4s"] [ext_resource type="Shader" path="res://shaders/tilemap.gdshader" id="11_7ohqv"] -[sub_resource type="ShaderMaterial" id="ShaderMaterial_6tiyy"] +[sub_resource type="ShaderMaterial" id="ShaderMaterial_idugi"] resource_local_to_scene = true shader = ExtResource("11_7ohqv") shader_parameter/radius = 0.39 @@ -45,7 +45,7 @@ offset_bottom = 1170.0 metadata/_edit_lock_ = true [node name="tilemap" parent="." instance=ExtResource("10_wpi4s")] -material = SubResource("ShaderMaterial_6tiyy") +material = SubResource("ShaderMaterial_idugi") [node name="canvas" parent="." instance=ExtResource("7_pvt8f")] metadata/_edit_lock_ = true @@ -128,14 +128,14 @@ size_flags_horizontal = 3 size_flags_vertical = 3 text = "Вид" -[node name="btn_scale" parent="." instance=ExtResource("8_xddop")] +[node name="btn_zoom" parent="." instance=ExtResource("8_xddop")] layout_mode = 0 offset_left = 952.0 offset_top = 1038.0 offset_right = 1104.0 offset_bottom = 1056.0 -metadata/zoom = 0 +metadata/zoom = 4 [connection signal="drag_begin" from="." to="." method="_on_drag_begin"] [connection signal="drag_continue" from="." to="." method="_on_drag_continue"] -[connection signal="pressed" from="btn_scale" to="." method="_on_btn_scale_pressed"] +[connection signal="pressed" from="btn_zoom" to="." method="_on_btn_scale_pressed"] diff --git a/scripts/mercator.gd b/scripts/mercator.gd index df0d804..8ead0fe 100644 --- a/scripts/mercator.gd +++ b/scripts/mercator.gd @@ -97,6 +97,27 @@ func radians(v: float) -> float: return (v * PI) / 180.0 func rshift(val: int, n: int) -> int: return (val % 0x100000000) >> n +func asinh(val: float): return log(val + sqrt(val * val + 1.0)) + + +## Lon./lat. to tile numbers +func deg2num(lat_deg: float, lon_deg: float, zoom: int): + var lat_rad: = radians(lat_deg) + var n: = float(1 << zoom) + var xtile: = int((lon_deg + 180.0) / 360.0 * n) + var ytile: = int((1.0 - asinh(tan(lat_rad)) / PI) / 2.0 * n) + return [xtile, ytile] + + +## Tile numbers to lon./lat. +func num2deg(xtile: int, ytile: int, zoom: int): + var n: = float(1 << zoom) + var lon_deg: = float(xtile) / n * 360.0 - 180.0 + var lat_rad: = atan(sinh(PI * (1.0 - 2.0 * float(ytile) / n))) + var lat_deg = degrees(lat_rad) + return [lat_deg, lon_deg] + + ## Расстояние по горизонтали в метрах, представленное одним пикселем ## [paramn lat] - Широта, градусы.[br] ## [paramn zoom] - Уровень детализации.[br] @@ -213,16 +234,16 @@ func ul2(tile: Tile) -> Array[float]: ## [param tile] - Плитка.[br] func bounds(tile: Tile) -> LngLatBbox: var z2: = pow(2, tile.z) - var ul_lon_deg = tile.x / z2 * 360.0 - 180.0 - var lr_lon_deg = (tile.x + 1) / z2 * 360.0 - 180.0 - var ul_lat_rad = atan(sinh(PI * (1 - 2 * tile.y / z2))) + var ul_lon_deg = float(tile.x) / z2 * 360.0 - 180.0 + var lr_lon_deg = (float(tile.x) + 1.0) / z2 * 360.0 - 180.0 + var ul_lat_rad = atan(sinh(PI * (1.0 - 2.0 * float(tile.y) / z2))) var ul_lat_deg = degrees(ul_lat_rad) - var lr_lat_rad = atan(sinh(PI * (1 - 2 * (tile.y + 1) / z2))) + var lr_lat_rad = atan(sinh(PI * (1.0 - 2.0 * (float(tile.y) + 1.0) / z2))) var lr_lat_deg = degrees(lr_lat_rad) return LngLatBbox.new(ul_lon_deg, lr_lat_deg, lr_lon_deg, ul_lat_deg) -func truncate_lnglat(lng: float, lat: float) -> Array[float]: +func truncate_lnglat(lng: float, lat: float) -> Array: if lng > 180.0: lng = 180.0 elif lng < -180.0: lng = -180.0 if lat > 90.0: lat = 90.0 @@ -236,7 +257,7 @@ func truncate_lnglat(lng: float, lat: float) -> Array[float]: ## [param truncate] - Нужно ли усекать входные данные до пределов веб-меркатора.[br] ## ([param lat] >= 90) [b]inf[/b] на северном и [b]-inf[/b] на южном полюсе ([param lat] <= -90). func xy(lng: float, lat: float, truncate: bool = false) -> Array[float]: - var ll = truncate_lnglat(lng, lat) if truncate else [0.0, 0.0] + var ll = truncate_lnglat(lng, lat) if truncate else [lng, lat] var x: float = RE * radians(lng) var y: float = 0.0 if ll[1] <= -90.0: y = float('-inf') @@ -251,7 +272,7 @@ func xy(lng: float, lat: float, truncate: bool = false) -> Array[float]: func lnglat(x: float, y: float, truncate: bool = false) -> LngLat: var lng: = x * R2D / RE var lat: = ((PI * 0.5) - 2.0 * atan(exp(-y / RE))) * R2D - var ll: = truncate_lnglat(lng, lat) if truncate else [0.0, 0.0] + var ll: = truncate_lnglat(lng, lat) if truncate else [lng, lat] return LngLat.new(ll[0], ll[1]) @@ -293,8 +314,8 @@ func xy_bounds(tile: Tile, zoom: int) -> Bbox: return Bbox.new(left, bottom, right, top) -func _xy(lng, lat, truncate=false) -> Array[float]: - var ll: = [lng, lat] if not truncate else truncate_lnglat(lng, lat) +func _xy(lng: float, lat: float, truncate=false) -> Array: + var ll: = truncate_lnglat(lng, lat) if truncate else [lng, lat] var x: float = ll[0] / 360.0 + 0.5 var sinlat: = sin(radians(ll[1])) var y: = 0.5 - 0.25 * log((1.0 + sinlat) / (1.0 - sinlat)) / PI diff --git a/scripts/signaller.gd b/scripts/signaller.gd index 0f40ac1..eaf8aee 100644 --- a/scripts/signaller.gd +++ b/scripts/signaller.gd @@ -22,6 +22,14 @@ signal threat_unselected(threats: Dictionary, th) signal full_screen(id: int) -## Вызывается при изменении уровня детализации карты +## Вызывается при запросе изменения уровня детализации карты ## [param zoom] - Вновь установленный уровень детализации signal zoom_changed(zoom: int) + +## Вызывается при завершении изменения уровня детализации карты +## [param zoom] - Вновь установленный уровень детализации +signal zoom_complete(zoom: int) + +## Вызывается при изменении координат карты +## [param lan], [param lat] - Вновь установленные координаты +signal map_coords_changed(zoom: int)