40 |
from Thuban import _ |
from Thuban import _ |
41 |
import Thuban.UI.baserenderer |
import Thuban.UI.baserenderer |
42 |
|
|
43 |
|
from capabilities import WMSCapabilities |
44 |
|
|
45 |
def epsg_code_to_projection(epsg): |
def epsg_code_to_projection(epsg): |
46 |
"""Find the projection for the given epsg code. |
"""Find the projection for the given epsg code. |
63 |
return (_("Extension: %s") % self.title, |
return (_("Extension: %s") % self.title, |
64 |
[ object.TreeInfo() for object in self.objects ]) |
[ object.TreeInfo() for object in self.objects ]) |
65 |
|
|
66 |
class WMSLayer(BaseLayer, WMSClient): |
class WMSLayer(BaseLayer): |
67 |
|
|
68 |
def __init__(self, title, url): |
def __init__(self, title, url): |
69 |
"""Initializes the WMSLayer. |
"""Initializes the WMSLayer. |
80 |
self.latlonbbox = None |
self.latlonbbox = None |
81 |
self.error_msg = None |
self.error_msg = None |
82 |
self.layer_name = None |
self.layer_name = None |
83 |
|
self.capabilities = None |
84 |
|
|
85 |
wms_response = self.getCapabilities(self.url, '1.0') |
# Change the cursor to demonstrate that we're busy but working |
86 |
self._capa_dom = xml.dom.minidom.parseString(wms_response) |
wxBeginBusyCursor() |
87 |
|
self.capabilities = WMSCapabilities(url) |
88 |
root = self._capa_dom.documentElement |
wxEndBusyCursor() |
89 |
cap = root.getElementsByTagName('Capability')[0] |
|
90 |
layer = cap.getElementsByTagName('Layer')[0] |
# name of the top layer of the remote map |
91 |
|
foo = self.capabilities.getLayers() |
92 |
# get projected bounding box and latlon bounding box |
if len(foo) == 0: |
93 |
for node in layer.childNodes: |
self.error_msg = _('No layers found in remote resource:\n'\ |
94 |
if node.nodeName == 'BoundingBox': |
'%s') % url |
95 |
minx = node.attributes.get('minx').nodeValue |
return |
96 |
miny = node.attributes.get('miny').nodeValue |
top_layer = foo[0] |
97 |
maxx = node.attributes.get('maxx').nodeValue |
self.layer_name = top_layer |
98 |
maxy = node.attributes.get('maxy').nodeValue |
|
99 |
self.bbox = (float(minx), float(miny), float(maxx), float(maxy)) |
# first projection of the top layer |
100 |
bbox = layer.getElementsByTagName('LatLonBoundingBox')[0] |
foo = self.capabilities.getLayerSRS(top_layer) |
101 |
self.layer_name = layer.getElementsByTagName('Name')[0].childNodes[0].data |
if len(foo) == 0: |
102 |
minx = bbox.attributes.get('minx').nodeValue |
self.error_msg = _('No LatLonBoundingBox found for top layer %s')\ |
103 |
miny = bbox.attributes.get('miny').nodeValue |
% top_layer |
104 |
maxx = bbox.attributes.get('maxx').nodeValue |
return |
105 |
maxy = bbox.attributes.get('maxy').nodeValue |
top_srs = foo[0] |
106 |
self.latlonbbox = (float(minx), float(miny), float(maxx), float(maxy)) |
|
107 |
|
# BoundingBox of the top layer |
108 |
|
bbox = self.capabilities.getLayerBBox(top_layer, top_srs) |
109 |
|
if len(bbox) == 0: |
110 |
|
self.error_msg = _('No BoundingBox found for layer %s and EPSG:')\ |
111 |
|
% (top_layer, top_srs) |
112 |
|
return |
113 |
|
self.bbox = (float(bbox['minx']), |
114 |
|
float(bbox['miny']), |
115 |
|
float(bbox['maxx']), |
116 |
|
float(bbox['maxy'])) |
117 |
|
|
118 |
|
# LatLonBox of the top layer |
119 |
|
bbox = self.capabilities.getLayerLatLonBBox(top_layer) |
120 |
|
self.latlonbbox = (float(bbox['minx']), |
121 |
|
float(bbox['miny']), |
122 |
|
float(bbox['maxx']), |
123 |
|
float(bbox['maxy'])) |
124 |
|
|
125 |
# get projection |
# get projection |
126 |
srs = layer.getElementsByTagName('SRS')[0].childNodes[0].data |
p = epsg_code_to_projection(top_srs) |
|
if len(srs.split(':')) == 1: |
|
|
epsg_id = srs |
|
|
else: |
|
|
epsg_id = srs.split(':')[1] |
|
|
|
|
|
p = epsg_code_to_projection(epsg_id) |
|
127 |
self.SetProjection(p) |
self.SetProjection(p) |
128 |
|
|
129 |
if p is None: |
if p is None: |
132 |
'Please set an appropriate projection yourself.'\ |
'Please set an appropriate projection yourself.'\ |
133 |
% epsg_id) |
% epsg_id) |
134 |
|
|
135 |
# get title |
# pre-determine the used format |
136 |
title = layer.getElementsByTagName('Title')[0].childNodes[0].data |
self.wmsformat, self.format = \ |
137 |
self.SetTitle(title.encode('latin1', 'replace')) |
self.calcFormat(self.capabilities.getFormats()) |
138 |
|
if self.wmsformat is None: |
139 |
|
self.error_msg = \ |
140 |
|
_('No supported image format found in remote resource') |
141 |
|
return |
142 |
|
|
143 |
|
# get and set the title |
144 |
|
self.SetTitle(self.capabilities.getTitle().encode('latin1', 'replace')) |
145 |
|
|
|
self._capa_dom.unlink() |
|
146 |
|
|
147 |
def LatLongBoundingBox(self): |
def LatLongBoundingBox(self): |
148 |
"""Return the layer's bounding box in lat-lon. |
"""Return the layer's bounding box in lat-lon. |
154 |
""" |
""" |
155 |
return self.bbox |
return self.bbox |
156 |
|
|
157 |
|
|
158 |
|
def getFormat(self, format): |
159 |
|
""" |
160 |
|
Return the image format for the render engine |
161 |
|
|
162 |
|
format -- format as returned by the WMS server |
163 |
|
|
164 |
|
If no mapping was found, None is returned |
165 |
|
|
166 |
|
An exception rule is implemented in order to not accept |
167 |
|
image/wbmp or WBMP which refers to WAP bitmap format and is |
168 |
|
not supported by the included render engine. |
169 |
|
""" |
170 |
|
fmap = {'png' : "PNG", |
171 |
|
'jpeg': "JPEG", |
172 |
|
'jpg' : "JPEG", |
173 |
|
'tif' : "TIFF", |
174 |
|
'gif' : "GIF", |
175 |
|
'wbmp': None, |
176 |
|
'bmp' : "BMP"} |
177 |
|
|
178 |
|
for f in fmap.keys(): |
179 |
|
if format.lower().find(f) > -1: |
180 |
|
return fmap[f] |
181 |
|
return None |
182 |
|
|
183 |
|
|
184 |
|
def calcFormat(self, formats): |
185 |
|
""" |
186 |
|
Calculate the preferred image format |
187 |
|
|
188 |
|
formats -- list of formates as returned by the WMS server |
189 |
|
|
190 |
|
The following priority is used: |
191 |
|
- PNG |
192 |
|
- JPEG |
193 |
|
- TIFF |
194 |
|
- GIF |
195 |
|
- BMP |
196 |
|
|
197 |
|
If no matching format was found, None, None will be returned. |
198 |
|
|
199 |
|
An exception rule is implemented in order to not accept |
200 |
|
image/wbmp or WBMP which refers to WAP bitmap format and is |
201 |
|
not supported by the included render engine. |
202 |
|
""" |
203 |
|
prio = ['png', 'jpeg', 'jpg', 'tif', 'gif', 'bmp'] |
204 |
|
for p in prio: |
205 |
|
for f in formats: |
206 |
|
if f.lower().find(p) > -1: |
207 |
|
if f.lower().find('wbmp') == -1: |
208 |
|
return f, self.getFormat(f) |
209 |
|
return None, None |
210 |
|
|
211 |
|
|
212 |
def GetMapImg(self, width, height, bbox): |
def GetMapImg(self, width, height, bbox): |
213 |
bbox_dict = { 'minx': bbox[0], 'miny': bbox[1], |
bbox_dict = { 'minx': bbox[0], 'miny': bbox[1], |
214 |
'maxx': bbox[2], 'maxy': bbox[3] } |
'maxx': bbox[2], 'maxy': bbox[3] } |
215 |
|
|
216 |
|
# Change the cursor to demonstrate that we're busy but working |
217 |
|
wxBeginBusyCursor() |
218 |
|
|
219 |
|
wmsclient = WMSClient() |
220 |
|
|
221 |
epsg_id = int(self.GetProjection().EPSGCode()) |
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 |
|
222 |
|
|
223 |
|
wms_response = wmsclient.getMap(self.url, self.wmsformat, width, height, |
224 |
|
epsg_id, bbox_dict, |
225 |
|
[self.layer_name], version = self.capabilities.getVersion()) |
226 |
|
wxEndBusyCursor() |
227 |
|
return wms_response, self.format |
228 |
|
|
229 |
|
|
230 |
def render_wms_layer(renderer, layer): |
def render_wms_layer(renderer, layer): |
237 |
xmax = (width - offx) / scale |
xmax = (width - offx) / scale |
238 |
ymax = (offy - 0) / scale |
ymax = (offy - 0) / scale |
239 |
|
|
240 |
img = layer.GetMapImg(width, height, (xmin, ymin, xmax, ymax)) |
img, format = layer.GetMapImg(width, height, (xmin, ymin, xmax, ymax)) |
241 |
renderer.draw_raster_data(img, "JPEG") |
renderer.draw_raster_data(img, format) |
242 |
|
|
243 |
return () |
return () |
244 |
|
|