В процессе. Добавлена работа с картами Меркатора. Добавлен общий шейдер. Рефактор

This commit is contained in:
sasha80
2023-11-02 12:49:19 +03:00
parent 94206beb47
commit d186f316f0
9 changed files with 159 additions and 211 deletions

View File

@@ -4,7 +4,7 @@
[ext_resource type="PackedScene" uid="uid://b276iygic5itk" path="res://scenes/работа.tscn" id="2_pdbvn"] [ext_resource type="PackedScene" uid="uid://b276iygic5itk" path="res://scenes/работа.tscn" id="2_pdbvn"]
[ext_resource type="PackedScene" uid="uid://lwmw4egynmd1" path="res://scenes/контроль.tscn" id="3_2apbp"] [ext_resource type="PackedScene" uid="uid://lwmw4egynmd1" path="res://scenes/контроль.tscn" id="3_2apbp"]
[ext_resource type="PackedScene" uid="uid://trt0q8th3bn2" path="res://scenes/журнал.tscn" id="4_yq6c0"] [ext_resource type="PackedScene" uid="uid://trt0q8th3bn2" path="res://scenes/журнал.tscn" id="4_yq6c0"]
[ext_resource type="PackedScene" uid="uid://dab6loryocc73" path="res://scenes/ЭМС.tscn" id="5_tlyql"] [ext_resource type="PackedScene" uid="uid://dab6loryocc73" path="res://scenes/эмс.tscn" id="5_tlyql"]
[ext_resource type="PackedScene" uid="uid://bnptm4rlp60dq" path="res://scenes/настройки.tscn" id="6_rxq15"] [ext_resource type="PackedScene" uid="uid://bnptm4rlp60dq" path="res://scenes/настройки.tscn" id="6_rxq15"]
[node name="tab_switch" type="TabContainer"] [node name="tab_switch" type="TabContainer"]

View File

@@ -8,6 +8,7 @@ resource_local_to_scene = true
shader = ExtResource("1_tsdui") shader = ExtResource("1_tsdui")
shader_parameter/center = Vector2(0.5, 0.5) shader_parameter/center = Vector2(0.5, 0.5)
shader_parameter/radius = 0.4 shader_parameter/radius = 0.4
shader_parameter/rotation = 0.0
[node name="tilemap" type="Sprite2D"] [node name="tilemap" type="Sprite2D"]
material = SubResource("ShaderMaterial_pmqvj") material = SubResource("ShaderMaterial_pmqvj")

View File

