14 |
|
|
15 |
from Thuban import _ |
from Thuban import _ |
16 |
|
|
|
import sys |
|
17 |
import os.path |
import os.path |
18 |
|
|
|
from math import hypot |
|
|
|
|
19 |
from wxPython.wx import wxWindow, \ |
from wxPython.wx import wxWindow, \ |
20 |
wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\ |
wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\ |
21 |
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, \ |
22 |
wxBITMAP_TYPE_XPM, wxCursor, wxPlatform, \ |
wxPlatform, wxBeginBusyCursor, wxEndBusyCursor, wxFileDialog, wxSAVE, \ |
|
wxBeginBusyCursor, wxEndBusyCursor, wxFileDialog, wxSAVE, \ |
|
23 |
wxOVERWRITE_PROMPT, wxID_OK |
wxOVERWRITE_PROMPT, wxID_OK |
24 |
|
|
25 |
# Export related stuff |
# Export related stuff |
28 |
|
|
29 |
from wxPython import wx |
from wxPython import wx |
30 |
|
|
31 |
from wxproj import point_in_polygon_shape, shape_centroid |
from Thuban.Model.messages import MAP_LAYERS_CHANGED, LAYER_CHANGED, \ |
32 |
|
LAYER_VISIBILITY_CHANGED |
|
from Thuban.Model.messages import \ |
|
|
MAP_PROJECTION_CHANGED, MAP_LAYERS_CHANGED, \ |
|
|
LAYER_PROJECTION_CHANGED, LAYER_CHANGED, LAYER_VISIBILITY_CHANGED |
|
33 |
|
|
34 |
from renderer import ScreenRenderer, ExportRenderer, PrinterRenderer |
from renderer import ScreenRenderer, ExportRenderer, PrinterRenderer |
35 |
|
|
36 |
import labeldialog |
import labeldialog |
37 |
|
|
38 |
from viewport import ViewPort, PanTool |
from viewport import ViewPort, PanTool, output_transform |
39 |
|
|
40 |
class CanvasPanTool(PanTool): |
class CanvasPanTool(PanTool): |
41 |
|
|
80 |
|
|
81 |
def draw_on_dc(self, dc): |
def draw_on_dc(self, dc): |
82 |
width, height = self.GetPageSizePixels() |
width, height = self.GetPageSizePixels() |
83 |
scale, offset, mapregion = OutputTransform(self.canvas.scale, |
scale, offset, mapregion = output_transform(self.canvas.scale, |
84 |
self.canvas.offset, |
self.canvas.offset, |
85 |
self.canvas.GetSizeTuple(), |
self.canvas.GetSizeTuple(), |
86 |
self.GetPageSizePixels()) |
self.GetPageSizePixels()) |
87 |
resx, resy = self.GetPPIPrinter() |
resx, resy = self.GetPPIPrinter() |
88 |
renderer = PrinterRenderer(dc, scale, offset, resolution = resy) |
renderer = PrinterRenderer(dc, scale, offset, resolution = resy) |
89 |
x, y, width, height = self.region |
x, y, width, height = self.region |
111 |
|
|
112 |
self.backgroundColor = wx.wxWHITE_BRUSH |
self.backgroundColor = wx.wxWHITE_BRUSH |
113 |
|
|
114 |
|
# Set to true if there ever is an error during redraw. There |
115 |
|
# should never be errors, but unfortunately bugs happen. |
116 |
|
self.error_on_redraw = 0 |
117 |
|
|
118 |
# subscribe the WX events we're interested in |
# subscribe the WX events we're interested in |
119 |
EVT_PAINT(self, self.OnPaint) |
EVT_PAINT(self, self.OnPaint) |
120 |
EVT_LEFT_DOWN(self, self.OnLeftDown) |
EVT_LEFT_DOWN(self, self.OnLeftDown) |
177 |
dc.EndDrawing() |
dc.EndDrawing() |
178 |
|
|
179 |
def OnIdle(self, event): |
def OnIdle(self, event): |
180 |
# render the screen if necessary |
"""Idle handler. Redraw the bitmap if necessary""" |
181 |
|
|
182 |
if self.bitmap != -1: |
if self.bitmap != -1: |
183 |
return |
return |
184 |
|
if self.error_on_redraw: |
185 |
|
return |
186 |
|
|
187 |
wxBeginBusyCursor() |
wxBeginBusyCursor() |
188 |
try: |
try: |
189 |
width, height = self.GetSizeTuple() |
try: |
190 |
|
self._do_redraw() |
191 |
|
except: |
192 |
|
self.error_on_redraw = True |
193 |
|
raise |
194 |
|
finally: |
195 |
|
wxEndBusyCursor() |
196 |
|
|
197 |
bitmap = wx.wxEmptyBitmap(width, height) |
def _do_redraw(self): |
198 |
dc = wx.wxMemoryDC() |
"""Called by OnIdle to do the actual redraw. |
199 |
dc.SelectObject(bitmap) |
""" |
200 |
dc.BeginDrawing() |
width, height = self.GetSizeTuple() |
201 |
|
|
202 |
dc.SetBackground(self.backgroundColor) |
bitmap = wx.wxEmptyBitmap(width, height) |
203 |
dc.Clear() |
dc = wx.wxMemoryDC() |
204 |
|
dc.SelectObject(bitmap) |
205 |
|
dc.BeginDrawing() |
206 |
|
|
207 |
selected_layer = self.selection.SelectedLayer() |
dc.SetBackground(self.backgroundColor) |
208 |
selected_shapes = self.selection.SelectedShapes() |
dc.Clear() |
209 |
|
|
210 |
# draw the map into the bitmap |
selected_layer = self.selection.SelectedLayer() |
211 |
renderer = ScreenRenderer(dc, self.scale, self.offset) |
selected_shapes = self.selection.SelectedShapes() |
212 |
|
|
213 |
# Pass the entire bitmap as update region to the renderer. |
# draw the map into the bitmap |
214 |
# We're redrawing the whole bitmap, after all. |
renderer = ScreenRenderer(dc, self.scale, self.offset) |
|
renderer.RenderMap(self.Map(), (0, 0, width, height), |
|
|
selected_layer, selected_shapes) |
|
215 |
|
|
216 |
dc.EndDrawing() |
# Pass the entire bitmap as update region to the renderer. |
217 |
dc.SelectObject(wx.wxNullBitmap) |
# We're redrawing the whole bitmap, after all. |
218 |
|
renderer.RenderMap(self.Map(), (0, 0, width, height), |
219 |
|
selected_layer, selected_shapes) |
220 |
|
|
221 |
self.bitmap = bitmap |
dc.EndDrawing() |
222 |
finally: |
dc.SelectObject(wx.wxNullBitmap) |
|
wxEndBusyCursor() |
|
|
pass |
|
223 |
|
|
224 |
|
self.bitmap = bitmap |
225 |
# This causes a paint event that then draws the bitmap |
# This causes a paint event that then draws the bitmap |
226 |
self.redraw() |
self.redraw() |
227 |
|
|
238 |
self.export_path = os.path.dirname(dlg.GetPath()) |
self.export_path = os.path.dirname(dlg.GetPath()) |
239 |
dc = wxMetaFileDC(dlg.GetPath()) |
dc = wxMetaFileDC(dlg.GetPath()) |
240 |
|
|
241 |
scale, offset, mapregion = OutputTransform(self.scale, |
scale, offset, mapregion = output_transform(self.scale, |
242 |
self.offset, |
self.offset, |
243 |
self.GetSizeTuple(), |
self.GetSizeTuple(), |
244 |
dc.GetSizeTuple()) |
dc.GetSizeTuple()) |
245 |
|
|
246 |
selected_layer = self.selection.SelectedLayer() |
selected_layer = self.selection.SelectedLayer() |
247 |
selected_shapes = self.selection.SelectedShapes() |
selected_shapes = self.selection.SelectedShapes() |
301 |
self.drag_dc.SetLogicalFunction(wxINVERT) |
self.drag_dc.SetLogicalFunction(wxINVERT) |
302 |
self.drag_dc.SetBrush(wxTRANSPARENT_BRUSH) |
self.drag_dc.SetBrush(wxTRANSPARENT_BRUSH) |
303 |
self.tool.Show(self.drag_dc) |
self.tool.Show(self.drag_dc) |
304 |
|
self.CaptureMouse() |
305 |
self.dragging = 1 |
self.dragging = 1 |
306 |
|
|
307 |
def OnLeftUp(self, event): |
def OnLeftUp(self, event): |
354 |
|
|
355 |
def LabelShapeAt(self, x, y, text=None): |
def LabelShapeAt(self, x, y, text=None): |
356 |
"""Add or remove a label at window position x, y. |
"""Add or remove a label at window position x, y. |
357 |
|
|
358 |
If there's a label at the given position, remove it. Otherwise |
If there's a label at the given position, remove it. Otherwise |
359 |
determine the shape at the position, run the label dialog and |
determine the shape at the position, run the label dialog and |
360 |
unless the user cancels the dialog, add a label. |
unless the user cancels the dialog, add a label. |
368 |
layer.ShapeStore().Table(), |
layer.ShapeStore().Table(), |
369 |
shape_index) |
shape_index) |
370 |
ViewPort.LabelShapeAt(self, x, y, text) |
ViewPort.LabelShapeAt(self, x, y, text) |
|
|
|
|
def OutputTransform(canvas_scale, canvas_offset, canvas_size, device_extend): |
|
|
"""Calculate dimensions to transform canvas content to output device.""" |
|
|
width, height = device_extend |
|
|
|
|
|
# Only 80 % of the with are available for the map |
|
|
width = width * 0.8 |
|
|
|
|
|
# Define the distance of the map from DC border |
|
|
distance = 20 |
|
|
|
|
|
if height < width: |
|
|
# landscape |
|
|
map_height = height - 2*distance |
|
|
map_width = map_height |
|
|
else: |
|
|
# portrait, recalibrate width (usually the legend width is too |
|
|
# small |
|
|
width = width * 0.9 |
|
|
map_height = width - 2*distance |
|
|
map_width = map_height |
|
|
|
|
|
mapregion = (distance, distance, |
|
|
distance+map_width, distance+map_height) |
|
|
|
|
|
canvas_width, canvas_height = canvas_size |
|
|
|
|
|
scalex = map_width / (canvas_width/canvas_scale) |
|
|
scaley = map_height / (canvas_height/canvas_scale) |
|
|
scale = min(scalex, scaley) |
|
|
canvas_offx, canvas_offy = canvas_offset |
|
|
offx = scale*canvas_offx/canvas_scale |
|
|
offy = scale*canvas_offy/canvas_scale |
|
|
|
|
|
return scale, (offx, offy), mapregion |
|