19 |
|
|
20 |
from math import hypot |
from math import hypot |
21 |
|
|
22 |
from wxPython.wx import wxWindow,\ |
from wxPython.wx import wxWindow, wxYield,\ |
23 |
wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\ |
wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\ |
24 |
EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \ |
EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW, \ |
25 |
wxBITMAP_TYPE_XPM, wxBeginBusyCursor, wxEndBusyCursor, wxCursor, \ |
wxBITMAP_TYPE_XPM, wxBeginBusyCursor, wxEndBusyCursor, wxCursor, \ |
35 |
from wxproj import point_in_polygon_shape, shape_centroid |
from wxproj import point_in_polygon_shape, shape_centroid |
36 |
|
|
37 |
from Thuban.Model.messages import MAP_PROJECTION_CHANGED, \ |
from Thuban.Model.messages import MAP_PROJECTION_CHANGED, \ |
38 |
|
LAYER_PROJECTION_CHANGED, \ |
39 |
MAP_LAYERS_CHANGED, LAYER_CHANGED, LAYER_VISIBILITY_CHANGED |
MAP_LAYERS_CHANGED, LAYER_CHANGED, LAYER_VISIBILITY_CHANGED |
40 |
from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \ |
from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \ |
41 |
SHAPETYPE_POINT |
SHAPETYPE_POINT |
274 |
self.selected_layer, self.selected_shapes) |
self.selected_layer, self.selected_shapes) |
275 |
return True |
return True |
276 |
|
|
|
|
|
277 |
class MapCanvas(wxWindow, Publisher): |
class MapCanvas(wxWindow, Publisher): |
278 |
|
|
279 |
"""A widget that displays a map and offers some interaction""" |
"""A widget that displays a map and offers some interaction""" |
302 |
# the map displayed in this canvas. Set with SetMap() |
# the map displayed in this canvas. Set with SetMap() |
303 |
self.map = None |
self.map = None |
304 |
|
|
305 |
|
# current map projection. should only differ from map.projection |
306 |
|
# when the map's projection is changing and we need access to the |
307 |
|
# old projection. |
308 |
|
self.current_map_proj = None |
309 |
|
|
310 |
# scale and offset describe the transformation from projected |
# scale and offset describe the transformation from projected |
311 |
# coordinates to window coordinates. |
# coordinates to window coordinates. |
312 |
self.scale = 1.0 |
self.scale = 1.0 |
383 |
clear = self.map is None or not self.map.HasLayers() |
clear = self.map is None or not self.map.HasLayers() |
384 |
|
|
385 |
wxBeginBusyCursor() |
wxBeginBusyCursor() |
386 |
|
wxYield() |
387 |
|
|
388 |
try: |
try: |
389 |
if not clear: |
if not clear: |
390 |
self.do_redraw() |
self.do_redraw() |
509 |
for channel in redraw_channels: |
for channel in redraw_channels: |
510 |
self.map.Unsubscribe(channel, self.full_redraw) |
self.map.Unsubscribe(channel, self.full_redraw) |
511 |
self.map.Unsubscribe(MAP_PROJECTION_CHANGED, |
self.map.Unsubscribe(MAP_PROJECTION_CHANGED, |
512 |
self.projection_changed) |
self.map_projection_changed) |
513 |
|
self.map.Unsubscribe(LAYER_PROJECTION_CHANGED, |
514 |
|
self.layer_projection_changed) |
515 |
self.map = map |
self.map = map |
516 |
|
self.current_map_proj = self.map.GetProjection() |
517 |
self.selection.ClearSelection() |
self.selection.ClearSelection() |
518 |
if self.map is not None: |
if self.map is not None: |
519 |
for channel in redraw_channels: |
for channel in redraw_channels: |
520 |
self.map.Subscribe(channel, self.full_redraw) |
self.map.Subscribe(channel, self.full_redraw) |
521 |
self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed) |
self.map.Subscribe(MAP_PROJECTION_CHANGED, self.map_projection_changed) |
522 |
|
self.map.Subscribe(LAYER_PROJECTION_CHANGED, self.layer_projection_changed) |
523 |
self.FitMapToWindow() |
self.FitMapToWindow() |
524 |
# force a redraw. If map is not empty, it's already been called |
# force a redraw. If map is not empty, it's already been called |
525 |
# by FitMapToWindow but if map is empty it hasn't been called |
# by FitMapToWindow but if map is empty it hasn't been called |
537 |
self.bitmap = None |
self.bitmap = None |
538 |
self.redraw() |
self.redraw() |
539 |
|
|
540 |
def projection_changed(self, *args): |
def map_projection_changed(self, *args): |
541 |
self.FitMapToWindow() |
|
542 |
|
proj = self.current_map_proj |
543 |
|
self.current_map_proj = self.map.GetProjection() |
544 |
|
|
545 |
|
bbox = None |
546 |
|
|
547 |
|
if proj is not None and self.current_map_proj is not None: |
548 |
|
width, height = self.GetSizeTuple() |
549 |
|
llx, lly = self.win_to_proj(0, height) |
550 |
|
urx, ury = self.win_to_proj(width, 0) |
551 |
|
bbox = proj.Inverse(llx, lly) + proj.Inverse(urx, ury) |
552 |
|
bbox = self.current_map_proj.ForwardBBox(bbox) |
553 |
|
|
554 |
|
if bbox is not None: |
555 |
|
self.FitRectToWindow(bbox) |
556 |
|
else: |
557 |
|
self.FitMapToWindow() |
558 |
|
|
559 |
|
self.full_redraw() |
560 |
|
|
561 |
|
def layer_projection_changed(self, *args): |
562 |
self.full_redraw() |
self.full_redraw() |
563 |
|
|
564 |
def set_view_transform(self, scale, offset): |
def set_view_transform(self, scale, offset): |
654 |
Set the scale so that the map fits exactly into the window and |
Set the scale so that the map fits exactly into the window and |
655 |
center it in the window. |
center it in the window. |
656 |
""" |
""" |
657 |
bbox = self.map.ProjectedBoundingBox() |
if self.map is not None: |
658 |
if bbox is not None: |
bbox = self.map.ProjectedBoundingBox() |
659 |
self.FitRectToWindow(bbox) |
if bbox is not None: |
660 |
|
self.FitRectToWindow(bbox) |
661 |
|
|
662 |
def FitLayerToWindow(self, layer): |
def FitLayerToWindow(self, layer): |
663 |
"""Fit the given layer to the window. |
"""Fit the given layer to the window. |