wms_base.py 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715
  1. """!
  2. @brief Preparation of parameters for drivers, which download it, and managing downloaded data.
  3. List of classes:
  4. - wms_base::WMSBase
  5. - wms_base::GRASSImporter
  6. - wms_base::WMSDriversInfo
  7. (C) 2012-2019 by the GRASS Development Team
  8. This program is free software under the GNU General Public License
  9. (>=v2). Read the file COPYING that comes with GRASS for details.
  10. @author Stepan Turek <stepan.turek seznam.cz> (Mentor: Martin Landa)
  11. """
  12. import os
  13. from math import ceil
  14. import base64
  15. try:
  16. from urllib2 import Request, urlopen, HTTPError
  17. from httplib import HTTPException
  18. except ImportError:
  19. from urllib.request import Request, urlopen
  20. from urllib.error import HTTPError
  21. from http.client import HTTPException
  22. import grass.script as grass
  23. from grass.exceptions import CalledModuleError
  24. class WMSBase(object):
  25. def __init__(self):
  26. # these variables are information for destructor
  27. self.temp_files_to_cleanup = []
  28. self.params = {}
  29. self.tile_size = {'bbox': None}
  30. self.temp_map = None
  31. self.temp_warpmap = None
  32. def __del__(self):
  33. # tries to remove temporary files, all files should be
  34. # removed before, implemented just in case of unexpected
  35. # stop of module
  36. for temp_file in self.temp_files_to_cleanup:
  37. grass.try_remove(temp_file)
  38. def _debug(self, fn, msg):
  39. grass.debug("%s.%s: %s" %
  40. (self.__class__.__name__, fn, msg))
  41. def _initializeParameters(self, options, flags):
  42. self._debug("_initialize_parameters", "started")
  43. # initialization of module parameters (options, flags)
  44. self.params['driver'] = options['driver']
  45. drv_info = WMSDriversInfo()
  46. driver_props = drv_info.GetDrvProperties(options['driver'])
  47. self._checkIgnoeredParams(options, flags, driver_props)
  48. self.params['capfile'] = options['capfile'].strip()
  49. for key in ['url', 'layers', 'styles', 'method']:
  50. self.params[key] = options[key].strip()
  51. self.flags = flags
  52. if self.flags['o']:
  53. self.params['transparent'] = 'FALSE'
  54. else:
  55. self.params['transparent'] = 'TRUE'
  56. for key in ['password', 'username', 'urlparams']:
  57. self.params[key] = options[key]
  58. if (self.params ['password'] and self.params ['username'] == '') or \
  59. (self.params['password'] == '' and self.params['username']):
  60. grass.fatal(_("Please insert both %s and %s parameters or none of them." %
  61. ('password', 'username')))
  62. self.params['bgcolor'] = options['bgcolor'].strip()
  63. if options['format'] == "jpeg" and \
  64. not 'format' in driver_props['ignored_params']:
  65. if not flags['o'] and \
  66. 'WMS' in self.params['driver']:
  67. grass.warning(_("JPEG format does not support transparency"))
  68. self.params['format'] = drv_info.GetFormat(options['format'])
  69. if not self.params['format']:
  70. self.params['format'] = self.params['format']
  71. # TODO: get srs from Tile Service file in OnEarth_GRASS driver
  72. self.params['srs'] = int(options['srs'])
  73. if self.params['srs'] <= 0 and not 'srs' in driver_props['ignored_params']:
  74. grass.fatal(_("Invalid EPSG code %d") % self.params['srs'])
  75. self.params['wms_version'] = options['wms_version']
  76. if "CRS" in GetSRSParamVal(self.params['srs']) and self.params['wms_version'] == "1.1.1":
  77. self.params['wms_version'] = "1.3.0"
  78. grass.warning(
  79. _("WMS version <1.3.0> will be used, because version <1.1.1> does not support <%s>projection") %
  80. GetSRSParamVal(
  81. self.params['srs']))
  82. if self.params['wms_version'] == "1.3.0":
  83. self.params['proj_name'] = "CRS"
  84. else:
  85. self.params['proj_name'] = "SRS"
  86. # read projection info
  87. self.proj_location = grass.read_command('g.proj',
  88. flags='jf').rstrip('\n')
  89. self.proj_location = self._modifyProj(self.proj_location)
  90. self.source_epsg = str(GetEpsg(self.params['srs']))
  91. self.target_epsg = None
  92. target_crs = grass.parse_command('g.proj', flags='g', delimiter = '=')
  93. if 'epsg' in target_crs.keys():
  94. self.target_epsg = target_crs['epsg']
  95. if self.source_epsg != self.target_epsg:
  96. grass.warning(_("SRS differences: WMS source EPSG %s != location EPSG %s (use srs=%s to adjust)") %
  97. (self.source_epsg, self.target_epsg, self.target_epsg))
  98. self.proj_srs = grass.read_command('g.proj',
  99. flags='jf',
  100. epsg=str(GetEpsg(self.params['srs'])))
  101. self.proj_srs = self.proj_srs.rstrip('\n')
  102. self.proj_srs = self._modifyProj(self.proj_srs)
  103. if not self.proj_srs or not self.proj_location:
  104. grass.fatal(_("Unable to get projection info"))
  105. self.region = options['region']
  106. min_tile_size = 100
  107. maxcols = int(options['maxcols'])
  108. if maxcols <= min_tile_size:
  109. grass.fatal(_("Maxcols must be greater than 100"))
  110. maxrows = int(options['maxrows'])
  111. if maxrows <= min_tile_size:
  112. grass.fatal(_("Maxrows must be greater than 100"))
  113. # setting optimal tile size according to maxcols and maxrows constraint
  114. # and region cols and rows
  115. self.tile_size['cols'] = int(
  116. self.region['cols'] /
  117. ceil(
  118. self.region['cols'] /
  119. float(maxcols)))
  120. self.tile_size['rows'] = int(
  121. self.region['rows'] /
  122. ceil(
  123. self.region['rows'] /
  124. float(maxrows)))
  125. # default format for GDAL library
  126. self.gdal_drv_format = "GTiff"
  127. self._debug("_initialize_parameters", "finished")
  128. def _modifyProj(self, proj):
  129. """!Modify proj.4 string for usage in this module"""
  130. # add +wktext parameter to avoid droping of +nadgrids parameter (if presented) in gdalwarp
  131. if '+nadgrids=' in proj and ' +wktext' not in proj:
  132. proj += ' +wktext'
  133. return proj
  134. def _checkIgnoeredParams(self, options, flags, driver_props):
  135. """!Write warnings for set parameters and flags, which chosen driver does not use."""
  136. not_relevant_params = []
  137. for i_param in driver_props['ignored_params']:
  138. if i_param in options and \
  139. options[i_param] and \
  140. i_param not in ['srs', 'wms_version', 'format']: # params with default value
  141. not_relevant_params.append('<' + i_param + '>')
  142. if len(not_relevant_params) > 0:
  143. grass.warning(_("These parameter are ignored: %s\n\
  144. %s driver does not support the parameters." %
  145. (','.join(not_relevant_params), options['driver'])))
  146. not_relevant_flags = []
  147. for i_flag in driver_props['ignored_flags']:
  148. if flags[i_flag]:
  149. not_relevant_flags.append('<' + i_flag + '>')
  150. if len(not_relevant_flags) > 0:
  151. grass.warning(_("These flags are ignored: %s\n\
  152. %s driver does not support the flags." %
  153. (','.join(not_relevant_flags), options['driver'])))
  154. def GetMap(self, options, flags):
  155. """!Download data from WMS server."""
  156. self._initializeParameters(options, flags)
  157. self.bbox = self._computeBbox()
  158. self.temp_map = self._download()
  159. if not self.temp_map:
  160. return
  161. self._reprojectMap()
  162. return self.temp_warpmap
  163. def _fetchCapabilities(self, options):
  164. """!Download capabilities from WMS server
  165. """
  166. cap_url = options['url'].strip()
  167. if "?" in cap_url:
  168. cap_url += "&"
  169. else:
  170. cap_url += "?"
  171. if 'WMTS' in options['driver']:
  172. cap_url += "SERVICE=WMTS&REQUEST=GetCapabilities&VERSION=1.0.0"
  173. elif 'OnEarth' in options['driver']:
  174. cap_url += "REQUEST=GetTileService"
  175. else:
  176. cap_url += "SERVICE=WMS&REQUEST=GetCapabilities&VERSION=" + options['wms_version']
  177. if options['urlparams']:
  178. cap_url += "&" + options['urlparams']
  179. grass.debug('Fetching capabilities file.\n%s' % cap_url)
  180. try:
  181. cap = self._fetchDataFromServer(cap_url, options['username'], options['password'])
  182. except (IOError, HTTPException) as e:
  183. if isinstance(e, HTTPError) and e.code == 401:
  184. grass.fatal(
  185. _("Authorization failed to <%s> when fetching capabilities") %
  186. options['url'])
  187. else:
  188. msg = _("Unable to fetch capabilities from <{0}>. Reason: ").format(
  189. options['url'])
  190. if hasattr(e, 'reason'):
  191. msg += '{0}'.format(e.reason)
  192. else:
  193. msg += '{0}'.format(e)
  194. grass.fatal(msg)
  195. grass.debug('Fetching capabilities OK')
  196. return grass.decode(cap)
  197. def _fetchDataFromServer(self, url, username=None, password=None):
  198. """!Fetch data from server
  199. """
  200. request = Request(url)
  201. if username and password:
  202. base64string = base64.encodestring('%s:%s' % (username, password)).replace('\n', '')
  203. request.add_header("Authorization", "Basic %s" % base64string)
  204. try:
  205. return urlopen(request)
  206. except ValueError as error:
  207. grass.fatal("%s" % error)
  208. def GetCapabilities(self, options):
  209. """!Get capabilities from WMS server
  210. """
  211. cap = self._fetchCapabilities(options)
  212. capfile_output = options['capfile_output'].strip()
  213. # save to file
  214. if capfile_output:
  215. try:
  216. with open(capfile_output, "w") as temp:
  217. temp.write(cap.read())
  218. return
  219. except IOError as error:
  220. grass.fatal(_("Unabble to open file '%s'.\n%s\n" % (cap_file, error)))
  221. # print to output
  222. cap_lines = cap.readlines()
  223. for line in cap_lines:
  224. print(line.rstrip())
  225. def _computeBbox(self):
  226. """!Get region extent for WMS query (bbox)
  227. """
  228. self._debug("_computeBbox", "started")
  229. bbox_region_items = {'maxy': 'n', 'miny': 's', 'maxx': 'e', 'minx': 'w'}
  230. bbox = {}
  231. if self.proj_srs == self.proj_location: # TODO: do it better
  232. for bbox_item, region_item in bbox_region_items.items():
  233. bbox[bbox_item] = self.region[region_item]
  234. # if location projection and wms query projection are
  235. # different, corner points of region are transformed into wms
  236. # projection and then bbox is created from extreme coordinates
  237. # of the transformed points
  238. else:
  239. for bbox_item, region_item in bbox_region_items.items():
  240. bbox[bbox_item] = None
  241. temp_region = self._tempfile()
  242. try:
  243. temp_region_opened = open(temp_region, 'w')
  244. temp_region_opened.write("%f %f\n%f %f\n%f %f\n%f %f\n" %
  245. (self.region['e'], self.region['n'],
  246. self.region['w'], self.region['n'],
  247. self.region['w'], self.region['s'],
  248. self.region['e'], self.region['s']))
  249. except IOError:
  250. grass.fatal(_("Unable to write data into tempfile"))
  251. finally:
  252. temp_region_opened.close()
  253. points = grass.read_command('m.proj', flags='d',
  254. proj_out=self.proj_srs,
  255. proj_in=self.proj_location,
  256. input=temp_region,
  257. quiet=True) # TODO: stdin
  258. grass.try_remove(temp_region)
  259. if not points:
  260. grass.fatal(_("Unable to determine region, %s failed") % 'm.proj')
  261. points = points.splitlines()
  262. if len(points) != 4:
  263. grass.fatal(_("Region definition: 4 points required"))
  264. for point in points:
  265. try:
  266. point = list(map(float, point.split("|")))
  267. except ValueError:
  268. grass.fatal(_('Reprojection of region using m.proj failed.'))
  269. if not bbox['maxy']:
  270. bbox['maxy'] = point[1]
  271. bbox['miny'] = point[1]
  272. bbox['maxx'] = point[0]
  273. bbox['minx'] = point[0]
  274. continue
  275. if bbox['maxy'] < point[1]:
  276. bbox['maxy'] = point[1]
  277. elif bbox['miny'] > point[1]:
  278. bbox['miny'] = point[1]
  279. if bbox['maxx'] < point[0]:
  280. bbox['maxx'] = point[0]
  281. elif bbox['minx'] > point[0]:
  282. bbox['minx'] = point[0]
  283. self._debug("_computeBbox", "finished -> %s" % bbox)
  284. # Ordering of coordinates axis of geographic coordinate
  285. # systems in WMS 1.3.0 is flipped. If self.tile_size['flip_coords'] is
  286. # True, coords in bbox need to be flipped in WMS query.
  287. return bbox
  288. def _reprojectMap(self):
  289. """!Reproject data using gdalwarp if needed
  290. """
  291. # reprojection of raster
  292. do_reproject = True
  293. if self.source_epsg is not None and self.target_epsg is not None \
  294. and self.source_epsg == self.target_epsg:
  295. do_reproject = False
  296. # TODO: correctly compare source and target crs
  297. if do_reproject == True and self.proj_srs == self.proj_location:
  298. do_reproject = False
  299. if do_reproject:
  300. grass.message(_("Reprojecting raster..."))
  301. self.temp_warpmap = grass.tempfile() + '.tif'
  302. if int(os.getenv('GRASS_VERBOSE', '2')) <= 2:
  303. nuldev = open(os.devnull, 'w+')
  304. else:
  305. nuldev = None
  306. if self.params['method'] == "nearest":
  307. gdal_method = "near"
  308. elif self.params['method'] == "linear":
  309. gdal_method = "bilinear"
  310. else:
  311. gdal_method = self.params['method']
  312. # RGB rasters - alpha layer is added for cropping edges of projected raster
  313. try:
  314. if self.temp_map_bands_num == 3:
  315. ps = grass.Popen(['gdalwarp',
  316. '-s_srs', '%s' % self.proj_srs,
  317. '-t_srs', '%s' % self.proj_location,
  318. '-r', gdal_method, '-dstalpha',
  319. self.temp_map, self.temp_warpmap], stdout=nuldev)
  320. # RGBA rasters
  321. else:
  322. ps = grass.Popen(['gdalwarp',
  323. '-s_srs', '%s' % self.proj_srs,
  324. '-t_srs', '%s' % self.proj_location,
  325. '-r', gdal_method,
  326. self.temp_map, self.temp_warpmap], stdout=nuldev)
  327. ps.wait()
  328. except OSError as e:
  329. grass.fatal('%s \nThis can be caused by missing %s utility. ' % (e, 'gdalwarp'))
  330. if nuldev:
  331. nuldev.close()
  332. if ps.returncode != 0:
  333. grass.fatal(_('%s failed') % 'gdalwarp')
  334. grass.try_remove(self.temp_map)
  335. # raster projection is same as projection of location
  336. else:
  337. self.temp_warpmap = self.temp_map
  338. self.temp_files_to_cleanup.remove(self.temp_map)
  339. return self.temp_warpmap
  340. def _tempfile(self):
  341. """!Create temp_file and append list self.temp_files_to_cleanup
  342. with path of file
  343. @return string path to temp_file
  344. """
  345. temp_file = grass.tempfile()
  346. if temp_file is None:
  347. grass.fatal(_("Unable to create temporary files"))
  348. # list of created tempfiles for destructor
  349. self.temp_files_to_cleanup.append(temp_file)
  350. return temp_file
  351. class GRASSImporter:
  352. def __init__(self, opt_output, cleanup_bands):
  353. self.cleanup_mask = False
  354. self.cleanup_bands = cleanup_bands
  355. # output map name
  356. self.opt_output = opt_output
  357. # suffix for existing mask (during overriding will be saved
  358. # into raster named:self.opt_output + this suffix)
  359. self.original_mask_suffix = "_temp_MASK"
  360. # check names of temporary rasters, which module may create
  361. maps = []
  362. for suffix in ('.red', '.green', '.blue', '.alpha', self.original_mask_suffix):
  363. rast = self.opt_output + suffix
  364. if grass.find_file(rast, element='cell', mapset='.')['file']:
  365. maps.append(rast)
  366. if len(maps) != 0:
  367. grass.fatal(_("Please change output name, or change names of these rasters: %s, "
  368. "module needs to create this temporary maps during execution.") % ",".join(maps))
  369. def __del__(self):
  370. # removes temporary mask, used for import transparent or warped temp_map
  371. if self.cleanup_mask:
  372. # clear temporary mask, which was set by module
  373. try:
  374. grass.run_command('r.mask', quiet=True, flags='r')
  375. except CalledModuleError:
  376. grass.fatal(_('%s failed') % 'r.mask')
  377. # restore original mask, if exists
  378. if grass.find_file(self.opt_output + self.original_mask_suffix,
  379. element='cell', mapset='.')['name']:
  380. try:
  381. mask_copy = self.opt_output + self.original_mask_suffix
  382. grass.run_command('g.copy', quiet=True,
  383. raster=mask_copy + ',MASK')
  384. except CalledModuleError:
  385. grass.fatal(_('%s failed') % 'g.copy')
  386. # remove temporary created rasters
  387. maps = []
  388. rast = self.opt_output + '.alpha'
  389. if grass.find_file(rast, element='cell', mapset='.')['file']:
  390. maps.append(rast)
  391. if self.cleanup_bands:
  392. for suffix in ('.red', '.green', '.blue', self.original_mask_suffix):
  393. rast = self.opt_output + suffix
  394. if grass.find_file(rast, element='cell', mapset='.')['file']:
  395. maps.append(rast)
  396. if maps:
  397. grass.run_command('g.remove',
  398. quiet=True,
  399. flags='fb',
  400. type='raster',
  401. name=','.join(maps))
  402. # delete environmental variable which overrides region
  403. if 'GRASS_REGION' in os.environ.keys():
  404. os.environ.pop('GRASS_REGION')
  405. maplist = grass.read_command('g.list', type = 'raster',
  406. pattern = '%s*' % (self.opt_output),
  407. mapset = '.', separator = ',').rstrip('\n')
  408. if len(maplist) == 0:
  409. grass.fatal(_('WMS import failed, nothing imported'))
  410. else:
  411. for raster in maplist.split(','):
  412. grass.raster_history(raster, overwrite = True)
  413. grass.run_command('r.support', map=raster, description='generated by r.in.wms')
  414. grass.message(_('<%s> created.') % raster)
  415. def ImportMapIntoGRASS(self, raster):
  416. """!Import raster into GRASS.
  417. """
  418. # importing temp_map into GRASS
  419. try:
  420. # do not use -o flag !
  421. grass.run_command('r.in.gdal', flags='o',
  422. quiet=True, overwrite=True,
  423. input=raster, output=self.opt_output)
  424. except CalledModuleError:
  425. grass.fatal(_('%s failed') % 'r.in.gdal')
  426. # information for destructor to cleanup temp_layers, created
  427. # with r.in.gdal
  428. # setting region for full extend of imported raster
  429. if grass.find_file(self.opt_output + '.red', element='cell', mapset='.')['file']:
  430. region_map = self.opt_output + '.red'
  431. else:
  432. region_map = self.opt_output
  433. os.environ['GRASS_REGION'] = grass.region_env(rast=region_map)
  434. # mask created from alpha layer, which describes real extend
  435. # of warped layer (may not be a rectangle), also mask contains
  436. # transparent parts of raster
  437. if grass.find_file(self.opt_output + '.alpha', element='cell', mapset='.')['name']:
  438. # saving current mask (if exists) into temp raster
  439. if grass.find_file('MASK', element='cell', mapset='.')['name']:
  440. try:
  441. mask_copy = self.opt_output + self.original_mask_suffix
  442. grass.run_command('g.copy', quiet=True,
  443. raster='MASK,' + mask_copy)
  444. except CalledModuleError:
  445. grass.fatal(_('%s failed') % 'g.copy')
  446. # info for destructor
  447. self.cleanup_mask = True
  448. try:
  449. grass.run_command('r.mask',
  450. quiet=True, overwrite=True,
  451. maskcats="0",
  452. flags='i',
  453. raster=self.opt_output + '.alpha')
  454. except CalledModuleError:
  455. grass.fatal(_('%s failed') % 'r.mask')
  456. if not self.cleanup_bands:
  457. # use the MASK to set NULL vlues
  458. for suffix in ('.red', '.green', '.blue'):
  459. rast = self.opt_output + suffix
  460. if grass.find_file(rast, element='cell', mapset='.')['file']:
  461. grass.run_command('g.rename', rast='%s,%s' % (rast, rast + '_null'), quiet = True)
  462. grass.run_command('r.mapcalc', expression = '%s = %s' % (rast, rast + '_null'), quiet = True)
  463. grass.run_command('g.remove', type='raster', name='%s' % (rast + '_null'), flags = 'f', quiet = True)
  464. # TODO one band + alpha band?
  465. if grass.find_file(self.opt_output + '.red', element='cell', mapset='.')['file'] and self.cleanup_bands:
  466. try:
  467. grass.run_command('r.composite',
  468. quiet=True, overwrite=True,
  469. red=self.opt_output + '.red',
  470. green=self.opt_output + '.green',
  471. blue=self.opt_output + '.blue',
  472. output=self.opt_output)
  473. except CalledModuleError:
  474. grass.fatal(_('%s failed') % 'r.composite')
  475. class WMSDriversInfo:
  476. def __init__(self):
  477. """!Provides information about driver parameters.
  478. """
  479. # format labels
  480. self.f_labels = ["geotiff", "tiff", "png", "jpeg", "gif", "png8"]
  481. # form for request
  482. self.formats = [
  483. "image/geotiff",
  484. "image/tiff",
  485. "image/png",
  486. "image/jpeg",
  487. "image/gif",
  488. "image/png8"]
  489. self.srs = ("epsg", "crs")
  490. def GetDrvProperties(self, driver):
  491. """!Get information about driver parameters.
  492. """
  493. if driver == 'WMS_GDAL':
  494. return self._GDALDrvProperties()
  495. if 'WMS' in driver:
  496. return self._WMSProperties()
  497. if 'WMTS' in driver:
  498. return self._WMTSProperties()
  499. if 'OnEarth' in driver:
  500. return self._OnEarthProperties()
  501. def _OnEarthProperties(self):
  502. props = {}
  503. props['ignored_flags'] = ['o']
  504. props['ignored_params'] = ['bgcolor', 'styles', 'capfile_output',
  505. 'format', 'srs', 'wms_version']
  506. props['req_multiple_layers'] = False
  507. return props
  508. def _WMSProperties(self):
  509. props = {}
  510. props['ignored_params'] = ['capfile']
  511. props['ignored_flags'] = []
  512. props['req_multiple_layers'] = True
  513. return props
  514. def _WMTSProperties(self):
  515. props = {}
  516. props['ignored_flags'] = ['o']
  517. props['ignored_params'] = ['urlparams', 'bgcolor', 'wms_version']
  518. props['req_multiple_layers'] = False
  519. return props
  520. def _GDALDrvProperties(self):
  521. props = {}
  522. props['ignored_flags'] = []
  523. props['ignored_params'] = ['urlparams', 'bgcolor', 'capfile', 'capfile_output',
  524. 'username', 'password']
  525. props['req_multiple_layers'] = True
  526. return props
  527. def GetFormatLabel(self, format):
  528. """!Convert format request form to value in parameter 'format'.
  529. """
  530. if format in self.formats:
  531. return self.f_labels[self.formats.index(format)]
  532. return None
  533. def GetFormat(self, label):
  534. """!Convert value in parameter 'format' to format request form.
  535. """
  536. if label in self.f_labels:
  537. return self.formats[self.f_labels.index(label)]
  538. return None
  539. def GetSrs(self):
  540. """!Get supported srs prefixes (e.g. epsg/crs)
  541. @todo filter according to version and driver params
  542. """
  543. return self.srs
  544. # TODO move to utils?
  545. def GetSRSParamVal(srs):
  546. """!Decides whether to use CRS or EPSG prefix according to srs number.
  547. """
  548. if srs in [84, 83, 27]:
  549. return "CRS:%d" % srs
  550. else:
  551. return "EPSG:%d" % srs
  552. def GetEpsg(srs):
  553. """
  554. @return EPSG number
  555. If srs is CRS number, return EPSG number which corresponds to CRS number.
  556. """
  557. if srs == 84:
  558. return 4326
  559. if srs == 83:
  560. return 4269
  561. if srs == 27:
  562. return 4267
  563. return srs