import gws
import gws.types as t
import gws.gis.proj
import gws.gis.zoom
import gws.gis.extent
import gws.common.layer
import gws.common.layer.types
import gws.tools.units as units
# https://wiki.openstreetmap.org/wiki/Zoom_levels
_DEFAULT_RESOLUTIONS = [
units.scale2res(150 * 1e6),
units.scale2res(70 * 1e6),
units.scale2res(35 * 1e6),
units.scale2res(15 * 1e6),
units.scale2res(10 * 1e6),
units.scale2res(4 * 1e6),
units.scale2res(2 * 1e6),
units.scale2res(1 * 1e6),
units.scale2res(500 * 1e3),
units.scale2res(250 * 1e3),
units.scale2res(150 * 1e3),
units.scale2res(70 * 1e3),
units.scale2res(35 * 1e3),
units.scale2res(15 * 1e3),
units.scale2res(8 * 1e3),
units.scale2res(4 * 1e3),
units.scale2res(2 * 1e3),
units.scale2res(1 * 1e3),
units.scale2res(500),
]
[docs]class Config(t.Config):
"""Map configuration"""
center: t.Optional[t.Point] #: map center
coordinatePrecision: t.Optional[int] #: precision for coordinates
crs: t.Optional[t.Crs] = 'EPSG:3857' #: crs for this map
extent: t.Optional[t.Extent] #: map extent
extentBuffer: t.Optional[int] #: extent buffer
layers: t.List[t.ext.layer.Config] #: collection of layers for this map
title: str = '' #: map title
skipInvalidLayers: bool = False #: remove invalid layers from the map
uid: t.Optional[str] #: unique id
zoom: t.Optional[gws.gis.zoom.Config] #: map scales and resolutions
[docs]class Props(t.Data):
crs: str
crsDef: t.Optional[str]
coordinatePrecision: int
extent: t.Extent
center: t.Point
initResolution: float
layers: t.List[gws.common.layer.types.LayerProps]
resolutions: t.List[float]
title: str = ''
#:export IMap
[docs]class Object(gws.Object, t.IMap):
@property
def bounds(self) -> t.Bounds:
return t.Bounds(crs=self.crs, extent=self.extent)
@property
def props(self):
proj = gws.gis.proj.as_proj(self.crs)
return Props({
'crs': proj.epsg,
'crsDef': proj.proj4text,
'coordinatePrecision': self.coordinate_precision,
'extent': self.extent,
'center': self.center,
'initResolution': self.init_resolution,
'layers': self.layers,
'resolutions': self.resolutions,
'title': self.var('titie'),
})
def _configure_extent(obj, target_crs, default_ext):
layers = gws.get(obj, 'layers') or []
# we have an explicit extent provided in the config
config_ext = obj.var('extent')
if config_ext:
if not gws.gis.extent.valid(config_ext):
raise gws.Error(f'{obj.uid!r}: invalid extent {config_ext!r}')
# configure sublayers using config_ext as a default
for la in layers:
_configure_extent(la, target_crs, config_ext)
obj.extent = config_ext
return obj.extent
if layers:
# no config extent, configure sublayers using the current default extent
# set obj.extent to the sum of sublayers' extents
layer_ext_list = []
for la in layers:
layer_ext = _configure_extent(la, target_crs, default_ext)
if layer_ext:
layer_ext_list.append(layer_ext)
if layer_ext_list:
obj.extent = gws.gis.extent.merge(layer_ext_list)
else:
obj.extent = default_ext
return obj.extent
# obj is a leaf layer and has no configured extent
# check if it has an own extent (from its source)
own_bounds: t.Bounds = gws.get(obj, 'own_bounds')
if own_bounds:
own_ext = own_bounds.extent
buf = obj.var('extentBuffer', parent=True)
if buf:
own_ext = gws.gis.extent.buffer(own_ext, buf)
own_ext = gws.gis.extent.transform(own_ext, own_bounds.crs, target_crs)
obj.extent = own_ext
return obj.extent
# obj is a leaf layer and has neither configured nor own extent
# try using the default extent
if default_ext:
obj.extent = default_ext
return obj.extent
# no extent can be computed, it will be set to the map extent later on
return None
def _set_default_extent(obj, extent):
if not gws.get(obj, 'extent'):
obj.extent = extent
for la in gws.get(obj, 'layers', []):
_set_default_extent(la, extent)