/[thuban]/branches/WIP-pyshapelib-bramz/Thuban/UI/view.py
ViewVC logotype

Annotation of /branches/WIP-pyshapelib-bramz/Thuban/UI/view.py

Parent Directory Parent Directory | Revision Log Revision Log


Revision 145 - (hide annotations)
Tue May 7 14:58:05 2002 UTC (22 years, 10 months ago) by bh
Original Path: trunk/thuban/Thuban/UI/view.py
File MIME type: text/x-python
File size: 25060 byte(s)
	* Thuban/UI/view.py (MapCanvas.__init__): New instance variable
	update_region for the update region.
	(MapCanvas.OnPaint): Maintain the update region
	(MapCanvas.do_redraw): Pass the bounding box of the update_region
	to the renderer when drawing the bitmap. Reset the update_region.

1 bh 78 # Copyright (c) 2001, 2002 by Intevation GmbH
2 bh 6 # Authors:
3     # Bernhard Herzog <[email protected]>
4     #
5     # This program is free software under the GPL (>=v2)
6     # Read the file COPYING coming with Thuban for details.
7    
8     """
9     Classes for display of a map and interaction with it
10     """
11    
12     __version__ = "$Revision$"
13    
14     from math import hypot
15    
16     from wxPython.wx import wxWindow,\
17     wxPaintDC, wxColour, wxClientDC, wxINVERT, wxTRANSPARENT_BRUSH, wxFont,\
18 bh 122 EVT_PAINT, EVT_LEFT_DOWN, EVT_LEFT_UP, EVT_MOTION, EVT_LEAVE_WINDOW
19 bh 6
20    
21     from wxPython import wx
22    
23     from wxproj import point_in_polygon_shape, shape_centroid
24    
25    
26     from Thuban.Model.messages import MAP_PROJECTION_CHANGED, \
27     LAYERS_CHANGED, LAYER_LEGEND_CHANGED, LAYER_VISIBILITY_CHANGED
28     from Thuban.Model.layer import SHAPETYPE_POLYGON, SHAPETYPE_ARC, \
29     SHAPETYPE_POINT
30     from Thuban.Model.label import ALIGN_CENTER, ALIGN_TOP, ALIGN_BOTTOM, \
31     ALIGN_LEFT, ALIGN_RIGHT
32 bh 122 from Thuban.Lib.connector import Publisher
33 bh 6
34     from renderer import ScreenRenderer, PrinterRender
35    
36     import labeldialog
37    
38 bh 122 from messages import SELECTED_SHAPE, VIEW_POSITION
39 bh 6
40    
41     #
42     # The tools
43     #
44    
45     class Tool:
46    
47     """
48     Base class for the interactive tools
49     """
50    
51     def __init__(self, view):
52     """Intitialize the tool. The view is the canvas displaying the map"""
53     self.view = view
54     self.start = self.current = None
55     self.dragging = 0
56     self.drawn = 0
57    
58     def Name(self):
59     """Return the tool's name"""
60     return ''
61    
62     def drag_start(self, x, y):
63     self.start = self.current = x, y
64     self.dragging = 1
65    
66     def drag_move(self, x, y):
67     self.current = x, y
68    
69     def drag_stop(self, x, y):
70     self.current = x, y
71     self.dragging = 0
72    
73     def Show(self, dc):
74     if not self.drawn:
75     self.draw(dc)
76     self.drawn = 1
77    
78     def Hide(self, dc):
79     if self.drawn:
80     self.draw(dc)
81     self.drawn = 0
82    
83     def draw(self, dc):
84     pass
85    
86     def MouseDown(self, event):
87     self.drag_start(event.m_x, event.m_y)
88    
89     def MouseMove(self, event):
90     if self.dragging:
91     self.drag_move(event.m_x, event.m_y)
92    
93     def MouseUp(self, event):
94     if self.dragging:
95     self.drag_move(event.m_x, event.m_y)
96    
97     def Cancel(self):
98     self.dragging = 0
99    
100    
101     class RectTool(Tool):
102    
103     """Base class for tools that draw rectangles while dragging"""
104    
105     def draw(self, dc):
106     sx, sy = self.start
107     cx, cy = self.current
108     dc.DrawRectangle(sx, sy, cx - sx, cy - sy)
109    
110     class ZoomInTool(RectTool):
111    
112     """The Zoom-In Tool"""
113    
114     def Name(self):
115     return "ZoomInTool"
116    
117     def proj_rect(self):
118     """return the rectangle given by start and current in projected
119     coordinates"""
120     sx, sy = self.start
121     cx, cy = self.current
122     left, top = self.view.win_to_proj(sx, sy)
123     right, bottom = self.view.win_to_proj(cx, cy)
124     return (min(left, right), min(top, bottom),
125     max(left, right), max(top, bottom))
126    
127     def MouseUp(self, event):
128     if self.dragging:
129     Tool.MouseUp(self, event)
130 bh 57 sx, sy = self.start
131     cx, cy = self.current
132     if sx == cx and sy == cy:
133     # Just a mouse click. Simply zoom in by a factor of two
134     self.view.ZoomFactor(2, center = (cx, cy))
135     else:
136     # A drag. Zoom in to the rectangle
137     self.view.FitRectToWindow(self.proj_rect())
138 bh 6
139    
140     class ZoomOutTool(RectTool):
141    
142     """The Zoom-Out Tool"""
143    
144     def Name(self):
145     return "ZoomOutTool"
146    
147     def MouseUp(self, event):
148     if self.dragging:
149     Tool.MouseUp(self, event)
150     sx, sy = self.start
151     cx, cy = self.current
152 bh 57 if sx == cx and sy == cy:
153     # Just a mouse click. Simply zoom out by a factor of two
154     self.view.ZoomFactor(0.5, center = (cy, cy))
155     else:
156     # A drag. Zoom out to the rectangle
157     self.view.ZoomOutToRect((min(sx, cx), min(sy, cy),
158     max(sx, cx), max(sy, cy)))
159 bh 6
160    
161     class PanTool(Tool):
162    
163     """The Pan Tool"""
164    
165     def Name(self):
166     return "PanTool"
167    
168     def MouseMove(self, event):
169     if self.dragging:
170     x0, y0 = self.current
171     Tool.MouseMove(self, event)
172     x, y = self.current
173     width, height = self.view.GetSizeTuple()
174     dc = self.view.drag_dc
175     dc.Blit(0, 0, width, height, dc, x0 - x, y0 - y)
176    
177     def MouseUp(self, event):
178     if self.dragging:
179     Tool.MouseUp(self, event)
180     sx, sy = self.start
181     cx, cy = self.current
182     self.view.Translate(cx - sx, cy - sy)
183    
184     class IdentifyTool(Tool):
185    
186     """The "Identify" Tool"""
187    
188     def Name(self):
189     return "IdentifyTool"
190    
191     def MouseUp(self, event):
192     self.view.SelectShapeAt(event.m_x, event.m_y)
193    
194    
195     class LabelTool(Tool):
196    
197     """The "Label" Tool"""
198    
199     def Name(self):
200     return "LabelTool"
201    
202     def MouseUp(self, event):
203     self.view.LabelShapeAt(event.m_x, event.m_y)
204    
205    
206    
207    
208     class MapPrintout(wx.wxPrintout):
209    
210     """
211     wxPrintout class for printing Thuban maps
212     """
213    
214     def __init__(self, map):
215     wx.wxPrintout.__init__(self)
216     self.map = map
217    
218     def GetPageInfo(self):
219     return (1, 1, 1, 1)
220    
221     def HasPage(self, pagenum):
222     return pagenum == 1
223    
224     def OnPrintPage(self, pagenum):
225     if pagenum == 1:
226     self.draw_on_dc(self.GetDC())
227    
228     def draw_on_dc(self, dc):
229     width, height = self.GetPageSizePixels()
230     llx, lly, urx, ury = self.map.ProjectedBoundingBox()
231     scalex = width / (urx - llx)
232     scaley = height / (ury - lly)
233     scale = min(scalex, scaley)
234     offx = 0.5 * (width - (urx + llx) * scale)
235     offy = 0.5 * (height + (ury + lly) * scale)
236    
237     resx, resy = self.GetPPIPrinter()
238     renderer = PrinterRender(dc, scale, (offx, offy), resolution = resx)
239     renderer.RenderMap(self.map)
240     return wx.true
241    
242    
243 bh 122 class MapCanvas(wxWindow, Publisher):
244 bh 6
245     """A widget that displays a map and offers some interaction"""
246    
247 bh 23 def __init__(self, parent, winid, interactor):
248 bh 6 wxWindow.__init__(self, parent, winid)
249     self.SetBackgroundColour(wxColour(255, 255, 255))
250 bh 125
251     # the map displayed in this canvas. Set with SetMap()
252 bh 6 self.map = None
253 bh 125
254     # scale and offset describe the transformation from projected
255     # coordinates to window coordinates.
256 bh 6 self.scale = 1.0
257     self.offset = (0, 0)
258 bh 125
259     # whether the user is currently dragging the mouse, i.e. moving
260     # the mouse while pressing a mouse button
261 bh 6 self.dragging = 0
262 bh 125
263     # the currently active tool
264 bh 6 self.tool = None
265 bh 125
266     # The current mouse position of the last OnMotion event or None
267     # if the mouse is outside the window.
268     self.current_position = None
269    
270     # If true, OnIdle will call do_redraw to do the actual
271     # redrawing. Set by OnPaint to avoid some unnecessary redraws.
272     # To force a redraw call full_redraw().
273 bh 6 self.redraw_on_idle = 0
274 bh 125
275 bh 145 # The region to update when idle
276     self.update_region = wx.wxRegion()
277    
278 bh 125 # the bitmap serving as backing store
279     self.bitmap = None
280    
281     # the interactor
282     self.interactor = interactor
283     self.interactor.Subscribe(SELECTED_SHAPE, self.shape_selected)
284    
285     # subscribe the WX events we're interested in
286 bh 6 EVT_PAINT(self, self.OnPaint)
287     EVT_LEFT_DOWN(self, self.OnLeftDown)
288     EVT_LEFT_UP(self, self.OnLeftUp)
289     EVT_MOTION(self, self.OnMotion)
290 bh 122 EVT_LEAVE_WINDOW(self, self.OnLeaveWindow)
291 bh 125 wx.EVT_SIZE(self, self.OnSize)
292 bh 6 wx.EVT_IDLE(self, self.OnIdle)
293    
294 bh 122 def __del__(self):
295     wxWindow.__del__(self)
296     Publisher.__del__(self)
297    
298 bh 6 def OnPaint(self, event):
299     dc = wxPaintDC(self)
300 bh 57 if self.map is not None and self.map.HasLayers():
301     # We have a non-empty map. Redraw it in idle time
302     self.redraw_on_idle = 1
303 bh 145 # update the region that has to be redrawn
304     self.update_region.UnionRegion(self.GetUpdateRegion())
305 bh 57 else:
306     # If we've got no map or if the map is empty, simply clear
307     # the screen.
308    
309     # XXX it's probably possible to get rid of this. The
310     # background color of the window is already white and the
311     # only thing we may have to do is to call self.Refresh()
312     # with a true argument in the right places.
313     dc.BeginDrawing()
314     dc.Clear()
315     dc.EndDrawing()
316 bh 6
317 bh 145 # clear the region
318     self.update_region = wx.wxRegion()
319    
320 bh 6 def do_redraw(self):
321 bh 145 # This should only be called if we have a non-empty map.
322 bh 125
323 bh 145 # get the update region and reset it.
324     update_box = self.update_region.GetBox()
325     self.update_region = wx.wxRegion()
326    
327     # Get the window size.
328 bh 6 width, height = self.GetSizeTuple()
329    
330 bh 125 # If self.bitmap's still there, reuse it. Otherwise redraw it
331     if self.bitmap is not None:
332     bitmap = self.bitmap
333 bh 6 else:
334 bh 125 bitmap = wx.wxEmptyBitmap(width, height)
335     dc = wx.wxMemoryDC()
336     dc.SelectObject(bitmap)
337     dc.BeginDrawing()
338 bh 57
339 bh 125 # clear the background
340     dc.SetBrush(wx.wxWHITE_BRUSH)
341     dc.SetPen(wx.wxTRANSPARENT_PEN)
342     dc.DrawRectangle(0, 0, width, height)
343 bh 6
344 bh 125 if 1: #self.interactor.selected_map is self.map:
345     selected_layer = self.interactor.selected_layer
346     selected_shape = self.interactor.selected_shape
347     else:
348     selected_layer = None
349     selected_shape = None
350 bh 57
351 bh 125 # draw the map into the bitmap
352     renderer = ScreenRenderer(dc, self.scale, self.offset)
353 bh 145 renderer.RenderMap(self.map, update_box,
354     selected_layer, selected_shape)
355 bh 125
356     dc.EndDrawing()
357     dc.SelectObject(wx.wxNullBitmap)
358     self.bitmap = bitmap
359    
360 bh 57 # blit the bitmap to the screen
361 bh 125 dc = wx.wxMemoryDC()
362     dc.SelectObject(bitmap)
363 bh 6 clientdc = wxClientDC(self)
364     clientdc.BeginDrawing()
365     clientdc.Blit(0, 0, width, height, dc, 0, 0)
366     clientdc.EndDrawing()
367    
368     def Print(self):
369     printer = wx.wxPrinter()
370     printout = MapPrintout(self.map)
371     printer.Print(self, printout, wx.true)
372     printout.Destroy()
373    
374     def SetMap(self, map):
375     redraw_channels = (LAYERS_CHANGED, LAYER_LEGEND_CHANGED,
376     LAYER_VISIBILITY_CHANGED)
377     if self.map is not None:
378     for channel in redraw_channels:
379 bh 125 self.map.Unsubscribe(channel, self.full_redraw)
380 bh 6 self.map.Unsubscribe(MAP_PROJECTION_CHANGED,
381     self.projection_changed)
382     self.map = map
383     if self.map is not None:
384     for channel in redraw_channels:
385 bh 125 self.map.Subscribe(channel, self.full_redraw)
386 bh 6 self.map.Subscribe(MAP_PROJECTION_CHANGED, self.projection_changed)
387     self.FitMapToWindow()
388 bh 57 # force a redraw. If map is not empty, it's already been called
389     # by FitMapToWindow but if map is empty it hasn't been called
390     # yet so we have to explicitly call it.
391 bh 125 self.full_redraw()
392 bh 6
393     def Map(self):
394     return self.map
395    
396     def redraw(self, *args):
397     self.Refresh(0)
398    
399 bh 125 def full_redraw(self, *args):
400     self.bitmap = None
401     self.redraw()
402    
403 bh 6 def projection_changed(self, *args):
404     self.FitMapToWindow()
405 bh 125 self.full_redraw()
406 bh 6
407     def set_view_transform(self, scale, offset):
408     self.scale = scale
409     self.offset = offset
410 bh 125 self.full_redraw()
411 bh 6
412     def proj_to_win(self, x, y):
413     """\
414     Return the point in window coords given by projected coordinates x y
415     """
416     offx, offy = self.offset
417     return (self.scale * x + offx, -self.scale * y + offy)
418    
419     def win_to_proj(self, x, y):
420     """\
421     Return the point in projected coordinates given by window coords x y
422     """
423     offx, offy = self.offset
424     return ((x - offx) / self.scale, (offy - y) / self.scale)
425    
426     def FitRectToWindow(self, rect):
427     width, height = self.GetSizeTuple()
428     llx, lly, urx, ury = rect
429 bh 45 if llx == urx or lly == ury:
430     # zero with or zero height. Do Nothing
431     return
432 bh 6 scalex = width / (urx - llx)
433     scaley = height / (ury - lly)
434     scale = min(scalex, scaley)
435     offx = 0.5 * (width - (urx + llx) * scale)
436     offy = 0.5 * (height + (ury + lly) * scale)
437     self.set_view_transform(scale, (offx, offy))
438    
439     def FitMapToWindow(self):
440     """\
441     Set the scale and offset so that the map is centered in the
442     window
443     """
444     bbox = self.map.ProjectedBoundingBox()
445     if bbox is not None:
446     self.FitRectToWindow(bbox)
447    
448 bh 57 def ZoomFactor(self, factor, center = None):
449     """Multiply the zoom by factor and center on center.
450    
451     The optional parameter center is a point in window coordinates
452     that should be centered. If it is omitted, it defaults to the
453     center of the window
454     """
455 bh 6 width, height = self.GetSizeTuple()
456     scale = self.scale * factor
457     offx, offy = self.offset
458 bh 57 if center is not None:
459     cx, cy = center
460     else:
461     cx = width / 2
462     cy = height / 2
463     offset = (factor * (offx - cx) + width / 2,
464     factor * (offy - cy) + height / 2)
465 bh 6 self.set_view_transform(scale, offset)
466    
467     def ZoomOutToRect(self, rect):
468     # rect is given in window coordinates
469    
470     # determine the bbox of the displayed region in projected
471     # coordinates
472     width, height = self.GetSizeTuple()
473     llx, lly = self.win_to_proj(0, height - 1)
474     urx, ury = self.win_to_proj(width - 1, 0)
475    
476     sx, sy, ex, ey = rect
477     scalex = (ex - sx) / (urx - llx)
478     scaley = (ey - sy) / (ury - lly)
479     scale = min(scalex, scaley)
480    
481     offx = 0.5 * ((ex + sx) - (urx + llx) * scale)
482     offy = 0.5 * ((ey + sy) + (ury + lly) * scale)
483     self.set_view_transform(scale, (offx, offy))
484    
485     def Translate(self, dx, dy):
486     offx, offy = self.offset
487     self.set_view_transform(self.scale, (offx + dx, offy + dy))
488    
489     def ZoomInTool(self):
490     self.tool = ZoomInTool(self)
491    
492     def ZoomOutTool(self):
493     self.tool = ZoomOutTool(self)
494    
495     def PanTool(self):
496     self.tool = PanTool(self)
497    
498     def IdentifyTool(self):
499     self.tool = IdentifyTool(self)
500    
501     def LabelTool(self):
502     self.tool = LabelTool(self)
503    
504     def CurrentTool(self):
505     return self.tool and self.tool.Name() or None
506    
507 bh 122 def CurrentPosition(self):
508     """Return current position of the mouse in projected coordinates.
509    
510     The result is a 2-tuple of floats with the coordinates. If the
511     mouse is not in the window, the result is None.
512     """
513     if self.current_position is not None:
514     x, y = self.current_position
515     return self.win_to_proj(x, y)
516     else:
517     return None
518    
519     def set_current_position(self, event):
520     """Set the current position from event
521    
522     Should be called by all events that contain mouse positions
523     especially EVT_MOTION. The event paramete may be None to
524     indicate the the pointer left the window.
525     """
526     if event is not None:
527     self.current_position = (event.m_x, event.m_y)
528     else:
529     self.current_position = None
530     self.issue(VIEW_POSITION)
531    
532 bh 6 def OnLeftDown(self, event):
533 bh 122 self.set_current_position(event)
534 bh 6 if self.tool is not None:
535     self.drag_dc = wxClientDC(self)
536     self.drag_dc.SetLogicalFunction(wxINVERT)
537     self.drag_dc.SetBrush(wxTRANSPARENT_BRUSH)
538     self.CaptureMouse()
539     self.tool.MouseDown(event)
540     self.tool.Show(self.drag_dc)
541     self.dragging = 1
542    
543     def OnLeftUp(self, event):
544     self.ReleaseMouse()
545 bh 122 self.set_current_position(event)
546 bh 6 if self.dragging:
547     self.tool.Hide(self.drag_dc)
548     self.tool.MouseUp(event)
549     self.drag_dc = None
550     self.dragging = 0
551    
552     def OnMotion(self, event):
553 bh 122 self.set_current_position(event)
554 bh 6 if self.dragging:
555     self.tool.Hide(self.drag_dc)
556     self.tool.MouseMove(event)
557     self.tool.Show(self.drag_dc)
558    
559 bh 122 def OnLeaveWindow(self, event):
560     self.set_current_position(None)
561    
562 bh 6 def OnIdle(self, event):
563     if self.redraw_on_idle:
564     self.do_redraw()
565     self.redraw_on_idle = 0
566    
567 bh 125 def OnSize(self, event):
568     # the window's size has changed. We have to get a new bitmap. If
569     # we want to be clever we could try to get by without throwing
570     # everything away. E.g. when the window gets smaller, we could
571     # either keep the bitmap or create the new one from the old one.
572     # Even when the window becomes larger some parts of the bitmap
573     # could be reused.
574     self.full_redraw()
575    
576 bh 6 def shape_selected(self, layer, shape):
577 bh 125 self.full_redraw()
578 bh 6
579 bh 43 def find_shape_at(self, px, py, select_labels = 0, selected_layer = 1):
580     """Determine the shape at point px, py in window coords
581    
582     Return the shape and the corresponding layer as a tuple (layer,
583     shape).
584    
585     If the optional parameter select_labels is true (default false)
586     search through the labels. If a label is found return it's index
587     as the shape and None as the layer.
588    
589     If the optional parameter selected_layer is true (default), only
590     search in the currently selected layer.
591     """
592 bh 6 map_proj = self.map.projection
593     if map_proj is not None:
594     forward = map_proj.Forward
595     else:
596     forward = None
597    
598     scale = self.scale
599     offx, offy = self.offset
600    
601     if select_labels:
602     labels = self.map.LabelLayer().Labels()
603    
604     if labels:
605     dc = wxClientDC(self)
606     font = wxFont(10, wx.wxSWISS, wx.wxNORMAL, wx.wxNORMAL)
607     dc.SetFont(font)
608 bh 60 for i in range(len(labels) - 1, -1, -1):
609 bh 6 label = labels[i]
610     x = label.x
611     y = label.y
612     text = label.text
613     if forward:
614     x, y = forward(x, y)
615     x = x * scale + offx
616     y = -y * scale + offy
617     width, height = dc.GetTextExtent(text)
618     if label.halign == ALIGN_LEFT:
619     # nothing to be done
620     pass
621     elif label.halign == ALIGN_RIGHT:
622     x = x - width
623     elif label.halign == ALIGN_CENTER:
624     x = x - width/2
625     if label.valign == ALIGN_TOP:
626     # nothing to be done
627     pass
628     elif label.valign == ALIGN_BOTTOM:
629     y = y - height
630     elif label.valign == ALIGN_CENTER:
631     y = y - height/2
632     if x <= px < x + width and y <= py <= y + height:
633     return None, i
634 bh 43
635     if selected_layer:
636     layer = self.interactor.SelectedLayer()
637     if layer is not None:
638     layers = [layer]
639     else:
640     # no layer selected. Use an empty list to effectively
641     # ignore all layers.
642     layers = []
643     else:
644     layers = self.map.Layers()
645    
646 bh 6 for layer_index in range(len(layers) - 1, -1, -1):
647     layer = layers[layer_index]
648    
649     # search only in visible layers
650     if not layer.Visible():
651     continue
652    
653     filled = layer.fill is not None
654     stroked = layer.stroke is not None
655    
656     layer_proj = layer.projection
657     if layer_proj is not None:
658     inverse = layer_proj.Inverse
659     else:
660     inverse = None
661    
662     shapetype = layer.ShapeType()
663    
664     select_shape = -1
665     if shapetype == SHAPETYPE_POLYGON:
666 bh 60 for i in range(layer.NumShapes() - 1, -1, -1):
667 bh 6 result = point_in_polygon_shape(layer.shapefile.cobject(),
668     i,
669     filled, stroked,
670     map_proj, layer_proj,
671     scale, -scale, offx, offy,
672     px, py)
673     if result:
674     select_shape = i
675     break
676     elif shapetype == SHAPETYPE_ARC:
677 bh 60 for i in range(layer.NumShapes() - 1, -1, -1):
678 bh 6 result = point_in_polygon_shape(layer.shapefile.cobject(),
679     i, 0, 1,
680     map_proj, layer_proj,
681     scale, -scale, offx, offy,
682     px, py)
683     if result < 0:
684     select_shape = i
685     break
686     elif shapetype == SHAPETYPE_POINT:
687 bh 60 for i in range(layer.NumShapes() - 1, -1, -1):
688 bh 6 shape = layer.Shape(i)
689     x, y = shape.Points()[0]
690     if inverse:
691     x, y = inverse(x, y)
692     if forward:
693     x, y = forward(x, y)
694     x = x * scale + offx
695     y = -y * scale + offy
696     if hypot(px - x, py - y) < 5:
697     select_shape = i
698     break
699    
700     if select_shape >= 0:
701     return layer, select_shape
702     return None, None
703    
704     def SelectShapeAt(self, x, y):
705 bh 78 layer, shape = self.find_shape_at(x, y, selected_layer = 0)
706 bh 43 # If layer is None, then shape will also be None. We don't want
707     # to deselect the currently selected layer, so we simply select
708     # the already selected layer again.
709     if layer is None:
710     layer = self.interactor.SelectedLayer()
711 bh 6 self.interactor.SelectLayerAndShape(layer, shape)
712    
713     def LabelShapeAt(self, x, y):
714     ox = x; oy = y
715     label_layer = self.map.LabelLayer()
716     layer, shape_index = self.find_shape_at(x, y, select_labels = 1)
717     if layer is None and shape_index is not None:
718     # a label was selected
719     label_layer.RemoveLabel(shape_index)
720     elif layer is not None:
721     text = labeldialog.run_label_dialog(self, layer.table, shape_index)
722     if text:
723     proj = self.map.projection
724     if proj is not None:
725     map_proj = proj
726     else:
727     map_proj = None
728     proj = layer.projection
729     if proj is not None:
730     layer_proj = proj
731     else:
732     layer_proj = None
733    
734     shapetype = layer.ShapeType()
735     if shapetype == SHAPETYPE_POLYGON:
736     x, y = shape_centroid(layer.shapefile.cobject(),
737     shape_index,
738     map_proj, layer_proj, 1, 1, 0, 0)
739     if map_proj is not None:
740     x, y = map_proj.Inverse(x, y)
741     else:
742     shape = layer.Shape(shape_index)
743     if shapetype == SHAPETYPE_POINT:
744     x, y = shape.Points()[0]
745     else:
746     # assume SHAPETYPE_ARC
747     points = shape.Points()
748     x, y = points[len(points) / 2]
749     if layer_proj is not None:
750     x, y = layer_proj.Inverse(x, y)
751     if shapetype == SHAPETYPE_POINT:
752     halign = ALIGN_LEFT
753     valign = ALIGN_CENTER
754     elif shapetype == SHAPETYPE_POLYGON:
755     halign = ALIGN_CENTER
756     valign = ALIGN_CENTER
757     elif shapetype == SHAPETYPE_ARC:
758     halign = ALIGN_LEFT
759     valign = ALIGN_CENTER
760     label_layer.AddLabel(x, y, text,
761     halign = halign, valign = valign)

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Revision

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26