@@ -12,10 +12,9 @@
[ext_resource type="PackedScene" uid="uid://bbq6nklh36yij" path="res://scenes/tilemap.tscn" id="10_wpi4s"] [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"] [ext_resource type="Shader" path="res://shaders/tilemap.gdshader" id="11_7ohqv"]
[sub_resource type="ShaderMaterial" id="ShaderMaterial_x7kiv"] [sub_resource type="ShaderMaterial" id="ShaderMaterial_whr8j"]
resource_local_to_scene = true resource_local_to_scene = true
shader = ExtResource("11_7ohqv") shader = ExtResource("11_7ohqv")
shader_parameter/center = Vector2(0.5, 0.5)
shader_parameter/radius = 0.4 shader_parameter/radius = 0.4
[node name="Работа" type="Panel"] [node name="Работа" type="Panel"]
@@ -134,8 +133,7 @@ offset_right = 1104.0
offset_bottom = 1056.0 offset_bottom = 1056.0
[node name="tilemap" parent="." instance=ExtResource("10_wpi4s")] [node name="tilemap" parent="." instance=ExtResource("10_wpi4s")]
material = SubResource("ShaderMaterial_x7kiv") material = SubResource("ShaderMaterial_whr8j")
position = Vector2(548, 552)
[connection signal="drag_begin" from="." to="." method="_on_drag_begin"] [connection signal="drag_begin" from="." to="." method="_on_drag_begin"]
[connection signal="drag_continue" from="." to="." method="_on_drag_continue"] [connection signal="drag_continue" from="." to="." method="_on_drag_continue"]

View File

@@ -1,5 +1,6 @@
extends Node extends Node
## Web mercator XYZ tile utilities
## Веб-утилиты для работы с меркаторскими XYZ-плитками.
const R2D: = 180.0 / PI const R2D: = 180.0 / PI
const RE: = 6378137.0 const RE: = 6378137.0
@@ -9,9 +10,8 @@ const LL_EPSILON: = 1e-11
const MAX_ZOOM: = 28 const MAX_ZOOM: = 28
## An XYZ web mercator tile ## XYZ-плитка веб-меркатора [param x], [param y], [param z] индексы
## x, y, z : int # [b]x[/b] и [b]y[/b] плитки и уровень масштабирования [b]z[/b].
## x and y indexes of the tile and zoom level z.
class Tile: class Tile:
var x: int var x: int
var y: int var y: int
@@ -38,20 +38,21 @@ class Tile:
class LngLat: class LngLat:
var lng: float = 0.0 ## Долгота в десятичных градусах восточной долготы. var lng: float = 0.0 ## Долгота в десятичных градусах восточной долготы.
var lat: float = 0.0 ## Широта в десятичных градусах северной широты. var lat: float = 0.0 ## Широта в десятичных градусах северной широты.
## Возвращает в виде массива
func as_array() -> Array: return [self.lng, self.lat]
func _init(lng0, lat0): func _init(lng0, lat0):
self.lng = lng0 self.lng = lng0
self.lat = lat0 self.lat = lat0
## Географическое ограничивающее поле. ## Географические границы. Хранит значения границ в десятичных градусах.
## запад, юг, восток, север : float
## Значения границ в десятичных градусах.
class LngLatBbox: class LngLatBbox:
var west: float var west: float ## Запад
var south: float var south: float ## Юг
var east: float var east: float ## Восток
var north: float var north: float ## Север
func as_array(): return [self.west, self.south, self.east, self.north] ## Возвращает в виде массива
func as_array() -> Array: return [self.west, self.south, self.east, self.north]
func _init(w: float = 0.0, s: float = 0.0, e: float = 0.0, n: float = 0.0): func _init(w: float = 0.0, s: float = 0.0, e: float = 0.0, n: float = 0.0):
self.west = w self.west = w
self.south = s self.south = s
@@ -59,15 +60,13 @@ class LngLatBbox:
self.north = n self.north = n
## Граничная область веб-меркатора. ## Граничная область веб-меркатора. Хранит значения границ в метрах.
## Атрибуты: left, bottom, right, top : float.
## Значения границ в метрах.
class Bbox: class Bbox:
var left: float var left: float
var bottom: float var bottom: float
var right: float var right: float
var top: float var top: float
func as_array(): return [self.left, self.bottom, self.right, self.top] func as_array() -> Array: return [self.left, self.bottom, self.right, self.top]
func _init(l: float = 0.0, b: float = 0.0, r: float = 0.0, t: float = 0.0): func _init(l: float = 0.0, b: float = 0.0, r: float = 0.0, t: float = 0.0):
self.left = l self.left = l
self.bottom = b self.bottom = b
@@ -75,25 +74,26 @@ class Bbox:
self.top = t self.top = t
func degrees(v: float): return (v * 180.0) / PI func degrees(v: float) -> float: return (v * 180.0) / PI
func radians(v: float): return (v * PI) / 180.0 func radians(v: float) -> float: return (v * PI) / 180.0
func rshift(val: int, n: int): return (val % 0x100000000) >> n func rshift(val: int, n: int) -> int: return (val % 0x100000000) >> n
## Возвращает плитки и занимаемый ими размер области в пикселях: ## Возвращает плитки и занимаемый ими размер области в пикселях:
## ширина, высота, левая граница, верхняя граница, плитки ## ширина, высота, левая граница, верхняя граница, плитки.[br]
## [param west] [float] Западная граница области ## [param west] - Западная граница области.[br]
## [param east] [float] Восточная граница области ## [param east] - Восточная граница области.[br]
## [param south] [float] Южная граница области ## [param south] - Южная граница области.[br]
## [param north] [float] Северная граница области ## [param north] - Северная граница области.[br]
## [param size] [float] Размер плитки в пикселях ## [param size] - Размер плитки в пикселях.[br]
## [param zoom] [float] Детализация ## [param zoom] - Детализация.[br]
func get_tiles(west, south, east, north, zoom, size): func get_tiles(west: float, south: float, east: float, north: float, zoom: int, size: int) -> Array:
var tiles = [create_tiles(west, south, east, north, zoom)] var tiles: = create_tiles(west, south, east, north, zoom)
var mm = [] var mm = []
for t in tiles: mm.append(t.x) for t in tiles: mm.append(t.x)
var min_x = mm.min() var min_x = mm.min()
@@ -109,32 +109,28 @@ func get_tiles(west, south, east, north, zoom, size):
return [w, h, min_x, min_y, tiles, max_x - min_x + 1] return [w, h, min_x, min_y, tiles, max_x - min_x + 1]
## Возвращает размер области в метрах ## Возвращает размер области в метрах.[br]
## [param west] [float] - Западная граница области ## [param west] - Западная граница области.[br]
## [param param] [float] - Восточная граница области ## [param param] - Восточная граница области.[br]
## [param south] [float] - Южная граница области ## [param south] - Южная граница области.[br]
## [param north] [float] - Северная граница области ## [param north] - Северная граница области.[br]
## [return] [Array] func get_size_from_degrees(west: float, south: float, east: float, north: float) -> Array[float]:
func get_size_from_degrees(west, south, east, north) -> Array[float]:
var xy0: = xy(west, north, true) var xy0: = xy(west, north, true)
var xy1: = xy(east, south, true) var xy1: = xy(east, south, true)
return [xy0[0] - xy1[0], xy0[1] - xy1[1]] return [xy0[0] - xy1[0], xy0[1] - xy1[1]]
## Возвращает границы области в градусах ## Возвращает границы области в градусах.[br]
## [param m] [float] - Размер карты в метрах. ## [param m] - Размер карты в метрах.[br]
## [param lng] [float] - Долгота центра области в градусах (-180...180). ## [param lng] - Долгота центра области в градусах (-180...180).[br]
## [param lat] [float] - Широта центра области в градусах (-90...90). ## [param lat] - Широта центра области в градусах (-90...90).[br]
## [return] [float, float, float, float] func get_degrees_bounds(m: float, lng: float, lat: float) -> Array[float]:
func get_degrees_bounds(m: float, lng: float, lat: float):
m /= 2.0 m /= 2.0
var x_y = xy(lng, lat, true) var x_y = xy(lng, lat, true)
var ws = lnglat(x_y[0] - m, x_y[1] - m) return [x_y[0] - m, x_y[1] - m, x_y[0] + m, x_y[1] + m]
var en = lnglat(x_y[0] + m, x_y[1] + m)
return [ws[0], ws[1], en[0], en[1]]
func get_tiles_bounds(tiles): func get_tiles_bounds(tiles: Array[Tile]) -> Array:
var mm = [] var mm = []
for t in tiles: mm.append(bounds(t).west) for t in tiles: mm.append(bounds(t).west)
var mmw = mm.min(); mm.clear() var mmw = mm.min(); mm.clear()
@@ -151,17 +147,15 @@ func get_tiles_bounds(tiles):
return [mmw, mms, mme, mmn] return [mmw, mms, mme, mmn]
## Возвращает левую верхнюю долготу и широту плитки. ## Возвращает левую верхнюю долготу и широту плитки.[br]
## [param tile] Плитка или последовательность int. Может быть либо экземпляр ## [param tile] Плитка.[br]
## Tile, либо 3 ints, X, Y, Z.
## [return] LngLat
## [codeblock] ## [codeblock]
## >>> ul(Tile(x=0, y=0, z=1)) ## >>> ul(Tile(x=0, y=0, z=1))
## LngLat(lng=-180.0, lat=85.0511287798066) ## LngLat(lng=-180.0, lat=85.0511287798066)
## >>> mercantile.ul(1, 1, 1) ## >>> mercantile.ul(1, 1, 1)
## LngLat(lng=0.0, lat=0.0) ## LngLat(lng=0.0, lat=0.0)
## [/codeblock] ## [/codeblock]
func ul(tile: Tile, zoom: int): func ul(tile: Tile, zoom: int) -> LngLat:
var Z2 = pow(2, zoom) var Z2 = pow(2, zoom)
var lon_deg = tile.x / Z2 * 360.0 - 180.0 var lon_deg = tile.x / Z2 * 360.0 - 180.0
var lat_rad = atan(sinh(PI * (1 - 2 * tile.y / Z2))) var lat_rad = atan(sinh(PI * (1 - 2 * tile.y / Z2)))
@@ -169,9 +163,8 @@ func ul(tile: Tile, zoom: int):
return LngLat.new(lon_deg, lat_deg) return LngLat.new(lon_deg, lat_deg)
## Возвращает левую верхнюю долготу и широту плитки. ## Возвращает левую верхнюю долготу и широту плитки.[br]
## [param tile] [Плитка] Может быть либо экземпляром Tile, либо 3 интами, X, Y, Z. ## [param tile] - Плитка.[br]
## [return] [LngLat]
## [codeblock] ## [codeblock]
## >>> ul(Tile(x=0, y=0, z=1)) ## >>> ul(Tile(x=0, y=0, z=1))
## LngLat(lng=-180.0, lat=85.0511287798066) ## LngLat(lng=-180.0, lat=85.0511287798066)
@@ -186,21 +179,16 @@ func ul2(tile: Tile) -> Array[float]:
return [lat_deg, lon_deg] return [lat_deg, lon_deg]
## Возвращает граничную область плитки. ## Возвращает граничную область плитки.[br]
## [param tile] [Tile] или [Array]. Может быть либо экземпляром [Tile], либо 3 ## [param tile] - Плитка.[br]
## целыми числами (X, Y, Z).
## [return] [LngLatBbox]
func bounds(tile: Tile) -> LngLatBbox: func bounds(tile: Tile) -> LngLatBbox:
var Z2: = pow(2, tile.z) var Z2: = pow(2, tile.z)
var ul_lon_deg = tile.x / Z2 * 360.0 - 180.0 var ul_lon_deg = tile.x / Z2 * 360.0 - 180.0
var ul_lat_rad = atan(sinh(PI * (1 - 2 * tile.y / Z2))) var ul_lat_rad = atan(sinh(PI * (1 - 2 * tile.y / Z2)))
var ul_lat_deg = degrees(ul_lat_rad) var ul_lat_deg = degrees(ul_lat_rad)
var lr_lon_deg = (tile.x + 1) / Z2 * 360.0 - 180.0 var lr_lon_deg = (tile.x + 1) / Z2 * 360.0 - 180.0
var lr_lat_rad = atan(sinh(PI * (1 - 2 * (tile.y + 1) / Z2))) var lr_lat_rad = atan(sinh(PI * (1 - 2 * (tile.y + 1) / Z2)))
var lr_lat_deg = degrees(lr_lat_rad) var lr_lat_deg = degrees(lr_lat_rad)
return LngLatBbox.new(ul_lon_deg, lr_lat_deg, lr_lon_deg, ul_lat_deg) return LngLatBbox.new(ul_lon_deg, lr_lat_deg, lr_lon_deg, ul_lat_deg)
@@ -212,12 +200,11 @@ func truncate_lnglat(lng: float, lat: float) -> Array:
return [lng, lat] return [lng, lat]
## Преобразование долготы и широты в веб-меркатор x, y. ## Преобразование долготы и широты в веб-меркатор x, y.[br]
## [param lng] [param lat]: float ## [param lng] - Долгота в десятичных градусах.[br]
## Долгота и широта в десятичных градусах [param truncate] [bool] -Нужно ли ## [param lat] - Широта в десятичных градусах.[br]
## усекать или обрезать входные данные до пределов веб-меркатора. ## [param truncate] - Нужно ли усекать входные данные до пределов веб-меркатора.[br]
## [return] [x: float, y: float]. [param y] будет [b]inf[/b] на северном полюсе. ## ([param lat] >= 90) [b]inf[/b] на северном и [b]-inf[/b] на южном полюсе ([param lat] <= -90).
## ([param lat] >= 90) и [b]-inf[/b] на южном полюсе ([param lat] <= -90).
func xy(lng: float, lat: float, truncate: bool = false) -> Array[float]: 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 [0.0, 0.0]
var x: float = RE * radians(lng) var x: float = RE * radians(lng)
@@ -228,18 +215,17 @@ func xy(lng: float, lat: float, truncate: bool = false) -> Array[float]:
return [x, y] return [x, y]
## Преобразование координат веб-меркатора x, y в долготу и широту. ## Преобразование координат веб-меркатора x, y в долготу и широту.[br]
## [param x] [float], [param y] [float] - Координаты веб-меркатора в метрах. ## [param x], [param y] - Координаты веб-меркатора в метрах.[br]
## [param truncate] [bool] - Нужно ли усекать или обрезать входные данные до границ веб-меркатора. ## [param truncate] - Нужно ли усекать или обрезать входные данные до границ веб-меркатора.
## [return] [LngLat] func lnglat(x: float, y: float, truncate: bool = false) -> LngLat:
func lnglat(x, y, truncate=false): var lng: = x * R2D / RE
var lng = x * R2D / RE var lat: = ((PI * 0.5) - 2.0 * atan(exp(-y / RE))) * R2D
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 [0.0, 0.0]
return LngLat.new(ll[0], ll[1]) return LngLat.new(ll[0], ll[1])
## Соседи плитки. [func neighbors] возвращает до восьми ## Соседи плитки. [method neighbors] возвращает до восьми
## соседних плиток, при этом плитки будут опущены, если они не являются действительными, например. ## соседних плиток, при этом плитки будут опущены, если они не являются действительными, например.
## Tile(-1, -1, z). [param tile]: Плитка или последовательность int ## Tile(-1, -1, z). [param tile]: Плитка или последовательность int
## Может быть либо экземпляр Tile, либо 3 ints, X, Y, Z. ## Может быть либо экземпляр Tile, либо 3 ints, X, Y, Z.
@@ -262,11 +248,9 @@ func neighbors(tile: Tile) -> Array[Tile]:
return tiles return tiles
## Получение меркаторской граничной рамки веб-плитки ## Получение меркаторской граничной рамки веб-плитки.[br]
## [param tile] - Плитка или последовательность int. Может быть либо экземпляр ## [param tile] - Плитка.[br]
## [Tile], либо 3 ints, X, Y, Z. ## [i]Эпсилон вычитается из правой границы и прибавляется к нижней[/i]
## [return] [Bbox]
## Примечания. Эпсилон вычитается из правой границы и прибавляется к нижней.
func xy_bounds(tile: Tile, zoom: int) -> Bbox: func xy_bounds(tile: Tile, zoom: int) -> Bbox:
var tile_size = CE / pow(2, zoom) var tile_size = CE / pow(2, zoom)
var left = tile.x * tile_size - CE / 2 var left = tile.x * tile_size - CE / 2
@@ -285,10 +269,9 @@ func _xy(lng, lat, truncate=false) -> Array:
## Получение плитки, содержащей долготу и широту ## Получение плитки, содержащей долготу и широту
## [param lng], [param lat] [float] - Пара долготы и широты в десятичных градусах. ## [param lng], [param lat] - Пара долготы и широты в десятичных градусах.[br]
## [param zoom] [int] - Уровень масштабирования веб-меркатора. ## [param zoom] - Уровень масштабирования веб-меркатора.[br]
## [param truncate] [bool] - Нужно ли усекать вводимые данные до границ веб-меркатора. ## [param truncate] - Нужно ли усекать вводимые данные до границ веб-меркатора.[br]
## [return] [Tile]
func create_tile(lng: float, lat: float, zoom: int, truncate: bool=false) -> Tile: func create_tile(lng: float, lat: float, zoom: int, truncate: bool=false) -> Tile:
var xy0: = _xy(lng, lat, truncate) var xy0: = _xy(lng, lat, truncate)
var Z2 = pow(2, zoom) var Z2 = pow(2, zoom)
@@ -308,12 +291,10 @@ func create_tile(lng: float, lat: float, zoom: int, truncate: bool=false) -> Til
return tile return tile
## Получение четверного ключа плитки ## Получение четверного ключа плитки.[br]
## [param tile] [Tile] или последовательность [int]. Может быть либо экземпляр ## [param tile] Плитка
## [Tile] или 3 целых, X, Y, Z. func quadkey(tile: Tile, zoom: int) -> String:
## [return] [String] var rs: = ''
func quadkey(tile: Tile, zoom) -> String:
var rs: = String()
for z in range(zoom, 0, -1): for z in range(zoom, 0, -1):
var digit = 0 var digit = 0
var mask = 1 << (z - 1) var mask = 1 << (z - 1)
@@ -325,10 +306,9 @@ func quadkey(tile: Tile, zoom) -> String:
return rs return rs
## Получение плитки, соответствующей четверному ключу. ## Получение плитки, соответствующей четверному ключу.[br]
## [param qk] [String] - Строка четверного ключа. ## [param qk] - Строка четверного ключа.
## [return] [Tile] func quadkey_to_tile(qk: Array) -> Tile:
func quadkey_to_tile(qk: Array):
var tile: = Tile.new() var tile: = Tile.new()
if len(qk) == 0: return tile if len(qk) == 0: return tile
var i = 0 var i = 0
@@ -351,14 +331,12 @@ func quadkey_to_tile(qk: Array):
return tile return tile
## Получение плиток, перекрываемых географической рамкой ## Получение плиток, перекрываемых географической рамкой.[br]
## [param west], [param south], [param east], [param north]: последовательность [float] ## [param west], [param south], [param east], [param north] - Значения границ в десятичных градусах.[br]
## - Значения границ в десятичных градусах. ## [param zooms] - Один или несколько уровней масштабирования.[br]
## [param zooms] [int] или [Array[int]]. - Один или несколько уровней масштабирования. ## [param truncate] [bool] - Нужно ли усекать вводимые данные до границ веб-меркатора.[br]
## [param truncate] [bool] - Нужно ли усекать вводимые данные до границ веб-меркатора. ## [i]В параметрах south и east используется небольшой эпсилон, чтобы
## [return] Tile ## функция выдавала ровно одну плитку при задании границ этой же плитки.[/i]
## Примечания. В параметрах south и east используется небольшой эпсилон, чтобы
## функция выдавала ровно одну плитку при задании границ этой же плитки.
func create_tiles(west: float, south: float, east: float, north: float, zooms, truncate: bool=false) -> Array[Tile]: func create_tiles(west: float, south: float, east: float, north: float, zooms, truncate: bool=false) -> Array[Tile]:
var west_south = [west, south] if truncate else truncate_lnglat(west, south) var west_south = [west, south] if truncate else truncate_lnglat(west, south)
var east_north = [east, north] if truncate else truncate_lnglat(east, north) var east_north = [east, north] if truncate else truncate_lnglat(east, north)
@@ -386,19 +364,17 @@ func create_tiles(west: float, south: float, east: float, north: float, zooms, t
## Получение родителя плитки. Родительская плитка - это плитка на один уровень масштабирования ниже, которая ## Получение родителя плитки. Родительская плитка - это плитка на один уровень масштабирования ниже, которая
## содержит данную "дочернюю" плитку. ## содержит данную "дочернюю" плитку.[br]
## [param tile] [Tile] или последовательность int - Может быть либо экземпляром Tile. ## [param tile] - Плитка.[br]
## или 3 ints, X, Y, Z. ## [param zoom] - Определяет уровень *масштабирования* возвращаемой родительской плитки.
## [param zoom] [int] - Определяет уровень *масштабирования* возвращаемой родительской плитки. ## По умолчанию это значение на один ниже, чем у плитки (непосредственного родителя).[br]
## По умолчанию это значение на один ниже, чем у плитки (непосредственного родителя).
## [return] [Tile]
## [codeblock] ## [codeblock]
## >>> parent(Tile(0, 0, 2)) ## >>> parent(Tile(0, 0, 2))
## Tile(x=0, y=0, z=1) ## Tile(x=0, y=0, z=1)
## >>> parent(Tile(0, 0, 2), zoom=0) ## >>> parent(Tile(0, 0, 2), zoom=0)
## Tile(x=0, y=0, z=0) ## Tile(x=0, y=0, z=0)
## [/codeblock] ## [/codeblock]
func parent(tile: Tile, zoom=null): func parent(tile: Tile, zoom=null) -> Tile:
if tile.z == 0: return null if tile.z == 0: return null
assert((zoom != null) and (tile.z > zoom or zoom == int(zoom)), 'Масштаб (zoom) должен быть целым числом и меньше масштаба входной плитки (tile).') assert((zoom != null) and (tile.z > zoom or zoom == int(zoom)), 'Масштаб (zoom) должен быть целым числом и меньше масштаба входной плитки (tile).')
@@ -424,13 +400,12 @@ func parent(tile: Tile, zoom=null):
## Получение дочерних элементов плитки. Дочерние элементы упорядочены: ## Получение дочерних элементов плитки. Дочерние элементы упорядочены:
## верхний-левый, верхний-правый, bottom-right, bottom-left. ## верхний-левый, верхний-правый, нижний-правый, нижний-левый. Возвращает все
## [tile] [Tile] или последовательность int. Может быть либо экземпляром Tile, ## дочерние элементы с масштабом *zoom*, в порядке убывания глубины в порядке
## либо 3 интами, X, Y, Z. ## вращения по часовой стрелке. Если не указано, возвращаются ближайшие
## [param zoom] [int] Возвращает все дочерние элементы с масштабом *zoom*, в порядке убывания глубины. ## (т.е. zoom + 1) дочерние элементы плитки.[br]
## в порядке намотки по часовой стрелке. Если не указано, возвращаются ближайшие (т.е. zoom + 1) ## [param tile] - Плитка.[br]
## дочерние элементы плитки. ## [param zoom] - Уровень детализации.
## [return] [Array]
## [codeblock] ## [codeblock]
## >>> children(Tile(0, 0, 0)) ## >>> children(Tile(0, 0, 0))
## [Tile(x=0, y=0, z=1), Tile(x=0, y=1, z=1), Tile(x=1, y=0, z=1), Tile(x=1, y=1, z=1)] ## [Tile(x=0, y=0, z=1), Tile(x=0, y=1, z=1), Tile(x=1, y=0, z=1), Tile(x=1, y=1, z=1)]
@@ -455,7 +430,7 @@ func children(tile, zoom) -> Array:
## Если есть, то происходит их слияние. Возвращает список плиток, а также булево ## Если есть, то происходит их слияние. Возвращает список плиток, а также булево
## число, указывающее, были ли они объединены. При многократном применяя ## число, указывающее, были ли они объединены. При многократном применяя
## [method merge], можно упростить набор плиток. ## [method merge], можно упростить набор плиток.
func merge(merge_set): func merge(merge_set) -> Array:
var upwards_merge: = {} var upwards_merge: = {}
for tile in merge_set.keys(): for tile in merge_set.keys():
var tile_parent = parent(tile) var tile_parent = parent(tile)
@@ -476,8 +451,7 @@ func merge(merge_set):
## Максимально уменьшает размер набора плиток путем слияния листьев с родителями. ## Максимально уменьшает размер набора плиток путем слияния листьев с родителями.
## [param tiles] - Последовательность плиток для слияния. ## [param tiles] - Последовательность плиток для слияния.
## [return] [Array] func simplify(tiles: Array) -> Array:
func simplify(tiles: Array):
# Проверьте, существует ли уже плитка и ее родитель. # Проверьте, существует ли уже плитка и ее родитель.
# Убедитесь, что плитки отсортированы по масштабу, поэтому родительские # Убедитесь, что плитки отсортированы по масштабу, поэтому родительские
# плитки встречаются первыми. Если да, отбросьте дочернюю плитку # плитки встречаются первыми. Если да, отбросьте дочернюю плитку
@@ -510,8 +484,7 @@ func simplify(tiles: Array):
## Tile(x=0, y=0, z=0). ## Tile(x=0, y=0, z=0).
## [param bbox] последовательность [float] значений границ запада, юга, востока, ## [param bbox] последовательность [float] значений границ запада, юга, востока,
## севера в десятичных градусах. ## севера в десятичных градусах.
## [return] [Tile] func bounding_tile(bbox, truncate: bool = false) -> Tile:
func bounding_tile(bbox, truncate: bool = false):
if len(bbox) == 2: if len(bbox) == 2:
bbox += bbox bbox += bbox
@@ -556,18 +529,14 @@ func _getBboxZoom(bbox: Array):
return MAX_ZOOM return MAX_ZOOM
## Получение GeoJSON-функции, соответствующей плитке ## Получение GeoJSON-функции, соответствующей плитке.[br]
## [param tile] [Плитка] или последовательность int - Может быть либо экземпляром [Плитка], либо 3 int, X, Y, Z. ## [param tile] - Плитка.[br]
## [Tile] или 3 целых, X, Y, Z. ## [param fid] - Идентификатор объекта.[br]
## [param fid] [String] - Идентификатор объекта. ## [param props] - Необязательные дополнительные свойства признака.[br]
## [param props] [Dictionary] - Необязательные дополнительные свойства признака. ## [param projected] - Можно создать нестандартный веб-меркатор GeoJSON передав 'mercator'[br]
## [param projected] [String] - Можно создать нестандартный веб-меркатор GeoJSON. ## [param buffer] - Необязательное буферное расстояние для полигона GeoJSON.[br]
## передав 'mercator'. ## [param precision] - Координаты GeoJSON будут усечены до данного количества знаков после запятой.[br]
## [param buffer] [float] - Необязательное буферное расстояние для полигона GeoJSON. func feature(tile: Tile, fid:String = 'null', props=null, projected='geographic', buffer=null) -> Dictionary:
## [param precision] [int] - Координаты GeoJSON будут усечены до данного
## количества знаков после запятой.
## [return] [Dictionary]
func feature(tile: Tile, fid=null, props=null, projected='geographic', buffer=null):
var west_south_east_north = bounds(tile).as_array() var west_south_east_north = bounds(tile).as_array()
var west = west_south_east_north[0] var west = west_south_east_north[0]
var south = west_south_east_north[1] var south = west_south_east_north[1]
@@ -605,23 +574,22 @@ func feature(tile: Tile, fid=null, props=null, projected='geographic', buffer=nu
if props: if props:
feat['properties'].update(props) feat['properties'].update(props)
if fid != null: if fid != 'null':
feat['id'] = fid feat['id'] = fid
return feat return feat
func isinstance(obj, types: Array): func isinstance(obj, types: Array) -> bool:
for type in types: for type in types:
if is_instance_of(obj, type): if is_instance_of(obj, type):
return true return true
return false return false
## Все кортежи координат из геометрии, объекта или коллекции ## Все кортежи координат из геометрии, объекта или коллекции.[br]
## [param lng] [float] - Долгота ## [param lng] - Долгота.[br]
## [param lat] [float] - широта ## [param lat] - широта.[br]
## [return] [Array]
func _coords(obj) -> Array: func _coords(obj) -> Array:
var coordinates = [] var coordinates = []
if is_instance_of(obj, TYPE_ARRAY): if is_instance_of(obj, TYPE_ARRAY):
@@ -645,7 +613,7 @@ func _coords(obj) -> Array:
return v return v
func func1(bbox: Array, coords: Array): func _func1(bbox: Array, coords: Array) -> Array[float]:
var w = bbox[0] var w = bbox[0]
var s = bbox[1] var s = bbox[1]
var e = bbox[2] var e = bbox[2]
@@ -655,10 +623,9 @@ func func1(bbox: Array, coords: Array):
return [min(w, lng), min(s, lat), max(e, lng), max(n, lat)] return [min(w, lng), min(s, lat), max(e, lng), max(n, lat)]
## Возвращает граничную область объекта GeoJSON. ## Возвращает граничную область объекта GeoJSON.[br]
## [param obj] - Отображение, геометрия GeoJSON, объект или коллекция объектов. ## [param obj] - Отображение, геометрия GeoJSON, объект или коллекция объектов.[br]
## [returns] [LngLatBbox] func geojson_bounds(obj) -> LngLatBbox:
func geojson_bounds(obj):
var coords: Array = _coords(obj) var coords: Array = _coords(obj)
var wsen = coords.reduce(func1, [180.0, 90.0, -180.0, -90.0]) var wsen = coords.reduce(_func1, [180.0, 90.0, -180.0, -90.0])
return LngLatBbox.new(wsen[0], wsen[1], wsen[2], wsen[3]) return LngLatBbox.new(wsen[0], wsen[1], wsen[2], wsen[3])

View File

@@ -1,7 +1,8 @@
shader_type canvas_item; shader_type canvas_item;
/* Закрашенная окружность */ #include "tools.gdshaderinc"
/* Закрашенная окружность */
uniform vec4 color: source_color = vec4(1, 1, 1, 1); uniform vec4 color: source_color = vec4(1, 1, 1, 1);
uniform vec4 color_up: source_color = vec4(1, 1, 1, 1); /* Цвет вспышки при обновлении */ uniform vec4 color_up: source_color = vec4(1, 1, 1, 1); /* Цвет вспышки при обновлении */
uniform uint tick_update = 0; /* Время последнего обновления, мс */ uniform uint tick_update = 0; /* Время последнего обновления, мс */
@@ -11,13 +12,8 @@ const vec2 center = vec2(0.125, 0.125); /* Центр долже
const float radius = 0.125 - ds * 2.0; /* Радиус должен быть 0.5, но это не так */ const float radius = 0.125 - ds * 2.0; /* Радиус должен быть 0.5, но это не так */
float smooth_px(float r, float R)
{
return 1.0 - smoothstep(R - ds, R + ds, r);
}
void fragment() void fragment()
{ {
COLOR = color * smooth_px(length(UV - center), radius); COLOR = color * smooth_px(length(UV - center), radius, ds);
} }

View File

@@ -1,5 +1,7 @@
shader_type canvas_item; shader_type canvas_item;
#include "tools.gdshaderinc"
/* Закрашенный сектор окружности ограниченный угловым сектором и радиусами */ /* Закрашенный сектор окружности ограниченный угловым сектором и радиусами */
uniform vec4 color: source_color = vec4(1, 1, 1, 1); uniform vec4 color: source_color = vec4(1, 1, 1, 1);
@@ -16,12 +18,6 @@ const float dsa = 0.0025; /* Относительное расс
const float dsr = 0.00025; /* Относительное расстояние на котором выполняется сглаживание краёв по круговым линиям */ const float dsr = 0.00025; /* Относительное расстояние на котором выполняется сглаживание краёв по круговым линиям */
float smooth_px(float r, float R, float ds)
{
return 1.0 - smoothstep(R - ds, R + ds, r);
}
vec4 sector(vec4 c, vec2 uv_pos, float r0, float r1, float w) vec4 sector(vec4 c, vec2 uv_pos, float r0, float r1, float w)
{ {
bool rc = false; bool rc = false;
@@ -49,17 +45,9 @@ vec4 sector(vec4 c, vec2 uv_pos, float r0, float r1, float w)
} }
void rotate_vec2(inout vec2 vert, float a)
{
float sin_a = sin(a);
float cos_a = cos(a);
vert *= mat2(vec2(cos_a, sin_a), vec2(-sin_a, cos_a));
}
void vertex() void vertex()
{ {
rotate_vec2(VERTEX, radians(90.0 - dir)); rotate_vec2(VERTEX, radians(90.0 - dir), vec2(0, 0));
} }

View File

@@ -3,6 +3,8 @@
[sub_resource type="Shader" id="1"] [sub_resource type="Shader" id="1"]
code = "shader_type canvas_item; code = "shader_type canvas_item;
#include \"tools.gdshaderinc\"
uniform vec2 pc0; /* Центр сетки антенн */ uniform vec2 pc0; /* Центр сетки антенн */
uniform float rotation: hint_range(0.0, 360.0) = 0.0; /* */ uniform float rotation: hint_range(0.0, 360.0) = 0.0; /* */
uniform vec4 color0: source_color = vec4(0.38, 0.47, 0.51, 0.4); uniform vec4 color0: source_color = vec4(0.38, 0.47, 0.51, 0.4);
@@ -40,12 +42,6 @@ const float d4 = 90.0;
const float ds = 1.0; const float ds = 1.0;
float SMOOTH(float r, float R, float d)
{
return 1.0 - smoothstep(R - d, R + d, r);
}
void sector(inout vec4 c, vec2 uv, vec2 center, float a, float da, float r0, float r1, vec4 color) void sector(inout vec4 c, vec2 uv, vec2 center, float a, float da, float r0, float r1, vec4 color)
{ {
float l = distance(center, uv); float l = distance(center, uv);
@@ -55,8 +51,8 @@ void sector(inout vec4 c, vec2 uv, vec2 center, float a, float da, float r0, flo
da /= 2.0; da /= 2.0;
float a0 = radians(a - da); float a0 = radians(a - da);
float a1 = radians(a + da); float a1 = radians(a + da);
float va = SMOOTH(a0 * sf, theta, ds) - SMOOTH(a1 * sf, theta, ds); float va = smooth_px(a0 * sf, theta, ds) - smooth_px(a1 * sf, theta, ds);
float vr = SMOOTH(r0, l, ds) - SMOOTH(r1, l, ds); float vr = smooth_px(r0, l, ds) - smooth_px(r1, l, ds);
float rgb = sqrt(va * vr); float rgb = sqrt(va * vr);
c.rgb += color.rgb * rgb * color.a; c.rgb += color.rgb * rgb * color.a;
c.a += rgb * color.a; c.a += rgb * color.a;
@@ -75,37 +71,9 @@ void antenas(inout vec4 c, vec2 uv, vec2 p0, int cnt, float r0, float r1, vec4 c
} }
void circle_thin(inout vec3 color, vec2 uv, vec2 p, float r, float w, vec3 c, float a)
{
float d = distance(uv, p);
float v0 = r - w;
float v1 = r + w;
color += a * sqrt(smoothstep(v1, v0, d) * smoothstep(v0, v1, d) * c);
}
void line_r(inout vec4 color, vec2 uv, vec2 center, float theta0, float radius, vec4 c)
{
vec2 d = uv - center;
vec2 p = radius * vec2(cos(theta0 * PI / 180.0), - sin(theta0 * PI / 180.0));
float l = length(d - p * clamp(dot(d, p) / dot(p, p), 0.0, 1.0));
color.rgb += c.rgb * SMOOTH(l, 1.0, ds) * c.a;
}
void rotate_vec2(inout vec2 vert, float a)
{
float sin_a = sin(a);
float cos_a = cos(a);
vert *= mat2(vec2(cos_a, sin_a), vec2(-sin_a, cos_a));
}
void vertex() void vertex()
{ {
VERTEX -= pc0; rotate_vec2(VERTEX, radians(rotation), pc0);
rotate_vec2(VERTEX, radians(rotation));
VERTEX += pc0;
} }

View File

@@ -2,9 +2,10 @@ shader_type canvas_item;
#include "tools.gdshaderinc" #include "tools.gdshaderinc"
uniform vec2 center = vec2(0.5, 0.5); /* Рисует текстуру по маске в форме окружности */
uniform float radius: hint_range(0.0, 1.0) = 0.4; /* Радиус */
uniform float radius: hint_range(0.0, 1.0) = 0.4; /* Радиус */
const vec2 center = vec2(0.5, 0.5);
void fragment() void fragment()
{ {

View File

@@ -1,6 +1,35 @@
const float DS = 0.004; /* Относительное расстояние на котором выполняется сглаживание краёв */ const float DS = 0.004; /* Относительное расстояние на котором выполняется сглаживание краёв */
float smooth_px(float r, float R, float ds) float smooth_px(float r, float R, float ds)
{ {
return 1.0 - smoothstep(R - ds, R + ds, r); return 1.0 - smoothstep(R - ds, R + ds, r);
} }
void circle_thin(inout vec3 color, vec2 uv, vec2 p, float r, float w, vec3 c, float a)
{
float d = distance(uv, p);
float v0 = r - w;
float v1 = r + w;
color += a * sqrt(smoothstep(v1, v0, d) * smoothstep(v0, v1, d) * c);
}
void line_r(inout vec4 color, vec2 uv, vec2 center, float theta0, float radius, vec4 c)
{
vec2 d = uv - center;
vec2 p = radius * vec2(cos(theta0 * PI / 180.0), - sin(theta0 * PI / 180.0));
float l = length(d - p * clamp(dot(d, p) / dot(p, p), 0.0, 1.0));
color.rgb += c.rgb * smooth_px(l, 1.0, DS) * c.a;
}
void rotate_vec2(inout vec2 vert, float a, vec2 pos)
{
vert -= pos;
float sin_a = sin(a);
float cos_a = cos(a);
vert *= mat2(vec2(cos_a, sin_a), vec2(-sin_a, cos_a));
vert += pos;
}