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