1 |
# Copyright (C) 2003, 2004 by Intevation GmbH |
# Copyright (C) 2003, 2004 by Intevation GmbH |
2 |
# Authors: |
# Authors: |
3 |
# Jan-Oliver Wagner <[email protected]> |
# Jan-Oliver Wagner <[email protected]> (2003, 2004) |
4 |
|
# Bernhard Herzog <[email protected]> (2004) |
5 |
|
# Martin Schulze <[email protected]> (2004) |
6 |
# |
# |
7 |
# This program is free software under the GPL (>=v2) |
# This program is free software under the GPL (>=v2) |
8 |
# Read the file COPYING coming with Thuban for details. |
# Read the file COPYING coming with Thuban for details. |
15 |
layer into Thuban via an extension. |
layer into Thuban via an extension. |
16 |
Some things are not wired, so be prepared for Exceptions |
Some things are not wired, so be prepared for Exceptions |
17 |
everywhere. |
everywhere. |
|
|
|
|
You will need PyOGCLib 0.1.0, see |
|
|
http://pyogclib.sourceforge.net/ |
|
|
Set the PYTHONPATH to the PyOGCLib directory before |
|
|
starting Thuban. |
|
18 |
""" |
""" |
19 |
|
|
20 |
__version__ = "$Revision$" |
__version__ = "$Revision$" |
21 |
|
# $Source$ |
22 |
|
# $Id$ |
23 |
|
|
24 |
import os, sys |
import os, sys |
25 |
import xml.dom.minidom |
import xml.dom.minidom |
27 |
|
|
28 |
from wxPython.wx import * |
from wxPython.wx import * |
29 |
|
|
|
from ogclib.WMSClient import WMSClient |
|
|
|
|
|
from Thuban.Model.layer import BaseLayer |
|
30 |
from Thuban.Model.proj import Projection |
from Thuban.Model.proj import Projection |
31 |
from Thuban.Model.extension import Extension |
from Thuban.Model.extension import Extension |
|
from Thuban.Model.resource import get_system_proj_file, EPSG_PROJ_FILE, \ |
|
|
EPSG_DEPRECATED_PROJ_FILE |
|
32 |
from Thuban.UI.command import registry, Command |
from Thuban.UI.command import registry, Command |
33 |
import Thuban.UI.mainwindow |
from Thuban.UI.mainwindow import main_menu, layer_properties_dialogs |
34 |
from Thuban import _ |
from Thuban import _ |
35 |
import Thuban.UI.baserenderer |
import Thuban.UI.baserenderer |
36 |
|
|
37 |
|
from layer import WMSLayer |
38 |
|
|
|
def epsg_code_to_projection(epsg): |
|
|
"""Find the projection for the given epsg code. |
|
|
|
|
|
epsg -- EPSG code as string |
|
|
""" |
|
|
proj_file, warnings = get_system_proj_file(EPSG_PROJ_FILE) |
|
|
|
|
|
for proj in proj_file.GetProjections(): |
|
|
if proj.EPSGCode() == epsg: |
|
|
return proj |
|
|
proj_file, warnings = get_system_proj_file(EPSG_DEPRECATED_PROJ_FILE) |
|
|
for proj in proj_file.GetProjections(): |
|
|
if proj.EPSGCode() == epsg: |
|
|
return proj |
|
|
return None |
|
39 |
|
|
40 |
class WMSExtension(Extension): |
class WMSExtension(Extension): |
41 |
def TreeInfo(self): |
def TreeInfo(self): |
42 |
return (_("Extension: %s") % self.title, |
return (_("Extension: %s") % self.title, |
43 |
[ object.TreeInfo() for object in self.objects ]) |
[ object.TreeInfo() for object in self.objects ]) |
44 |
|
|
|
class WMSLayer(BaseLayer, WMSClient): |
|
|
|
|
|
def __init__(self, title, url): |
|
|
"""Initializes the WMSLayer. |
|
|
|
|
|
title -- Title of this layer. |
|
|
url -- URL of the WMS-Server wich must contain '?' |
|
|
|
|
|
If an error occured, self.error_msg is a string describing |
|
|
the problem(s). Else, self.error_msg is None. |
|
|
""" |
|
|
BaseLayer.__init__(self, title, visible = True, projection = None) |
|
|
self.url = url |
|
|
self.bbox = None |
|
|
self.latlonbbox = None |
|
|
self.error_msg = None |
|
|
self.layer_name = None |
|
|
|
|
|
wms_response = self.getCapabilities(self.url, '1.0') |
|
|
self._capa_dom = xml.dom.minidom.parseString(wms_response) |
|
|
|
|
|
root = self._capa_dom.documentElement |
|
|
cap = root.getElementsByTagName('Capability')[0] |
|
|
layer = cap.getElementsByTagName('Layer')[0] |
|
|
|
|
|
# get projected bounding box and latlon bounding box |
|
|
for node in layer.childNodes: |
|
|
if node.nodeName == 'BoundingBox': |
|
|
minx = node.attributes.get('minx').nodeValue |
|
|
miny = node.attributes.get('miny').nodeValue |
|
|
maxx = node.attributes.get('maxx').nodeValue |
|
|
maxy = node.attributes.get('maxy').nodeValue |
|
|
self.bbox = (float(minx), float(miny), float(maxx), float(maxy)) |
|
|
bbox = layer.getElementsByTagName('LatLonBoundingBox')[0] |
|
|
self.layer_name = layer.getElementsByTagName('Name')[0].childNodes[0].data |
|
|
minx = bbox.attributes.get('minx').nodeValue |
|
|
miny = bbox.attributes.get('miny').nodeValue |
|
|
maxx = bbox.attributes.get('maxx').nodeValue |
|
|
maxy = bbox.attributes.get('maxy').nodeValue |
|
|
self.latlonbbox = (float(minx), float(miny), float(maxx), float(maxy)) |
|
|
|
|
|
# get projection |
|
|
srs = layer.getElementsByTagName('SRS')[0].childNodes[0].data |
|
|
if len(srs.split(':')) == 1: |
|
|
epsg_id = srs |
|
|
else: |
|
|
epsg_id = srs.split(':')[1] |
|
|
|
|
|
p = epsg_code_to_projection(epsg_id) |
|
|
self.SetProjection(p) |
|
|
|
|
|
if p is None: |
|
|
self.error_msg = _('EPSG projection code %s not found!\n'\ |
|
|
'Setting projection to "None".\n'\ |
|
|
'Please set an appropriate projection yourself.'\ |
|
|
% epsg_id) |
|
|
|
|
|
# get title |
|
|
title = layer.getElementsByTagName('Title')[0].childNodes[0].data |
|
|
self.SetTitle(title.encode('latin1', 'replace')) |
|
|
|
|
|
self._capa_dom.unlink() |
|
|
|
|
|
def LatLongBoundingBox(self): |
|
|
"""Return the layer's bounding box in lat-lon. |
|
|
""" |
|
|
return self.latlonbbox |
|
|
|
|
|
def BoundingBox(self): |
|
|
"""Return the layer's bounding box in the intrinsic coordinate system. |
|
|
""" |
|
|
return self.bbox |
|
|
|
|
|
def GetMapImg(self, width, height, bbox): |
|
|
bbox_dict = { 'minx': bbox[0], 'miny': bbox[1], |
|
|
'maxx': bbox[2], 'maxy': bbox[3] } |
|
|
epsg_id = int(self.GetProjection().EPSGCode()) |
|
|
wms_response = self.getMap(self.url, 'JPEG', width, height, |
|
|
epsg_id, bbox_dict, |
|
|
[self.layer_name], version = '1.0') |
|
|
return wms_response |
|
|
|
|
|
|
|
45 |
|
|
46 |
def render_wms_layer(renderer, layer): |
def render_wms_layer(renderer, layer): |
47 |
offx, offy = renderer.offset |
offx, offy = renderer.offset |
53 |
xmax = (width - offx) / scale |
xmax = (width - offx) / scale |
54 |
ymax = (offy - 0) / scale |
ymax = (offy - 0) / scale |
55 |
|
|
56 |
img = layer.GetMapImg(width, height, (xmin, ymin, xmax, ymax)) |
img, format = layer.GetMapImg(width, height, (xmin, ymin, xmax, ymax)) |
57 |
renderer.draw_raster_data(img, "JPEG") |
renderer.draw_raster_data(img, format) |
58 |
|
|
59 |
return () |
return () |
60 |
|
|
61 |
Thuban.UI.baserenderer.add_renderer_extension(WMSLayer, render_wms_layer) |
Thuban.UI.baserenderer.add_renderer_extension(WMSLayer, render_wms_layer) |
62 |
|
from properties import wmsProperties |
63 |
|
layer_properties_dialogs.add(WMSLayer, wmsProperties) |
64 |
|
|
65 |
|
|
66 |
class SelectWMSServer(wxDialog): |
class SelectWMSServer(wxDialog): |
118 |
|
|
119 |
if dialog.ShowModal() == wxID_OK: |
if dialog.ShowModal() == wxID_OK: |
120 |
url = dialog.url |
url = dialog.url |
121 |
|
if len(url) == 0: |
122 |
|
url = None |
123 |
else: |
else: |
124 |
url = None |
url = None |
125 |
dialog.Destroy() |
dialog.Destroy() |
149 |
helptext = _('Add a WMS Layer'))) |
helptext = _('Add a WMS Layer'))) |
150 |
|
|
151 |
# find the experimental menu (create it anew if not found) |
# find the experimental menu (create it anew if not found) |
152 |
main_menu = Thuban.UI.mainwindow.main_menu |
experimental_menu = main_menu.FindOrInsertMenu('experimental', |
153 |
experimental_menu = main_menu.find_menu('experimental') |
_('Experimenta&l')) |
|
if experimental_menu is None: |
|
|
experimental_menu = main_menu.InsertMenu('experimental', _('Experimenta&l')) |
|
154 |
|
|
155 |
# finally add the new entry to the experimental menu |
# finally add the new entry to the experimental menu |
156 |
experimental_menu.InsertItem('wms') |
experimental_menu.InsertItem('wms') |